microsoft / microsoft/fluentui-react-native
Theming: Storybook Appearance Integration
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 1.4k
- Forks
- 179
- Avg merge
- 16h 17m
- Merged PRs (30d)
- 30
Description
Summary
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
createDefaultThemecalls 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 aThemeReferencebuilt from a FluentTheme, so a Flex-authored theme
has no integration exercise in the Storybook today. - Observed. The toolbar
StyleSheetcontains eleven literal hex values
(#f5f5f5,#d1d1d1,#242424,#ffffff,#b3b3b3,#0f6cbd) that
duplicate design token values rather than sourcing them from the token system
(StorybookTheme.tsxstyles 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 orThemeStateinvalidation on macOS or
Windows could ship silently. - Inferred. Toolbar colors derived from literals are inconsistent with
themedStyleSheetFactoryusage across agentic components and create a
maintenance burden when brand or neutral token values change.
Observed current state
- Observed.
themeChoiceNamesis['none', 'light', 'dark', 'highContrast'].
themeChoicesbuilds each entry withcreateDefaultThemefrom
@fluentui-react-native/default-theme;'none'omits the theme entirely
(StorybookTheme.tsxlines 12-20). - Observed.
StorybookThemeProvider(used as a story decorator in
preview.tsx)
reads theThemeReferencefromStorybookThemeContextand conditionally
renders<ThemeProvider theme={theme}>. No Flex-value context provider is
present. - Observed.
StorybookThemeHostin
StorybookApp.tsx
wraps the entire Storybook UI and is the root that renders the toolbar.
The toolbar sits outside the story-levelThemeProvider, so it currently has
no access to the Flex tokens of the selected theme. - Observed. Toolbar
testIDvalues are already stable:
agentic-storybook-theme-toolbaron the containingViewand
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
testIDusing
@react-native-windows/automationbut makes no reference to any theme button
(storybook-smoke.test.cjs). - Observed.
useFlexTokenscurrently ignores context and always returns
defaultFlexTokens
(packages/agentic/design/src/tokens/useFlexTokens.ts);
this is noted as temporary in
PR #4156
and is the subject of Dynamic Theme Building. - Observed. System appearance handling is split across four
platformUtils
files andThemeStatedoes 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 FluentThemepresent. - Replace the literal hex values in the toolbar
StyleSheetwith 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-levelThemeProvider. - Add unit tests (Jest, host environment) that render
StorybookThemeHostand
assert: each button sets the expected context value,StorybookThemeProvider
wraps withThemeProvideronly when a theme is selected, and selecting the
Flex option activates the Flex-value context instead ofThemeProvider. - Extend the Windows smoke test to locate and activate at least the light and
dark toolbar buttons by their stabletestIDvalues 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
useFlexTokenscontext-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
themeChoiceNamestuple that includes'dynamic'and a Flex
theme option, with correspondingthemeChoicesentries. - A token-sourced toolbar
StyleSheetthat reads chrome colors from the Flex
token set, with a documented fallback for the'none'case. - A Flex-value context provider path in
StorybookThemeProviderthat 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
withappearance: '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 FluentTheme. - The toolbar
StyleSheetcontains 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
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. - Unit tests pass: each toolbar choice produces the correct context value,
StorybookThemeProviderwraps withThemeProviderfor 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, andyarn lage lintpass 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:defaultFlexTokensis always available as the
module-level default indefaultTokens.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:getCurrentAppearanceon the default platform falls back to
thedefaultAppearancevalue, 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) mockAppearance.getColorSchemeto 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
ThemeReferencethat forces a fixed appearance in test environments. The
chosen approach must be documented in the test file. - Risk. Token-sourced chrome requires
useFlexTokens(oruseThemeState)
to be callable outside the story-levelThemeProvider. If the chrome hook is
called fromStorybookThemeHostbefore anyThemeProvideris mounted, it
must safely return the default token set; the current context-free
implementation inuseFlexTokens.tsalready 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.
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'.- System Appearance Handling: owns
'dynamic'resolution and the platform subscription model that this task's dynamic toolbar option depends on. - Dynamic Theme Building: owns the Flex-value context type and context-aware
useFlexTokensthat this task's Flex theme option depends on. - Package Consolidation: defines the final submodule paths that this task imports from.
- Default Values Codegen: determines what the default Flex token set contains for the
'none'chrome fallback and potentially the Flex theme option.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with apps/storybook/src/StorybookTheme.tsx, then trace StorybookThemeProvider in preview.tsx and StorybookThemeHost in StorybookApp.tsx. Read useFlexTokens.ts and the linked dependency issues before proceeding, and run apps/storybook/windows-tests/storybook-smoke.test.cjs. Done means all toolbar choices and context paths are tested, Windows light/dark interaction works, dynamic behavior is deterministic, macOS validation is documented, root checks pass, and changesets are present.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react-native, typescript
- Domain
- design, frontend, testing-qa
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 45/100