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
@@ -67,10 +67,7 @@ export const AvatarOrIcon = ({
if (isIconInverted || isDefined(IconBackgroundColor)) {
return (
<StyledAvatarOrIconWrapper
isClickable={isClickable}
onClick={onClick}
>
<StyledAvatarOrIconWrapper isClickable={isClickable} onClick={onClick}>
<StyledIconWithBackgroundContainer
backgroundColor={
IconBackgroundColor ?? theme.background.invertedSecondary
@@ -87,10 +84,7 @@ export const AvatarOrIcon = ({
}
return (
<StyledAvatarOrIconWrapper
isClickable={isClickable}
onClick={onClick}
>
<StyledAvatarOrIconWrapper isClickable={isClickable} onClick={onClick}>
<Icon
size={theme.icon.size.sm}
stroke={theme.icon.stroke.sm}
@@ -140,8 +140,8 @@ const StyledContainer = styled.div<
`;
const StyledRightComponentDivider = styled.div`
border-left: 1px solid ${themeCssVariables.border.color.light};
align-self: stretch;
border-left: 1px solid ${themeCssVariables.border.color.light};
`;
const renderRightComponent = (
@@ -155,7 +155,7 @@ const renderRightComponent = (
const rendered =
typeof rightComponent === 'function' ? rightComponent() : rightComponent;
if (rightComponentDivider) {
if (rightComponentDivider === true) {
return (
<>
<StyledRightComponentDivider />