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:
@@ -1,7 +1,7 @@
|
||||
import { AuthModalMountEffect } from '@/auth/components/AuthModalMountEffect';
|
||||
import { AUTH_MODAL_ID } from '@/auth/constants/AuthModalId';
|
||||
import { getAuthModalConfig } from '@/auth/utils/getAuthModalConfig';
|
||||
import { Modal } from '@/ui/layout/modal/components/Modal';
|
||||
import { ModalStatefulWrapper } from '@/ui/layout/modal/components/ModalStatefulWrapper';
|
||||
import { ScrollWrapper } from '@/ui/utilities/scroll/components/ScrollWrapper';
|
||||
import { styled } from '@linaria/react';
|
||||
import React from 'react';
|
||||
@@ -23,11 +23,11 @@ export const AuthModal = ({ children }: AuthModalProps) => {
|
||||
return (
|
||||
<>
|
||||
<AuthModalMountEffect />
|
||||
<Modal
|
||||
modalId={AUTH_MODAL_ID}
|
||||
<ModalStatefulWrapper
|
||||
modalInstanceId={AUTH_MODAL_ID}
|
||||
padding="none"
|
||||
size={config.size}
|
||||
modalVariant={config.variant}
|
||||
overlay={config.overlay}
|
||||
>
|
||||
{config.showScrollWrapper ? (
|
||||
<ScrollWrapper componentInstanceId="scroll-wrapper-modal-content">
|
||||
@@ -36,7 +36,7 @@ export const AuthModal = ({ children }: AuthModalProps) => {
|
||||
) : (
|
||||
<>{children}</>
|
||||
)}
|
||||
</Modal>
|
||||
</ModalStatefulWrapper>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useVerifyLogin } from '@/auth/hooks/useVerifyLogin';
|
||||
import { clientConfigApiStatusState } from '@/client-config/states/clientConfigApiStatusState';
|
||||
import { useIsCurrentLocationOnAWorkspace } from '@/domain-manager/hooks/useIsCurrentLocationOnAWorkspace';
|
||||
import { useRedirectToWorkspaceDomain } from '@/domain-manager/hooks/useRedirectToWorkspaceDomain';
|
||||
import { Modal } from '@/ui/layout/modal/components/Modal';
|
||||
import { ModalContent } from 'twenty-ui/layout';
|
||||
import { useLingui } from '@lingui/react/macro';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
@@ -126,9 +126,9 @@ export const VerifyEmailEffect = () => {
|
||||
|
||||
if (isError) {
|
||||
return (
|
||||
<Modal.Content isVerticalCentered isHorizontalCentered>
|
||||
<ModalContent isVerticallyCentered isHorizontallyCentered>
|
||||
<EmailVerificationSent email={email} isError={true} />
|
||||
</Modal.Content>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -5,14 +5,14 @@ import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
||||
// Mock component that just renders the error state of VerifyEmailEffect directly
|
||||
// (since normal VerifyEmailEffect has async logic that's hard to test in Storybook)
|
||||
import { EmailVerificationSent } from '@/auth/sign-in-up/components/EmailVerificationSent';
|
||||
import { Modal } from '@/ui/layout/modal/components/Modal';
|
||||
import { ModalContent } from 'twenty-ui/layout';
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
|
||||
const VerifyEmailEffectErrorState = ({ email = 'user@example.com' }) => {
|
||||
return (
|
||||
<Modal.Content isVerticalCentered isHorizontalCentered>
|
||||
<ModalContent isVerticallyCentered isHorizontallyCentered>
|
||||
<EmailVerificationSent email={email} isError={true} />
|
||||
</Modal.Content>
|
||||
</ModalContent>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -29,7 +29,7 @@ const meta: Meta<typeof VerifyEmailEffectErrorState> = {
|
||||
],
|
||||
parameters: {
|
||||
codeSection: {
|
||||
docs: 'IMPORTANT: When rendering EmailVerificationSent from VerifyEmailEffect, always wrap it with Modal.Content to maintain consistent styling.',
|
||||
docs: 'IMPORTANT: When rendering EmailVerificationSent from VerifyEmailEffect, always wrap it with ModalContent to maintain consistent styling.',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import {
|
||||
type ModalSize,
|
||||
type ModalVariants,
|
||||
} from '@/ui/layout/modal/components/Modal';
|
||||
import { type ModalOverlay, type ModalSize } from 'twenty-ui/layout';
|
||||
import { AppPath } from 'twenty-shared/types';
|
||||
|
||||
type AuthModalConfigType = {
|
||||
size: ModalSize;
|
||||
variant: ModalVariants;
|
||||
overlay: ModalOverlay;
|
||||
showScrollWrapper: boolean;
|
||||
};
|
||||
|
||||
@@ -16,12 +13,12 @@ export const AUTH_MODAL_CONFIG: {
|
||||
} = {
|
||||
default: {
|
||||
size: 'medium',
|
||||
variant: 'primary',
|
||||
overlay: 'dark',
|
||||
showScrollWrapper: true,
|
||||
},
|
||||
[AppPath.BookCall]: {
|
||||
size: 'extraLarge',
|
||||
variant: 'transparent',
|
||||
overlay: 'transparent',
|
||||
showScrollWrapper: false,
|
||||
},
|
||||
};
|
||||
|
||||
+7
-14
@@ -1,24 +1,17 @@
|
||||
import { type Meta, type StoryObj } from '@storybook/react-vite';
|
||||
|
||||
import { EmailVerificationSent } from '@/auth/sign-in-up/components/EmailVerificationSent';
|
||||
import { Modal } from '@/ui/layout/modal/components/Modal';
|
||||
import { ModalContent } from 'twenty-ui/layout';
|
||||
import { ComponentDecorator } from 'twenty-ui/testing';
|
||||
import { SnackBarDecorator } from '~/testing/decorators/SnackBarDecorator';
|
||||
|
||||
// Wrap the component in Modal.Content to reflect how it's used in the app
|
||||
const RenderWithModal = (
|
||||
const RenderWithModalContent = (
|
||||
args: React.ComponentProps<typeof EmailVerificationSent>,
|
||||
) => {
|
||||
return (
|
||||
<Modal
|
||||
modalId="email-verification-sent-modal"
|
||||
padding="none"
|
||||
modalVariant="primary"
|
||||
>
|
||||
<Modal.Content isVerticalCentered isHorizontalCentered>
|
||||
<EmailVerificationSent email={args.email} isError={args.isError} />
|
||||
</Modal.Content>
|
||||
</Modal>
|
||||
<ModalContent isVerticallyCentered isHorizontallyCentered>
|
||||
<EmailVerificationSent email={args.email} isError={args.isError} />
|
||||
</ModalContent>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -28,10 +21,10 @@ const meta: Meta<typeof EmailVerificationSent> = {
|
||||
decorators: [ComponentDecorator, SnackBarDecorator],
|
||||
parameters: {
|
||||
codeSection: {
|
||||
docs: 'This component should always be wrapped with Modal.Content in the app.\n\nCorrect usage:\n```tsx\n<Modal.Content isVerticalCentered isHorizontalCentered>\n <EmailVerificationSent email={email} />\n</Modal.Content>\n```\n',
|
||||
docs: 'This component should always be wrapped with ModalContent in the app.\n\nCorrect usage:\n```tsx\n<ModalContent isVerticallyCentered isHorizontallyCentered>\n <EmailVerificationSent email={email} />\n</ModalContent>\n```\n',
|
||||
},
|
||||
},
|
||||
render: RenderWithModal,
|
||||
render: RenderWithModalContent,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
Reference in New Issue
Block a user