From db930638767a2952a4c729fb1335c834651ab64f Mon Sep 17 00:00:00 2001 From: Boram Yi Date: Fri, 11 Sep 2026 10:30:03 -0400 Subject: [PATCH] feat: SW-2592 raised surface for DataAppShellRightPanel MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The docked panel painted bg-background — the same token as — so it read as a column of the page rather than a surface on it. Give it (and the overlay Sheet) a bg-card surface with a tinted accent header cap via a new `surface` prop ("raised" default | "flat"). bg-card maps to --surface-bright in both themes, so it stays raised in dark where bg-sidebar (which resolves to --surface = the body colour in dark) would not. Surface only — no docking changes. Co-Authored-By: Claude Opus 4.8 --- .../DataAppShell/DataAppShell.stories.tsx | 12 ++++++++ .../composed/DataAppShell/RightPanel.tsx | 28 +++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/src/components/composed/DataAppShell/DataAppShell.stories.tsx b/src/components/composed/DataAppShell/DataAppShell.stories.tsx index 5e2d6b93..567531ff 100644 --- a/src/components/composed/DataAppShell/DataAppShell.stories.tsx +++ b/src/components/composed/DataAppShell/DataAppShell.stories.tsx @@ -1019,6 +1019,18 @@ export const WithRightPanel: Story = { const panel = await canvas.findByRole("complementary", { name: "Details" }); await waitFor(() => expect(panel).toBeVisible()); }); + + await step("Raised surface: the panel reads as a surface on the page, not part of it (SW-2592)", async () => { + const panel = canvas.getByRole("complementary", { name: "Details" }); + const main = canvasElement.querySelector("main"); + // The docked panel (bg-card) must not share the page ground (bg-background). + expect(main).not.toBeNull(); + expect(getComputedStyle(panel).backgroundColor).not.toBe(getComputedStyle(main!).backgroundColor); + // Header carries the tinted accent cap, distinct again from the panel body. + const header = panel.querySelector('[data-slot="data-app-shell-right-panel-header"]') as HTMLElement; + expect(header).not.toBeNull(); + expect(getComputedStyle(header).backgroundColor).not.toBe(getComputedStyle(panel).backgroundColor); + }); }, parameters: { zephyr: { testCaseId: "SW-T5535" }, diff --git a/src/components/composed/DataAppShell/RightPanel.tsx b/src/components/composed/DataAppShell/RightPanel.tsx index 4ba6a458..922215d9 100644 --- a/src/components/composed/DataAppShell/RightPanel.tsx +++ b/src/components/composed/DataAppShell/RightPanel.tsx @@ -255,6 +255,16 @@ export interface DataAppShellRightPanelProps extends Omit {icon != null && {icon}} {title != null && {title}} @@ -421,7 +440,9 @@ function DataAppShellRightPanel({ closeFocusRef?.current?.focus({ preventScroll: true }); }} style={{ width }} - className={cn("gap-0 data-[side=right]:sm:max-w-none", className)} + // Sheet defaults to bg-background — override so the overlay variant + // matches the docked variant's surface (SW-2592). + className={cn("gap-0 data-[side=right]:sm:max-w-none", surfaceClass, className)} {...props} > {accessibleName} @@ -445,7 +466,8 @@ function DataAppShellRightPanel({ aria-label={accessibleName} style={{ width }} className={cn( - "relative flex h-full shrink-0 flex-col overflow-hidden border-l border-border bg-background", + "relative flex h-full shrink-0 flex-col overflow-hidden border-l border-border", + surfaceClass, "motion-safe:animate-in motion-safe:fade-in-0 motion-safe:slide-in-from-right-4", !dragging && "motion-safe:transition-[width] motion-safe:duration-200", className,