diff --git a/packages/@react-spectrum/ai/stories/Alert.stories.tsx b/packages/@react-spectrum/ai/stories/Alert.stories.tsx index 1ba553a12f4..e7cfc08ad03 100644 --- a/packages/@react-spectrum/ai/stories/Alert.stories.tsx +++ b/packages/@react-spectrum/ai/stories/Alert.stories.tsx @@ -42,7 +42,8 @@ export default meta; type Story = StoryObj; export const Example: Story = { - render: args => + // Storybook uses 16px padding left and right + render: args => }; const VARIANTS = ['informative', 'positive', 'notice', 'negative', 'neutral'] as const; @@ -52,7 +53,12 @@ export const AllVariants: Story = { render: args => (
{VARIANTS.map(variant => ( - + ))}
), diff --git a/packages/@react-spectrum/ai/stories/ResponseStatus.stories.tsx b/packages/@react-spectrum/ai/stories/ResponseStatus.stories.tsx index a5dac4e2e95..fa766be60ca 100644 --- a/packages/@react-spectrum/ai/stories/ResponseStatus.stories.tsx +++ b/packages/@react-spectrum/ai/stories/ResponseStatus.stories.tsx @@ -66,7 +66,7 @@ type Story = StoryObj; export const Example: Story = { render: args => ( -
+
{args.status === 'pending' @@ -86,7 +86,7 @@ export const Example: Story = { export const NoResponseContent: Story = { render: args => ( -
+
{args.status === 'pending' @@ -228,7 +228,7 @@ function WithExecutionTraceRender(args) { return (
): void { }); } +type Scheme = 'light' | 'dark'; + +function getDocumentColorScheme(): Scheme { + return document.documentElement.getAttribute('data-color-scheme') === 'dark' ? 'dark' : 'light'; +} + +function useStorybookColorScheme(): Scheme { + const [colorScheme, setColorScheme] = useState(getDocumentColorScheme); + useEffect(() => { + const docEl = document.documentElement; + const update = () => setColorScheme(getDocumentColorScheme()); + update(); + const observer = new MutationObserver(update); + observer.observe(docEl, {attributes: true, attributeFilter: ['data-color-scheme']}); + return () => observer.disconnect(); + }, []); + return colorScheme; +} + +/** + * The app rendered into the nested shadow root. It tracks Storybook's color scheme itself and + * passes it to ``, so the scheme updates through React state within this + * root. + */ +function ShadowApp({portalContainerRef}: {portalContainerRef: {current: HTMLDivElement | null}}) { + const colorScheme = useStorybookColorScheme(); + return ( + + portalContainerRef.current}> + + + + ); +} + function ShadowDOMContained() { const hostRef = useRef(null); const portalContainerRef = useRef(null); @@ -178,12 +213,6 @@ function ShadowDOMContained() { const shadowRoot = host.attachShadow({mode: 'open'}); - // So S2 theme variables apply: :host in the copied CSS targets the shadow host. - const scheme = document.documentElement.getAttribute('data-color-scheme'); - if (scheme) { - host.setAttribute('data-color-scheme', scheme); - } - // Copy all styles from the document into the shadow root so S2 (and Storybook) styles apply. // Shadow DOM does not inherit styles; we must duplicate every stylesheet. shadowRoot.appendChild(createClonedDocumentStyleRoot()); @@ -199,13 +228,7 @@ function ShadowDOMContained() { const root = createRoot(appContainer); rootRef.current = root; - root.render( - - portalContainerRef.current}> - - - - ); + root.render(); return () => { rootRef.current = null; @@ -233,13 +256,6 @@ function ShadowDOMPortalToBody() { const shadowRoot = host.attachShadow({mode: 'open'}); const shadowPortal = portalHost.attachShadow({mode: 'open'}); - // So S2 theme variables apply: :host in the copied CSS targets the shadow host. - const scheme = document.documentElement.getAttribute('data-color-scheme'); - if (scheme) { - host.setAttribute('data-color-scheme', scheme); - portalHost.setAttribute('data-color-scheme', scheme); - } - // Each shadow root needs its own style clone — reusing one node only leaves styles in the last root. shadowRoot.appendChild(createClonedDocumentStyleRoot()); shadowPortal.appendChild(createClonedDocumentStyleRoot()); @@ -255,13 +271,8 @@ function ShadowDOMPortalToBody() { const root = createRoot(appContainer); rootRef.current = root; - root.render( - - portalContainerRef.current}> - - - - ); + // The portaled overlays inherit colorScheme through the Provider context, so both shadows theme. + root.render(); return () => { rootRef.current = null; @@ -557,7 +568,9 @@ function AllComponents() { )}> - Name + + Name + Value