Skip to content

Theming: High-Contrast Token Source Consolidation #4265

Description

@JasonVMo

Summary

Extract the PlatformColor-remapping logic shared by the three high-contrast alias
token files into a single internal utility, and eliminate the byte-for-byte duplicate
that win32-theme carries of the theme-tokens Win32 variant.

The Windows/UWP name transform (SystemColor*Color) and the Win32 name transform
(raw system color name) are intentional platform differences that must be preserved
exactly. This task shares the mechanism without silently unifying the behavior.

Goal

Reduce the processAliasTokens body to one definition, called from both platform
variants in theme-tokens, and replace win32-theme's local copy with an import
from @fluentui-react-native/theme-tokens, which win32-theme already depends on.

Stage

Stage 1 - Beta foundations.

Why it matters

  • Observed. packages/theming/theme-tokens/src/highContrast/tokens-alias.win32.ts
    and packages/theming/win32-theme/src/highContrast/tokens-alias.ts are
    byte-for-byte identical: same JSON import, same processAliasTokens body, same
    hcAliasTokens export. A diff of the two files produces no output.
  • Observed. A bug fix or behavior change in the Win32 PlatformColor remapping
    path must be applied in two places by hand. The duplication has already allowed the
    two Win32 files to exist without any comment explaining why a copy lives in
    win32-theme instead of importing from theme-tokens.
  • Observed. No unit test exists for processAliasTokens in either package.
    The only high-contrast coverage is the win32-theme snapshot suite, which
    exercises createOfficeColorAliasTokens for the HighContrast case and captures
    round-trip output, but does not assert either name-transform rule directly.
  • Inferred. Consolidating before
    Package Consolidation is executed avoids migrating
    duplicated code into the design package and having to reconcile the copies there.

Observed current state

The three implementations

All three files import
@fluentui-react-native/design-tokens-win32/hc/tokens-aliases.json and export
hcAliasTokens. They differ only in how they rewrite the string-encoded
PlatformColor(name) entries found in the JSON.

Intentional name-transform difference

  • Observed. The Windows/UWP PlatformColor API (react-native-windows) expects
    CSS4 system-color names of the form SystemColorButtonFaceColor. The Win32
    PlatformColor API (@office-iss/react-native-win32) expects raw Win32 system
    color names of the form ButtonFace. The two formats are not interchangeable;
    passing the wrong format to either API produces incorrect or missing colors at
    runtime.
  • Inferred. This difference is a load-bearing platform contract. Any shared
    utility must accept the name transform as a parameter rather than encoding one
    behavior.

Consumers and package boundary

  • Observed.
    packages/theming/theme-tokens/src/getTokens.ts
    imports { hcAliasTokens } from ./highContrast/tokens-alias and returns it for
    mode === 'highContrast'. The React Native bundler resolves the .win32.ts
    override on Win32 and falls back to .ts on other platforms.
  • Observed.
    packages/theming/win32-theme/src/getOfficeTokens.ts
    imports { hcAliasTokens } from ./highContrast/tokens-alias (the local
    duplicate) and returns it for officeTheme === 'HighContrast'.
  • Observed. win32-theme already declares
    @fluentui-react-native/theme-tokens as a direct dependency in its
    package.json,
    so no new package-level dependency is required to remove the local copy.

Test coverage

  • Observed. packages/theming/theme-tokens has no __tests__ directory and no
    unit tests for the high-contrast alias processing.
  • Observed.
    packages/theming/win32-theme/src/__tests__/win32-theme.test.ts
    covers createOfficeColorAliasTokens and createOfficeShadowAliasTokens for
    each of the five office themes, including HighContrast, through Jest snapshots.
    The snapshots provide round-trip coverage but do not assert either name-transform
    rule directly.

Scope

  • Extract the processAliasTokens logic into a single internal utility inside
    packages/theming/theme-tokens/src/highContrast/ that accepts the alias token
    object and a name-transform function, and returns the remapped result.
  • Update tokens-alias.ts (Windows/UWP) and tokens-alias.win32.ts (Win32) to
    call the shared utility with their respective transforms. The visible behavior of
    each must be identical to the current implementation.
  • Export hcAliasTokens from packages/theming/theme-tokens/src/index.ts so
    win32-theme can import it by package name without reaching into internal paths.
  • Update win32-theme/src/getOfficeTokens.ts to import hcAliasTokens from
    @fluentui-react-native/theme-tokens and delete
    win32-theme/src/highContrast/tokens-alias.ts.
  • Add unit tests in packages/theming/theme-tokens that assert the two
    name-transform rules independently.
  • Add changesets for each changed package.

Out of scope

  • Changing the PlatformColor name values, the JSON source file
    (design-tokens-win32/hc/tokens-aliases.json), or the two-level loop structure
    that iterates over the alias object.
  • Modifying the Windows/UWP transform rule (SystemColor*Color) or the Win32
    transform rule (raw name). Both must remain as documented above; see the
    intentional difference section.
  • Moving the high-contrast alias logic into @fluentui-react-native/design; that
    boundary question belongs to Package Consolidation.
  • Broadening unit test coverage in theme-tokens beyond the processAliasTokens
    utility itself.
  • Any changes to iOS or Android high-contrast handling.
  • Changing the in-place mutation pattern; the function currently mutates the JSON
    object passed to it, which is load-time-only and safe today. Altering that
    behavior is a separate decision.

Deliverables

  1. A shared internal utility function in
    packages/theming/theme-tokens/src/highContrast/ that processes alias token
    JSON with a caller-supplied name-transform function.
  2. Updated tokens-alias.ts and tokens-alias.win32.ts using that utility,
    verified to produce identical output to the current implementations.
  3. hcAliasTokens added to packages/theming/theme-tokens/src/index.ts exports.
  4. win32-theme/src/getOfficeTokens.ts importing hcAliasTokens from
    @fluentui-react-native/theme-tokens, with win32-theme/src/highContrast/
    removed.
  5. Unit tests in packages/theming/theme-tokens asserting the SystemColor*Color
    transform and the raw Win32 name transform.
  6. Changesets for @fluentui-react-native/theme-tokens and
    @fluentui-react-native/win32-theme.

Acceptance criteria

  • Only one definition of the alias-processing logic exists in the repository;
    the two platform-variant files in theme-tokens call it with different
    name-transform functions.
  • win32-theme/src/highContrast/ does not contain a tokens-alias.ts file.
  • win32-theme/src/getOfficeTokens.ts imports hcAliasTokens from
    @fluentui-react-native/theme-tokens, not from a local relative path.
  • A unit test asserts that the Windows/UWP transform converts
    "PlatformColor(ButtonFace)" to PlatformColor('SystemColorButtonFaceColor'),
    and a separate unit test asserts that the Win32 transform converts the same
    input to PlatformColor('ButtonFace').
  • The existing win32-theme Jest snapshots for the HighContrast theme pass
    without modifying the snapshot files.
  • yarn build, yarn lage test, and yarn lage lint pass at the repository
    root, and changesets are present.

Dependencies and ordering

  • No prerequisite tasks; this cleanup can proceed at any stage independently of the
    staged roadmap.
  • Interacts with Package Consolidation: if
    theme-tokens is shimmed before this task lands, the shared utility and the new
    hcAliasTokens export must be placed in the design destination submodule rather
    than in theme-tokens directly. Landing this task first avoids migrating
    duplicated code.
  • Interacts with System Appearance Handling:
    hcAliasTokens is currently consumed by getAliasTokens, which that task may
    replace or restructure. No sequencing constraint exists; this task changes only
    the source location of the alias data, not how it is selected.

Risks and open decisions

  • Open decision. Whether hcAliasTokens is added to the existing
    theme-tokens root index or exposed through a separate subpath export. Adding it
    to the root barrel makes a Win32-specific value reachable on all platforms; a
    subpath entry avoids that but introduces a new export pattern. Inferred: given
    that getAliasTokens and getShadowTokens are already in the root index and are
    similarly platform-conditional in their useful values, adding hcAliasTokens
    there follows the existing precedent.
  • Risk. Adding hcAliasTokens to theme-tokens/index.ts changes the public
    export surface of the package. Observed: no consumer in packages/ or apps/
    re-exports * from '@fluentui-react-native/theme-tokens'; the package is consumed
    by named import throughout, so the surface change has no fan-out risk.
  • Risk. The current processAliasTokens function mutates the imported JSON
    object in place. This is safe today because the module-level hcAliasTokens is
    the sole reference. The shared utility must carry a comment documenting this
    mutation so it is not accidentally removed in a refactor that calls the function
    more than once.

Evidence and references

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions