You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Extend StorybookTheme.tsx to support 'dynamic' system appearance and a
Flex-authored theme, replace hard-coded hex values in the toolbar chrome with
token-derived values, and add deterministic tests that exercise theme selection
and validate toolbar behavior on both macOS and Windows.
The Storybook toolbar is the only runtime surface that exercises the full
theme-switching flow. Its current four choices all use createDefaultTheme, it
cannot exercise 'dynamic' appearance or the Flex-value context, and the
toolbar styles are literal hex values that are inconsistent with the theming
patterns the workstream is establishing.
Goal
After this task, the Storybook toolbar adds a 'dynamic' system-appearance
option, a Flex-authored-theme option, and token-sourced toolbar chrome. Tests
confirm that each toolbar choice produces the expected context value, that the
toolbar is functional on macOS and Windows, and that CI does not depend on the
host machine's system appearance.
Stage
Stage 2 - Beta delivery.
Why it matters
Observed. The toolbar hard-codes four createDefaultTheme calls and has
no 'dynamic' option, so a developer running the Storybook cannot trigger the
system-appearance code path without modifying source
(apps/storybook/src/StorybookTheme.tsx).
Observed. No toolbar option exercises the Flex-value context. Every choice
is a ThemeReference built from a Fluent Theme, so a Flex-authored theme
has no integration exercise in the Storybook today.
Observed. The toolbar StyleSheet contains eleven literal hex values
(#f5f5f5, #d1d1d1, #242424, #ffffff, #b3b3b3, #0f6cbd) that
duplicate design token values rather than sourcing them from the token system
(StorybookTheme.tsx styles block).
Observed. The Windows smoke test
(apps/storybook/windows-tests/storybook-smoke.test.cjs) does not exercise
any theme button, so the toolbar is not covered by automated validation on
Windows.
Inferred. Without a 'dynamic' integration test, a regression in
appearance-change notification or ThemeState invalidation on macOS or
Windows could ship silently.
Inferred. Toolbar colors derived from literals are inconsistent with themedStyleSheetFactory usage across agentic components and create a
maintenance burden when brand or neutral token values change.
Observed current state
Observed.themeChoiceNames is ['none', 'light', 'dark', 'highContrast']. themeChoices builds each entry with createDefaultTheme from @fluentui-react-native/default-theme; 'none' omits the theme entirely
(StorybookTheme.tsx lines 12-20).
Observed.StorybookThemeProvider (used as a story decorator in preview.tsx)
reads the ThemeReference from StorybookThemeContext and conditionally
renders <ThemeProvider theme={theme}>. No Flex-value context provider is
present.
Observed.StorybookThemeHost in StorybookApp.tsx
wraps the entire Storybook UI and is the root that renders the toolbar.
The toolbar sits outside the story-level ThemeProvider, so it currently has
no access to the Flex tokens of the selected theme.
Observed. Toolbar testID values are already stable: agentic-storybook-theme-toolbar on the containing View and agentic-storybook-theme-${name} on each button, providing reliable
automation targets for both macOS accessibility IDs and Windows UIA selectors.
Observed. The Windows smoke test locates story elements by testID using @react-native-windows/automation but makes no reference to any theme button
(storybook-smoke.test.cjs).
Observed. System appearance handling is split across four platformUtils
files and ThemeState does not expose the resolved scheme; this is the
subject of System Appearance Handling.
Scope
Add a 'dynamic' toolbar option that constructs a theme using the 'dynamic' appearance value and relies on the platform subscription defined
in System Appearance Handling to re-render when the
system appearance changes.
Add a Flex theme toolbar option that wraps stories with the Flex-value context
provider defined in Dynamic Theme Building,
supplying a minimal Flex-authored token set so the full context path is
exercised without a Fluent Theme present.
Replace the literal hex values in the toolbar StyleSheet with values sourced
from the Flex token set. The toolbar chrome must remain functional when no
theme is selected (the 'none' case), so it requires a stable base token set
that does not depend on a story-level ThemeProvider.
Add unit tests (Jest, host environment) that render StorybookThemeHost and
assert: each button sets the expected context value, StorybookThemeProvider
wraps with ThemeProvider only when a theme is selected, and selecting the
Flex option activates the Flex-value context instead of ThemeProvider.
Extend the Windows smoke test to locate and activate at least the light and
dark toolbar buttons by their stable testID values and confirm the toolbar
is present and interactive after each selection.
Document the macOS validation steps: verifying that selecting 'dynamic'
with macOS system appearance toggled between light and dark re-renders the
story with updated tokens.
Provide a deterministic CI strategy so 'dynamic' appearance selections do
not make snapshot or token-equality tests dependent on the host machine's
system appearance setting.
Out of scope
Implementing 'dynamic' appearance resolution and the platform subscription
mechanism; see System Appearance Handling.
Defining the Flex-value context type and making useFlexTokens context-aware;
see Dynamic Theme Building.
Generating default Flex token values or adding appearance-specific token sets;
see Default Values Codegen.
Building a macOS or Windows platform theme against the Flex contract; see Apple Theme.
Deliverables
An extended themeChoiceNames tuple that includes 'dynamic' and a Flex
theme option, with corresponding themeChoices entries.
A token-sourced toolbar StyleSheet that reads chrome colors from the Flex
token set, with a documented fallback for the 'none' case.
A Flex-value context provider path in StorybookThemeProvider that activates
when the Flex theme option is selected.
Unit tests covering all toolbar choices, context wrapping, and the Flex
context path.
An extended Windows smoke test that exercises the theme toolbar buttons.
A macOS validation note documenting the manual appearance-toggle verification
steps and the expected re-render behavior.
A CI determinism note or implementation specifying how 'dynamic' is handled
in tests (for example, forcing a fixed system appearance in Jest or skipping
appearance-dependent assertions).
Changesets.
Acceptance criteria
The toolbar exposes a 'dynamic' option that activates a theme constructed
with appearance: 'dynamic', and a system appearance change on macOS
re-renders the story without a crash.
The toolbar exposes a Flex theme option that supplies tokens through the
Flex-value context defined in Dynamic Theme Building
without constructing a Fluent Theme.
The toolbar StyleSheet contains no hex literals; all chrome colors are
derived from the Flex token set, and the 'none' case renders the toolbar
with a stable default without accessing an undefined token.
Existing testID values (agentic-storybook-theme-toolbar, agentic-storybook-theme-none, agentic-storybook-theme-light, agentic-storybook-theme-dark, agentic-storybook-theme-highContrast,
plus any new entries) remain stable and are findable by Windows UIA and
macOS accessibility.
Unit tests pass: each toolbar choice produces the correct context value, StorybookThemeProvider wraps with ThemeProvider for Fluent choices and
with the Flex context provider for the Flex choice, and 'none' renders
children without either.
The Windows smoke test locates the theme toolbar, activates the light and
dark buttons, and confirms the toolbar element remains displayed after each
selection.
CI test runs do not fail or produce different results depending on the host
machine's system appearance setting.
yarn build, yarn lage test, and yarn lage lint pass at the
repository root, and changesets are present.
Dependencies and ordering
Depends on Dynamic Theme Building (Stage 1) for
the Flex-value context type and the context-aware useFlexTokens. The Flex
theme option cannot be wired until that context exists and a minimal Flex token
set can be supplied.
Depends on System Appearance Handling (Stage 2) for
the 'dynamic' appearance value to be reliably resolved into a concrete scheme.
The dynamic toolbar option can be scaffolded before that task lands, but its
subscription behavior and the macOS and Windows validation steps cannot be
completed until the structured appearance model is in place.
Should follow Package Consolidation so the Flex
context type and the toolbar's token imports resolve from their final submodule
paths in @fluentui-react-native/design.
Risks and open decisions
Open decision. Which Flex token set the toolbar chrome uses when 'none'
is selected. Observed:defaultFlexTokens is always available as the
module-level default in defaultTokens.ts, so it is the natural fallback.
The owner should confirm whether the chrome should always render with the
default Flex tokens or should follow whatever the selected theme supplies.
Open decision. Whether the Flex toolbar option uses the generated default
Flex tokens or a small authored override set. Inferred: using the generated
defaults keeps the option stateless but exercises less of the override path;
a small authored set with a visible brand color change would make the Flex
context visually distinguishable from the existing 'light' choice. This
interacts with Default Values Codegen.
Open decision. Whether 'dynamic' should be disabled or hidden on
platforms where the system appearance subscription is not available. Observed:getCurrentAppearance on the default platform falls back to
the defaultAppearance value, so a 'dynamic' theme is safe to construct on
all platforms but may not respond to system changes everywhere.
Open decision. How to make CI deterministic for the 'dynamic' option.
Options include: (a) mock Appearance.getColorScheme to return 'light' in
Jest, (b) exclude 'dynamic' from snapshot tests and cover it only with
interaction tests that do not assert token values, or (c) use a controlled ThemeReference that forces a fixed appearance in test environments. The
chosen approach must be documented in the test file.
Risk. Token-sourced chrome requires useFlexTokens (or useThemeState)
to be callable outside the story-level ThemeProvider. If the chrome hook is
called from StorybookThemeHost before any ThemeProvider is mounted, it
must safely return the default token set; the current context-free
implementation in useFlexTokens.ts already does this, but the updated
context-aware version must preserve that fallback.
Risk. The toolbar sits outside StorybookThemeProvider, which is the
story-level decorator. Adding a Flex context provider there does not affect the
toolbar, so the two providers are structurally separate. A design where the
chrome uses story-level tokens (the Flex choice) would require re-ordering the
provider hierarchy, which may affect story rendering.
Summary
Extend
StorybookTheme.tsxto support'dynamic'system appearance and aFlex-authored theme, replace hard-coded hex values in the toolbar chrome with
token-derived values, and add deterministic tests that exercise theme selection
and validate toolbar behavior on both macOS and Windows.
The Storybook toolbar is the only runtime surface that exercises the full
theme-switching flow. Its current four choices all use
createDefaultTheme, itcannot exercise
'dynamic'appearance or the Flex-value context, and thetoolbar styles are literal hex values that are inconsistent with the theming
patterns the workstream is establishing.
Goal
After this task, the Storybook toolbar adds a
'dynamic'system-appearanceoption, a Flex-authored-theme option, and token-sourced toolbar chrome. Tests
confirm that each toolbar choice produces the expected context value, that the
toolbar is functional on macOS and Windows, and that CI does not depend on the
host machine's system appearance.
Stage
Stage 2 - Beta delivery.
Why it matters
createDefaultThemecalls and hasno
'dynamic'option, so a developer running the Storybook cannot trigger thesystem-appearance code path without modifying source
(
apps/storybook/src/StorybookTheme.tsx).is a
ThemeReferencebuilt from a FluentTheme, so a Flex-authored themehas no integration exercise in the Storybook today.
StyleSheetcontains eleven literal hex values(
#f5f5f5,#d1d1d1,#242424,#ffffff,#b3b3b3,#0f6cbd) thatduplicate design token values rather than sourcing them from the token system
(
StorybookTheme.tsxstyles block).(
apps/storybook/windows-tests/storybook-smoke.test.cjs) does not exerciseany theme button, so the toolbar is not covered by automated validation on
Windows.
'dynamic'integration test, a regression inappearance-change notification or
ThemeStateinvalidation on macOS orWindows could ship silently.
themedStyleSheetFactoryusage across agentic components and create amaintenance burden when brand or neutral token values change.
Observed current state
themeChoiceNamesis['none', 'light', 'dark', 'highContrast'].themeChoicesbuilds each entry withcreateDefaultThemefrom@fluentui-react-native/default-theme;'none'omits the theme entirely(
StorybookTheme.tsxlines 12-20).StorybookThemeProvider(used as a story decorator inpreview.tsx)reads the
ThemeReferencefromStorybookThemeContextand conditionallyrenders
<ThemeProvider theme={theme}>. No Flex-value context provider ispresent.
StorybookThemeHostinStorybookApp.tsxwraps the entire Storybook UI and is the root that renders the toolbar.
The toolbar sits outside the story-level
ThemeProvider, so it currently hasno access to the Flex tokens of the selected theme.
testIDvalues are already stable:agentic-storybook-theme-toolbaron the containingViewandagentic-storybook-theme-${name}on each button, providing reliableautomation targets for both macOS accessibility IDs and Windows UIA selectors.
testIDusing@react-native-windows/automationbut makes no reference to any theme button(
storybook-smoke.test.cjs).useFlexTokenscurrently ignores context and always returnsdefaultFlexTokens(
packages/agentic/design/src/tokens/useFlexTokens.ts);this is noted as temporary in
PR #4156
and is the subject of Dynamic Theme Building.
platformUtilsfiles and
ThemeStatedoes not expose the resolved scheme; this is thesubject of System Appearance Handling.
Scope
'dynamic'toolbar option that constructs a theme using the'dynamic'appearance value and relies on the platform subscription definedin System Appearance Handling to re-render when the
system appearance changes.
provider defined in Dynamic Theme Building,
supplying a minimal Flex-authored token set so the full context path is
exercised without a Fluent
Themepresent.StyleSheetwith values sourcedfrom the Flex token set. The toolbar chrome must remain functional when no
theme is selected (the
'none'case), so it requires a stable base token setthat does not depend on a story-level
ThemeProvider.StorybookThemeHostandassert: each button sets the expected context value,
StorybookThemeProviderwraps with
ThemeProvideronly when a theme is selected, and selecting theFlex option activates the Flex-value context instead of
ThemeProvider.dark toolbar buttons by their stable
testIDvalues and confirm the toolbaris present and interactive after each selection.
'dynamic'with macOS system appearance toggled between light and dark re-renders the
story with updated tokens.
'dynamic'appearance selections donot make snapshot or token-equality tests dependent on the host machine's
system appearance setting.
Out of scope
'dynamic'appearance resolution and the platform subscriptionmechanism; see System Appearance Handling.
useFlexTokenscontext-aware;see Dynamic Theme Building.
see Default Values Codegen.
Apple Theme.
Deliverables
themeChoiceNamestuple that includes'dynamic'and a Flextheme option, with corresponding
themeChoicesentries.StyleSheetthat reads chrome colors from the Flextoken set, with a documented fallback for the
'none'case.StorybookThemeProviderthat activateswhen the Flex theme option is selected.
context path.
steps and the expected re-render behavior.
'dynamic'is handledin tests (for example, forcing a fixed system appearance in Jest or skipping
appearance-dependent assertions).
Acceptance criteria
'dynamic'option that activates a theme constructedwith
appearance: 'dynamic', and a system appearance change on macOSre-renders the story without a crash.
Flex-value context defined in Dynamic Theme Building
without constructing a Fluent
Theme.StyleSheetcontains no hex literals; all chrome colors arederived from the Flex token set, and the
'none'case renders the toolbarwith a stable default without accessing an undefined token.
testIDvalues (agentic-storybook-theme-toolbar,agentic-storybook-theme-none,agentic-storybook-theme-light,agentic-storybook-theme-dark,agentic-storybook-theme-highContrast,plus any new entries) remain stable and are findable by Windows UIA and
macOS accessibility.
StorybookThemeProviderwraps withThemeProviderfor Fluent choices andwith the Flex context provider for the Flex choice, and
'none'renderschildren without either.
dark buttons, and confirms the toolbar element remains displayed after each
selection.
machine's system appearance setting.
yarn build,yarn lage test, andyarn lage lintpass at therepository root, and changesets are present.
Dependencies and ordering
Depends on Dynamic Theme Building (Stage 1) for
the Flex-value context type and the context-aware
useFlexTokens. The Flextheme option cannot be wired until that context exists and a minimal Flex token
set can be supplied.
Depends on System Appearance Handling (Stage 2) for
the
'dynamic'appearance value to be reliably resolved into a concrete scheme.The dynamic toolbar option can be scaffolded before that task lands, but its
subscription behavior and the macOS and Windows validation steps cannot be
completed until the structured appearance model is in place.
Should follow Package Consolidation so the Flex
context type and the toolbar's token imports resolve from their final submodule
paths in
@fluentui-react-native/design.Risks and open decisions
'none'is selected. Observed:
defaultFlexTokensis always available as themodule-level default in
defaultTokens.ts, so it is the natural fallback.The owner should confirm whether the chrome should always render with the
default Flex tokens or should follow whatever the selected theme supplies.
Flex tokens or a small authored override set. Inferred: using the generated
defaults keeps the option stateless but exercises less of the override path;
a small authored set with a visible brand color change would make the Flex
context visually distinguishable from the existing
'light'choice. Thisinteracts with Default Values Codegen.
'dynamic'should be disabled or hidden onplatforms where the system appearance subscription is not available.
Observed:
getCurrentAppearanceon the default platform falls back tothe
defaultAppearancevalue, so a'dynamic'theme is safe to construct onall platforms but may not respond to system changes everywhere.
'dynamic'option.Options include: (a) mock
Appearance.getColorSchemeto return'light'inJest, (b) exclude
'dynamic'from snapshot tests and cover it only withinteraction tests that do not assert token values, or (c) use a controlled
ThemeReferencethat forces a fixed appearance in test environments. Thechosen approach must be documented in the test file.
useFlexTokens(oruseThemeState)to be callable outside the story-level
ThemeProvider. If the chrome hook iscalled from
StorybookThemeHostbefore anyThemeProvideris mounted, itmust safely return the default token set; the current context-free
implementation in
useFlexTokens.tsalready does this, but the updatedcontext-aware version must preserve that fallback.
StorybookThemeProvider, which is thestory-level decorator. Adding a Flex context provider there does not affect the
toolbar, so the two providers are structurally separate. A design where the
chrome uses story-level tokens (the Flex choice) would require re-ordering the
provider hierarchy, which may affect story rendering.
Evidence and references
apps/storybook/src/StorybookTheme.tsx: current toolbar implementation with four fixed choices and literal hex styles.apps/storybook/src/preview.tsx:StorybookThemeProviderused as a story-level decorator.apps/storybook/src/StorybookApp.tsx:StorybookThemeHostas the root wrapper.apps/storybook/windows-tests/storybook-smoke.test.cjs: Windows automation test that exercises storytestIDvalues but not the theme toolbar.apps/storybook/scripts/smoke-stories.json: smoke-test story index.packages/agentic/design/src/tokens/useFlexTokens.ts: temporary context-free implementation; context-awareness is the subject of Dynamic Theme Building.packages/agentic/design/src/useThemeState.ts:ThemeState, caching, andthemedStyleSheetFactory.packages/agentic/design/src/tokens/defaultTokens.ts:defaultFlexTokensas the fallback token set.packages/agentic/design/src/theming/types/Theme.types.ts:AppearanceOptionsincluding'dynamic'.'dynamic'resolution and the platform subscription model that this task's dynamic toolbar option depends on.useFlexTokensthat this task's Flex theme option depends on.'none'chrome fallback and potentially the Flex theme option.