From 8244555fc649ea859b0fc8d5aeb70ce063b1b845 Mon Sep 17 00:00:00 2001 From: "Ziggy Z." Date: Thu, 20 Aug 2026 16:02:57 +0700 Subject: [PATCH 01/12] [CCUBE-2221][ZZ] feat: adding card fullscreen props and adjust styles --- src/modal-v2/slots/card.tsx | 1 + src/modal-v2/slots/slot-styles.ts | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/modal-v2/slots/card.tsx b/src/modal-v2/slots/card.tsx index 22e43ac5f..8f924f2bf 100644 --- a/src/modal-v2/slots/card.tsx +++ b/src/modal-v2/slots/card.tsx @@ -62,6 +62,7 @@ function CardInner( ref={mergeRefs(ref, elementRef)} id={id} data-testid={testId} + data-fullscreen={fullscreen || undefined} {...otherProps} onClick={handleOnClick} className={clsx( diff --git a/src/modal-v2/slots/slot-styles.ts b/src/modal-v2/slots/slot-styles.ts index 8f1da1ab7..9f1a2c7d0 100644 --- a/src/modal-v2/slots/slot-styles.ts +++ b/src/modal-v2/slots/slot-styles.ts @@ -76,6 +76,16 @@ export const modalCard = css` ${MediaQuery.MaxWidth.xxs} { max-width: calc(100% - ${Breakpoint["xxs-margin"]} * 2); } + + &&[data-fullscreen] { + max-width: none; + width: 100%; + height: 100vh; + margin: 0; + border-radius: 0; + padding: 0; + box-shadow: none; + } `; export const fullscreenModalCard = css` From e4bf8664c5ee481c4d2aa1c6694ecb572dd19ce9 Mon Sep 17 00:00:00 2001 From: "Ziggy Z." Date: Thu, 20 Aug 2026 16:06:11 +0700 Subject: [PATCH 02/12] [CCUBE-2221][ZZ] story: adding fullscreen story to modal v2 card --- stories/modal-v2/modal-v2.stories.tsx | 31 +++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/stories/modal-v2/modal-v2.stories.tsx b/stories/modal-v2/modal-v2.stories.tsx index f8c9879c0..1b9066809 100644 --- a/stories/modal-v2/modal-v2.stories.tsx +++ b/stories/modal-v2/modal-v2.stories.tsx @@ -404,6 +404,37 @@ export const StackedModals: StoryObj = { }, }; +export const Fullscreen: StoryObj = { + render: () => { + const [show, setShow] = useState(false); + const openModal = () => setShow(true); + const closeModal = () => setShow(false); + return ( + <> + + + + + + + This card fills the entire viewport with no + border-radius, padding, or box-shadow. + + + + + + ); + }, +}; + export const ScrollHandling: StoryObj = { render: (_args) => { const [show, setShow] = useState(false); From e7ac387a55b730de577c8006dca9da8933a12d86 Mon Sep 17 00:00:00 2001 From: "Ziggy Z." Date: Tue, 18 Aug 2026 16:21:22 +0700 Subject: [PATCH 03/12] [CCUBE-2221][ZZ] feat: migrate e-signature to use modal v2 instead --- src/e-signature/e-signature.styles.ts | 196 ++++++++++++++++++-------- src/e-signature/e-signature.tsx | 66 ++++----- 2 files changed, 171 insertions(+), 91 deletions(-) diff --git a/src/e-signature/e-signature.styles.ts b/src/e-signature/e-signature.styles.ts index ad12de9a5..94530bfad 100644 --- a/src/e-signature/e-signature.styles.ts +++ b/src/e-signature/e-signature.styles.ts @@ -1,11 +1,15 @@ import { css } from "@linaria/core"; -import * as modalStyles from "../modal/modal.styles"; -import { Border, Colour, Font, MediaQuery, Radius, Spacing } from "../theme"; - -// ============================================================================= -// STYLING -// ============================================================================= +import { slotSpacerTokens } from "../modal-v2/slots/slot-styles"; +import { + Border, + Colour, + Font, + MediaQuery, + Radius, + Shadow, + Spacing, +} from "../theme"; // ----------------------------------------------------------------------------- // MAIN FIELD @@ -71,56 +75,117 @@ export const instructions = css` // SIGNATURE MODAL // ----------------------------------------------------------------------------- -export const scrollableModal = css` - /* increase specificity as the styles are overwritten */ +export const modalCard = css` && { - height: 100%; - overflow-y: auto; + width: 100%; + height: 29rem; + max-width: 672px; + max-height: none; + margin: 0 auto; + padding: ${Spacing["spacing-16"]}; + box-shadow: ${Shadow["lg-strong"]}; } -`; -export const growContainer = css` - width: 100%; - margin: auto; - padding: ${Spacing["layout-xxl"]} ${Spacing["layout-sm"]}; + ${MediaQuery.MaxWidth.sm} { + &[data-mobile-landscape][data-mobile-landscape] { + max-width: none; + height: 100vh; + margin: 0; + border-radius: 0; + padding: 0; + box-shadow: none; + } + } - ${MediaQuery.MaxWidth.sm}, &[data-mobile-landscape="true"] { + &[data-mobile-landscape="true"][data-mobile-landscape] { + max-width: none; + height: 100vh; + margin: 0; + border-radius: 0; padding: 0; - width: 100%; - height: 100%; + box-shadow: none; } -`; -export const modalBox = css` - width: 100%; - height: 29rem; - max-width: 672px; - max-height: none; - margin: 0 auto; - padding: ${Spacing["spacing-16"]}; - - ${MediaQuery.MaxWidth.sm}, &[data-mobile-landscape="true"] { + & > [data-has-close-button] { + flex: 1; display: flex; flex-direction: column; - max-width: none; - height: 100%; - border-radius: 0; - padding: 0; + min-height: 0; - ${modalStyles.tokens.closeButton.topInset}: ${Spacing["spacing-8"]}; - ${modalStyles.tokens.closeButton.rightInset}: ${Spacing["spacing-20"]}; + ${slotSpacerTokens.contentLastChildMarginBottom}: 0; + ${slotSpacerTokens.footerNotFirstChildMarginTop}: 0; + ${slotSpacerTokens.footerLastChildMarginBottom}: 0; } `; -export const modalTitle = css` - ${Font["body-baseline-semibold"]} - color: ${Colour["text"]}; - margin-bottom: ${Spacing["spacing-16"]}; - text-align: center; +export const modalHeader = css` + && { + padding: 0 0 ${Spacing["spacing-16"]}; + position: relative; + } - ${MediaQuery.MaxWidth.sm}, &[data-mobile-landscape="true"] { - ${Font["body-md-semibold"]} - margin: ${Spacing["spacing-12"]} 0; + & > span { + ${Font["body-baseline-semibold"]} + flex: unset; + width: 100%; + text-align: center; + } + + & > button { + position: absolute; + top: 0; + right: 0; + } + + & > div[aria-hidden] { + display: none; + } + + ${MediaQuery.MaxWidth.sm} { + &[data-mobile-landscape] { + padding: ${Spacing["spacing-12"]} ${Spacing["spacing-20"]}; + } + + &[data-mobile-landscape] > span { + ${Font["body-md-semibold"]} + } + + &[data-mobile-landscape] > button { + top: ${Spacing["spacing-8"]}; + right: ${Spacing["spacing-20"]}; + } + } + + &[data-mobile-landscape="true"] { + padding: ${Spacing["spacing-12"]} ${Spacing["spacing-20"]}; + + & > span { + ${Font["body-md-semibold"]} + } + + & > button { + top: ${Spacing["spacing-8"]}; + right: ${Spacing["spacing-20"]}; + } + } +`; + +export const modalContent = css` + && { + margin: 0; + } + display: flex; + flex-direction: column; + min-height: 0; + + ${MediaQuery.MaxWidth.sm} { + &[data-mobile-landscape] { + flex: 1; + } + } + + &[data-mobile-landscape="true"] { + flex: 1; } `; @@ -130,12 +195,16 @@ export const eSignatureContainer = css` border-radius: ${Radius["lg"]}; overflow: hidden; - ${MediaQuery.MaxWidth.sm}, &[data-mobile-landscape="true"] { - border-radius: 0; - flex: 1; + ${MediaQuery.MaxWidth.sm} { + &[data-mobile-landscape] { + border-radius: 0; + flex: 1; + } } &[data-mobile-landscape="true"] { + height: auto; + flex: 1; background: ${Colour["bg-strong"]}; } `; @@ -180,30 +249,39 @@ export const signatureLine = css` `; export const modalButtons = css` - display: flex; - justify-content: space-between; - margin-top: ${Spacing["spacing-16"]}; + && { + flex-direction: row-reverse; + margin: ${Spacing["spacing-16"]} 0 0; + margin-right: 0; + margin-left: 0; + justify-content: space-between; + column-gap: 0; + } + + && > button { + flex: none; + width: 8.5rem; + } ${MediaQuery.MaxWidth.sm} { - flex-direction: column-reverse; - margin: ${Spacing["spacing-16"]} ${Spacing["spacing-24"]} - ${Spacing["spacing-48"]}; - gap: ${Spacing["spacing-16"]}; + &[data-mobile-landscape] { + flex-direction: column; + margin: ${Spacing["spacing-16"]} ${Spacing["spacing-24"]} + ${Spacing["spacing-48"]}; + gap: ${Spacing["spacing-16"]}; + } + + &[data-mobile-landscape] > button { + width: 100%; + } } &[data-mobile-landscape="true"] { - flex-direction: row; margin: ${Spacing["spacing-16"]} ${Spacing["spacing-20"]}; } `; export const modalActionButton = css` - width: 8.5rem; - - ${MediaQuery.MaxWidth.sm} { - width: 100%; - } - &[data-mobile-landscape="true"] { height: 2.5rem; } diff --git a/src/e-signature/e-signature.tsx b/src/e-signature/e-signature.tsx index b56d620d3..85923ace4 100644 --- a/src/e-signature/e-signature.tsx +++ b/src/e-signature/e-signature.tsx @@ -3,7 +3,7 @@ import { lazy, Suspense, useEffect, useRef, useState } from "react"; import { Button } from "../button"; import { DashedBorder } from "../dashed-border"; -import { Modal } from "../modal"; +import { ModalV2 } from "../modal-v2"; import { ProgressBar } from "../shared/progress-bar"; import { Border, @@ -142,26 +142,25 @@ export const ESignature = (props: EsignatureProps) => { const renderModal = () => { return ( - setShowModal(false)} > -
- + setShowModal(false)} > -

- Signature -

{
-
+ + { isMobileLandscape ? "small" : "default" } type="button" - styleType={ - isMobile && !isMobileLandscape - ? "light" - : "link" - } - icon={} - onClick={handleClearDrawing} + onClick={handleClickSave} > - Clear + Save + } + secondaryButton={ -
- - -
+ } + /> + + ); }; From cd2ef9bc11f490b239bc54199b05a6e37123a1f6 Mon Sep 17 00:00:00 2001 From: "Ziggy Z." Date: Tue, 18 Aug 2026 16:23:38 +0700 Subject: [PATCH 04/12] [CCUBE-2221][ZZ] test: adjust unit test post migration --- tests/e-signature/e-signature.spec.tsx | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/tests/e-signature/e-signature.spec.tsx b/tests/e-signature/e-signature.spec.tsx index 6d8130eb9..ce22798e8 100644 --- a/tests/e-signature/e-signature.spec.tsx +++ b/tests/e-signature/e-signature.spec.tsx @@ -1,4 +1,10 @@ -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { + act, + fireEvent, + render, + screen, + waitFor, +} from "@testing-library/react"; import { ESignature } from "src/e-signature"; import { createMatchMediaMock } from "../_common"; @@ -85,6 +91,7 @@ describe("ESignature", () => { }); it("should call onChange and show signature preview on clicking save button", async () => { + jest.useFakeTimers(); const changeFn = jest.fn(); render(); @@ -92,13 +99,15 @@ describe("ESignature", () => { drawSignature(); fireEvent.click(screen.getByRole("button", { name: "Save" })); - await waitFor(() => { - expect(getSignatureModal()).not.toBeVisible(); + await act(async () => { + jest.advanceTimersByTime(500); }); + expect(queryAddSignatureButton()).not.toBeInTheDocument(); expect(getEditSignatureButton()).toBeInTheDocument(); expect(changeFn).toHaveBeenCalled(); expect(screen.getByAltText("Signature preview")).toBeInTheDocument(); + jest.useRealTimers(); }); it("should discard unsaved changes on clicking cross button in modal", () => { @@ -115,6 +124,7 @@ describe("ESignature", () => { }); it("should clear the field value on clicking clear button and save button subsequently", async () => { + jest.useFakeTimers(); render(); fireEvent.click(getAddSignatureButton()); @@ -122,10 +132,12 @@ describe("ESignature", () => { fireEvent.click(screen.getByRole("button", { name: "Clear" })); fireEvent.click(screen.getByRole("button", { name: "Save" })); - await waitFor(() => { - expect(getSignatureModal()).not.toBeVisible(); + await act(async () => { + jest.advanceTimersByTime(500); }); + expect(getAddSignatureButton()).toBeInTheDocument(); + jest.useRealTimers(); }); }); From bacf370b75186c890eba41901ab0b0fd3444018a Mon Sep 17 00:00:00 2001 From: "Ziggy Z." Date: Tue, 18 Aug 2026 16:25:08 +0700 Subject: [PATCH 05/12] [CCUBE-2221][ZZ] test: update screenshot --- .../ESignature-Modal-mobile---modal-open.png | Bin 7403 -> 7855 bytes ...re-Modal-mobile-landscape---modal-open.png | Bin 5966 -> 6633 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/e2e/tests/components/e-signature/__screenshots__/chromium/ESignature-Modal-mobile---modal-open.png b/e2e/tests/components/e-signature/__screenshots__/chromium/ESignature-Modal-mobile---modal-open.png index 6f4a28068ee4057e882f2087efbf23ac3a1654df..273ebf9249cd30bc935daad6a225ad974d7c1142 100644 GIT binary patch literal 7855 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 VIZy*lJ?S4A8!N{v)xX}j|6fb970Uns diff --git a/e2e/tests/components/e-signature/__screenshots__/chromium/ESignature-Modal-mobile-landscape---modal-open.png b/e2e/tests/components/e-signature/__screenshots__/chromium/ESignature-Modal-mobile-landscape---modal-open.png index cb214a9615b0df5150afe7fe0c5a6fc9c929b162..20c7c90a000881b06b867f817bcc6b90a7aa2419 100644 GIT binary patch literal 6633 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 From f34874aceb8fe84645724e7f77d2b03be1714ca6 Mon Sep 17 00:00:00 2001 From: "Ziggy Z." Date: Wed, 19 Aug 2026 13:58:38 +0700 Subject: [PATCH 06/12] [CCUBE-2221][ZZ] style: remove unneccessary attribute addition --- src/e-signature/e-signature.styles.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/e-signature/e-signature.styles.ts b/src/e-signature/e-signature.styles.ts index 94530bfad..a6c3ca158 100644 --- a/src/e-signature/e-signature.styles.ts +++ b/src/e-signature/e-signature.styles.ts @@ -88,9 +88,7 @@ export const modalCard = css` ${MediaQuery.MaxWidth.sm} { &[data-mobile-landscape][data-mobile-landscape] { - max-width: none; height: 100vh; - margin: 0; border-radius: 0; padding: 0; box-shadow: none; @@ -252,8 +250,6 @@ export const modalButtons = css` && { flex-direction: row-reverse; margin: ${Spacing["spacing-16"]} 0 0; - margin-right: 0; - margin-left: 0; justify-content: space-between; column-gap: 0; } From 668e29481858ea67415bba80aaf5252caca886e4 Mon Sep 17 00:00:00 2001 From: "Ziggy Z." Date: Thu, 20 Aug 2026 15:09:38 +0700 Subject: [PATCH 07/12] [CCUBE-2221][ZZ] style: remove action button styling --- src/e-signature/e-signature.styles.ts | 6 ------ src/e-signature/e-signature.tsx | 2 -- 2 files changed, 8 deletions(-) diff --git a/src/e-signature/e-signature.styles.ts b/src/e-signature/e-signature.styles.ts index a6c3ca158..aa14763c3 100644 --- a/src/e-signature/e-signature.styles.ts +++ b/src/e-signature/e-signature.styles.ts @@ -277,12 +277,6 @@ export const modalButtons = css` } `; -export const modalActionButton = css` - &[data-mobile-landscape="true"] { - height: 2.5rem; - } -`; - export const signatureCanvasContainer = css` width: 100%; height: 100%; diff --git a/src/e-signature/e-signature.tsx b/src/e-signature/e-signature.tsx index 85923ace4..070401d29 100644 --- a/src/e-signature/e-signature.tsx +++ b/src/e-signature/e-signature.tsx @@ -189,7 +189,6 @@ export const ESignature = (props: EsignatureProps) => { data-mobile-landscape={isMobileLandscape} primaryButton={ - } - secondaryButton={ +
- } - /> + +
+ ); From 3774a845c7db257479ad2555c67ba7b1f959685a Mon Sep 17 00:00:00 2001 From: "Ziggy Z." Date: Thu, 20 Aug 2026 16:07:31 +0700 Subject: [PATCH 09/12] [CCUBE-2221][ZZ] feat: update card usage for e-signature and remove card on mobile specific styling --- src/e-signature/e-signature.styles.ts | 18 ------------------ src/e-signature/e-signature.tsx | 1 + 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/src/e-signature/e-signature.styles.ts b/src/e-signature/e-signature.styles.ts index fc2606262..3f69bf0b0 100644 --- a/src/e-signature/e-signature.styles.ts +++ b/src/e-signature/e-signature.styles.ts @@ -86,24 +86,6 @@ export const modalCard = css` box-shadow: ${Shadow["lg-strong"]}; } - ${MediaQuery.MaxWidth.sm} { - &[data-mobile-landscape][data-mobile-landscape] { - height: 100vh; - border-radius: 0; - padding: 0; - box-shadow: none; - } - } - - &[data-mobile-landscape="true"][data-mobile-landscape] { - max-width: none; - height: 100vh; - margin: 0; - border-radius: 0; - padding: 0; - box-shadow: none; - } - & > [data-has-close-button] { flex: 1; display: flex; diff --git a/src/e-signature/e-signature.tsx b/src/e-signature/e-signature.tsx index e6ad762e7..9d167101f 100644 --- a/src/e-signature/e-signature.tsx +++ b/src/e-signature/e-signature.tsx @@ -150,6 +150,7 @@ export const ESignature = (props: EsignatureProps) => { Date: Mon, 21 Sep 2026 16:38:53 +0700 Subject: [PATCH 10/12] [CCUBE-2221][ZZ] feat: update modal v2 specificity and add property changes to accomodate different scenarios --- docs/component-catalog.json | 2 +- src/modal-v2/modal-v2.tsx | 4 +- src/modal-v2/slots/card.tsx | 3 +- src/modal-v2/slots/header.tsx | 2 +- src/modal-v2/slots/slot-styles.ts | 215 +++++++++++++++++------------- src/modal-v2/types.ts | 14 +- 6 files changed, 139 insertions(+), 101 deletions(-) diff --git a/docs/component-catalog.json b/docs/component-catalog.json index bf869195a..6faf6f893 100644 --- a/docs/component-catalog.json +++ b/docs/component-catalog.json @@ -478,7 +478,7 @@ { "name": "ModalV2", "importPath": "@lifesg/react-design-system/modal-v2", - "description": "A composable modal dialog with slot-based content layout. Use `ModalV2` when you need a controlled overlay dialog with structured content slots. Sub-components: - `ModalV2.Card` — wraps modal content and arranges `Content`, `Footer`, and `CloseButton` slots in the correct layout. Supports a `fullscreen` prop that makes the card fill the viewport. - `ModalV2.CloseButton` — renders an accessible close button that invokes the modal's `onClose` callback. - `ModalV2.Content` — container for the body content of the modal card. - `ModalV2.Footer` — footer area for primary and secondary action buttons.", + "description": "A composable modal dialog with slot-based content layout. Use `ModalV2` when you need a controlled overlay dialog with structured content slots. Sub-components: - `ModalV2.Card` — wraps modal content and arranges `Content`, `Footer`, and `CloseButton` slots in the correct layout. Supports a `fullscreen` prop that makes the card fill the viewport, and a `fillHeight` prop that stretches the slots to fill a size-constrained card. - `ModalV2.CloseButton` — renders an accessible close button that invokes the modal's `onClose` callback. - `ModalV2.Content` — container for the body content of the modal card. - `ModalV2.Footer` — footer area for primary and secondary action buttons.", "keywords": ["dialog", "overlay", "popup"] }, { diff --git a/src/modal-v2/modal-v2.tsx b/src/modal-v2/modal-v2.tsx index d2a4dc931..e911a971d 100644 --- a/src/modal-v2/modal-v2.tsx +++ b/src/modal-v2/modal-v2.tsx @@ -138,14 +138,14 @@ const Base = ({ * content slots. * * Sub-components: - * - `ModalV2.Card` — wraps modal content and arranges `Content`, `Footer`, and `CloseButton` slots in the correct layout. Supports a `fullscreen` prop that makes the card fill the viewport. + * - `ModalV2.Card` — wraps modal content and arranges `Content`, `Footer`, and `CloseButton` slots in the correct layout. Supports a `fullscreen` prop that makes the card fill the viewport, and a `fillHeight` prop that stretches the slots to fill a size-constrained card. * - `ModalV2.CloseButton` — renders an accessible close button that invokes the modal's `onClose` callback. * - `ModalV2.Content` — container for the body content of the modal card. * - `ModalV2.Footer` — footer area for primary and secondary action buttons. * @keywords dialog, overlay, popup */ export const ModalV2 = Object.assign(Base, { - /** Wraps modal content and arranges `Content`, `Footer`, and `CloseButton` slots in the correct layout. Supports a `fullscreen` prop. */ + /** Wraps modal content and arranges `Content`, `Footer`, and `CloseButton` slots in the correct layout. Supports `fullscreen` and `fillHeight` props. */ Card, /** Renders an accessible close button that invokes the modal's `onClose` callback. */ CloseButton, diff --git a/src/modal-v2/slots/card.tsx b/src/modal-v2/slots/card.tsx index 8f924f2bf..8384b45cc 100644 --- a/src/modal-v2/slots/card.tsx +++ b/src/modal-v2/slots/card.tsx @@ -19,6 +19,7 @@ function CardInner( className, elementRef, fullscreen, + fillHeight, ...otherProps }: ModalCardProps, ref: React.ForwardedRef @@ -75,7 +76,7 @@ function CardInner( data-has-close-button={!!hasHeader} className={clsx( styles.slotSpacer, - fullscreen && styles.fullscreenSlotSpacer + (fullscreen || fillHeight) && styles.fillHeightSlotSpacer )} > {ContentSlot} diff --git a/src/modal-v2/slots/header.tsx b/src/modal-v2/slots/header.tsx index c6951fbfd..21969a34c 100644 --- a/src/modal-v2/slots/header.tsx +++ b/src/modal-v2/slots/header.tsx @@ -33,7 +33,7 @@ export const Header = ({ > - {title && {title}} + {title &&
{title}
} {title &&
}
); diff --git a/src/modal-v2/slots/slot-styles.ts b/src/modal-v2/slots/slot-styles.ts index 9f1a2c7d0..0644dd0a6 100644 --- a/src/modal-v2/slots/slot-styles.ts +++ b/src/modal-v2/slots/slot-styles.ts @@ -34,72 +34,92 @@ export const slotSpacerTokens = { "--fds-internal-modalV2-slotSpacer-footerLastChildMarginBottom", } as const; +export const headerTokens = { + padding: "--fds-internal-modalV2-header-padding", +} as const; + // ============================================================================= // STYLING // ============================================================================= /** Shared by both the windowed (`modalCard`) and `fullscreenModalCard` variants. */ export const cardBase = css` - background: ${Colour.bg}; + :where(&) { + background: ${Colour.bg}; - display: flex; - flex-direction: column-reverse; + display: flex; + flex-direction: column-reverse; + } `; export const modalCard = css` - width: 40rem; - margin: ${Spacing["spacing-64"]} auto; - box-shadow: ${Shadow["xs-strong"]}; - border-radius: ${Radius["lg"]}; + :where(&) { + width: 40rem; + margin: ${Spacing["spacing-64"]} auto; + box-shadow: ${Shadow["xs-strong"]}; + border-radius: ${Radius["lg"]}; - max-width: calc(100% - ${Breakpoint["xxl-margin"]} * 2); + max-width: calc(100% - ${Breakpoint["xxl-margin"]} * 2); - ${MediaQuery.MaxWidth.xl} { - max-width: calc(100% - ${Breakpoint["xl-margin"]} * 2); - } + ${MediaQuery.MaxWidth.xl} { + max-width: calc(100% - ${Breakpoint["xl-margin"]} * 2); + } - ${MediaQuery.MaxWidth.lg} { - max-width: calc(100% - ${Breakpoint["lg-margin"]} * 2); - } + ${MediaQuery.MaxWidth.lg} { + max-width: calc(100% - ${Breakpoint["lg-margin"]} * 2); + } - ${MediaQuery.MaxWidth.md} { - max-width: calc(100% - ${Breakpoint["md-margin"]} * 2); - } + ${MediaQuery.MaxWidth.md} { + max-width: calc(100% - ${Breakpoint["md-margin"]} * 2); + } - ${MediaQuery.MaxWidth.sm} { - max-width: calc(100% - ${Breakpoint["sm-margin"]} * 2); - } + ${MediaQuery.MaxWidth.sm} { + max-width: calc(100% - ${Breakpoint["sm-margin"]} * 2); + } - ${MediaQuery.MaxWidth.xs} { - max-width: calc(100% - ${Breakpoint["xs-margin"]} * 2); - } + ${MediaQuery.MaxWidth.xs} { + max-width: calc(100% - ${Breakpoint["xs-margin"]} * 2); + } - ${MediaQuery.MaxWidth.xxs} { - max-width: calc(100% - ${Breakpoint["xxs-margin"]} * 2); + ${MediaQuery.MaxWidth.xxs} { + max-width: calc(100% - ${Breakpoint["xxs-margin"]} * 2); + } } +`; +/* + * Deliberately high specificity, unlike the other card styles: `fullscreen` has + * to win over sizing and spacing that a consumer sets via `className` (e.g. + * e-signature's own modalCard pins height/max-width/padding/box-shadow). That + * is also why every property it needs to neutralise is reset explicitly here + * rather than relying on `modalCard` being absent. + */ +export const fullscreenModalCard = css` &&[data-fullscreen] { - max-width: none; width: 100%; height: 100vh; + max-width: none; margin: 0; - border-radius: 0; padding: 0; + border-radius: 0; box-shadow: none; } `; -export const fullscreenModalCard = css` - width: 100%; - height: 100vh; -`; - export const closeButtonContainer = css` - margin-right: ${Spacing["spacing-16"]}; - margin-left: auto; - margin-top: ${Spacing["spacing-16"]}; - margin-bottom: ${Spacing["spacing-16"]}; + :where(&) { + margin-right: ${Spacing["spacing-16"]}; + margin-left: auto; + margin-top: ${Spacing["spacing-16"]}; + margin-bottom: ${Spacing["spacing-16"]}; + } `; +/* + * Applied to a ClickableIcon, so these declarations are deliberately NOT + * wrapped in :where(): they have to outrank ClickableIcon's own `main` class + * (which sets `padding: spacing-24` and sizes `svg` to 1.125rem). Dropping + * them to zero specificity lets those defaults win and inflates the card. + */ export const styledClickableIcon = css` padding: 0; color: ${Colour.icon}; @@ -111,86 +131,84 @@ export const styledClickableIcon = css` `; export const contentContainer = css` - margin-right: ${Spacing["spacing-64"]}; - margin-left: ${Spacing["spacing-64"]}; - - ${MediaQuery.MaxWidth.sm} { - margin-right: ${Spacing["spacing-20"]}; - margin-left: ${Spacing["spacing-20"]}; + :where(&) { + margin-right: ${Spacing["spacing-64"]}; + margin-left: ${Spacing["spacing-64"]}; + + ${MediaQuery.MaxWidth.sm} { + margin-right: ${Spacing["spacing-20"]}; + margin-left: ${Spacing["spacing-20"]}; + } } `; export const footerContainer = css` - margin-right: ${Spacing["spacing-64"]}; - margin-left: ${Spacing["spacing-64"]}; - - ${MediaQuery.MaxWidth.sm} { - margin-right: ${Spacing["spacing-20"]}; - margin-left: ${Spacing["spacing-20"]}; + :where(&) { + margin-right: ${Spacing["spacing-64"]}; + margin-left: ${Spacing["spacing-64"]}; + + ${MediaQuery.MaxWidth.sm} { + margin-right: ${Spacing["spacing-20"]}; + margin-left: ${Spacing["spacing-20"]}; + } + + display: flex; + flex-direction: row-reverse; /* primary button on right */ + column-gap: ${Spacing["spacing-32"]}; + row-gap: ${Spacing["spacing-16"]}; + + ${MediaQuery.MaxWidth.md} { + flex-direction: column; + } } - display: flex; - flex-direction: row-reverse; /* primary button on right */ - column-gap: ${Spacing["spacing-32"]}; - row-gap: ${Spacing["spacing-16"]}; - - & > button { + :where(& > button) { flex: 1; } - - ${MediaQuery.MaxWidth.md} { - flex-direction: column; - } `; export const slotSpacer = css` - ${slotSpacerTokens.contentLastChildMarginBottom}: initial; - ${slotSpacerTokens.footerNotFirstChildMarginTop}: initial; - ${slotSpacerTokens.footerLastChildMarginBottom}: initial; - ${slotSpacerTokens.firstChildMarginTopWithCloseButton}: initial; - ${slotSpacerTokens.firstChildMarginTopNoCloseButton}: initial; - - ${internalSlotSpacerTokens.firstChildMarginTop}: var( - ${slotSpacerTokens.firstChildMarginTopNoCloseButton}, - ${Spacing["spacing-64"]} - ); - - & > :where(.${contentContainer}:last-child) { + :where(&) { + ${internalSlotSpacerTokens.firstChildMarginTop}: var( + ${slotSpacerTokens.firstChildMarginTopNoCloseButton}, + ${Spacing["spacing-64"]} + ); + } + + :where(& > .${contentContainer}:last-child) { margin-bottom: var( ${slotSpacerTokens.contentLastChildMarginBottom}, ${Spacing["spacing-64"]} ); } - & > :where(.${footerContainer}:not(:first-child)) { + :where(& > .${footerContainer}:not(:first-child)) { margin-top: var( ${slotSpacerTokens.footerNotFirstChildMarginTop}, ${Spacing["spacing-32"]} ); } - & > :where(.${footerContainer}:last-child) { + :where(& > .${footerContainer}:last-child) { margin-bottom: var( ${slotSpacerTokens.footerLastChildMarginBottom}, ${Spacing["spacing-64"]} ); } - & - > :where( - .${contentContainer}:first-child, .${footerContainer}:first-child - ) { + :where(& > .${contentContainer}:first-child), + :where(& > .${footerContainer}:first-child) { margin-top: var(${internalSlotSpacerTokens.firstChildMarginTop}); } - &[${slotSpacerHasCloseButtonAttribute}="true"] { + :where(&[${slotSpacerHasCloseButtonAttribute}="true"]) { ${internalSlotSpacerTokens.firstChildMarginTop}: var( ${slotSpacerTokens.firstChildMarginTopWithCloseButton}, 0 ); } - &[${slotSpacerHasCloseButtonAttribute}="false"] { + :where(&[${slotSpacerHasCloseButtonAttribute}="false"]) { ${internalSlotSpacerTokens.firstChildMarginTop}: var( ${slotSpacerTokens.firstChildMarginTopNoCloseButton}, ${Spacing["spacing-64"]} @@ -198,31 +216,40 @@ export const slotSpacer = css` } `; -export const fullscreenSlotSpacer = css` - flex-grow: 1; +/** Lets the slot area absorb the leftover height of a size-constrained card. */ +export const fillHeightSlotSpacer = css` + :where(&) { + flex: 1; + min-height: 0; - display: flex; - flex-direction: column; - justify-content: space-between; + display: flex; + flex-direction: column; + justify-content: space-between; + } `; export const headerContainer = css` - display: flex; - align-items: center; - padding: ${Spacing["spacing-16"]}; + :where(&) { + display: flex; + align-items: center; + padding: var(${headerTokens.padding}, ${Spacing["spacing-16"]}); + } - &[data-close-button-position="right"] { + :where(&[data-close-button-position="right"]) { flex-direction: row-reverse; } `; export const headerTitle = css` - ${Font["heading-xs-semibold"]} - color: ${Colour.text}; - flex: 1; - text-align: center; + :where(&) { + ${Font["heading-xs-semibold"]} + color: ${Colour.text}; + flex: 1; + text-align: center; + } `; +/* Also a ClickableIcon — see the note on styledClickableIcon above. */ export const headerCloseButton = css` padding: 0; color: ${Colour.icon}; @@ -235,6 +262,8 @@ export const headerCloseButton = css` `; export const headerSpacer = css` - width: 2rem; - flex-shrink: 0; + :where(&) { + width: 2rem; + flex-shrink: 0; + } `; diff --git a/src/modal-v2/types.ts b/src/modal-v2/types.ts index af3ba85f1..18a346ff4 100644 --- a/src/modal-v2/types.ts +++ b/src/modal-v2/types.ts @@ -22,6 +22,12 @@ export interface ModalCardProps extends React.HTMLAttributes { * padding, or box-shadow. */ fullscreen?: boolean | undefined; + /** + * When `true`, the slot area stretches to absorb any leftover height of a + * size-constrained card. Use this when the card is given an explicit height + * and its content should fill it. Implied by `fullscreen`. + */ + fillHeight?: boolean | undefined; } // @storybookSection ModalV2.CloseButton @@ -40,16 +46,18 @@ export interface ModalCloseButtonProps /** * Props for the `ModalV2.Header` slot. */ -export interface ModalHeaderProps extends React.HTMLAttributes { +export interface ModalHeaderProps + extends Omit, "title"> { /** * @default "modal-header" */ "data-testid"?: string | undefined; /** - * Heading text rendered in the header. Always centered regardless of + * Heading rendered in the header. Accepts a plain string, or a node when + * you need to control the typography. Always centered regardless of * `closeButtonPosition`. Omit for a close-button-only header. */ - title?: string | undefined; + title?: React.ReactNode | undefined; /** * Which side of the header the close button is placed on. The title * alignment adjusts automatically. From a0e9920cb78dbf946c1ce7e2e2b5bb95d70558f0 Mon Sep 17 00:00:00 2001 From: "Ziggy Z." Date: Mon, 21 Sep 2026 16:43:11 +0700 Subject: [PATCH 11/12] [CCUBE-2221][ZZ] story + test: remove redundant story component and adding test case for custom header --- stories/modal-v2/modal-v2.stories.tsx | 31 --------------------------- tests/modal-v2/modal-v2.spec.tsx | 17 +++++++++++++++ 2 files changed, 17 insertions(+), 31 deletions(-) diff --git a/stories/modal-v2/modal-v2.stories.tsx b/stories/modal-v2/modal-v2.stories.tsx index 1b9066809..f8c9879c0 100644 --- a/stories/modal-v2/modal-v2.stories.tsx +++ b/stories/modal-v2/modal-v2.stories.tsx @@ -404,37 +404,6 @@ export const StackedModals: StoryObj = { }, }; -export const Fullscreen: StoryObj = { - render: () => { - const [show, setShow] = useState(false); - const openModal = () => setShow(true); - const closeModal = () => setShow(false); - return ( - <> - - - - - - - This card fills the entire viewport with no - border-radius, padding, or box-shadow. - - - - - - ); - }, -}; - export const ScrollHandling: StoryObj = { render: (_args) => { const [show, setShow] = useState(false); diff --git a/tests/modal-v2/modal-v2.spec.tsx b/tests/modal-v2/modal-v2.spec.tsx index 769916d37..e7cc93d3d 100644 --- a/tests/modal-v2/modal-v2.spec.tsx +++ b/tests/modal-v2/modal-v2.spec.tsx @@ -89,4 +89,21 @@ describe("ModalV2", () => { expect(mockClose).toHaveBeenCalled(); expect(mockOverlayClick).not.toHaveBeenCalled(); }); + + it("should render the Header title and trigger onClose from its close button", () => { + const mockClose = jest.fn(); + render( + + + + + + ); + + expect(screen.getByTestId("modal-header")).toBeInTheDocument(); + expect(screen.getByText("Signature")).toBeInTheDocument(); + + fireEvent.click(screen.getByTestId("close-button")); + expect(mockClose).toHaveBeenCalled(); + }); }); From c087d8288b1d95d6c42980ff351f599100b61a07 Mon Sep 17 00:00:00 2001 From: "Ziggy Z." Date: Mon, 21 Sep 2026 16:43:52 +0700 Subject: [PATCH 12/12] [CCUBE-2221][ZZ] feat: implement changes from modal v2 to e-signature --- src/e-signature/e-signature.styles.ts | 76 ++++++++------------------- src/e-signature/e-signature.tsx | 13 ++++- 2 files changed, 33 insertions(+), 56 deletions(-) diff --git a/src/e-signature/e-signature.styles.ts b/src/e-signature/e-signature.styles.ts index 3f69bf0b0..7c71d83ca 100644 --- a/src/e-signature/e-signature.styles.ts +++ b/src/e-signature/e-signature.styles.ts @@ -1,15 +1,7 @@ import { css } from "@linaria/core"; -import { slotSpacerTokens } from "../modal-v2/slots/slot-styles"; -import { - Border, - Colour, - Font, - MediaQuery, - Radius, - Shadow, - Spacing, -} from "../theme"; +import { headerTokens, slotSpacerTokens } from "../modal-v2/slots/slot-styles"; +import { Border, Colour, MediaQuery, Radius, Shadow, Spacing } from "../theme"; // ----------------------------------------------------------------------------- // MAIN FIELD @@ -76,38 +68,20 @@ export const instructions = css` // ----------------------------------------------------------------------------- export const modalCard = css` - && { - width: 100%; - height: 29rem; - max-width: 672px; - max-height: none; - margin: 0 auto; - padding: ${Spacing["spacing-16"]}; - box-shadow: ${Shadow["lg-strong"]}; - } - - & > [data-has-close-button] { - flex: 1; - display: flex; - flex-direction: column; - min-height: 0; + width: 100%; + height: 29rem; + max-width: 672px; + max-height: none; + margin: 0 auto; + padding: ${Spacing["spacing-16"]}; + box-shadow: ${Shadow["lg-strong"]}; - ${slotSpacerTokens.contentLastChildMarginBottom}: 0; - } + ${slotSpacerTokens.contentLastChildMarginBottom}: 0; `; export const modalHeader = css` - && { - padding: 0 0 ${Spacing["spacing-16"]}; - position: relative; - } - - & > span { - ${Font["body-baseline-semibold"]} - flex: unset; - width: 100%; - text-align: center; - } + ${headerTokens.padding}: 0 0 ${Spacing["spacing-16"]}; + position: relative; & > button { position: absolute; @@ -121,11 +95,8 @@ export const modalHeader = css` ${MediaQuery.MaxWidth.sm} { &[data-mobile-landscape] { - padding: ${Spacing["spacing-12"]} ${Spacing["spacing-20"]}; - } - - &[data-mobile-landscape] > span { - ${Font["body-md-semibold"]} + ${headerTokens.padding}: ${Spacing["spacing-12"]} + ${Spacing["spacing-20"]}; } &[data-mobile-landscape] > button { @@ -135,23 +106,18 @@ export const modalHeader = css` } &[data-mobile-landscape="true"] { - padding: ${Spacing["spacing-12"]} ${Spacing["spacing-20"]}; - - & > span { - ${Font["body-md-semibold"]} - } + ${headerTokens.padding}: ${Spacing["spacing-12"]} + ${Spacing["spacing-20"]}; + } - & > button { - top: ${Spacing["spacing-8"]}; - right: ${Spacing["spacing-20"]}; - } + &[data-mobile-landscape="true"] > button { + top: ${Spacing["spacing-8"]}; + right: ${Spacing["spacing-20"]}; } `; export const modalContent = css` - && { - margin: 0; - } + margin: 0; display: flex; flex-direction: column; min-height: 0; diff --git a/src/e-signature/e-signature.tsx b/src/e-signature/e-signature.tsx index 9d167101f..2451e4301 100644 --- a/src/e-signature/e-signature.tsx +++ b/src/e-signature/e-signature.tsx @@ -151,9 +151,20 @@ export const ESignature = (props: EsignatureProps) => { className={styles.modalCard} data-mobile-landscape={isMobileLandscape} fullscreen={isMobile || isMobileLandscape} + fillHeight > + Signature + + ) : ( + + Signature + + ) + } closeButtonPosition="right" className={styles.modalHeader} data-mobile-landscape={isMobileLandscape}