Refactor modal (#18377)

## Summary

- Move Modal UI components (`Modal`, `ModalContent`, `ModalHeader`,
`ModalFooter`, `ModalBackdrop`) from `twenty-front` to `twenty-ui` as
stateless, reusable components
- Create `ModalStatefulWrapper` in `twenty-front` that connects Jotai
state (`isModalOpenedComponentState`) to the stateless `Modal` via an
`isOpen` prop
- Rename `modalVariant` prop to `overlay` with clearer values: `'dark'`
(default), `'light'` (in-container), `'transparent'` (invisible panel).
Remove unused `'medium'` overlay
- Rename `modalId` to `modalInstanceId` across the entire modal zone
(~30 consumer files)
- Extract `ModalProps` to its own file in
`twenty-ui/types/ModalProps.ts`; extract `ModalStatefulWrapperProps` to
its own file using `Pick<ModalProps, ...>` for shared props
- Extract `ModalBackdrop` to its own file and export from `twenty-ui`;
use it in `UserOrMetadataLoader` instead of a local styled component
- Use `ModalFooter` in `StepNavigationButton` and `ModalHeader` in
`SpreadsheetImportStepperContainer` instead of duplicated `styled.div`
definitions
- Remove unused `onClose` prop from stateless `Modal`; fix `typeof
document` guard in `ModalStatefulWrapper`
- Split shared types into individual files: `ModalSize.ts`,
`ModalPadding.ts`, `ModalOverlay.ts`
- Extract wyw profiling instrumentation from `vite.config.ts` into
reusable `createWywProfilingPlugin` with parametrized threshold and
improved logging
- Delete old `Modal.tsx`, `Modal.styles.ts`, `ModalContent.tsx`,
`ModalHeader.tsx`, `ModalFooter.tsx` from `twenty-front`
- Add comprehensive Storybook stories in `twenty-ui` covering Default,
Confirmation, Small, ExtraLarge, Closed, and Interactive variants
This commit is contained in:
Charles Bochet
2026-03-04 13:22:31 +01:00
committed by GitHub
parent 995793c0ac
commit 3b2bf39565
99 changed files with 4283 additions and 3688 deletions
@@ -0,0 +1,98 @@
/* eslint-disable no-console */
import { type Plugin } from 'vite';
const LINARIA_IMPORT_RE = /@linaria/;
type WywProfilingOptions = {
slowThresholdMs?: number;
topSlowFilesCount?: number;
progressIntervalFiles?: number;
};
export const createWywProfilingPlugin = (
wywPlugin: Plugin,
options?: WywProfilingOptions,
): Plugin => {
const slowThresholdMs = options?.slowThresholdMs ?? 50;
const topSlowFilesCount = options?.topSlowFilesCount ?? 10;
const progressIntervalFiles = options?.progressIntervalFiles ?? 50;
let totalMs = 0;
let fileCount = 0;
let skippedCount = 0;
const slowFiles: { id: string; ms: number }[] = [];
const originalTransform = wywPlugin.transform;
console.log(
`[linaria/wyw] CSS pre-build profiling enabled (slow threshold: ${slowThresholdMs}ms)`,
);
return {
...wywPlugin,
enforce: 'pre' as const,
transform(code: string, id: string, ...rest: unknown[]) {
if (!LINARIA_IMPORT_RE.test(code)) {
skippedCount++;
return null;
}
const start = performance.now();
const result = (originalTransform as Function).call(
this,
code,
id,
...rest,
);
const handleTiming = (elapsed: number) => {
totalMs += elapsed;
fileCount++;
if (elapsed > slowThresholdMs) {
slowFiles.push({ id, ms: elapsed });
}
if (fileCount % progressIntervalFiles === 0) {
console.log(
`[linaria/wyw] CSS pre-build progress: ${fileCount} transformed, ${skippedCount} skipped, ${totalMs.toFixed(0)}ms total`,
);
}
};
if (result && typeof result === 'object' && 'then' in result) {
return (result as Promise<unknown>).then((res) => {
handleTiming(performance.now() - start);
return res;
});
}
handleTiming(performance.now() - start);
return result;
},
buildEnd() {
console.log('\n[linaria/wyw] ===== CSS PRE-BUILD TIMING SUMMARY =====');
console.log(`[linaria/wyw] Files transformed: ${fileCount}`);
console.log(`[linaria/wyw] Files skipped (no @linaria): ${skippedCount}`);
console.log(`[linaria/wyw] Transform time: ${totalMs.toFixed(0)}ms`);
console.log(
`[linaria/wyw] Avg per transformed file: ${fileCount > 0 ? (totalMs / fileCount).toFixed(1) : 0}ms`,
);
if (slowFiles.length > 0) {
console.log(
`[linaria/wyw] Slow CSS pre-build files (>${slowThresholdMs}ms):`,
);
slowFiles
.sort((a, b) => b.ms - a.ms)
.slice(0, topSlowFilesCount)
.forEach((slowFile) =>
console.log(
`[linaria/wyw] ${slowFile.ms.toFixed(0)}ms ${slowFile.id.replace(process.cwd(), '')}`,
),
);
}
console.log('[linaria/wyw] ==========================================\n');
},
};
};
+10
View File
@@ -0,0 +1,10 @@
/*
* _____ _
*|_ _|_ _____ _ __ | |_ _ _
* | | \ \ /\ / / _ \ '_ \| __| | | | Auto-generated file
* | | \ V V / __/ | | | |_| |_| | Any edits to this will be overridden
* |_| \_/\_/ \___|_| |_|\__|\__, |
* |___/
*/
export { createWywProfilingPlugin } from './createWywProfilingPlugin';