From 154eb2ac9dd6baba0f461fae0a7b38df46383f4e Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 23 Oct 2026 17:36:08 -0700 Subject: [PATCH 01/18] add refactoring plan --- .changeset/spotty-cases-build.md | 5 + packages/agentic/design/refactoring.md | 612 ++++++++++++++++++ .../design/references/remaining-work.md | 4 + 3 files changed, 621 insertions(+) create mode 100644 .changeset/spotty-cases-build.md create mode 100644 packages/agentic/design/refactoring.md diff --git a/.changeset/spotty-cases-build.md b/.changeset/spotty-cases-build.md new file mode 100644 index 0000000000..0e89297f93 --- /dev/null +++ b/.changeset/spotty-cases-build.md @@ -0,0 +1,5 @@ +--- + +--- + +Documentation-only design refactoring proposal; no package release. diff --git a/packages/agentic/design/refactoring.md b/packages/agentic/design/refactoring.md new file mode 100644 index 0000000000..ce9097db38 --- /dev/null +++ b/packages/agentic/design/refactoring.md @@ -0,0 +1,612 @@ +# Design package reorganization and evolution + +**Status:** Proposed; documentation only. Owner-approved decisions below supersede the initial review recommendations. +Only the remaining implementation gates require further decisions. + +**Scope:** Reorganize `@fluentui-react-native/design`, add tone-aware appearance, separate Flex policy from color +algorithms, and introduce authored and resolved interactive colors with verified Flex defaults. Preserve legacy +theming consumers, including consumers outside this repository. Modern/Flex authoring changes are intentionally +breaking and require a coordinated migration. + +This owner-requested review draft is a narrow exception to R-PKGDOC-009. [Remaining work](references/remaining-work.md) +remains the package's open-work index; it should point here rather than duplicate the implementation checklist. Once +implemented, move the durable contract into the owning references and remove this draft and its pointer. This draft +is repository-only, not part of the published package inventory. + +## 1. Success criteria and compatibility boundary + +- Flex implementation belongs in `src/flex/`; legacy Fluent implementation in `src/fluent/`; shared types in + `src/types/`; test and validation collateral in `src/test/`. +- One `ThemeProvider` continues to serve both authoring models. A Flex provider publishes metadata without resolving + either model; hooks construct only the model they return. Legacy raw-context behavior remains supported. +- Existing legacy packages, exported names, public subpaths, constructors, recipe behavior, context identities, + deprecated appearance APIs, and legacy-authored values remain compatible. +- `ColorTone` is `'cool' | 'warm'`, defaults to `'cool'`, and participates in top-level appearance and every applicable + cache identity. No OS tone signal or `'system'` tone is invented. +- Interactive colors have distinct input and output contracts. Explicit states win; missing supported states are + calculated lazily and automatically for Flex consumers, at most once per state and resolved entry. Unmappable rest + colors fall back to that same rest value. No author-owned object is mutated. +- Default Flex values use current x3 sources, pinned to an immutable revision when refreshed, with an explicit native + adaptation ledger. Omit hover/pressed defaults wherever the dynamic APIs reproduce them from `[light, dark]` rest + colors. Mapping coverage, value parity, algorithm conformance, and contrast are separate checks. +- The modern Flex graph includes the raw algorithms needed for automatic interaction colors, but remains free of + legacy projection/default payloads and test helpers. Legacy Fluent consumers retain their existing graph and + behavior; the engine is not injected through shared provider utilities. +- Close the non-color gaps, including missing motion/spacing roles and layered/dark shadows, without changing legacy + Fluent types. +- Consumer code, generated mappings, component token references, authoring instructions, and migration examples + change together. No component interaction or accessibility redesign is included. + +### Confirmed legacy and Flex ownership + +**Confirmed by the owner:** legacy consumers use legacy Fluent themes and the existing legacy provider entry points. +Preserve `ThemeReference`, legacy platform factories, raw `ThemeContext`, compatibility packages, and their existing +values. The Flex refactor must not change those consumers. No additional provider is required. + +Agentic/Flex consumers are in rapid development: adopt current x3 values, including intentional visual changes, without +an opt-in historical preset or a separate default-activation approval. Do not gate those changes on preserving legacy +visuals beneath an implicit Flex root; that is not the legacy consumption model in scope. + +If an application deliberately mixes legacy consumers with a Flex-authored source, keep mapped Flex values +authoritative in its legacy projection. Do not introduce author-touched-path side channels or historical palette +overlays to make the two hooks disagree about the selected source. + +## 2. Evidence and work that must be reconciled + +The baseline inspected for this proposal is `cfa4c66257b7a00d9d828c81da7c36d2e0043c5b`. +**Observed** describes that checkout or an explicitly identified verification. **Proposed** describes future behavior; +it is not an implementation claim. + +| Observed surface | Evidence in this package | Consequence | +| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | +| Shared providers and consumption-time conversion already exist | `src/theming/ThemeProvider.tsx:19-53`, `src/theming/themeRuntime.ts:17-72`, `src/theming/useTheme.ts:16-46` | Preserve the architecture rather than adding another provider | +| Appearance keys currently have three axes | `src/theming/appearance.types.ts:1-39`, `src/theming/appearance.ts:16-81` | Tone must reach normalization, interning, reference caches, state caches, and legacy projection caches | +| Rest values and partial `color.hover`/`color.pressed` maps are separate | `src/tokens/flex.types.ts:208-281`, `src/theming/flexThemeReference.ts:22-45` | The new model changes types, merge rules, mappings, styles, tests, and consumers | +| Every appearance starts from the same hand-authored default table | `src/tokens/defaultTokens.ts:69-392`, `src/theming/flexThemeReference.ts:137-143`, [open defaults work](references/remaining-work.md#appearance-specific-default-tokens) | Reformatting that table does not establish x3 correctness | +| color-lib owns Flex classification and bulk token operations | `src/color-lib/interaction.ts:26-125`, `src/color-lib/interaction.ts:172-194`, `src/color-lib/interaction.ts:255-316` | Separate semantic policy from numerical algorithms | +| Pairings and contrast audits are already test-only | `src/testing/color-validation/pairings.ts:15-21`, `src/testing/color-validation/validation.ts:1-35` | Relocate their ownership, not duplicate them in Flex runtime | +| Reverse projection has canonical collisions, transforms, and legacy fallback precedence | `src/theming/compat/themeFromFlexTokens.ts:75-110`, `src/tokens/mappings/flex-token-map.yaml:74-99` | Preserve these policies while regenerating paths | +| Bundle assertions match current directory substrings | `apps/bundle-size/scenarios.json:14-52` in the repository | Update positive and negative assertions with moves, or they become vacuous | + +There is overlapping, unlanded default-theme/codegen work for #4263. Before implementation, inspect its actual branch +and reconcile reusable legacy-payload generation, appearance selection, and bundle evidence. Its platform-derived +Flex defaults are not proof of x3 parity and are not present merely because a workstream records them. Do not build a +second competing generator or merge that work blindly. + +### Demonstrated duplication + +| Candidate | Proposed treatment | +| ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | +| Guarded object-path traversal in `src/utilities/objects.ts:8-57` and `src/theming/compat/themeFromFlexTokens.ts:22-63` | Share the traversal primitive; preserve distinct overwrite and missing-value policies | +| Interactive membership in types, runtime arrays, YAML state mappings, and fixtures | Derive or validate membership against one canonical mapping inventory; retain independent value fixtures | +| Public `ThemeState` and internal `RuntimeThemeState` structure | One type-only definition in `src/types/`; no new runtime dependency cycle | +| Similar partial-color inputs and duplicated conformance-color test setup | Use the new authored-input contract and a shared test-only fixture builder | +| Repeated warm reference-backdrop constant | Keep one algorithm-owned constant, not a semantic-token lookup | +| Revision/appearance cache boilerplate | Normalize keys centrally; extract storage mechanics only if it keeps modern and legacy runtime graphs separate | + +Do not merge `ThemeReference` and `FlexThemeReference` just because they have similar caches. Do not pool every color +literal or generated payload into one eagerly reachable module without measured bundle evidence. Preserve existing +root versus legacy meanings of similarly named font types instead of renaming a legacy API during this move. + +## 3. Target ownership and dependency direction + +```text +src/ + types/ Shared, type-only appearance, color and state contracts + theming/ Shared providers, boundaries, appearance sources and runtime identity + flex/ + tokens.types.ts Authored and resolved Flex contracts + flexThemeReference.ts Modern source and recipe resolution + colors/ flexColor, lazy resolution, token classification and metadata + defaults/ Provenance-bearing generated defaults and native adaptations + adapters/ Lightweight legacy Theme-to-Flex conversion + styling/ Flex-aware color style factories + fluent/ + types/ Legacy Theme, palette, typography and shadow contracts + themeReference.ts Legacy authoring and merge behavior + useTheme.ts Legacy consumption + compat/ Reverse projection and complete legacy defaults + tokens/ Legacy alias, shadow and global payloads + styling/ Legacy token builders and themed stylesheet + ... Legacy pipeline helpers and platform utilities + color-lib/ Raw parsing, conversion, compositing and interaction algorithms + styling/ Shared state/style utilities and public styling facade + tokens/ + mappings/ Existing canonical YAML, projections and upstream pin + ... Existing generated platform global entry points + test/ + fixtures/ Mock themes and conformance fixtures + color-validation/ Pairings, bulk audits and contrast validation + utilities/ Small, genuinely shared runtime primitives +``` + +Keep `src/tokens/mappings/flex-token-map.yaml` at its current canonical path during this work. Its location is embedded +in scripts, rules, contracts, and source references; moving it is not required to move Flex runtime ownership. Treat +generated platform globals separately from semantic Flex defaults. Move platform variants and their platform-specific +tests together. + +**Allowed dependencies:** shared types are runtime-free; raw algorithms depend on shared types, not Flex token names; +Flex runtime uses the necessary raw interaction algorithms, shared utilities, and generated defaults automatically. +Shared theming selects the appropriate consumption path without installing a color engine on the legacy path; legacy +consumption may reach complete legacy defaults. The modern forward adapter can reference legacy types without loading +legacy runtime payloads. Test helpers can depend on production code; production cannot depend on `src/test/` or the +public `testing` entry point. + +Physical folders need not become public subpaths. Preserve explicit, named entry-point exports; do not introduce +`export *` barrels, global engine registration, or a second source of theme truth. + +### Public entry-point preservation + +Retain every current export-map key and its `types`, `react-native`, `import`, and `default` resolution semantics: + +```text +. +./theming +./theming/legacy-source +./theming/compat +./theming/compat/defaults +./tokens/global +./tokens/legacy +./color-lib +./styling +./styling/stylesheet +./styling/tokens +./testing +./package.json +``` + +Entry-point targets may follow moved implementations, or remain thin named facades. Do not produce separate contexts, +constructors, or mutable singletons through old and new entry points. Retain the six compatibility packages documented +in [Entry points](references/entry-points.md); inventory actual exports as well as documentation, including +`hcAliasTokens`. + +Compatibility covers supported package specifiers, not arbitrary private `src/` or `lib/` deep imports. Inventory such +imports before moving files and document this distinction. Modern root and color-lib API changes must be called out +explicitly; retaining a subpath does not imply preserving every modern signature behind it. + +## 4. Appearance and ColorTone + +**Proposed shared type:** + +```ts +export type ColorTone = 'cool' | 'warm'; +``` + +Add `appearance.colorTone` to the existing top-level appearance configuration accepted by theme sources, +`ThemeProvider`, and `ThemedRoot`. Resolved modern appearance always has a concrete tone. Omitted tone means cool, +with no platform listener or automatic tone inference. + +Tone precedence is explicit provider/root override, then source option, then the configured fallback tone, then cool. +An inheriting `ThemedRoot` retains the enclosing request; an explicit theme starts a complete boundary, as today. +Keep scheme, contrast, and interface-level precedence unchanged. Preserve the distinction between an omitted tone +request and an explicitly requested cool tone until fallback resolution. + +Legacy-facing functions must continue accepting existing three-field appearance literals. Normalize missing tone at +the boundary rather than making every external `ResolvedThemeAppearance` argument suddenly require a fourth field. +Keep `colorTone` optional on the existing exported compatibility type, and introduce a strict normalized modern output +type. Widening function parameters alone does not preserve external declarations of the old type. Compile +representative external-style calls before finalizing the new name. Do not add tone to the old `AppearanceOptions` +union. Its reverse conversion remains intentionally lossy. + +Update request keys, resolved interning, source/reference caches, compatibility-default caches, `ThemeState`, recipes, +and style registry identity. Preserve existing cool `themeAppearanceKey` strings if that exported utility's consumers +depend on them; a distinct warm suffix can distinguish tone without changing historical cool keys. Missing and explicit +cool inputs must converge on the same resolved identity. + +A tone-only transition selects a distinct state without mutating the previous one. Returning to a previously resolved +appearance may reuse its state within the same revision; every new state owns a fresh style registry. `update()` and +`invalidate()` still replace all revision-scoped entries. Raw legacy-context boundaries retain their current boundary +semantics: absent tone resolves to cool rather than introducing new inheritance across an implicit legacy boundary. +Cover that behavior explicitly. + +Rename the raw interaction option from `variant: 'default' | 'bebopWarm'` to `colorTone: 'cool' | 'warm'`. +The vocabulary-only change must preserve numerical behavior and the warm reference-backdrop solve. Separately +reconcile any algorithm changes needed to reproduce current x3 sources rather than freezing the older pin's output. +Palette selection and interaction algorithm selection use the same resolved tone. Verify warm provenance alongside +cool; freshness is approved, but unverified values are not. + +## 5. Authored and resolved Flex colors + +### Public contracts + +Use the requested input/output split. Accept readonly tuples as well as ordinary tuples so `as const` authoring works; +the package must not mutate either. + +```ts +import type { ColorValue } from 'react-native'; + +export type ColorTuple = readonly [light: ColorValue, dark: ColorValue]; +export type ColorEntry = ColorValue | ColorTuple; +export type InteractiveColorType = 'standard' | 'inverted' | 'fixed'; + +export type InteractiveColorOptions = { + rest: ColorEntry; + hover?: ColorEntry; + pressed?: ColorEntry; + type?: InteractiveColorType; +}; + +export type InteractiveColor = { + readonly rest: ColorValue; + readonly hover: ColorValue; + readonly pressed: ColorValue; +}; + +export declare function flexColor(value: ColorEntry | InteractiveColorOptions, colorType?: InteractiveColorType): InteractiveColorOptions; +``` + +`flexColor` is a small, pure input normalizer. Its second argument defaults to standard; an explicit +`value.type` wins. It does not resolve appearance, derive colors, or attach caches to its argument. Recognize tuples +and option objects with precise guards; opaque native color objects are leaves, not option bags. + +**Selected output scope:** every Flex color resolves to an `InteractiveColor`, giving consumers and generated +projections one `.rest/.hover/.pressed` access pattern. Every color accepts `ColorEntry | InteractiveColorOptions`. +Keep the canonical interaction-eligibility inventory separate: ineligible tokens expose explicit states when supplied, +otherwise equal rest values and never run derivation. A uniform envelope does not make a disabled, focus, fixed, or +decorative role newly interactive. + +Default definitions and legacy adapters explicitly provide the correct inverted metadata for existing heavy/loud/ +onloud roles. Do not silently override the documented standard default of a newly authored `flexColor` entry by +guessing from its name. Export token-aware classification from the Flex implementation for callers that need it. +Keep interaction eligibility, inversion, and fixed behavior separate. + +### Resolution rules + +1. A single `ColorValue` applies to either scheme. A tuple selects light at index zero and dark at index one. +2. Explicit hover and pressed values are authoritative independently, including native values. Only `undefined` + denotes absence. +3. Rest is available without executing interaction algorithms. Each omitted state gets its own lazy, memoized getter; + pressed derives from rest, never from hover. Reading one state must not calculate the other. +4. Standard and inverted use the reviewed scheme-dependent direction rules. Fixed promises a scheme-independent + derivation policy, but the current implementation does not define one. For derivable literals, require explicit + fixed states until that policy has authoritative evidence and review; do not silently choose light-mode mathematics + or equate fixed with disabled. The unmappable, ineligible, and high-contrast rest-fallback rules still apply. +5. In high contrast, explicit states remain authoritative and missing states deliberately resolve to rest rather than + applying standard/warm fallback math. Light/dark tuples do not encode high-contrast or elevated alternatives; + appearance-aware defaults, bases, or recipes supply those. +6. If the selected rest value is `PlatformColor`, another opaque/dynamic native color, or any other value the raw + parser cannot map, an omitted hover or pressed state returns that exact rest value directly. This is an approved + resolution policy, not an error, warning, or requirement to supply explicit states. Preserve native object identity + and do not inspect or fabricate channels. Explicit states still win. Direct raw APIs retain their structured + unresolvable results for callers and test audits that need them. +7. Cache only package-owned normalized descriptors and resolved entries. Frozen output envelopes may hold memoized + state in closures. Never mutate or freeze caller-owned native objects. + +An authored dynamic native color can still follow the OS appearance rather than a forced theme scheme. Document that +distinction and recommend explicit scheme tuples where the author needs theme-controlled selection. + +### Automatic dynamic colors for Flex + +**Confirmed by the owner:** Flex consumers receive the dynamic interaction APIs automatically. The Flex resolver +synchronously imports and calls the required raw algorithm modules; no source-level deriver option, extra author +import, provider setting, registration, or missing-engine error exists. The public `/color-lib` entry point remains +available for direct algorithm use, but it is not an opt-in requirement for theme authors. + +Keep evaluation lazy even though the necessary code is bundled. Provider mount, rest reads, and explicit state reads +must not calculate omitted states. Omit each generated default hover/pressed value independently when the built-in +algorithm can reproduce the current x3 reference from the selected rest color, scheme, tone, and token metadata. +Author concise `[light, dark]` rest tuples; keep an explicit state only for a genuine source exception or another +non-derivable authored override. Unmappable rest values need no duplicate interaction fields. + +This intentionally changes the old modern-root color-lib exclusion, not the legacy API contract. Update the design +package invariants, contributing guidance, and bundle scenarios when implementing it. Keep unrelated color utilities, +test audits, and legacy payloads out of the Flex graph where tree shaking permits; do not hide the added algorithm +cost behind a lazy getter claim. + +Use the raw API's structured unresolvable result for the approved rest fallback. Do not broadly catch unexpected +algorithm errors and turn them into rest values. Invalid authoring inputs and unsupported fixed-literal semantics +still require explicit errors; native/unmappable colors do not. + +### Merge and recipe rules + +Color tokens are atomic replacement leaves. A replacement requires rest; omitted interactions belong to the new rest +and must not inherit stale explicit states from an earlier layer. Arrays and opaque colors also remain atomic. +`undefined` means no override. Preserve existing non-color merge behavior unless a separately reviewed requirement +changes it. + +Keep defaults, base, and recipe ordering. Recipes receive accumulated readonly authored descriptions plus normalized +appearance; merge those descriptions before producing resolved getter objects. Parent references supply their +descriptions internally, not appearance-bound outputs. Provide a small pure selector for authored rest/explicit tuple +values where recipes need an appearance-specific value. This is an intentional modern recipe API break and needs a +worked migration. + +Do not accept resolved `FlexTokens` as ordinary authoring input or pass resolved entries through generic deep merge, +spread, `Object.assign`, or serialization. Own enumerable getters are invoked by `Object.assign`; copying a getter +does not preserve its laziness. A `WeakSet` brand alone cannot prove that an entry's captured appearance, revision, +algorithm policy, and token context are valid for reuse. Do not add that hidden coercion layer. + +## 6. Raw algorithms, Flex policy, and test collateral + +| Responsibility | Owner | +| ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | +| Literal parsing, RGBA/OKLCH conversion, compositing, contrast math, cool/warm interaction transforms | `src/color-lib/` | +| Interactive token membership, deep/inverted classification, semantic background/stroke policy | `src/flex/colors/` | +| The `InteractiveColorOptions` resolver and lazy `InteractiveColor` envelopes | `src/flex/colors/` | +| Default foreground/background pairings, WCAG audits, bulk fixture generation, known conformance cases | `src/test/` | +| Mathematical reference backdrops required by the warm transform | Raw algorithm, passed generic compositing intent; not test pairings or semantic-token lookups | + +Raw functions accept numerical/color inputs, state, scheme, tone, direction, and genuinely required compositing +context; they do not inspect Flex token spelling. The Flex resolver uses those functions automatically and applies +high-contrast suppression and unmappable-rest fallback. Move test-only bulk operations rather than advertising them +as a new production API. + +Move token-aware APIs such as inverse-token classification to Flex exports. Treat changed color-lib signatures and +the removed variant vocabulary as modern API migration work; add a deprecated compatibility wrapper only if the +legacy inventory demonstrates a real obligation. Do not retain semantic policy inside the raw implementation merely +to preserve an undocumented modern signature. + +## 7. Default values and immutable x3 evidence + +### Approved current-source target and verified evidence + +**Confirmed by the owner:** use current x3 color source values. Agentic components are in rapid development, and +modern value changes are approved; do not preserve the older pin merely to avoid them. Refresh to current upstream +main during implementation, record the resulting immutable revision and blob identities, and reconcile differences. +Drift review documents the change; it is not a new approval gate for adopting current values. + +On 2026-10-23, authenticated read-only metadata checks reverified +`x3-design/fluent-design@206e890b645fb450ad7c5df2ff981765349a2b58` as current main, committed 2026-09-11. Its tree includes: + +| Current source | Blob SHA | +| ------------------------------------------------------- | ------------------------------------------ | +| `dev/web/flex-themes/css/semantic.css` | `4c9f3e0a70bdbb8b7183d2db15254d9427d8e6ab` | +| `dev/web/flex-themes/css/interaction-fallback.css` | `c69ff3145f4f9b1228a694a3e7ba8b1a65d2c032` | +| `dev/web/flex-themes/css/warm/semantic.css` | `dfe8416dffb4b215777d0270c3fe40a5d631ee2c` | +| `dev/web/flex-themes/css/warm/interaction-fallback.css` | `6dbe4a963fd197cac7fabf35cf6c801f68aa1f4c` | +| `dev/web/flex-tokens/mappings.json` | `33c7a100a200d52d48f35faae5adf9f6282e462a` | +| `dev/web/flex-tokens/tokens.json` | `49bec466b835c0df87c879f399a29fc60db6b426` | + +The split light/dark semantic and interaction companions also exist for cool and warm at this revision. Include all +required sources in the refreshed pin and compare derived states against their reference values; do not confuse +omitting runtime defaults with omitting source evidence. + +The checked-in runtime pin is still the historical `d334acf5cbad813f2b7cd554da942b09a7ff8f10` until implementation. +Its earlier offline check passed in `offline-snapshot` mode with three matching integrity entries and no drift. +That result is historical local-integrity evidence, not parity with the current target. These metadata checks did not +copy private source bodies, change the runtime pin, or verify every current default value. + +### Access and reference procedure + +Use the token and component references in `https://github.com/x3-design/fluent-design` as needed, at immutable +identities. This internal source requires authenticated access, not an unauthenticated public link probe: + +1. For an internal source, select an existing authorized **Microsoft EMU** GitHub identity using `gh auth switch`. + Verify the repository and exact commit with read-only REST GETs. Do not diagnose a public-identity 404 as missing + upstream evidence. +2. For tokens, resolve current upstream main, refresh the design pin and source identities above, then inspect that + revision's token, semantic, interaction, and warm companions. Resolve source variables and scheme/tone overrides + before comparing values. Recheck main when implementation begins rather than treating today's target as permanent. +3. For components, use `@fluentui-react-native/components/references/contract-sources/flex-x3.md`, the + `flex-authoring` profile, the matching `flex-components:` source, and + `@fluentui-react-native/components/spec-source-lock.json`. Read shared, usage, and relevant platform companions. + Modern source and component changes are approved: refresh affected source locks and contracts through their + workflow where current tokens require it. Do not combine releases accidentally or promote contracts without review. +4. The Node drift tool reads `GITHUB_TOKEN`/`GH_TOKEN`; switching the `gh` account alone does not authenticate that + process. Supply approved command-scoped credentials without printing, persisting, or committing them. Restore the + public GitHub identity before public-repository operations, including on failure. +5. Respect R-REPO-004: source access is not permission to copy or mechanically transform private source bodies or token + tables into this public repository. Confirm permitted data publication before extending snapshots or emitting + derived payloads. Keep private reports/logs local; publish original documentation and permitted provenance only. + +Durable maintenance instructions belong in [Tokens](references/tokens.md); component contracts retain their own +source-adapter workflow rather than acquiring a second copy of it here. + +### Completeness and generation gate + +Build a coverage ledger for **every supported Flex destination**, not just interactive colors. Record source commit, +path, role, scheme/tone, native representation, explicit versus computed state, adaptation reason, and unsupported or +platform-owned cases. Never label a missing role complete because it inherited rest. + +The reviewed generator must resolve source variables and overrides, preserve alpha, normalize units deliberately, and +emit deterministic, provenance-bearing defaults in `src/flex/defaults/`. Emit `[light, dark]` rest colors plus the +required type/role metadata for each tone, omitting each hover/pressed field that the automatic dynamic implementation +reproduces correctly. Keep explicit exceptions only where needed. Compare resolved outputs, not authored-field +presence, when testing completeness. Preserve complete current interaction reference data in permitted test-only +evidence so derivation is checked independently of the generator. Use `flexColor` and tuple helpers to keep authored +definitions concise without forcing helper calls around every generated literal. + +Explicitly resolve these known gaps: + +- Cool and warm palettes need independently verified rest and interaction data. Warm algorithm vectors are not proof + of a complete warm palette. +- The historical interaction fixture had ten cool-table cases using the warm path. Revalidate them against current + sources; retain an explicit state only where current source values cannot be reproduced by the approved dynamic + policy. Do not carry stale exceptions forward automatically or omit real source exceptions. +- Adopt current x3 brand values alongside the rest of the current palette. Record and qualify visual changes; a + separate brand-approval gate is no longer required. +- **Approved:** close non-color gaps across fonts, weights, line heights, spacing, radii, strokes, motion, and shadows. + Extend the modern contract/mapping for missing motion-duration/easing roles and `componentBase800` where current + sources define them; do not leave them deferred merely because the old contract omitted them. +- **Approved:** support the current layered shadows and dark overrides with a modern representation that preserves + all source layers and valid native behavior. Keep legacy `ShadowToken` unchanged and document any lossy legacy + projection or platform-specific adaptation explicitly; do not silently truncate modern shadows. +- The selected x3 semantic evidence does not define native high-contrast/elevated defaults. Preserve platform-owned + behavior and document any base-appearance reuse; do not synthesize purported x3 values. +- Re-evaluate historical dark-pressed contrast failures against current values and keep any remaining failures visible + as audit outcomes, separate from matching the design source. + +Extend pin/drift tooling to all approved source IDs and validate generated value parity independently of +`check:mappings`. Repeated generation must be byte-for-byte stable. Reuse compatible existing codegen work after +reconciliation, but do not substitute platform-package equivalence for the requested x3 evidence. + +## 8. Legacy adapters and consumer migration + +### Conversion guarantees + +Forward conversion preserves legacy-authored rest, hover, pressed, native colors, and existing missing-value fallback +ownership. Replacing the modern token representation must not silently change the forward adapter's fallback values; +if a new modern-only policy is desired, isolate and review it separately. + +Reverse conversion keeps its existing order: complete legacy base, `legacyFallback`, authoritative mapped Flex values, +then legacy appearance metadata. Preserve canonical collision choices, omitted candidates, transforms, complete legacy +values Flex cannot represent, and lazy loading. If the published converter accepts old flat token inputs, retain a +compatibility input normalization path rather than accidentally breaking legacy consumers through a modern type move. + +The YAML remains canonical. Update its destinations and the generator/validator to understand per-token +`.rest/.hover/.pressed` paths, then regenerate both projections. Do not hand-edit JSON projections or weaken validation +to accept unresolved new paths. + +### Migration order and concrete surfaces + +1. Update the design color-style factory internally so existing key-based `colorStyleDef` declarations keep their + interaction precedence. Keep the shared state factory independent of per-color representation. +2. Migrate direct interactive reads in Input and ListboxItem, then remaining component, story, and test reads. + Migrate all scalar color reads to `.rest`, including static roles now using the uniform envelope. Inventory all + direct accesses, not just the old override maps. +3. Migrate Storybook chrome and theme fixtures, including `testing` exports and consumers re-exporting `mockTheme`. + Keep `/testing` as the public spelling even though implementation moves to `src/test/`. +4. Component owners revise affected token references, including Accordion, Button, and Input `spec/tokens.yaml`, + through their contract workflow. An import/path migration does not authorize a component behavior change or + automatic contract promotion. +5. Update [Theming](references/theming.md), [Tokens](references/tokens.md), [Styling](references/styling.md), + [Color library](references/color-lib.md), [Testing](references/testing.md), [Entry points](references/entry-points.md), + [Contributing](references/contributing.md), the package quick start, component styles-and-tokens instructions, + and repository theming basics. + +Representative modern migration: + +```ts +// Before +const rest = tokens.color.backgroundBrandLoud; +const hover = tokens.color.hover.backgroundBrandLoud ?? rest; + +// After +const { backgroundBrandLoud } = tokens.color; +const rest = backgroundBrandLoud.rest; +const hover = backgroundBrandLoud.hover; +``` + +Read only the states a style path needs. Destructuring both hover and pressed eagerly reads both getters; this is +valid when needed, but not evidence of interaction-time laziness. + +Illustrative input authoring, not x3 default values: + +```ts +const brand = flexColor({ + rest: ['#345678', '#abcdef'], + hover: ['#234567', '#bcdef0'], + pressed: ['#123456', '#cdef01'], + type: 'inverted', +}); +``` + +For the normal automatic-derivation case, the author only supplies rest colors and any required classification: + +```ts +const brand = flexColor(['#345678', '#abcdef'], 'inverted'); +``` + +No deriver configuration or separate dynamic-color import is required. The migration guide must also show explicit +state exceptions, tuple selection, atomic replacement, automatic unmappable-rest/high-contrast fallback, recipe +migration, `legacyFallback`, and how legacy Fluent themes/provider usage remains unchanged. Do not remove deprecated +appearance APIs as incidental cleanup. + +## 9. Delivery phases, ownership, and exit criteria + +| Phase | Owner and work | Prerequisite | Exit gate | +| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| 0. Resolve remaining gates and overlap | Apply owner-approved decisions; reconcile existing default-theme/codegen work, fixed semantics, and source publication permissions | This review draft | Current-source adoption, automatic Flex derivation, native rest fallback, and non-color gap closure are not reopened as approval gates | +| 1. Capture compatibility | Design and compatibility-package owners record public symbol/type fixtures, external-style imports, legacy Fluent runtime/default snapshots, and bundle baselines | Phase 0 | Baselines cover legacy themes/provider entry points, raw contexts, native colors, fallback ownership, and every export condition | +| 2. Mechanical organization | Move owned implementations and platform tests; update entry targets, references, generators' fixed source paths, and bundle positive/negative controls; deduplicate demonstrated helpers | Phase 1 | No behavior or exported legacy-name change; no vacuous import boundary tests | +| 3. Tone and automatic engine | Add compatible tone normalization and cache keys; wire required raw algorithms into Flex only; update import invariants and conformance coverage | Phase 2 | Tone-only transitions, three-field legacy calls, automatic Flex imports, and legacy graph isolation behave as specified | +| 4. Interactive representation | Implement authored/resolved contracts, atomic color replacement, automatic lazy states, recipe semantics, adapters, and regenerated YAML projections; migrate consumers coherently | Phase 3 and fixed semantics where applicable | Existing default values first survive a representation-only migration; no stale states, eager copying, or legacy fallback changes | +| 5. Current x3 defaults and non-color completion | Refresh to current x3, generate rest-first cool/warm defaults and necessary explicit exceptions, extend non-color contracts and layered shadows | Source publication gate and stable Phase 4 representation | Resolved values match current sources; derivable state fields are absent; approved gaps are closed; legacy Fluent themes stay unchanged | +| 6. Release and qualification | Update owning references, consumer guidance and changesets; inspect packed artifacts, bundles, and affected native stories | Phases 2-5 | Modern migration is complete, legacy contract holds, validation and native limitations are explicit | + +Upstream investigation and compatibility capture can proceed independently. Activate current Flex defaults once +their permitted provenance, resolved-value checks, and implementation qualification pass; no historical-Flex visual +preservation or additional modern-default approval is required. Keep mechanical moves separate from value changes +so regressions can be attributed and reviewed. + +## 10. Validation and acceptance + +Use existing declared scripts. Focused test names below select related existing files; add colocated coverage for the +new contracts rather than inventing an unconfigured runner. + +| Scope | Commands | Required evidence | +| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| This documentation change | Root `yarn format:check` scoped to edited files; `yarn check-agent-instructions`; configured Markdown link checks; `yarn change:check`; final cache-cleared aggregate for the changed instruction reference | Valid navigation, formatting and an empty changeset for a no-release package change | +| Appearance/runtime iteration | In design: `yarn test appearance flexThemeReference themeReference useThemeState useTheme ThemedRoot` | Tone keys, normalized defaults, boundary precedence, subscriptions, revisions, state identity, fresh style registries | +| Color/adapter iteration | In design: `yarn test colorLib colorStyles validation flexTokenMappings flexTokensFromTheme themeFromFlexTokens objects` | Automatic derivation, explicit-state precedence, unmappable-rest identity, frozen inputs, atomic replacement, conformance and projection policies | +| Types | In design: `yarn build` | Public legacy three-axis calls, readonly tuples, authored recipe types and uniform output envelopes; Jest alone does not check types | +| Mapping/provenance | In design: `yarn check:mappings`; `yarn gen:upstream-drift --offline`; authenticated current-source drift when refreshing the pin | Valid mappings, current resolved default-value coverage, omitted derivable fields, non-color completeness, snapshot integrity and explicit online/offline modes | +| Owning implementation package | In design: `yarn format`, `yarn lint`, `yarn build`, `yarn test`, `yarn check:mappings` | Full package acceptance after focused iteration | +| Migrated consumers | Declared build/lint/test scripts in affected component, Storybook runtime, platform-theme and compatibility packages | No remaining old interactive accesses; state precedence and external-style imports preserved | +| Distribution and graphs | Root `yarn bundle-size`, `yarn check-package-contents`, `yarn check-publishing`, `yarn lage test-links` after moves | Actual retained-module boundaries, positive controls, valid packed export targets and documentation links | +| Final implementation acceptance | Root `yarn clean-lage-cache`, then `yarn lage buildci` | One final cache-cleared aggregate; rerun failed downstream checks after fixes | +| Native qualification | Existing affected Storybook/native test workflows on supported platforms and renderers | Visual states, tone/scheme/contrast/elevation transitions, opaque/system colors and legacy/Flex coexistence | + +Add explicit zero-call/one-call derivation assertions: provider mount and rest access derive nothing; hover derives only +hover; repeated hover access derives once; an explicit state never invokes the engine. Include regression tests proving +that copying/merging a parent token does not read its getters. A normal `FlexThemeReference` must derive omitted states +without configuration. For unmappable values, both omitted states must return the identical rest value, while +explicit states still win; an unexpected algorithm failure must not be swallowed as that fallback. Distinguish raw +API diagnostics, approved unmappable-rest fallback, high-contrast suppression, and invalid-authoring errors. + +Test every default state against the current source after native normalization. Independently assert that each +derivable hover/pressed field is absent from runtime definitions, with any retained explicit exception documented. +Cover cool/warm, light/dark, inversion, native values, and the approved motion, spacing, and layered/dark shadow gaps. + +Import guards must forbid `/fluent/` compatibility payloads and `/test/` from the modern root, while allowing the +lightweight forward adapter and required raw color algorithms. Flex-state scenarios must positively require automatic +interaction modules; legacy-only scenarios must protect their existing graph and avoid acquiring the engine through +shared utilities. Reverse-projection and direct color-lib scenarios positively require their expected modules. +Test `flexColor` as a pure normalizer, not as a promise that the Flex runtime is engine-free. Review measured bundle +deltas before updating baselines. Bundle measurement is not included in `buildci`; add lightweight import-direction +assertions to the package test suite so ordinary CI also protects the dependency rules. + +This change does not implement or natively qualify the refactor. R-VALID-003 exempts plans; the original navigation +edit also changed an instruction reference and therefore required a cache-cleared aggregate. Subsequent plan-only +amendments require documentation checks, not a repeat product build or native run. Later implementation requires the +focused and native evidence above, not merely the documentation checks. Record checks as passed, failed, skipped, +not run, or unsupported; JavaScript tests and bundles are not native qualification. + +## 11. Confirmed decisions and remaining implementation gates + +The owner's 2026-10-23 follow-up settles these decisions: + +| Confirmed decision | Implementation requirement | +| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | +| Legacy consumers use legacy Fluent themes and the old provider | Preserve that path; current Flex defaults need no legacy implicit-root visual-compatibility gate | +| Dynamic interaction APIs are automatic for Flex | Wire required algorithms into the Flex runtime; remove deriver injection and missing-engine configuration | +| Default interactions should be derived wherever possible | Emit `[light, dark]` rest colors and classification, omitting each reproducible hover/pressed default independently | +| Platform/native/unmappable rest colors are valid | Omitted states return the rest value directly, preserving identity and requiring no explicit override or warning | +| Current x3 values are preferred over old modern values | Refresh current upstream identities and adopt the values, including brand changes; qualify rather than block the approved changes | +| Non-color gaps are approved | Implement missing current motion/spacing roles and layered/dark shadows while preserving legacy types | + +Only these implementation gates remain: + +| Gate | Required evidence | +| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Fixed derivation for mappable literals | Obtain an authoritative scheme-independent rule; until then require explicit fixed states | +| Source publication | Confirm permitted publication before adding private-source snapshots or derived payloads; current-source adoption itself is approved | +| Native non-color adaptations | Define and qualify renderer/unit/shadow behavior and document lossy legacy projections; this is implementation detail, not another scope-approval gate | + +## 12. Reciprocal-review provenance and reconciliation + +Two independent investigations used **GPT-6 Astra** (`gpt-6-astra`) and **Claude Opus 5.5** +(`claude-opus-5.5`), each configured with `reasoning_effort: max` and `context_tier: long_context`. Each model then +reviewed the other's complete report in its original thread. Full reports and critiques are private session artifacts, +not copied source material or published package content. + +The complete independent reports are `astra-independent-report.txt` and `opus-independent-report.txt`; their +reciprocal critiques are `astra-cross-review.txt` and `opus-cross-review.txt` in the private session artifacts. +The owner subsequently resolved several product decisions in section 11; that follow-up takes precedence over the +initial model recommendations. No new reciprocal-review round is claimed for these owner-directed amendments. +Reconciliation and the subsequent decisions are recorded explicitly: + +| Reviewed disagreement | Resolution and rationale | +| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| Uniform versus interactive-only envelopes | Uniform outputs match the requested consumption model and simplify projection paths; eligibility remains separate so static roles never derive | +| Resolved-parent versus authored-parent recipes | Merge authored descriptions before resolving; avoid eager getters and appearance-bound output reuse | +| Deriver injection and missing-engine errors | Superseded by owner decision: Flex always includes dynamic derivation; unmappable colors intentionally return rest | +| Fixed equals standard-light mathematics | Rejected as unsupported; explicit fixed states work while computed semantics remain gated | +| Touched-path legacy projection | Rejected by both reviewers; authoritative projection remains, and the owner confirmed that legacy users stay on legacy themes/provider | +| Required tone on old exported appearance types | Rejected as a legacy type break; retain optional compatibility fields and strict normalized modern outputs | +| Helper default versus token-name inference | Preserve the requested standard default; generated defaults/adapters supply reviewed inverted metadata explicitly | +| Source/table mismatch totals | Do not adopt unverified zero-match claims; concrete counterexamples were found during reciprocal review | +| Shape change before consumer migration | Rejected as an unbuildable intermediate phase; migrate the representation and consumers atomically, with value changes separate | +| Old pin and non-color scope gates | Superseded by owner decision: adopt current x3 values and close non-color gaps, recording immutable provenance and native adaptations | + +The remaining fixed-derivation and publication gates are explicit. Primary implementation evidence and the owner's +confirmed decisions take precedence over either model's speculation. diff --git a/packages/agentic/design/references/remaining-work.md b/packages/agentic/design/references/remaining-work.md index 544a702c50..641ea2503c 100644 --- a/packages/agentic/design/references/remaining-work.md +++ b/packages/agentic/design/references/remaining-work.md @@ -41,6 +41,10 @@ behavior is documented in `theming.md`, `tokens.md`, and `entry-points.md`. supply appearance-aware bases or recipes for dark or high-contrast values. - **Done when:** generated defaults exist for each supported appearance and `FlexThemeReference` selects them by the resolved appearance without changing its laziness or identity guarantees. +- **Review draft:** repository-only `packages/agentic/design/refactoring.md` coordinates package reorganization, + tone-aware interactive colors, verified x3 defaults, and the legacy compatibility gates. It is an explicitly + requested review artifact, not a second open-work index; remove the draft and this pointer when its durable contract + has moved into the owning references. ## Flex authoring migration guide From d3af17badf09b40fa52dd83483bfd00f8adc33ba Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 23 Oct 2026 17:52:49 -0700 Subject: [PATCH 02/18] design: capture compatibility baselines (refactor phase 1) Add export-map, runtime export, type inventory, legacy theme, adapter, native color, and Flex default fingerprint baselines that later phases must preserve. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5030bce5-d7f7-4fb1-93de-68599b79269f --- .../compatibilityBaseline.test.ts.snap | 187 +++ .../__snapshots__/entryPoints.test.ts.snap | 1020 +++++++++++++++++ .../compatibilityBaseline.test.ts | 69 ++ .../test/compatibility/entryPoints.test.ts | 65 ++ .../compatibility/entryPoints.types.test.ts | 265 +++++ .../src/test/compatibility/fingerprint.ts | 78 ++ 6 files changed, 1684 insertions(+) create mode 100644 packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap create mode 100644 packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap create mode 100644 packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts create mode 100644 packages/agentic/design/src/test/compatibility/entryPoints.test.ts create mode 100644 packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts create mode 100644 packages/agentic/design/src/test/compatibility/fingerprint.ts diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap new file mode 100644 index 0000000000..945f1afad9 --- /dev/null +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap @@ -0,0 +1,187 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Flex default baseline keeps the dark legacy projection of the default Flex tokens 1`] = ` +{ + "colorCount": 274, + "colors": "d455d2657fac4c32", + "components": "72a2537e550ec269", + "host": "e8e4ef993a27738e", + "shadows": "6cb9f79865a74b20", + "spacing": "ae5c5f37376210ff", + "typography": "758be399ff81061a", +} +`; + +exports[`Flex default baseline keeps the darkElevated legacy projection of the default Flex tokens 1`] = ` +{ + "colorCount": 274, + "colors": "d455d2657fac4c32", + "components": "72a2537e550ec269", + "host": "f94ca80c0bbf7966", + "shadows": "6cb9f79865a74b20", + "spacing": "ae5c5f37376210ff", + "typography": "758be399ff81061a", +} +`; + +exports[`Flex default baseline keeps the highContrast legacy projection of the default Flex tokens 1`] = ` +{ + "colorCount": 274, + "colors": "c43a121decc8c5b8", + "components": "72a2537e550ec269", + "host": "9db06d0a5ce1e422", + "shadows": "6cb9f79865a74b20", + "spacing": "ae5c5f37376210ff", + "typography": "758be399ff81061a", +} +`; + +exports[`Flex default baseline keeps the light legacy projection of the default Flex tokens 1`] = ` +{ + "colorCount": 274, + "colors": "86f973400507e95e", + "components": "72a2537e550ec269", + "host": "6be4fd450402dc4f", + "shadows": "6cb9f79865a74b20", + "spacing": "ae5c5f37376210ff", + "typography": "758be399ff81061a", +} +`; + +exports[`Flex default baseline keeps the values consumers read from the default Flex tokens 1`] = ` +{ + "borderRadius": "13bd91dc683ef515", + "color": "929614bda52b14dd", + "colorCount": 119, + "fontFamily": "7a4e96787cf538ad", + "fontSize": "684a251b98d9a7a5", + "fontWeight": "51d94cec151d0fba", + "lineHeight": "e10b09e52a79eb29", + "shadow": "844e4f7e40ea22d0", + "spacing": "d8a73be81c0519cd", + "strokeWidth": "d7b6d097ecd34db0", +} +`; + +exports[`legacy compatibility baseline keeps Flex values converted from the dark default legacy theme 1`] = ` +{ + "borderRadius": "13bd91dc683ef515", + "color": "8b3240b5c9086b86", + "colorCount": 119, + "fontFamily": "1563f269b690db9d", + "fontSize": "52fa58b4bacaf329", + "fontWeight": "8fe4b9b24b1f62c7", + "lineHeight": "e10b09e52a79eb29", + "shadow": "f6ac563fefc348cd", + "spacing": "d8a73be81c0519cd", + "strokeWidth": "d7b6d097ecd34db0", +} +`; + +exports[`legacy compatibility baseline keeps Flex values converted from the darkElevated default legacy theme 1`] = ` +{ + "borderRadius": "13bd91dc683ef515", + "color": "8b3240b5c9086b86", + "colorCount": 119, + "fontFamily": "1563f269b690db9d", + "fontSize": "52fa58b4bacaf329", + "fontWeight": "8fe4b9b24b1f62c7", + "lineHeight": "e10b09e52a79eb29", + "shadow": "f6ac563fefc348cd", + "spacing": "d8a73be81c0519cd", + "strokeWidth": "d7b6d097ecd34db0", +} +`; + +exports[`legacy compatibility baseline keeps Flex values converted from the highContrast default legacy theme 1`] = ` +{ + "borderRadius": "13bd91dc683ef515", + "color": "428227abcd661352", + "colorCount": 119, + "fontFamily": "1563f269b690db9d", + "fontSize": "52fa58b4bacaf329", + "fontWeight": "8fe4b9b24b1f62c7", + "lineHeight": "e10b09e52a79eb29", + "shadow": "f6ac563fefc348cd", + "spacing": "d8a73be81c0519cd", + "strokeWidth": "d7b6d097ecd34db0", +} +`; + +exports[`legacy compatibility baseline keeps Flex values converted from the light default legacy theme 1`] = ` +{ + "borderRadius": "13bd91dc683ef515", + "color": "847181f1c8ec73a4", + "colorCount": 119, + "fontFamily": "1563f269b690db9d", + "fontSize": "52fa58b4bacaf329", + "fontWeight": "8fe4b9b24b1f62c7", + "lineHeight": "e10b09e52a79eb29", + "shadow": "844e4f7e40ea22d0", + "spacing": "d8a73be81c0519cd", + "strokeWidth": "d7b6d097ecd34db0", +} +`; + +exports[`legacy compatibility baseline keeps Flex values converted from the mock theme 1`] = ` +{ + "borderRadius": "13bd91dc683ef515", + "color": "182c4b50bcf5e1b8", + "colorCount": 119, + "fontFamily": "dc70eb85181162c3", + "fontSize": "5f02d7a42f1f300e", + "fontWeight": "8fe4b9b24b1f62c7", + "lineHeight": "e10b09e52a79eb29", + "shadow": "4d7c42320ddafbfb", + "spacing": "d8a73be81c0519cd", + "strokeWidth": "d7b6d097ecd34db0", +} +`; + +exports[`legacy compatibility baseline keeps the dark default legacy theme 1`] = ` +{ + "colorCount": 275, + "colors": "6e9e7b821c45c476", + "components": "44136fa355b3678a", + "host": "e8e4ef993a27738e", + "shadows": "3388fc7114c96ee3", + "spacing": "ae5c5f37376210ff", + "typography": "1c07bfca1b48a07f", +} +`; + +exports[`legacy compatibility baseline keeps the darkElevated default legacy theme 1`] = ` +{ + "colorCount": 275, + "colors": "6e9e7b821c45c476", + "components": "44136fa355b3678a", + "host": "f94ca80c0bbf7966", + "shadows": "3388fc7114c96ee3", + "spacing": "ae5c5f37376210ff", + "typography": "1c07bfca1b48a07f", +} +`; + +exports[`legacy compatibility baseline keeps the highContrast default legacy theme 1`] = ` +{ + "colorCount": 275, + "colors": "730a40d80e103538", + "components": "44136fa355b3678a", + "host": "9db06d0a5ce1e422", + "shadows": "3388fc7114c96ee3", + "spacing": "ae5c5f37376210ff", + "typography": "1c07bfca1b48a07f", +} +`; + +exports[`legacy compatibility baseline keeps the light default legacy theme 1`] = ` +{ + "colorCount": 275, + "colors": "8b685906103f0ebf", + "components": "44136fa355b3678a", + "host": "6be4fd450402dc4f", + "shadows": "6cb9f79865a74b20", + "spacing": "ae5c5f37376210ff", + "typography": "1c07bfca1b48a07f", +} +`; diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap new file mode 100644 index 0000000000..f6133d3c0d --- /dev/null +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap @@ -0,0 +1,1020 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`public entry points . keeps its runtime export names 1`] = ` +[ + "FlexThemeReference: function", + "RootContext: object", + "RootInputBoundary: object", + "ThemeProvider: function", + "ThemedRoot: object", + "createThemeAppearanceSource: function", + "flexTokensFromTheme: function", + "fontSize: function", + "fontWeight: function", + "normalizeThemeAppearanceRequest: function", + "resolveThemeAppearance: function", + "themedStyleSheetFactory: function", + "useRootInputModality: function", + "useRootSettings: function", + "useThemeAppearance: function", + "useThemeState: function", +] +`; + +exports[`public entry points ./color-lib keeps its runtime export names 1`] = ` +[ + "compositeColor: function", + "compositeRgba: function", + "getContrastRatio: function", + "getHoverColor: function", + "getInteractionColor: function", + "getPressColor: function", + "isInverseInteractionToken: function", + "oklchToRgb: function", + "parseColorValue: function", + "resolveContrastColors: function", + "rgbToOklch: function", + "rgbaToHex: function", +] +`; + +exports[`public entry points ./styling keeps its runtime export names 1`] = ` +[ + "colorStyleDef: function", + "createStateLevelMap: function", + "getActiveState: function", + "getGapStyleValue: function", + "getNumericStyleValue: function", + "getStateStyleFactory: function", + "getThemedColorStyleFactory: function", + "getThemedStateStyleFactory: function", + "interactiveStatePriority: object", + "pickActiveStyle: function", + "styleDefinitionToBranchedStyles: function", +] +`; + +exports[`public entry points ./styling/stylesheet keeps its runtime export names 1`] = ` +[ + "themedStyleSheet: function", +] +`; + +exports[`public entry points ./styling/tokens keeps its runtime export names 1`] = ` +[ + "backgroundColorTokens: object", + "borderStyles: object", + "borderTokens: object", + "colorTokens: object", + "fontStyles: object", + "foregroundColorTokens: object", + "getPaletteFromTheme: function", + "layoutStyles: object", + "layoutTokens: object", + "shadowStyles: object", + "shadowTokens: object", + "styleFunction: function", + "textTokens: function", + "tokenBuilder: function", +] +`; + +exports[`public entry points ./testing keeps its runtime export names 1`] = ` +[ + "MODE_SURFACE: object", + "PAIRINGS: object", + "WCAG: object", + "defaultFlexTokens: object", + "defaultResolvedThemeAppearance: object", + "getContrastFailures: function", + "getUnresolvableContrastPairs: function", + "mockTheme: object", + "validateContrastPairs: function", +] +`; + +exports[`public entry points ./theming keeps its runtime export names 1`] = ` +[ + "FlexThemeReference: function", + "RootContext: object", + "RootInputBoundary: object", + "ThemeContext: object", + "ThemeProvider: function", + "ThemeReference: function", + "ThemedRoot: object", + "appearanceOptionFromResolved: function", + "appearanceOptionsFromLegacy: function", + "createThemeAppearanceSource: function", + "getCurrentAppearance: function", + "isHighContrast: function", + "mapFontPipelineToTheme: function", + "mapPipelineToShadow: function", + "mapPipelineToTheme: function", + "normalizeThemeAppearanceRequest: function", + "resolveThemeAppearance: function", + "setIsHighContrast: function", + "themeAppearanceKey: function", + "useRootInputModality: function", + "useRootSettings: function", + "useTheme: function", +] +`; + +exports[`public entry points ./theming/compat keeps its runtime export names 1`] = ` +[ + "getDefaultLegacyTheme: function", + "themeFromFlexTokens: function", +] +`; + +exports[`public entry points ./theming/compat/defaults keeps its runtime export names 1`] = ` +[ + "getDefaultLegacyTheme: function", +] +`; + +exports[`public entry points ./theming/legacy-source keeps its runtime export names 1`] = ` +[ + "ThemeReference: function", +] +`; + +exports[`public entry points ./tokens/global keeps its runtime export names 1`] = ` +[ + "colorAnchorPrimary: string", + "colorAnchorShade10: string", + "colorAnchorShade20: string", + "colorAnchorShade30: string", + "colorAnchorShade40: string", + "colorAnchorShade50: string", + "colorAnchorTint10: string", + "colorAnchorTint20: string", + "colorAnchorTint30: string", + "colorAnchorTint40: string", + "colorAnchorTint50: string", + "colorAnchorTint60: string", + "colorBeigePrimary: string", + "colorBeigeShade10: string", + "colorBeigeShade20: string", + "colorBeigeShade30: string", + "colorBeigeShade40: string", + "colorBeigeShade50: string", + "colorBeigeTint10: string", + "colorBeigeTint20: string", + "colorBeigeTint30: string", + "colorBeigeTint40: string", + "colorBeigeTint50: string", + "colorBeigeTint60: string", + "colorBerryPrimary: string", + "colorBerryShade10: string", + "colorBerryShade20: string", + "colorBerryShade30: string", + "colorBerryShade40: string", + "colorBerryShade50: string", + "colorBerryTint10: string", + "colorBerryTint20: string", + "colorBerryTint30: string", + "colorBerryTint40: string", + "colorBerryTint50: string", + "colorBerryTint60: string", + "colorBlack: string", + "colorBlackAlpha10: string", + "colorBlackAlpha20: string", + "colorBlackAlpha30: string", + "colorBlackAlpha40: string", + "colorBlackAlpha5: string", + "colorBlackAlpha50: string", + "colorBlackAlpha60: string", + "colorBlackAlpha70: string", + "colorBlackAlpha80: string", + "colorBlackAlpha90: string", + "colorBluePrimary: string", + "colorBlueShade10: string", + "colorBlueShade20: string", + "colorBlueShade30: string", + "colorBlueShade40: string", + "colorBlueShade50: string", + "colorBlueTint10: string", + "colorBlueTint20: string", + "colorBlueTint30: string", + "colorBlueTint40: string", + "colorBlueTint50: string", + "colorBlueTint60: string", + "colorBrand10: string", + "colorBrand100: string", + "colorBrand110: string", + "colorBrand120: string", + "colorBrand130: string", + "colorBrand140: string", + "colorBrand150: string", + "colorBrand160: string", + "colorBrand20: string", + "colorBrand30: string", + "colorBrand40: string", + "colorBrand50: string", + "colorBrand60: string", + "colorBrand70: string", + "colorBrand80: string", + "colorBrand90: string", + "colorBrandShade40: string", + "colorBrandShade50: string", + "colorBrandShade60: string", + "colorBrandShadowAmbient: string", + "colorBrandShadowKey: string", + "colorBrandTint50: string", + "colorBrandTint60: string", + "colorBrassPrimary: string", + "colorBrassShade10: string", + "colorBrassShade20: string", + "colorBrassShade30: string", + "colorBrassShade40: string", + "colorBrassShade50: string", + "colorBrassTint10: string", + "colorBrassTint20: string", + "colorBrassTint30: string", + "colorBrassTint40: string", + "colorBrassTint50: string", + "colorBrassTint60: string", + "colorBronzePrimary: string", + "colorBronzeShade10: string", + "colorBronzeShade20: string", + "colorBronzeShade30: string", + "colorBronzeShade40: string", + "colorBronzeShade50: string", + "colorBronzeTint10: string", + "colorBronzeTint20: string", + "colorBronzeTint30: string", + "colorBronzeTint40: string", + "colorBronzeTint50: string", + "colorBronzeTint60: string", + "colorBrownPrimary: string", + "colorBrownShade10: string", + "colorBrownShade20: string", + "colorBrownShade30: string", + "colorBrownShade40: string", + "colorBrownShade50: string", + "colorBrownTint10: string", + "colorBrownTint20: string", + "colorBrownTint30: string", + "colorBrownTint40: string", + "colorBrownTint50: string", + "colorBrownTint60: string", + "colorBurgundyPrimary: string", + "colorBurgundyShade10: string", + "colorBurgundyShade20: string", + "colorBurgundyShade30: string", + "colorBurgundyShade40: string", + "colorBurgundyShade50: string", + "colorBurgundyTint10: string", + "colorBurgundyTint20: string", + "colorBurgundyTint30: string", + "colorBurgundyTint40: string", + "colorBurgundyTint50: string", + "colorBurgundyTint60: string", + "colorCharcoalPrimary: string", + "colorCharcoalShade10: string", + "colorCharcoalShade20: string", + "colorCharcoalShade30: string", + "colorCharcoalShade40: string", + "colorCharcoalShade50: string", + "colorCharcoalTint10: string", + "colorCharcoalTint20: string", + "colorCharcoalTint30: string", + "colorCharcoalTint40: string", + "colorCharcoalTint50: string", + "colorCharcoalTint60: string", + "colorCornflowerPrimary: string", + "colorCornflowerShade10: string", + "colorCornflowerShade20: string", + "colorCornflowerShade30: string", + "colorCornflowerShade40: string", + "colorCornflowerShade50: string", + "colorCornflowerTint10: string", + "colorCornflowerTint20: string", + "colorCornflowerTint30: string", + "colorCornflowerTint40: string", + "colorCornflowerTint50: string", + "colorCornflowerTint60: string", + "colorCranberryPrimary: string", + "colorCranberryShade10: string", + "colorCranberryShade20: string", + "colorCranberryShade30: string", + "colorCranberryShade40: string", + "colorCranberryShade50: string", + "colorCranberryTint10: string", + "colorCranberryTint20: string", + "colorCranberryTint30: string", + "colorCranberryTint40: string", + "colorCranberryTint50: string", + "colorCranberryTint60: string", + "colorCyanPrimary: string", + "colorCyanShade10: string", + "colorCyanShade20: string", + "colorCyanShade30: string", + "colorCyanShade40: string", + "colorCyanShade50: string", + "colorCyanTint10: string", + "colorCyanTint20: string", + "colorCyanTint30: string", + "colorCyanTint40: string", + "colorCyanTint50: string", + "colorCyanTint60: string", + "colorDarkBluePrimary: string", + "colorDarkBlueShade10: string", + "colorDarkBlueShade20: string", + "colorDarkBlueShade30: string", + "colorDarkBlueShade40: string", + "colorDarkBlueShade50: string", + "colorDarkBlueTint10: string", + "colorDarkBlueTint20: string", + "colorDarkBlueTint30: string", + "colorDarkBlueTint40: string", + "colorDarkBlueTint50: string", + "colorDarkBlueTint60: string", + "colorDarkBrownPrimary: string", + "colorDarkBrownShade10: string", + "colorDarkBrownShade20: string", + "colorDarkBrownShade30: string", + "colorDarkBrownShade40: string", + "colorDarkBrownShade50: string", + "colorDarkBrownTint10: string", + "colorDarkBrownTint20: string", + "colorDarkBrownTint30: string", + "colorDarkBrownTint40: string", + "colorDarkBrownTint50: string", + "colorDarkBrownTint60: string", + "colorDarkGreenPrimary: string", + "colorDarkGreenShade10: string", + "colorDarkGreenShade20: string", + "colorDarkGreenShade30: string", + "colorDarkGreenShade40: string", + "colorDarkGreenShade50: string", + "colorDarkGreenTint10: string", + "colorDarkGreenTint20: string", + "colorDarkGreenTint30: string", + "colorDarkGreenTint40: string", + "colorDarkGreenTint50: string", + "colorDarkGreenTint60: string", + "colorDarkOrangePrimary: string", + "colorDarkOrangeShade10: string", + "colorDarkOrangeShade20: string", + "colorDarkOrangeShade30: string", + "colorDarkOrangeShade40: string", + "colorDarkOrangeShade50: string", + "colorDarkOrangeTint10: string", + "colorDarkOrangeTint20: string", + "colorDarkOrangeTint30: string", + "colorDarkOrangeTint40: string", + "colorDarkOrangeTint50: string", + "colorDarkOrangeTint60: string", + "colorDarkPurplePrimary: string", + "colorDarkPurpleShade10: string", + "colorDarkPurpleShade20: string", + "colorDarkPurpleShade30: string", + "colorDarkPurpleShade40: string", + "colorDarkPurpleShade50: string", + "colorDarkPurpleTint10: string", + "colorDarkPurpleTint20: string", + "colorDarkPurpleTint30: string", + "colorDarkPurpleTint40: string", + "colorDarkPurpleTint50: string", + "colorDarkPurpleTint60: string", + "colorDarkRedPrimary: string", + "colorDarkRedShade10: string", + "colorDarkRedShade20: string", + "colorDarkRedShade30: string", + "colorDarkRedShade40: string", + "colorDarkRedShade50: string", + "colorDarkRedTint10: string", + "colorDarkRedTint20: string", + "colorDarkRedTint30: string", + "colorDarkRedTint40: string", + "colorDarkRedTint50: string", + "colorDarkRedTint60: string", + "colorDarkTealPrimary: string", + "colorDarkTealShade10: string", + "colorDarkTealShade20: string", + "colorDarkTealShade30: string", + "colorDarkTealShade40: string", + "colorDarkTealShade50: string", + "colorDarkTealTint10: string", + "colorDarkTealTint20: string", + "colorDarkTealTint30: string", + "colorDarkTealTint40: string", + "colorDarkTealTint50: string", + "colorDarkTealTint60: string", + "colorExcelPrimary: string", + "colorExcelShade10: string", + "colorExcelShade20: string", + "colorExcelShade30: string", + "colorExcelShade40: string", + "colorExcelShade50: string", + "colorExcelShade60: string", + "colorExcelTint10: string", + "colorExcelTint20: string", + "colorExcelTint30: string", + "colorExcelTint40: string", + "colorExcelTint50: string", + "colorExcelTint60: string", + "colorForestPrimary: string", + "colorForestShade10: string", + "colorForestShade20: string", + "colorForestShade30: string", + "colorForestShade40: string", + "colorForestShade50: string", + "colorForestTint10: string", + "colorForestTint20: string", + "colorForestTint30: string", + "colorForestTint40: string", + "colorForestTint50: string", + "colorForestTint60: string", + "colorGoldPrimary: string", + "colorGoldShade10: string", + "colorGoldShade20: string", + "colorGoldShade30: string", + "colorGoldShade40: string", + "colorGoldShade50: string", + "colorGoldTint10: string", + "colorGoldTint20: string", + "colorGoldTint30: string", + "colorGoldTint40: string", + "colorGoldTint50: string", + "colorGoldTint60: string", + "colorGrapePrimary: string", + "colorGrapeShade10: string", + "colorGrapeShade20: string", + "colorGrapeShade30: string", + "colorGrapeShade40: string", + "colorGrapeShade50: string", + "colorGrapeTint10: string", + "colorGrapeTint20: string", + "colorGrapeTint30: string", + "colorGrapeTint40: string", + "colorGrapeTint50: string", + "colorGrapeTint60: string", + "colorGreenPrimary: string", + "colorGreenShade10: string", + "colorGreenShade20: string", + "colorGreenShade30: string", + "colorGreenShade40: string", + "colorGreenShade50: string", + "colorGreenTint10: string", + "colorGreenTint20: string", + "colorGreenTint30: string", + "colorGreenTint40: string", + "colorGreenTint50: string", + "colorGreenTint60: string", + "colorGrey10: string", + "colorGrey10Alpha10: string", + "colorGrey10Alpha20: string", + "colorGrey10Alpha30: string", + "colorGrey10Alpha40: string", + "colorGrey10Alpha5: string", + "colorGrey10Alpha50: string", + "colorGrey10Alpha60: string", + "colorGrey10Alpha70: string", + "colorGrey10Alpha80: string", + "colorGrey10Alpha90: string", + "colorGrey12: string", + "colorGrey12Alpha10: string", + "colorGrey12Alpha20: string", + "colorGrey12Alpha30: string", + "colorGrey12Alpha40: string", + "colorGrey12Alpha5: string", + "colorGrey12Alpha50: string", + "colorGrey12Alpha60: string", + "colorGrey12Alpha70: string", + "colorGrey12Alpha80: string", + "colorGrey12Alpha90: string", + "colorGrey14: string", + "colorGrey14Alpha10: string", + "colorGrey14Alpha20: string", + "colorGrey14Alpha30: string", + "colorGrey14Alpha40: string", + "colorGrey14Alpha5: string", + "colorGrey14Alpha50: string", + "colorGrey14Alpha60: string", + "colorGrey14Alpha70: string", + "colorGrey14Alpha80: string", + "colorGrey14Alpha90: string", + "colorGrey16: string", + "colorGrey18: string", + "colorGrey2: string", + "colorGrey20: string", + "colorGrey22: string", + "colorGrey24: string", + "colorGrey26: string", + "colorGrey28: string", + "colorGrey30: string", + "colorGrey32: string", + "colorGrey34: string", + "colorGrey36: string", + "colorGrey38: string", + "colorGrey4: string", + "colorGrey40: string", + "colorGrey42: string", + "colorGrey44: string", + "colorGrey46: string", + "colorGrey48: string", + "colorGrey50: string", + "colorGrey52: string", + "colorGrey54: string", + "colorGrey56: string", + "colorGrey58: string", + "colorGrey6: string", + "colorGrey60: string", + "colorGrey62: string", + "colorGrey64: string", + "colorGrey66: string", + "colorGrey68: string", + "colorGrey70: string", + "colorGrey72: string", + "colorGrey74: string", + "colorGrey76: string", + "colorGrey78: string", + "colorGrey8: string", + "colorGrey80: string", + "colorGrey82: string", + "colorGrey84: string", + "colorGrey86: string", + "colorGrey88: string", + "colorGrey90: string", + "colorGrey92: string", + "colorGrey94: string", + "colorGrey96: string", + "colorGrey98: string", + "colorHcButtonFace: string", + "colorHcButtonText: string", + "colorHcCanvas: string", + "colorHcCanvasText: string", + "colorHcDisabled: string", + "colorHcHighlight: string", + "colorHcHighlightText: string", + "colorHcHyperlink: string", + "colorHotPinkPrimary: string", + "colorHotPinkShade10: string", + "colorHotPinkShade20: string", + "colorHotPinkShade30: string", + "colorHotPinkShade40: string", + "colorHotPinkShade50: string", + "colorHotPinkTint10: string", + "colorHotPinkTint20: string", + "colorHotPinkTint30: string", + "colorHotPinkTint40: string", + "colorHotPinkTint50: string", + "colorHotPinkTint60: string", + "colorLavenderPrimary: string", + "colorLavenderShade10: string", + "colorLavenderShade20: string", + "colorLavenderShade30: string", + "colorLavenderShade40: string", + "colorLavenderShade50: string", + "colorLavenderTint10: string", + "colorLavenderTint20: string", + "colorLavenderTint30: string", + "colorLavenderTint40: string", + "colorLavenderTint50: string", + "colorLavenderTint60: string", + "colorLightBluePrimary: string", + "colorLightBlueShade10: string", + "colorLightBlueShade20: string", + "colorLightBlueShade30: string", + "colorLightBlueShade40: string", + "colorLightBlueShade50: string", + "colorLightBlueTint10: string", + "colorLightBlueTint20: string", + "colorLightBlueTint30: string", + "colorLightBlueTint40: string", + "colorLightBlueTint50: string", + "colorLightBlueTint60: string", + "colorLightGreenPrimary: string", + "colorLightGreenShade10: string", + "colorLightGreenShade20: string", + "colorLightGreenShade30: string", + "colorLightGreenShade40: string", + "colorLightGreenShade50: string", + "colorLightGreenTint10: string", + "colorLightGreenTint20: string", + "colorLightGreenTint30: string", + "colorLightGreenTint40: string", + "colorLightGreenTint50: string", + "colorLightGreenTint60: string", + "colorLightTealPrimary: string", + "colorLightTealShade10: string", + "colorLightTealShade20: string", + "colorLightTealShade30: string", + "colorLightTealShade40: string", + "colorLightTealShade50: string", + "colorLightTealTint10: string", + "colorLightTealTint20: string", + "colorLightTealTint30: string", + "colorLightTealTint40: string", + "colorLightTealTint50: string", + "colorLightTealTint60: string", + "colorLilacPrimary: string", + "colorLilacShade10: string", + "colorLilacShade20: string", + "colorLilacShade30: string", + "colorLilacShade40: string", + "colorLilacShade50: string", + "colorLilacTint10: string", + "colorLilacTint20: string", + "colorLilacTint30: string", + "colorLilacTint40: string", + "colorLilacTint50: string", + "colorLilacTint60: string", + "colorLimePrimary: string", + "colorLimeShade10: string", + "colorLimeShade20: string", + "colorLimeShade30: string", + "colorLimeShade40: string", + "colorLimeShade50: string", + "colorLimeTint10: string", + "colorLimeTint20: string", + "colorLimeTint30: string", + "colorLimeTint40: string", + "colorLimeTint50: string", + "colorLimeTint60: string", + "colorMagentaPrimary: string", + "colorMagentaShade10: string", + "colorMagentaShade20: string", + "colorMagentaShade30: string", + "colorMagentaShade40: string", + "colorMagentaShade50: string", + "colorMagentaTint10: string", + "colorMagentaTint20: string", + "colorMagentaTint30: string", + "colorMagentaTint40: string", + "colorMagentaTint50: string", + "colorMagentaTint60: string", + "colorMarigoldPrimary: string", + "colorMarigoldShade10: string", + "colorMarigoldShade20: string", + "colorMarigoldShade30: string", + "colorMarigoldShade40: string", + "colorMarigoldShade50: string", + "colorMarigoldTint10: string", + "colorMarigoldTint20: string", + "colorMarigoldTint30: string", + "colorMarigoldTint40: string", + "colorMarigoldTint50: string", + "colorMarigoldTint60: string", + "colorMinkPrimary: string", + "colorMinkShade10: string", + "colorMinkShade20: string", + "colorMinkShade30: string", + "colorMinkShade40: string", + "colorMinkShade50: string", + "colorMinkTint10: string", + "colorMinkTint20: string", + "colorMinkTint30: string", + "colorMinkTint40: string", + "colorMinkTint50: string", + "colorMinkTint60: string", + "colorNavyPrimary: string", + "colorNavyShade10: string", + "colorNavyShade20: string", + "colorNavyShade30: string", + "colorNavyShade40: string", + "colorNavyShade50: string", + "colorNavyTint10: string", + "colorNavyTint20: string", + "colorNavyTint30: string", + "colorNavyTint40: string", + "colorNavyTint50: string", + "colorNavyTint60: string", + "colorNeutralShadowAmbient: string", + "colorNeutralShadowAmbientDarker: string", + "colorNeutralShadowAmbientLighter: string", + "colorNeutralShadowKey: string", + "colorNeutralShadowKeyDarker: string", + "colorNeutralShadowKeyLighter: string", + "colorOfficePrimary: string", + "colorOfficeShade10: string", + "colorOfficeShade20: string", + "colorOfficeShade30: string", + "colorOfficeShade40: string", + "colorOfficeShade50: string", + "colorOfficeShade60: string", + "colorOfficeTint10: string", + "colorOfficeTint20: string", + "colorOfficeTint30: string", + "colorOfficeTint40: string", + "colorOfficeTint50: string", + "colorOfficeTint60: string", + "colorOneNotePrimary: string", + "colorOneNoteShade10: string", + "colorOneNoteShade20: string", + "colorOneNoteShade30: string", + "colorOneNoteShade40: string", + "colorOneNoteShade50: string", + "colorOneNoteShade60: string", + "colorOneNoteTint10: string", + "colorOneNoteTint20: string", + "colorOneNoteTint30: string", + "colorOneNoteTint40: string", + "colorOneNoteTint50: string", + "colorOneNoteTint60: string", + "colorOrangePrimary: string", + "colorOrangeShade10: string", + "colorOrangeShade20: string", + "colorOrangeShade30: string", + "colorOrangeShade40: string", + "colorOrangeShade50: string", + "colorOrangeTint10: string", + "colorOrangeTint20: string", + "colorOrangeTint30: string", + "colorOrangeTint40: string", + "colorOrangeTint50: string", + "colorOrangeTint60: string", + "colorOrchidPrimary: string", + "colorOrchidShade10: string", + "colorOrchidShade20: string", + "colorOrchidShade30: string", + "colorOrchidShade40: string", + "colorOrchidShade50: string", + "colorOrchidTint10: string", + "colorOrchidTint20: string", + "colorOrchidTint30: string", + "colorOrchidTint40: string", + "colorOrchidTint50: string", + "colorOrchidTint60: string", + "colorOutlookPrimary: string", + "colorOutlookShade10: string", + "colorOutlookShade20: string", + "colorOutlookShade30: string", + "colorOutlookShade40: string", + "colorOutlookShade50: string", + "colorOutlookShade60: string", + "colorOutlookTint10: string", + "colorOutlookTint20: string", + "colorOutlookTint30: string", + "colorOutlookTint40: string", + "colorOutlookTint50: string", + "colorOutlookTint60: string", + "colorPeachPrimary: string", + "colorPeachShade10: string", + "colorPeachShade20: string", + "colorPeachShade30: string", + "colorPeachShade40: string", + "colorPeachShade50: string", + "colorPeachTint10: string", + "colorPeachTint20: string", + "colorPeachTint30: string", + "colorPeachTint40: string", + "colorPeachTint50: string", + "colorPeachTint60: string", + "colorPinkPrimary: string", + "colorPinkShade10: string", + "colorPinkShade20: string", + "colorPinkShade30: string", + "colorPinkShade40: string", + "colorPinkShade50: string", + "colorPinkTint10: string", + "colorPinkTint20: string", + "colorPinkTint30: string", + "colorPinkTint40: string", + "colorPinkTint50: string", + "colorPinkTint60: string", + "colorPlatinumPrimary: string", + "colorPlatinumShade10: string", + "colorPlatinumShade20: string", + "colorPlatinumShade30: string", + "colorPlatinumShade40: string", + "colorPlatinumShade50: string", + "colorPlatinumTint10: string", + "colorPlatinumTint20: string", + "colorPlatinumTint30: string", + "colorPlatinumTint40: string", + "colorPlatinumTint50: string", + "colorPlatinumTint60: string", + "colorPlumPrimary: string", + "colorPlumShade10: string", + "colorPlumShade20: string", + "colorPlumShade30: string", + "colorPlumShade40: string", + "colorPlumShade50: string", + "colorPlumTint10: string", + "colorPlumTint20: string", + "colorPlumTint30: string", + "colorPlumTint40: string", + "colorPlumTint50: string", + "colorPlumTint60: string", + "colorPowerPointPrimary: string", + "colorPowerPointShade10: string", + "colorPowerPointShade20: string", + "colorPowerPointShade30: string", + "colorPowerPointShade40: string", + "colorPowerPointShade50: string", + "colorPowerPointShade60: string", + "colorPowerPointTint10: string", + "colorPowerPointTint20: string", + "colorPowerPointTint30: string", + "colorPowerPointTint40: string", + "colorPowerPointTint50: string", + "colorPowerPointTint60: string", + "colorPumpkinPrimary: string", + "colorPumpkinShade10: string", + "colorPumpkinShade20: string", + "colorPumpkinShade30: string", + "colorPumpkinShade40: string", + "colorPumpkinShade50: string", + "colorPumpkinTint10: string", + "colorPumpkinTint20: string", + "colorPumpkinTint30: string", + "colorPumpkinTint40: string", + "colorPumpkinTint50: string", + "colorPumpkinTint60: string", + "colorPurplePrimary: string", + "colorPurpleShade10: string", + "colorPurpleShade20: string", + "colorPurpleShade30: string", + "colorPurpleShade40: string", + "colorPurpleShade50: string", + "colorPurpleTint10: string", + "colorPurpleTint20: string", + "colorPurpleTint30: string", + "colorPurpleTint40: string", + "colorPurpleTint50: string", + "colorPurpleTint60: string", + "colorRedPrimary: string", + "colorRedShade10: string", + "colorRedShade20: string", + "colorRedShade30: string", + "colorRedShade40: string", + "colorRedShade50: string", + "colorRedTint10: string", + "colorRedTint20: string", + "colorRedTint30: string", + "colorRedTint40: string", + "colorRedTint50: string", + "colorRedTint60: string", + "colorRoyalBluePrimary: string", + "colorRoyalBlueShade10: string", + "colorRoyalBlueShade20: string", + "colorRoyalBlueShade30: string", + "colorRoyalBlueShade40: string", + "colorRoyalBlueShade50: string", + "colorRoyalBlueTint10: string", + "colorRoyalBlueTint20: string", + "colorRoyalBlueTint30: string", + "colorRoyalBlueTint40: string", + "colorRoyalBlueTint50: string", + "colorRoyalBlueTint60: string", + "colorSeafoamPrimary: string", + "colorSeafoamShade10: string", + "colorSeafoamShade20: string", + "colorSeafoamShade30: string", + "colorSeafoamShade40: string", + "colorSeafoamShade50: string", + "colorSeafoamTint10: string", + "colorSeafoamTint20: string", + "colorSeafoamTint30: string", + "colorSeafoamTint40: string", + "colorSeafoamTint50: string", + "colorSeafoamTint60: string", + "colorSilverPrimary: string", + "colorSilverShade10: string", + "colorSilverShade20: string", + "colorSilverShade30: string", + "colorSilverShade40: string", + "colorSilverShade50: string", + "colorSilverTint10: string", + "colorSilverTint20: string", + "colorSilverTint30: string", + "colorSilverTint40: string", + "colorSilverTint50: string", + "colorSilverTint60: string", + "colorSteelPrimary: string", + "colorSteelShade10: string", + "colorSteelShade20: string", + "colorSteelShade30: string", + "colorSteelShade40: string", + "colorSteelShade50: string", + "colorSteelTint10: string", + "colorSteelTint20: string", + "colorSteelTint30: string", + "colorSteelTint40: string", + "colorSteelTint50: string", + "colorSteelTint60: string", + "colorTealPrimary: string", + "colorTealShade10: string", + "colorTealShade20: string", + "colorTealShade30: string", + "colorTealShade40: string", + "colorTealShade50: string", + "colorTealTint10: string", + "colorTealTint20: string", + "colorTealTint30: string", + "colorTealTint40: string", + "colorTealTint50: string", + "colorTealTint60: string", + "colorWhite: string", + "colorWhiteAlpha10: string", + "colorWhiteAlpha20: string", + "colorWhiteAlpha30: string", + "colorWhiteAlpha40: string", + "colorWhiteAlpha5: string", + "colorWhiteAlpha50: string", + "colorWhiteAlpha60: string", + "colorWhiteAlpha70: string", + "colorWhiteAlpha80: string", + "colorWhiteAlpha90: string", + "colorWordPrimary: string", + "colorWordShade10: string", + "colorWordShade20: string", + "colorWordShade30: string", + "colorWordShade40: string", + "colorWordShade50: string", + "colorWordShade60: string", + "colorWordTint10: string", + "colorWordTint20: string", + "colorWordTint30: string", + "colorWordTint40: string", + "colorWordTint50: string", + "colorWordTint60: string", + "colorYellowPrimary: string", + "colorYellowShade10: string", + "colorYellowShade20: string", + "colorYellowShade30: string", + "colorYellowShade40: string", + "colorYellowShade50: string", + "colorYellowTint10: string", + "colorYellowTint20: string", + "colorYellowTint30: string", + "colorYellowTint40: string", + "colorYellowTint50: string", + "colorYellowTint60: string", + "cornerRadius120: number", + "cornerRadius20: number", + "cornerRadius40: number", + "cornerRadius60: number", + "cornerRadius80: number", + "cornerRadiusCircular: number", + "cornerRadiusNone: number", + "fontFamilyBase: string", + "fontFamilyMonospace: string", + "fontFamilyNumeric: string", + "fontLineHeight100: number", + "fontLineHeight1000: number", + "fontLineHeight200: number", + "fontLineHeight300: number", + "fontLineHeight400: number", + "fontLineHeight500: number", + "fontLineHeight600: number", + "fontLineHeight700: number", + "fontLineHeight800: number", + "fontLineHeight900: number", + "fontSize100: number", + "fontSize1000: number", + "fontSize200: number", + "fontSize300: number", + "fontSize400: number", + "fontSize500: number", + "fontSize600: number", + "fontSize700: number", + "fontSize800: number", + "fontSize900: number", + "fontWeightBold: string", + "fontWeightMedium: string", + "fontWeightRegular: string", + "fontWeightSemibold: string", + "size100: number", + "size120: number", + "size1200: number", + "size160: number", + "size20: number", + "size200: number", + "size240: number", + "size280: number", + "size320: number", + "size360: number", + "size40: number", + "size400: number", + "size480: number", + "size560: number", + "size60: number", + "size640: number", + "size720: number", + "size80: number", + "size800: number", + "sizeNone: number", + "strokeWidth05: number", + "strokeWidth10: number", + "strokeWidth15: number", + "strokeWidth20: number", + "strokeWidth30: number", + "strokeWidth40: number", + "strokeWidth60: number", + "strokeWidthNone: number", +] +`; + +exports[`public entry points ./tokens/legacy keeps its runtime export names 1`] = ` +[ + "getAliasTokens: function", + "getShadowTokens: function", + "globalTokens: object", + "hcAliasTokens: object", +] +`; diff --git a/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts b/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts new file mode 100644 index 0000000000..117e678419 --- /dev/null +++ b/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts @@ -0,0 +1,69 @@ +import { PlatformColor } from 'react-native'; + +import { getDefaultLegacyTheme } from '../../theming/compat/defaultLegacyTheme'; +import { themeFromFlexTokens } from '../../theming/compat/themeFromFlexTokens'; +import type { ResolvedThemeAppearance } from '../../theming/appearance.types'; +import type { Theme } from '../../theming/types/Theme.types'; +import { mockTheme } from '../../testing/mockTheme'; +import { defaultFlexTokens } from '../../tokens/defaultTokens'; +import { flexTokensFromTheme } from '../../tokens/flexTokensFromTheme'; +import { flexTokenFingerprints, themeFingerprints } from './fingerprint'; + +const appearances: [string, ResolvedThemeAppearance][] = [ + ['light', { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base' }], + ['dark', { colorScheme: 'dark', contrast: 'standard', interfaceLevel: 'base' }], + ['darkElevated', { colorScheme: 'dark', contrast: 'standard', interfaceLevel: 'elevated' }], + ['highContrast', { colorScheme: 'dark', contrast: 'highContrast', interfaceLevel: 'base' }], +]; + +/** + * Legacy Fluent consumers must observe identical values through every Flex + * refactoring phase. The forward-adapter baseline compares the values a + * consumer reads for each color state, so a representation change that keeps + * those values passes unchanged. + */ +describe('legacy compatibility baseline', () => { + it.each(appearances)('keeps the %s default legacy theme', (_name, appearance) => { + expect(themeFingerprints(getDefaultLegacyTheme(appearance))).toMatchSnapshot(); + }); + + it.each(appearances)('keeps Flex values converted from the %s default legacy theme', (_name, appearance) => { + expect(flexTokenFingerprints(flexTokensFromTheme(getDefaultLegacyTheme(appearance)))).toMatchSnapshot(); + }); + + it('keeps Flex values converted from the mock theme', () => { + expect(flexTokenFingerprints(flexTokensFromTheme(mockTheme))).toMatchSnapshot(); + }); + + it('keeps native colors authored in a legacy theme through both adapters', () => { + const rest = PlatformColor('controlAccentColor'); + const hover = PlatformColor('selectedControlColor'); + const theme: Theme = { + ...mockTheme, + colors: { ...mockTheme.colors, brandBackground: rest, brandBackgroundHover: hover }, + }; + + const tokens = flexTokensFromTheme(theme); + expect(tokens.color.backgroundBrandHeavy).toEqual(rest); + expect(tokens.color.hover.backgroundBrandHeavy).toEqual(hover); + + const projected = themeFromFlexTokens(tokens, appearances[0][1]); + expect(projected.colors.brandBackground).toEqual(rest); + expect(projected.colors.brandBackgroundHover).toEqual(hover); + }); +}); + +/** + * Flex-sourced values. These intentionally change when the Flex defaults adopt + * current x3 sources; they must not change during mechanical or + * representation-only phases. + */ +describe('Flex default baseline', () => { + it('keeps the values consumers read from the default Flex tokens', () => { + expect(flexTokenFingerprints(defaultFlexTokens)).toMatchSnapshot(); + }); + + it.each(appearances)('keeps the %s legacy projection of the default Flex tokens', (_name, appearance) => { + expect(themeFingerprints(themeFromFlexTokens(defaultFlexTokens, appearance))).toMatchSnapshot(); + }); +}); diff --git a/packages/agentic/design/src/test/compatibility/entryPoints.test.ts b/packages/agentic/design/src/test/compatibility/entryPoints.test.ts new file mode 100644 index 0000000000..febe565024 --- /dev/null +++ b/packages/agentic/design/src/test/compatibility/entryPoints.test.ts @@ -0,0 +1,65 @@ +type ExportConditions = { + types: string; + 'react-native': string; + import: string; + default: string; +}; + +type PackageJson = { + exports: Record; +}; + +const packageJson = jest.requireActual('../../../package.json'); + +const publicEntryPoints = [ + '.', + './tokens/global', + './tokens/legacy', + './color-lib', + './theming', + './theming/legacy-source', + './theming/compat', + './theming/compat/defaults', + './testing', + './styling', + './styling/stylesheet', + './styling/tokens', +]; + +const moduleEntries = Object.entries(packageJson.exports).filter(([key]) => key !== './package.json') as [string, ExportConditions][]; + +function sourceStem(target: string): string { + const prefix = './src/'; + const extension = target.endsWith('.tsx') ? '.tsx' : '.ts'; + expect(target.startsWith(prefix)).toBe(true); + expect(target.endsWith(extension)).toBe(true); + return target.slice(prefix.length, target.length - extension.length); +} + +function describeExports(moduleExports: Record): string[] { + return Object.keys(moduleExports) + .sort() + .map((name) => `${name}: ${typeof moduleExports[name]}`); +} + +describe('public entry points', () => { + it('retains every supported package subpath', () => { + expect(Object.keys(packageJson.exports).sort()).toEqual([...publicEntryPoints, './package.json'].sort()); + expect(packageJson.exports['./package.json']).toBe('./package.json'); + }); + + it.each(moduleEntries)('%s keeps mirrored types, react-native, import, and default conditions', (_key, conditions) => { + expect(Object.keys(conditions)).toEqual(['types', 'react-native', 'import', 'default']); + expect(conditions.default).toBe(conditions['react-native']); + + const stem = sourceStem(conditions['react-native']); + expect(conditions.types).toBe(`./lib/${stem}.d.ts`); + expect(conditions.import).toBe(`./lib/${stem}.js`); + }); + + it.each(moduleEntries)('%s keeps its runtime export names', (_key, conditions) => { + const moduleExports = jest.requireActual>(`../../../${conditions['react-native'].slice(2)}`); + + expect(describeExports(moduleExports)).toMatchSnapshot(); + }); +}); diff --git a/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts b/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts new file mode 100644 index 0000000000..072420107d --- /dev/null +++ b/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts @@ -0,0 +1,265 @@ +import type { TextStyle } from 'react-native'; + +import { flexTokensFromTheme, useThemeState } from '../../index'; +import type { + FontSize as RootFontSize, + FontWeight as RootFontWeight, + ResolvedThemeAppearance as RootResolvedThemeAppearance, + ThemeAppearanceOptions as RootThemeAppearanceOptions, + ThemeState, +} from '../../index'; +import { getDefaultLegacyTheme as getDefaultLegacyThemeOnly } from '../../theming/compat/defaultLegacyTheme'; +import { getDefaultLegacyTheme, themeFromFlexTokens } from '../../theming/compat/index'; +import type { ThemeFromFlexTokensOptions } from '../../theming/compat/index'; +import { + getCurrentAppearance, + isHighContrast, + mapFontPipelineToTheme, + mapPipelineToShadow, + mapPipelineToTheme, + resolveThemeAppearance, + setIsHighContrast, + ThemeContext, + ThemeProvider, + ThemeReference, + themeAppearanceKey, + useTheme, +} from '../../theming/index'; +import type { + AliasColorTokens, + AppearanceOptions, + BaseShadowAliasTokens, + Color, + FabricWebPalette, + FontDynamicTypeRamp, + FontFamilies, + FontFamily, + FontFamilyValue, + FontSize, + FontSizeValuePoints, + FontSizes, + FontWeight, + FontWeightValue, + FontWeights, + OfficePalette, + OnThemeChange, + Palette, + PaletteBackgroundColors, + PaletteTextColors, + PartialPalette, + PartialShadowDefinition, + PartialTheme, + PartialTypography, + ResolvedThemeAppearance, + ShadowToken, + ShadowValue, + Spacing, + TextStyling, + Theme, + ThemeColorDefinition, + ThemeOptions, + ThemeProviderProps, + ThemeRecipe, + ThemeShadowDefinition, + ThemeTransform, + Typography, + Variant, + Variants, + VariantValue, +} from '../../theming/index'; +import { ThemeReference as LegacySourceThemeReference } from '../../theming/legacySource'; +import type { OnThemeChange as LegacySourceOnThemeChange, ThemeRecipe as LegacySourceThemeRecipe } from '../../theming/legacySource'; +import { themedStyleSheet } from '../../styling/stylesheet/index'; +import type { NamedStyles } from '../../styling/stylesheet/index'; +import { + backgroundColorTokens, + borderStyles, + borderTokens, + colorTokens, + fontStyles, + foregroundColorTokens, + getPaletteFromTheme, + layoutStyles, + layoutTokens, + shadowStyles, + shadowTokens, + styleFunction, + textTokens, + tokenBuilder, +} from '../../styling/tokens/index'; +import type { + FontDecorationTokens, + FontStyleTokens, + FontTokens, + FontVariantTokens, + IBackgroundColorTokens, + IBorderTokens, + IColorTokens, + IForegroundColorTokens, + IShadowTokens, + LayoutTokens, + LookupThemePart, + OperationSet, + StyleFactoryFunction, + StyleFactoryFunctionRaw, + StyleFactoryOperation, + TokenBuilder, +} from '../../styling/tokens/index'; +import { getAliasTokens, getShadowTokens, globalTokens, hcAliasTokens } from '../../tokens/legacy/index'; + +/** + * Every type name the compatibility packages re-export must remain importable + * from its owning design entry point. + */ +export type LegacyThemeTypeInventory = [ + AliasColorTokens, + AppearanceOptions, + BaseShadowAliasTokens, + Color, + FabricWebPalette, + FontDynamicTypeRamp, + FontFamilies, + FontFamily, + FontFamilyValue, + FontSize, + FontSizeValuePoints, + FontSizes, + FontWeight, + FontWeightValue, + FontWeights, + OfficePalette, + OnThemeChange, + LegacySourceOnThemeChange, + Palette, + PaletteBackgroundColors, + PaletteTextColors, + PartialPalette, + PartialShadowDefinition, + PartialTheme, + PartialTypography, + ShadowToken, + ShadowValue, + Spacing, + TextStyling, + Theme, + ThemeColorDefinition, + ThemeOptions, + ThemeProviderProps, + ThemeRecipe, + LegacySourceThemeRecipe, + ThemeShadowDefinition, + ThemeTransform, + Typography, + Variant, + VariantValue, + Variants, + ThemeFromFlexTokensOptions, +]; + +export type LegacyStylingTypeInventory = [ + FontDecorationTokens, + FontStyleTokens, + FontTokens, + FontVariantTokens, + IBackgroundColorTokens, + IBorderTokens, + IColorTokens, + IForegroundColorTokens, + IShadowTokens, + LayoutTokens, + LookupThemePart, + OperationSet, + StyleFactoryFunction, + StyleFactoryFunctionRaw, + StyleFactoryOperation, + TokenBuilder, + NamedStyles<{ root: object }>, +]; + +// The root and legacy entry points keep their distinct meanings for these names. +export type RootTextAttributeInventory = [RootFontSize, RootFontWeight]; + +// External code declares three-field appearance literals and must keep compiling. +const legacyAppearance: ResolvedThemeAppearance = { + colorScheme: 'dark', + contrast: 'standard', + interfaceLevel: 'base', +}; +const rootAppearance: RootResolvedThemeAppearance = { + colorScheme: 'light', + contrast: 'highContrast', + interfaceLevel: 'elevated', +}; +const rootAppearanceOptions: RootThemeAppearanceOptions = { colorScheme: 'system', contrast: 'standard' }; +const fallbackAppearance: Partial = { colorScheme: 'dark' }; + +function externalAppearanceKey(appearance: ResolvedThemeAppearance): string { + return themeAppearanceKey(appearance); +} + +function appearanceFromState(state: ThemeState): ResolvedThemeAppearance { + return state.appearance; +} + +const legacyTransform: ThemeTransform = (parent: Theme, appearance?: ResolvedThemeAppearance) => ({ + colors: { bodyText: appearance?.colorScheme === 'dark' ? parent.colors.bodyText : '#010203' }, +}); + +describe('legacy compatibility types', () => { + it('accepts three-field appearance values at every legacy-facing boundary', () => { + expect(externalAppearanceKey(legacyAppearance)).toBe('dark|standard|base'); + expect(themeAppearanceKey(rootAppearance)).toBe('light|highContrast|elevated'); + expect(resolveThemeAppearance(rootAppearanceOptions, {}, fallbackAppearance).resolved).toEqual( + expect.objectContaining({ colorScheme: 'dark', contrast: 'standard', interfaceLevel: 'base' }), + ); + + const legacyTheme = getDefaultLegacyTheme(legacyAppearance); + expect(getDefaultLegacyThemeOnly(legacyAppearance)).toBe(legacyTheme); + expect(themeFromFlexTokens(flexTokensFromTheme(legacyTheme), legacyAppearance).host.appearance).toBe('dark'); + + const reference = new ThemeReference(legacyTheme, legacyTransform); + expect(reference.resolveTheme(legacyAppearance).colors.bodyText).toBe(legacyTheme.colors.bodyText); + expect(reference.resolveTheme(rootAppearance).colors.bodyText).toBe('#010203'); + expect(appearanceFromState).toEqual(expect.any(Function)); + }); + + it('shares legacy constructors and contexts across entry points', () => { + expect(LegacySourceThemeReference).toBe(ThemeReference); + expect(ThemeContext).toBeDefined(); + expect(ThemeProvider).toEqual(expect.any(Function)); + expect(useTheme).toEqual(expect.any(Function)); + expect(useThemeState).toEqual(expect.any(Function)); + }); + + it('keeps legacy utility and token builder values', () => { + for (const value of [ + getCurrentAppearance, + isHighContrast, + mapFontPipelineToTheme, + mapPipelineToShadow, + mapPipelineToTheme, + setIsHighContrast, + getAliasTokens, + getShadowTokens, + themedStyleSheet, + backgroundColorTokens, + borderStyles, + borderTokens, + colorTokens, + fontStyles, + foregroundColorTokens, + getPaletteFromTheme, + layoutStyles, + layoutTokens, + shadowStyles, + shadowTokens, + styleFunction, + textTokens, + tokenBuilder, + ]) { + expect(value).toBeDefined(); + } + expect(globalTokens).toBeDefined(); + expect(hcAliasTokens).toBeDefined(); + }); +}); diff --git a/packages/agentic/design/src/test/compatibility/fingerprint.ts b/packages/agentic/design/src/test/compatibility/fingerprint.ts new file mode 100644 index 0000000000..350d754358 --- /dev/null +++ b/packages/agentic/design/src/test/compatibility/fingerprint.ts @@ -0,0 +1,78 @@ +import { createHash } from 'node:crypto'; + +import type { Theme } from '../../theming/types/Theme.types'; +import type { FlexTokens } from '../../tokens/flex.types'; + +type EffectiveColor = { rest: unknown; hover: unknown; pressed: unknown }; + +function sortValue(value: unknown): unknown { + if (Array.isArray(value)) { + return value.map(sortValue); + } + if (typeof value === 'function') { + return '[function]'; + } + if (value && typeof value === 'object') { + const record = value as Record; + return Object.fromEntries( + Object.keys(record) + .sort() + .map((key) => [key, sortValue(record[key])]), + ); + } + return value; +} + +/** + * A short, order-independent digest of a JSON-compatible value. Snapshots of + * these digests detect any value change without checking in large payloads. + */ +export function fingerprint(value: unknown): string { + return createHash('sha256') + .update(JSON.stringify(sortValue(value)) ?? 'undefined') + .digest('hex') + .slice(0, 16); +} + +/** + * The color values a consumer observes for each token and interaction state, + * independent of how the token representation stores omitted states. + */ +export function effectiveFlexColors(color: FlexTokens['color']): Record { + const result: Record = {}; + for (const name of Object.keys(color).sort()) { + if (name === 'hover' || name === 'pressed') { + continue; + } + const rest = color[name as keyof typeof color]; + result[name] = { + rest, + hover: color.hover?.[name as keyof typeof color.hover] ?? rest, + pressed: color.pressed?.[name as keyof typeof color.pressed] ?? rest, + }; + } + return result; +} + +export function flexTokenFingerprints(tokens: FlexTokens): Record { + const { color, ...groups } = tokens; + const colors = effectiveFlexColors(color); + const result: Record = { + colorCount: Object.keys(colors).length, + color: fingerprint(colors), + }; + for (const group of Object.keys(groups).sort()) { + result[group] = fingerprint(groups[group as keyof typeof groups]); + } + return result; +} + +export function themeFingerprints(theme: Theme): Record { + const result: Record = { + colorCount: Object.keys(theme.colors).length, + }; + for (const section of Object.keys(theme).sort()) { + result[section] = fingerprint(theme[section as keyof Theme]); + } + return result; +} From 178892a56947e8b5792aef77a5cb8acb21ac0883 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 23 Oct 2026 18:05:39 -0700 Subject: [PATCH 03/18] design: reorganize into flex/fluent/types/test (refactor phase 2) Move Flex-owned implementations under src/flex, legacy Fluent theme types, references, token data, compat projection, and legacy styling under src/fluent, shared type-only contracts under src/types, and test-only fixtures and validation under src/test. Package export keys and conditions are unchanged; only their targets moved. - Unify ThemeState in src/types/themeState.types.ts and remove the duplicate RuntimeThemeState. - Share guarded object-path traversal between mapObjectFromObject and themeFromFlexTokens while keeping their overwrite policies and errors. - Add an import-boundary test with positive controls, and give every design bundle-size scenario a required-module control. - Update generator paths, owning references, and docs links. Compatibility baselines and snapshots are unchanged. Bundle module counts are unchanged; Flex scenarios grow 122 B raw from the shared path helpers and the legacy projection shrinks 238 B. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5030bce5-d7f7-4fb1-93de-68599b79269f --- apps/bundle-size/scenarios.json | 19 +- docs/pages/Theming/CustomTheme.md | 8 +- docs/pages/Theming/Tokens/Basics.md | 2 +- packages/agentic/design/package.json | 56 ++--- .../agentic/design/references/contributing.md | 38 ++-- .../agentic/design/references/entry-points.md | 22 +- packages/agentic/design/references/styling.md | 3 +- packages/agentic/design/references/testing.md | 10 +- packages/agentic/design/references/theming.md | 5 +- packages/agentic/design/references/tokens.md | 16 +- .../scripts/token-mappings/check-mappings.cjs | 4 +- .../design/src/color-lib/colorLib.test.ts | 6 +- .../design/src/color-lib/interaction.ts | 2 +- .../agentic/design/src/color-lib/types.ts | 4 +- .../adapters}/flexTokensFromTheme.test.ts | 4 +- .../adapters}/flexTokensFromTheme.ts | 10 +- .../defaults}/defaultTokens.ts | 4 +- .../flexThemeReference.test.ts | 2 +- .../{theming => flex}/flexThemeReference.ts | 12 +- .../{ => flex}/styling/colorStyles.test.ts | 8 +- .../src/{ => flex}/styling/colorStyles.ts | 8 +- .../flex.test.ts => flex/tokens.test.ts} | 6 +- .../flex.types.ts => flex/tokens.types.ts} | 2 +- .../src/{ => flex}/useThemeState.test.ts | 16 +- .../design/src/{ => flex}/useThemeState.ts | 34 +-- .../__snapshots__/theming-utils.test.ts.snap | 0 .../__tests__/themeReference.test.ts | 6 +- .../__tests__/theming-utils.test.ts | 2 +- .../__tests__/defaultLegacyTheme.test.ios.ts | 0 .../compat/createLegacyAliasTokens.ts | 2 +- .../compat/defaultLegacyColors.ts | 0 .../compat/defaultLegacyTheme.test.ts | 0 .../compat/defaultLegacyTheme.ts | 6 +- .../src/{theming => fluent}/compat/index.ts | 0 .../compat/stockWebPalette.macos.ts | 2 +- .../compat/stockWebPalette.ts | 2 +- .../compat/stockWebPalette.win32.ts | 2 +- .../compat/themeFromFlexTokens.test.ts | 4 +- .../compat/themeFromFlexTokens.ts | 43 +--- .../src/{theming => fluent}/legacySource.ts | 2 +- .../mapPipelineToShadow.ts | 0 .../mapPipelineToTheme.android.ts | 0 .../mapPipelineToTheme.ios.ts | 2 +- .../{theming => fluent}/mapPipelineToTheme.ts | 0 .../src/{theming => fluent}/mergeTheme.ts | 2 +- .../platformUtils.defaults.ts | 0 .../platformUtils.macos.ts | 2 +- .../src/{theming => fluent}/platformUtils.ts | 0 .../platformUtils.win32.ts | 0 .../platformUtils.windows.ts | 0 .../{ => fluent}/styling/stylesheet/index.ts | 0 .../stylesheet/themedStyleSheet.test.ts | 0 .../styling/stylesheet/themedStyleSheet.ts | 0 .../styling/tokens/border-tokens.ts | 2 +- .../styling/tokens/color-tokens.ts | 3 +- .../src/{ => fluent}/styling/tokens/index.ts | 0 .../styling/tokens/layout-tokens.ts | 2 +- .../styling/tokens/shadow-tokens.ts | 2 +- .../styling/tokens/text-tokens.ts | 3 +- .../styling/tokens/token.function.ts | 0 .../styling/tokens/token.types.ts | 0 .../styling/tokens/tokenBuilder.ts | 2 +- .../src/{theming => fluent}/themeReference.ts | 12 +- .../tokens}/getTokens.android.ts | 2 +- .../legacy => fluent/tokens}/getTokens.ios.ts | 2 +- .../legacy => fluent/tokens}/getTokens.ts | 2 +- .../__tests__/processAliasTokens.test.ts | 0 .../highContrast/processAliasTokens.ts | 0 .../tokens}/highContrast/tokens-alias.ts | 0 .../highContrast/tokens-alias.win32.ts | 0 .../{tokens/legacy => fluent/tokens}/index.ts | 0 .../tokens}/tokens-global.android.ts | 0 .../tokens}/tokens-global.ios.ts | 0 .../legacy => fluent/tokens}/tokens-global.ts | 0 .../tokens}/tokens-global.win32.ts | 0 .../{theming => fluent}/types/Color.types.ts | 0 .../{theming => fluent}/types/Shadow.types.ts | 0 .../{theming => fluent}/types/Theme.types.ts | 0 .../types/Typography.types.ts | 0 .../types/palette.types.ts | 0 .../src/{theming => fluent}/useTheme.test.ts | 14 +- .../src/{theming => fluent}/useTheme.ts | 10 +- packages/agentic/design/src/index.ts | 13 +- .../design/src/styling/branchedStyle.test.ts | 4 +- .../design/src/styling/branchedStyle.ts | 4 +- packages/agentic/design/src/styling/index.ts | 4 +- .../design/src/{testing => test}/README.md | 0 .../color-validation/constants.ts | 0 .../color-validation/pairings.ts | 0 .../color-validation/types.ts | 2 +- .../color-validation/validation.test.ts | 6 +- .../color-validation/validation.ts | 2 +- .../compatibilityBaseline.test.ts | 14 +- .../compatibility/entryPoints.types.test.ts | 20 +- .../src/test/compatibility/fingerprint.ts | 4 +- .../compatibility/importBoundaries.test.ts | 205 ++++++++++++++++++ .../{testing => test/fixtures}/mockTheme.ts | 2 +- .../fixtures}/x3InteractionConformance.ts | 0 .../design/src/{testing => test}/index.ts | 4 +- .../design/src/theming/ThemeProvider.tsx | 2 +- .../design/src/theming/ThemedRoot.test.tsx | 12 +- .../agentic/design/src/theming/ThemedRoot.tsx | 2 +- .../agentic/design/src/theming/appearance.ts | 4 +- .../design/src/theming/appearanceSource.ts | 2 +- .../agentic/design/src/theming/context.ts | 4 +- packages/agentic/design/src/theming/index.ts | 34 +-- packages/agentic/design/src/theming/modern.ts | 6 +- .../design/src/theming/themeRuntime.ts | 24 +- .../agentic/design/src/theming/themeSource.ts | 6 +- .../src/tokens/mappings/flex-token-map.yaml | 8 +- .../{concepts => tokens}/textAttributes.ts | 2 +- .../{theming => types}/appearance.types.ts | 0 .../design/src/types/themeState.types.ts | 31 +++ .../agentic/design/src/utilities/objects.ts | 51 ++++- packages/components/Text/MIGRATION.md | 2 +- 115 files changed, 580 insertions(+), 328 deletions(-) rename packages/agentic/design/src/{tokens => flex/adapters}/flexTokensFromTheme.test.ts (94%) rename packages/agentic/design/src/{tokens => flex/adapters}/flexTokensFromTheme.ts (62%) rename packages/agentic/design/src/{tokens => flex/defaults}/defaultTokens.ts (99%) rename packages/agentic/design/src/{theming => flex}/flexThemeReference.test.ts (97%) rename packages/agentic/design/src/{theming => flex}/flexThemeReference.ts (94%) rename packages/agentic/design/src/{ => flex}/styling/colorStyles.test.ts (95%) rename packages/agentic/design/src/{ => flex}/styling/colorStyles.ts (95%) rename packages/agentic/design/src/{tokens/flex.test.ts => flex/tokens.test.ts} (96%) rename packages/agentic/design/src/{tokens/flex.types.ts => flex/tokens.types.ts} (99%) rename packages/agentic/design/src/{ => flex}/useThemeState.test.ts (95%) rename packages/agentic/design/src/{ => flex}/useThemeState.ts (67%) rename packages/agentic/design/src/{theming => fluent}/__tests__/__snapshots__/theming-utils.test.ts.snap (100%) rename packages/agentic/design/src/{theming => fluent}/__tests__/themeReference.test.ts (97%) rename packages/agentic/design/src/{theming => fluent}/__tests__/theming-utils.test.ts (98%) rename packages/agentic/design/src/{theming => fluent}/compat/__tests__/defaultLegacyTheme.test.ios.ts (100%) rename packages/agentic/design/src/{theming => fluent}/compat/createLegacyAliasTokens.ts (92%) rename packages/agentic/design/src/{theming => fluent}/compat/defaultLegacyColors.ts (100%) rename packages/agentic/design/src/{theming => fluent}/compat/defaultLegacyTheme.test.ts (100%) rename packages/agentic/design/src/{theming => fluent}/compat/defaultLegacyTheme.ts (97%) rename packages/agentic/design/src/{theming => fluent}/compat/index.ts (100%) rename packages/agentic/design/src/{theming => fluent}/compat/stockWebPalette.macos.ts (97%) rename packages/agentic/design/src/{theming => fluent}/compat/stockWebPalette.ts (98%) rename packages/agentic/design/src/{theming => fluent}/compat/stockWebPalette.win32.ts (97%) rename packages/agentic/design/src/{theming => fluent}/compat/themeFromFlexTokens.test.ts (96%) rename packages/agentic/design/src/{theming => fluent}/compat/themeFromFlexTokens.ts (64%) rename packages/agentic/design/src/{theming => fluent}/legacySource.ts (65%) rename packages/agentic/design/src/{theming => fluent}/mapPipelineToShadow.ts (100%) rename packages/agentic/design/src/{theming => fluent}/mapPipelineToTheme.android.ts (100%) rename packages/agentic/design/src/{theming => fluent}/mapPipelineToTheme.ios.ts (99%) rename packages/agentic/design/src/{theming => fluent}/mapPipelineToTheme.ts (100%) rename packages/agentic/design/src/{theming => fluent}/mergeTheme.ts (80%) rename packages/agentic/design/src/{theming => fluent}/platformUtils.defaults.ts (100%) rename packages/agentic/design/src/{theming => fluent}/platformUtils.macos.ts (79%) rename packages/agentic/design/src/{theming => fluent}/platformUtils.ts (100%) rename packages/agentic/design/src/{theming => fluent}/platformUtils.win32.ts (100%) rename packages/agentic/design/src/{theming => fluent}/platformUtils.windows.ts (100%) rename packages/agentic/design/src/{ => fluent}/styling/stylesheet/index.ts (100%) rename packages/agentic/design/src/{ => fluent}/styling/stylesheet/themedStyleSheet.test.ts (100%) rename packages/agentic/design/src/{ => fluent}/styling/stylesheet/themedStyleSheet.ts (100%) rename packages/agentic/design/src/{ => fluent}/styling/tokens/border-tokens.ts (93%) rename packages/agentic/design/src/{ => fluent}/styling/tokens/color-tokens.ts (86%) rename packages/agentic/design/src/{ => fluent}/styling/tokens/index.ts (100%) rename packages/agentic/design/src/{ => fluent}/styling/tokens/layout-tokens.ts (95%) rename packages/agentic/design/src/{ => fluent}/styling/tokens/shadow-tokens.ts (93%) rename packages/agentic/design/src/{ => fluent}/styling/tokens/text-tokens.ts (96%) rename packages/agentic/design/src/{ => fluent}/styling/tokens/token.function.ts (100%) rename packages/agentic/design/src/{ => fluent}/styling/tokens/token.types.ts (100%) rename packages/agentic/design/src/{ => fluent}/styling/tokens/tokenBuilder.ts (92%) rename packages/agentic/design/src/{theming => fluent}/themeReference.ts (96%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/getTokens.android.ts (95%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/getTokens.ios.ts (96%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/getTokens.ts (94%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/highContrast/__tests__/processAliasTokens.test.ts (100%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/highContrast/processAliasTokens.ts (100%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/highContrast/tokens-alias.ts (100%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/highContrast/tokens-alias.win32.ts (100%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/index.ts (100%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/tokens-global.android.ts (100%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/tokens-global.ios.ts (100%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/tokens-global.ts (100%) rename packages/agentic/design/src/{tokens/legacy => fluent/tokens}/tokens-global.win32.ts (100%) rename packages/agentic/design/src/{theming => fluent}/types/Color.types.ts (100%) rename packages/agentic/design/src/{theming => fluent}/types/Shadow.types.ts (100%) rename packages/agentic/design/src/{theming => fluent}/types/Theme.types.ts (100%) rename packages/agentic/design/src/{theming => fluent}/types/Typography.types.ts (100%) rename packages/agentic/design/src/{theming => fluent}/types/palette.types.ts (100%) rename packages/agentic/design/src/{theming => fluent}/useTheme.test.ts (89%) rename packages/agentic/design/src/{theming => fluent}/useTheme.ts (81%) rename packages/agentic/design/src/{testing => test}/README.md (100%) rename packages/agentic/design/src/{testing => test}/color-validation/constants.ts (100%) rename packages/agentic/design/src/{testing => test}/color-validation/pairings.ts (100%) rename packages/agentic/design/src/{testing => test}/color-validation/types.ts (96%) rename packages/agentic/design/src/{testing => test}/color-validation/validation.test.ts (97%) rename packages/agentic/design/src/{testing => test}/color-validation/validation.ts (98%) create mode 100644 packages/agentic/design/src/test/compatibility/importBoundaries.test.ts rename packages/agentic/design/src/{testing => test/fixtures}/mockTheme.ts (99%) rename packages/agentic/design/src/{testing/color-validation => test/fixtures}/x3InteractionConformance.ts (100%) rename packages/agentic/design/src/{testing => test}/index.ts (82%) rename packages/agentic/design/src/{concepts => tokens}/textAttributes.ts (98%) rename packages/agentic/design/src/{theming => types}/appearance.types.ts (100%) create mode 100644 packages/agentic/design/src/types/themeState.types.ts diff --git a/apps/bundle-size/scenarios.json b/apps/bundle-size/scenarios.json index bd5bb63949..dbbae8f21d 100644 --- a/apps/bundle-size/scenarios.json +++ b/apps/bundle-size/scenarios.json @@ -15,13 +15,19 @@ "name": "design-theme-state", "module": "@fluentui-react-native/design", "exports": ["FlexThemeReference", "ThemeProvider", "useThemeState"], - "forbiddenInputPatterns": ["/theming/compat/", "/tokens/legacy/", "/color-lib/"] + "forbiddenInputPatterns": ["/design/src/fluent/", "/design/src/test/", "/color-lib/"], + "requiredInputPatterns": [ + "/design/src/flex/flexThemeReference.", + "/design/src/flex/useThemeState.", + "/design/src/theming/ThemeProvider." + ] }, { "name": "design-themed-root", "module": "@fluentui-react-native/design", "exports": ["ThemedRoot", "useRootSettings", "useThemeState"], - "forbiddenInputPatterns": ["/theming/compat/", "/tokens/legacy/", "/color-lib/"] + "forbiddenInputPatterns": ["/design/src/fluent/", "/design/src/test/", "/color-lib/"], + "requiredInputPatterns": ["/design/src/flex/useThemeState.", "/design/src/theming/ThemedRoot."] }, { "name": "design-color-lib", @@ -41,13 +47,18 @@ "exports": ["ThemeReference"] } ], - "forbiddenInputPatterns": ["/theming/compat/", "/tokens/legacy/"] + "forbiddenInputPatterns": ["/design/src/fluent/compat/", "/design/src/fluent/tokens/", "/design/src/test/"], + "requiredInputPatterns": ["/design/src/fluent/themeReference."] }, { "name": "design-legacy-theme-from-flex", "module": "@fluentui-react-native/design/theming", "exports": ["FlexThemeReference", "ThemeProvider", "useTheme"], - "requiredInputPatterns": ["/theming/compat/themeFromFlexTokens.", "/tokens/legacy/"] + "requiredInputPatterns": [ + "/design/src/fluent/compat/themeFromFlexTokens.", + "/design/src/fluent/tokens/", + "/design/src/fluent/useTheme." + ] } ] } diff --git a/docs/pages/Theming/CustomTheme.md b/docs/pages/Theming/CustomTheme.md index 800a85d1e1..b226e436df 100644 --- a/docs/pages/Theming/CustomTheme.md +++ b/docs/pages/Theming/CustomTheme.md @@ -8,7 +8,7 @@ There are two ways to make a custom theme: you can tack onto an existing one usi ### Extending an existing `ThemeReference` -We have a concept of `ThemeRecipes` which allow for layering of partial theme objects to create the ultimately desired theme. `ThemeRecipes` are functions which take a `Theme` and spit out a [`PartialTheme`](../../../packages/agentic/design/src/theming/types/Theme.types.ts), which is then deep merged into the base theme object. +We have a concept of `ThemeRecipes` which allow for layering of partial theme objects to create the ultimately desired theme. `ThemeRecipes` are functions which take a `Theme` and spit out a [`PartialTheme`](../../../packages/agentic/design/src/fluent/types/Theme.types.ts), which is then deep merged into the base theme object. You can extend one of our default themes by creating a `ThemeReference` using the default theme as the base theme, and then add your customization as a `ThemeRecipe`: @@ -35,7 +35,7 @@ const theme = new ThemeReference(createDefaultTheme(), ### `ThemeReference` from scratch -You can create your own `ThemeReference` and pass it into the `ThemeProvider`. To create a `ThemeReference` you'll need to create a new instance of `ThemeReference`. You can find the type definition [here](../../../packages/agentic/design/src/theming/themeReference.ts). +You can create your own `ThemeReference` and pass it into the `ThemeProvider`. To create a `ThemeReference` you'll need to create a new instance of `ThemeReference`. You can find the type definition [here](../../../packages/agentic/design/src/fluent/themeReference.ts). ## Theme property customization @@ -46,7 +46,7 @@ There's two ways to customize a FURN theme's properties: ### Changing theme tokens directly -Theme tokens can be overridden directly. You can specify different values for theme entries and add to the set of colors. You can see what can be overridden by looking at the [Theme type definition](../../../packages/agentic/design/src/theming/types/Theme.types.ts). +Theme tokens can be overridden directly. You can specify different values for theme entries and add to the set of colors. You can see what can be overridden by looking at the [Theme type definition](../../../packages/agentic/design/src/fluent/types/Theme.types.ts). This approach is useful if you need the customizations to be applied to all components. @@ -161,7 +161,7 @@ interface Theme { } ``` -(Taken from the [`Theme` type definition](../../../packages/agentic/design/src/theming/types/Theme.types.ts).) +(Taken from the [`Theme` type definition](../../../packages/agentic/design/src/fluent/types/Theme.types.ts).) NOTE: If you would prefer to customize one instance of a FURN component instead, use [the customize API](../../../packages/framework/composition/README.md). diff --git a/docs/pages/Theming/Tokens/Basics.md b/docs/pages/Theming/Tokens/Basics.md index c2bdc62b1b..06fd9f882b 100644 --- a/docs/pages/Theming/Tokens/Basics.md +++ b/docs/pages/Theming/Tokens/Basics.md @@ -74,7 +74,7 @@ export const defaultNotificationTokens: TokenSettings Notes about alias color tokens: -- Different platforms can have different sets of alias tokens; however, the entire set of alias tokens are all defined in the same interface. See [Color.types.ts](../../../../packages/agentic/design/src/theming/types/Color.types.ts#L861) for this interface and which platforms define which alias tokens. +- Different platforms can have different sets of alias tokens; however, the entire set of alias tokens are all defined in the same interface. See [Color.types.ts](../../../../packages/agentic/design/src/fluent/types/Color.types.ts#L861) for this interface and which platforms define which alias tokens. - As a result, if an alias token is referenced that does not exist for that platform, there won't be any compile-time or run-time errors. Instead, the color shown will default to black. Special case: if accessing a specific color, you can find it in the `globalTokens.color` property. diff --git a/packages/agentic/design/package.json b/packages/agentic/design/package.json index 737366a905..6e3459c7f6 100644 --- a/packages/agentic/design/package.json +++ b/packages/agentic/design/package.json @@ -40,10 +40,10 @@ "default": "./src/tokens/global.generated.ts" }, "./tokens/legacy": { - "types": "./lib/tokens/legacy/index.d.ts", - "react-native": "./src/tokens/legacy/index.ts", - "import": "./lib/tokens/legacy/index.js", - "default": "./src/tokens/legacy/index.ts" + "types": "./lib/fluent/tokens/index.d.ts", + "react-native": "./src/fluent/tokens/index.ts", + "import": "./lib/fluent/tokens/index.js", + "default": "./src/fluent/tokens/index.ts" }, "./color-lib": { "types": "./lib/color-lib/index.d.ts", @@ -58,28 +58,28 @@ "default": "./src/theming/index.ts" }, "./theming/legacy-source": { - "types": "./lib/theming/legacySource.d.ts", - "react-native": "./src/theming/legacySource.ts", - "import": "./lib/theming/legacySource.js", - "default": "./src/theming/legacySource.ts" + "types": "./lib/fluent/legacySource.d.ts", + "react-native": "./src/fluent/legacySource.ts", + "import": "./lib/fluent/legacySource.js", + "default": "./src/fluent/legacySource.ts" }, "./theming/compat": { - "types": "./lib/theming/compat/index.d.ts", - "react-native": "./src/theming/compat/index.ts", - "import": "./lib/theming/compat/index.js", - "default": "./src/theming/compat/index.ts" + "types": "./lib/fluent/compat/index.d.ts", + "react-native": "./src/fluent/compat/index.ts", + "import": "./lib/fluent/compat/index.js", + "default": "./src/fluent/compat/index.ts" }, "./theming/compat/defaults": { - "types": "./lib/theming/compat/defaultLegacyTheme.d.ts", - "react-native": "./src/theming/compat/defaultLegacyTheme.ts", - "import": "./lib/theming/compat/defaultLegacyTheme.js", - "default": "./src/theming/compat/defaultLegacyTheme.ts" + "types": "./lib/fluent/compat/defaultLegacyTheme.d.ts", + "react-native": "./src/fluent/compat/defaultLegacyTheme.ts", + "import": "./lib/fluent/compat/defaultLegacyTheme.js", + "default": "./src/fluent/compat/defaultLegacyTheme.ts" }, "./testing": { - "types": "./lib/testing/index.d.ts", - "react-native": "./src/testing/index.ts", - "import": "./lib/testing/index.js", - "default": "./src/testing/index.ts" + "types": "./lib/test/index.d.ts", + "react-native": "./src/test/index.ts", + "import": "./lib/test/index.js", + "default": "./src/test/index.ts" }, "./styling": { "types": "./lib/styling/index.d.ts", @@ -88,16 +88,16 @@ "default": "./src/styling/index.ts" }, "./styling/stylesheet": { - "types": "./lib/styling/stylesheet/index.d.ts", - "react-native": "./src/styling/stylesheet/index.ts", - "import": "./lib/styling/stylesheet/index.js", - "default": "./src/styling/stylesheet/index.ts" + "types": "./lib/fluent/styling/stylesheet/index.d.ts", + "react-native": "./src/fluent/styling/stylesheet/index.ts", + "import": "./lib/fluent/styling/stylesheet/index.js", + "default": "./src/fluent/styling/stylesheet/index.ts" }, "./styling/tokens": { - "types": "./lib/styling/tokens/index.d.ts", - "react-native": "./src/styling/tokens/index.ts", - "import": "./lib/styling/tokens/index.js", - "default": "./src/styling/tokens/index.ts" + "types": "./lib/fluent/styling/tokens/index.d.ts", + "react-native": "./src/fluent/styling/tokens/index.ts", + "import": "./lib/fluent/styling/tokens/index.js", + "default": "./src/fluent/styling/tokens/index.ts" }, "./package.json": "./package.json" }, diff --git a/packages/agentic/design/references/contributing.md b/packages/agentic/design/references/contributing.md index ef353ef42c..295ac78772 100644 --- a/packages/agentic/design/references/contributing.md +++ b/packages/agentic/design/references/contributing.md @@ -9,18 +9,25 @@ owner_paths: ## Source map -| Path | Owns | -| ---------------------- | ----------------------------------------------------------------------------------------- | -| `src/theming/` | Theme sources, providers, boundaries, appearance, runtime caches, and legacy theme types | -| `src/theming/compat/` | The Flex-to-legacy projection and complete legacy defaults; never reachable from the root | -| `src/useThemeState.ts` | `useThemeState`, `useThemeAppearance`, and `themedStyleSheetFactory` | -| `src/tokens/` | Flex token types and defaults, the Theme-to-Flex adapter, and generated global tokens | -| `src/tokens/mappings/` | The canonical token map and its generated projections; see `tokens.md` | -| `src/tokens/legacy/` | Legacy alias, shadow, and global token data | -| `src/styling/` | State and color style factories plus the legacy styling subpaths; see `styling.md` | -| `src/color-lib/` | The runtime color engine; see `color-lib.md` | -| `src/testing/` | Test-only fixtures and color validation; see `testing.md` | -| `src/index.ts` | The modern root entry point; see `entry-points.md` for every subpath | +| Path | Owns | +| ---------------------- | -------------------------------------------------------------------------------------------------------- | +| `src/types/` | Type-only contracts shared by the Flex and Fluent models, such as appearance and theme state | +| `src/theming/` | Shared theme sources, providers, boundaries, appearance, runtime caches, and the `theming` facades | +| `src/flex/` | Flex token types, defaults, the Theme-to-Flex adapter, `FlexThemeReference`, `useThemeState`, and styles | +| `src/fluent/` | Legacy Fluent theme types, `ThemeReference`, `useTheme`, platform utilities, and legacy styling | +| `src/fluent/compat/` | The Flex-to-legacy projection and complete legacy defaults; never reachable from the root | +| `src/fluent/tokens/` | Legacy alias, shadow, and global token data | +| `src/tokens/` | Generated global tokens and shared token attributes | +| `src/tokens/mappings/` | The canonical token map and its generated projections; see `tokens.md` | +| `src/styling/` | Shared state style factories and the `styling` facade; see `styling.md` | +| `src/color-lib/` | The runtime color engine; see `color-lib.md` | +| `src/test/` | Test-only fixtures, compatibility baselines, and color validation; see `testing.md` | +| `src/index.ts` | The modern root entry point; see `entry-points.md` for every subpath | + +Shared modules may import types from either model. At runtime, only the `theming` facade and the legacy subpaths reach +`src/fluent/`; the root and `styling` graphs may reach `src/flex/` but never `src/fluent/`. Production code never imports +`src/test/`. Source paths are private: consumers use the package subpaths in `entry-points.md`, never `src/` or `lib/` +paths. The package's scripts directory holds `codegen.cts`, which runs before every build, and the token-mapping check and upstream drift tools described in `tokens.md`. Generated token and projection files are committed; change their inputs @@ -28,8 +35,9 @@ and rebuild rather than editing them. ## Invariants -- Keep the root import graph modern: it must not reach `useTheme`, `src/theming/compat/`, legacy token payloads, or - `src/color-lib/`. Run the bundle-size scenarios when changing imports between these areas. +- Keep the root import graph modern: it must not reach `useTheme`, anything under `src/fluent/`, or + `src/color-lib/`. `src/test/compatibility/importBoundaries.test.ts` checks the entry graphs; run the bundle-size + scenarios too when changing imports between these areas. - Never mutate author-owned theme inputs; caches are external and keyed by source, revision, and resolved appearance. - Keep platform appearance listeners subscription-scoped; nothing subscribes at module import. - Keep the experimental native appearance modules and platform theme packages out of this package's dependencies; @@ -41,6 +49,8 @@ and rebuild rather than editing them. Jest runs with the macOS platform preset declared in `package.json`. A test named `*.test..ts`, such as `defaultLegacyTheme.test.ios.ts`, runs under that platform, so add one when a platform implementation file changes. Iterate with a focused selection, such as `yarn test themeRuntime` or `yarn test --findRelatedTests src/theming/appearance.ts`. +`src/test/compatibility/` holds the public-surface, legacy-runtime, and import-boundary baselines; update their +snapshots only for an intended compatibility change. ## Validation diff --git a/packages/agentic/design/references/entry-points.md b/packages/agentic/design/references/entry-points.md index b408e6c75d..a10eb023ef 100644 --- a/packages/agentic/design/references/entry-points.md +++ b/packages/agentic/design/references/entry-points.md @@ -27,7 +27,11 @@ public symbols by name from each entry point; do not add barrel re-exports. The `apps/bundle-size` `design-*` scenarios guard these boundaries: the modern root and legacy-source scenarios forbid the compatibility, legacy-token, and (for the root) color-library modules, while the color-library and legacy-projection -scenarios require their expected modules. +scenarios require their expected modules. Every scenario also requires a module it is expected to load, so a moved file +cannot make a forbidden pattern pass vacuously. + +The package specifiers above are the supported import surface. Source and build paths such as `src/fluent/...` or +`lib/...` are private implementation details that may move without a breaking change. ## Compatibility packages @@ -35,14 +39,14 @@ scenarios require their expected modules. The legacy packages listed here are compatibility entry points and contain only explicit named re-exports. -| Legacy package | Exported symbols | Owning design entry point | Definition | -| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ | -| `@fluentui-react-native/theme` | `ThemeProvider`, `ThemeProviderProps`, `ThemeReference`, `OnThemeChange`, `ThemeRecipe`, `ThemeTransform` | `@fluentui-react-native/design/theming` | `src/theming/ThemeProvider.tsx`, `src/theming/themeReference.ts` | -| `@fluentui-react-native/theme-types` | `AliasColorTokens`, `AppearanceOptions`, `BaseShadowAliasTokens`, `Color`, `FabricWebPalette`, `FontDynamicTypeRamp`, `FontFamilies`, `FontFamily`, `FontFamilyValue`, `FontSize`, `FontSizeValuePoints`, `FontSizes`, `FontWeight`, `FontWeightValue`, `FontWeights`, `OfficePalette`, `Palette`, `PaletteBackgroundColors`, `PaletteTextColors`, `PartialPalette`, `PartialShadowDefinition`, `PartialTheme`, `PartialTypography`, `ShadowToken`, `ShadowValue`, `Spacing`, `TextStyling`, `Theme`, `ThemeColorDefinition`, `ThemeContext`, `ThemeOptions`, `ThemeShadowDefinition`, `Typography`, `Variant`, `VariantValue`, `Variants`, `useTheme` | `@fluentui-react-native/design/theming` | `src/theming/context.ts`, `src/theming/types/` | -| `@fluentui-react-native/theming-utils` | `getCurrentAppearance`, `isHighContrast`, `mapFontPipelineToTheme`, `mapPipelineToShadow`, `mapPipelineToTheme`, `setIsHighContrast` | `@fluentui-react-native/design/theming` | `src/theming/platformUtils.*.ts`, `src/theming/mapPipelineToShadow.ts`, `src/theming/mapPipelineToTheme*.ts` | -| `@fluentui-react-native/theme-tokens` | `getAliasTokens`, `getShadowTokens`, `globalTokens` | `@fluentui-react-native/design/tokens/legacy` | `src/tokens/legacy/` | -| `@fluentui-react-native/tokens` | `backgroundColorTokens`, `borderStyles`, `borderTokens`, `colorTokens`, `fontStyles`, `foregroundColorTokens`, `getPaletteFromTheme`, `layoutStyles`, `layoutTokens`, `shadowStyles`, `shadowTokens`, `styleFunction`, `textTokens`, `tokenBuilder`, `FontDecorationTokens`, `FontStyleTokens`, `FontTokens`, `FontVariantTokens`, `IBackgroundColorTokens`, `IBorderTokens`, `IColorTokens`, `IForegroundColorTokens`, `IShadowTokens`, `LayoutTokens`, `LookupThemePart`, `OperationSet`, `StyleFactoryFunction`, `StyleFactoryFunctionRaw`, `StyleFactoryOperation`, `TokenBuilder` | `@fluentui-react-native/design/styling/tokens` | `src/styling/tokens/` | -| `@fluentui-react-native/themed-stylesheet` | `NamedStyles`, `themedStyleSheet` | `@fluentui-react-native/design/styling/stylesheet` | `src/styling/stylesheet/themedStyleSheet.ts` | +| Legacy package | Exported symbols | Owning design entry point | Definition | +| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | +| `@fluentui-react-native/theme` | `ThemeProvider`, `ThemeProviderProps`, `ThemeReference`, `OnThemeChange`, `ThemeRecipe`, `ThemeTransform` | `@fluentui-react-native/design/theming` | `src/theming/ThemeProvider.tsx`, `src/fluent/themeReference.ts` | +| `@fluentui-react-native/theme-types` | `AliasColorTokens`, `AppearanceOptions`, `BaseShadowAliasTokens`, `Color`, `FabricWebPalette`, `FontDynamicTypeRamp`, `FontFamilies`, `FontFamily`, `FontFamilyValue`, `FontSize`, `FontSizeValuePoints`, `FontSizes`, `FontWeight`, `FontWeightValue`, `FontWeights`, `OfficePalette`, `Palette`, `PaletteBackgroundColors`, `PaletteTextColors`, `PartialPalette`, `PartialShadowDefinition`, `PartialTheme`, `PartialTypography`, `ShadowToken`, `ShadowValue`, `Spacing`, `TextStyling`, `Theme`, `ThemeColorDefinition`, `ThemeContext`, `ThemeOptions`, `ThemeShadowDefinition`, `Typography`, `Variant`, `VariantValue`, `Variants`, `useTheme` | `@fluentui-react-native/design/theming` | `src/theming/context.ts`, `src/fluent/types/` | +| `@fluentui-react-native/theming-utils` | `getCurrentAppearance`, `isHighContrast`, `mapFontPipelineToTheme`, `mapPipelineToShadow`, `mapPipelineToTheme`, `setIsHighContrast` | `@fluentui-react-native/design/theming` | `src/fluent/platformUtils.*.ts`, `src/fluent/mapPipelineToShadow.ts`, `src/fluent/mapPipelineToTheme*.ts` | +| `@fluentui-react-native/theme-tokens` | `getAliasTokens`, `getShadowTokens`, `globalTokens` | `@fluentui-react-native/design/tokens/legacy` | `src/fluent/tokens/` | +| `@fluentui-react-native/tokens` | `backgroundColorTokens`, `borderStyles`, `borderTokens`, `colorTokens`, `fontStyles`, `foregroundColorTokens`, `getPaletteFromTheme`, `layoutStyles`, `layoutTokens`, `shadowStyles`, `shadowTokens`, `styleFunction`, `textTokens`, `tokenBuilder`, `FontDecorationTokens`, `FontStyleTokens`, `FontTokens`, `FontVariantTokens`, `IBackgroundColorTokens`, `IBorderTokens`, `IColorTokens`, `IForegroundColorTokens`, `IShadowTokens`, `LayoutTokens`, `LookupThemePart`, `OperationSet`, `StyleFactoryFunction`, `StyleFactoryFunctionRaw`, `StyleFactoryOperation`, `TokenBuilder` | `@fluentui-react-native/design/styling/tokens` | `src/fluent/styling/tokens/` | +| `@fluentui-react-native/themed-stylesheet` | `NamedStyles`, `themedStyleSheet` | `@fluentui-react-native/design/styling/stylesheet` | `src/fluent/styling/stylesheet/themedStyleSheet.ts` | The three optional entry points (`tokens/legacy`, `styling/tokens`, and `styling/stylesheet`) are intentionally absent from the design root barrel. diff --git a/packages/agentic/design/references/styling.md b/packages/agentic/design/references/styling.md index dd88ddd8fd..1de482e269 100644 --- a/packages/agentic/design/references/styling.md +++ b/packages/agentic/design/references/styling.md @@ -3,7 +3,8 @@ id: design.styling kind: instruction-reference owner_paths: - packages/agentic/design/src/styling - - packages/agentic/design/src/useThemeState.ts + - packages/agentic/design/src/flex/styling + - packages/agentic/design/src/flex/useThemeState.ts --- # Styling diff --git a/packages/agentic/design/references/testing.md b/packages/agentic/design/references/testing.md index 21bfcb8fc2..2b1e4c7101 100644 --- a/packages/agentic/design/references/testing.md +++ b/packages/agentic/design/references/testing.md @@ -2,7 +2,7 @@ id: design.testing kind: instruction-reference owner_paths: - - packages/agentic/design/src/testing + - packages/agentic/design/src/test --- # Testing helpers @@ -21,9 +21,11 @@ The color validation helpers build on `color-lib`, but are not designed for component render paths or other production runtime code. Production consumers that need parsing, conversion, interaction generation, compositing, or a direct contrast ratio should import `@fluentui-react-native/design/color-lib`. -Color validation policy, semantic pairings, audit helpers, and conformance -fixtures belong under `src/testing`; export them from the `testing` entry point -when they are generally useful to tests. Testing-only validation is +Color validation policy, semantic pairings, and audit helpers belong under +`src/test/color-validation`, and conformance fixtures under `src/test/fixtures`; +export them from the `testing` entry point when they are generally useful to +tests. `src/test/compatibility` holds the public-surface, legacy-runtime, and +import-boundary baselines. Testing-only validation is intentionally omitted from production bundle-size scenarios. ```ts diff --git a/packages/agentic/design/references/theming.md b/packages/agentic/design/references/theming.md index 684d79fecf..6d2375c824 100644 --- a/packages/agentic/design/references/theming.md +++ b/packages/agentic/design/references/theming.md @@ -3,7 +3,10 @@ id: design.theming kind: instruction-reference owner_paths: - packages/agentic/design/src/theming - - packages/agentic/design/src/useThemeState.ts + - packages/agentic/design/src/types + - packages/agentic/design/src/flex/flexThemeReference.ts + - packages/agentic/design/src/flex/useThemeState.ts + - packages/agentic/design/src/fluent --- # Theming diff --git a/packages/agentic/design/references/tokens.md b/packages/agentic/design/references/tokens.md index 0907bdb36b..6d1a71bdb3 100644 --- a/packages/agentic/design/references/tokens.md +++ b/packages/agentic/design/references/tokens.md @@ -3,6 +3,10 @@ id: design.tokens kind: instruction-reference owner_paths: - packages/agentic/design/src/tokens + - packages/agentic/design/src/flex/tokens.types.ts + - packages/agentic/design/src/flex/defaults + - packages/agentic/design/src/flex/adapters + - packages/agentic/design/src/fluent/tokens - packages/agentic/design/scripts --- @@ -15,11 +19,11 @@ owner_paths: component, use the Win32, macOS, or Windows implementation as the compatibility reference; use iOS only when the work explicitly targets iOS. -| Tokens | Entry point | Source | -| ------------------------------ | ------------------------------------------------- | --------------------------------------------------------------------------- | -| Flex semantic tokens | `FlexTokens` from `@fluentui-react-native/design` | `src/tokens/flex.types.ts`; defaults in `src/tokens/defaultTokens.ts` | -| Platform global tokens | `@fluentui-react-native/design/tokens/global` | Generated into `src/tokens/global.generated.ts` and `src/tokens/generated/` | -| Legacy alias and shadow tokens | `@fluentui-react-native/design/tokens/legacy` | `src/tokens/legacy/`, for legacy themes only | +| Tokens | Entry point | Source | +| ------------------------------ | ------------------------------------------------- | ---------------------------------------------------------------------------- | +| Flex semantic tokens | `FlexTokens` from `@fluentui-react-native/design` | `src/flex/tokens.types.ts`; defaults in `src/flex/defaults/defaultTokens.ts` | +| Platform global tokens | `@fluentui-react-native/design/tokens/global` | Generated into `src/tokens/global.generated.ts` and `src/tokens/generated/` | +| Legacy alias and shadow tokens | `@fluentui-react-native/design/tokens/legacy` | `src/fluent/tokens/`, for legacy themes only | `FlexTokens` groups `color` (with `hover` and `pressed` overrides), `shadow`, `fontWeight`, `fontFamily`, `fontSize`, `lineHeight`, `borderRadius`, `spacing`, and `strokeWidth`. Components read the active values from @@ -47,7 +51,7 @@ required by a target path. `nonFluentFlexTokens` supplies values for supported Flex destinations without a Theme source. A complete legacy Theme also requires values that Flex cannot represent; those values are supplied by the lazy compatibility base under -`src/theming/compat`. +`src/fluent/compat`. ### Internal consistency diff --git a/packages/agentic/design/scripts/token-mappings/check-mappings.cjs b/packages/agentic/design/scripts/token-mappings/check-mappings.cjs index 3da0ad61f2..94adccd5e8 100644 --- a/packages/agentic/design/scripts/token-mappings/check-mappings.cjs +++ b/packages/agentic/design/scripts/token-mappings/check-mappings.cjs @@ -9,10 +9,10 @@ const { parse: parseYaml } = nodeRequire(path.join(yamlPackageRoot, 'dist/index. const packageRoot = path.resolve(__dirname, '../..'); const defaultPaths = { - defaultTokens: path.join(packageRoot, 'src/tokens/defaultTokens.ts'), + defaultTokens: path.join(packageRoot, 'src/flex/defaults/defaultTokens.ts'), flexFromTheme: path.join(packageRoot, 'src/tokens/mappings/flex-from-theme.json'), flexTokenMap: path.join(packageRoot, 'src/tokens/mappings/flex-token-map.yaml'), - flexTypes: path.join(packageRoot, 'src/tokens/flex.types.ts'), + flexTypes: path.join(packageRoot, 'src/flex/tokens.types.ts'), themeFromFlex: path.join(packageRoot, 'src/tokens/mappings/theme-from-flex.json'), }; diff --git a/packages/agentic/design/src/color-lib/colorLib.test.ts b/packages/agentic/design/src/color-lib/colorLib.test.ts index 6c6f4f2757..eb42307659 100644 --- a/packages/agentic/design/src/color-lib/colorLib.test.ts +++ b/packages/agentic/design/src/color-lib/colorLib.test.ts @@ -4,9 +4,9 @@ import { x3BebopWarmInteractionConformance, x3InteractionConformance, x3WarmVariantDeviations, -} from '../testing/color-validation/x3InteractionConformance'; -import { defaultFlexTokens } from '../tokens/defaultTokens'; -import type { SemanticColorTokenValues } from '../tokens/flex.types'; +} from '../test/fixtures/x3InteractionConformance'; +import { defaultFlexTokens } from '../flex/defaults/defaultTokens'; +import type { SemanticColorTokenValues } from '../flex/tokens.types'; import { compositeColor, compositeRgba, diff --git a/packages/agentic/design/src/color-lib/interaction.ts b/packages/agentic/design/src/color-lib/interaction.ts index 6a824c9b72..44485ac9b5 100644 --- a/packages/agentic/design/src/color-lib/interaction.ts +++ b/packages/agentic/design/src/color-lib/interaction.ts @@ -16,7 +16,7 @@ import type { RgbColor, RgbaColor, } from './types'; -import type { InteractiveColorOverrides, SemanticColors, SemanticColorTokenValues } from '../tokens/flex.types'; +import type { InteractiveColorOverrides, SemanticColors, SemanticColorTokenValues } from '../flex/tokens.types'; /** * Interactive subset of the Flex semantic color tokens. diff --git a/packages/agentic/design/src/color-lib/types.ts b/packages/agentic/design/src/color-lib/types.ts index 74845db0be..7dd69d7fe8 100644 --- a/packages/agentic/design/src/color-lib/types.ts +++ b/packages/agentic/design/src/color-lib/types.ts @@ -1,7 +1,7 @@ import type { ColorValue } from 'react-native'; -import type { ThemeColorScheme } from '../theming/appearance.types'; -import type { InteractiveColorOverrides, SemanticColors, SemanticColorTokenValues } from '../tokens/flex.types'; +import type { ThemeColorScheme } from '../types/appearance.types'; +import type { InteractiveColorOverrides, SemanticColors, SemanticColorTokenValues } from '../flex/tokens.types'; export type ColorDiagnosticReason = 'non-literal-color' | 'unsupported-color-format'; diff --git a/packages/agentic/design/src/tokens/flexTokensFromTheme.test.ts b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts similarity index 94% rename from packages/agentic/design/src/tokens/flexTokensFromTheme.test.ts rename to packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts index 7c4c7e01a0..a4c167e0d3 100644 --- a/packages/agentic/design/src/tokens/flexTokensFromTheme.test.ts +++ b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts @@ -1,5 +1,5 @@ -import type { Theme } from '../theming'; -import { mockTheme } from '../testing/mockTheme'; +import type { Theme } from '../../theming'; +import { mockTheme } from '../../test/fixtures/mockTheme'; import { flexTokensFromTheme } from './flexTokensFromTheme'; function createTheme(): Theme { diff --git a/packages/agentic/design/src/tokens/flexTokensFromTheme.ts b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts similarity index 62% rename from packages/agentic/design/src/tokens/flexTokensFromTheme.ts rename to packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts index 0b30f13369..bdad600fa8 100644 --- a/packages/agentic/design/src/tokens/flexTokensFromTheme.ts +++ b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts @@ -1,10 +1,10 @@ import { immutableMerge } from '@fluentui-react-native/framework-base'; -import type { Theme } from '../theming'; -import { mapObjectFromObject } from '../utilities/objects'; -import { defaultFlexTokens, nonFluentFlexTokens } from './defaultTokens'; -import type { FlexTokens } from './flex.types'; -import flexFromTheme from './mappings/flex-from-theme.json' with { type: 'json' }; +import type { Theme } from '../../fluent/types/Theme.types'; +import { mapObjectFromObject } from '../../utilities/objects'; +import { defaultFlexTokens, nonFluentFlexTokens } from '../defaults/defaultTokens'; +import type { FlexTokens } from '../tokens.types'; +import flexFromTheme from '../../tokens/mappings/flex-from-theme.json' with { type: 'json' }; const defaultMappedFlexTokens = mapObjectFromObject( defaultFlexTokens, diff --git a/packages/agentic/design/src/tokens/defaultTokens.ts b/packages/agentic/design/src/flex/defaults/defaultTokens.ts similarity index 99% rename from packages/agentic/design/src/tokens/defaultTokens.ts rename to packages/agentic/design/src/flex/defaults/defaultTokens.ts index 10e0575d1a..14ffb8ec22 100644 --- a/packages/agentic/design/src/tokens/defaultTokens.ts +++ b/packages/agentic/design/src/flex/defaults/defaultTokens.ts @@ -51,8 +51,8 @@ import { strokeWidth20, strokeWidth30, strokeWidth40, -} from './global.generated'; -import type { FlexTokens, InteractiveColorOverrides, SemanticColorTokenValues } from './flex.types'; +} from '../../tokens/global.generated'; +import type { FlexTokens, InteractiveColorOverrides, SemanticColorTokenValues } from '../tokens.types'; type NonFluentFlexTokens = { [Group in Exclude]?: Partial; diff --git a/packages/agentic/design/src/theming/flexThemeReference.test.ts b/packages/agentic/design/src/flex/flexThemeReference.test.ts similarity index 97% rename from packages/agentic/design/src/theming/flexThemeReference.test.ts rename to packages/agentic/design/src/flex/flexThemeReference.test.ts index 288d62d891..639255a68b 100644 --- a/packages/agentic/design/src/theming/flexThemeReference.test.ts +++ b/packages/agentic/design/src/flex/flexThemeReference.test.ts @@ -1,4 +1,4 @@ -import { defaultResolvedThemeAppearance } from './appearance'; +import { defaultResolvedThemeAppearance } from '../theming/appearance'; import { FlexThemeReference } from './flexThemeReference'; const darkAppearance = { diff --git a/packages/agentic/design/src/theming/flexThemeReference.ts b/packages/agentic/design/src/flex/flexThemeReference.ts similarity index 94% rename from packages/agentic/design/src/theming/flexThemeReference.ts rename to packages/agentic/design/src/flex/flexThemeReference.ts index e0f468e9e6..11271966ab 100644 --- a/packages/agentic/design/src/theming/flexThemeReference.ts +++ b/packages/agentic/design/src/flex/flexThemeReference.ts @@ -1,6 +1,6 @@ import { immutableMerge } from '@fluentui-react-native/framework-base'; -import { defaultFlexTokens } from '../tokens/defaultTokens'; +import { defaultFlexTokens } from './defaults/defaultTokens'; import type { FlexTokens, InteractiveColorOverrides, @@ -13,11 +13,11 @@ import type { SemanticShadows, SemanticSpacing, SemanticStrokeWidths, -} from '../tokens/flex.types'; -import { themeAppearanceKey } from './appearance'; -import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceSource } from './appearance.types'; -import type { FlexThemeSource, OnThemeChange } from './themeSource'; -import type { PartialTheme, Theme } from './types/Theme.types'; +} from './tokens.types'; +import { themeAppearanceKey } from '../theming/appearance'; +import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceSource } from '../types/appearance.types'; +import type { FlexThemeSource, OnThemeChange } from '../theming/themeSource'; +import type { PartialTheme, Theme } from '../fluent/types/Theme.types'; export type PartialFlexTokens = { color?: Partial & { diff --git a/packages/agentic/design/src/styling/colorStyles.test.ts b/packages/agentic/design/src/flex/styling/colorStyles.test.ts similarity index 95% rename from packages/agentic/design/src/styling/colorStyles.test.ts rename to packages/agentic/design/src/flex/styling/colorStyles.test.ts index 21f2b5f710..23ec0b76fd 100644 --- a/packages/agentic/design/src/styling/colorStyles.test.ts +++ b/packages/agentic/design/src/flex/styling/colorStyles.test.ts @@ -1,7 +1,7 @@ -import type { FlexTokens } from '../tokens/flex.types'; -import { defaultFlexTokens } from '../tokens/defaultTokens'; -import { defaultResolvedThemeAppearance } from '../theming/appearance'; -import type { ThemeState } from '../useThemeState'; +import type { FlexTokens } from '../tokens.types'; +import { defaultFlexTokens } from '../defaults/defaultTokens'; +import { defaultResolvedThemeAppearance } from '../../theming/appearance'; +import type { ThemeState } from '../../types/themeState.types'; import { colorStyleDef, getThemedColorStyleFactory } from './colorStyles'; import type { ColorStyleDefinition, ViewColorStyle } from './colorStyles'; diff --git a/packages/agentic/design/src/styling/colorStyles.ts b/packages/agentic/design/src/flex/styling/colorStyles.ts similarity index 95% rename from packages/agentic/design/src/styling/colorStyles.ts rename to packages/agentic/design/src/flex/styling/colorStyles.ts index 568398454e..1a8ceb3a67 100644 --- a/packages/agentic/design/src/styling/colorStyles.ts +++ b/packages/agentic/design/src/flex/styling/colorStyles.ts @@ -1,10 +1,10 @@ import type { ColorValue, TextStyle, ViewStyle } from 'react-native'; -import type { FlexTokens, SemanticColors } from '../tokens/flex.types'; -import type { ThemeState } from '../useThemeState'; +import type { FlexTokens, SemanticColors } from '../tokens.types'; +import type { ThemeState } from '../../types/themeState.types'; -import { createStateLevelMap, getThemedStateStyleFactory } from './branchedStyle'; -import type { StateLevels, StateNames, StateSource, StyleDefinition, StyleDefFromTokens } from './branchedStyle'; +import { createStateLevelMap, getThemedStateStyleFactory } from '../../styling/branchedStyle'; +import type { StateLevels, StateNames, StateSource, StyleDefinition, StyleDefFromTokens } from '../../styling/branchedStyle'; export type ViewColorStyle = Pick; export type TextColorStyle = Pick; diff --git a/packages/agentic/design/src/tokens/flex.test.ts b/packages/agentic/design/src/flex/tokens.test.ts similarity index 96% rename from packages/agentic/design/src/tokens/flex.test.ts rename to packages/agentic/design/src/flex/tokens.test.ts index dffebf4efd..4185b721b1 100644 --- a/packages/agentic/design/src/tokens/flex.test.ts +++ b/packages/agentic/design/src/flex/tokens.test.ts @@ -1,9 +1,9 @@ -import { defaultFlexTokens, nonFluentFlexTokens } from './defaultTokens'; -import type { FlexTokens, SemanticColorTokenValues } from './flex.types'; +import { defaultFlexTokens, nonFluentFlexTokens } from './defaults/defaultTokens'; +import type { FlexTokens, SemanticColorTokenValues } from './tokens.types'; const colorTokens: SemanticColorTokenValues = defaultFlexTokens.color; const flexTokens: FlexTokens = defaultFlexTokens; -const flexFromTheme = jest.requireActual>('./mappings/flex-from-theme.json'); +const flexFromTheme = jest.requireActual>('../tokens/mappings/flex-from-theme.json'); function getTokenPaths(tokens: object, color: { hover: object; pressed: object }): string[] { const colorPaths = Object.keys(color) diff --git a/packages/agentic/design/src/tokens/flex.types.ts b/packages/agentic/design/src/flex/tokens.types.ts similarity index 99% rename from packages/agentic/design/src/tokens/flex.types.ts rename to packages/agentic/design/src/flex/tokens.types.ts index 8ba74f2615..7329face10 100644 --- a/packages/agentic/design/src/tokens/flex.types.ts +++ b/packages/agentic/design/src/flex/tokens.types.ts @@ -1,5 +1,5 @@ import type { ColorValue, TextStyle, ViewStyle, DimensionValue } from 'react-native'; -import type { ShadowToken } from '../theming/types/Shadow.types'; +import type { ShadowToken } from '../fluent/types/Shadow.types'; type FontWeight = TextStyle['fontWeight']; type FontSize = TextStyle['fontSize']; diff --git a/packages/agentic/design/src/useThemeState.test.ts b/packages/agentic/design/src/flex/useThemeState.test.ts similarity index 95% rename from packages/agentic/design/src/useThemeState.test.ts rename to packages/agentic/design/src/flex/useThemeState.test.ts index a5345e49d9..303c6b27b4 100644 --- a/packages/agentic/design/src/useThemeState.test.ts +++ b/packages/agentic/design/src/flex/useThemeState.test.ts @@ -4,15 +4,15 @@ import { StyleSheet } from 'react-native'; import { act, create } from 'react-test-renderer'; import type { ReactTestRenderer } from 'react-test-renderer'; -import { defaultResolvedThemeAppearance } from './theming/appearance'; -import type { ThemeAppearanceSource, ThemeAppearanceSourceSnapshot } from './theming/appearance.types'; -import { ThemeContext } from './theming/context'; -import { FlexThemeReference } from './theming/flexThemeReference'; -import { ThemeProvider } from './theming/ThemeProvider'; -import type { Theme } from './theming/types/Theme.types'; -import { mockTheme } from './testing/mockTheme'; +import { defaultResolvedThemeAppearance } from '../theming/appearance'; +import type { ThemeAppearanceSource, ThemeAppearanceSourceSnapshot } from '../types/appearance.types'; +import { ThemeContext } from '../theming/context'; +import { FlexThemeReference } from './flexThemeReference'; +import { ThemeProvider } from '../theming/ThemeProvider'; +import type { Theme } from '../fluent/types/Theme.types'; +import { mockTheme } from '../test/fixtures/mockTheme'; import { themedStyleSheetFactory, useThemeAppearance, useThemeState } from './useThemeState'; -import type { ThemeState } from './useThemeState'; +import type { ThemeState } from '../types/themeState.types'; function ThemeStateProbe({ states }: { states: ThemeState[] }) { states.push(useThemeState()); diff --git a/packages/agentic/design/src/useThemeState.ts b/packages/agentic/design/src/flex/useThemeState.ts similarity index 67% rename from packages/agentic/design/src/useThemeState.ts rename to packages/agentic/design/src/flex/useThemeState.ts index 5fb9a52215..e11994663b 100644 --- a/packages/agentic/design/src/useThemeState.ts +++ b/packages/agentic/design/src/flex/useThemeState.ts @@ -1,37 +1,13 @@ import type { ImageStyle, TextStyle, ViewStyle } from 'react-native'; -import { defaultThemeAppearanceState } from './theming/appearance'; -import type { ResolvedThemeAppearance, ThemeAppearanceState } from './theming/appearance.types'; -import { useThemeBoundary } from './theming/context'; -import { defaultThemeState, getThemeState } from './theming/themeRuntime'; -import type { FlexTokens } from './tokens/flex.types'; +import { defaultThemeAppearanceState } from '../theming/appearance'; +import { useThemeBoundary } from '../theming/context'; +import { defaultThemeState, getThemeState } from '../theming/themeRuntime'; +import type { ThemeAppearanceState } from '../types/appearance.types'; +import type { ThemeState } from '../types/themeState.types'; export type ThemeStyleSheet = Record; -export type ThemeState = { - /** - * The set of flex tokens - */ - readonly tokens: FlexTokens; - /** - * Structured appearance values used to resolve this theme state. - */ - readonly appearance: Readonly; - /** - * @deprecated Use appearance.contrast. - */ - readonly highContrast: boolean; - /** - * Style sheets shared by every component instance using this theme state. - * - * Components should use a module-scoped symbol as their key and lazily store - * one immutable StyleSheet.create result whose values depend only on this - * ThemeState. Component props, interaction state, and user styles must be - * applied separately. - */ - readonly themeStyles: Record; -}; - /** * Theme state should be consistent on object identity until a theme change or system appearance change occurs. Each new * theme state must own a new themeStyles registry so cached style sheets cannot leak across themes. diff --git a/packages/agentic/design/src/theming/__tests__/__snapshots__/theming-utils.test.ts.snap b/packages/agentic/design/src/fluent/__tests__/__snapshots__/theming-utils.test.ts.snap similarity index 100% rename from packages/agentic/design/src/theming/__tests__/__snapshots__/theming-utils.test.ts.snap rename to packages/agentic/design/src/fluent/__tests__/__snapshots__/theming-utils.test.ts.snap diff --git a/packages/agentic/design/src/theming/__tests__/themeReference.test.ts b/packages/agentic/design/src/fluent/__tests__/themeReference.test.ts similarity index 97% rename from packages/agentic/design/src/theming/__tests__/themeReference.test.ts rename to packages/agentic/design/src/fluent/__tests__/themeReference.test.ts index 2e8c25b743..d4a7e4d6fe 100644 --- a/packages/agentic/design/src/theming/__tests__/themeReference.test.ts +++ b/packages/agentic/design/src/fluent/__tests__/themeReference.test.ts @@ -1,7 +1,7 @@ -import { mockTheme } from '../../testing'; -import type { Theme, Spacing, PartialTheme } from '../index'; +import { mockTheme } from '../../test'; +import type { Theme, Spacing, PartialTheme } from '../../theming/index'; -import { defaultResolvedThemeAppearance } from '../appearance'; +import { defaultResolvedThemeAppearance } from '../../theming/appearance'; import { ThemeReference } from '../themeReference'; const themeBase = mockTheme; diff --git a/packages/agentic/design/src/theming/__tests__/theming-utils.test.ts b/packages/agentic/design/src/fluent/__tests__/theming-utils.test.ts similarity index 98% rename from packages/agentic/design/src/theming/__tests__/theming-utils.test.ts rename to packages/agentic/design/src/fluent/__tests__/theming-utils.test.ts index ef4cb3989a..d39064c02d 100644 --- a/packages/agentic/design/src/theming/__tests__/theming-utils.test.ts +++ b/packages/agentic/design/src/fluent/__tests__/theming-utils.test.ts @@ -7,7 +7,7 @@ import darkShadowTokens from '@fluentui-react-native/design-tokens-windows/dark/ import lightAliasTokens from '@fluentui-react-native/design-tokens-windows/light/tokens-aliases.json'; import lightShadowTokens from '@fluentui-react-native/design-tokens-windows/light/tokens-shadow.json'; -import { getCurrentAppearance } from '../'; +import { getCurrentAppearance } from '../../theming'; import { mapPipelineToShadow } from '../mapPipelineToShadow'; import { mapPipelineToTheme, mapFontPipelineToTheme } from '../mapPipelineToTheme'; diff --git a/packages/agentic/design/src/theming/compat/__tests__/defaultLegacyTheme.test.ios.ts b/packages/agentic/design/src/fluent/compat/__tests__/defaultLegacyTheme.test.ios.ts similarity index 100% rename from packages/agentic/design/src/theming/compat/__tests__/defaultLegacyTheme.test.ios.ts rename to packages/agentic/design/src/fluent/compat/__tests__/defaultLegacyTheme.test.ios.ts diff --git a/packages/agentic/design/src/theming/compat/createLegacyAliasTokens.ts b/packages/agentic/design/src/fluent/compat/createLegacyAliasTokens.ts similarity index 92% rename from packages/agentic/design/src/theming/compat/createLegacyAliasTokens.ts rename to packages/agentic/design/src/fluent/compat/createLegacyAliasTokens.ts index 810b77bbda..5ea18a461f 100644 --- a/packages/agentic/design/src/theming/compat/createLegacyAliasTokens.ts +++ b/packages/agentic/design/src/fluent/compat/createLegacyAliasTokens.ts @@ -1,6 +1,6 @@ import { memoize } from '@fluentui-react-native/framework-base'; -import { getAliasTokens, getShadowTokens } from '../../tokens/legacy'; +import { getAliasTokens, getShadowTokens } from '../tokens'; import { mapPipelineToShadow } from '../mapPipelineToShadow'; import { mapPipelineToTheme } from '../mapPipelineToTheme'; import type { AliasColorTokens } from '../types/Color.types'; diff --git a/packages/agentic/design/src/theming/compat/defaultLegacyColors.ts b/packages/agentic/design/src/fluent/compat/defaultLegacyColors.ts similarity index 100% rename from packages/agentic/design/src/theming/compat/defaultLegacyColors.ts rename to packages/agentic/design/src/fluent/compat/defaultLegacyColors.ts diff --git a/packages/agentic/design/src/theming/compat/defaultLegacyTheme.test.ts b/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.test.ts similarity index 100% rename from packages/agentic/design/src/theming/compat/defaultLegacyTheme.test.ts rename to packages/agentic/design/src/fluent/compat/defaultLegacyTheme.test.ts diff --git a/packages/agentic/design/src/theming/compat/defaultLegacyTheme.ts b/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts similarity index 97% rename from packages/agentic/design/src/theming/compat/defaultLegacyTheme.ts rename to packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts index cc560f18fb..334d1f7cbc 100644 --- a/packages/agentic/design/src/theming/compat/defaultLegacyTheme.ts +++ b/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts @@ -1,9 +1,9 @@ import { Platform } from 'react-native'; import { fontWeightRegular, fontWeightSemibold } from '../../tokens/global.generated'; -import globalTokens from '../../tokens/legacy/tokens-global'; -import { appearanceOptionFromResolved, themeAppearanceKey } from '../appearance'; -import type { ResolvedThemeAppearance } from '../appearance.types'; +import globalTokens from '../tokens/tokens-global'; +import { appearanceOptionFromResolved, themeAppearanceKey } from '../../theming/appearance'; +import type { ResolvedThemeAppearance } from '../../types/appearance.types'; import type { Theme, Spacing } from '../types/Theme.types'; import type { FontSize, FontSizes, FontWeightValue, Typography, Variants } from '../types/Typography.types'; diff --git a/packages/agentic/design/src/theming/compat/index.ts b/packages/agentic/design/src/fluent/compat/index.ts similarity index 100% rename from packages/agentic/design/src/theming/compat/index.ts rename to packages/agentic/design/src/fluent/compat/index.ts diff --git a/packages/agentic/design/src/theming/compat/stockWebPalette.macos.ts b/packages/agentic/design/src/fluent/compat/stockWebPalette.macos.ts similarity index 97% rename from packages/agentic/design/src/theming/compat/stockWebPalette.macos.ts rename to packages/agentic/design/src/fluent/compat/stockWebPalette.macos.ts index 59226a9e33..f5f729421e 100644 --- a/packages/agentic/design/src/theming/compat/stockWebPalette.macos.ts +++ b/packages/agentic/design/src/fluent/compat/stockWebPalette.macos.ts @@ -1,5 +1,5 @@ import { colorBlack, colorBurgundyPrimary, colorRedPrimary, colorWhite } from '../../tokens/global.generated'; -import globalTokens from '../../tokens/legacy/tokens-global'; +import globalTokens from '../tokens/tokens-global'; import type { ThemeColorDefinition } from '../types/Color.types'; import { createLegacyColorAliasTokens } from './createLegacyAliasTokens'; diff --git a/packages/agentic/design/src/theming/compat/stockWebPalette.ts b/packages/agentic/design/src/fluent/compat/stockWebPalette.ts similarity index 98% rename from packages/agentic/design/src/theming/compat/stockWebPalette.ts rename to packages/agentic/design/src/fluent/compat/stockWebPalette.ts index d588e872fc..c4168fb51b 100644 --- a/packages/agentic/design/src/theming/compat/stockWebPalette.ts +++ b/packages/agentic/design/src/fluent/compat/stockWebPalette.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/ban-ts-comment */ import { colorBlack, colorBurgundyPrimary, colorRedPrimary, colorWhite } from '../../tokens/global.generated'; -import globalTokens from '../../tokens/legacy/tokens-global'; +import globalTokens from '../tokens/tokens-global'; import type { ThemeColorDefinition } from '../types/Color.types'; import { createLegacyColorAliasTokens } from './createLegacyAliasTokens'; diff --git a/packages/agentic/design/src/theming/compat/stockWebPalette.win32.ts b/packages/agentic/design/src/fluent/compat/stockWebPalette.win32.ts similarity index 97% rename from packages/agentic/design/src/theming/compat/stockWebPalette.win32.ts rename to packages/agentic/design/src/fluent/compat/stockWebPalette.win32.ts index 59226a9e33..f5f729421e 100644 --- a/packages/agentic/design/src/theming/compat/stockWebPalette.win32.ts +++ b/packages/agentic/design/src/fluent/compat/stockWebPalette.win32.ts @@ -1,5 +1,5 @@ import { colorBlack, colorBurgundyPrimary, colorRedPrimary, colorWhite } from '../../tokens/global.generated'; -import globalTokens from '../../tokens/legacy/tokens-global'; +import globalTokens from '../tokens/tokens-global'; import type { ThemeColorDefinition } from '../types/Color.types'; import { createLegacyColorAliasTokens } from './createLegacyAliasTokens'; diff --git a/packages/agentic/design/src/theming/compat/themeFromFlexTokens.test.ts b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts similarity index 96% rename from packages/agentic/design/src/theming/compat/themeFromFlexTokens.test.ts rename to packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts index 865b4183c3..5f83dee99e 100644 --- a/packages/agentic/design/src/theming/compat/themeFromFlexTokens.test.ts +++ b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts @@ -1,5 +1,5 @@ -import { defaultFlexTokens } from '../../tokens/defaultTokens'; -import type { FlexTokens } from '../../tokens/flex.types'; +import { defaultFlexTokens } from '../../flex/defaults/defaultTokens'; +import type { FlexTokens } from '../../flex/tokens.types'; import type { PartialTheme } from '../types/Theme.types'; import { themeFromFlexTokens } from './themeFromFlexTokens'; diff --git a/packages/agentic/design/src/theming/compat/themeFromFlexTokens.ts b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts similarity index 64% rename from packages/agentic/design/src/theming/compat/themeFromFlexTokens.ts rename to packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts index 85c89bc662..6922fb6ea7 100644 --- a/packages/agentic/design/src/theming/compat/themeFromFlexTokens.ts +++ b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts @@ -1,7 +1,8 @@ -import type { FlexTokens } from '../../tokens/flex.types'; +import type { FlexTokens } from '../../flex/tokens.types'; import reverseProjection from '../../tokens/mappings/theme-from-flex.json' with { type: 'json' }; -import { appearanceOptionFromResolved } from '../appearance'; -import type { ResolvedThemeAppearance } from '../appearance.types'; +import { appearanceOptionFromResolved } from '../../theming/appearance'; +import type { ResolvedThemeAppearance } from '../../types/appearance.types'; +import { ensureParentRecord, getValueAtSegments, splitObjectPath } from '../../utilities/objects'; import { mergeTheme } from '../mergeTheme'; import type { PartialTheme, Theme } from '../types/Theme.types'; @@ -19,46 +20,18 @@ export interface ThemeFromFlexTokensOptions { fallback?: Theme | PartialTheme; } -const unsafePathSegments = new Set(['__proto__', 'constructor', 'prototype']); - function getPathSegments(path: string): string[] { - const segments = path.split('.'); - if (segments.some((segment) => segment.length === 0 || unsafePathSegments.has(segment))) { - throw new Error(`Invalid generated theme projection path "${path}".`); - } - return segments; -} - -function isRecord(value: unknown): value is Record { - return typeof value === 'object' && value !== null && !Array.isArray(value); + return splitObjectPath(path, () => new Error(`Invalid generated theme projection path "${path}".`)); } function getValueAtPath(source: object, path: string): unknown { - let value: unknown = source; - for (const segment of getPathSegments(path)) { - if (!isRecord(value) || !Object.prototype.hasOwnProperty.call(value, segment)) { - return undefined; - } - value = value[segment]; - } - return value; + return getValueAtSegments(source, getPathSegments(path)); } +// Later projection entries overwrite earlier leaves; conflicting parents are generator errors. function setValueAtPath(destination: Record, path: string, value: unknown): void { const segments = getPathSegments(path); - let target = destination; - for (const segment of segments.slice(0, -1)) { - const existing = target[segment]; - if (existing === undefined) { - const nested: Record = {}; - target[segment] = nested; - target = nested; - } else if (isRecord(existing)) { - target = existing; - } else { - throw new Error(`Cannot create generated theme projection path "${path}".`); - } - } + const target = ensureParentRecord(destination, segments, () => new Error(`Cannot create generated theme projection path "${path}".`)); target[segments[segments.length - 1]] = value; } diff --git a/packages/agentic/design/src/theming/legacySource.ts b/packages/agentic/design/src/fluent/legacySource.ts similarity index 65% rename from packages/agentic/design/src/theming/legacySource.ts rename to packages/agentic/design/src/fluent/legacySource.ts index 8389dd1087..baf196e007 100644 --- a/packages/agentic/design/src/theming/legacySource.ts +++ b/packages/agentic/design/src/fluent/legacySource.ts @@ -1,3 +1,3 @@ export { ThemeReference } from './themeReference'; export type { OnThemeChange, ThemeRecipe, ThemeReferenceOptions, ThemeTransform } from './themeReference'; -export type { LegacyThemeSource, ThemeSourceBase } from './themeSource'; +export type { LegacyThemeSource, ThemeSourceBase } from '../theming/themeSource'; diff --git a/packages/agentic/design/src/theming/mapPipelineToShadow.ts b/packages/agentic/design/src/fluent/mapPipelineToShadow.ts similarity index 100% rename from packages/agentic/design/src/theming/mapPipelineToShadow.ts rename to packages/agentic/design/src/fluent/mapPipelineToShadow.ts diff --git a/packages/agentic/design/src/theming/mapPipelineToTheme.android.ts b/packages/agentic/design/src/fluent/mapPipelineToTheme.android.ts similarity index 100% rename from packages/agentic/design/src/theming/mapPipelineToTheme.android.ts rename to packages/agentic/design/src/fluent/mapPipelineToTheme.android.ts diff --git a/packages/agentic/design/src/theming/mapPipelineToTheme.ios.ts b/packages/agentic/design/src/fluent/mapPipelineToTheme.ios.ts similarity index 99% rename from packages/agentic/design/src/theming/mapPipelineToTheme.ios.ts rename to packages/agentic/design/src/fluent/mapPipelineToTheme.ios.ts index 960624f783..48639002e4 100644 --- a/packages/agentic/design/src/theming/mapPipelineToTheme.ios.ts +++ b/packages/agentic/design/src/fluent/mapPipelineToTheme.ios.ts @@ -1,4 +1,4 @@ -import type { FontStyleTokens } from '../styling/tokens'; +import type { FontStyleTokens } from './styling/tokens'; import type { AliasColorTokens } from './types/Color.types'; import type { FontDynamicTypeRamp, Variants, VariantValue } from './types/Typography.types'; diff --git a/packages/agentic/design/src/theming/mapPipelineToTheme.ts b/packages/agentic/design/src/fluent/mapPipelineToTheme.ts similarity index 100% rename from packages/agentic/design/src/theming/mapPipelineToTheme.ts rename to packages/agentic/design/src/fluent/mapPipelineToTheme.ts diff --git a/packages/agentic/design/src/theming/mergeTheme.ts b/packages/agentic/design/src/fluent/mergeTheme.ts similarity index 80% rename from packages/agentic/design/src/theming/mergeTheme.ts rename to packages/agentic/design/src/fluent/mergeTheme.ts index dc7d5e4bc9..b282cd49f6 100644 --- a/packages/agentic/design/src/theming/mergeTheme.ts +++ b/packages/agentic/design/src/fluent/mergeTheme.ts @@ -1,6 +1,6 @@ import { immutableMerge } from '@fluentui-react-native/framework-base'; -import type { Theme, PartialTheme } from './index'; +import type { PartialTheme, Theme } from './types/Theme.types'; export function mergeTheme(base: TTheme, partial: TPartial): TTheme { return immutableMerge(base, partial as unknown as TTheme); diff --git a/packages/agentic/design/src/theming/platformUtils.defaults.ts b/packages/agentic/design/src/fluent/platformUtils.defaults.ts similarity index 100% rename from packages/agentic/design/src/theming/platformUtils.defaults.ts rename to packages/agentic/design/src/fluent/platformUtils.defaults.ts diff --git a/packages/agentic/design/src/theming/platformUtils.macos.ts b/packages/agentic/design/src/fluent/platformUtils.macos.ts similarity index 79% rename from packages/agentic/design/src/theming/platformUtils.macos.ts rename to packages/agentic/design/src/fluent/platformUtils.macos.ts index b1ad5dbbe2..69acda42e9 100644 --- a/packages/agentic/design/src/theming/platformUtils.macos.ts +++ b/packages/agentic/design/src/fluent/platformUtils.macos.ts @@ -1,5 +1,5 @@ import type { Theme } from './types/Theme.types'; -import { platformAppearance, setPlatformHighContrast } from './platformAppearance'; +import { platformAppearance, setPlatformHighContrast } from '../theming/platformAppearance'; export { getCurrentAppearance } from './platformUtils.defaults'; diff --git a/packages/agentic/design/src/theming/platformUtils.ts b/packages/agentic/design/src/fluent/platformUtils.ts similarity index 100% rename from packages/agentic/design/src/theming/platformUtils.ts rename to packages/agentic/design/src/fluent/platformUtils.ts diff --git a/packages/agentic/design/src/theming/platformUtils.win32.ts b/packages/agentic/design/src/fluent/platformUtils.win32.ts similarity index 100% rename from packages/agentic/design/src/theming/platformUtils.win32.ts rename to packages/agentic/design/src/fluent/platformUtils.win32.ts diff --git a/packages/agentic/design/src/theming/platformUtils.windows.ts b/packages/agentic/design/src/fluent/platformUtils.windows.ts similarity index 100% rename from packages/agentic/design/src/theming/platformUtils.windows.ts rename to packages/agentic/design/src/fluent/platformUtils.windows.ts diff --git a/packages/agentic/design/src/styling/stylesheet/index.ts b/packages/agentic/design/src/fluent/styling/stylesheet/index.ts similarity index 100% rename from packages/agentic/design/src/styling/stylesheet/index.ts rename to packages/agentic/design/src/fluent/styling/stylesheet/index.ts diff --git a/packages/agentic/design/src/styling/stylesheet/themedStyleSheet.test.ts b/packages/agentic/design/src/fluent/styling/stylesheet/themedStyleSheet.test.ts similarity index 100% rename from packages/agentic/design/src/styling/stylesheet/themedStyleSheet.test.ts rename to packages/agentic/design/src/fluent/styling/stylesheet/themedStyleSheet.test.ts diff --git a/packages/agentic/design/src/styling/stylesheet/themedStyleSheet.ts b/packages/agentic/design/src/fluent/styling/stylesheet/themedStyleSheet.ts similarity index 100% rename from packages/agentic/design/src/styling/stylesheet/themedStyleSheet.ts rename to packages/agentic/design/src/fluent/styling/stylesheet/themedStyleSheet.ts diff --git a/packages/agentic/design/src/styling/tokens/border-tokens.ts b/packages/agentic/design/src/fluent/styling/tokens/border-tokens.ts similarity index 93% rename from packages/agentic/design/src/styling/tokens/border-tokens.ts rename to packages/agentic/design/src/fluent/styling/tokens/border-tokens.ts index cd25b4084b..60837e3569 100644 --- a/packages/agentic/design/src/styling/tokens/border-tokens.ts +++ b/packages/agentic/design/src/fluent/styling/tokens/border-tokens.ts @@ -1,6 +1,6 @@ import type { ViewStyle, ColorValue, AnimatableNumericValue } from 'react-native'; -import type { Theme } from '../../theming'; +import type { Theme } from '../../types/Theme.types'; import { getPaletteFromTheme } from './color-tokens'; import type { OperationSet } from './token.types'; diff --git a/packages/agentic/design/src/styling/tokens/color-tokens.ts b/packages/agentic/design/src/fluent/styling/tokens/color-tokens.ts similarity index 86% rename from packages/agentic/design/src/styling/tokens/color-tokens.ts rename to packages/agentic/design/src/fluent/styling/tokens/color-tokens.ts index 2905961adc..011b3f2200 100644 --- a/packages/agentic/design/src/styling/tokens/color-tokens.ts +++ b/packages/agentic/design/src/fluent/styling/tokens/color-tokens.ts @@ -1,6 +1,7 @@ import type { ColorValue } from 'react-native'; -import type { Theme, ThemeColorDefinition } from '../../theming'; +import type { ThemeColorDefinition } from '../../types/Color.types'; +import type { Theme } from '../../types/Theme.types'; import type { OperationSet } from './token.types'; diff --git a/packages/agentic/design/src/styling/tokens/index.ts b/packages/agentic/design/src/fluent/styling/tokens/index.ts similarity index 100% rename from packages/agentic/design/src/styling/tokens/index.ts rename to packages/agentic/design/src/fluent/styling/tokens/index.ts diff --git a/packages/agentic/design/src/styling/tokens/layout-tokens.ts b/packages/agentic/design/src/fluent/styling/tokens/layout-tokens.ts similarity index 95% rename from packages/agentic/design/src/styling/tokens/layout-tokens.ts rename to packages/agentic/design/src/fluent/styling/tokens/layout-tokens.ts index 675818d475..9af4c388bc 100644 --- a/packages/agentic/design/src/styling/tokens/layout-tokens.ts +++ b/packages/agentic/design/src/fluent/styling/tokens/layout-tokens.ts @@ -1,6 +1,6 @@ import type { ViewStyle } from 'react-native'; -import type { Theme } from '../../theming'; +import type { Theme } from '../../types/Theme.types'; import type { OperationSet } from './token.types'; import { tokenBuilder } from './tokenBuilder'; diff --git a/packages/agentic/design/src/styling/tokens/shadow-tokens.ts b/packages/agentic/design/src/fluent/styling/tokens/shadow-tokens.ts similarity index 93% rename from packages/agentic/design/src/styling/tokens/shadow-tokens.ts rename to packages/agentic/design/src/fluent/styling/tokens/shadow-tokens.ts index 3aa84aaefb..3a0d78fd29 100644 --- a/packages/agentic/design/src/styling/tokens/shadow-tokens.ts +++ b/packages/agentic/design/src/fluent/styling/tokens/shadow-tokens.ts @@ -1,6 +1,6 @@ import type { AnimatableNumericValue, ColorValue, ViewStyle } from 'react-native'; -import type { Theme } from '../../theming'; +import type { Theme } from '../../types/Theme.types'; import type { OperationSet } from './token.types'; import { tokenBuilder } from './tokenBuilder'; diff --git a/packages/agentic/design/src/styling/tokens/text-tokens.ts b/packages/agentic/design/src/fluent/styling/tokens/text-tokens.ts similarity index 96% rename from packages/agentic/design/src/styling/tokens/text-tokens.ts rename to packages/agentic/design/src/fluent/styling/tokens/text-tokens.ts index 2715856f39..7f59dba822 100644 --- a/packages/agentic/design/src/styling/tokens/text-tokens.ts +++ b/packages/agentic/design/src/fluent/styling/tokens/text-tokens.ts @@ -1,7 +1,8 @@ import type { TextProps, TextStyle } from 'react-native'; import type { ITextProps, ITextStyle } from '@fluentui-react-native/adapters'; -import type { Theme, Typography } from '../../theming'; +import type { Theme } from '../../types/Theme.types'; +import type { Typography } from '../../types/Typography.types'; import { styleFunction } from './token.function'; import type { TokenBuilder } from './tokenBuilder'; diff --git a/packages/agentic/design/src/styling/tokens/token.function.ts b/packages/agentic/design/src/fluent/styling/tokens/token.function.ts similarity index 100% rename from packages/agentic/design/src/styling/tokens/token.function.ts rename to packages/agentic/design/src/fluent/styling/tokens/token.function.ts diff --git a/packages/agentic/design/src/styling/tokens/token.types.ts b/packages/agentic/design/src/fluent/styling/tokens/token.types.ts similarity index 100% rename from packages/agentic/design/src/styling/tokens/token.types.ts rename to packages/agentic/design/src/fluent/styling/tokens/token.types.ts diff --git a/packages/agentic/design/src/styling/tokens/tokenBuilder.ts b/packages/agentic/design/src/fluent/styling/tokens/tokenBuilder.ts similarity index 92% rename from packages/agentic/design/src/styling/tokens/tokenBuilder.ts rename to packages/agentic/design/src/fluent/styling/tokens/tokenBuilder.ts index 6f0f304255..5b907b22dc 100644 --- a/packages/agentic/design/src/styling/tokens/tokenBuilder.ts +++ b/packages/agentic/design/src/fluent/styling/tokens/tokenBuilder.ts @@ -1,6 +1,6 @@ import type { ViewStyle, TextStyle, ImageStyle } from 'react-native'; -import type { Theme } from '../../theming'; +import type { Theme } from '../../types/Theme.types'; export type TokenBuilder = { from: (tokens: TTokens, theme: Theme) => TStyle; diff --git a/packages/agentic/design/src/theming/themeReference.ts b/packages/agentic/design/src/fluent/themeReference.ts similarity index 96% rename from packages/agentic/design/src/theming/themeReference.ts rename to packages/agentic/design/src/fluent/themeReference.ts index 380b601b75..c54b26212c 100644 --- a/packages/agentic/design/src/theming/themeReference.ts +++ b/packages/agentic/design/src/fluent/themeReference.ts @@ -1,12 +1,12 @@ -import type { Theme, PartialTheme } from './index'; +import type { PartialTheme, Theme } from './types/Theme.types'; -import { appearanceOptionsFromLegacy, resolveThemeAppearance, themeAppearanceKey } from './appearance'; -import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceSource } from './appearance.types'; +import { appearanceOptionsFromLegacy, resolveThemeAppearance, themeAppearanceKey } from '../theming/appearance'; +import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceSource } from '../types/appearance.types'; import { mergeTheme } from './mergeTheme'; -import { platformAppearance } from './platformAppearance'; -import type { LegacyThemeSource, OnThemeChange } from './themeSource'; +import { platformAppearance } from '../theming/platformAppearance'; +import type { LegacyThemeSource, OnThemeChange } from '../theming/themeSource'; -export type { OnThemeChange } from './themeSource'; +export type { OnThemeChange } from '../theming/themeSource'; /** * A function that takes in a parent theme, then returns a partial set of changes to be merged with the parent theme to update diff --git a/packages/agentic/design/src/tokens/legacy/getTokens.android.ts b/packages/agentic/design/src/fluent/tokens/getTokens.android.ts similarity index 95% rename from packages/agentic/design/src/tokens/legacy/getTokens.android.ts rename to packages/agentic/design/src/fluent/tokens/getTokens.android.ts index cc8275e33b..90872f2dbe 100644 --- a/packages/agentic/design/src/tokens/legacy/getTokens.android.ts +++ b/packages/agentic/design/src/fluent/tokens/getTokens.android.ts @@ -2,7 +2,7 @@ import darkAliasTokens from '@fluentui-react-native/design-tokens-android/dark/t import darkShadowTokens from '@fluentui-react-native/design-tokens-android/dark/tokens-shadow.json'; import lightAliasTokens from '@fluentui-react-native/design-tokens-android/light/tokens-aliases.json'; import lightShadowTokens from '@fluentui-react-native/design-tokens-android/light/tokens-shadow.json'; -import type { AppearanceOptions } from '../../theming'; +import type { AppearanceOptions } from '../types/Theme.types'; export function getAliasTokens(mode: AppearanceOptions) { if (mode === 'light') { diff --git a/packages/agentic/design/src/tokens/legacy/getTokens.ios.ts b/packages/agentic/design/src/fluent/tokens/getTokens.ios.ts similarity index 96% rename from packages/agentic/design/src/tokens/legacy/getTokens.ios.ts rename to packages/agentic/design/src/fluent/tokens/getTokens.ios.ts index 1103fd1a05..f46d59589b 100644 --- a/packages/agentic/design/src/tokens/legacy/getTokens.ios.ts +++ b/packages/agentic/design/src/fluent/tokens/getTokens.ios.ts @@ -3,7 +3,7 @@ import iOSDarkShadowTokens from '@fluentui-react-native/design-tokens-ios/dark/t import iOSDarkElevatedAliasTokens from '@fluentui-react-native/design-tokens-ios/elevateddark/tokens-aliases.json'; import iOSLightAliasTokens from '@fluentui-react-native/design-tokens-ios/light/tokens-aliases.json'; import iOSLightShadowTokens from '@fluentui-react-native/design-tokens-ios/light/tokens-shadow.json'; -import type { AppearanceOptions } from '../../theming'; +import type { AppearanceOptions } from '../types/Theme.types'; import { assertNever } from 'assert-never'; export function getAliasTokens(mode: AppearanceOptions) { diff --git a/packages/agentic/design/src/tokens/legacy/getTokens.ts b/packages/agentic/design/src/fluent/tokens/getTokens.ts similarity index 94% rename from packages/agentic/design/src/tokens/legacy/getTokens.ts rename to packages/agentic/design/src/fluent/tokens/getTokens.ts index 86cf9063ed..07d6c201d6 100644 --- a/packages/agentic/design/src/tokens/legacy/getTokens.ts +++ b/packages/agentic/design/src/fluent/tokens/getTokens.ts @@ -3,7 +3,7 @@ import darkAliasTokens from '@fluentui-react-native/design-tokens-windows/dark/t import darkShadowTokens from '@fluentui-react-native/design-tokens-windows/dark/tokens-shadow.json'; import lightAliasTokens from '@fluentui-react-native/design-tokens-windows/light/tokens-aliases.json'; import lightShadowTokens from '@fluentui-react-native/design-tokens-windows/light/tokens-shadow.json'; -import type { AppearanceOptions } from '../../theming'; +import type { AppearanceOptions } from '../types/Theme.types'; import { assertNever } from 'assert-never'; import { hcAliasTokens } from './highContrast/tokens-alias'; diff --git a/packages/agentic/design/src/tokens/legacy/highContrast/__tests__/processAliasTokens.test.ts b/packages/agentic/design/src/fluent/tokens/highContrast/__tests__/processAliasTokens.test.ts similarity index 100% rename from packages/agentic/design/src/tokens/legacy/highContrast/__tests__/processAliasTokens.test.ts rename to packages/agentic/design/src/fluent/tokens/highContrast/__tests__/processAliasTokens.test.ts diff --git a/packages/agentic/design/src/tokens/legacy/highContrast/processAliasTokens.ts b/packages/agentic/design/src/fluent/tokens/highContrast/processAliasTokens.ts similarity index 100% rename from packages/agentic/design/src/tokens/legacy/highContrast/processAliasTokens.ts rename to packages/agentic/design/src/fluent/tokens/highContrast/processAliasTokens.ts diff --git a/packages/agentic/design/src/tokens/legacy/highContrast/tokens-alias.ts b/packages/agentic/design/src/fluent/tokens/highContrast/tokens-alias.ts similarity index 100% rename from packages/agentic/design/src/tokens/legacy/highContrast/tokens-alias.ts rename to packages/agentic/design/src/fluent/tokens/highContrast/tokens-alias.ts diff --git a/packages/agentic/design/src/tokens/legacy/highContrast/tokens-alias.win32.ts b/packages/agentic/design/src/fluent/tokens/highContrast/tokens-alias.win32.ts similarity index 100% rename from packages/agentic/design/src/tokens/legacy/highContrast/tokens-alias.win32.ts rename to packages/agentic/design/src/fluent/tokens/highContrast/tokens-alias.win32.ts diff --git a/packages/agentic/design/src/tokens/legacy/index.ts b/packages/agentic/design/src/fluent/tokens/index.ts similarity index 100% rename from packages/agentic/design/src/tokens/legacy/index.ts rename to packages/agentic/design/src/fluent/tokens/index.ts diff --git a/packages/agentic/design/src/tokens/legacy/tokens-global.android.ts b/packages/agentic/design/src/fluent/tokens/tokens-global.android.ts similarity index 100% rename from packages/agentic/design/src/tokens/legacy/tokens-global.android.ts rename to packages/agentic/design/src/fluent/tokens/tokens-global.android.ts diff --git a/packages/agentic/design/src/tokens/legacy/tokens-global.ios.ts b/packages/agentic/design/src/fluent/tokens/tokens-global.ios.ts similarity index 100% rename from packages/agentic/design/src/tokens/legacy/tokens-global.ios.ts rename to packages/agentic/design/src/fluent/tokens/tokens-global.ios.ts diff --git a/packages/agentic/design/src/tokens/legacy/tokens-global.ts b/packages/agentic/design/src/fluent/tokens/tokens-global.ts similarity index 100% rename from packages/agentic/design/src/tokens/legacy/tokens-global.ts rename to packages/agentic/design/src/fluent/tokens/tokens-global.ts diff --git a/packages/agentic/design/src/tokens/legacy/tokens-global.win32.ts b/packages/agentic/design/src/fluent/tokens/tokens-global.win32.ts similarity index 100% rename from packages/agentic/design/src/tokens/legacy/tokens-global.win32.ts rename to packages/agentic/design/src/fluent/tokens/tokens-global.win32.ts diff --git a/packages/agentic/design/src/theming/types/Color.types.ts b/packages/agentic/design/src/fluent/types/Color.types.ts similarity index 100% rename from packages/agentic/design/src/theming/types/Color.types.ts rename to packages/agentic/design/src/fluent/types/Color.types.ts diff --git a/packages/agentic/design/src/theming/types/Shadow.types.ts b/packages/agentic/design/src/fluent/types/Shadow.types.ts similarity index 100% rename from packages/agentic/design/src/theming/types/Shadow.types.ts rename to packages/agentic/design/src/fluent/types/Shadow.types.ts diff --git a/packages/agentic/design/src/theming/types/Theme.types.ts b/packages/agentic/design/src/fluent/types/Theme.types.ts similarity index 100% rename from packages/agentic/design/src/theming/types/Theme.types.ts rename to packages/agentic/design/src/fluent/types/Theme.types.ts diff --git a/packages/agentic/design/src/theming/types/Typography.types.ts b/packages/agentic/design/src/fluent/types/Typography.types.ts similarity index 100% rename from packages/agentic/design/src/theming/types/Typography.types.ts rename to packages/agentic/design/src/fluent/types/Typography.types.ts diff --git a/packages/agentic/design/src/theming/types/palette.types.ts b/packages/agentic/design/src/fluent/types/palette.types.ts similarity index 100% rename from packages/agentic/design/src/theming/types/palette.types.ts rename to packages/agentic/design/src/fluent/types/palette.types.ts diff --git a/packages/agentic/design/src/theming/useTheme.test.ts b/packages/agentic/design/src/fluent/useTheme.test.ts similarity index 89% rename from packages/agentic/design/src/theming/useTheme.test.ts rename to packages/agentic/design/src/fluent/useTheme.test.ts index 7d32b7e0f8..2618e3ac7f 100644 --- a/packages/agentic/design/src/theming/useTheme.test.ts +++ b/packages/agentic/design/src/fluent/useTheme.test.ts @@ -3,13 +3,13 @@ import * as React from 'react'; import { act, create } from 'react-test-renderer'; import type { ReactTestRenderer } from 'react-test-renderer'; -import { mockTheme } from '../testing/mockTheme'; -import { useThemeState } from '../useThemeState'; -import type { ThemeState } from '../useThemeState'; -import type { ThemeAppearanceSource } from './appearance.types'; -import { ThemeContext } from './context'; -import { FlexThemeReference } from './flexThemeReference'; -import { ThemeProvider } from './ThemeProvider'; +import { mockTheme } from '../test/fixtures/mockTheme'; +import { useThemeState } from '../flex/useThemeState'; +import type { ThemeState } from '../types/themeState.types'; +import type { ThemeAppearanceSource } from '../types/appearance.types'; +import { ThemeContext } from '../theming/context'; +import { FlexThemeReference } from '../flex/flexThemeReference'; +import { ThemeProvider } from '../theming/ThemeProvider'; import type { Theme } from './types/Theme.types'; import { useTheme } from './useTheme'; diff --git a/packages/agentic/design/src/theming/useTheme.ts b/packages/agentic/design/src/fluent/useTheme.ts similarity index 81% rename from packages/agentic/design/src/theming/useTheme.ts rename to packages/agentic/design/src/fluent/useTheme.ts index 4d5393dd48..a232b81f44 100644 --- a/packages/agentic/design/src/theming/useTheme.ts +++ b/packages/agentic/design/src/fluent/useTheme.ts @@ -1,10 +1,10 @@ import type { PartialTheme, Theme } from './types/Theme.types'; import { themeFromFlexTokens } from './compat'; -import { themeAppearanceKey } from './appearance'; -import type { ResolvedThemeAppearance } from './appearance.types'; -import { useThemeBoundary } from './context'; -import { getFlexTokens } from './themeRuntime'; -import type { FlexThemeSource } from './themeSource'; +import { themeAppearanceKey } from '../theming/appearance'; +import type { ResolvedThemeAppearance } from '../types/appearance.types'; +import { useThemeBoundary } from '../theming/context'; +import { getFlexTokens } from '../theming/themeRuntime'; +import type { FlexThemeSource } from '../theming/themeSource'; type LegacyCache = { revision: number; diff --git a/packages/agentic/design/src/index.ts b/packages/agentic/design/src/index.ts index a3fa3c501c..505b7ad447 100644 --- a/packages/agentic/design/src/index.ts +++ b/packages/agentic/design/src/index.ts @@ -1,5 +1,5 @@ -export type { FontSize, FontWeight } from './concepts/textAttributes'; -export { fontSize, fontWeight } from './concepts/textAttributes'; +export type { FontSize, FontWeight } from './tokens/textAttributes'; +export { fontSize, fontWeight } from './tokens/textAttributes'; export type { FlexTokens, InteractiveColorOverrides, @@ -15,8 +15,8 @@ export type { SemanticStrokeWidths, SemanticTokens, UnsupportedFlexTokens, -} from './tokens/flex.types'; -export { flexTokensFromTheme } from './tokens/flexTokensFromTheme'; +} from './flex/tokens.types'; +export { flexTokensFromTheme } from './flex/adapters/flexTokensFromTheme'; export { createThemeAppearanceSource, FlexThemeReference, @@ -54,5 +54,6 @@ export type { ThemeSource, ThemeSourceBase, } from './theming/modern'; -export type { ThemeState, ThemeStyleSheet } from './useThemeState'; -export { themedStyleSheetFactory, useThemeAppearance, useThemeState } from './useThemeState'; +export type { ThemeStyleSheet } from './flex/useThemeState'; +export type { ThemeState } from './types/themeState.types'; +export { themedStyleSheetFactory, useThemeAppearance, useThemeState } from './flex/useThemeState'; diff --git a/packages/agentic/design/src/styling/branchedStyle.test.ts b/packages/agentic/design/src/styling/branchedStyle.test.ts index ab03abd866..9c83aabb48 100644 --- a/packages/agentic/design/src/styling/branchedStyle.test.ts +++ b/packages/agentic/design/src/styling/branchedStyle.test.ts @@ -1,8 +1,8 @@ import type { ViewStyle } from 'react-native'; import { defaultResolvedThemeAppearance } from '../theming/appearance'; -import { defaultFlexTokens } from '../tokens/defaultTokens'; -import type { ThemeState } from '../useThemeState'; +import { defaultFlexTokens } from '../flex/defaults/defaultTokens'; +import type { ThemeState } from '../types/themeState.types'; import { getActiveState, diff --git a/packages/agentic/design/src/styling/branchedStyle.ts b/packages/agentic/design/src/styling/branchedStyle.ts index 8c7abc28a3..8e8051ffac 100644 --- a/packages/agentic/design/src/styling/branchedStyle.ts +++ b/packages/agentic/design/src/styling/branchedStyle.ts @@ -1,7 +1,7 @@ import type { ImageStyle, TextStyle, ViewStyle } from 'react-native'; -import type { FlexTokens } from '../tokens/flex.types'; -import type { ThemeState } from '../useThemeState'; +import type { FlexTokens } from '../flex/tokens.types'; +import type { ThemeState } from '../types/themeState.types'; type AnyStyle = ViewStyle | ImageStyle | TextStyle; diff --git a/packages/agentic/design/src/styling/index.ts b/packages/agentic/design/src/styling/index.ts index 60f0538950..6936f0651d 100644 --- a/packages/agentic/design/src/styling/index.ts +++ b/packages/agentic/design/src/styling/index.ts @@ -8,7 +8,7 @@ export { styleDefinitionToBranchedStyles, } from './branchedStyle'; export { getGapStyleValue } from './gapStyleValue'; -export type { ColorKey, ColorStyleDefinition, TextColorStyle, ViewColorStyle } from './colorStyles'; -export { colorStyleDef, getThemedColorStyleFactory } from './colorStyles'; +export type { ColorKey, ColorStyleDefinition, TextColorStyle, ViewColorStyle } from '../flex/styling/colorStyles'; +export { colorStyleDef, getThemedColorStyleFactory } from '../flex/styling/colorStyles'; export { interactiveStatePriority } from './interactiveStatePriority'; export { getNumericStyleValue } from './numericStyleValue'; diff --git a/packages/agentic/design/src/testing/README.md b/packages/agentic/design/src/test/README.md similarity index 100% rename from packages/agentic/design/src/testing/README.md rename to packages/agentic/design/src/test/README.md diff --git a/packages/agentic/design/src/testing/color-validation/constants.ts b/packages/agentic/design/src/test/color-validation/constants.ts similarity index 100% rename from packages/agentic/design/src/testing/color-validation/constants.ts rename to packages/agentic/design/src/test/color-validation/constants.ts diff --git a/packages/agentic/design/src/testing/color-validation/pairings.ts b/packages/agentic/design/src/test/color-validation/pairings.ts similarity index 100% rename from packages/agentic/design/src/testing/color-validation/pairings.ts rename to packages/agentic/design/src/test/color-validation/pairings.ts diff --git a/packages/agentic/design/src/testing/color-validation/types.ts b/packages/agentic/design/src/test/color-validation/types.ts similarity index 96% rename from packages/agentic/design/src/testing/color-validation/types.ts rename to packages/agentic/design/src/test/color-validation/types.ts index 794f082ede..45d250dcfc 100644 --- a/packages/agentic/design/src/testing/color-validation/types.ts +++ b/packages/agentic/design/src/test/color-validation/types.ts @@ -1,7 +1,7 @@ import type { ColorValue } from 'react-native'; import type { ColorDiagnostic, ColorMode } from '../../color-lib'; -import type { SemanticColorTokenValues } from '../../tokens/flex.types'; +import type { SemanticColorTokenValues } from '../../flex/tokens.types'; export type ContrastColorToken = keyof SemanticColorTokenValues; diff --git a/packages/agentic/design/src/testing/color-validation/validation.test.ts b/packages/agentic/design/src/test/color-validation/validation.test.ts similarity index 97% rename from packages/agentic/design/src/testing/color-validation/validation.test.ts rename to packages/agentic/design/src/test/color-validation/validation.test.ts index fe9bca69f7..1d275b4184 100644 --- a/packages/agentic/design/src/testing/color-validation/validation.test.ts +++ b/packages/agentic/design/src/test/color-validation/validation.test.ts @@ -2,10 +2,10 @@ import { PlatformColor } from 'react-native'; import { getInteractionColorOverrides, INTERACTIVE_COLOR_TOKENS } from '../../color-lib/interaction'; import type { ColorMode, InteractionColorState, InteractionColorVariant } from '../../color-lib/types'; -import { defaultFlexTokens } from '../../tokens/defaultTokens'; -import type { SemanticColorTokenValues } from '../../tokens/flex.types'; +import { defaultFlexTokens } from '../../flex/defaults/defaultTokens'; +import type { SemanticColorTokenValues } from '../../flex/tokens.types'; import { getContrastFailures, getUnresolvableContrastPairs, MODE_SURFACE, PAIRINGS, validateContrastPairs, WCAG } from '../index'; -import { x3BebopWarmInteractionConformance, x3InteractionConformance } from './x3InteractionConformance'; +import { x3BebopWarmInteractionConformance, x3InteractionConformance } from '../fixtures/x3InteractionConformance'; function conformanceColors( mode: ColorMode, diff --git a/packages/agentic/design/src/testing/color-validation/validation.ts b/packages/agentic/design/src/test/color-validation/validation.ts similarity index 98% rename from packages/agentic/design/src/testing/color-validation/validation.ts rename to packages/agentic/design/src/test/color-validation/validation.ts index b33cd1df6a..134dc98c27 100644 --- a/packages/agentic/design/src/testing/color-validation/validation.ts +++ b/packages/agentic/design/src/test/color-validation/validation.ts @@ -1,6 +1,6 @@ import { parseColorValue, resolveContrastColors } from '../../color-lib'; import type { ColorDiagnostic, ColorMode } from '../../color-lib'; -import type { SemanticColorTokenValues } from '../../tokens/flex.types'; +import type { SemanticColorTokenValues } from '../../flex/tokens.types'; import { MODE_SURFACE } from './constants'; import { PAIRINGS } from './pairings'; import type { diff --git a/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts b/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts index 117e678419..35c29b1b46 100644 --- a/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts +++ b/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts @@ -1,12 +1,12 @@ import { PlatformColor } from 'react-native'; -import { getDefaultLegacyTheme } from '../../theming/compat/defaultLegacyTheme'; -import { themeFromFlexTokens } from '../../theming/compat/themeFromFlexTokens'; -import type { ResolvedThemeAppearance } from '../../theming/appearance.types'; -import type { Theme } from '../../theming/types/Theme.types'; -import { mockTheme } from '../../testing/mockTheme'; -import { defaultFlexTokens } from '../../tokens/defaultTokens'; -import { flexTokensFromTheme } from '../../tokens/flexTokensFromTheme'; +import { getDefaultLegacyTheme } from '../../fluent/compat/defaultLegacyTheme'; +import { themeFromFlexTokens } from '../../fluent/compat/themeFromFlexTokens'; +import type { ResolvedThemeAppearance } from '../../types/appearance.types'; +import type { Theme } from '../../fluent/types/Theme.types'; +import { mockTheme } from '../fixtures/mockTheme'; +import { defaultFlexTokens } from '../../flex/defaults/defaultTokens'; +import { flexTokensFromTheme } from '../../flex/adapters/flexTokensFromTheme'; import { flexTokenFingerprints, themeFingerprints } from './fingerprint'; const appearances: [string, ResolvedThemeAppearance][] = [ diff --git a/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts b/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts index 072420107d..53d064cf55 100644 --- a/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts +++ b/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts @@ -8,9 +8,9 @@ import type { ThemeAppearanceOptions as RootThemeAppearanceOptions, ThemeState, } from '../../index'; -import { getDefaultLegacyTheme as getDefaultLegacyThemeOnly } from '../../theming/compat/defaultLegacyTheme'; -import { getDefaultLegacyTheme, themeFromFlexTokens } from '../../theming/compat/index'; -import type { ThemeFromFlexTokensOptions } from '../../theming/compat/index'; +import { getDefaultLegacyTheme as getDefaultLegacyThemeOnly } from '../../fluent/compat/defaultLegacyTheme'; +import { getDefaultLegacyTheme, themeFromFlexTokens } from '../../fluent/compat/index'; +import type { ThemeFromFlexTokensOptions } from '../../fluent/compat/index'; import { getCurrentAppearance, isHighContrast, @@ -67,10 +67,10 @@ import type { Variants, VariantValue, } from '../../theming/index'; -import { ThemeReference as LegacySourceThemeReference } from '../../theming/legacySource'; -import type { OnThemeChange as LegacySourceOnThemeChange, ThemeRecipe as LegacySourceThemeRecipe } from '../../theming/legacySource'; -import { themedStyleSheet } from '../../styling/stylesheet/index'; -import type { NamedStyles } from '../../styling/stylesheet/index'; +import { ThemeReference as LegacySourceThemeReference } from '../../fluent/legacySource'; +import type { OnThemeChange as LegacySourceOnThemeChange, ThemeRecipe as LegacySourceThemeRecipe } from '../../fluent/legacySource'; +import { themedStyleSheet } from '../../fluent/styling/stylesheet/index'; +import type { NamedStyles } from '../../fluent/styling/stylesheet/index'; import { backgroundColorTokens, borderStyles, @@ -86,7 +86,7 @@ import { styleFunction, textTokens, tokenBuilder, -} from '../../styling/tokens/index'; +} from '../../fluent/styling/tokens/index'; import type { FontDecorationTokens, FontStyleTokens, @@ -104,8 +104,8 @@ import type { StyleFactoryFunctionRaw, StyleFactoryOperation, TokenBuilder, -} from '../../styling/tokens/index'; -import { getAliasTokens, getShadowTokens, globalTokens, hcAliasTokens } from '../../tokens/legacy/index'; +} from '../../fluent/styling/tokens/index'; +import { getAliasTokens, getShadowTokens, globalTokens, hcAliasTokens } from '../../fluent/tokens/index'; /** * Every type name the compatibility packages re-export must remain importable diff --git a/packages/agentic/design/src/test/compatibility/fingerprint.ts b/packages/agentic/design/src/test/compatibility/fingerprint.ts index 350d754358..2ddda6025c 100644 --- a/packages/agentic/design/src/test/compatibility/fingerprint.ts +++ b/packages/agentic/design/src/test/compatibility/fingerprint.ts @@ -1,7 +1,7 @@ import { createHash } from 'node:crypto'; -import type { Theme } from '../../theming/types/Theme.types'; -import type { FlexTokens } from '../../tokens/flex.types'; +import type { Theme } from '../../fluent/types/Theme.types'; +import type { FlexTokens } from '../../flex/tokens.types'; type EffectiveColor = { rest: unknown; hover: unknown; pressed: unknown }; diff --git a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts new file mode 100644 index 0000000000..0e75eb6143 --- /dev/null +++ b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts @@ -0,0 +1,205 @@ +import { parse } from '@babel/parser'; +import fs from 'node:fs'; +import path from 'node:path'; + +type Statement = ReturnType['program']['body'][number]; + +const srcRoot = path.resolve(__dirname, '../..'); +const platformSuffixes = ['android', 'ios', 'macos', 'native', 'win32', 'windows']; + +type ImportEdge = { specifier: string; typeOnly: boolean }; + +function toSrcPath(file: string): string { + return path.relative(srcRoot, file).split(path.sep).join('/'); +} + +const statementCache = new Map(); + +function readStatements(file: string): Statement[] { + let statements = statementCache.get(file); + if (!statements) { + const plugins: ('typescript' | 'jsx')[] = file.endsWith('.tsx') ? ['typescript', 'jsx'] : ['typescript']; + statements = parse(fs.readFileSync(file, 'utf8'), { sourceType: 'module', plugins }).program.body; + statementCache.set(file, statements); + } + return statements; +} + +function readImports(file: string): ImportEdge[] { + const edges: ImportEdge[] = []; + for (const statement of readStatements(file)) { + if (statement.type === 'ImportDeclaration') { + const typeOnly = + statement.importKind === 'type' || + (statement.specifiers.length > 0 && + statement.specifiers.every((specifier) => specifier.type === 'ImportSpecifier' && specifier.importKind === 'type')); + edges.push({ specifier: statement.source.value, typeOnly }); + } else if (statement.type === 'ExportNamedDeclaration' && statement.source) { + const typeOnly = + statement.exportKind === 'type' || + (statement.specifiers.length > 0 && + statement.specifiers.every((specifier) => specifier.type === 'ExportSpecifier' && specifier.exportKind === 'type')); + edges.push({ specifier: statement.source.value, typeOnly }); + } else if (statement.type === 'ExportAllDeclaration') { + edges.push({ specifier: statement.source.value, typeOnly: statement.exportKind === 'type' }); + } + } + return edges; +} + +function isFile(candidate: string): boolean { + return fs.existsSync(candidate) && fs.statSync(candidate).isFile(); +} + +/** Resolve a relative specifier to every platform file Metro or esbuild could select. */ +function resolveRelative(fromFile: string, specifier: string): string[] { + const base = path.resolve(path.dirname(fromFile), specifier); + const exact = [base, `${base}.ts`, `${base}.tsx`, `${base}.json`].find(isFile); + const variants = platformSuffixes.flatMap((platform) => [`${base}.${platform}.ts`, `${base}.${platform}.tsx`]).filter(isFile); + const resolved = exact ? [exact, ...variants] : variants; + if (resolved.length === 0) { + const index = [path.join(base, 'index.ts'), path.join(base, 'index.tsx')].find(isFile); + if (index) { + resolved.push(index); + } + } + if (resolved.length === 0) { + throw new Error(`Cannot resolve "${specifier}" from ${toSrcPath(fromFile)}.`); + } + return resolved; +} + +function runtimeGraph(entry: string): Set { + const reached = new Set(); + const pending = [path.join(srcRoot, entry)]; + while (pending.length > 0) { + const file = pending.pop() as string; + const srcPath = toSrcPath(file); + if (reached.has(srcPath)) { + continue; + } + reached.add(srcPath); + if (file.endsWith('.json')) { + continue; + } + for (const edge of readImports(file)) { + if (!edge.typeOnly && edge.specifier.startsWith('.')) { + pending.push(...resolveRelative(file, edge.specifier)); + } + } + } + return reached; +} + +function listSourceFiles(dir: string): string[] { + return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => { + const file = path.join(dir, entry.name); + if (entry.isDirectory()) { + return listSourceFiles(file); + } + return /\.tsx?$/.test(entry.name) ? [file] : []; + }); +} + +function isTestSource(srcPath: string): boolean { + return srcPath.startsWith('test/') || srcPath.includes('/__tests__/') || /\.test(\.[a-z0-9]+)?\.tsx?$/.test(srcPath); +} + +function reachedUnder(graph: Set, prefix: string): string[] { + return [...graph].filter((file) => file.startsWith(prefix)).sort(); +} + +function isTypeOnlyStatement(statement: Statement): boolean { + switch (statement.type) { + case 'TSTypeAliasDeclaration': + case 'TSInterfaceDeclaration': + return true; + case 'ImportDeclaration': + case 'ExportNamedDeclaration': + case 'ExportAllDeclaration': + if (statement.type === 'ExportNamedDeclaration' && statement.declaration) { + return statement.declaration.type === 'TSTypeAliasDeclaration' || statement.declaration.type === 'TSInterfaceDeclaration'; + } + return statement.type === 'ImportDeclaration' ? statement.importKind === 'type' : statement.exportKind === 'type'; + default: + return false; + } +} + +const productionFiles = listSourceFiles(srcRoot).filter((file) => !isTestSource(toSrcPath(file))); + +describe('production code never depends on test collateral', () => { + it('resolves test-only imports when they exist', () => { + const testImporter = path.join(srcRoot, 'fluent/__tests__/themeReference.test.ts'); + const resolvedTestImports = readImports(testImporter) + .filter((edge) => edge.specifier.startsWith('.')) + .flatMap((edge) => resolveRelative(testImporter, edge.specifier).map(toSrcPath)); + expect(resolvedTestImports).toContain('test/index.ts'); + }); + + it('has no production import of src/test or the testing entry point', () => { + expect(productionFiles.length).toBeGreaterThan(50); + const violations = productionFiles.flatMap((file) => + readImports(file) + .filter((edge) => + edge.specifier.startsWith('.') + ? resolveRelative(file, edge.specifier).some((resolved) => toSrcPath(resolved).startsWith('test/')) + : edge.specifier === '@fluentui-react-native/design/testing', + ) + .map((edge) => `${toSrcPath(file)} -> ${edge.specifier}`), + ); + expect(violations).toEqual([]); + }); +}); + +describe('runtime graph ownership', () => { + const legacyThemingGraph = runtimeGraph('theming/index.ts'); + + it('detects the legacy projection and payloads from the legacy theming entry', () => { + expect(legacyThemingGraph).toContain('fluent/useTheme.ts'); + expect(legacyThemingGraph).toContain('fluent/compat/themeFromFlexTokens.ts'); + expect(reachedUnder(legacyThemingGraph, 'fluent/tokens/').length).toBeGreaterThan(0); + }); + + it('keeps the modern root free of legacy Fluent runtime and test collateral', () => { + const rootGraph = runtimeGraph('index.ts'); + expect(rootGraph).toContain('flex/useThemeState.ts'); + expect(rootGraph).toContain('flex/flexThemeReference.ts'); + expect(rootGraph).toContain('flex/adapters/flexTokensFromTheme.ts'); + expect(rootGraph).toContain('theming/ThemeProvider.tsx'); + expect(reachedUnder(rootGraph, 'fluent/')).toEqual([]); + expect(reachedUnder(rootGraph, 'test/')).toEqual([]); + }); + + it('keeps the shared styling entry free of legacy Fluent runtime', () => { + const stylingGraph = runtimeGraph('styling/index.ts'); + expect(stylingGraph).toContain('flex/styling/colorStyles.ts'); + expect(reachedUnder(stylingGraph, 'fluent/')).toEqual([]); + expect(reachedUnder(stylingGraph, 'test/')).toEqual([]); + }); + + it('keeps the legacy-source entry free of the projection and legacy payloads', () => { + const legacySourceGraph = runtimeGraph('fluent/legacySource.ts'); + expect(legacySourceGraph).toContain('fluent/themeReference.ts'); + expect(reachedUnder(legacySourceGraph, 'fluent/compat/')).toEqual([]); + expect(reachedUnder(legacySourceGraph, 'fluent/tokens/')).toEqual([]); + }); +}); + +describe('shared types', () => { + it('contain only type declarations and type-only imports', () => { + const typeFiles = listSourceFiles(path.join(srcRoot, 'types')); + expect(typeFiles.map(toSrcPath).sort()).toEqual(expect.arrayContaining(['types/appearance.types.ts', 'types/themeState.types.ts'])); + const runtimeStatements = typeFiles.flatMap((file) => + readStatements(file) + .filter((statement) => !isTypeOnlyStatement(statement)) + .map((statement) => `${toSrcPath(file)}:${statement.loc?.start.line} ${statement.type}`), + ); + expect(runtimeStatements).toEqual([]); + }); + + it('reject runtime statements', () => { + const runtimeModule = path.join(srcRoot, 'theming/appearance.ts'); + expect(readStatements(runtimeModule).some((statement) => !isTypeOnlyStatement(statement))).toBe(true); + }); +}); diff --git a/packages/agentic/design/src/testing/mockTheme.ts b/packages/agentic/design/src/test/fixtures/mockTheme.ts similarity index 99% rename from packages/agentic/design/src/testing/mockTheme.ts rename to packages/agentic/design/src/test/fixtures/mockTheme.ts index 5fc3e4b206..5dc943d8ca 100644 --- a/packages/agentic/design/src/testing/mockTheme.ts +++ b/packages/agentic/design/src/test/fixtures/mockTheme.ts @@ -1,4 +1,4 @@ -import type { Theme } from '../theming'; +import type { Theme } from '../../fluent/types/Theme.types'; const black = 'black'; const neutralDark = '#201f1e'; diff --git a/packages/agentic/design/src/testing/color-validation/x3InteractionConformance.ts b/packages/agentic/design/src/test/fixtures/x3InteractionConformance.ts similarity index 100% rename from packages/agentic/design/src/testing/color-validation/x3InteractionConformance.ts rename to packages/agentic/design/src/test/fixtures/x3InteractionConformance.ts diff --git a/packages/agentic/design/src/testing/index.ts b/packages/agentic/design/src/test/index.ts similarity index 82% rename from packages/agentic/design/src/testing/index.ts rename to packages/agentic/design/src/test/index.ts index 7ee6cf4c01..6e66d4c472 100644 --- a/packages/agentic/design/src/testing/index.ts +++ b/packages/agentic/design/src/test/index.ts @@ -1,5 +1,5 @@ export { defaultResolvedThemeAppearance } from '../theming/appearance'; -export { defaultFlexTokens } from '../tokens/defaultTokens'; +export { defaultFlexTokens } from '../flex/defaults/defaultTokens'; export type { ContrastColorDiagnostic, ContrastColorToken, @@ -12,4 +12,4 @@ export type { export { MODE_SURFACE, WCAG } from './color-validation/constants'; export { PAIRINGS } from './color-validation/pairings'; export { getContrastFailures, getUnresolvableContrastPairs, validateContrastPairs } from './color-validation/validation'; -export { mockTheme } from './mockTheme'; +export { mockTheme } from './fixtures/mockTheme'; diff --git a/packages/agentic/design/src/theming/ThemeProvider.tsx b/packages/agentic/design/src/theming/ThemeProvider.tsx index 4cb1670a95..a56c70ad0b 100644 --- a/packages/agentic/design/src/theming/ThemeProvider.tsx +++ b/packages/agentic/design/src/theming/ThemeProvider.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import { resolveThemeAppearance } from './appearance'; -import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceSource } from './appearance.types'; +import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceSource } from '../types/appearance.types'; import { ThemeContext, ThemeSourceContext } from './context'; import { platformAppearance } from './platformAppearance'; import type { ThemeSource } from './themeSource'; diff --git a/packages/agentic/design/src/theming/ThemedRoot.test.tsx b/packages/agentic/design/src/theming/ThemedRoot.test.tsx index 506f5312bd..be5854d2c5 100644 --- a/packages/agentic/design/src/theming/ThemedRoot.test.tsx +++ b/packages/agentic/design/src/theming/ThemedRoot.test.tsx @@ -4,13 +4,13 @@ import { Platform, View } from 'react-native'; import { act, create } from 'react-test-renderer'; import type { ReactTestRenderer } from 'react-test-renderer'; -import { mockTheme } from '../testing/mockTheme'; -import { defaultFlexTokens } from '../tokens/defaultTokens'; -import { useThemeState } from '../useThemeState'; -import type { ThemeState } from '../useThemeState'; -import type { ResolvedThemeAppearance, ThemeAppearanceSource, ThemeAppearanceSourceSnapshot } from './appearance.types'; +import { mockTheme } from '../test/fixtures/mockTheme'; +import { defaultFlexTokens } from '../flex/defaults/defaultTokens'; +import { useThemeState } from '../flex/useThemeState'; +import type { ThemeState } from '../types/themeState.types'; +import type { ResolvedThemeAppearance, ThemeAppearanceSource, ThemeAppearanceSourceSnapshot } from '../types/appearance.types'; import { ThemeContext } from './context'; -import { FlexThemeReference } from './flexThemeReference'; +import { FlexThemeReference } from '../flex/flexThemeReference'; import { useRootSettings } from './rootContext'; import type { RootSettings } from './rootContext'; import { ThemedRoot } from './ThemedRoot'; diff --git a/packages/agentic/design/src/theming/ThemedRoot.tsx b/packages/agentic/design/src/theming/ThemedRoot.tsx index a5c8dee453..085cfa8146 100644 --- a/packages/agentic/design/src/theming/ThemedRoot.tsx +++ b/packages/agentic/design/src/theming/ThemedRoot.tsx @@ -4,7 +4,7 @@ import { View } from 'react-native'; import type { IViewProps } from '@fluentui-react-native/adapters'; import { useThemeBoundary } from './context'; -import { FlexThemeReference } from './flexThemeReference'; +import { FlexThemeReference } from '../flex/flexThemeReference'; import { RootContext } from './rootContext'; import { createRootInputController, RootInputContext } from './rootInputController'; import { useRootInputProps } from './useRootInputProps'; diff --git a/packages/agentic/design/src/theming/appearance.ts b/packages/agentic/design/src/theming/appearance.ts index 4abbabbd21..1d6f5411cc 100644 --- a/packages/agentic/design/src/theming/appearance.ts +++ b/packages/agentic/design/src/theming/appearance.ts @@ -1,11 +1,11 @@ -import type { AppearanceOptions, Theme } from './types/Theme.types'; +import type { AppearanceOptions, Theme } from '../fluent/types/Theme.types'; import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceRequest, ThemeAppearanceSourceSnapshot, ThemeAppearanceState, -} from './appearance.types'; +} from '../types/appearance.types'; export const defaultThemeAppearanceRequest: Readonly = Object.freeze({ colorScheme: 'system', diff --git a/packages/agentic/design/src/theming/appearanceSource.ts b/packages/agentic/design/src/theming/appearanceSource.ts index 228aa20436..2d0186fb50 100644 --- a/packages/agentic/design/src/theming/appearanceSource.ts +++ b/packages/agentic/design/src/theming/appearanceSource.ts @@ -1,4 +1,4 @@ -import type { ThemeAppearanceSourceSnapshot, ThemeAppearanceStore } from './appearance.types'; +import type { ThemeAppearanceSourceSnapshot, ThemeAppearanceStore } from '../types/appearance.types'; type NativeSubscribe = (listener: () => void) => () => void; diff --git a/packages/agentic/design/src/theming/context.ts b/packages/agentic/design/src/theming/context.ts index 1e77b68f00..dbb6e1195c 100644 --- a/packages/agentic/design/src/theming/context.ts +++ b/packages/agentic/design/src/theming/context.ts @@ -1,11 +1,11 @@ import * as React from 'react'; import { appearanceOptionsFromLegacy, resolveThemeAppearance } from './appearance'; -import type { ResolvedThemeAppearance, ThemeAppearanceSource, ThemeAppearanceState } from './appearance.types'; +import type { ResolvedThemeAppearance, ThemeAppearanceSource, ThemeAppearanceState } from '../types/appearance.types'; import { platformAppearance } from './platformAppearance'; import type { ThemeSource } from './themeSource'; import { legacyThemeSourceFromTheme } from './themeSource'; -import type { Theme } from './types/Theme.types'; +import type { Theme } from '../fluent/types/Theme.types'; export const ThemeContext = React.createContext(undefined); diff --git a/packages/agentic/design/src/theming/index.ts b/packages/agentic/design/src/theming/index.ts index 5ac164bac4..400f75a30e 100644 --- a/packages/agentic/design/src/theming/index.ts +++ b/packages/agentic/design/src/theming/index.ts @@ -7,9 +7,15 @@ export type { PaletteTextColors, PartialPalette, ThemeColorDefinition, -} from './types/Color.types'; -export type { ShadowValue, ShadowToken, BaseShadowAliasTokens, ThemeShadowDefinition, PartialShadowDefinition } from './types/Shadow.types'; -export type { AppearanceOptions, PartialTheme, Spacing, Theme, ThemeOptions } from './types/Theme.types'; +} from '../fluent/types/Color.types'; +export type { + ShadowValue, + ShadowToken, + BaseShadowAliasTokens, + ThemeShadowDefinition, + PartialShadowDefinition, +} from '../fluent/types/Shadow.types'; +export type { AppearanceOptions, PartialTheme, Spacing, Theme, ThemeOptions } from '../fluent/types/Theme.types'; export type { ResolvedThemeAppearance, ThemeAppearanceOptions, @@ -21,7 +27,7 @@ export type { ThemeColorScheme, ThemeContrast, ThemeInterfaceLevel, -} from './appearance.types'; +} from '../types/appearance.types'; export { appearanceOptionFromResolved, appearanceOptionsFromLegacy, @@ -47,10 +53,10 @@ export type { Variant, VariantValue, Variants, -} from './types/Typography.types'; +} from '../fluent/types/Typography.types'; export { ThemeContext } from './context'; -export { useTheme } from './useTheme'; -export type { OfficePalette } from './types/palette.types'; +export { useTheme } from '../fluent/useTheme'; +export type { OfficePalette } from '../fluent/types/palette.types'; export { ThemeProvider } from './ThemeProvider'; export type { ThemeProviderProps } from './ThemeProvider'; export { ThemedRoot } from './ThemedRoot'; @@ -59,17 +65,17 @@ export { RootContext, useRootSettings } from './rootContext'; export { RootInputBoundary } from './RootInputBoundary'; export { useRootInputModality } from './useRootInputModality'; export type { InputModality, RootSettings } from './rootContext'; -export { FlexThemeReference } from './flexThemeReference'; +export { FlexThemeReference } from '../flex/flexThemeReference'; export type { FlexThemeInput, FlexThemeRecipe, FlexThemeReferenceOptions, LegacyThemeFallback, PartialFlexTokens, -} from './flexThemeReference'; -export { ThemeReference } from './themeReference'; -export type { OnThemeChange, ThemeRecipe, ThemeReferenceOptions, ThemeTransform } from './themeReference'; +} from '../flex/flexThemeReference'; +export { ThemeReference } from '../fluent/themeReference'; +export type { OnThemeChange, ThemeRecipe, ThemeReferenceOptions, ThemeTransform } from '../fluent/themeReference'; export type { FlexThemeSource, LegacyThemeSource, ThemeSource, ThemeSourceBase } from './themeSource'; -export { getCurrentAppearance, isHighContrast, setIsHighContrast } from './platformUtils'; -export { mapFontPipelineToTheme, mapPipelineToTheme } from './mapPipelineToTheme'; -export { mapPipelineToShadow } from './mapPipelineToShadow'; +export { getCurrentAppearance, isHighContrast, setIsHighContrast } from '../fluent/platformUtils'; +export { mapFontPipelineToTheme, mapPipelineToTheme } from '../fluent/mapPipelineToTheme'; +export { mapPipelineToShadow } from '../fluent/mapPipelineToShadow'; diff --git a/packages/agentic/design/src/theming/modern.ts b/packages/agentic/design/src/theming/modern.ts index 1e83197417..f7bcdfaaa4 100644 --- a/packages/agentic/design/src/theming/modern.ts +++ b/packages/agentic/design/src/theming/modern.ts @@ -9,7 +9,7 @@ export type { ThemeColorScheme, ThemeContrast, ThemeInterfaceLevel, -} from './appearance.types'; +} from '../types/appearance.types'; export { appearanceOptionFromResolved, appearanceOptionsFromLegacy, @@ -18,14 +18,14 @@ export { themeAppearanceKey, } from './appearance'; export { createThemeAppearanceSource } from './appearanceSource'; -export { FlexThemeReference } from './flexThemeReference'; +export { FlexThemeReference } from '../flex/flexThemeReference'; export type { FlexThemeInput, FlexThemeRecipe, FlexThemeReferenceOptions, LegacyThemeFallback, PartialFlexTokens, -} from './flexThemeReference'; +} from '../flex/flexThemeReference'; export { ThemeProvider } from './ThemeProvider'; export type { ThemeProviderProps } from './ThemeProvider'; export { ThemedRoot } from './ThemedRoot'; diff --git a/packages/agentic/design/src/theming/themeRuntime.ts b/packages/agentic/design/src/theming/themeRuntime.ts index 0c6264fd82..6b73315bf8 100644 --- a/packages/agentic/design/src/theming/themeRuntime.ts +++ b/packages/agentic/design/src/theming/themeRuntime.ts @@ -1,22 +1,14 @@ -import { defaultFlexTokens } from '../tokens/defaultTokens'; -import type { FlexTokens } from '../tokens/flex.types'; -import { flexTokensFromTheme } from '../tokens/flexTokensFromTheme'; +import { defaultFlexTokens } from '../flex/defaults/defaultTokens'; +import type { FlexTokens } from '../flex/tokens.types'; +import { flexTokensFromTheme } from '../flex/adapters/flexTokensFromTheme'; import { defaultResolvedThemeAppearance, themeAppearanceKey } from './appearance'; -import type { ResolvedThemeAppearance } from './appearance.types'; +import type { ResolvedThemeAppearance } from '../types/appearance.types'; +import type { ThemeState } from '../types/themeState.types'; import type { ThemeSource } from './themeSource'; -export type ThemeStyleRegistry = Record; - -export interface RuntimeThemeState { - readonly tokens: FlexTokens; - readonly appearance: Readonly; - readonly highContrast: boolean; - readonly themeStyles: ThemeStyleRegistry; -} - type AppearanceCache = { flexTokens?: FlexTokens; - themeState?: RuntimeThemeState; + themeState?: ThemeState; }; type SourceCache = { @@ -26,7 +18,7 @@ type SourceCache = { const sourceCaches = new WeakMap(); -export const defaultThemeState: RuntimeThemeState = { +export const defaultThemeState: ThemeState = { tokens: defaultFlexTokens, appearance: defaultResolvedThemeAppearance, highContrast: false, @@ -57,7 +49,7 @@ export function getFlexTokens(source: ThemeSource, appearance: ResolvedThemeAppe return cache.flexTokens; } -export function getThemeState(source: ThemeSource, appearance: ResolvedThemeAppearance): RuntimeThemeState { +export function getThemeState(source: ThemeSource, appearance: ResolvedThemeAppearance): ThemeState { const cache = getAppearanceCache(source, appearance); if (!cache.themeState) { cache.themeState = { diff --git a/packages/agentic/design/src/theming/themeSource.ts b/packages/agentic/design/src/theming/themeSource.ts index 21d2a91480..bc02da2c69 100644 --- a/packages/agentic/design/src/theming/themeSource.ts +++ b/packages/agentic/design/src/theming/themeSource.ts @@ -1,6 +1,6 @@ -import type { FlexTokens } from '../tokens/flex.types'; -import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceSource } from './appearance.types'; -import type { PartialTheme, Theme } from './types/Theme.types'; +import type { FlexTokens } from '../flex/tokens.types'; +import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceSource } from '../types/appearance.types'; +import type { PartialTheme, Theme } from '../fluent/types/Theme.types'; export type OnThemeChange = () => void; diff --git a/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml b/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml index f5fe940758..83a9cea7bb 100644 --- a/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml +++ b/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml @@ -5,7 +5,7 @@ target: types: supported: FlexTokens unsupported: UnsupportedFlexTokens - definition: '../flex.types.ts' + definition: '../../flex/tokens.types.ts' direction: flex token path <- authoring source token sources: generic: @@ -23,7 +23,7 @@ sources: furn-theme: description: Dot path to the corresponding value in the Fluent UI React Native Theme type. - definition: '../../theming/types/Theme.types.ts' + definition: '../../fluent/types/Theme.types.ts' projection: './flex-from-theme.json' reverseProjection: './theme-from-flex.json' rules: @@ -58,9 +58,9 @@ rules: - furn-theme is omitted when Theme has no corresponding value path. - scripts/token-mappings/check-mappings.cjs enforces that flex-from-theme.json exactly matches the furn-theme mappings in this file. - - flexTokensFromTheme.ts consumes flex-from-theme.json and merges the projected + - ../../flex/adapters/flexTokensFromTheme.ts consumes flex-from-theme.json and merges the projected Theme values over nonFluentFlexTokens. - - The same check enforces that nonFluentFlexTokens in ../defaultTokens.ts covers + - The same check enforces that nonFluentFlexTokens in ../../flex/defaults/defaultTokens.ts covers unmapped supported destinations. An unmapped hover or pressed fallback is included only when its rest destination is also unmapped; otherwise the state value remains only in defaultFlexTokens so a Theme-provided rest value does diff --git a/packages/agentic/design/src/concepts/textAttributes.ts b/packages/agentic/design/src/tokens/textAttributes.ts similarity index 98% rename from packages/agentic/design/src/concepts/textAttributes.ts rename to packages/agentic/design/src/tokens/textAttributes.ts index 6ab9bf50ba..ccffd27e4a 100644 --- a/packages/agentic/design/src/concepts/textAttributes.ts +++ b/packages/agentic/design/src/tokens/textAttributes.ts @@ -13,7 +13,7 @@ import { fontWeightRegular, fontWeightMedium, fontWeightBold, -} from '../tokens/global.generated'; +} from './global.generated'; /** * Represents the available font sizes for this platform. Available via key lookup diff --git a/packages/agentic/design/src/theming/appearance.types.ts b/packages/agentic/design/src/types/appearance.types.ts similarity index 100% rename from packages/agentic/design/src/theming/appearance.types.ts rename to packages/agentic/design/src/types/appearance.types.ts diff --git a/packages/agentic/design/src/types/themeState.types.ts b/packages/agentic/design/src/types/themeState.types.ts new file mode 100644 index 0000000000..818c5aa3d8 --- /dev/null +++ b/packages/agentic/design/src/types/themeState.types.ts @@ -0,0 +1,31 @@ +import type { FlexTokens } from '../flex/tokens.types'; +import type { ResolvedThemeAppearance } from './appearance.types'; + +/** + * Style sheets cached for one theme state, keyed by a module-scoped symbol per component. + */ +export type ThemeStyleRegistry = Record; + +export type ThemeState = { + /** + * The set of flex tokens + */ + readonly tokens: FlexTokens; + /** + * Structured appearance values used to resolve this theme state. + */ + readonly appearance: Readonly; + /** + * @deprecated Use appearance.contrast. + */ + readonly highContrast: boolean; + /** + * Style sheets shared by every component instance using this theme state. + * + * Components should use a module-scoped symbol as their key and lazily store + * one immutable StyleSheet.create result whose values depend only on this + * ThemeState. Component props, interaction state, and user styles must be + * applied separately. + */ + readonly themeStyles: ThemeStyleRegistry; +}; diff --git a/packages/agentic/design/src/utilities/objects.ts b/packages/agentic/design/src/utilities/objects.ts index 607689b9bd..c5085e306e 100644 --- a/packages/agentic/design/src/utilities/objects.ts +++ b/packages/agentic/design/src/utilities/objects.ts @@ -5,26 +5,34 @@ */ export type ObjectFromObjectMapping = Record; +export type InvalidPathReason = 'empty' | 'unsafe'; + const unsafePathSegments = new Set(['__proto__', 'constructor', 'prototype']); -function getPathSegments(path: string, pathKind: 'source' | 'destination'): string[] { +/** + * Split a dotted object path, rejecting empty and prototype-polluting segments with the caller's error. + */ +export function splitObjectPath(path: string, invalidPath: (reason: InvalidPathReason) => Error): string[] { const segments = path.split('.'); if (segments.some((segment) => segment.length === 0)) { - throw new Error(`Invalid ${pathKind} path "${path}".`); + throw invalidPath('empty'); } if (segments.some((segment) => unsafePathSegments.has(segment))) { - throw new Error(`Unsafe ${pathKind} path "${path}".`); + throw invalidPath('unsafe'); } return segments; } -function isRecord(value: unknown): value is Record { +export function isRecord(value: unknown): value is Record { return typeof value === 'object' && value !== null && !Array.isArray(value); } -function getValueAtPath(source: object, path: string): unknown { +/** + * Read an own value at the path, or undefined when any segment is missing. + */ +export function getValueAtSegments(source: object, segments: readonly string[]): unknown { let value: unknown = source; - for (const segment of getPathSegments(path, 'source')) { + for (const segment of segments) { if (!isRecord(value) || !Object.prototype.hasOwnProperty.call(value, segment)) { return undefined; } @@ -33,10 +41,15 @@ function getValueAtPath(source: object, path: string): unknown { return value; } -function setValueAtPath(destination: Record, path: string, value: unknown): void { - const segments = getPathSegments(path, 'destination'); +/** + * Return the record that owns the path's leaf, creating missing parents. A non-record parent throws the caller's error. + */ +export function ensureParentRecord( + destination: Record, + segments: readonly string[], + conflict: (segment: string) => Error, +): Record { let target = destination; - for (const segment of segments.slice(0, -1)) { const existing = target[segment]; if (existing === undefined) { @@ -46,9 +59,27 @@ function setValueAtPath(destination: Record, path: string, valu } else if (isRecord(existing)) { target = existing; } else { - throw new Error(`Cannot create destination path "${path}" because "${segment}" is not an object.`); + throw conflict(segment); } } + return target; +} + +function getPathSegments(path: string, pathKind: 'source' | 'destination'): string[] { + return splitObjectPath(path, (reason) => new Error(`${reason === 'empty' ? 'Invalid' : 'Unsafe'} ${pathKind} path "${path}".`)); +} + +function getValueAtPath(source: object, path: string): unknown { + return getValueAtSegments(source, getPathSegments(path, 'source')); +} + +function setValueAtPath(destination: Record, path: string, value: unknown): void { + const segments = getPathSegments(path, 'destination'); + const target = ensureParentRecord( + destination, + segments, + (segment) => new Error(`Cannot create destination path "${path}" because "${segment}" is not an object.`), + ); const leaf = segments[segments.length - 1]; if (target[leaf] !== undefined) { diff --git a/packages/components/Text/MIGRATION.md b/packages/components/Text/MIGRATION.md index 281c19cc8e..239875d941 100644 --- a/packages/components/Text/MIGRATION.md +++ b/packages/components/Text/MIGRATION.md @@ -21,7 +21,7 @@ import { TextV1 as Text } from '@fluentui-react-native/text'; ### Props changed -- `variant` => Prop name remains identical, but will support a different collection of named font variants. Newly defined v1 variants can be found in [Typography.types](../../agentic/design/src/theming/types/Typography.types.ts) under theme-types. +- `variant` => Prop name remains identical, but will support a different collection of named font variants. Newly defined v1 variants can be found in [Typography.types](../../agentic/design/src/fluent/types/Typography.types.ts) under theme-types. ### Props added From bf3b1bfe7b4c15181799f444dd3df8020a809d3d Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 23 Oct 2026 18:30:53 -0700 Subject: [PATCH 04/18] design: add ColorTone and automatic Flex interaction engine (refactor phase 3) - Add ColorTone (cool|warm) to appearance requests and resolved appearances; tone resolves provider/root > source option > fallback > cool and is keyed separately only for warm. Raw legacy ThemeContext boundaries resolve cool. - Make color-lib's interaction API token-free (colorTone, direction, compositing) and move interactive-token classification to src/flex/colors, exported from the root. - FlexThemeReference derives omitted hover/pressed entries from rest for the appearance's scheme and tone; high contrast and unresolvable rest values use rest. The fill is eager per resolved appearance for now; phase 4 replaces it with lazy state envelopes. - Move the bulk interaction-override helper to test fixtures. - Guard ownership with import-boundary tests and add retained-output bundle assertions so legacy-only scenarios cannot retain the engine. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5030bce5-d7f7-4fb1-93de-68599b79269f --- apps/bundle-size/README.md | 7 + apps/bundle-size/scenarios.json | 22 +- apps/bundle-size/scripts/measure.mts | 64 +++-- apps/bundle-size/scripts/types.mts | 2 + .../src/common/useFocusVisuals.test.tsx | 2 +- packages/agentic/design/README.md | 2 +- .../agentic/design/references/color-lib.md | 35 ++- .../agentic/design/references/contributing.md | 18 +- .../agentic/design/references/entry-points.md | 12 +- packages/agentic/design/references/testing.md | 5 +- packages/agentic/design/references/theming.md | 23 +- packages/agentic/design/references/tokens.md | 7 +- .../design/src/color-lib/colorLib.test.ts | 172 +++++--------- .../agentic/design/src/color-lib/index.ts | 9 +- .../design/src/color-lib/interaction.ts | 222 +++--------------- .../agentic/design/src/color-lib/types.ts | 42 ++-- .../src/flex/colors/interactionPolicy.test.ts | 184 +++++++++++++++ .../src/flex/colors/interactionPolicy.ts | 57 +++++ .../src/flex/colors/interactiveTokens.ts | 94 ++++++++ .../src/flex/flexThemeReference.test.ts | 90 +++++++ .../design/src/flex/flexThemeReference.ts | 35 ++- .../agentic/design/src/flex/themeState.ts | 47 ++++ .../design/src/flex/useThemeState.test.ts | 37 +++ .../agentic/design/src/flex/useThemeState.ts | 2 +- .../fluent/__tests__/themeReference.test.ts | 17 ++ .../fluent/compat/defaultLegacyTheme.test.ts | 7 + .../src/fluent/compat/defaultLegacyTheme.ts | 7 +- .../design/src/fluent/themeReference.ts | 13 +- .../agentic/design/src/fluent/useTheme.ts | 4 +- packages/agentic/design/src/index.ts | 4 + .../test/color-validation/validation.test.ts | 22 +- .../__snapshots__/entryPoints.test.ts.snap | 3 +- .../compatibility/importBoundaries.test.ts | 17 ++ .../src/test/fixtures/interactionColors.ts | 45 ++++ .../test/fixtures/x3InteractionConformance.ts | 9 +- .../design/src/theming/ThemedRoot.test.tsx | 85 ++++++- .../design/src/theming/appearance.test.ts | 62 +++++ .../agentic/design/src/theming/appearance.ts | 59 ++++- packages/agentic/design/src/theming/index.ts | 2 + packages/agentic/design/src/theming/modern.ts | 2 + .../design/src/theming/themeRuntime.ts | 49 ++-- .../design/src/types/appearance.types.ts | 26 +- .../design/src/types/themeState.types.ts | 4 +- 43 files changed, 1161 insertions(+), 466 deletions(-) create mode 100644 packages/agentic/design/src/flex/colors/interactionPolicy.test.ts create mode 100644 packages/agentic/design/src/flex/colors/interactionPolicy.ts create mode 100644 packages/agentic/design/src/flex/colors/interactiveTokens.ts create mode 100644 packages/agentic/design/src/flex/themeState.ts create mode 100644 packages/agentic/design/src/test/fixtures/interactionColors.ts diff --git a/apps/bundle-size/README.md b/apps/bundle-size/README.md index 3a8f69c341..5ec90ef3a8 100644 --- a/apps/bundle-size/README.md +++ b/apps/bundle-size/README.md @@ -54,5 +54,12 @@ workflow. 3. Run `yarn bundle-size` and inspect the generated esbuild metafile. The metafile can also be loaded into the esbuild bundle analyzer. +A scenario can also guard module boundaries with path substrings. `forbiddenInputPatterns` and +`requiredInputPatterns` match every module esbuild resolves from the entry, including modules +tree shaking later removes. `forbiddenOutputPatterns` and `requiredOutputPatterns` match only +the modules that contribute bytes to the bundle. Use input patterns when a module must not +even be reachable, and output patterns when a shared entry reaches a module that a consumer's +imports must not retain. + Use a supported public package or subpath export when measuring consumer cost. A source-relative module path is useful for diagnostics, but it does not prove the cost of the published API. diff --git a/apps/bundle-size/scenarios.json b/apps/bundle-size/scenarios.json index dbbae8f21d..caf672fd58 100644 --- a/apps/bundle-size/scenarios.json +++ b/apps/bundle-size/scenarios.json @@ -15,19 +15,21 @@ "name": "design-theme-state", "module": "@fluentui-react-native/design", "exports": ["FlexThemeReference", "ThemeProvider", "useThemeState"], - "forbiddenInputPatterns": ["/design/src/fluent/", "/design/src/test/", "/color-lib/"], + "forbiddenInputPatterns": ["/design/src/fluent/", "/design/src/test/", "/color-lib/compositing."], "requiredInputPatterns": [ "/design/src/flex/flexThemeReference.", "/design/src/flex/useThemeState.", "/design/src/theming/ThemeProvider." - ] + ], + "requiredOutputPatterns": ["/color-lib/interaction.", "/design/src/flex/colors/interactionPolicy."] }, { "name": "design-themed-root", "module": "@fluentui-react-native/design", "exports": ["ThemedRoot", "useRootSettings", "useThemeState"], - "forbiddenInputPatterns": ["/design/src/fluent/", "/design/src/test/", "/color-lib/"], - "requiredInputPatterns": ["/design/src/flex/useThemeState.", "/design/src/theming/ThemedRoot."] + "forbiddenInputPatterns": ["/design/src/fluent/", "/design/src/test/", "/color-lib/compositing."], + "requiredInputPatterns": ["/design/src/flex/useThemeState.", "/design/src/theming/ThemedRoot."], + "requiredOutputPatterns": ["/color-lib/interaction.", "/design/src/flex/colors/interactionPolicy."] }, { "name": "design-color-lib", @@ -48,7 +50,17 @@ } ], "forbiddenInputPatterns": ["/design/src/fluent/compat/", "/design/src/fluent/tokens/", "/design/src/test/"], - "requiredInputPatterns": ["/design/src/fluent/themeReference."] + "requiredInputPatterns": ["/design/src/fluent/themeReference."], + "forbiddenOutputPatterns": ["/color-lib/", "/design/src/flex/colors/", "/design/src/flex/flexThemeReference."] + }, + { + "name": "design-legacy-theme", + "module": "@fluentui-react-native/design/theming", + "exports": ["ThemeProvider", "ThemeReference", "useTheme"], + "forbiddenInputPatterns": ["/design/src/test/"], + "requiredInputPatterns": ["/design/src/theming/ThemeProvider."], + "forbiddenOutputPatterns": ["/color-lib/", "/design/src/flex/"], + "requiredOutputPatterns": ["/design/src/fluent/themeReference.", "/design/src/fluent/useTheme."] }, { "name": "design-legacy-theme-from-flex", diff --git a/apps/bundle-size/scripts/measure.mts b/apps/bundle-size/scripts/measure.mts index 171b7e58e5..d019da1d37 100644 --- a/apps/bundle-size/scripts/measure.mts +++ b/apps/bundle-size/scripts/measure.mts @@ -97,9 +97,7 @@ function getWorkspacePackage(source: string): string | undefined { return undefined; } -function getWorkspaceContributions(metafile: Metafile) { - const packageModules = new Map(); - const packageBytes = new Map(); +function getContributingInputs(metafile: Metafile): Map { const contributingInputs = new Map(); for (const output of Object.values(metafile.outputs)) { @@ -110,6 +108,13 @@ function getWorkspaceContributions(metafile: Metafile) { } } + return contributingInputs; +} + +function getWorkspaceContributions(contributingInputs: Map) { + const packageModules = new Map(); + const packageBytes = new Map(); + for (const [source, bytes] of contributingInputs) { const packageName = getWorkspacePackage(source); if (packageName) { @@ -127,6 +132,29 @@ function getWorkspaceContributions(metafile: Metafile) { }; } +function assertModulePatterns( + scenario: Scenario, + kind: 'input' | 'output', + paths: string[], + forbidden: string[] = [], + required: string[] = [], +) { + const subject = kind === 'input' ? 'includes' : 'retains'; + for (const pattern of forbidden) { + const match = paths.find((source) => source.includes(pattern)); + if (match) { + throw new Error(`Scenario "${scenario.name}" unexpectedly ${subject} "${match}" (forbidden by "${pattern}")`); + } + } + for (const pattern of required) { + if (!paths.some((source) => source.includes(pattern))) { + throw new Error( + `Scenario "${scenario.name}" does not ${subject.slice(0, -1)} a module matching required ${kind} pattern "${pattern}"`, + ); + } + } +} + async function runBundle(platform: string, scenario: Scenario): Promise { const entryPath = join(entryRoot, `${scenario.name}.js`); const bundlePath = join(outputRoot, platform, `${scenario.name}.bundle`); @@ -143,19 +171,23 @@ async function runBundle(platform: string, scenario: Scenario): Promise source.replaceAll('\\', '/')); - for (const pattern of scenario.forbiddenInputPatterns ?? []) { - const match = inputPaths.find((source) => source.includes(pattern)); - if (match) { - throw new Error(`Scenario "${scenario.name}" unexpectedly includes "${match}" (forbidden by "${pattern}")`); - } - } - for (const pattern of scenario.requiredInputPatterns ?? []) { - if (!inputPaths.some((source) => source.includes(pattern))) { - throw new Error(`Scenario "${scenario.name}" does not include a module matching required pattern "${pattern}"`); - } - } - const contributions = getWorkspaceContributions(metafile); + const normalizePath = (source: string) => source.replaceAll('\\', '/'); + const contributingInputs = getContributingInputs(metafile); + assertModulePatterns( + scenario, + 'input', + Object.keys(metafile.inputs).map(normalizePath), + scenario.forbiddenInputPatterns, + scenario.requiredInputPatterns, + ); + assertModulePatterns( + scenario, + 'output', + [...contributingInputs.keys()].map(normalizePath), + scenario.forbiddenOutputPatterns, + scenario.requiredOutputPatterns, + ); + const contributions = getWorkspaceContributions(contributingInputs); return { platform, diff --git a/apps/bundle-size/scripts/types.mts b/apps/bundle-size/scripts/types.mts index 57f3e3889a..15fa03a86f 100644 --- a/apps/bundle-size/scripts/types.mts +++ b/apps/bundle-size/scripts/types.mts @@ -12,6 +12,8 @@ export interface Scenario { imports?: ScenarioImport[]; forbiddenInputPatterns?: string[]; requiredInputPatterns?: string[]; + forbiddenOutputPatterns?: string[]; + requiredOutputPatterns?: string[]; } export interface ScenarioConfig { diff --git a/packages/agentic/components/src/common/useFocusVisuals.test.tsx b/packages/agentic/components/src/common/useFocusVisuals.test.tsx index 1fda2c47f3..ba5df593d9 100644 --- a/packages/agentic/components/src/common/useFocusVisuals.test.tsx +++ b/packages/agentic/components/src/common/useFocusVisuals.test.tsx @@ -133,7 +133,7 @@ describe('useFocusVisuals', () => { get tokens() { return getTokens(); }, - appearance: { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base' }, + appearance: { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base', colorTone: 'cool' }, highContrast: false, themeStyles: {}, }; diff --git a/packages/agentic/design/README.md b/packages/agentic/design/README.md index 2ac38f9c4c..ca24383c80 100644 --- a/packages/agentic/design/README.md +++ b/packages/agentic/design/README.md @@ -36,7 +36,7 @@ Existing `ThemeReference` themes and `useTheme` consumers keep working under the | [Theming](references/theming.md) | Theme references, providers, appearance, hooks, and legacy projection | | [Tokens](references/tokens.md) | Token sources and Flex token mapping maintenance | | [Styling](references/styling.md) | Themed style caches and state or color style factories | -| [Color library](references/color-lib.md) | The opt-in `color-lib` runtime color engine | +| [Color library](references/color-lib.md) | Raw `color-lib` algorithms and the Flex interaction-color policy | | [Testing helpers](references/testing.md) | Test-only fixtures and contrast validation | | [Entry points](references/entry-points.md) | Every subpath and the legacy compatibility packages | | [Contributing](references/contributing.md) | Source ownership, generated files, tests, and validation | diff --git a/packages/agentic/design/references/color-lib.md b/packages/agentic/design/references/color-lib.md index b0e5064392..c9069aa24d 100644 --- a/packages/agentic/design/references/color-lib.md +++ b/packages/agentic/design/references/color-lib.md @@ -3,18 +3,20 @@ id: design.color-lib kind: instruction-reference owner_paths: - packages/agentic/design/src/color-lib + - packages/agentic/design/src/flex/colors --- # Color library -`@fluentui-react-native/design/color-lib` is the opt-in runtime color engine. -It groups public utilities by responsibility: +`@fluentui-react-native/design/color-lib` exposes the raw color algorithms for +direct use. Theme authors do not need it: `FlexThemeReference` fills omitted +interaction states automatically (see `theming.md`). It groups public utilities +by responsibility: - `parsing.ts` parses literal React Native colors and formats RGBA values; - `conversion.ts` converts between normalized sRGB and OKLCH; - `compositing.ts` composites alpha colors and calculates WCAG contrast; -- `interaction.ts` generates hover and pressed colors with the default or - Bebop Warm algorithm. +- `interaction.ts` generates one hover or pressed color from a rest color. Native and dynamic color objects cannot be resolved in JavaScript, so parsing and interaction APIs return structured diagnostics instead of fabricated @@ -23,23 +25,32 @@ for unsupported values. The algorithms are ported from [`x3-design/fluent-design@d334acf5cbad813f2b7cd554da942b09a7ff8f10`](https://github.com/x3-design/fluent-design/tree/d334acf5cbad813f2b7cd554da942b09a7ff8f10/dev/web/flex-themes). -The default variant preserves chroma. The `bebopWarm` variant adds the pinned -opacity-aware lightness, chroma, bounds, and translucent reference-backdrop -solve. +The interaction API knows nothing about Flex tokens. Its options select: + +| Option | Values | Effect | +| ------------- | -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| `colorTone` | `cool` (default), `warm` | `cool` shifts OKLCH lightness and preserves chroma; `warm` adds the pinned opacity-aware lightness, chroma, and bounds | +| `direction` | `standard` (default), `inverted` | `inverted` shifts lightness opposite the scheme's standard direction | +| `compositing` | `direct` (default), `backdrop` | For `warm` only, `backdrop` composites a translucent color over the scheme's reference backdrop and solves a source at the target alpha | ```ts import { getContrastRatio, getHoverColor } from '@fluentui-react-native/design/color-lib'; -const hover = getHoverColor('#c02e56', 'backgroundDangerLoud', 'light', { - variant: 'bebopWarm', -}); +const hover = getHoverColor('#c02e56', 'light', { colorTone: 'warm', direction: 'inverted' }); const ratio = getContrastRatio('#000000db', '#ffffff'); ``` +Token classification is Flex policy, not part of this library. +`INTERACTIVE_COLOR_TOKENS` and `isInverseInteractionToken` are exported from +the package root and owned by `src/flex/colors/`, which maps each Flex token to +a direction and compositing mode before calling `getInteractionColor`. + Keep the public exports narrow and add APIs only for demonstrated production needs. The public interaction surface is intentionally limited to generating one hover or pressed value at a time. Bulk fallback helpers and algorithm constants remain internal until a production consumer needs them. -The submodule is absent from the design root barrel and does not import the -test-only `testing` submodule. +The library imports only its own modules and shared types; it never reaches +Flex, Fluent, or the test-only `testing` submodule. The modern root reaches +`interaction.ts` and its parsing and conversion dependencies through the Flex +interaction policy, but not `compositing.ts`. diff --git a/packages/agentic/design/references/contributing.md b/packages/agentic/design/references/contributing.md index 295ac78772..9dae388363 100644 --- a/packages/agentic/design/references/contributing.md +++ b/packages/agentic/design/references/contributing.md @@ -14,20 +14,22 @@ owner_paths: | `src/types/` | Type-only contracts shared by the Flex and Fluent models, such as appearance and theme state | | `src/theming/` | Shared theme sources, providers, boundaries, appearance, runtime caches, and the `theming` facades | | `src/flex/` | Flex token types, defaults, the Theme-to-Flex adapter, `FlexThemeReference`, `useThemeState`, and styles | +| `src/flex/colors/` | Interactive-token classification and the automatic interaction-color policy; see `color-lib.md` | | `src/fluent/` | Legacy Fluent theme types, `ThemeReference`, `useTheme`, platform utilities, and legacy styling | | `src/fluent/compat/` | The Flex-to-legacy projection and complete legacy defaults; never reachable from the root | | `src/fluent/tokens/` | Legacy alias, shadow, and global token data | | `src/tokens/` | Generated global tokens and shared token attributes | | `src/tokens/mappings/` | The canonical token map and its generated projections; see `tokens.md` | | `src/styling/` | Shared state style factories and the `styling` facade; see `styling.md` | -| `src/color-lib/` | The runtime color engine; see `color-lib.md` | +| `src/color-lib/` | Raw, token-free color algorithms; see `color-lib.md` | | `src/test/` | Test-only fixtures, compatibility baselines, and color validation; see `testing.md` | | `src/index.ts` | The modern root entry point; see `entry-points.md` for every subpath | Shared modules may import types from either model. At runtime, only the `theming` facade and the legacy subpaths reach -`src/fluent/`; the root and `styling` graphs may reach `src/flex/` but never `src/fluent/`. Production code never imports -`src/test/`. Source paths are private: consumers use the package subpaths in `entry-points.md`, never `src/` or `lib/` -paths. +`src/fluent/`; the root and `styling` graphs may reach `src/flex/` but never `src/fluent/`. Dependencies point one way: +`src/flex/colors/` may import `src/color-lib/`, but `src/color-lib/` imports only its own modules and shared types. +Production code never imports `src/test/`. Source paths are private: consumers use the package subpaths in +`entry-points.md`, never `src/` or `lib/` paths. The package's scripts directory holds `codegen.cts`, which runs before every build, and the token-mapping check and upstream drift tools described in `tokens.md`. Generated token and projection files are committed; change their inputs @@ -35,9 +37,11 @@ and rebuild rather than editing them. ## Invariants -- Keep the root import graph modern: it must not reach `useTheme`, anything under `src/fluent/`, or - `src/color-lib/`. `src/test/compatibility/importBoundaries.test.ts` checks the entry graphs; run the bundle-size - scenarios too when changing imports between these areas. +- Keep the root import graph modern: it must not reach `useTheme` or anything under `src/fluent/`. It reaches + `color-lib/interaction` (with its parsing and conversion dependencies) only through `src/flex/colors/`, never + `color-lib/compositing`. The legacy `ThemeReference`, `useTheme`, and `ThemeProvider` graphs must not reach + `src/flex/` or `src/color-lib/`. `src/test/compatibility/importBoundaries.test.ts` checks the entry graphs; run the + bundle-size scenarios too when changing imports between these areas. - Never mutate author-owned theme inputs; caches are external and keyed by source, revision, and resolved appearance. - Keep platform appearance listeners subscription-scoped; nothing subscribes at module import. - Keep the experimental native appearance modules and platform theme packages out of this package's dependencies; diff --git a/packages/agentic/design/references/entry-points.md b/packages/agentic/design/references/entry-points.md index a10eb023ef..d0be2a6e9f 100644 --- a/packages/agentic/design/references/entry-points.md +++ b/packages/agentic/design/references/entry-points.md @@ -19,16 +19,18 @@ public symbols by name from each entry point; do not add barrel re-exports. | `./theming/compat/defaults` | `getDefaultLegacyTheme` alone, for platform theme packages | | `./tokens/global` | Generated platform global token constants | | `./tokens/legacy` | Legacy alias, shadow, and global token data | -| `./color-lib` | The opt-in runtime color engine; see `color-lib.md` | +| `./color-lib` | Raw color parsing, conversion, compositing, and interaction algorithms; see `color-lib.md` | | `./styling` | State and color style factories; see `styling.md` | | `./styling/stylesheet` | The legacy `themedStyleSheet` helper | | `./styling/tokens` | Legacy token-to-style builders | | `./testing` | Test-only fixtures and validation; see `testing.md` | -The `apps/bundle-size` `design-*` scenarios guard these boundaries: the modern root and legacy-source scenarios forbid -the compatibility, legacy-token, and (for the root) color-library modules, while the color-library and legacy-projection -scenarios require their expected modules. Every scenario also requires a module it is expected to load, so a moved file -cannot make a forbidden pattern pass vacuously. +The `apps/bundle-size` `design-*` scenarios guard these boundaries. Input patterns check the import graph and output +patterns check the modules a tree-shaken bundle retains. The modern root and legacy-source scenarios forbid the +compatibility and legacy-token modules; the modern root scenarios forbid `color-lib/compositing` and require the +retained Flex interaction policy; the legacy-source and legacy theme scenarios forbid any retained color-library or Flex +interaction module; and the color-library and legacy-projection scenarios require their expected modules. Every scenario +also requires a module it is expected to load, so a moved file cannot make a forbidden pattern pass vacuously. The package specifiers above are the supported import surface. Source and build paths such as `src/fluent/...` or `lib/...` are private implementation details that may move without a breaking change. diff --git a/packages/agentic/design/references/testing.md b/packages/agentic/design/references/testing.md index 2b1e4c7101..d912e4d9b8 100644 --- a/packages/agentic/design/references/testing.md +++ b/packages/agentic/design/references/testing.md @@ -35,5 +35,6 @@ const failures = getContrastFailures(validateContrastPairs(defaultFlexTokens.col ``` The package's internal validation suite audits rest, hover, and pressed values -for both default and Bebop Warm interaction variants. Its pinned conformance -fixtures are implementation evidence rather than public testing exports. +for both the cool and warm color tones. Its pinned conformance fixtures and the +bulk `getInteractionColorOverrides` helper under `src/test/fixtures` are +implementation evidence rather than public testing exports. diff --git a/packages/agentic/design/references/theming.md b/packages/agentic/design/references/theming.md index 6d2375c824..dd532ca62b 100644 --- a/packages/agentic/design/references/theming.md +++ b/packages/agentic/design/references/theming.md @@ -24,8 +24,14 @@ both models. Modern consumers read Flex tokens through `useThemeState`; legacy c `FlexThemeReference` accepts `base`, `appearance`, `fallbackAppearance`, `appearanceSource`, and `legacyFallback` options followed by recipes. It resolves the design package's default Flex tokens, then the base input, then recipes in -declaration order. A base or recipe may be a function of the resolved appearance. `PartialFlexTokens` is shape-aware so -opaque React Native colors stay leaves. +declaration order. A base or recipe may be a function of the resolved appearance, which always has a concrete +`colorTone`. `PartialFlexTokens` is shape-aware so opaque React Native colors stay leaves. + +After the recipes run, each omitted `hover` or `pressed` entry of an interactive color token is derived from that +token's resolved rest color with the `color-lib` interaction algorithm for the appearance's color scheme and tone; no +import, provider setting, or registration is required. Authored state values are kept. High contrast and rest values +JavaScript cannot resolve, such as `PlatformColor`, resolve the omitted state to the rest value. `color-lib.md` +describes the token classification. The derivation currently runs once when an appearance's tokens are resolved. ```ts import { FlexThemeReference } from '@fluentui-react-native/design'; @@ -90,7 +96,12 @@ back to an appearance reuses its entry within a revision, and a revision change ## Appearance A request has `colorScheme` (`light`, `dark`, or `system`), `contrast` (`standard`, `highContrast`, or `system`), and -`interfaceLevel` (`base`, `elevated`, or `system`). The resolved appearance is always concrete. A +`interfaceLevel` (`base`, `elevated`, or `system`), plus an optional `colorTone` (`cool` or `warm`). The resolved +appearance is always concrete. `colorTone` is a design choice rather than a platform setting, so appearance sources never +supply it: it resolves from the provider or root request, then the source's `appearance` option, then the fallback +appearance, then `cool`. A nested `ThemedRoot` inherits it with the other requested axes, and a raw legacy +`ThemeContext` boundary resolves to `cool`. Caches key a warm appearance separately; cool keeps the existing +`colorScheme|contrast|interfaceLevel` key, and the complete legacy defaults do not vary by tone. A `ThemeAppearanceSource` provides a stable `getSnapshot()` and a `subscribe()` that installs native listeners only while subscribed; create one with `createThemeAppearanceSource`. @@ -109,8 +120,10 @@ including `darkElevated`, `highContrast`, and `dynamic`. `getCurrentAppearance`, ## Legacy projection and bundle boundary The package root exports only the modern authoring and consumption APIs. It reaches the forward Theme-to-Flex adapter, -which `useThemeState` needs for legacy sources, but not `useTheme`, the reverse converter, the complete legacy -defaults, or legacy token payloads. `entry-points.md` lists every subpath. +which `useThemeState` needs for legacy sources, and the Flex interaction policy with the raw `color-lib` interaction +algorithm, but not `useTheme`, the reverse converter, the complete legacy defaults, or legacy token payloads. The legacy +`ThemeReference`, `useTheme`, and `ThemeProvider` graphs reach neither Flex nor `color-lib`. `entry-points.md` lists +every subpath. `themeFromFlexTokens` in `theming/compat` builds a complete `Theme` in this order: diff --git a/packages/agentic/design/references/tokens.md b/packages/agentic/design/references/tokens.md index 6d1a71bdb3..8a3102dd0c 100644 --- a/packages/agentic/design/references/tokens.md +++ b/packages/agentic/design/references/tokens.md @@ -25,7 +25,8 @@ owner_paths: | Platform global tokens | `@fluentui-react-native/design/tokens/global` | Generated into `src/tokens/global.generated.ts` and `src/tokens/generated/` | | Legacy alias and shadow tokens | `@fluentui-react-native/design/tokens/legacy` | `src/fluent/tokens/`, for legacy themes only | -`FlexTokens` groups `color` (with `hover` and `pressed` overrides), `shadow`, `fontWeight`, `fontFamily`, `fontSize`, +`FlexTokens` groups `color` (with `hover` and `pressed` maps whose omitted interactive entries are derived from rest), +`shadow`, `fontWeight`, `fontFamily`, `fontSize`, `lineHeight`, `borderRadius`, `spacing`, and `strokeWidth`. Components read the active values from `useThemeState().tokens`; `theming.md` explains how they are resolved. The defaults currently do not vary by appearance; see `remaining-work.md`. @@ -44,8 +45,8 @@ canonical Flex value back to each representable legacy Theme path. The reverse projection is intentionally lossy. When several Flex roles share one legacy Theme path, `reverse.canonical` names the selected source, lists every omitted candidate, and records why that choice is stable. Interactive reverse -entries fall back to their rest value when the authored hover or pressed map -does not override that token. `reverse.transforms` owns any value conversion +entries fall back to their rest value when the resolved hover or pressed map +has no entry for that token. `reverse.transforms` owns any value conversion required by a target path. `nonFluentFlexTokens` supplies values for supported Flex destinations without a diff --git a/packages/agentic/design/src/color-lib/colorLib.test.ts b/packages/agentic/design/src/color-lib/colorLib.test.ts index eb42307659..5b85172433 100644 --- a/packages/agentic/design/src/color-lib/colorLib.test.ts +++ b/packages/agentic/design/src/color-lib/colorLib.test.ts @@ -1,12 +1,5 @@ import { PlatformColor } from 'react-native'; -import { - x3BebopWarmInteractionConformance, - x3InteractionConformance, - x3WarmVariantDeviations, -} from '../test/fixtures/x3InteractionConformance'; -import { defaultFlexTokens } from '../flex/defaults/defaultTokens'; -import type { SemanticColorTokenValues } from '../flex/tokens.types'; import { compositeColor, compositeRgba, @@ -14,38 +7,13 @@ import { getHoverColor, getInteractionColor, getPressColor, - isInverseInteractionToken, oklchToRgb, parseColorValue, resolveContrastColors, rgbaToHex, rgbToOklch, } from './index'; -import type { ColorMode, InteractionColorState } from './index'; -import { getInteractionColorOverrides, getInteractionColors, INTERACTIVE_COLOR_TOKENS } from './interaction'; - -const modeIndexes = { - light: { rest: 0, hover: 1, pressed: 2 }, - dark: { rest: 3, hover: 4, pressed: 5 }, -} as const; - -function conformanceColors(mode: ColorMode): SemanticColorTokenValues { - const { hover: _hover, pressed: _pressed, ...colors } = defaultFlexTokens.color; - for (const token of INTERACTIVE_COLOR_TOKENS) { - colors[token] = x3InteractionConformance[token][modeIndexes[mode].rest]; - } - return colors; -} - -function getStateColor( - state: InteractionColorState, - color: string, - token: (typeof INTERACTIVE_COLOR_TOKENS)[number], - mode: ColorMode, - variant: 'default' | 'bebopWarm', -) { - return state === 'hover' ? getHoverColor(color, token, mode, { variant }) : getPressColor(color, token, mode, { variant }); -} +import type { InteractionColorOptions } from './index'; describe('color parsing and conversion', () => { it('parses supported literal formats', () => { @@ -153,112 +121,84 @@ describe('color compositing and contrast', () => { }); }); -describe.each(['light', 'dark'] as const)('%s interaction colors', (mode) => { - it.each(INTERACTIVE_COLOR_TOKENS)('matches default and Bebop Warm output for %s', (token) => { - const vector = x3InteractionConformance[token]; - const warmVector = x3BebopWarmInteractionConformance[token]; - for (const state of ['hover', 'pressed'] as const) { - const deviationKey = `${token}.${state}.${mode}` as keyof typeof x3WarmVariantDeviations; - const deviation = x3WarmVariantDeviations[deviationKey]; - const upstreamValue = vector[modeIndexes[mode][state]]; - const warmValue = warmVector[modeIndexes[mode][state]]; +describe('raw interaction colors', () => { + it('defaults to the cool tone, standard direction, and direct compositing', () => { + const explicit: InteractionColorOptions = { colorTone: 'cool', direction: 'standard', compositing: 'direct' }; - expect(getStateColor(state, vector[modeIndexes[mode].rest], token, mode, 'default')).toEqual({ - status: 'derived', - value: deviation?.defaultValue ?? upstreamValue, - }); - expect(getStateColor(state, warmVector[modeIndexes[mode].rest], token, mode, 'bebopWarm')).toEqual({ - status: 'derived', - value: warmValue, - }); - if (deviation) { - expect(upstreamValue).toBe(deviation.warmValue); + expect(getHoverColor('#ebebeb', 'light')).toEqual({ status: 'derived', value: '#e1e1e1' }); + expect(getPressColor('#ebebeb', 'light')).toEqual({ status: 'derived', value: '#d7d7d7' }); + for (const state of ['hover', 'pressed'] as const) { + for (const mode of ['light', 'dark'] as const) { + expect(getInteractionColor('#e9e9e980', mode, state)).toEqual(getInteractionColor('#e9e9e980', mode, state, explicit)); } } }); - it('generates a complete override map', () => { - const colors = conformanceColors(mode); - for (const token of INTERACTIVE_COLOR_TOKENS) { - colors[token] = x3BebopWarmInteractionConformance[token][modeIndexes[mode].rest]; - } - const result = getInteractionColorOverrides(colors, mode, 'hover', { variant: 'bebopWarm' }); - - expect(result.diagnostics).toEqual([]); - expect(Object.keys(result.overrides)).toHaveLength(59); + it('shifts standard colors with the scheme and inverted colors against it', () => { + expect(getHoverColor('#242424', 'light', { direction: 'inverted' })).toEqual({ status: 'derived', value: '#363636' }); + expect(getHoverColor('#ffffff', 'dark', { direction: 'inverted' })).toEqual({ status: 'derived', value: '#f5f5f5' }); + expect(getHoverColor('#1b1b1b', 'dark')).toEqual({ status: 'derived', value: '#2f2f2f' }); }); -}); -describe('interaction color API', () => { - it('classifies every inverse token with the upstream heavy/loud/onloud rule', () => { - const expected = [ - 'backgroundNeutralHeavy', - 'backgroundNeutralLoud', - 'backgroundBrandHeavy', - 'backgroundBrandLoud', - 'backgroundDangerLoud', - 'backgroundWarningLoud', - 'backgroundSuccessLoud', - 'strokeNeutralHeavy', - 'strokeNeutralLoud', - 'strokeNeutralOnloud', - 'strokeBrandLoud', - 'strokeBrandOnloud', - 'strokeDangerLoud', - 'strokeDangerOnloud', - 'strokeWarningLoud', - 'strokeWarningOnloud', - 'strokeSuccessLoud', - 'strokeSuccessOnloud', - 'foregroundNeutralOnloud', - 'foregroundBrandOnloud', - 'foregroundDangerOnloud', - 'foregroundWarningOnloud', - 'foregroundSuccessOnloud', - ]; + it('raises standard alpha and keeps inverted alpha', () => { + expect(getHoverColor('#e9e9e980', 'light')).toEqual({ status: 'derived', value: '#dfdfdf8a' }); + const inverted = getHoverColor('#00000080', 'light', { direction: 'inverted' }); - expect(INTERACTIVE_COLOR_TOKENS.filter(isInverseInteractionToken)).toEqual(expected); - expect(INTERACTIVE_COLOR_TOKENS).toHaveLength(59); - expect(Object.keys(x3WarmVariantDeviations)).toHaveLength(10); + expect(inverted.status).toBe('derived'); + expect(inverted.value).toMatch(/80$/); }); - it('fills missing values without replacing authored interaction colors', () => { - const input = { - ...conformanceColors('light'), - hover: { surfaceNeutralFarther: '#123456' }, - }; - const result = getInteractionColors(input, 'light'); + it('applies the warm reference backdrop only to translucent backdrop colors', () => { + const backdrop = getHoverColor('#e9e9e980', 'light', { colorTone: 'warm', compositing: 'backdrop' }); + const direct = getHoverColor('#e9e9e980', 'light', { colorTone: 'warm', compositing: 'direct' }); - expect(result.colors.hover.surfaceNeutralFarther).toBe('#123456'); - expect(result.colors.hover.surfaceNeutralFar).toBe('#e8e8e8'); - expect(result.colors.pressed.surfaceNeutralFarther).toBe('#d7d7d7'); - expect(result.diagnostics).toEqual([]); + expect(backdrop).toEqual({ status: 'derived', value: '#dcdcd68a' }); + expect(direct.status).toBe('derived'); + expect(direct.value).not.toBe(backdrop.value); + expect(direct.value).toMatch(/8a$/); + expect(getHoverColor('#ebebeb', 'light', { colorTone: 'warm', compositing: 'backdrop' })).toEqual( + getHoverColor('#ebebeb', 'light', { colorTone: 'warm', compositing: 'direct' }), + ); }); - it('preserves identity when every interaction value is authored', () => { - const colors = conformanceColors('light'); - const hover = getInteractionColorOverrides(colors, 'light', 'hover').overrides; - const pressed = getInteractionColorOverrides(colors, 'light', 'pressed').overrides; - const input = { ...colors, hover, pressed }; + it('ignores compositing for the cool tone', () => { + expect(getPressColor('#e9e9e980', 'dark', { compositing: 'backdrop' })).toEqual(getPressColor('#e9e9e980', 'dark')); + }); + + it('adds chroma for the warm tone and preserves it for the cool tone', () => { + const cool = getPressColor('#808080', 'light'); + const warm = getPressColor('#808080', 'light', { colorTone: 'warm' }); - expect(getInteractionColors(input, 'light').colors).toBe(input); + expect(cool.status).toBe('derived'); + expect(warm.status).toBe('derived'); + expect(rgbToOklch(hexChannels(cool.value as string)).C).toBeCloseTo(0, 6); + expect(rgbToOklch(hexChannels(warm.value as string)).C).toBeGreaterThan(0.005); }); it('reports opaque platform colors instead of deriving a wrong value', () => { - expect(getInteractionColor(PlatformColor('labelColor'), 'foregroundNeutralPrimary', 'light', 'hover')).toMatchObject({ + const rest = PlatformColor('labelColor'); + const result = getInteractionColor(rest, 'light', 'hover', { colorTone: 'warm' }); + + expect(result).toMatchObject({ status: 'unresolvable', - diagnostic: { - reason: 'non-literal-color', - token: 'foregroundNeutralPrimary', - state: 'hover', - }, + diagnostic: { reason: 'non-literal-color', state: 'hover' }, }); + expect(result.value).toBe(rest); + expect(result.status === 'unresolvable' && 'token' in result.diagnostic).toBe(false); }); it('reports malformed literals', () => { - expect(getPressColor('rgb(12oops 0 0)', 'foregroundDangerPrimary', 'light')).toMatchObject({ + expect(getPressColor('rgb(12oops 0 0)', 'light')).toMatchObject({ status: 'unresolvable', - diagnostic: { reason: 'unsupported-color-format' }, + diagnostic: { reason: 'unsupported-color-format', state: 'pressed' }, }); }); }); + +function hexChannels(value: string) { + const parsed = parseColorValue(value); + if (parsed.status !== 'resolved') { + throw new Error(`Expected a literal color: ${value}`); + } + return parsed.color; +} diff --git a/packages/agentic/design/src/color-lib/index.ts b/packages/agentic/design/src/color-lib/index.ts index fd24af8f2e..2d43136766 100644 --- a/packages/agentic/design/src/color-lib/index.ts +++ b/packages/agentic/design/src/color-lib/index.ts @@ -3,14 +3,11 @@ export type { ColorDiagnosticReason, ColorMode, InteractionColorDiagnostic, - InteractionColorInput, InteractionColorOptions, - InteractionColorOverridesResult, InteractionColorResult, - InteractionColorsResult, InteractionColorState, - InteractionColorVariant, - InteractiveColorToken, + InteractionCompositing, + InteractionDirection, OklchColor, ParsedColorValue, ResolvedContrastColors, @@ -20,4 +17,4 @@ export type { export { parseColorValue, rgbaToHex } from './parsing'; export { oklchToRgb, rgbToOklch } from './conversion'; export { compositeColor, compositeRgba, getContrastRatio, resolveContrastColors } from './compositing'; -export { getHoverColor, getInteractionColor, getPressColor, isInverseInteractionToken } from './interaction'; +export { getHoverColor, getInteractionColor, getPressColor } from './interaction'; diff --git a/packages/agentic/design/src/color-lib/interaction.ts b/packages/agentic/design/src/color-lib/interaction.ts index 44485ac9b5..d8932338f5 100644 --- a/packages/agentic/design/src/color-lib/interaction.ts +++ b/packages/agentic/design/src/color-lib/interaction.ts @@ -3,89 +3,13 @@ import type { ColorValue } from 'react-native'; import { rgbToOklch, oklchToRgb } from './conversion'; import { channelToByte, clamp } from './math'; import { parseColorValue, rgbaToHex } from './parsing'; -import type { - ColorMode, - InteractionColorDiagnostic, - InteractionColorInput, - InteractionColorOptions, - InteractionColorOverridesResult, - InteractionColorResult, - InteractionColorsResult, - InteractionColorState, - InteractiveColorToken, - RgbColor, - RgbaColor, -} from './types'; -import type { InteractiveColorOverrides, SemanticColors, SemanticColorTokenValues } from '../flex/tokens.types'; +import type { ColorMode, InteractionColorOptions, InteractionColorResult, InteractionColorState, RgbColor, RgbaColor } from './types'; /** - * Interactive subset of the Flex semantic color tokens. + * Default interaction lightness and alpha shifts for each state and mode. * * Source: x3-design/fluent-design@d334acf5cbad813f2b7cd554da942b09a7ff8f10. */ -export const INTERACTIVE_COLOR_TOKENS = [ - 'surfaceNeutralFarther', - 'surfaceNeutralFar', - 'surfaceNeutralNear', - 'surfaceNeutralNearer', - 'surfaceNeutralTranslucent', - 'backgroundNeutralHeavy', - 'backgroundNeutralLoud', - 'backgroundNeutralSoft', - 'backgroundNeutralSubtle', - 'backgroundNeutralTransparent', - 'backgroundNeutralTranslucent', - 'backgroundBrandHeavy', - 'backgroundBrandLoud', - 'backgroundBrandSoft', - 'backgroundBrandSubtle', - 'backgroundBrandTransparent', - 'backgroundDangerLoud', - 'backgroundDangerSoft', - 'backgroundDangerSubtle', - 'backgroundWarningLoud', - 'backgroundWarningSoft', - 'backgroundWarningSubtle', - 'backgroundSuccessLoud', - 'backgroundSuccessSoft', - 'backgroundSuccessSubtle', - 'strokeNeutralHeavy', - 'strokeNeutralLoud', - 'strokeNeutralSoft', - 'strokeNeutralSubtle', - 'strokeNeutralTransparent', - 'strokeNeutralOnloud', - 'strokeBrandLoud', - 'strokeBrandSoft', - 'strokeBrandSubtle', - 'strokeBrandOnloud', - 'strokeDangerLoud', - 'strokeDangerSoft', - 'strokeDangerSubtle', - 'strokeDangerOnloud', - 'strokeWarningLoud', - 'strokeWarningSoft', - 'strokeWarningSubtle', - 'strokeWarningOnloud', - 'strokeSuccessLoud', - 'strokeSuccessSoft', - 'strokeSuccessSubtle', - 'strokeSuccessOnloud', - 'foregroundNeutralPrimary', - 'foregroundNeutralSecondary', - 'foregroundNeutralTertiary', - 'foregroundNeutralOnloud', - 'foregroundBrandPrimary', - 'foregroundBrandOnloud', - 'foregroundDangerPrimary', - 'foregroundDangerOnloud', - 'foregroundWarningPrimary', - 'foregroundWarningOnloud', - 'foregroundSuccessPrimary', - 'foregroundSuccessOnloud', -] as const satisfies readonly InteractiveColorToken[]; - -/** Default interaction lightness and alpha shifts for each state and mode. */ export const INTERACTION_COLOR_DELTAS = { hover: { light: { lightness: -0.03, alpha: 0.04 }, @@ -97,28 +21,26 @@ export const INTERACTION_COLOR_DELTAS = { }, } as const; -/** Reference surfaces used to solve translucent Bebop Warm source colors. */ -export const BEBOP_WARM_REFERENCE_BACKDROP = { - light: '#ffffff', - dark: '#292929', -} as const; - /** - * Return whether a semantic interaction token shifts opposite the standard - * lightness direction. + * Reference surfaces, as 8-bit sRGB channels, that the warm transform uses to + * solve translucent colors: `#ffffff` in light mode and `#292929` in dark mode. */ -export function isInverseInteractionToken(token: InteractiveColorToken): boolean { - return /heavy|loud|onloud/i.test(token); -} +export const WARM_REFERENCE_BACKDROP = { + light: [255, 255, 255], + dark: [41, 41, 41], +} as const; function interactionCurveMultiplier(lightness: number): number { return clamp((0.5 - lightness) / 0.1, 1, 3); } -function defaultInteractionColor(color: RgbaColor, token: InteractiveColorToken, mode: ColorMode, state: InteractionColorState): string { +function isTranslucent(alpha: number): boolean { + return alpha > 1e-9 && alpha < 1 - 1e-9; +} + +function coolInteractionColor(color: RgbaColor, mode: ColorMode, state: InteractionColorState, inverse: boolean): string { const oklch = rgbToOklch(color); const delta = INTERACTION_COLOR_DELTAS[state][mode]; - const inverse = isInverseInteractionToken(token); const rgb = oklchToRgb({ ...oklch, L: clamp(oklch.L + (inverse ? -1 : 1) * delta.lightness * interactionCurveMultiplier(oklch.L)), @@ -169,23 +91,24 @@ function warmInteractionRgb(color: RgbColor, alpha: number, mode: ColorMode, sta return oklchToRgb({ L: clamp(nextLightness), C: C + chromaDelta, h }); } -function isTranslucentSurfaceToken(token: InteractiveColorToken, alpha: number): boolean { - return (token.startsWith('background') || token.startsWith('stroke')) && alpha > 1e-9 && alpha < 1 - 1e-9; -} - -function bebopWarmInteractionColor(color: RgbaColor, token: InteractiveColorToken, mode: ColorMode, state: InteractionColorState): string { - const inverse = isInverseInteractionToken(token); +function warmInteractionColor( + color: RgbaColor, + mode: ColorMode, + state: InteractionColorState, + inverse: boolean, + backdrop: boolean, +): string { const alpha = inverse ? color.a : clamp(color.a + INTERACTION_COLOR_DELTAS[state][mode].alpha); - if (isTranslucentSurfaceToken(token, color.a)) { + if (backdrop && isTranslucent(color.a)) { const source = [channelToByte(color.r), channelToByte(color.g), channelToByte(color.b)]; - const backdrop = mode === 'light' ? [255, 255, 255] : [41, 41, 41]; + const reference = WARM_REFERENCE_BACKDROP[mode]; const sourceAlpha = channelToByte(color.a); const targetAlpha = channelToByte(alpha); - const apparent = source.map((channel, index) => compositeChannel(channel, backdrop[index], sourceAlpha)); + const apparent = source.map((channel, index) => compositeChannel(channel, reference[index], sourceAlpha)); const shifted = warmInteractionRgb({ r: apparent[0] / 255, g: apparent[1] / 255, b: apparent[2] / 255 }, color.a, mode, state, inverse); const target = [channelToByte(shifted.r), channelToByte(shifted.g), channelToByte(shifted.b)]; - const solved = target.map((channel, index) => solveSourceChannel(channel, backdrop[index], targetAlpha)); + const solved = target.map((channel, index) => solveSourceChannel(channel, reference[index], targetAlpha)); return rgbaToHex({ r: solved[0] / 255, g: solved[1] / 255, b: solved[2] / 255, a: targetAlpha / 255 }); } @@ -196,12 +119,12 @@ function bebopWarmInteractionColor(color: RgbaColor, token: InteractiveColorToke } /** - * Generate one interaction-state color with either the default or Bebop Warm - * OKLCH algorithm. + * Generate one interaction-state color from a rest color with the cool or + * warm OKLCH algorithm. Colors JavaScript cannot resolve return a structured + * diagnostic instead of a fabricated value. */ export function getInteractionColor( colorValue: ColorValue, - token: InteractiveColorToken, mode: ColorMode, state: InteractionColorState, options: InteractionColorOptions = {}, @@ -213,98 +136,27 @@ export function getInteractionColor( value: colorValue, diagnostic: { ...parsed.diagnostic, - token, state, }, }; } + const inverse = options.direction === 'inverted'; return { status: 'derived', value: - options.variant === 'bebopWarm' - ? bebopWarmInteractionColor(parsed.color, token, mode, state) - : defaultInteractionColor(parsed.color, token, mode, state), + options.colorTone === 'warm' + ? warmInteractionColor(parsed.color, mode, state, inverse, options.compositing === 'backdrop') + : coolInteractionColor(parsed.color, mode, state, inverse), }; } -/** Generate a hover color from a semantic token's rest value. */ -export function getHoverColor( - colorValue: ColorValue, - token: InteractiveColorToken, - mode: ColorMode, - options?: InteractionColorOptions, -): InteractionColorResult { - return getInteractionColor(colorValue, token, mode, 'hover', options); -} - -/** Generate a pressed color from a semantic token's rest value. */ -export function getPressColor( - colorValue: ColorValue, - token: InteractiveColorToken, - mode: ColorMode, - options?: InteractionColorOptions, -): InteractionColorResult { - return getInteractionColor(colorValue, token, mode, 'pressed', options); -} - -/** - * Generate every interactive token override for one state and collect - * diagnostics for colors that JavaScript cannot resolve. - */ -export function getInteractionColorOverrides( - colors: SemanticColorTokenValues, - mode: ColorMode, - state: InteractionColorState, - options?: InteractionColorOptions, -): InteractionColorOverridesResult { - const overrides: InteractiveColorOverrides = {}; - const diagnostics: InteractionColorDiagnostic[] = []; - - for (const token of INTERACTIVE_COLOR_TOKENS) { - const result = getInteractionColor(colors[token], token, mode, state, options); - if (result.status === 'derived') { - overrides[token] = result.value; - } else { - diagnostics.push(result.diagnostic); - } - } - - return { overrides, diagnostics }; +/** Generate a hover color from a rest color. */ +export function getHoverColor(colorValue: ColorValue, mode: ColorMode, options?: InteractionColorOptions): InteractionColorResult { + return getInteractionColor(colorValue, mode, 'hover', options); } -/** - * Fill missing hover and pressed colors without replacing authored values. - * Callers should not apply this fallback to high-contrast themes. - */ -export function getInteractionColors( - colors: InteractionColorInput, - mode: ColorMode, - options?: InteractionColorOptions, -): InteractionColorsResult { - const hover: InteractiveColorOverrides = { ...colors.hover }; - const pressed: InteractiveColorOverrides = { ...colors.pressed }; - const diagnostics: InteractionColorDiagnostic[] = []; - let changed = colors.hover === undefined || colors.pressed === undefined; - - for (const state of ['hover', 'pressed'] as const) { - const overrides = state === 'hover' ? hover : pressed; - for (const token of INTERACTIVE_COLOR_TOKENS) { - if (overrides[token] !== undefined) { - continue; - } - const result = getInteractionColor(colors[token], token, mode, state, options); - if (result.status === 'derived') { - overrides[token] = result.value; - changed = true; - } else { - diagnostics.push(result.diagnostic); - } - } - } - - return { - colors: changed ? { ...colors, hover, pressed } : (colors as SemanticColors), - diagnostics, - }; +/** Generate a pressed color from a rest color. */ +export function getPressColor(colorValue: ColorValue, mode: ColorMode, options?: InteractionColorOptions): InteractionColorResult { + return getInteractionColor(colorValue, mode, 'pressed', options); } diff --git a/packages/agentic/design/src/color-lib/types.ts b/packages/agentic/design/src/color-lib/types.ts index 7dd69d7fe8..b275ee9390 100644 --- a/packages/agentic/design/src/color-lib/types.ts +++ b/packages/agentic/design/src/color-lib/types.ts @@ -1,7 +1,6 @@ import type { ColorValue } from 'react-native'; -import type { ThemeColorScheme } from '../types/appearance.types'; -import type { InteractiveColorOverrides, SemanticColors, SemanticColorTokenValues } from '../flex/tokens.types'; +import type { ColorTone, ThemeColorScheme } from '../types/appearance.types'; export type ColorDiagnosticReason = 'non-literal-color' | 'unsupported-color-format'; @@ -47,15 +46,31 @@ export interface ResolvedContrastColors { } export type InteractionColorState = 'hover' | 'pressed'; -export type InteractionColorVariant = 'default' | 'bebopWarm'; -export type InteractiveColorToken = keyof InteractiveColorOverrides; + +/** + * Lightness direction. Inverted colors shift opposite the standard direction + * for the scheme and keep their alpha. + */ +export type InteractionDirection = 'standard' | 'inverted'; + +/** + * How the warm transform treats a translucent color. `backdrop` composites it + * over the scheme's reference backdrop, shifts the apparent color, and solves + * a source color at the target alpha. `direct` shifts the channels in place. + * The cool transform always shifts directly. + */ +export type InteractionCompositing = 'direct' | 'backdrop'; export interface InteractionColorOptions { - readonly variant?: InteractionColorVariant; + /** Interaction algorithm tone. Defaults to cool. */ + readonly colorTone?: ColorTone; + /** Defaults to standard. */ + readonly direction?: InteractionDirection; + /** Defaults to direct. */ + readonly compositing?: InteractionCompositing; } export interface InteractionColorDiagnostic extends ColorDiagnostic { - readonly token: InteractiveColorToken; readonly state: InteractionColorState; } @@ -70,19 +85,4 @@ export type InteractionColorResult = readonly diagnostic: InteractionColorDiagnostic; }; -export interface InteractionColorOverridesResult { - readonly overrides: InteractiveColorOverrides; - readonly diagnostics: readonly InteractionColorDiagnostic[]; -} - -export type InteractionColorInput = SemanticColorTokenValues & { - readonly hover?: InteractiveColorOverrides; - readonly pressed?: InteractiveColorOverrides; -}; - -export interface InteractionColorsResult { - readonly colors: SemanticColors; - readonly diagnostics: readonly InteractionColorDiagnostic[]; -} - export type ColorMode = ThemeColorScheme; diff --git a/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts b/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts new file mode 100644 index 0000000000..798d425418 --- /dev/null +++ b/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts @@ -0,0 +1,184 @@ +import { PlatformColor } from 'react-native'; + +import { getInteractionColorOverrides } from '../../test/fixtures/interactionColors'; +import { + x3BebopWarmInteractionConformance, + x3InteractionConformance, + x3WarmToneDeviations, +} from '../../test/fixtures/x3InteractionConformance'; +import type { InteractionConformanceVector } from '../../test/fixtures/x3InteractionConformance'; +import type { ColorMode } from '../../color-lib/types'; +import type { ColorTone, NormalizedThemeAppearance } from '../../types/appearance.types'; +import { defaultFlexTokens } from '../defaults/defaultTokens'; +import type { SemanticColors, SemanticColorTokenValues } from '../tokens.types'; +import { deriveInteractionColor, withDerivedInteractionColors } from './interactionPolicy'; +import { + getInteractionCompositing, + getInteractionDirection, + INTERACTIVE_COLOR_TOKENS, + isInverseInteractionToken, +} from './interactiveTokens'; +import type { InteractiveColorToken } from './interactiveTokens'; + +const modeIndexes = { + light: { rest: 0, hover: 1, pressed: 2 }, + dark: { rest: 3, hover: 4, pressed: 5 }, +} as const; + +function appearance(colorScheme: ColorMode, colorTone: ColorTone = 'cool'): NormalizedThemeAppearance { + return { colorScheme, contrast: 'standard', interfaceLevel: 'base', colorTone }; +} + +function restColors( + mode: ColorMode, + conformance: Readonly> = x3InteractionConformance, +): SemanticColors { + const colors: SemanticColorTokenValues = { ...defaultFlexTokens.color }; + for (const token of INTERACTIVE_COLOR_TOKENS) { + colors[token] = conformance[token][modeIndexes[mode].rest]; + } + return { ...colors, hover: {}, pressed: {} }; +} + +describe('interactive token classification', () => { + it('classifies every inverse token with the upstream heavy/loud/onloud rule', () => { + const expected = [ + 'backgroundNeutralHeavy', + 'backgroundNeutralLoud', + 'backgroundBrandHeavy', + 'backgroundBrandLoud', + 'backgroundDangerLoud', + 'backgroundWarningLoud', + 'backgroundSuccessLoud', + 'strokeNeutralHeavy', + 'strokeNeutralLoud', + 'strokeNeutralOnloud', + 'strokeBrandLoud', + 'strokeBrandOnloud', + 'strokeDangerLoud', + 'strokeDangerOnloud', + 'strokeWarningLoud', + 'strokeWarningOnloud', + 'strokeSuccessLoud', + 'strokeSuccessOnloud', + 'foregroundNeutralOnloud', + 'foregroundBrandOnloud', + 'foregroundDangerOnloud', + 'foregroundWarningOnloud', + 'foregroundSuccessOnloud', + ]; + + expect(INTERACTIVE_COLOR_TOKENS.filter(isInverseInteractionToken)).toEqual(expected); + expect(INTERACTIVE_COLOR_TOKENS.filter((token) => getInteractionDirection(token) === 'inverted')).toEqual(expected); + expect(INTERACTIVE_COLOR_TOKENS).toHaveLength(59); + expect(Object.keys(x3WarmToneDeviations)).toHaveLength(10); + }); + + it('composites only background and stroke tokens against the warm backdrop', () => { + for (const token of INTERACTIVE_COLOR_TOKENS) { + const expected = token.startsWith('background') || token.startsWith('stroke') ? 'backdrop' : 'direct'; + expect([token, getInteractionCompositing(token)]).toEqual([token, expected]); + } + }); +}); + +describe.each(['light', 'dark'] as const)('%s Flex interaction policy', (mode) => { + it.each(INTERACTIVE_COLOR_TOKENS)('matches the cool and warm conformance values for %s', (token) => { + const vector = x3InteractionConformance[token]; + const warmVector = x3BebopWarmInteractionConformance[token]; + for (const state of ['hover', 'pressed'] as const) { + const deviationKey = `${token}.${state}.${mode}` as keyof typeof x3WarmToneDeviations; + const deviation = x3WarmToneDeviations[deviationKey]; + const upstreamValue = vector[modeIndexes[mode][state]]; + + expect(deriveInteractionColor(vector[modeIndexes[mode].rest], token, state, appearance(mode))).toBe( + deviation?.defaultValue ?? upstreamValue, + ); + expect(deriveInteractionColor(warmVector[modeIndexes[mode].rest], token, state, appearance(mode, 'warm'))).toBe( + warmVector[modeIndexes[mode][state]], + ); + if (deviation) { + expect(upstreamValue).toBe(deviation.warmValue); + } + } + }); + + it.each(['cool', 'warm'] as const)('derives a complete %s override map', (colorTone) => { + const conformance = colorTone === 'warm' ? x3BebopWarmInteractionConformance : x3InteractionConformance; + const result = getInteractionColorOverrides(restColors(mode, conformance), mode, 'hover', colorTone); + + expect(result.diagnostics).toEqual([]); + expect(Object.keys(result.overrides)).toHaveLength(59); + }); +}); + +describe('deriveInteractionColor', () => { + it('returns rest in high contrast', () => { + expect( + deriveInteractionColor('#ebebeb', 'surfaceNeutralFarther', 'hover', { ...appearance('light', 'warm'), contrast: 'highContrast' }), + ).toBe('#ebebeb'); + }); + + it('returns the same rest value when the engine cannot resolve it', () => { + const rest = PlatformColor('labelColor'); + + expect(deriveInteractionColor(rest, 'foregroundNeutralPrimary', 'pressed', appearance('dark'))).toBe(rest); + }); + + it('does not swallow unexpected engine failures', () => { + jest.isolateModules(() => { + jest.doMock('../../color-lib/interaction', () => ({ + getInteractionColor: () => { + throw new Error('engine failure'); + }, + })); + const policy = require('./interactionPolicy') as typeof import('./interactionPolicy'); + + expect(() => policy.deriveInteractionColor('#ebebeb', 'surfaceNeutralFarther', 'hover', appearance('light'))).toThrow( + 'engine failure', + ); + }); + }); +}); + +describe('withDerivedInteractionColors', () => { + it('fills omitted states without replacing authored values', () => { + const input = { ...restColors('light'), hover: { surfaceNeutralFarther: '#123456' } }; + const result = withDerivedInteractionColors(input, appearance('light')); + + expect(result).not.toBe(input); + expect(result.hover.surfaceNeutralFarther).toBe('#123456'); + expect(result.hover.surfaceNeutralFar).toBe('#e8e8e8'); + expect(result.pressed.surfaceNeutralFarther).toBe('#d7d7d7'); + expect(Object.keys(result.hover)).toHaveLength(59); + expect(Object.keys(result.pressed)).toHaveLength(59); + expect(input.hover).toEqual({ surfaceNeutralFarther: '#123456' }); + }); + + it('preserves identity when every interaction value is authored', () => { + const colors = restColors('light'); + const input = { + ...colors, + hover: getInteractionColorOverrides(colors, 'light', 'hover').overrides, + pressed: getInteractionColorOverrides(colors, 'light', 'pressed').overrides, + }; + + expect(withDerivedInteractionColors(input, appearance('light'))).toBe(input); + }); + + it('uses the appearance tone', () => { + const colors = restColors('light', x3BebopWarmInteractionConformance); + const result = withDerivedInteractionColors(colors, appearance('light', 'warm')); + + expect(result.hover.backgroundNeutralTranslucent).toBe(x3BebopWarmInteractionConformance.backgroundNeutralTranslucent[1]); + }); + + it('skips tokens without a rest value', () => { + const { surfaceNeutralFarther: _omitted, ...colors } = restColors('dark'); + const result = withDerivedInteractionColors(colors as SemanticColors, appearance('dark')); + + expect(result.hover).not.toHaveProperty('surfaceNeutralFarther'); + expect(result.pressed).not.toHaveProperty('surfaceNeutralFarther'); + expect(Object.keys(result.hover)).toHaveLength(58); + }); +}); diff --git a/packages/agentic/design/src/flex/colors/interactionPolicy.ts b/packages/agentic/design/src/flex/colors/interactionPolicy.ts new file mode 100644 index 0000000000..861c4ebe94 --- /dev/null +++ b/packages/agentic/design/src/flex/colors/interactionPolicy.ts @@ -0,0 +1,57 @@ +import type { ColorValue } from 'react-native'; + +import { getInteractionColor } from '../../color-lib/interaction'; +import type { InteractionColorState } from '../../color-lib/types'; +import type { NormalizedThemeAppearance } from '../../types/appearance.types'; +import type { InteractiveColorOverrides, SemanticColors } from '../tokens.types'; +import { getInteractionCompositing, getInteractionDirection, INTERACTIVE_COLOR_TOKENS } from './interactiveTokens'; +import type { InteractiveColorToken } from './interactiveTokens'; + +/** + * Resolve an omitted interaction state for one Flex token from its rest value. + * High contrast and rest values the raw engine cannot map, such as native + * platform colors, resolve to the rest value itself. + */ +export function deriveInteractionColor( + rest: ColorValue, + token: InteractiveColorToken, + state: InteractionColorState, + appearance: Readonly, +): ColorValue { + if (appearance.contrast === 'highContrast') { + return rest; + } + + const result = getInteractionColor(rest, appearance.colorScheme, state, { + colorTone: appearance.colorTone, + direction: getInteractionDirection(token), + compositing: getInteractionCompositing(token), + }); + return result.status === 'derived' ? result.value : rest; +} + +/** + * Fill each omitted hover and pressed value for the interactive tokens while + * keeping authored values. Returns the input when nothing is omitted. + */ +export function withDerivedInteractionColors(colors: SemanticColors, appearance: Readonly): SemanticColors { + let hover: InteractiveColorOverrides | undefined; + let pressed: InteractiveColorOverrides | undefined; + + for (const token of INTERACTIVE_COLOR_TOKENS) { + const rest = colors[token]; + if (rest === undefined) { + continue; + } + if (colors.hover?.[token] === undefined) { + hover ??= { ...colors.hover }; + hover[token] = deriveInteractionColor(rest, token, 'hover', appearance); + } + if (colors.pressed?.[token] === undefined) { + pressed ??= { ...colors.pressed }; + pressed[token] = deriveInteractionColor(rest, token, 'pressed', appearance); + } + } + + return hover || pressed ? { ...colors, hover: hover ?? colors.hover, pressed: pressed ?? colors.pressed } : colors; +} diff --git a/packages/agentic/design/src/flex/colors/interactiveTokens.ts b/packages/agentic/design/src/flex/colors/interactiveTokens.ts new file mode 100644 index 0000000000..8f2e9fe4d0 --- /dev/null +++ b/packages/agentic/design/src/flex/colors/interactiveTokens.ts @@ -0,0 +1,94 @@ +import type { InteractionCompositing, InteractionDirection } from '../../color-lib/types'; +import type { InteractiveColorOverrides } from '../tokens.types'; + +/** A Flex semantic color token that has hover and pressed states. */ +export type InteractiveColorToken = keyof InteractiveColorOverrides; + +/** + * Interactive subset of the Flex semantic color tokens. + * + * Source: x3-design/fluent-design@d334acf5cbad813f2b7cd554da942b09a7ff8f10. + */ +export const INTERACTIVE_COLOR_TOKENS = [ + 'surfaceNeutralFarther', + 'surfaceNeutralFar', + 'surfaceNeutralNear', + 'surfaceNeutralNearer', + 'surfaceNeutralTranslucent', + 'backgroundNeutralHeavy', + 'backgroundNeutralLoud', + 'backgroundNeutralSoft', + 'backgroundNeutralSubtle', + 'backgroundNeutralTransparent', + 'backgroundNeutralTranslucent', + 'backgroundBrandHeavy', + 'backgroundBrandLoud', + 'backgroundBrandSoft', + 'backgroundBrandSubtle', + 'backgroundBrandTransparent', + 'backgroundDangerLoud', + 'backgroundDangerSoft', + 'backgroundDangerSubtle', + 'backgroundWarningLoud', + 'backgroundWarningSoft', + 'backgroundWarningSubtle', + 'backgroundSuccessLoud', + 'backgroundSuccessSoft', + 'backgroundSuccessSubtle', + 'strokeNeutralHeavy', + 'strokeNeutralLoud', + 'strokeNeutralSoft', + 'strokeNeutralSubtle', + 'strokeNeutralTransparent', + 'strokeNeutralOnloud', + 'strokeBrandLoud', + 'strokeBrandSoft', + 'strokeBrandSubtle', + 'strokeBrandOnloud', + 'strokeDangerLoud', + 'strokeDangerSoft', + 'strokeDangerSubtle', + 'strokeDangerOnloud', + 'strokeWarningLoud', + 'strokeWarningSoft', + 'strokeWarningSubtle', + 'strokeWarningOnloud', + 'strokeSuccessLoud', + 'strokeSuccessSoft', + 'strokeSuccessSubtle', + 'strokeSuccessOnloud', + 'foregroundNeutralPrimary', + 'foregroundNeutralSecondary', + 'foregroundNeutralTertiary', + 'foregroundNeutralOnloud', + 'foregroundBrandPrimary', + 'foregroundBrandOnloud', + 'foregroundDangerPrimary', + 'foregroundDangerOnloud', + 'foregroundWarningPrimary', + 'foregroundWarningOnloud', + 'foregroundSuccessPrimary', + 'foregroundSuccessOnloud', +] as const satisfies readonly InteractiveColorToken[]; + +/** + * Return whether an interactive token shifts opposite the standard lightness + * direction. Heavy, loud, and on-loud roles are inverted. + */ +export function isInverseInteractionToken(token: InteractiveColorToken): boolean { + const name = token.toLowerCase(); + return name.includes('heavy') || name.includes('loud'); +} + +/** The raw interaction direction for an interactive token. */ +export function getInteractionDirection(token: InteractiveColorToken): InteractionDirection { + return isInverseInteractionToken(token) ? 'inverted' : 'standard'; +} + +/** + * The raw compositing intent for an interactive token. Translucent backgrounds + * and strokes are solved against the reference backdrop. + */ +export function getInteractionCompositing(token: InteractiveColorToken): InteractionCompositing { + return token.startsWith('background') || token.startsWith('stroke') ? 'backdrop' : 'direct'; +} diff --git a/packages/agentic/design/src/flex/flexThemeReference.test.ts b/packages/agentic/design/src/flex/flexThemeReference.test.ts index 639255a68b..8aa94dfe77 100644 --- a/packages/agentic/design/src/flex/flexThemeReference.test.ts +++ b/packages/agentic/design/src/flex/flexThemeReference.test.ts @@ -1,5 +1,10 @@ +import { PlatformColor } from 'react-native'; +import type { ColorValue } from 'react-native'; + import { defaultResolvedThemeAppearance } from '../theming/appearance'; +import { defaultFlexTokens } from './defaults/defaultTokens'; import { FlexThemeReference } from './flexThemeReference'; +import type { PartialFlexTokens } from './flexThemeReference'; const darkAppearance = { colorScheme: 'dark', @@ -82,3 +87,88 @@ describe('FlexThemeReference', () => { expect(child.resolveFlexTokens(defaultResolvedThemeAppearance)).not.toBe(initial); }); }); + +describe('FlexThemeReference color tone', () => { + const lightAppearance = { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base' } as const; + + it('passes a concrete tone to bases and recipes and keys warm separately', () => { + const tones: string[] = []; + const reference = new FlexThemeReference( + { + base: (appearance) => { + tones.push(`base:${appearance.colorTone}`); + return {}; + }, + }, + (_tokens, appearance) => { + tones.push(`recipe:${appearance.colorTone}`); + return {}; + }, + ); + const omitted = reference.resolveFlexTokens(lightAppearance); + + expect(reference.resolveFlexTokens({ ...lightAppearance, colorTone: 'cool' })).toBe(omitted); + expect(reference.resolveFlexTokens({ ...lightAppearance, colorTone: 'warm' })).not.toBe(omitted); + expect(tones).toEqual(['base:cool', 'recipe:cool', 'base:warm', 'recipe:warm']); + }); + + it('keeps the complete default interaction values for every tone', () => { + const reference = new FlexThemeReference(); + + for (const colorTone of ['cool', 'warm'] as const) { + for (const colorScheme of ['light', 'dark'] as const) { + const tokens = reference.resolveFlexTokens({ ...lightAppearance, colorScheme, colorTone }); + expect(tokens.color).toBe(defaultFlexTokens.color); + } + } + }); +}); + +describe('FlexThemeReference interaction derivation', () => { + const omitInteraction = (rest: ColorValue) => + ({ + color: { + backgroundNeutralTranslucent: rest, + hover: { backgroundNeutralTranslucent: undefined }, + pressed: { backgroundNeutralTranslucent: undefined }, + }, + }) as PartialFlexTokens; + + it('derives omitted states from rest with the appearance tone', () => { + const reference = new FlexThemeReference({}, omitInteraction('#e9e9e980')); + const cool = reference.resolveFlexTokens(defaultResolvedThemeAppearance).color; + const warm = reference.resolveFlexTokens({ ...defaultResolvedThemeAppearance, colorTone: 'warm' }).color; + + expect(cool.hover.backgroundNeutralTranslucent).toBe('#dfdfdf8a'); + expect(cool.pressed.backgroundNeutralTranslucent).toBe('#d5d5d594'); + expect(warm.hover.backgroundNeutralTranslucent).toBe('#dcdcd68a'); + expect(warm.pressed.backgroundNeutralTranslucent).toBe('#d2cfc894'); + }); + + it('keeps authored interaction values', () => { + const reference = new FlexThemeReference({}, omitInteraction('#e9e9e980'), { + color: { hover: { backgroundNeutralTranslucent: '#123456' } }, + }); + const colors = reference.resolveFlexTokens(defaultResolvedThemeAppearance).color; + + expect(colors.hover.backgroundNeutralTranslucent).toBe('#123456'); + expect(colors.pressed.backgroundNeutralTranslucent).toBe('#d5d5d594'); + }); + + it('falls back to the same rest value when it cannot be derived', () => { + const rest = PlatformColor('windowBackgroundColor'); + const reference = new FlexThemeReference({}, omitInteraction(rest)); + const colors = reference.resolveFlexTokens({ ...defaultResolvedThemeAppearance, colorTone: 'warm' }).color; + + expect(colors.hover.backgroundNeutralTranslucent).toBe(rest); + expect(colors.pressed.backgroundNeutralTranslucent).toBe(rest); + }); + + it('uses rest in high contrast', () => { + const reference = new FlexThemeReference({}, omitInteraction('#e9e9e980')); + const colors = reference.resolveFlexTokens({ ...defaultResolvedThemeAppearance, contrast: 'highContrast' }).color; + + expect(colors.hover.backgroundNeutralTranslucent).toBe('#e9e9e980'); + expect(colors.pressed.backgroundNeutralTranslucent).toBe('#e9e9e980'); + }); +}); diff --git a/packages/agentic/design/src/flex/flexThemeReference.ts b/packages/agentic/design/src/flex/flexThemeReference.ts index 11271966ab..fd9ae6b021 100644 --- a/packages/agentic/design/src/flex/flexThemeReference.ts +++ b/packages/agentic/design/src/flex/flexThemeReference.ts @@ -14,8 +14,14 @@ import type { SemanticSpacing, SemanticStrokeWidths, } from './tokens.types'; -import { themeAppearanceKey } from '../theming/appearance'; -import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceSource } from '../types/appearance.types'; +import { withDerivedInteractionColors } from './colors/interactionPolicy'; +import { internResolvedThemeAppearance, themeAppearanceKey } from '../theming/appearance'; +import type { + NormalizedThemeAppearance, + ResolvedThemeAppearance, + ThemeAppearanceOptions, + ThemeAppearanceSource, +} from '../types/appearance.types'; import type { FlexThemeSource, OnThemeChange } from '../theming/themeSource'; import type { PartialTheme, Theme } from '../fluent/types/Theme.types'; @@ -34,11 +40,16 @@ export type PartialFlexTokens = { strokeWidth?: Partial; }; -export type FlexThemeInput = FlexTokens | PartialFlexTokens | ((appearance: ResolvedThemeAppearance) => FlexTokens | PartialFlexTokens); +export type FlexThemeInput = + | FlexTokens + | PartialFlexTokens + | ((appearance: Readonly) => FlexTokens | PartialFlexTokens); -export type FlexThemeRecipe = PartialFlexTokens | ((parent: FlexTokens, appearance: ResolvedThemeAppearance) => PartialFlexTokens); +export type FlexThemeRecipe = + | PartialFlexTokens + | ((parent: FlexTokens, appearance: Readonly) => PartialFlexTokens); -export type LegacyThemeFallback = Theme | PartialTheme | ((appearance: ResolvedThemeAppearance) => Theme | PartialTheme); +export type LegacyThemeFallback = Theme | PartialTheme | ((appearance: Readonly) => Theme | PartialTheme); export interface FlexThemeReferenceOptions { base?: FlexThemeInput | FlexThemeReference; @@ -79,8 +90,13 @@ export class FlexThemeReference implements FlexThemeSource { return this.revisionValue; } - public resolveFlexTokens(appearance: ResolvedThemeAppearance): FlexTokens { + /** + * Resolve the tokens for one appearance. A missing tone means cool. Omitted + * interactive hover and pressed values are derived from rest automatically. + */ + public resolveFlexTokens(requestedAppearance: ResolvedThemeAppearance): FlexTokens { this.syncParentRevision(); + const appearance = internResolvedThemeAppearance(requestedAppearance); const key = themeAppearanceKey(appearance); const cached = this.tokensByAppearance.get(key); if (cached) { @@ -91,12 +107,13 @@ export class FlexThemeReference implements FlexThemeSource { for (const recipe of this.recipes) { tokens = immutableMerge(tokens, typeof recipe === 'function' ? recipe(tokens, appearance) : recipe); } - tokens = { ...tokens }; + tokens = { ...tokens, color: withDerivedInteractionColors(tokens.color, appearance) }; this.tokensByAppearance.set(key, tokens); return tokens; } - public resolveLegacyFallback(appearance: ResolvedThemeAppearance): Theme | PartialTheme | undefined { + public resolveLegacyFallback(requestedAppearance: ResolvedThemeAppearance): Theme | PartialTheme | undefined { + const appearance = internResolvedThemeAppearance(requestedAppearance); const parentFallback = this.base instanceof FlexThemeReference ? this.base.resolveLegacyFallback(appearance) : undefined; const fallback = typeof this.legacyFallback === 'function' ? this.legacyFallback(appearance) : this.legacyFallback; return parentFallback && fallback ? immutableMerge(parentFallback, fallback) : (fallback ?? parentFallback); @@ -134,7 +151,7 @@ export class FlexThemeReference implements FlexThemeSource { this.invalidate(); } - private resolveBase(appearance: ResolvedThemeAppearance): FlexTokens { + private resolveBase(appearance: Readonly): FlexTokens { if (this.base instanceof FlexThemeReference) { return this.base.resolveFlexTokens(appearance); } diff --git a/packages/agentic/design/src/flex/themeState.ts b/packages/agentic/design/src/flex/themeState.ts new file mode 100644 index 0000000000..5ac9463b38 --- /dev/null +++ b/packages/agentic/design/src/flex/themeState.ts @@ -0,0 +1,47 @@ +import { defaultFlexTokens } from './defaults/defaultTokens'; +import { flexTokensFromTheme } from './adapters/flexTokensFromTheme'; +import type { FlexTokens } from './tokens.types'; +import { defaultResolvedThemeAppearance } from '../theming/appearance'; +import { getFlexSourceTokens, getThemeAppearanceCache } from '../theming/themeRuntime'; +import type { ThemeSource } from '../theming/themeSource'; +import type { NormalizedThemeAppearance } from '../types/appearance.types'; +import type { ThemeState } from '../types/themeState.types'; + +export const defaultThemeState: ThemeState = { + tokens: defaultFlexTokens, + appearance: defaultResolvedThemeAppearance, + highContrast: false, + themeStyles: {}, +}; + +/** + * Resolve Flex tokens for any source. Legacy sources use the forward adapter. + */ +export function getFlexTokens(source: ThemeSource, appearance: Readonly): FlexTokens { + if (source.kind === 'flex') { + return getFlexSourceTokens(source, appearance); + } + + const cache = getThemeAppearanceCache(source, appearance); + if (!cache.flexTokens) { + cache.flexTokens = flexTokensFromTheme(source.resolveTheme(appearance)); + } + return cache.flexTokens; +} + +/** + * Return the shared theme state for one source revision and resolved + * appearance. Every new state owns a fresh style registry. + */ +export function getThemeState(source: ThemeSource, appearance: Readonly): ThemeState { + const cache = getThemeAppearanceCache(source, appearance); + if (!cache.themeState) { + cache.themeState = { + tokens: getFlexTokens(source, appearance), + appearance, + highContrast: appearance.contrast === 'highContrast', + themeStyles: {}, + }; + } + return cache.themeState; +} diff --git a/packages/agentic/design/src/flex/useThemeState.test.ts b/packages/agentic/design/src/flex/useThemeState.test.ts index 303c6b27b4..a2f276c81c 100644 --- a/packages/agentic/design/src/flex/useThemeState.test.ts +++ b/packages/agentic/design/src/flex/useThemeState.test.ts @@ -154,6 +154,7 @@ describe('useThemeState', () => { expect(states[0].tokens.color.backgroundNeutralSubtle).toBe('#123456'); expect(states[0].highContrast).toBe(true); expect(states[0].appearance.contrast).toBe('highContrast'); + expect(states[0].appearance.colorTone).toBe('cool'); expect(Object.getOwnPropertySymbols(theme)).toEqual(initialSymbols); @@ -280,6 +281,42 @@ describe('useThemeState', () => { act(() => component!.unmount()); }); + it('keys ThemeState and theme styles by color tone', () => { + const reference = new FlexThemeReference(); + const states: ThemeState[] = []; + const render = (colorTone: 'cool' | 'warm') => + React.createElement( + ThemeProvider, + { theme: reference, appearanceSource: lightAppearanceSource, appearance: { colorTone } }, + React.createElement(ThemeStateProbe, { states }), + ); + let createCount = 0; + const getStyles = themedStyleSheetFactory('test.tone', ({ appearance }) => { + createCount += 1; + return { root: { opacity: appearance.colorTone === 'warm' ? 0.5 : 1 } }; + }); + let component: ReactTestRenderer; + + act(() => { + component = create(render('cool')); + }); + const coolState = states.at(-1)!; + act(() => component!.update(render('warm'))); + const warmState = states.at(-1)!; + + expect(warmState).not.toBe(coolState); + expect(warmState.appearance).toMatchObject({ colorScheme: 'light', colorTone: 'warm' }); + expect(warmState.themeStyles).not.toBe(coolState.themeStyles); + expect(getStyles(coolState).root.opacity).toBe(1); + expect(getStyles(warmState).root.opacity).toBe(0.5); + + act(() => component!.update(render('cool'))); + expect(states.at(-1)).toBe(coolState); + expect(getStyles(coolState).root.opacity).toBe(1); + expect(createCount).toBe(2); + act(() => component!.unmount()); + }); + it('replaces ThemeState after source invalidation', () => { const reference = new FlexThemeReference(); const states: ThemeState[] = []; diff --git a/packages/agentic/design/src/flex/useThemeState.ts b/packages/agentic/design/src/flex/useThemeState.ts index e11994663b..b9f3a5e169 100644 --- a/packages/agentic/design/src/flex/useThemeState.ts +++ b/packages/agentic/design/src/flex/useThemeState.ts @@ -2,7 +2,7 @@ import type { ImageStyle, TextStyle, ViewStyle } from 'react-native'; import { defaultThemeAppearanceState } from '../theming/appearance'; import { useThemeBoundary } from '../theming/context'; -import { defaultThemeState, getThemeState } from '../theming/themeRuntime'; +import { defaultThemeState, getThemeState } from './themeState'; import type { ThemeAppearanceState } from '../types/appearance.types'; import type { ThemeState } from '../types/themeState.types'; diff --git a/packages/agentic/design/src/fluent/__tests__/themeReference.test.ts b/packages/agentic/design/src/fluent/__tests__/themeReference.test.ts index d4a7e4d6fe..6fd484ba7f 100644 --- a/packages/agentic/design/src/fluent/__tests__/themeReference.test.ts +++ b/packages/agentic/design/src/fluent/__tests__/themeReference.test.ts @@ -42,6 +42,23 @@ describe('ThemeReference tests', () => { expect(themeRef.resolveTheme(defaultResolvedThemeAppearance)).not.toBe(before); }); + it('passes a concrete color tone to transforms and keys warm separately', () => { + const tones: unknown[] = []; + const themeRef = new ThemeReference(themeBase, (_theme, appearance) => { + tones.push(appearance?.colorTone); + return { colors: { white: appearance?.colorTone === 'warm' ? 'peach' : 'white' } }; + }); + const threeField = { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base' } as const; + const omitted = themeRef.resolveTheme(threeField); + + expect(themeRef.resolveTheme({ ...threeField, colorTone: 'cool' })).toBe(omitted); + const warm = themeRef.resolveTheme({ ...threeField, colorTone: 'warm' }); + expect(warm).not.toBe(omitted); + expect(warm.colors.white).toBe('peach'); + expect(omitted.colors.white).toBe('white'); + expect(tones).toEqual(['cool', 'warm']); + }); + it('performs a simple merge', () => { const themeRef = new ThemeReference(themeBase, { colors: { diff --git a/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.test.ts b/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.test.ts index 8a9170165f..890d5431f0 100644 --- a/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.test.ts +++ b/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.test.ts @@ -22,6 +22,13 @@ const highContrast = { } as const; describe('getDefaultLegacyTheme', () => { + it('shares one legacy base across color tones', () => { + const lightTheme = getDefaultLegacyTheme(light); + + expect(getDefaultLegacyTheme({ ...light, colorTone: 'cool' })).toBe(lightTheme); + expect(getDefaultLegacyTheme({ ...light, colorTone: 'warm' })).toBe(lightTheme); + }); + it('creates complete stable legacy bases lazily per resolved appearance', () => { const lightTheme = getDefaultLegacyTheme(light); const darkTheme = getDefaultLegacyTheme(dark); diff --git a/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts b/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts index 334d1f7cbc..3a04d029e5 100644 --- a/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts +++ b/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts @@ -2,7 +2,7 @@ import { Platform } from 'react-native'; import { fontWeightRegular, fontWeightSemibold } from '../../tokens/global.generated'; import globalTokens from '../tokens/tokens-global'; -import { appearanceOptionFromResolved, themeAppearanceKey } from '../../theming/appearance'; +import { appearanceOptionFromResolved, legacyThemeAppearanceKey } from '../../theming/appearance'; import type { ResolvedThemeAppearance } from '../../types/appearance.types'; import type { Theme, Spacing } from '../types/Theme.types'; import type { FontSize, FontSizes, FontWeightValue, Typography, Variants } from '../types/Typography.types'; @@ -104,10 +104,11 @@ function getDefaultSpacing(): Spacing { /** * Returns a complete legacy Theme without constructing any other appearance. * The result is stable for one resolved appearance and safe to use as an - * immutable base for Flex-to-legacy projection. + * immutable base for Flex-to-legacy projection. Legacy themes do not vary by + * tone, so every tone shares one Theme identity. */ export function getDefaultLegacyTheme(appearance: ResolvedThemeAppearance): Theme { - const key = themeAppearanceKey(appearance); + const key = legacyThemeAppearanceKey(appearance); const cached = defaultThemes.get(key); if (cached) { return cached; diff --git a/packages/agentic/design/src/fluent/themeReference.ts b/packages/agentic/design/src/fluent/themeReference.ts index c54b26212c..0a06578a57 100644 --- a/packages/agentic/design/src/fluent/themeReference.ts +++ b/packages/agentic/design/src/fluent/themeReference.ts @@ -1,6 +1,11 @@ import type { PartialTheme, Theme } from './types/Theme.types'; -import { appearanceOptionsFromLegacy, resolveThemeAppearance, themeAppearanceKey } from '../theming/appearance'; +import { + appearanceOptionsFromLegacy, + internResolvedThemeAppearance, + resolveThemeAppearance, + themeAppearanceKey, +} from '../theming/appearance'; import type { ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceSource } from '../types/appearance.types'; import { mergeTheme } from './mergeTheme'; import { platformAppearance } from '../theming/platformAppearance'; @@ -143,10 +148,12 @@ export class ThemeReference { expect(getUnresolvableContrastPairs(results)).toEqual([]); }); - it.each(['default', 'bebopWarm'] as const)('audits %s interaction values', (variant) => { + it.each(['cool', 'warm'] as const)('audits %s interaction values', (colorTone) => { for (const state of ['hover', 'pressed'] as const) { - const failures = getContrastFailures(validateContrastPairs(interactionConformanceColors(mode, state, variant), mode)).map( + const failures = getContrastFailures(validateContrastPairs(interactionConformanceColors(mode, state, colorTone), mode)).map( (result) => `${result.foreground.token}/${result.background.token}`, ); const expectedFailures = - mode === 'dark' && variant === 'bebopWarm' && state === 'pressed' + mode === 'dark' && colorTone === 'warm' && state === 'pressed' ? [ 'foregroundDangerPrimary/surfaceNeutralNearer', 'foregroundDangerPrimary/backgroundDangerSubtle', diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap index f6133d3c0d..0c6aa3b1bc 100644 --- a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap @@ -3,6 +3,7 @@ exports[`public entry points . keeps its runtime export names 1`] = ` [ "FlexThemeReference: function", + "INTERACTIVE_COLOR_TOKENS: object", "RootContext: object", "RootInputBoundary: object", "ThemeProvider: function", @@ -11,6 +12,7 @@ exports[`public entry points . keeps its runtime export names 1`] = ` "flexTokensFromTheme: function", "fontSize: function", "fontWeight: function", + "isInverseInteractionToken: function", "normalizeThemeAppearanceRequest: function", "resolveThemeAppearance: function", "themedStyleSheetFactory: function", @@ -29,7 +31,6 @@ exports[`public entry points ./color-lib keeps its runtime export names 1`] = ` "getHoverColor: function", "getInteractionColor: function", "getPressColor: function", - "isInverseInteractionToken: function", "oklchToRgb: function", "parseColorValue: function", "resolveContrastColors: function", diff --git a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts index 0e75eb6143..eb1b5b057b 100644 --- a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts +++ b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts @@ -166,11 +166,28 @@ describe('runtime graph ownership', () => { expect(rootGraph).toContain('flex/useThemeState.ts'); expect(rootGraph).toContain('flex/flexThemeReference.ts'); expect(rootGraph).toContain('flex/adapters/flexTokensFromTheme.ts'); + expect(rootGraph).toContain('flex/colors/interactionPolicy.ts'); + expect(rootGraph).toContain('color-lib/interaction.ts'); expect(rootGraph).toContain('theming/ThemeProvider.tsx'); expect(reachedUnder(rootGraph, 'fluent/')).toEqual([]); expect(reachedUnder(rootGraph, 'test/')).toEqual([]); }); + it('keeps legacy theme runtime free of the Flex engine and color library', () => { + for (const entry of ['fluent/useTheme.ts', 'fluent/themeReference.ts', 'theming/ThemeProvider.tsx']) { + const graph = runtimeGraph(entry); + expect([entry, reachedUnder(graph, 'flex/')]).toEqual([entry, []]); + expect([entry, reachedUnder(graph, 'color-lib/')]).toEqual([entry, []]); + } + expect(runtimeGraph('theming/ThemedRoot.tsx')).toContain('flex/colors/interactionPolicy.ts'); + }); + + it('keeps the color library free of token, theme, and test ownership', () => { + const colorLibGraph = runtimeGraph('color-lib/index.ts'); + expect(colorLibGraph).toContain('color-lib/interaction.ts'); + expect([...colorLibGraph].filter((file) => !file.startsWith('color-lib/')).sort()).toEqual([]); + }); + it('keeps the shared styling entry free of legacy Fluent runtime', () => { const stylingGraph = runtimeGraph('styling/index.ts'); expect(stylingGraph).toContain('flex/styling/colorStyles.ts'); diff --git a/packages/agentic/design/src/test/fixtures/interactionColors.ts b/packages/agentic/design/src/test/fixtures/interactionColors.ts new file mode 100644 index 0000000000..b20d882158 --- /dev/null +++ b/packages/agentic/design/src/test/fixtures/interactionColors.ts @@ -0,0 +1,45 @@ +import { getInteractionColor } from '../../color-lib/interaction'; +import type { ColorMode, InteractionColorDiagnostic, InteractionColorState } from '../../color-lib/types'; +import { getInteractionCompositing, getInteractionDirection, INTERACTIVE_COLOR_TOKENS } from '../../flex/colors/interactiveTokens'; +import type { InteractiveColorToken } from '../../flex/colors/interactiveTokens'; +import type { InteractiveColorOverrides, SemanticColorTokenValues } from '../../flex/tokens.types'; +import type { ColorTone } from '../../types/appearance.types'; + +export interface InteractionAuditDiagnostic extends InteractionColorDiagnostic { + readonly token: InteractiveColorToken; +} + +export interface InteractionOverridesResult { + readonly overrides: InteractiveColorOverrides; + readonly diagnostics: readonly InteractionAuditDiagnostic[]; +} + +/** + * Test-only bulk generation of one interaction state for every interactive + * token. Unlike the Flex runtime policy, unresolvable rest values are reported + * for audits instead of falling back to rest. + */ +export function getInteractionColorOverrides( + colors: SemanticColorTokenValues, + mode: ColorMode, + state: InteractionColorState, + colorTone: ColorTone = 'cool', +): InteractionOverridesResult { + const overrides: InteractiveColorOverrides = {}; + const diagnostics: InteractionAuditDiagnostic[] = []; + + for (const token of INTERACTIVE_COLOR_TOKENS) { + const result = getInteractionColor(colors[token], mode, state, { + colorTone, + direction: getInteractionDirection(token), + compositing: getInteractionCompositing(token), + }); + if (result.status === 'derived') { + overrides[token] = result.value; + } else { + diagnostics.push({ ...result.diagnostic, token }); + } + } + + return { overrides, diagnostics }; +} diff --git a/packages/agentic/design/src/test/fixtures/x3InteractionConformance.ts b/packages/agentic/design/src/test/fixtures/x3InteractionConformance.ts index 71cb11f9ce..993ccea819 100644 --- a/packages/agentic/design/src/test/fixtures/x3InteractionConformance.ts +++ b/packages/agentic/design/src/test/fixtures/x3InteractionConformance.ts @@ -1,4 +1,4 @@ -import type { InteractiveColorToken } from '../../color-lib'; +import type { InteractiveColorToken } from '../../flex/colors/interactiveTokens'; export type InteractionConformanceVector = readonly [ lightRest: string, @@ -140,11 +140,10 @@ export const x3BebopWarmInteractionConformance = { /** * The generated x3 table routes these entries through its separately scoped - * Bebop Warm path. `defaultValue` is the result of the default algorithm - * requested by #4268; `warmValue` is retained to make every table deviation - * explicit. + * Bebop Warm path. `defaultValue` is the result of the cool tone requested by + * #4268; `warmValue` is retained to make every table deviation explicit. */ -export const x3WarmVariantDeviations = { +export const x3WarmToneDeviations = { 'backgroundNeutralTranslucent.hover.light': { warmValue: '#d8d8d88a', defaultValue: '#dfdfdf8a', diff --git a/packages/agentic/design/src/theming/ThemedRoot.test.tsx b/packages/agentic/design/src/theming/ThemedRoot.test.tsx index be5854d2c5..e4bec4d363 100644 --- a/packages/agentic/design/src/theming/ThemedRoot.test.tsx +++ b/packages/agentic/design/src/theming/ThemedRoot.test.tsx @@ -265,7 +265,12 @@ describe('ThemedRoot', () => { , ); expect(nestedThemes[0].tokens.color.backgroundBrandHeavy).toBe('#111111'); - expect(nestedThemes[0].appearance).toEqual({ colorScheme: 'dark', contrast: 'highContrast', interfaceLevel: 'elevated' }); + expect(nestedThemes[0].appearance).toEqual({ + colorScheme: 'dark', + contrast: 'highContrast', + interfaceLevel: 'elevated', + colorTone: 'cool', + }); expect(parentThemes[0].appearance.interfaceLevel).toBe('base'); act(() => theme.update({ spacing: { componentBase100: 21 } })); expect(nestedThemes[nestedThemes.length - 1].tokens.spacing.componentBase100).toBe(21); @@ -287,13 +292,84 @@ describe('ThemedRoot', () => { , ); - expect(themes[0].appearance).toEqual({ colorScheme: 'dark', contrast: 'highContrast', interfaceLevel: 'elevated' }); + expect(themes[0].appearance).toEqual({ colorScheme: 'dark', contrast: 'highContrast', interfaceLevel: 'elevated', colorTone: 'cool' }); act(() => appearance.update({ colorScheme: 'light', contrast: 'standard' })); - expect(themes[themes.length - 1].appearance).toEqual({ colorScheme: 'light', contrast: 'standard', interfaceLevel: 'elevated' }); + expect(themes[themes.length - 1].appearance).toEqual({ + colorScheme: 'light', + contrast: 'standard', + interfaceLevel: 'elevated', + colorTone: 'cool', + }); act(() => component!.unmount()); expect(appearance.listeners.size).toBe(0); }); + it('inherits an explicit color tone through nested roots', () => { + const outer: ThemeState[] = []; + const inherited: ThemeState[] = []; + const overridden: ThemeState[] = []; + render( + + + + + + + + + + + , + ); + expect(outer[0].appearance.colorTone).toBe('warm'); + expect(inherited[0].appearance).toMatchObject({ colorScheme: 'dark', colorTone: 'warm' }); + expect(overridden[0].appearance).toMatchObject({ colorScheme: 'dark', colorTone: 'cool' }); + }); + + it('resolves tone from the provider, then the source, then the fallback, then cool', () => { + const fromProvider: ThemeState[] = []; + const fromSource: ThemeState[] = []; + const fromFallback: ThemeState[] = []; + const fromRootFallback: ThemeState[] = []; + const fromDefault: ThemeState[] = []; + const sourceWarm = new FlexThemeReference({ appearance: { colorTone: 'warm' }, fallbackAppearance: { colorTone: 'cool' } }); + const fallbackWarm = new FlexThemeReference({ fallbackAppearance: { colorTone: 'warm' } }); + render( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + , + ); + expect(fromProvider[0].appearance.colorTone).toBe('cool'); + expect(fromSource[0].appearance.colorTone).toBe('warm'); + expect(fromFallback[0].appearance.colorTone).toBe('warm'); + expect(fromRootFallback[0].appearance.colorTone).toBe('warm'); + expect(fromDefault[0].appearance.colorTone).toBe('cool'); + }); + it('can opt an inherited fixed appearance back into the inherited system source', () => { const appearance = createAppearanceSource({ colorScheme: 'light' }); const themes: ThemeState[] = []; @@ -377,7 +453,7 @@ describe('ThemedRoot', () => { host: { ...mockTheme.host, appearance: 'dark' as const }, }; render( - + @@ -387,6 +463,7 @@ describe('ThemedRoot', () => { ); expect(themes[0].tokens.color.backgroundNeutralSubtle).toBe('#123456'); expect(themes[0].appearance.colorScheme).toBe('dark'); + expect(themes[0].appearance.colorTone).toBe('cool'); }); it('reports a missing scene root instead of returning an untracked modality', () => { diff --git a/packages/agentic/design/src/theming/appearance.test.ts b/packages/agentic/design/src/theming/appearance.test.ts index 20171f4a5c..81533ff6fd 100644 --- a/packages/agentic/design/src/theming/appearance.test.ts +++ b/packages/agentic/design/src/theming/appearance.test.ts @@ -1,8 +1,11 @@ import { appearanceOptionFromResolved, appearanceOptionsFromLegacy, + internResolvedThemeAppearance, + legacyThemeAppearanceKey, normalizeThemeAppearanceRequest, resolveThemeAppearance, + themeAppearanceKey, } from './appearance'; describe('structured theme appearance', () => { @@ -21,6 +24,7 @@ describe('structured theme appearance', () => { colorScheme: 'dark', contrast: 'highContrast', interfaceLevel: 'elevated', + colorTone: 'cool', }); }); @@ -46,5 +50,63 @@ describe('structured theme appearance', () => { it('maps structured appearance back to the legacy compatibility union', () => { expect(appearanceOptionFromResolved({ colorScheme: 'dark', contrast: 'standard', interfaceLevel: 'elevated' })).toBe('darkElevated'); expect(appearanceOptionFromResolved({ colorScheme: 'dark', contrast: 'highContrast', interfaceLevel: 'base' })).toBe('highContrast'); + expect(appearanceOptionFromResolved({ colorScheme: 'dark', contrast: 'standard', interfaceLevel: 'base', colorTone: 'warm' })).toBe( + 'dark', + ); + }); +}); + +describe('color tone', () => { + const base = { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base' } as const; + + it('keeps the historical key for omitted and cool tones and suffixes warm', () => { + expect(themeAppearanceKey(base)).toBe('light|standard|base'); + expect(themeAppearanceKey({ ...base, colorTone: 'cool' })).toBe('light|standard|base'); + expect(themeAppearanceKey({ ...base, colorTone: 'warm' })).toBe('light|standard|base|warm'); + expect(legacyThemeAppearanceKey({ ...base, colorTone: 'warm' })).toBe('light|standard|base'); + }); + + it('interns omitted and cool tones to one normalized identity', () => { + const omitted = internResolvedThemeAppearance(base); + + expect(omitted).toEqual({ ...base, colorTone: 'cool' }); + expect(internResolvedThemeAppearance({ ...base, colorTone: 'cool' })).toBe(omitted); + expect(internResolvedThemeAppearance({ ...base, colorTone: 'warm' })).toEqual({ ...base, colorTone: 'warm' }); + expect(Object.isFrozen(omitted)).toBe(true); + }); + + it('records an explicit tone request without changing omitted requests', () => { + expect(normalizeThemeAppearanceRequest({ colorScheme: 'dark' })).not.toHaveProperty('colorTone'); + expect(normalizeThemeAppearanceRequest({ colorTone: 'cool' })).toMatchObject({ colorTone: 'cool' }); + }); + + it('distinguishes omitted from explicit cool requests while sharing the resolved identity', () => { + const omitted = resolveThemeAppearance({ colorScheme: 'light' }); + const cool = resolveThemeAppearance({ colorScheme: 'light', colorTone: 'cool' }); + + expect(omitted).not.toBe(cool); + expect(omitted.requested).not.toHaveProperty('colorTone'); + expect(cool.requested.colorTone).toBe('cool'); + expect(omitted.resolved).toBe(cool.resolved); + }); + + it('resolves the requested tone before the fallback tone and then cool', () => { + const warmFallback = { ...base, colorTone: 'warm' } as const; + + expect(resolveThemeAppearance({ colorTone: 'cool' }, {}, warmFallback).resolved.colorTone).toBe('cool'); + expect(resolveThemeAppearance({}, {}, warmFallback).resolved.colorTone).toBe('warm'); + expect(resolveThemeAppearance({}, {}, base).resolved.colorTone).toBe('cool'); + expect(resolveThemeAppearance().resolved.colorTone).toBe('cool'); + }); + + it('ignores platform snapshots for tone', () => { + const snapshot = { colorScheme: 'dark', colorTone: 'warm' } as unknown as Parameters[1]; + + expect(resolveThemeAppearance({ colorScheme: 'system' }, snapshot).resolved).toEqual({ + colorScheme: 'dark', + contrast: 'standard', + interfaceLevel: 'base', + colorTone: 'cool', + }); }); }); diff --git a/packages/agentic/design/src/theming/appearance.ts b/packages/agentic/design/src/theming/appearance.ts index 1d6f5411cc..69f5e114b0 100644 --- a/packages/agentic/design/src/theming/appearance.ts +++ b/packages/agentic/design/src/theming/appearance.ts @@ -1,5 +1,7 @@ import type { AppearanceOptions, Theme } from '../fluent/types/Theme.types'; import type { + ColorTone, + NormalizedThemeAppearance, ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceRequest, @@ -13,21 +15,38 @@ export const defaultThemeAppearanceRequest: Readonly = O interfaceLevel: 'system', }); -export const defaultResolvedThemeAppearance: Readonly = Object.freeze({ +export const defaultColorTone: ColorTone = 'cool'; + +export const defaultResolvedThemeAppearance: Readonly = Object.freeze({ colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base', + colorTone: defaultColorTone, }); -const resolvedAppearances = new Map>([['light|standard|base', defaultResolvedThemeAppearance]]); +const resolvedAppearances = new Map>([['light|standard|base', defaultResolvedThemeAppearance]]); const appearanceStates = new Map>(); -export function themeAppearanceKey(appearance: ResolvedThemeAppearance): string { +/** + * Key for the scheme, contrast, and interface-level axes only. Legacy Fluent + * themes do not vary by tone. + */ +export function legacyThemeAppearanceKey(appearance: ResolvedThemeAppearance): string { return `${appearance.colorScheme}|${appearance.contrast}|${appearance.interfaceLevel}`; } +/** + * Identity key for a resolved appearance. Omitted and cool tones share the + * historical three-axis key; warm appends a suffix. + */ +export function themeAppearanceKey(appearance: ResolvedThemeAppearance): string { + const key = legacyThemeAppearanceKey(appearance); + return appearance.colorTone === 'warm' ? `${key}|warm` : key; +} + function themeAppearanceRequestKey(request: ThemeAppearanceRequest): string { - return `${request.colorScheme}|${request.contrast}|${request.interfaceLevel}`; + const key = `${request.colorScheme}|${request.contrast}|${request.interfaceLevel}`; + return request.colorTone === undefined ? key : `${key}|${request.colorTone}`; } export function normalizeThemeAppearanceRequest(options?: ThemeAppearanceOptions): Readonly { @@ -35,23 +54,42 @@ export function normalizeThemeAppearanceRequest(options?: ThemeAppearanceOptions return defaultThemeAppearanceRequest; } - return Object.freeze({ + const request: ThemeAppearanceRequest = { colorScheme: options.colorScheme ?? defaultThemeAppearanceRequest.colorScheme, contrast: options.contrast ?? defaultThemeAppearanceRequest.contrast, interfaceLevel: options.interfaceLevel ?? defaultThemeAppearanceRequest.interfaceLevel, - }); + }; + if (options.colorTone !== undefined) { + request.colorTone = options.colorTone; + } + return Object.freeze(request); } -export function internResolvedThemeAppearance(appearance: ResolvedThemeAppearance): Readonly { +/** + * Return the shared normalized identity for a concrete appearance. A missing + * tone resolves to cool, so three-field values and explicit cool converge. + */ +export function internResolvedThemeAppearance(appearance: ResolvedThemeAppearance): Readonly { const key = themeAppearanceKey(appearance); let interned = resolvedAppearances.get(key); if (!interned) { - interned = Object.freeze({ ...appearance }); + interned = Object.freeze({ + colorScheme: appearance.colorScheme, + contrast: appearance.contrast, + interfaceLevel: appearance.interfaceLevel, + colorTone: appearance.colorTone === 'warm' ? 'warm' : defaultColorTone, + }); resolvedAppearances.set(key, interned); } return interned; } +/** + * Resolve requested appearance options. Scheme, contrast, and interface level + * fall back from the request to the platform snapshot and then the fallback. + * Tone has no platform source: it falls back from the request to the fallback + * and then cool. + */ export function resolveThemeAppearance( options?: ThemeAppearanceOptions, snapshot: ThemeAppearanceSourceSnapshot = {}, @@ -71,6 +109,7 @@ export function resolveThemeAppearance( requested.interfaceLevel === 'system' ? (snapshot.interfaceLevel ?? fallback.interfaceLevel ?? defaultResolvedThemeAppearance.interfaceLevel) : requested.interfaceLevel, + colorTone: requested.colorTone ?? fallback.colorTone ?? defaultColorTone, }); const key = `${themeAppearanceRequestKey(requested)}>${themeAppearanceKey(resolved)}`; let state = appearanceStates.get(key); @@ -97,6 +136,10 @@ export function appearanceOptionsFromLegacy(appearance: Theme['host']['appearanc } } +/** + * Project a resolved appearance onto the legacy appearance union. Tone has no + * legacy representation and is intentionally dropped. + */ export function appearanceOptionFromResolved(appearance: ResolvedThemeAppearance): AppearanceOptions { if (appearance.contrast === 'highContrast') { return 'highContrast'; diff --git a/packages/agentic/design/src/theming/index.ts b/packages/agentic/design/src/theming/index.ts index 400f75a30e..e6dec96df8 100644 --- a/packages/agentic/design/src/theming/index.ts +++ b/packages/agentic/design/src/theming/index.ts @@ -17,6 +17,8 @@ export type { } from '../fluent/types/Shadow.types'; export type { AppearanceOptions, PartialTheme, Spacing, Theme, ThemeOptions } from '../fluent/types/Theme.types'; export type { + ColorTone, + NormalizedThemeAppearance, ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceRequest, diff --git a/packages/agentic/design/src/theming/modern.ts b/packages/agentic/design/src/theming/modern.ts index f7bcdfaaa4..06ec0e499d 100644 --- a/packages/agentic/design/src/theming/modern.ts +++ b/packages/agentic/design/src/theming/modern.ts @@ -1,4 +1,6 @@ export type { + ColorTone, + NormalizedThemeAppearance, ResolvedThemeAppearance, ThemeAppearanceOptions, ThemeAppearanceRequest, diff --git a/packages/agentic/design/src/theming/themeRuntime.ts b/packages/agentic/design/src/theming/themeRuntime.ts index 6b73315bf8..eb9acf07b3 100644 --- a/packages/agentic/design/src/theming/themeRuntime.ts +++ b/packages/agentic/design/src/theming/themeRuntime.ts @@ -1,31 +1,29 @@ -import { defaultFlexTokens } from '../flex/defaults/defaultTokens'; +import { themeAppearanceKey } from './appearance'; import type { FlexTokens } from '../flex/tokens.types'; -import { flexTokensFromTheme } from '../flex/adapters/flexTokensFromTheme'; -import { defaultResolvedThemeAppearance, themeAppearanceKey } from './appearance'; import type { ResolvedThemeAppearance } from '../types/appearance.types'; import type { ThemeState } from '../types/themeState.types'; -import type { ThemeSource } from './themeSource'; +import type { FlexThemeSource, ThemeSource } from './themeSource'; -type AppearanceCache = { +/** + * Values derived from one source revision and one resolved appearance. + */ +export type ThemeAppearanceCache = { flexTokens?: FlexTokens; themeState?: ThemeState; }; type SourceCache = { revision: number; - byAppearance: Map; + byAppearance: Map; }; const sourceCaches = new WeakMap(); -export const defaultThemeState: ThemeState = { - tokens: defaultFlexTokens, - appearance: defaultResolvedThemeAppearance, - highContrast: false, - themeStyles: {}, -}; - -function getAppearanceCache(source: ThemeSource, appearance: ResolvedThemeAppearance): AppearanceCache { +/** + * Return the revision-scoped cache for one source and appearance. A source + * revision change replaces every entry for that source. + */ +export function getThemeAppearanceCache(source: ThemeSource, appearance: ResolvedThemeAppearance): ThemeAppearanceCache { let sourceCache = sourceCaches.get(source); if (!sourceCache || sourceCache.revision !== source.revision) { sourceCache = { revision: source.revision, byAppearance: new Map() }; @@ -41,23 +39,14 @@ function getAppearanceCache(source: ThemeSource, appearance: ResolvedThemeAppear return appearanceCache; } -export function getFlexTokens(source: ThemeSource, appearance: ResolvedThemeAppearance): FlexTokens { - const cache = getAppearanceCache(source, appearance); +/** + * Resolve Flex tokens from a Flex-authored source. This shared helper never + * reaches the legacy forward adapter, so legacy-only graphs stay free of it. + */ +export function getFlexSourceTokens(source: FlexThemeSource, appearance: ResolvedThemeAppearance): FlexTokens { + const cache = getThemeAppearanceCache(source, appearance); if (!cache.flexTokens) { - cache.flexTokens = source.kind === 'flex' ? source.resolveFlexTokens(appearance) : flexTokensFromTheme(source.resolveTheme(appearance)); + cache.flexTokens = source.resolveFlexTokens(appearance); } return cache.flexTokens; } - -export function getThemeState(source: ThemeSource, appearance: ResolvedThemeAppearance): ThemeState { - const cache = getAppearanceCache(source, appearance); - if (!cache.themeState) { - cache.themeState = { - tokens: getFlexTokens(source, appearance), - appearance, - highContrast: appearance.contrast === 'highContrast', - themeStyles: {}, - }; - } - return cache.themeState; -} diff --git a/packages/agentic/design/src/types/appearance.types.ts b/packages/agentic/design/src/types/appearance.types.ts index a2f5b13d78..79153d1b20 100644 --- a/packages/agentic/design/src/types/appearance.types.ts +++ b/packages/agentic/design/src/types/appearance.types.ts @@ -2,23 +2,47 @@ export type ThemeColorScheme = 'light' | 'dark'; export type ThemeContrast = 'standard' | 'highContrast'; export type ThemeInterfaceLevel = 'base' | 'elevated'; +/** + * Palette tone. It selects both the Flex palette and the interaction-color + * algorithm. Tone is configuration only; no platform source reports it. + */ +export type ColorTone = 'cool' | 'warm'; + export interface ThemeAppearanceRequest { colorScheme: ThemeColorScheme | 'system'; contrast: ThemeContrast | 'system'; interfaceLevel: ThemeInterfaceLevel | 'system'; + /** + * Explicit tone request. Omission is preserved until resolution, where the + * configured fallback tone and then cool apply. + */ + colorTone?: ColorTone; } export type ThemeAppearanceOptions = Partial; +/** + * A concrete appearance accepted by legacy-facing and recipe APIs. Existing + * three-field values remain valid; an omitted tone means cool. + */ export interface ResolvedThemeAppearance { colorScheme: ThemeColorScheme; contrast: ThemeContrast; interfaceLevel: ThemeInterfaceLevel; + colorTone?: ColorTone; +} + +/** + * A resolved appearance produced by the theme runtime. Every axis, including + * tone, is concrete. + */ +export interface NormalizedThemeAppearance extends ResolvedThemeAppearance { + colorTone: ColorTone; } export interface ThemeAppearanceState { requested: Readonly; - resolved: Readonly; + resolved: Readonly; } export interface ThemeAppearanceSourceSnapshot { diff --git a/packages/agentic/design/src/types/themeState.types.ts b/packages/agentic/design/src/types/themeState.types.ts index 818c5aa3d8..5e45c00231 100644 --- a/packages/agentic/design/src/types/themeState.types.ts +++ b/packages/agentic/design/src/types/themeState.types.ts @@ -1,5 +1,5 @@ import type { FlexTokens } from '../flex/tokens.types'; -import type { ResolvedThemeAppearance } from './appearance.types'; +import type { NormalizedThemeAppearance } from './appearance.types'; /** * Style sheets cached for one theme state, keyed by a module-scoped symbol per component. @@ -14,7 +14,7 @@ export type ThemeState = { /** * Structured appearance values used to resolve this theme state. */ - readonly appearance: Readonly; + readonly appearance: Readonly; /** * @deprecated Use appearance.contrast. */ From 7a265cc513680664f6e03ca1d314de5a7c568dcf Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 23 Oct 2026 19:13:17 -0700 Subject: [PATCH 05/18] design: interactive color representation and consumer migration (refactor phase 4) Represent every Flex semantic color as one authored description and one resolved InteractiveColor envelope with rest, hover, and pressed. - Authored colors accept a value, a [light, dark] tuple, or flexColor options with explicit states and a standard, inverted, or fixed interaction type. - Overrides replace each color atomically; color.hover/pressed maps are rejected with a migration error. - Omitted interactive states derive lazily on first read and memoize per resolved color; defaults and the Theme adapter resolve explicitly. - Recipes receive the authored description plus the resolved appearance; selectColorEntry reads appearance-specific entries. - Migrate components and Storybook runtime reads to .rest/.hover/.pressed, revise component token-path contracts, and document the model and migration in the new design flex-colors reference. - Narrow the legacy-source bundle scenario to allow the engine-free color envelope while still forbidding color-lib and the interaction policy. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5030bce5-d7f7-4fb1-93de-68599b79269f --- apps/bundle-size/scenarios.json | 7 +- .../references/styles-and-tokens.md | 8 +- .../src/common/applyFocusRingStyles.ts | 4 +- .../src/common/focusVisualPolicy.test.tsx | 4 +- .../src/common/renderWithTheme.test.tsx | 2 +- .../components/accordion/accordion.test.tsx | 12 +- .../src/components/accordion/spec/tokens.yaml | 4 +- .../src/components/avatar/avatar.styles.ts | 6 +- .../src/components/avatar/avatar.test.tsx | 8 +- .../src/components/avatar/useAvatarStyles.ts | 2 +- .../src/components/badge/badge.test.tsx | 12 +- .../src/components/button/button.test.tsx | 36 +- .../src/components/button/spec/tokens.yaml | 9 +- .../src/components/card/card.styles.ts | 2 +- .../src/components/card/card.test.tsx | 16 +- .../src/components/card/spec/tokens.yaml | 5 +- .../src/components/checkbox/checkbox.test.tsx | 32 +- .../src/components/checkbox/spec/tokens.yaml | 6 +- .../src/components/divider/divider.styles.ts | 6 +- .../src/components/divider/divider.test.tsx | 8 +- .../components/divider/useDividerStyles.ts | 2 +- .../components/dropdown/dropdown.styles.ts | 10 +- .../src/components/input/input.styles.ts | 46 +- .../src/components/input/input.test.tsx | 22 +- .../src/components/input/spec/tokens.yaml | 4 +- .../components/list-item/list-item.test.tsx | 4 +- .../listbox-item/listbox-item.styles.ts | 28 +- .../listbox-item/listbox-item.test.tsx | 8 +- .../listbox-item/useListboxItemStyles.ts | 12 +- .../components/menu-item/menu-item.styles.ts | 4 +- .../components/menu-item/useMenuItemStyles.ts | 4 +- .../src/components/menu/menu.styles.ts | 4 +- .../src/components/popover/popover.styles.ts | 4 +- .../progress-bar/progress-bar.styles.ts | 8 +- .../components/progress-bar/useProgressBar.ts | 6 +- .../src/components/radio/radio.styles.ts | 4 +- .../src/components/radio/radio.test.tsx | 24 +- .../components/skeleton/skeleton.stories.tsx | 2 +- .../components/skeleton/skeleton.styles.ts | 6 +- .../src/components/skeleton/skeleton.test.tsx | 6 +- .../src/components/skeleton/useSkeleton.ts | 2 +- .../src/components/spinner/spinner.test.tsx | 4 +- .../src/components/spinner/useSpinner.ts | 4 +- .../src/components/switch/switch.styles.ts | 4 +- .../src/components/switch/switch.test.tsx | 26 +- .../src/components/tab/tab.test.tsx | 10 +- .../src/components/tag/tag.test.tsx | 12 +- .../src/components/text/text.styles.ts | 2 +- packages/agentic/design/AGENTS.md | 8 +- packages/agentic/design/README.md | 3 +- packages/agentic/design/references/README.md | 1 + .../agentic/design/references/color-lib.md | 13 +- .../agentic/design/references/contributing.md | 33 +- .../agentic/design/references/entry-points.md | 3 +- .../agentic/design/references/flex-colors.md | 124 ++++++ packages/agentic/design/references/styling.md | 4 +- packages/agentic/design/references/testing.md | 4 + packages/agentic/design/references/theming.md | 29 +- packages/agentic/design/references/tokens.md | 9 +- .../scripts/token-mappings/check-mappings.cjs | 37 +- .../flex/adapters/flexTokensFromTheme.test.ts | 34 +- .../src/flex/adapters/flexTokensFromTheme.ts | 42 +- .../design/src/flex/colors/flexColor.test.ts | 109 +++++ .../design/src/flex/colors/flexColor.ts | 163 +++++++ .../flex/colors/interactionLaziness.test.tsx | 116 +++++ .../src/flex/colors/interactionPolicy.test.ts | 138 ++++-- .../src/flex/colors/interactionPolicy.ts | 92 ++-- .../src/flex/colors/interactiveColor.ts | 48 +++ .../src/flex/colors/interactiveTokens.ts | 27 +- .../design/src/flex/defaults/defaultTokens.ts | 277 ++++-------- .../src/flex/flexThemeReference.test.ts | 137 ++++-- .../design/src/flex/flexThemeReference.ts | 84 ++-- .../design/src/flex/flexTokenDescription.ts | 109 +++++ .../src/flex/styling/colorStyles.test.ts | 45 +- .../design/src/flex/styling/colorStyles.ts | 27 +- .../agentic/design/src/flex/themeState.ts | 2 +- .../agentic/design/src/flex/tokens.test.ts | 70 +-- .../agentic/design/src/flex/tokens.types.ts | 397 +++++++++--------- .../design/src/flex/useThemeState.test.ts | 12 +- .../agentic/design/src/fluent/compat/index.ts | 2 +- .../fluent/compat/themeFromFlexTokens.test.ts | 63 ++- .../src/fluent/compat/themeFromFlexTokens.ts | 51 ++- .../design/src/fluent/useTheme.test.ts | 2 +- packages/agentic/design/src/index.ts | 16 +- .../test/color-validation/validation.test.ts | 12 +- .../src/test/color-validation/validation.ts | 24 +- .../__snapshots__/entryPoints.test.ts.snap | 5 + .../compatibilityBaseline.test.ts | 4 +- .../src/test/compatibility/fingerprint.ts | 11 +- .../src/test/fixtures/interactionColors.ts | 17 +- .../design/src/theming/ThemedRoot.test.tsx | 4 +- packages/agentic/design/src/theming/index.ts | 11 +- packages/agentic/design/src/theming/modern.ts | 11 +- .../src/tokens/mappings/flex-from-theme.json | 238 +++++------ .../src/tokens/mappings/flex-token-map.yaml | 152 +++---- .../tokens/mappings/flexTokenMappings.test.ts | 40 +- .../src/tokens/mappings/theme-from-flex.json | 198 ++++----- .../src/StorybookTheme.test.tsx | 26 +- .../src/StorybookTheme.tsx | 20 +- .../src/useStorybookTheme.test.tsx | 8 +- .../src/useStorybookTheme.ts | 4 +- 101 files changed, 2273 insertions(+), 1304 deletions(-) create mode 100644 packages/agentic/design/references/flex-colors.md create mode 100644 packages/agentic/design/src/flex/colors/flexColor.test.ts create mode 100644 packages/agentic/design/src/flex/colors/flexColor.ts create mode 100644 packages/agentic/design/src/flex/colors/interactionLaziness.test.tsx create mode 100644 packages/agentic/design/src/flex/colors/interactiveColor.ts create mode 100644 packages/agentic/design/src/flex/flexTokenDescription.ts diff --git a/apps/bundle-size/scenarios.json b/apps/bundle-size/scenarios.json index caf672fd58..5a8cfed141 100644 --- a/apps/bundle-size/scenarios.json +++ b/apps/bundle-size/scenarios.json @@ -51,7 +51,12 @@ ], "forbiddenInputPatterns": ["/design/src/fluent/compat/", "/design/src/fluent/tokens/", "/design/src/test/"], "requiredInputPatterns": ["/design/src/fluent/themeReference."], - "forbiddenOutputPatterns": ["/color-lib/", "/design/src/flex/colors/", "/design/src/flex/flexThemeReference."] + "forbiddenOutputPatterns": [ + "/color-lib/", + "/design/src/flex/colors/interactionPolicy.", + "/design/src/flex/colors/interactiveTokens.", + "/design/src/flex/flexThemeReference." + ] }, { "name": "design-legacy-theme", diff --git a/packages/agentic/components/references/styles-and-tokens.md b/packages/agentic/components/references/styles-and-tokens.md index e2384c1dc5..cb0b60ddb9 100644 --- a/packages/agentic/components/references/styles-and-tokens.md +++ b/packages/agentic/components/references/styles-and-tokens.md @@ -19,7 +19,9 @@ Consult `flex-token-map.yaml` before choosing a value. -- Read semantic colors from `useThemeState().tokens.color`. +- Read semantic colors from `useThemeState().tokens.color`. Each color is a resolved envelope: read `.rest` for static + styles and `.hover` or `.pressed` only for those states, because an omitted state is computed on first read. The design + Flex color reference (`@fluentui-react-native/design/references/flex-colors.md`) owns the color contract. - Read grouped categories from `tokens.borderRadius`, `tokens.spacing`, `tokens.strokeWidth`, `tokens.fontFamily`, `tokens.fontSize`, `tokens.fontWeight`, `tokens.lineHeight`, and `tokens.shadow`. - Prefer Flex tokens for every mapped semantic value. @@ -74,12 +76,12 @@ states in `disabled`, `pressed`, `hovered` order so the first active state has t Use `getThemedStateStyleFactory` for token-derived hierarchy definitions and `getStateStyleFactory` for theme-independent definitions. Use `getThemedColorStyleFactory` for semantic background, border, and foreground colors; -it automatically resolves `tokens.color.hover` and `tokens.color.pressed` for inherited semantic keys. +it automatically reads the resolved `hover` and `pressed` states of inherited semantic keys. An interaction may intentionally switch semantic keys. Button Subtle is transparent at rest but explicitly selects `backgroundNeutralSubtle` inside hovered and pressed branches. Button Outline uses `strokeNeutralLoud`, whose hover and pressed token values provide visible stroke feedback. Do not assume a token named `Transparent` will produce visible -interaction states; verify the resolved token maps. +interaction states; verify the resolved colors' `hover` and `pressed` values. Build the state source from resolved state without hiding precedence in conditionals. Button pushes appearance, selected, disabled, pressed, and hovered values, then lets the declared hierarchy select the winner. diff --git a/packages/agentic/components/src/common/applyFocusRingStyles.ts b/packages/agentic/components/src/common/applyFocusRingStyles.ts index c35b474375..68748d6840 100644 --- a/packages/agentic/components/src/common/applyFocusRingStyles.ts +++ b/packages/agentic/components/src/common/applyFocusRingStyles.ts @@ -10,12 +10,12 @@ import type { FocusVisualsState } from './useFocusVisuals'; const getStyles = themedStyleSheetFactory('FocusRing', ({ tokens }) => StyleSheet.create({ outer: { - borderColor: tokens.color.strokeFocusOuter, + borderColor: tokens.color.strokeFocusOuter.rest, borderStyle: 'solid', borderWidth: tokens.strokeWidth.thick, }, inner: { - borderColor: tokens.color.strokeFocusInner, + borderColor: tokens.color.strokeFocusInner.rest, borderStyle: 'solid', borderWidth: tokens.strokeWidth.thin, }, diff --git a/packages/agentic/components/src/common/focusVisualPolicy.test.tsx b/packages/agentic/components/src/common/focusVisualPolicy.test.tsx index 51b9761abc..e9fec7bd40 100644 --- a/packages/agentic/components/src/common/focusVisualPolicy.test.tsx +++ b/packages/agentic/components/src/common/focusVisualPolicy.test.tsx @@ -67,12 +67,12 @@ describe.each(['windows', 'macos', 'win32'])('component focus visuals on %s', (p expect(component.getByTestId('focus-visual', { includeHiddenElements: true })).toBe(outerRing); expect(component.getByTestId('focus-visual-inner', { includeHiddenElements: true })).toBe(innerRing); expect(StyleSheet.flatten(outerRing.props.style)).toMatchObject({ - borderColor: defaultFlexTokens.color.strokeFocusOuter, + borderColor: defaultFlexTokens.color.strokeFocusOuter.rest, borderWidth: defaultFlexTokens.strokeWidth.thick, }); expect(StyleSheet.flatten(outerRing.props.style).opacity).toBeUndefined(); expect(StyleSheet.flatten(innerRing.props.style)).toMatchObject({ - borderColor: defaultFlexTokens.color.strokeFocusInner, + borderColor: defaultFlexTokens.color.strokeFocusInner.rest, borderWidth: defaultFlexTokens.strokeWidth.thin, }); expect(outerRing.props).toMatchObject({ accessible: false, focusable: false, pointerEvents: 'none' }); diff --git a/packages/agentic/components/src/common/renderWithTheme.test.tsx b/packages/agentic/components/src/common/renderWithTheme.test.tsx index 99d26ccd1f..5490b14614 100644 --- a/packages/agentic/components/src/common/renderWithTheme.test.tsx +++ b/packages/agentic/components/src/common/renderWithTheme.test.tsx @@ -58,7 +58,7 @@ describe('themed test scenes', () => { await scene.rerender(); expect(wrapperRoots.every((root) => root === roots[0])).toBe(true); - expect(themes.every((state) => state.tokens.color.foregroundNeutralPrimary === '#123456')).toBe(true); + expect(themes.every((state) => state.tokens.color.foregroundNeutralPrimary.rest === '#123456')).toBe(true); expect(roots.every((root) => root === roots[0])).toBe(true); }); diff --git a/packages/agentic/components/src/components/accordion/accordion.test.tsx b/packages/agentic/components/src/components/accordion/accordion.test.tsx index bf8217a99e..8c6880ed38 100644 --- a/packages/agentic/components/src/components/accordion/accordion.test.tsx +++ b/packages/agentic/components/src/components/accordion/accordion.test.tsx @@ -153,21 +153,21 @@ describe('Accordion', () => { const header = getHeader(component); expect(getHeaderStyle(component)).toMatchObject({ - backgroundColor: colors.backgroundNeutralTransparent, + backgroundColor: colors.backgroundNeutralTransparent.rest, }); - expect(getTitleStyle(component).color).toBe(colors.foregroundNeutralPrimary); + expect(getTitleStyle(component).color).toBe(colors.foregroundNeutralPrimary.rest); await fireEvent(header, 'hoverIn', {}); expect(getHeaderStyle(component)).toMatchObject({ - backgroundColor: colors.hover.backgroundNeutralSubtle, + backgroundColor: colors.backgroundNeutralSubtle.hover, }); - expect(getTitleStyle(component).color).toBe(colors.hover.foregroundNeutralPrimary); + expect(getTitleStyle(component).color).toBe(colors.foregroundNeutralPrimary.hover); await fireEvent(header, 'pressIn', {}); expect(getHeaderStyle(component)).toMatchObject({ - backgroundColor: colors.pressed.backgroundNeutralSubtle, + backgroundColor: colors.backgroundNeutralSubtle.pressed, }); - expect(getTitleStyle(component).color).toBe(colors.pressed.foregroundNeutralPrimary); + expect(getTitleStyle(component).color).toBe(colors.foregroundNeutralPrimary.pressed); }); it('places the chevron at the leading or trailing edge according to layout', async () => { diff --git a/packages/agentic/components/src/components/accordion/spec/tokens.yaml b/packages/agentic/components/src/components/accordion/spec/tokens.yaml index f5309e90e4..883c8812a2 100644 --- a/packages/agentic/components/src/components/accordion/spec/tokens.yaml +++ b/packages/agentic/components/src/components/accordion/spec/tokens.yaml @@ -21,8 +21,8 @@ bindings: paddingVertical: spacing.componentBase100 background: rest: color.backgroundNeutralTransparent - hovered: color.hover.backgroundNeutralSubtle - pressed: color.pressed.backgroundNeutralSubtle + hovered: color.backgroundNeutralSubtle.hover + pressed: color.backgroundNeutralSubtle.pressed title: small: fontFamily: fontFamily.functional diff --git a/packages/agentic/components/src/components/avatar/avatar.styles.ts b/packages/agentic/components/src/components/avatar/avatar.styles.ts index 86881e2e27..8f613f5e14 100644 --- a/packages/agentic/components/src/components/avatar/avatar.styles.ts +++ b/packages/agentic/components/src/components/avatar/avatar.styles.ts @@ -39,7 +39,7 @@ type AvatarSizeState = StateNames; function createRingStyle({ color, strokeWidth }: FlexTokens, offset: 'thin' | 'thick', width: 'thin' | 'thick' | 'thicker'): ViewStyle { const inset = -(strokeWidth[offset] + strokeWidth[width]); return { - borderColor: color.strokeBrandLoud, + borderColor: color.strokeBrandLoud.rest, borderStyle: 'solid', borderWidth: strokeWidth[width], bottom: inset, @@ -54,11 +54,11 @@ function createSizeStyleDefinition(tokens: FlexTokens, size: AvatarSize): StyleD return { alignItems: 'center', - backgroundColor: color.backgroundNeutralSoft, + backgroundColor: color.backgroundNeutralSoft.rest, borderRadius: borderRadius.circular, height: size, image: { - backgroundColor: color.backgroundNeutralTransparent, + backgroundColor: color.backgroundNeutralTransparent.rest, padding: 0, }, minHeight: size, diff --git a/packages/agentic/components/src/components/avatar/avatar.test.tsx b/packages/agentic/components/src/components/avatar/avatar.test.tsx index a39ab80c3c..9f59d6bc6c 100644 --- a/packages/agentic/components/src/components/avatar/avatar.test.tsx +++ b/packages/agentic/components/src/components/avatar/avatar.test.tsx @@ -89,7 +89,7 @@ describe('Avatar', () => { expect(component.getByText('LM', { includeHiddenElements: true })).toBeOnTheScreen(); expect(getRootStyle(component)).toMatchObject({ alignItems: 'center', - backgroundColor: tokens.color.backgroundNeutralSoft, + backgroundColor: tokens.color.backgroundNeutralSoft.rest, flexDirection: 'row', height: 40, justifyContent: 'center', @@ -123,7 +123,7 @@ describe('Avatar', () => { top: 0, }); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: tokens.color.backgroundNeutralTransparent, + backgroundColor: tokens.color.backgroundNeutralTransparent.rest, height: 56, padding: 0, width: 56, @@ -144,7 +144,7 @@ describe('Avatar', () => { height: 120, }); expect(StyleSheet.flatten(component.getByTestId('avatar-activity-ring', { includeHiddenElements: true }).props.style)).toMatchObject({ - borderColor: tokens.color.strokeBrandLoud, + borderColor: tokens.color.strokeBrandLoud.rest, borderRadius: tokens.borderRadius.circular, borderStyle: 'solid', borderWidth: tokens.strokeWidth.thicker, @@ -182,7 +182,7 @@ describe('Avatar', () => { pointerEvents: 'none', }); expect(StyleSheet.flatten(ring.props.style)).toMatchObject({ - borderColor: tokens.color.strokeBrandLoud, + borderColor: tokens.color.strokeBrandLoud.rest, borderWidth: width, bottom: -(offset + width), left: -(offset + width), diff --git a/packages/agentic/components/src/components/avatar/useAvatarStyles.ts b/packages/agentic/components/src/components/avatar/useAvatarStyles.ts index 24c91a3d44..b7e409df82 100644 --- a/packages/agentic/components/src/components/avatar/useAvatarStyles.ts +++ b/packages/agentic/components/src/components/avatar/useAvatarStyles.ts @@ -7,7 +7,7 @@ import { avatarStyles, getAvatarActivityRingStyle, getAvatarIconSize, getAvatarI import type { AvatarState } from './avatar.types'; export function useAvatarStyles_unstable(state: AvatarState) { - const foregroundColor = state.tokens.color.foregroundNeutralPrimary; + const foregroundColor = state.tokens.color.foregroundNeutralPrimary.rest; const imageStyle: StyleProp = [ avatarStyles.image, { diff --git a/packages/agentic/components/src/components/badge/badge.test.tsx b/packages/agentic/components/src/components/badge/badge.test.tsx index 8ffffa0e0e..ee2cff8046 100644 --- a/packages/agentic/components/src/components/badge/badge.test.tsx +++ b/packages/agentic/components/src/components/badge/badge.test.tsx @@ -68,13 +68,13 @@ describe('Badge', () => { expect(getRoot(component).props.accessible).toBe(true); expect(getRootStyle(component)).toMatchObject({ alignItems: 'center', - backgroundColor: tokens.color.backgroundBrandSoft, + backgroundColor: tokens.color.backgroundBrandSoft.rest, borderRadius: tokens.borderRadius.circular, minHeight: 20, paddingHorizontal: tokens.spacing.componentBase150, }); expect(StyleSheet.flatten(component.getByText('Badge').props.style)).toMatchObject({ - color: tokens.color.foregroundBrandPrimary, + color: tokens.color.foregroundBrandPrimary.rest, fontFamily: expect.any(String), fontSize: tokens.fontSize.functionalBodySmall, }); @@ -83,7 +83,7 @@ describe('Badge', () => { width: 16, }); expect(StyleSheet.flatten(component.getByText(String.fromCodePoint(badgeIcon.fontSource.codepoint)).props.style)).toMatchObject({ - color: tokens.color.foregroundBrandPrimary, + color: tokens.color.foregroundBrandPrimary.rest, }); }); @@ -160,11 +160,11 @@ describe('Badge', () => { }); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: tokens.color[backgroundToken], - borderColor: tokens.color[borderToken], + backgroundColor: tokens.color[backgroundToken].rest, + borderColor: tokens.color[borderToken].rest, borderWidth, }); - expect(StyleSheet.flatten(component.getByText('Badge').props.style).color).toBe(tokens.color[foregroundToken]); + expect(StyleSheet.flatten(component.getByText('Badge').props.style).color).toBe(tokens.color[foregroundToken].rest); }); it.each([ diff --git a/packages/agentic/components/src/components/button/button.test.tsx b/packages/agentic/components/src/components/button/button.test.tsx index 8691fad177..ed9c98875f 100644 --- a/packages/agentic/components/src/components/button/button.test.tsx +++ b/packages/agentic/components/src/components/button/button.test.tsx @@ -343,20 +343,20 @@ describe('Button', () => { const root = getRoot(component); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors[restBackground], - borderColor: colors[restBorder], + backgroundColor: colors[restBackground].rest, + borderColor: colors[restBorder].rest, }); await fireEvent(root, 'hoverIn', {}); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors.hover[interactionBackground], - borderColor: colors.hover[interactionBorder], + backgroundColor: colors[interactionBackground].hover, + borderColor: colors[interactionBorder].hover, }); await fireEvent(root, 'pressIn', {}); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors.pressed[interactionBackground], - borderColor: colors.pressed[interactionBorder], + backgroundColor: colors[interactionBackground].pressed, + borderColor: colors[interactionBorder].pressed, }); }, ); @@ -415,32 +415,32 @@ describe('Button', () => { StyleSheet.flatten(component.getAllByText(appearance, { includeHiddenElements: true })[1].props.style).color; expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors[background], - borderColor: colors[border], + backgroundColor: colors[background].rest, + borderColor: colors[border].rest, }); - expect(getForegroundColor()).toBe(colors[foreground]); + expect(getForegroundColor()).toBe(colors[foreground].rest); await fireEvent(root, 'hoverIn', {}); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors.hover[background], - borderColor: colors.hover[border], + backgroundColor: colors[background].hover, + borderColor: colors[border].hover, }); - expect(getForegroundColor()).toBe(colors.hover[foreground]); + expect(getForegroundColor()).toBe(colors[foreground].hover); await fireEvent(root, 'pressIn', {}); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors.pressed[background], - borderColor: colors.pressed[border], + backgroundColor: colors[background].pressed, + borderColor: colors[border].pressed, }); - expect(getForegroundColor()).toBe(colors.pressed[foreground]); + expect(getForegroundColor()).toBe(colors[foreground].pressed); const disabledComponent = await renderButton({ appearance, content: appearance, disabled: true, selected: true }); expect(getRootStyle(disabledComponent)).toMatchObject({ - backgroundColor: colors[disabledBackground], - borderColor: colors[disabledBorder], + backgroundColor: colors[disabledBackground].rest, + borderColor: colors[disabledBorder].rest, }); expect(StyleSheet.flatten(disabledComponent.getAllByText(appearance, { includeHiddenElements: true })[1].props.style).color).toBe( - colors.foregroundNeutralDisabled, + colors.foregroundNeutralDisabled.rest, ); }, ); diff --git a/packages/agentic/components/src/components/button/spec/tokens.yaml b/packages/agentic/components/src/components/button/spec/tokens.yaml index d9e8def76f..dba51d5d65 100644 --- a/packages/agentic/components/src/components/button/spec/tokens.yaml +++ b/packages/agentic/components/src/components/button/spec/tokens.yaml @@ -67,10 +67,11 @@ bindings: selectedSubtle: backgroundColor: color.backgroundNeutralSubtleDisabled interaction: - hovered: color.hover - pressed: color.pressed - subtleHoveredBackground: color.hover.backgroundNeutralSubtle - subtlePressedBackground: color.pressed.backgroundNeutralSubtle + # is the semantic color key the state inherits from its parent style. + hovered: color..hover + pressed: color..pressed + subtleHoveredBackground: color.backgroundNeutralSubtle.hover + subtlePressedBackground: color.backgroundNeutralSubtle.pressed size: small: roundedRadius: borderRadius.base200 diff --git a/packages/agentic/components/src/components/card/card.styles.ts b/packages/agentic/components/src/components/card/card.styles.ts index 6506bf79c4..f48b184695 100644 --- a/packages/agentic/components/src/components/card/card.styles.ts +++ b/packages/agentic/components/src/components/card/card.styles.ts @@ -161,7 +161,7 @@ type NestedBlockStyleStateLevels = typeof nestedBlockStyleStateLevels; type NestedBlockStyleState = StateNames; function createNestedBlockStyleDefinition({ borderRadius, color }: FlexTokens): StyleDefinition { - const nestedBackground: ViewStyle = { backgroundColor: color.backgroundNeutralTranslucent }; + const nestedBackground: ViewStyle = { backgroundColor: color.backgroundNeutralTranslucent.rest }; return { small: { default: { diff --git a/packages/agentic/components/src/components/card/card.test.tsx b/packages/agentic/components/src/components/card/card.test.tsx index 712c661cf4..988cca77c6 100644 --- a/packages/agentic/components/src/components/card/card.test.tsx +++ b/packages/agentic/components/src/components/card/card.test.tsx @@ -130,8 +130,8 @@ describe('Card', () => { const colors = defaultFlexTokens.color; expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors.surfaceNeutralTranslucent, - borderColor: colors.strokeNeutralSubtle, + backgroundColor: colors.surfaceNeutralTranslucent.rest, + borderColor: colors.strokeNeutralSubtle.rest, }); expect(component.getByText('Summary')).toBeOnTheScreen(); }); @@ -164,20 +164,20 @@ describe('Card', () => { expect(button.props.accessibilityState).toEqual({ disabled: false, selected: true }); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors.backgroundNeutralSoft, - borderColor: colors.strokeNeutralSoft, + backgroundColor: colors.backgroundNeutralSoft.rest, + borderColor: colors.strokeNeutralSoft.rest, }); await fireEvent(button, 'hoverIn', {}); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors.hover.backgroundNeutralSoft, - borderColor: colors.hover.strokeNeutralSoft, + backgroundColor: colors.backgroundNeutralSoft.hover, + borderColor: colors.strokeNeutralSoft.hover, }); await fireEvent(button, 'pressIn', {}); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors.pressed.backgroundNeutralSoft, - borderColor: colors.pressed.strokeNeutralSoft, + backgroundColor: colors.backgroundNeutralSoft.pressed, + borderColor: colors.strokeNeutralSoft.pressed, }); await fireEvent(button, 'focus', {}); diff --git a/packages/agentic/components/src/components/card/spec/tokens.yaml b/packages/agentic/components/src/components/card/spec/tokens.yaml index 2ddeb7d69b..d68ee9eb1e 100644 --- a/packages/agentic/components/src/components/card/spec/tokens.yaml +++ b/packages/agentic/components/src/components/card/spec/tokens.yaml @@ -24,8 +24,9 @@ bindings: disabled: backgroundColor: color.backgroundNeutralDisabled borderColor: color.strokeNeutralDisabled - hovered: color.hover - pressed: color.pressed + # is the semantic color key the state inherits from its parent style. + hovered: color..hover + pressed: color..pressed size: small: borderRadius: borderRadius.base600 diff --git a/packages/agentic/components/src/components/checkbox/checkbox.test.tsx b/packages/agentic/components/src/components/checkbox/checkbox.test.tsx index 66ae89dde3..56aa102d45 100644 --- a/packages/agentic/components/src/components/checkbox/checkbox.test.tsx +++ b/packages/agentic/components/src/components/checkbox/checkbox.test.tsx @@ -39,8 +39,8 @@ describe('Checkbox', () => { expect(component.getByText('Save drafts')).toBeOnTheScreen(); expect(getIndicatorStyle(component)).toMatchObject({ alignItems: 'center', - backgroundColor: colors.backgroundNeutralTransparent, - borderColor: colors.strokeNeutralHeavy, + backgroundColor: colors.backgroundNeutralTransparent.rest, + borderColor: colors.strokeNeutralHeavy.rest, }); expect(getRootStyle(component)).toMatchObject({ borderStyle: 'solid', @@ -251,23 +251,23 @@ describe('Checkbox', () => { const root = getRoot(component); expect(getIndicatorStyle(component)).toMatchObject({ - backgroundColor: colors.backgroundNeutralTransparent, - borderColor: colors.strokeNeutralHeavy, + backgroundColor: colors.backgroundNeutralTransparent.rest, + borderColor: colors.strokeNeutralHeavy.rest, }); await fireEvent(root, 'hoverIn', {}); expect(getIndicatorStyle(component)).toMatchObject({ - backgroundColor: colors.hover.backgroundNeutralTransparent, - borderColor: colors.hover.strokeNeutralHeavy, + backgroundColor: colors.backgroundNeutralTransparent.hover, + borderColor: colors.strokeNeutralHeavy.hover, }); - expect(StyleSheet.flatten(component.getByTestId('checkbox-label').props.style).color).toBe(colors.hover.foregroundNeutralSecondary); + expect(StyleSheet.flatten(component.getByTestId('checkbox-label').props.style).color).toBe(colors.foregroundNeutralSecondary.hover); await fireEvent(root, 'pressIn', {}); expect(getIndicatorStyle(component)).toMatchObject({ - backgroundColor: colors.pressed.backgroundNeutralTransparent, - borderColor: colors.pressed.strokeNeutralHeavy, + backgroundColor: colors.backgroundNeutralTransparent.pressed, + borderColor: colors.strokeNeutralHeavy.pressed, }); - expect(StyleSheet.flatten(component.getByTestId('checkbox-label').props.style).color).toBe(colors.pressed.foregroundNeutralSecondary); + expect(StyleSheet.flatten(component.getByTestId('checkbox-label').props.style).color).toBe(colors.foregroundNeutralSecondary.pressed); }); it('uses native focus visuals without mounting custom rings', async () => { @@ -299,14 +299,14 @@ describe('Checkbox', () => { const component = await renderCheckbox({ label: status, status }); const label = component.getByTestId('checkbox-label'); const indicator = component.getByTestId('checkbox-indicator'); - const expectedBackground = status === 'unchecked' ? colors.backgroundNeutralTransparent : colors.backgroundBrandHeavy; - const expectedLabelColor = status === 'unchecked' ? colors.foregroundNeutralSecondary : colors.foregroundNeutralPrimary; + const expectedBackground = status === 'unchecked' ? colors.backgroundNeutralTransparent.rest : colors.backgroundBrandHeavy.rest; + const expectedLabelColor = status === 'unchecked' ? colors.foregroundNeutralSecondary.rest : colors.foregroundNeutralPrimary.rest; expect(StyleSheet.flatten(indicator.props.style).backgroundColor).toBe(expectedBackground); expect(StyleSheet.flatten(label.props.style).color).toBe(expectedLabelColor); if (status !== 'unchecked') { const icon = component.getByText(status === 'indeterminate' ? '\u2212' : '\u2713'); - expect(StyleSheet.flatten(icon.props.style).color).toBe(colors.foregroundBrandOnloud); + expect(StyleSheet.flatten(icon.props.style).color).toBe(colors.foregroundBrandOnloud.rest); } }); @@ -326,10 +326,10 @@ describe('Checkbox', () => { const tokens = defaultFlexTokens.color; expect(StyleSheet.flatten(component.getByTestId('checkbox-indicator').props.style)).toMatchObject({ - backgroundColor: tokens.backgroundNeutralHeavyDisabled, - borderColor: tokens.strokeNeutralTransparent, + backgroundColor: tokens.backgroundNeutralHeavyDisabled.rest, + borderColor: tokens.strokeNeutralTransparent.rest, }); - expect(StyleSheet.flatten(component.getByTestId('checkbox-label').props.style).color).toBe(tokens.foregroundNeutralDisabled); + expect(StyleSheet.flatten(component.getByTestId('checkbox-label').props.style).color).toBe(tokens.foregroundNeutralDisabled.rest); }); describe('SPEC regression coverage', () => { diff --git a/packages/agentic/components/src/components/checkbox/spec/tokens.yaml b/packages/agentic/components/src/components/checkbox/spec/tokens.yaml index 92401fb009..d68ae06cbc 100644 --- a/packages/agentic/components/src/components/checkbox/spec/tokens.yaml +++ b/packages/agentic/components/src/components/checkbox/spec/tokens.yaml @@ -3,9 +3,9 @@ component: checkbox implementation: checkbox.styles.ts # Interaction colors are declared once per status. The `hovered` and `pressed` -# entries resolve the same semantic color key through the `color.hover` and -# `color.pressed` sub-palettes, so no separate interaction token names appear -# in the definitions below. +# entries read the `hover` and `pressed` states of the same resolved semantic +# color, so no separate interaction token names appear in the definitions +# below. statePrecedence: - status - disabled diff --git a/packages/agentic/components/src/components/divider/divider.styles.ts b/packages/agentic/components/src/components/divider/divider.styles.ts index 974b58c246..191e5679be 100644 --- a/packages/agentic/components/src/components/divider/divider.styles.ts +++ b/packages/agentic/components/src/components/divider/divider.styles.ts @@ -74,14 +74,14 @@ function createLabelStyleDefinition({ return { horizontal: { - color: color.foregroundNeutralSecondary, + color: color.foregroundNeutralSecondary.rest, fontFamily: fontFamily.functional, fontSize: bodySmallSize, fontWeight: fontWeight.functionalRegular, lineHeight: bodySmallLineHeight, }, vertical: { - color: color.foregroundNeutralSecondary, + color: color.foregroundNeutralSecondary.rest, fontFamily: fontFamily.functional, fontSize: bodySmallSize, fontWeight: fontWeight.functionalRegular, @@ -102,7 +102,7 @@ export function getDividerLineStyle(state: DividerState, position: 'before' | 'a const lineThickness = Number(state.tokens.strokeWidth.thin); return { - backgroundColor: state.tokens.color.strokeNeutralSubtle, + backgroundColor: state.tokens.color.strokeNeutralSubtle.rest, ...(state.vertical ? { width: lineThickness } : { height: lineThickness }), flexBasis, flexGrow: isStub ? 0 : 1, diff --git a/packages/agentic/components/src/components/divider/divider.test.tsx b/packages/agentic/components/src/components/divider/divider.test.tsx index 17bb3673d5..f25e9d2201 100644 --- a/packages/agentic/components/src/components/divider/divider.test.tsx +++ b/packages/agentic/components/src/components/divider/divider.test.tsx @@ -118,12 +118,12 @@ describe('Divider', () => { const afterExpected = layout === 'end' ? { flexBasis: stub, flexGrow: 0 } : { flexBasis: 0, flexGrow: 1 }; expect(StyleSheet.flatten(beforeLine.props.style)).toMatchObject({ - backgroundColor: tokens.color.strokeNeutralSubtle, + backgroundColor: tokens.color.strokeNeutralSubtle.rest, height: tokens.strokeWidth.thin, ...beforeExpected, }); expect(StyleSheet.flatten(afterLine.props.style)).toMatchObject({ - backgroundColor: tokens.color.strokeNeutralSubtle, + backgroundColor: tokens.color.strokeNeutralSubtle.rest, height: tokens.strokeWidth.thin, ...afterExpected, }); @@ -142,7 +142,7 @@ describe('Divider', () => { expect(StyleSheet.flatten(root.props.style)).toMatchObject({ flexDirection: 'column' }); expect(StyleSheet.flatten(beforeLine.props.style)).toMatchObject({ - backgroundColor: tokens.color.strokeNeutralSubtle, + backgroundColor: tokens.color.strokeNeutralSubtle.rest, width: tokens.strokeWidth.thin, flexGrow: 1, }); @@ -151,7 +151,7 @@ describe('Divider', () => { paddingVertical: tokens.spacing.componentBase300, }); expect(StyleSheet.flatten(component.getByText('Section').props.style)).toMatchObject({ - color: tokens.color.foregroundNeutralSecondary, + color: tokens.color.foregroundNeutralSecondary.rest, fontFamily: tokens.fontFamily.functional, fontSize: tokens.fontSize.functionalBodySmall, lineHeight: tokens.lineHeight.functionalBodySmall, diff --git a/packages/agentic/components/src/components/divider/useDividerStyles.ts b/packages/agentic/components/src/components/divider/useDividerStyles.ts index 26632d4e92..9ef070644d 100644 --- a/packages/agentic/components/src/components/divider/useDividerStyles.ts +++ b/packages/agentic/components/src/components/divider/useDividerStyles.ts @@ -27,7 +27,7 @@ export function useDividerStyles_unstable(state: DividerState) { if (state.icon) { attachSlotProps(state.icon, { accessible: false, - color: state.tokens.color.foregroundNeutralSecondary, + color: state.tokens.color.foregroundNeutralSecondary.rest, height: 20, width: 20, }); diff --git a/packages/agentic/components/src/components/dropdown/dropdown.styles.ts b/packages/agentic/components/src/components/dropdown/dropdown.styles.ts index 18df1099b8..9b69ba200b 100644 --- a/packages/agentic/components/src/components/dropdown/dropdown.styles.ts +++ b/packages/agentic/components/src/components/dropdown/dropdown.styles.ts @@ -38,8 +38,8 @@ export const dropdownStyles = StyleSheet.create({ export const getDropdownThemeStyles = themedStyleSheetFactory('Dropdown.listbox', ({ tokens }) => StyleSheet.create({ surface: { - backgroundColor: tokens.color.surfaceNeutralNearer, - borderColor: tokens.color.strokeNeutralSubtle, + backgroundColor: tokens.color.surfaceNeutralNearer.rest, + borderColor: tokens.color.strokeNeutralSubtle.rest, borderRadius: tokens.borderRadius.base400, borderStyle: 'solid', borderWidth: tokens.strokeWidth.thin, @@ -51,10 +51,10 @@ export const getDropdownThemeStyles = themedStyleSheetFactory('Dropdown.listbox' /** The chevron is disabled when disabled, primary in error or while the focus indicator shows, and secondary otherwise. */ export function getDropdownChevronColor(tokens: FlexTokens, visualState: InputVisualState, focusVisible: boolean): ColorValue { if (visualState === 'disabled') { - return tokens.color.foregroundNeutralDisabled; + return tokens.color.foregroundNeutralDisabled.rest; } if (visualState === 'error' || focusVisible) { - return tokens.color.foregroundNeutralPrimary; + return tokens.color.foregroundNeutralPrimary.rest; } - return tokens.color.foregroundNeutralSecondary; + return tokens.color.foregroundNeutralSecondary.rest; } diff --git a/packages/agentic/components/src/components/input/input.styles.ts b/packages/agentic/components/src/components/input/input.styles.ts index adcf3bc903..e349cd2cbd 100644 --- a/packages/agentic/components/src/components/input/input.styles.ts +++ b/packages/agentic/components/src/components/input/input.styles.ts @@ -168,22 +168,22 @@ function createContentsStrokeDefinition(tokens: FlexTokens): StyleDefinition; const underlineStates = { - disabled: { borderBottomColor: color.strokeNeutralDisabled }, - error: { borderBottomColor: color.strokeDangerLoud }, - focused: { borderBottomColor: color.strokeFocusOuter }, - hovered: { borderBottomColor: color.hover.strokeNeutralLoud }, - pressed: { borderBottomColor: color.pressed.strokeNeutralLoud }, - readOnly: { borderBottomColor: color.strokeNeutralDisabled }, - rest: { borderBottomColor: color.strokeNeutralLoud }, + disabled: { borderBottomColor: color.strokeNeutralDisabled.rest }, + error: { borderBottomColor: color.strokeDangerLoud.rest }, + focused: { borderBottomColor: color.strokeFocusOuter.rest }, + hovered: { borderBottomColor: color.strokeNeutralLoud.hover }, + pressed: { borderBottomColor: color.strokeNeutralLoud.pressed }, + readOnly: { borderBottomColor: color.strokeNeutralDisabled.rest }, + rest: { borderBottomColor: color.strokeNeutralLoud.rest }, } satisfies Record; function createSizeBranch(base: ViewStyle, states: Record) { @@ -254,7 +254,7 @@ function createTextInputDefinition(tokens: FlexTokens): StyleDefinition { expect(onFocus).toHaveBeenCalledTimes(1); expect(onChangeText).toHaveBeenCalledWith('hello'); expect(flattenStyle(getContents(component).props.style)).toMatchObject({ - borderColor: colors.strokeNeutralSubtle, + borderColor: colors.strokeNeutralSubtle.rest, }); }); @@ -215,7 +215,7 @@ describe('Input', () => { expect(textbox.props.editable).toBe(false); expect(textbox.props.accessibilityState).toMatchObject({ disabled: true, readOnly: false }); expect(flattenStyle(getContents(component).props.style)).toMatchObject({ - borderColor: colors.strokeNeutralDisabled, + borderColor: colors.strokeNeutralDisabled.rest, }); await fireEvent.changeText(textbox, 'blocked'); @@ -230,7 +230,7 @@ describe('Input', () => { expect(textbox.props.editable).toBe(false); expect(textbox.props.accessibilityState).toMatchObject({ disabled: false, readOnly: true }); expect(flattenStyle(getContents(component).props.style)).toMatchObject({ - borderColor: colors.strokeNeutralDisabled, + borderColor: colors.strokeNeutralDisabled.rest, }); }); @@ -271,21 +271,21 @@ describe('Input', () => { } expect(flattenStyle(indicator.props.style).opacity).not.toBe(0); const boundary = props.error - ? colors.strokeDangerLoud + ? colors.strokeDangerLoud.rest : props.readOnly - ? colors.strokeNeutralDisabled + ? colors.strokeNeutralDisabled.rest : props.variant === 'outline' - ? colors.strokeNeutralSubtle - : colors.strokeFocusOuter; + ? colors.strokeNeutralSubtle.rest + : colors.strokeFocusOuter.rest; if (props.variant === 'outline') { expect(flattenStyle(getContents(component).props.style).borderColor).toBe(boundary); expect(flattenStyle(indicator.props.style)).toMatchObject({ - borderColor: colors.strokeFocusOuter, + borderColor: colors.strokeFocusOuter.rest, borderWidth: defaultFlexTokens.strokeWidth.thick, }); const inner = component.getByTestId('focus-visual-inner', { includeHiddenElements: true }); expect(flattenStyle(inner.props.style)).toMatchObject({ - borderColor: colors.strokeFocusInner, + borderColor: colors.strokeFocusInner.rest, borderWidth: defaultFlexTokens.strokeWidth.thin, }); } else { @@ -295,7 +295,7 @@ describe('Input', () => { borderBottomWidth: defaultFlexTokens.strokeWidth.thin, }); expect(flattenStyle(indicator.props.style)).toMatchObject({ - borderBottomColor: colors.strokeFocusOuter, + borderBottomColor: colors.strokeFocusOuter.rest, borderBottomWidth: defaultFlexTokens.strokeWidth.thin, bottom: defaultFlexTokens.strokeWidth.thin, }); @@ -327,7 +327,7 @@ describe('Input', () => { width: 24, }); expect(flattenStyle(component.getByText('\u2605').props.style)).toMatchObject({ - color: colors.foregroundNeutralPrimary, + color: colors.foregroundNeutralPrimary.rest, }); expect(component.getByTestId('icon-end-1').props.style).toMatchObject({ height: 24, width: 24 }); expect(component.getByTestId('icon-end-2').props.style).toMatchObject({ height: 24, width: 24 }); diff --git a/packages/agentic/components/src/components/input/spec/tokens.yaml b/packages/agentic/components/src/components/input/spec/tokens.yaml index 490dd22a47..8c9be6f7b0 100644 --- a/packages/agentic/components/src/components/input/spec/tokens.yaml +++ b/packages/agentic/components/src/components/input/spec/tokens.yaml @@ -56,8 +56,8 @@ bindings: focused: outline: color.strokeNeutralSubtle underline: color.strokeFocusOuter - pressed: color.pressed.strokeNeutralLoud - hovered: color.hover.strokeNeutralLoud + pressed: color.strokeNeutralLoud.pressed + hovered: color.strokeNeutralLoud.hover rest: color.strokeNeutralLoud iconTextStack: diff --git a/packages/agentic/components/src/components/list-item/list-item.test.tsx b/packages/agentic/components/src/components/list-item/list-item.test.tsx index 90945f3bc9..8fcd5de26f 100644 --- a/packages/agentic/components/src/components/list-item/list-item.test.tsx +++ b/packages/agentic/components/src/components/list-item/list-item.test.tsx @@ -104,7 +104,7 @@ describe('ListItem', () => { await fireEvent(root, 'hoverIn', {}); expect(onHoverIn).toHaveBeenCalledTimes(1); - expect(getRootStyle(component).backgroundColor).toBe(colors.hover.backgroundNeutralTransparent); + expect(getRootStyle(component).backgroundColor).toBe(colors.backgroundNeutralTransparent.hover); await fireEvent(root, 'pressIn', {}); expect(onPress).toHaveBeenCalledTimes(0); @@ -137,7 +137,7 @@ describe('ListItem', () => { const component = await renderListItem({ content: 'Selected', selectionMode: 'multiple', selected: true }); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: colors.backgroundNeutralTransparent, + backgroundColor: colors.backgroundNeutralTransparent.rest, }); }); diff --git a/packages/agentic/components/src/components/listbox-item/listbox-item.styles.ts b/packages/agentic/components/src/components/listbox-item/listbox-item.styles.ts index e33430c0b1..df19711c22 100644 --- a/packages/agentic/components/src/components/listbox-item/listbox-item.styles.ts +++ b/packages/agentic/components/src/components/listbox-item/listbox-item.styles.ts @@ -64,18 +64,18 @@ export const listboxItemStyles = StyleSheet.create({ function getColor(state: ListboxItemState, key: 'primary' | 'secondary'): ViewStyle['backgroundColor'] { const colors = state.tokens.color; if (state.disabled) { - return colors.foregroundNeutralDisabled; + return colors.foregroundNeutralDisabled.rest; } if (state.pressed) { - return key === 'primary' ? colors.pressed.foregroundNeutralPrimary : colors.pressed.foregroundNeutralSecondary; + return key === 'primary' ? colors.foregroundNeutralPrimary.pressed : colors.foregroundNeutralSecondary.pressed; } if (state.hovered) { - return key === 'primary' ? colors.hover.foregroundNeutralPrimary : colors.hover.foregroundNeutralSecondary; + return key === 'primary' ? colors.foregroundNeutralPrimary.hover : colors.foregroundNeutralSecondary.hover; } if (key === 'secondary' && state.variant === 'listItem' && state.selected && !state.multiselect) { - return colors.foregroundNeutralPrimary; + return colors.foregroundNeutralPrimary.rest; } - return key === 'primary' ? colors.foregroundNeutralPrimary : colors.foregroundNeutralSecondary; + return key === 'primary' ? colors.foregroundNeutralPrimary.rest : colors.foregroundNeutralSecondary.rest; } function getLabelWeight(state: ListboxItemState): TextStyle['fontWeight'] { @@ -89,19 +89,19 @@ export function getListboxItemRootStyle(state: ListboxItemState): ViewStyle { const selected = state.variant === 'listItem' && state.selected && !state.multiselect; const backgroundColor = state.disabled ? selected - ? colors.backgroundNeutralSubtleDisabled - : colors.backgroundNeutralTransparent + ? colors.backgroundNeutralSubtleDisabled.rest + : colors.backgroundNeutralTransparent.rest : state.pressed ? selected - ? colors.pressed.backgroundNeutralSoft - : colors.pressed.backgroundNeutralTransparent + ? colors.backgroundNeutralSoft.pressed + : colors.backgroundNeutralTransparent.pressed : state.hovered ? selected - ? colors.hover.backgroundNeutralSoft - : colors.hover.backgroundNeutralTransparent + ? colors.backgroundNeutralSoft.hover + : colors.backgroundNeutralTransparent.hover : selected - ? colors.backgroundNeutralSoft - : colors.backgroundNeutralTransparent; + ? colors.backgroundNeutralSoft.rest + : colors.backgroundNeutralTransparent.rest; return { backgroundColor, @@ -114,7 +114,7 @@ export function getListboxItemRootStyle(state: ListboxItemState): ViewStyle { export function getListboxItemHeaderStyle(state: ListboxItemState): ViewStyle { return { - backgroundColor: state.tokens.color.backgroundNeutralTransparent, + backgroundColor: state.tokens.color.backgroundNeutralTransparent.rest, borderRadius: state.tokens.borderRadius.base300, minHeight: 40, paddingHorizontal: state.tokens.spacing.componentBase300, diff --git a/packages/agentic/components/src/components/listbox-item/listbox-item.test.tsx b/packages/agentic/components/src/components/listbox-item/listbox-item.test.tsx index 94df9b8000..a0a3d56622 100644 --- a/packages/agentic/components/src/components/listbox-item/listbox-item.test.tsx +++ b/packages/agentic/components/src/components/listbox-item/listbox-item.test.tsx @@ -117,7 +117,7 @@ describe('ListboxItem', () => { const component = await renderListboxItem({ content: 'Choice', multiselect: true, selected: true }); const root = component.getByRole('button'); - expect(StyleSheet.flatten(root.props.style).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralTransparent); + expect(StyleSheet.flatten(root.props.style).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralTransparent.rest); expect(StyleSheet.flatten(component.getByText('Choice').props.style).fontWeight).toBe(defaultFlexTokens.fontWeight.functionalRegular); expect(component.getByText('✓')).toBeOnTheScreen(); }); @@ -147,16 +147,16 @@ describe('ListboxItem', () => { const component = await renderListboxItem({ content: 'Choice' }); const root = component.getByRole('button'); await fireEvent(root, 'hoverIn', {}); - expect(StyleSheet.flatten(root.props.style).backgroundColor).toBe(defaultFlexTokens.color.hover.backgroundNeutralTransparent); + expect(StyleSheet.flatten(root.props.style).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralTransparent.hover); await fireEvent(root, 'pressIn', {}); - expect(StyleSheet.flatten(root.props.style).backgroundColor).toBe(defaultFlexTokens.color.pressed.backgroundNeutralTransparent); + expect(StyleSheet.flatten(root.props.style).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralTransparent.pressed); await fireEvent(root, 'focus', {}); expect(root.props.enableFocusRing).toBe(true); expect(component.queryByTestId('focus-visual', { includeHiddenElements: true })).toBeNull(); expect(StyleSheet.flatten(root.props.style)).not.toMatchObject({ - outlineColor: defaultFlexTokens.color.strokeFocusOuter, + outlineColor: defaultFlexTokens.color.strokeFocusOuter.rest, outlineStyle: 'solid', }); }); diff --git a/packages/agentic/components/src/components/listbox-item/useListboxItemStyles.ts b/packages/agentic/components/src/components/listbox-item/useListboxItemStyles.ts index 906dfbe2e3..1d713000ad 100644 --- a/packages/agentic/components/src/components/listbox-item/useListboxItemStyles.ts +++ b/packages/agentic/components/src/components/listbox-item/useListboxItemStyles.ts @@ -90,7 +90,7 @@ export function useListboxItemStyles_unstable(state: ListboxItemState) { if (state.chevronIndicator) { attachSlotProps(state.chevronIndicator, { accessible: false, - color: state.tokens.color.foregroundNeutralPrimary, + color: state.tokens.color.foregroundNeutralPrimary.rest, height: getListboxItemIconSize(), width: getListboxItemIconSize(), }); @@ -99,7 +99,7 @@ export function useListboxItemStyles_unstable(state: ListboxItemState) { if (state.checkmarkIndicator) { attachSlotProps(state.checkmarkIndicator, { accessible: false, - color: state.tokens.color.foregroundNeutralPrimary, + color: state.tokens.color.foregroundNeutralPrimary.rest, height: getListboxItemCheckmarkSize(), width: getListboxItemCheckmarkSize(), }); @@ -107,14 +107,16 @@ export function useListboxItemStyles_unstable(state: ListboxItemState) { if (state.checkboxIndicator) { attachSlotProps(state.checkboxIndicator, { - iconColor: state.tokens.color.foregroundNeutralOnloud, + iconColor: state.tokens.color.foregroundNeutralOnloud.rest, iconSize: 12, status: state.selected ? 'checked' : 'unchecked', style: [ listboxItemStyles.checkboxBox, { - backgroundColor: state.selected ? state.tokens.color.backgroundBrandHeavy : state.tokens.color.backgroundNeutralTransparent, - borderColor: state.selected ? state.tokens.color.backgroundBrandHeavy : state.tokens.color.foregroundNeutralSecondary, + backgroundColor: state.selected + ? state.tokens.color.backgroundBrandHeavy.rest + : state.tokens.color.backgroundNeutralTransparent.rest, + borderColor: state.selected ? state.tokens.color.backgroundBrandHeavy.rest : state.tokens.color.foregroundNeutralSecondary.rest, height: getListboxItemCheckmarkSize(), width: getListboxItemCheckmarkSize(), }, diff --git a/packages/agentic/components/src/components/menu-item/menu-item.styles.ts b/packages/agentic/components/src/components/menu-item/menu-item.styles.ts index 7f84efe1bf..e472c214e4 100644 --- a/packages/agentic/components/src/components/menu-item/menu-item.styles.ts +++ b/packages/agentic/components/src/components/menu-item/menu-item.styles.ts @@ -289,8 +289,8 @@ export function getMenuItemCheckboxStyle(state: MenuItemState): ViewStyle { const colors = state.tokens.color; return { alignItems: 'center', - backgroundColor: state.selected ? colors.backgroundBrandHeavy : colors.backgroundNeutralTransparent, - borderColor: state.selected ? colors.backgroundBrandHeavy : colors.strokeNeutralLoud, + backgroundColor: state.selected ? colors.backgroundBrandHeavy.rest : colors.backgroundNeutralTransparent.rest, + borderColor: state.selected ? colors.backgroundBrandHeavy.rest : colors.strokeNeutralLoud.rest, borderRadius: 4, borderWidth: 1, height: size160, diff --git a/packages/agentic/components/src/components/menu-item/useMenuItemStyles.ts b/packages/agentic/components/src/components/menu-item/useMenuItemStyles.ts index 7b06dbd23f..1b73b28919 100644 --- a/packages/agentic/components/src/components/menu-item/useMenuItemStyles.ts +++ b/packages/agentic/components/src/components/menu-item/useMenuItemStyles.ts @@ -65,7 +65,7 @@ export function useMenuItemStyles_unstable(state: MenuItemState) { if (state.checkmark) { attachSlotProps(state.checkmark, { accessible: false, - color: state.hasMultiselect ? state.tokens.color.foregroundBrandOnloud : labelColor, + color: state.hasMultiselect ? state.tokens.color.foregroundBrandOnloud.rest : labelColor, height: state.hasMultiselect ? 12 : 16, style: state.selected ? undefined : { opacity: 0 }, width: state.hasMultiselect ? 12 : 16, @@ -75,7 +75,7 @@ export function useMenuItemStyles_unstable(state: MenuItemState) { if (state.multiselectCheckbox) { attachSlotProps(state.multiselectCheckbox, { ...hiddenFromAccessibilityProps, - iconColor: state.tokens.color.foregroundBrandOnloud, + iconColor: state.tokens.color.foregroundBrandOnloud.rest, iconSize: 12, status: state.selected ? 'checked' : 'unchecked', style: [menuItemStyles.multiselectCheckbox, getMenuItemCheckboxStyle(state), getMenuItemTrailingStyle(state)], diff --git a/packages/agentic/components/src/components/menu/menu.styles.ts b/packages/agentic/components/src/components/menu/menu.styles.ts index 05eabf96f9..0f3b4588b2 100644 --- a/packages/agentic/components/src/components/menu/menu.styles.ts +++ b/packages/agentic/components/src/components/menu/menu.styles.ts @@ -14,8 +14,8 @@ export const menuStyles = StyleSheet.create({ export const getMenuThemeStyles = themedStyleSheetFactory('Menu.surface', ({ tokens }) => StyleSheet.create({ surface: { - backgroundColor: tokens.color.surfaceNeutralNearer, - borderColor: tokens.color.strokeNeutralSubtle, + backgroundColor: tokens.color.surfaceNeutralNearer.rest, + borderColor: tokens.color.strokeNeutralSubtle.rest, borderRadius: tokens.borderRadius.base400, borderStyle: 'solid', borderWidth: tokens.strokeWidth.thin, diff --git a/packages/agentic/components/src/components/popover/popover.styles.ts b/packages/agentic/components/src/components/popover/popover.styles.ts index 09f3f03273..0412d0f686 100644 --- a/packages/agentic/components/src/components/popover/popover.styles.ts +++ b/packages/agentic/components/src/components/popover/popover.styles.ts @@ -13,8 +13,8 @@ export const popoverStyles = StyleSheet.create({ export const getPopoverThemeStyles = themedStyleSheetFactory('Popover.surface', ({ tokens }) => StyleSheet.create({ surface: { - backgroundColor: tokens.color.surfaceNeutralNearer, - borderColor: tokens.color.strokeNeutralSubtle, + backgroundColor: tokens.color.surfaceNeutralNearer.rest, + borderColor: tokens.color.strokeNeutralSubtle.rest, borderRadius: tokens.borderRadius.base400, borderStyle: 'solid', borderWidth: tokens.strokeWidth.thin, diff --git a/packages/agentic/components/src/components/progress-bar/progress-bar.styles.ts b/packages/agentic/components/src/components/progress-bar/progress-bar.styles.ts index fedb0564bc..9f56aed59a 100644 --- a/packages/agentic/components/src/components/progress-bar/progress-bar.styles.ts +++ b/packages/agentic/components/src/components/progress-bar/progress-bar.styles.ts @@ -35,7 +35,7 @@ export function getProgressBarThemeStyles(themeState: ThemeState): ProgressBarTh minWidth: 0, }, indicator: { - backgroundColor: color.foregroundBrandPrimary, + backgroundColor: color.foregroundBrandPrimary.rest, borderRadius: cornerRadiusCircular, bottom: 0, left: 0, @@ -43,7 +43,7 @@ export function getProgressBarThemeStyles(themeState: ThemeState): ProgressBarTh top: 0, }, label: { - color: color.foregroundNeutralPrimary, + color: color.foregroundNeutralPrimary.rest, flexGrow: 1, flexShrink: 1, fontFamily: fontFamily.functional, @@ -62,7 +62,7 @@ export function getProgressBarThemeStyles(themeState: ThemeState): ProgressBarTh gap: getGapStyleValue(spacing.componentBase100), }, track: { - backgroundColor: color.backgroundNeutralSoft, + backgroundColor: color.backgroundNeutralSoft.rest, borderRadius: cornerRadiusCircular, height: spacing.componentBase100, overflow: 'hidden', @@ -73,7 +73,7 @@ export function getProgressBarThemeStyles(themeState: ThemeState): ProgressBarTh width: size160, }, valueText: { - color: color.foregroundNeutralSecondary, + color: color.foregroundNeutralSecondary.rest, fontFamily: fontFamily.functional, fontSize: fontSize.functionalBodySmall, lineHeight: lineHeight.functionalBodySmall, diff --git a/packages/agentic/components/src/components/progress-bar/useProgressBar.ts b/packages/agentic/components/src/components/progress-bar/useProgressBar.ts index 18dd793e57..df07f3dc18 100644 --- a/packages/agentic/components/src/components/progress-bar/useProgressBar.ts +++ b/packages/agentic/components/src/components/progress-bar/useProgressBar.ts @@ -29,12 +29,12 @@ function getStatusColor(themeState: ReturnType, status: Pr const { color } = themeState.tokens; switch (status) { case 'error': - return color.foregroundDangerPrimary; + return color.foregroundDangerPrimary.rest; case 'success': - return color.foregroundSuccessPrimary; + return color.foregroundSuccessPrimary.rest; case 'neutral': default: - return color.foregroundBrandPrimary; + return color.foregroundBrandPrimary.rest; } } diff --git a/packages/agentic/components/src/components/radio/radio.styles.ts b/packages/agentic/components/src/components/radio/radio.styles.ts index f1b1ffa335..5102e4f458 100644 --- a/packages/agentic/components/src/components/radio/radio.styles.ts +++ b/packages/agentic/components/src/components/radio/radio.styles.ts @@ -50,7 +50,7 @@ const toDimensionValue = (value: unknown): number => Number(getNumericStyleValue const getRadioRootLayoutStyle = getThemedStateStyleFactory( 'Radio.rootLayout', ({ borderRadius, color, spacing }: FlexTokens): StyleDefinition => ({ - backgroundColor: color.backgroundNeutralTransparent, + backgroundColor: color.backgroundNeutralTransparent.rest, borderRadius: borderRadius.base300, gap: toDimensionValue(spacing.componentBase100), }), @@ -60,7 +60,7 @@ const getRadioRootLayoutStyle = getThemedStateStyleFactory( const getRadioIndicatorLayoutStyle = getThemedStateStyleFactory( 'Radio.indicatorLayout', ({ color, spacing, strokeWidth }: FlexTokens): StyleDefinition => ({ - backgroundColor: color.backgroundNeutralTransparent, + backgroundColor: color.backgroundNeutralTransparent.rest, borderRadius: 8, borderStyle: 'solid', borderWidth: strokeWidth.thin, diff --git a/packages/agentic/components/src/components/radio/radio.test.tsx b/packages/agentic/components/src/components/radio/radio.test.tsx index db83b7fe2b..4c03cf8d7c 100644 --- a/packages/agentic/components/src/components/radio/radio.test.tsx +++ b/packages/agentic/components/src/components/radio/radio.test.tsx @@ -67,26 +67,26 @@ describe('Radio', () => { expect(getRootStyle(component)).toMatchObject({ alignItems: 'center', - backgroundColor: tokens.color.backgroundNeutralTransparent, + backgroundColor: tokens.color.backgroundNeutralTransparent.rest, borderRadius: tokens.borderRadius.base300, gap: tokens.spacing.componentBase100, }); expect(StyleSheet.flatten(getTestId(component, 'radio-indicator').props.style)).toMatchObject({ - backgroundColor: tokens.color.backgroundNeutralTransparent, - borderColor: tokens.color.strokeNeutralHeavy, + backgroundColor: tokens.color.backgroundNeutralTransparent.rest, + borderColor: tokens.color.strokeNeutralHeavy.rest, borderStyle: 'solid', borderWidth: tokens.strokeWidth.thin, height: 16, width: 16, }); expect(StyleSheet.flatten(getTestId(component, 'radio-dot').props.style)).toMatchObject({ - backgroundColor: tokens.color.foregroundBrandPrimary, + backgroundColor: tokens.color.foregroundBrandPrimary.rest, height: 10, opacity: 0, width: 10, }); expect(StyleSheet.flatten(getText(component, 'Choice').props.style)).toMatchObject({ - color: tokens.color.foregroundNeutralSecondary, + color: tokens.color.foregroundNeutralSecondary.rest, fontSize: expect.any(Number), }); }); @@ -97,12 +97,12 @@ describe('Radio', () => { const root = getRoot(component); expect(root.props.accessibilityState).toEqual({ checked: true, selected: true, disabled: false }); - expect(StyleSheet.flatten(getTestId(component, 'radio-indicator').props.style).borderColor).toBe(tokens.strokeBrandLoud); + expect(StyleSheet.flatten(getTestId(component, 'radio-indicator').props.style).borderColor).toBe(tokens.strokeBrandLoud.rest); expect(StyleSheet.flatten(getTestId(component, 'radio-dot').props.style)).toMatchObject({ - backgroundColor: tokens.foregroundBrandPrimary, + backgroundColor: tokens.foregroundBrandPrimary.rest, opacity: 1, }); - expect(StyleSheet.flatten(getText(component, 'Choice').props.style).color).toBe(tokens.foregroundNeutralPrimary); + expect(StyleSheet.flatten(getText(component, 'Choice').props.style).color).toBe(tokens.foregroundNeutralPrimary.rest); }); it('updates interaction colors on hover and press', async () => { @@ -111,12 +111,12 @@ describe('Radio', () => { const root = getRoot(component); await fireEvent(root, 'hoverIn', {}); - expect(StyleSheet.flatten(getTestId(component, 'radio-indicator').props.style).borderColor).toBe(tokens.hover.strokeNeutralHeavy); - expect(StyleSheet.flatten(getText(component, 'Choice').props.style).color).toBe(tokens.hover.foregroundNeutralSecondary); + expect(StyleSheet.flatten(getTestId(component, 'radio-indicator').props.style).borderColor).toBe(tokens.strokeNeutralHeavy.hover); + expect(StyleSheet.flatten(getText(component, 'Choice').props.style).color).toBe(tokens.foregroundNeutralSecondary.hover); await fireEvent(root, 'pressIn', {}); - expect(StyleSheet.flatten(getTestId(component, 'radio-indicator').props.style).borderColor).toBe(tokens.pressed.strokeNeutralHeavy); - expect(StyleSheet.flatten(getText(component, 'Choice').props.style).color).toBe(tokens.pressed.foregroundNeutralSecondary); + expect(StyleSheet.flatten(getTestId(component, 'radio-indicator').props.style).borderColor).toBe(tokens.strokeNeutralHeavy.pressed); + expect(StyleSheet.flatten(getText(component, 'Choice').props.style).color).toBe(tokens.foregroundNeutralSecondary.pressed); }); it('uses native focus visuals without mounting custom rings', async () => { diff --git a/packages/agentic/components/src/components/skeleton/skeleton.stories.tsx b/packages/agentic/components/src/components/skeleton/skeleton.stories.tsx index 48e16b99af..878b24042c 100644 --- a/packages/agentic/components/src/components/skeleton/skeleton.stories.tsx +++ b/packages/agentic/components/src/components/skeleton/skeleton.stories.tsx @@ -59,7 +59,7 @@ type Story = WdioStory>; function MotionExample() { const reduceMotion = useReducedMotion(); - const highlightColor: unknown = useThemeState().tokens.color.backgroundNeutralSubtle; + const highlightColor: unknown = useThemeState().tokens.color.backgroundNeutralSubtle.rest; return ( diff --git a/packages/agentic/components/src/components/skeleton/skeleton.styles.ts b/packages/agentic/components/src/components/skeleton/skeleton.styles.ts index 7ec3b201c6..d5470522a7 100644 --- a/packages/agentic/components/src/components/skeleton/skeleton.styles.ts +++ b/packages/agentic/components/src/components/skeleton/skeleton.styles.ts @@ -23,12 +23,12 @@ export const skeletonStyles = StyleSheet.create({ }); export const getSkeletonThemeStyles = themedStyleSheetFactory('Skeleton', ({ tokens }: ThemeState) => { - const opaqueHighlight = typeof tokens.color.backgroundNeutralSubtle !== 'string'; + const opaqueHighlight = typeof tokens.color.backgroundNeutralSubtle.rest !== 'string'; return StyleSheet.create({ root: { - backgroundColor: tokens.color.backgroundNeutralSoft, + backgroundColor: tokens.color.backgroundNeutralSoft.rest, borderRadius: tokens.borderRadius.base100, - ...(opaqueHighlight ? { borderColor: tokens.color.strokeNeutralLoud, borderWidth: Number(tokens.strokeWidth.thin) } : {}), + ...(opaqueHighlight ? { borderColor: tokens.color.strokeNeutralLoud.rest, borderWidth: Number(tokens.strokeWidth.thin) } : {}), }, }); }); diff --git a/packages/agentic/components/src/components/skeleton/skeleton.test.tsx b/packages/agentic/components/src/components/skeleton/skeleton.test.tsx index f24ed96c22..2ec51ec169 100644 --- a/packages/agentic/components/src/components/skeleton/skeleton.test.tsx +++ b/packages/agentic/components/src/components/skeleton/skeleton.test.tsx @@ -154,7 +154,7 @@ describe('Skeleton', () => { y2: bandWidth / 2, }); expect(gradient.props.x2 - gradient.props.x1).toBe(gradient.props.y2 - gradient.props.y1); - const color = processColor(defaultFlexTokens.color.backgroundNeutralSubtle); + const color = processColor(defaultFlexTokens.color.backgroundNeutralSubtle.rest); if (typeof color !== 'number') { throw new Error('The test theme must supply a concrete SVG highlight color.'); } @@ -220,8 +220,8 @@ describe('Skeleton', () => { }); expect(component.queryByTestId('skeleton-shimmer', { includeHiddenElements: true })).toBeNull(); - expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralSoft); - expect(getRootStyle(component).backgroundColor).not.toBe(defaultFlexTokens.color.backgroundNeutralSubtle); + expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralSoft.rest); + expect(getRootStyle(component).backgroundColor).not.toBe(defaultFlexTokens.color.backgroundNeutralSubtle.rest); }); it('reports unsupported opaque gradient colors and retains a native outlined placeholder', async () => { diff --git a/packages/agentic/components/src/components/skeleton/useSkeleton.ts b/packages/agentic/components/src/components/skeleton/useSkeleton.ts index 149f93f862..ce86b483e8 100644 --- a/packages/agentic/components/src/components/skeleton/useSkeleton.ts +++ b/packages/agentic/components/src/components/skeleton/useSkeleton.ts @@ -19,7 +19,7 @@ export function useSkeleton_unstable(props: SkeletonProps): SkeletonState { const { onLayout, style: userStyle, ...rest } = props; const themeState = useThemeState(); const gradientId = `skeleton-gradient-${React.useId().replace(/:/g, '')}`; - const highlightColor: unknown = themeState.tokens.color.backgroundNeutralSubtle; + const highlightColor: unknown = themeState.tokens.color.backgroundNeutralSubtle.rest; const shimmerColor = typeof highlightColor === 'string' ? highlightColor : undefined; const [layout, setLayout] = React.useState(createEmptyLayout); const reduceMotion = useReducedMotion() ?? false; diff --git a/packages/agentic/components/src/components/spinner/spinner.test.tsx b/packages/agentic/components/src/components/spinner/spinner.test.tsx index bbba2d1b9b..8729fb8eda 100644 --- a/packages/agentic/components/src/components/spinner/spinner.test.tsx +++ b/packages/agentic/components/src/components/spinner/spinner.test.tsx @@ -69,9 +69,9 @@ describe('Spinner', () => { expect(getRootStyle(component)).toMatchObject({ height: 32, width: 32 }); expect(svg.props.width).toBe(32); expect(svg.props.height).toBe(32); - expect(track.props.stroke).toEqual(normalizeColor(tokens.color.strokeNeutralSubtle)); + expect(track.props.stroke).toEqual(normalizeColor(tokens.color.strokeNeutralSubtle.rest)); expect(track.props.strokeWidth).toBe(tokens.strokeWidth.thick); - expect(indicator.props.stroke).toEqual(normalizeColor(tokens.color.strokeNeutralLoud)); + expect(indicator.props.stroke).toEqual(normalizeColor(tokens.color.strokeNeutralLoud.rest)); const circumference = 2 * Math.PI * ((32 - Number(tokens.strokeWidth.thick)) / 2); expect(indicator.props.strokeDasharray).toEqual([circumference / 4, (circumference * 3) / 4]); expect(indicator.props).not.toHaveProperty('pathLength'); diff --git a/packages/agentic/components/src/components/spinner/useSpinner.ts b/packages/agentic/components/src/components/spinner/useSpinner.ts index 72cdb80f58..2403ed1ada 100644 --- a/packages/agentic/components/src/components/spinner/useSpinner.ts +++ b/packages/agentic/components/src/components/spinner/useSpinner.ts @@ -19,8 +19,8 @@ export function useSpinner_unstable(props: SpinnerProps): SpinnerState { const themeState = useThemeState(); const { center, diameter, radius, strokeWidth } = getSpinnerMetrics(size, themeState.tokens); - const trackColor = themeState.tokens.color.strokeNeutralSubtle; - const indicatorColor = themeState.tokens.color.strokeNeutralLoud; + const trackColor = themeState.tokens.color.strokeNeutralSubtle.rest; + const indicatorColor = themeState.tokens.color.strokeNeutralLoud.rest; const reduceMotionEnabled = useReducedMotion(); const rotation = useSharedAnimatedLoop({ channel: 'agentic-components:spinner', diff --git a/packages/agentic/components/src/components/switch/switch.styles.ts b/packages/agentic/components/src/components/switch/switch.styles.ts index fa1b979cea..610fe95e8b 100644 --- a/packages/agentic/components/src/components/switch/switch.styles.ts +++ b/packages/agentic/components/src/components/switch/switch.styles.ts @@ -129,13 +129,13 @@ const labelStateLevels = [['disabled']] as const; const getLabelStyle = getThemedStateStyleFactory( 'Switch.label', ({ color, fontFamily, fontSize, fontWeight, lineHeight }: FlexTokens): StyleDefinition => ({ - color: color.foregroundNeutralPrimary, + color: color.foregroundNeutralPrimary.rest, fontFamily: fontFamily.functional, fontSize: fontSize.functionalBodyMedium, fontWeight: fontWeight.functionalRegular, lineHeight: lineHeight.functionalBodyMedium, disabled: { - color: color.foregroundNeutralDisabled, + color: color.foregroundNeutralDisabled.rest, }, }), labelStateLevels, diff --git a/packages/agentic/components/src/components/switch/switch.test.tsx b/packages/agentic/components/src/components/switch/switch.test.tsx index c5f365f771..50da14bf28 100644 --- a/packages/agentic/components/src/components/switch/switch.test.tsx +++ b/packages/agentic/components/src/components/switch/switch.test.tsx @@ -343,27 +343,27 @@ describe('Switch', () => { const baseThumbKey = checked ? 'foregroundNeutralOnloud' : 'foregroundNeutralSecondary'; const expectedTrackBackground = disabled ? checked - ? colors.backgroundNeutralHeavyDisabled - : colors.backgroundNeutralTransparent + ? colors.backgroundNeutralHeavyDisabled.rest + : colors.backgroundNeutralTransparent.rest : pressed - ? colors.pressed[baseBackgroundKey] + ? colors[baseBackgroundKey].pressed : hovered - ? colors.hover[baseBackgroundKey] - : colors[baseBackgroundKey]; + ? colors[baseBackgroundKey].hover + : colors[baseBackgroundKey].rest; const expectedTrackBorder = disabled - ? colors.strokeNeutralDisabled + ? colors.strokeNeutralDisabled.rest : pressed - ? colors.pressed[baseBorderKey] + ? colors[baseBorderKey].pressed : hovered - ? colors.hover[baseBorderKey] - : colors[baseBorderKey]; + ? colors[baseBorderKey].hover + : colors[baseBorderKey].rest; const expectedThumb = disabled - ? colors.foregroundNeutralDisabled + ? colors.foregroundNeutralDisabled.rest : pressed - ? colors.pressed[baseThumbKey] + ? colors[baseThumbKey].pressed : hovered - ? colors.hover[baseThumbKey] - : colors[baseThumbKey]; + ? colors[baseThumbKey].hover + : colors[baseThumbKey].rest; const resolvedTrack = getSwitchTrackColorStyle(state, checked); const resolvedThumb = getSwitchThumbColorStyle(state, checked); diff --git a/packages/agentic/components/src/components/tab/tab.test.tsx b/packages/agentic/components/src/components/tab/tab.test.tsx index f3abf06a1d..3aa161bb07 100644 --- a/packages/agentic/components/src/components/tab/tab.test.tsx +++ b/packages/agentic/components/src/components/tab/tab.test.tsx @@ -325,7 +325,7 @@ describe('Tab', () => { expect(StyleSheet.flatten(labels[1].parent?.props.style)).toMatchObject({ position: 'absolute', justifyContent: 'center' }); expect(getRootStyle(component)).toMatchObject({ alignItems: 'center', - backgroundColor: tokens.color.backgroundNeutralTransparent, + backgroundColor: tokens.color.backgroundNeutralTransparent.rest, borderRadius: tokens.borderRadius.base300, gap: tokens.spacing.componentBase100, paddingHorizontal: tokens.spacing.componentBase300, @@ -345,11 +345,11 @@ describe('Tab', () => { const root = getRoot(component); const colors = defaultFlexTokens.color; - expect(getRootStyle(component).backgroundColor).toBe(colors.backgroundNeutralHeavy); + expect(getRootStyle(component).backgroundColor).toBe(colors.backgroundNeutralHeavy.rest); await fireEvent(root, 'hoverIn', {}); - expect(getRootStyle(component).backgroundColor).toBe(colors.hover.backgroundNeutralHeavy); + expect(getRootStyle(component).backgroundColor).toBe(colors.backgroundNeutralHeavy.hover); await fireEvent(root, 'pressIn', {}); - expect(getRootStyle(component).backgroundColor).toBe(colors.pressed.backgroundNeutralHeavy); + expect(getRootStyle(component).backgroundColor).toBe(colors.backgroundNeutralHeavy.pressed); await fireEvent.press(root); expect(onHoverIn).toHaveBeenCalledTimes(1); expect(onPress).toHaveBeenCalledTimes(1); @@ -378,7 +378,7 @@ describe('Tab', () => { expect(root).toBeDisabled(); expect(root.props.focusable).toBe(false); expect(root.props.accessibilityState).toEqual({ disabled: true, selected: true }); - expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralHeavyDisabled); + expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralHeavyDisabled.rest); }); it('renders icon-only tabs with icon swap and accessible labels', async () => { diff --git a/packages/agentic/components/src/components/tag/tag.test.tsx b/packages/agentic/components/src/components/tag/tag.test.tsx index efc6bc4fd9..28f69bce08 100644 --- a/packages/agentic/components/src/components/tag/tag.test.tsx +++ b/packages/agentic/components/src/components/tag/tag.test.tsx @@ -192,21 +192,21 @@ describe('Tag', () => { const restForeground = StyleSheet.flatten(text.props.style).color; expect(getRootStyle(component)).toMatchObject({ - backgroundColor: tokens.color.backgroundBrandHeavy, + backgroundColor: tokens.color.backgroundBrandHeavy.rest, }); - expect(restForeground).toBe(tokens.color.foregroundNeutralOnloud); + expect(restForeground).toBe(tokens.color.foregroundNeutralOnloud.rest); await fireEvent(root, 'hoverIn', {}); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: tokens.color.hover.backgroundBrandHeavy, + backgroundColor: tokens.color.backgroundBrandHeavy.hover, }); - expect(StyleSheet.flatten(text.props.style).color).toBe(tokens.color.foregroundNeutralOnloud); + expect(StyleSheet.flatten(text.props.style).color).toBe(tokens.color.foregroundNeutralOnloud.rest); await fireEvent(root, 'pressIn', {}); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: tokens.color.pressed.backgroundBrandHeavy, + backgroundColor: tokens.color.backgroundBrandHeavy.pressed, }); - expect(StyleSheet.flatten(text.props.style).color).toBe(tokens.color.foregroundNeutralOnloud); + expect(StyleSheet.flatten(text.props.style).color).toBe(tokens.color.foregroundNeutralOnloud.rest); }); it('uses native focus visuals without mounting custom rings', async () => { diff --git a/packages/agentic/components/src/components/text/text.styles.ts b/packages/agentic/components/src/components/text/text.styles.ts index 52458f5197..e0e7606f78 100644 --- a/packages/agentic/components/src/components/text/text.styles.ts +++ b/packages/agentic/components/src/components/text/text.styles.ts @@ -5,7 +5,7 @@ import { themedStyleSheetFactory } from '@fluentui-react-native/design'; export const getTextStyles = themedStyleSheetFactory('Text.styles', ({ tokens }) => StyleSheet.create({ root: { - color: tokens.color.foregroundNeutralPrimary, + color: tokens.color.foregroundNeutralPrimary.rest, fontFamily: tokens.fontFamily.functional, fontSize: tokens.fontSize.functionalBodyMedium, fontWeight: tokens.fontWeight.functionalRegular, diff --git a/packages/agentic/design/AGENTS.md b/packages/agentic/design/AGENTS.md index d2a90ecdf5..b8d2231733 100644 --- a/packages/agentic/design/AGENTS.md +++ b/packages/agentic/design/AGENTS.md @@ -11,6 +11,7 @@ Read the [user guide](README.md), then select the narrowest topic in the [refere | Task | Read | | ------------------------------------------------------------------------- | ---------------------------------------------- | | Theme authoring, providers, appearance, theme hooks, or legacy projection | [Theming](references/theming.md) | +| Authoring, resolving, or reading Flex colors, or migrating flat colors | [Flex colors](references/flex-colors.md) | | Token sources, Flex token mapping, or the pinned x3 source | [Tokens](references/tokens.md) | | Themed style caches or state and color style factories | [Styling](references/styling.md) | | Runtime color parsing, contrast, or interaction colors | [Color library](references/color-lib.md) | @@ -28,8 +29,11 @@ repository reference `components.agentic.styles-and-tokens`. models, and neither hook constructs the model it does not return. - Key caches by source, revision, and resolved appearance, keep them outside author-owned objects, and give every new `ThemeState` a new style registry. -- Keep the root entry point free of the legacy projection, legacy token payloads, and the color library; legacy and - optional APIs stay behind their subpaths. +- Keep the root entry point free of the legacy projection, legacy token payloads, and color compositing; it reaches + the color library's interaction algorithm only through the Flex interaction policy. Legacy and optional APIs stay + behind their subpaths. +- Keep color resolution lazy: resolving, merging, and reading rest never run the interaction algorithm, and a derived + state computes once per resolved color. - Treat `src/tokens/mappings/flex-token-map.yaml` as the canonical token mapping (R-DESIGN-001), and regenerate rather than edit generated token and projection files. - Production code must not depend on the `testing` entry point (R-DESIGN-002). diff --git a/packages/agentic/design/README.md b/packages/agentic/design/README.md index ca24383c80..ce99108b59 100644 --- a/packages/agentic/design/README.md +++ b/packages/agentic/design/README.md @@ -16,7 +16,7 @@ const theme = new FlexThemeReference({ appearance: { colorScheme: 'system' } }); const Title = () => { const { tokens } = useThemeState(); - return Hello; + return Hello; }; export const App = () => ( @@ -34,6 +34,7 @@ Existing `ThemeReference` themes and `useTheme` consumers keep working under the | Topic | Covers | | ---------------------------------------------- | --------------------------------------------------------------------- | | [Theming](references/theming.md) | Theme references, providers, appearance, hooks, and legacy projection | +| [Flex colors](references/flex-colors.md) | Authoring and reading Flex colors, and migrating from flat colors | | [Tokens](references/tokens.md) | Token sources and Flex token mapping maintenance | | [Styling](references/styling.md) | Themed style caches and state or color style factories | | [Color library](references/color-lib.md) | Raw `color-lib` algorithms and the Flex interaction-color policy | diff --git a/packages/agentic/design/references/README.md b/packages/agentic/design/references/README.md index 360ac884f7..ae02ec129f 100644 --- a/packages/agentic/design/references/README.md +++ b/packages/agentic/design/references/README.md @@ -10,6 +10,7 @@ owner_paths: | ID | Document | Read when | | ----------------------- | ----------------------------------- | -------------------------------------------------------------------------------- | | `design.theming` | [Theming](theming.md) | Authoring themes, providers, appearance, theme hooks, or the legacy projection | +| `design.flex-colors` | [Flex colors](flex-colors.md) | Authoring, resolving, or reading Flex colors, or migrating from flat colors | | `design.tokens` | [Tokens](tokens.md) | Choosing token sources, mapping Flex tokens, or updating mappings and the x3 pin | | `design.styling` | [Styling](styling.md) | Using or changing themed style caches and state or color style factories | | `design.color-lib` | [Color library](color-lib.md) | Parsing, converting, compositing, or generating interaction colors at runtime | diff --git a/packages/agentic/design/references/color-lib.md b/packages/agentic/design/references/color-lib.md index c9069aa24d..aec5215bcb 100644 --- a/packages/agentic/design/references/color-lib.md +++ b/packages/agentic/design/references/color-lib.md @@ -9,8 +9,8 @@ owner_paths: # Color library `@fluentui-react-native/design/color-lib` exposes the raw color algorithms for -direct use. Theme authors do not need it: `FlexThemeReference` fills omitted -interaction states automatically (see `theming.md`). It groups public utilities +direct use. Theme authors do not need it: resolved Flex colors compute omitted +interaction states on first read (see `flex-colors.md`). It groups public utilities by responsibility: - `parsing.ts` parses literal React Native colors and formats RGBA values; @@ -41,9 +41,12 @@ const ratio = getContrastRatio('#000000db', '#ffffff'); ``` Token classification is Flex policy, not part of this library. -`INTERACTIVE_COLOR_TOKENS` and `isInverseInteractionToken` are exported from -the package root and owned by `src/flex/colors/`, which maps each Flex token to -a direction and compositing mode before calling `getInteractionColor`. +`INTERACTIVE_COLOR_TOKENS`, `isInteractiveColorToken`, and +`isInverseInteractionToken` are exported from the package root and owned by +`src/flex/colors/`, which maps each Flex token to a compositing mode and uses +the authored color type as the direction before calling `getInteractionColor`. +The inverse classification sets the type of package defaults and +legacy-projected colors; newly authored colors declare their type. Keep the public exports narrow and add APIs only for demonstrated production needs. The public interaction surface is intentionally limited to generating one diff --git a/packages/agentic/design/references/contributing.md b/packages/agentic/design/references/contributing.md index 9dae388363..971d0a423f 100644 --- a/packages/agentic/design/references/contributing.md +++ b/packages/agentic/design/references/contributing.md @@ -9,21 +9,21 @@ owner_paths: ## Source map -| Path | Owns | -| ---------------------- | -------------------------------------------------------------------------------------------------------- | -| `src/types/` | Type-only contracts shared by the Flex and Fluent models, such as appearance and theme state | -| `src/theming/` | Shared theme sources, providers, boundaries, appearance, runtime caches, and the `theming` facades | -| `src/flex/` | Flex token types, defaults, the Theme-to-Flex adapter, `FlexThemeReference`, `useThemeState`, and styles | -| `src/flex/colors/` | Interactive-token classification and the automatic interaction-color policy; see `color-lib.md` | -| `src/fluent/` | Legacy Fluent theme types, `ThemeReference`, `useTheme`, platform utilities, and legacy styling | -| `src/fluent/compat/` | The Flex-to-legacy projection and complete legacy defaults; never reachable from the root | -| `src/fluent/tokens/` | Legacy alias, shadow, and global token data | -| `src/tokens/` | Generated global tokens and shared token attributes | -| `src/tokens/mappings/` | The canonical token map and its generated projections; see `tokens.md` | -| `src/styling/` | Shared state style factories and the `styling` facade; see `styling.md` | -| `src/color-lib/` | Raw, token-free color algorithms; see `color-lib.md` | -| `src/test/` | Test-only fixtures, compatibility baselines, and color validation; see `testing.md` | -| `src/index.ts` | The modern root entry point; see `entry-points.md` for every subpath | +| Path | Owns | +| ---------------------- | ----------------------------------------------------------------------------------------------------------- | +| `src/types/` | Type-only contracts shared by the Flex and Fluent models, such as appearance and theme state | +| `src/theming/` | Shared theme sources, providers, boundaries, appearance, runtime caches, and the `theming` facades | +| `src/flex/` | Flex token types, defaults, the Theme-to-Flex adapter, `FlexThemeReference`, `useThemeState`, and styles | +| `src/flex/colors/` | Authored color normalization, the resolved color envelope, token classification, and the interaction policy | +| `src/fluent/` | Legacy Fluent theme types, `ThemeReference`, `useTheme`, platform utilities, and legacy styling | +| `src/fluent/compat/` | The Flex-to-legacy projection and complete legacy defaults; never reachable from the root | +| `src/fluent/tokens/` | Legacy alias, shadow, and global token data | +| `src/tokens/` | Generated global tokens and shared token attributes | +| `src/tokens/mappings/` | The canonical token map and its generated projections; see `tokens.md` | +| `src/styling/` | Shared state style factories and the `styling` facade; see `styling.md` | +| `src/color-lib/` | Raw, token-free color algorithms; see `color-lib.md` | +| `src/test/` | Test-only fixtures, compatibility baselines, and color validation; see `testing.md` | +| `src/index.ts` | The modern root entry point; see `entry-points.md` for every subpath | Shared modules may import types from either model. At runtime, only the `theming` facade and the legacy subpaths reach `src/fluent/`; the root and `styling` graphs may reach `src/flex/` but never `src/fluent/`. Dependencies point one way: @@ -43,6 +43,9 @@ and rebuild rather than editing them. `src/flex/` or `src/color-lib/`. `src/test/compatibility/importBoundaries.test.ts` checks the entry graphs; run the bundle-size scenarios too when changing imports between these areas. - Never mutate author-owned theme inputs; caches are external and keyed by source, revision, and resolved appearance. +- Keep color resolution lazy: resolving tokens, reading rest, merging, and copying the color map must not run the + interaction algorithm, and a derived state computes at most once per resolved color. `flex-colors.md` owns the color + contract, and `src/flex/colors/interactionLaziness.test.tsx` guards it. - Keep platform appearance listeners subscription-scoped; nothing subscribes at module import. - Keep the experimental native appearance modules and platform theme packages out of this package's dependencies; platform theme packages inject their sources. diff --git a/packages/agentic/design/references/entry-points.md b/packages/agentic/design/references/entry-points.md index d0be2a6e9f..ad9061dc22 100644 --- a/packages/agentic/design/references/entry-points.md +++ b/packages/agentic/design/references/entry-points.md @@ -29,7 +29,8 @@ The `apps/bundle-size` `design-*` scenarios guard these boundaries. Input patter patterns check the modules a tree-shaken bundle retains. The modern root and legacy-source scenarios forbid the compatibility and legacy-token modules; the modern root scenarios forbid `color-lib/compositing` and require the retained Flex interaction policy; the legacy-source and legacy theme scenarios forbid any retained color-library or Flex -interaction module; and the color-library and legacy-projection scenarios require their expected modules. Every scenario +interaction module, although the legacy-source scenario retains the engine-free color envelope that `useThemeState` +returns; and the color-library and legacy-projection scenarios require their expected modules. Every scenario also requires a module it is expected to load, so a moved file cannot make a forbidden pattern pass vacuously. The package specifiers above are the supported import surface. Source and build paths such as `src/fluent/...` or diff --git a/packages/agentic/design/references/flex-colors.md b/packages/agentic/design/references/flex-colors.md new file mode 100644 index 0000000000..d73ad97c2c --- /dev/null +++ b/packages/agentic/design/references/flex-colors.md @@ -0,0 +1,124 @@ +--- +id: design.flex-colors +kind: instruction-reference +owner_paths: + - packages/agentic/design/src/flex/colors + - packages/agentic/design/src/flex/flexTokenDescription.ts + - packages/agentic/design/src/flex/tokens.types.ts +--- + +# Flex colors + +Every Flex semantic color is authored once and resolved per appearance into one envelope with its interaction states. +This reference covers the authored and resolved contracts, resolution and merge rules, and migration from the earlier +flat colors with separate `color.hover` and `color.pressed` maps. + +## Resolved colors + +`useThemeState().tokens.color.` is a frozen `InteractiveColor` with `rest`, `hover`, and `pressed`. Every semantic +color uses the same envelope, including roles whose states equal rest. + +```ts +const { backgroundBrandLoud } = tokens.color; +const rest = backgroundBrandLoud.rest; +const hover = backgroundBrandLoud.hover; +``` + +An omitted state is computed on its first read and memoized for that resolved appearance. Read only the states a style +path needs; destructuring `hover` and `pressed` reads both. Resolved tokens are appearance-bound outputs: never author +them back into a theme. + +## Authored colors + +A `FlexColorInput` is one of: + +| Input | Meaning | +| ----------------------------------- | ----------------------------------------------------------- | +| A `ColorValue` | Rest for every color scheme | +| A `[light, dark]` tuple | Rest selected by the resolved `colorScheme` | +| `{ rest, hover?, pressed?, type? }` | Rest plus explicit states; each entry is a value or a tuple | + +`flexColor(value, type?)` normalizes an input into a new frozen description and never mutates its argument. The second +argument sets the interaction type unless `value.type` is supplied. `selectColorEntry(entry, appearance)` reads the +scheme-specific value from an authored entry. + +```ts +import { flexColor } from '@fluentui-react-native/design'; + +// The common case: rest colors only, derived states. +const brand = flexColor(['#345678', '#abcdef'], 'inverted'); + +// Explicit state exceptions. +const accent = flexColor({ rest: ['#345678', '#abcdef'], pressed: ['#123456', '#cdef01'], type: 'inverted' }); +``` + +| Type | Omitted interactive states | +| ---------- | ---------------------------------------------------------------------------------------- | +| `standard` | Derived in the scheme's standard lightness direction; the type of a plain value | +| `inverted` | Derived in the opposite direction, as the default heavy, loud, and on-loud roles do | +| `fixed` | Not derived; an interactive token with a mappable rest must author `hover` and `pressed` | + +## Resolution + +For each color and resolved appearance: + +1. A tuple selects light or dark. +2. An explicit state wins. +3. An omitted state of a token outside `INTERACTIVE_COLOR_TOKENS` (see `color-lib.md`) is rest. +4. A `fixed` interactive color throws while resolving if a state is omitted and JavaScript can map rest; with a rest it + cannot map, the omitted state is rest. +5. In high contrast, an omitted state is rest. +6. Otherwise the omitted state is derived from rest on first read with the `color-lib` interaction algorithm, using the + color's type as the direction, the appearance's `colorTone`, and the token's compositing mode. No import, provider + setting, or registration is required. When JavaScript cannot map rest, such as a `PlatformColor`, the state is the + identical rest value; unexpected algorithm failures still throw. + +The default description and the Theme-to-Flex adapter never derive states: their omitted states equal rest, so +existing default and legacy-projected values are unchanged. + +## Merging and recipes + +`FlexThemeReference` merges the package defaults, its `base`, and its recipes in order. A color override replaces the +previous color atomically, including its explicit states and type, so a stale state never survives a new rest. An +`undefined` color is not an override. Other token groups keep deep-merge semantics. + +Because replacement is atomic, a plain override uses the `standard` type even where the default color is inverted. +Use `flexColor(value, 'inverted')` when overriding a heavy, loud, or on-loud role that should keep inverted interaction +feedback. + +A `base` function receives the resolved appearance. A recipe function receives the accumulated authored description and +the resolved appearance, and returns overrides. Description colors are authored entries, not resolved envelopes: + +```ts +import { FlexThemeReference, selectColorEntry } from '@fluentui-react-native/design'; + +const theme = new FlexThemeReference({}, (description, appearance) => ({ + color: { strokeBrandLoud: selectColorEntry(description.color.backgroundBrandLoud.rest, appearance) }, +})); +``` + +Authoring rejects resolved `InteractiveColor` values, tuples without exactly two entries, unknown option keys, nested +options, and the removed `color.hover` and `color.pressed` maps. + +## Migrating from flat colors + +| Before | After | +| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| `tokens.color.backgroundBrandLoud` | `tokens.color.backgroundBrandLoud.rest` | +| `tokens.color.hover.backgroundBrandLoud ?? tokens.color.backgroundBrandLoud` | `tokens.color.backgroundBrandLoud.hover` | +| `{ color: { x: rest, hover: { x: hover } } }` | `{ color: { x: { rest, hover } } }` | +| `{ color: { backgroundBrandLoud: '#…' } }` (implicitly inverted) | `{ color: { backgroundBrandLoud: flexColor('#…', 'inverted') } }` | +| A recipe branching on `appearance.colorScheme` for a color | A `[light, dark]` tuple | +| `(parent, appearance) => …parent.color.x…` | `(description, appearance) => …selectColorEntry(description.color.x.rest, appearance)…` | +| `InteractiveColorOverrides` | `InteractiveColorOptions` or `PartialSemanticColors` | + +Other surfaces: + +- Style factories keep their key-based definitions. `colorStyleDef` and `getThemedColorStyleFactory` read + `.hover` and `.pressed` for inherited semantic keys; see `styling.md`. +- A custom `FlexThemeSource` must return resolved envelopes from `resolveFlexTokens`. Delegate to a + `FlexThemeReference` to get atomic merging and automatic states. +- `legacyFallback` is unchanged and still supplies values Flex cannot represent to the projected legacy `Theme`. +- `themeFromFlexTokens` accepts resolved tokens and still accepts the deprecated `FlatFlexTokens` shape. +- `validateContrastPairs` audits resolved colors at rest; pass a flat map of state values to audit hover or pressed. +- Legacy `ThemeReference` themes, `ThemeProvider`, `useTheme`, and the legacy Fluent defaults are unchanged. diff --git a/packages/agentic/design/references/styling.md b/packages/agentic/design/references/styling.md index 1de482e269..a8f68b038b 100644 --- a/packages/agentic/design/references/styling.md +++ b/packages/agentic/design/references/styling.md @@ -47,8 +47,8 @@ states come from deeper levels. `getActiveState` picks the first active state in `interactiveStatePriority` is `disabled`, `pressed`, then `hovered`. `getThemedColorStyleFactory` and `colorStyleDef` accept semantic color keys in place of colors. They synthesize hovered -and pressed nodes wherever those states are declared, resolving `tokens.color.hover` and `tokens.color.pressed` for the -inherited key. An interaction branch may still select a different semantic key explicitly. +and pressed nodes wherever those states are declared, reading the inherited key's resolved `hover` or `pressed` state +only when that node is built. An interaction branch may still select a different semantic key explicitly. ## Value helpers diff --git a/packages/agentic/design/references/testing.md b/packages/agentic/design/references/testing.md index d912e4d9b8..aeadd869c5 100644 --- a/packages/agentic/design/references/testing.md +++ b/packages/agentic/design/references/testing.md @@ -38,3 +38,7 @@ The package's internal validation suite audits rest, hover, and pressed values for both the cool and warm color tones. Its pinned conformance fixtures and the bulk `getInteractionColorOverrides` helper under `src/test/fixtures` are implementation evidence rather than public testing exports. + +`validateContrastPairs` accepts a flat map of color values or resolved +`InteractiveColor` envelopes, which it audits at rest. To audit an interaction +state, pass a flat map of that state's values. diff --git a/packages/agentic/design/references/theming.md b/packages/agentic/design/references/theming.md index dd532ca62b..ca2455f236 100644 --- a/packages/agentic/design/references/theming.md +++ b/packages/agentic/design/references/theming.md @@ -23,22 +23,24 @@ both models. Modern consumers read Flex tokens through `useThemeState`; legacy c | `ThemeReference` | `legacy` | One legacy `Theme` per resolved appearance | `@fluentui-react-native/design/theming` or `@fluentui-react-native/design/theming/legacy-source` | `FlexThemeReference` accepts `base`, `appearance`, `fallbackAppearance`, `appearanceSource`, and `legacyFallback` -options followed by recipes. It resolves the design package's default Flex tokens, then the base input, then recipes in -declaration order. A base or recipe may be a function of the resolved appearance, which always has a concrete -`colorTone`. `PartialFlexTokens` is shape-aware so opaque React Native colors stay leaves. +options followed by recipes. It merges the design package's default Flex token description, then the base input, then +recipes in declaration order, and resolves the result once per appearance. A base may be a function of the resolved +appearance, which always has a concrete `colorTone`. A recipe receives the accumulated authored description and the +resolved appearance. `PartialFlexTokens` is shape-aware so opaque React Native colors stay leaves. -After the recipes run, each omitted `hover` or `pressed` entry of an interactive color token is derived from that -token's resolved rest color with the `color-lib` interaction algorithm for the appearance's color scheme and tone; no -import, provider setting, or registration is required. Authored state values are kept. High contrast and rest values -JavaScript cannot resolve, such as `PlatformColor`, resolve the omitted state to the rest value. `color-lib.md` -describes the token classification. The derivation currently runs once when an appearance's tokens are resolved. +Each color is authored as a value, a `[light, dark]` tuple, or `flexColor` options with explicit states and an +interaction type, and replaces the previous color atomically. Each resolved color is an `InteractiveColor` with `rest`, +`hover`, and `pressed`. Omitted states of interactive tokens are derived from rest with the `color-lib` interaction +algorithm on first read; no import, provider setting, or registration is required. `flex-colors.md` owns the authoring, +resolution, and merge rules and the migration from flat colors. ```ts import { FlexThemeReference } from '@fluentui-react-native/design'; -const theme = new FlexThemeReference({ appearance: { colorScheme: 'system' } }, (_parent, appearance) => ({ - color: { surfaceNeutralNear: appearance.colorScheme === 'dark' ? '#1f1f1f' : '#ffffff' }, -})); +const theme = new FlexThemeReference({ + appearance: { colorScheme: 'system' }, + base: { color: { surfaceNeutralNear: ['#ffffff', '#1f1f1f'] } }, +}); ``` `ThemeReference` keeps its constructor, one-argument recipes, `theme` accessor, `update`, `invalidate`, and listeners. @@ -122,8 +124,9 @@ including `darkElevated`, `highContrast`, and `dynamic`. `getCurrentAppearance`, The package root exports only the modern authoring and consumption APIs. It reaches the forward Theme-to-Flex adapter, which `useThemeState` needs for legacy sources, and the Flex interaction policy with the raw `color-lib` interaction algorithm, but not `useTheme`, the reverse converter, the complete legacy defaults, or legacy token payloads. The legacy -`ThemeReference`, `useTheme`, and `ThemeProvider` graphs reach neither Flex nor `color-lib`. `entry-points.md` lists -every subpath. +`ThemeReference`, `useTheme`, and `ThemeProvider` graphs reach neither Flex nor `color-lib`. An app that pairs a legacy +`ThemeReference` with `useThemeState` reaches the forward adapter and the engine-free color envelope, but not +`FlexThemeReference`, the interaction policy, or `color-lib`. `entry-points.md` lists every subpath. `themeFromFlexTokens` in `theming/compat` builds a complete `Theme` in this order: diff --git a/packages/agentic/design/references/tokens.md b/packages/agentic/design/references/tokens.md index 8a3102dd0c..4790864ef5 100644 --- a/packages/agentic/design/references/tokens.md +++ b/packages/agentic/design/references/tokens.md @@ -25,8 +25,8 @@ owner_paths: | Platform global tokens | `@fluentui-react-native/design/tokens/global` | Generated into `src/tokens/global.generated.ts` and `src/tokens/generated/` | | Legacy alias and shadow tokens | `@fluentui-react-native/design/tokens/legacy` | `src/fluent/tokens/`, for legacy themes only | -`FlexTokens` groups `color` (with `hover` and `pressed` maps whose omitted interactive entries are derived from rest), -`shadow`, `fontWeight`, `fontFamily`, `fontSize`, +`FlexTokens` groups `color` (one `InteractiveColor` with `rest`, `hover`, and `pressed` per semantic color; see +`flex-colors.md`), `shadow`, `fontWeight`, `fontFamily`, `fontSize`, `lineHeight`, `borderRadius`, `spacing`, and `strokeWidth`. Components read the active values from `useThemeState().tokens`; `theming.md` explains how they are resolved. The defaults currently do not vary by appearance; see `remaining-work.md`. @@ -45,8 +45,9 @@ canonical Flex value back to each representable legacy Theme path. The reverse projection is intentionally lossy. When several Flex roles share one legacy Theme path, `reverse.canonical` names the selected source, lists every omitted candidate, and records why that choice is stable. Interactive reverse -entries fall back to their rest value when the resolved hover or pressed map -has no entry for that token. `reverse.transforms` owns any value conversion +entries read the resolved color's `hover` or `pressed` state; for the +deprecated `FlatFlexTokens` input they fall back to rest when the state map has +no entry for that token. `reverse.transforms` owns any value conversion required by a target path. `nonFluentFlexTokens` supplies values for supported Flex destinations without a diff --git a/packages/agentic/design/scripts/token-mappings/check-mappings.cjs b/packages/agentic/design/scripts/token-mappings/check-mappings.cjs index 94adccd5e8..8111821beb 100644 --- a/packages/agentic/design/scripts/token-mappings/check-mappings.cjs +++ b/packages/agentic/design/scripts/token-mappings/check-mappings.cjs @@ -58,14 +58,13 @@ function flattenTokenMappings(mapping, violations) { } if (basePath.startsWith('color.') && Object.hasOwn(mappingEntry, 'rest')) { - const colorName = basePath.slice('color.'.length); for (const state of ['rest', 'hover', 'pressed']) { if (!Object.hasOwn(mappingEntry, state)) { continue; } const stateEntry = mappingEntry[state]; - const destination = state === 'rest' ? basePath : `color.${state}.${colorName}`; + const destination = `${basePath}.${state}`; if (!isRecord(stateEntry)) { addViolation(violations, 'schema', destination, 'a color-state mapping object', stateEntry); continue; @@ -76,8 +75,9 @@ function flattenTokenMappings(mapping, violations) { }); } } else { - entries.set(basePath, { - themeSource: getThemeSource(mappingEntry, basePath, violations), + const destination = basePath.startsWith('color.') ? `${basePath}.rest` : basePath; + entries.set(destination, { + themeSource: getThemeSource(mappingEntry, destination, violations), }); } } @@ -355,9 +355,9 @@ function readTypePaths(typesPath, typeName) { const paths = new Set(); for (const [groupName, groupType] of resolveProperties(declaration, aliases)) { for (const [tokenName, tokenType] of resolveProperties(groupType, aliases)) { - if (groupName === 'color' && (tokenName === 'hover' || tokenName === 'pressed')) { - for (const stateTokenName of resolveProperties(tokenType, aliases).keys()) { - paths.add(`${groupName}.${tokenName}.${stateTokenName}`); + if (groupName === 'color') { + for (const state of resolveProperties(tokenType, aliases).keys()) { + paths.add(`${groupName}.${tokenName}.${state}`); } } else { paths.add(`${groupName}.${tokenName}`); @@ -408,6 +408,8 @@ function findVariableInitializer(program, variableName) { throw new Error(`Unable to find ${variableName}.`); } +const colorTokenPattern = /^color\.[^.]+$/; + function readNonFluentValues(defaultTokensPath, supportedTypePaths) { const sourceText = fs.readFileSync(defaultTokensPath, 'utf8'); const program = parseTypeScript(sourceText, { @@ -419,7 +421,19 @@ function readNonFluentValues(defaultTokensPath, supportedTypePaths) { const values = new Map(); function collect(expression, prefix) { - const value = unwrapExpression(expression); + let value = unwrapExpression(expression); + if (colorTokenPattern.test(prefix)) { + if (value.type === 'CallExpression' && value.callee.type === 'Identifier' && value.callee.name === 'flexColor') { + value = unwrapExpression(value.arguments[0]); + } + const isOptions = + value.type === 'ObjectExpression' && + value.properties.some((property) => property.type === 'ObjectProperty' && getPropertyName(property) === 'rest'); + if (!isOptions) { + values.set(`${prefix}.rest`, sourceText.slice(value.start, value.end)); + return; + } + } if (prefix && supportedTypePaths.has(prefix)) { values.set(prefix, sourceText.slice(value.start, value.end)); return; @@ -437,6 +451,9 @@ function readNonFluentValues(defaultTokensPath, supportedTypePaths) { } const name = getPropertyName(property); + if (name === 'type' && colorTokenPattern.test(prefix)) { + continue; + } collect(property.value, prefix ? `${prefix}.${name}` : name); } } @@ -462,8 +479,8 @@ function loadMappingInputs(paths = defaultPaths) { } function getInteractionRestPath(tokenPath) { - const match = /^color\.(?:hover|pressed)\.(.+)$/.exec(tokenPath); - return match ? `color.${match[1]}` : undefined; + const match = /^color\.([^.]+)\.(?:hover|pressed)$/.exec(tokenPath); + return match ? `color.${match[1]}.rest` : undefined; } function validateMappingInputs(inputs) { diff --git a/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts index a4c167e0d3..928905e00e 100644 --- a/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts +++ b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts @@ -1,5 +1,7 @@ +import * as interaction from '../../color-lib/interaction'; import type { Theme } from '../../theming'; import { mockTheme } from '../../test/fixtures/mockTheme'; +import { defaultFlexTokens } from '../defaults/defaultTokens'; import { flexTokensFromTheme } from './flexTokensFromTheme'; function createTheme(): Theme { @@ -27,14 +29,10 @@ describe('flexTokensFromTheme', () => { const theme = createTheme(); const tokens = flexTokensFromTheme(theme); - expect(tokens.color.backgroundNeutralSubtle).toBe('#223344'); - expect(tokens.color.hover.backgroundNeutralSubtle).toBe('#334455'); - expect(tokens.color.pressed.backgroundNeutralSubtle).toBe('#445566'); - expect(tokens.color.backgroundBrandSoft).toBe('#112233'); - expect(tokens.color.hover.backgroundBrandSoft).toBeUndefined(); - expect(tokens.color.pressed.backgroundBrandSoft).toBeUndefined(); - expect(tokens.color.backgroundNeutralSoft).toBe('#0000001a'); - expect(tokens.color.hover.backgroundNeutralSoft).toBe('#0000001a'); + expect(tokens.color.backgroundNeutralSubtle).toEqual({ rest: '#223344', hover: '#334455', pressed: '#445566' }); + expect(tokens.color.backgroundBrandSoft).toEqual({ rest: '#112233', hover: '#112233', pressed: '#112233' }); + expect(tokens.color.backgroundNeutralSoft).toEqual({ rest: '#0000001a', hover: '#0000001a', pressed: '#0000001a' }); + expect(tokens.color.expressionAccentHeavy).toEqual({ rest: '#242424', hover: '#242424', pressed: '#242424' }); expect(tokens.borderRadius.base100).toBe(2); expect(tokens.borderRadius.base200).toBe(10); expect(tokens.borderRadius.base300).toBe(10); @@ -47,6 +45,24 @@ describe('flexTokensFromTheme', () => { expect(tokens.borderRadius.base200).toBe(4); expect(tokens.borderRadius.base300).toBe(4); - expect(tokens.color.backgroundBrandHeavy).toBe('#185abd'); + expect(tokens.color.backgroundBrandHeavy.rest).toBe('#185abd'); + }); + + it('resolves every color and never runs the interaction engine', () => { + const spy = jest.spyOn(interaction, 'getInteractionColor'); + try { + const tokens = flexTokensFromTheme(createTheme(), { colorScheme: 'dark' }); + for (const color of Object.values(tokens.color)) { + void color.hover; + void color.pressed; + } + + expect(spy).not.toHaveBeenCalled(); + expect(Object.isFrozen(tokens)).toBe(true); + expect(Object.isFrozen(tokens.color)).toBe(true); + expect(Object.keys(tokens.color).sort()).toEqual(Object.keys(defaultFlexTokens.color).sort()); + } finally { + spy.mockRestore(); + } }); }); diff --git a/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts index bdad600fa8..4bf922114b 100644 --- a/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts +++ b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts @@ -1,20 +1,50 @@ import { immutableMerge } from '@fluentui-react-native/framework-base'; +import type { ColorValue } from 'react-native'; import type { Theme } from '../../fluent/types/Theme.types'; +import { defaultResolvedThemeAppearance } from '../../theming/appearance'; import { mapObjectFromObject } from '../../utilities/objects'; +import { normalizeFlexColor, resolveExplicitFlexColor } from '../colors/flexColor'; +import type { ColorSchemeSelector } from '../colors/flexColor'; +import { createInteractiveColor } from '../colors/interactiveColor'; import { defaultFlexTokens, nonFluentFlexTokens } from '../defaults/defaultTokens'; -import type { FlexTokens } from '../tokens.types'; +import type { FlexColorInput, FlexTokens, InteractiveColor, SemanticColors } from '../tokens.types'; import flexFromTheme from '../../tokens/mappings/flex-from-theme.json' with { type: 'json' }; -const defaultMappedFlexTokens = mapObjectFromObject( +type MappedColor = { rest: ColorValue; hover?: ColorValue; pressed?: ColorValue }; +type MappedFlexTokens = Omit, 'color'> & { color?: Record }; + +const defaultMappedFlexTokens = mapObjectFromObject( defaultFlexTokens, Object.fromEntries(Object.keys(flexFromTheme).map((destinationPath) => [destinationPath, destinationPath])), ); +const { color: nonFluentColors, ...nonFluentGroups } = nonFluentFlexTokens; +const nonFluentColorDescriptions = Object.entries(nonFluentColors as Record).map( + ([name, value]) => [name, normalizeFlexColor(value, 'standard', `color.${name}`)] as const, +); + /** - * Build Flex tokens from the values exposed by a FURN Theme. + * Build Flex tokens from the values exposed by a FURN Theme. Interaction + * states the Theme does not map equal rest; no interaction algorithm runs. + * The scheme selects light/dark tuples in values without a Theme source. */ -export function flexTokensFromTheme(theme: Theme): FlexTokens { - const mappedThemeTokens = immutableMerge(defaultMappedFlexTokens, mapObjectFromObject(theme, flexFromTheme)); - return immutableMerge(nonFluentFlexTokens, mappedThemeTokens); +export function flexTokensFromTheme(theme: Theme, appearance: ColorSchemeSelector = defaultResolvedThemeAppearance): FlexTokens { + const { color: mappedColors = {}, ...mappedGroups } = immutableMerge( + defaultMappedFlexTokens, + mapObjectFromObject(theme, flexFromTheme), + ) as MappedFlexTokens; + + const color: Record = {}; + for (const [name, description] of nonFluentColorDescriptions) { + color[name] = resolveExplicitFlexColor(description, appearance); + } + for (const [name, { rest, hover, pressed }] of Object.entries(mappedColors)) { + color[name] = createInteractiveColor(rest, hover ?? rest, pressed ?? rest); + } + + return Object.freeze({ + color: Object.freeze(color) as SemanticColors, + ...immutableMerge(nonFluentGroups as object, mappedGroups as object), + }) as FlexTokens; } diff --git a/packages/agentic/design/src/flex/colors/flexColor.test.ts b/packages/agentic/design/src/flex/colors/flexColor.test.ts new file mode 100644 index 0000000000..828ee90e50 --- /dev/null +++ b/packages/agentic/design/src/flex/colors/flexColor.test.ts @@ -0,0 +1,109 @@ +import { PlatformColor } from 'react-native'; + +import type { FlexColorInput, InteractiveColorType } from '../tokens.types'; +import { flexColor, normalizeFlexColor, resolveExplicitFlexColor, selectColorEntry } from './flexColor'; +import { createInteractiveColor } from './interactiveColor'; + +const light = { colorScheme: 'light' } as const; +const dark = { colorScheme: 'dark' } as const; + +describe('flexColor', () => { + it('describes a single value with the requested type', () => { + expect(flexColor('#123456')).toEqual({ rest: '#123456', type: 'standard' }); + expect(flexColor('#123456', 'inverted')).toEqual({ rest: '#123456', type: 'inverted' }); + }); + + it('lets an explicit value type win over the second argument', () => { + expect(flexColor({ rest: '#123456', type: 'fixed' }, 'inverted')).toEqual({ rest: '#123456', type: 'fixed' }); + expect(flexColor({ rest: '#123456' }, 'inverted')).toEqual({ rest: '#123456', type: 'inverted' }); + }); + + it('returns a new frozen description without mutating the input', () => { + const tuple = ['#ffffff', '#000000'] as const; + const input = { rest: tuple, hover: '#eeeeee' }; + const snapshot = structuredClone(input); + + const result = flexColor(input, 'inverted'); + + expect(result).not.toBe(input); + expect(input).toEqual(snapshot); + expect(Object.isFrozen(result)).toBe(true); + expect(Object.isFrozen(result.rest)).toBe(true); + expect(result.rest).not.toBe(tuple); + expect(result).toEqual({ rest: ['#ffffff', '#000000'], hover: '#eeeeee', type: 'inverted' }); + expect(Object.keys(result)).toEqual(['rest', 'hover', 'type']); + }); + + it('accepts frozen inputs and native colors', () => { + const native = PlatformColor('controlAccentColor'); + + expect(flexColor(Object.freeze({ rest: native, pressed: '#000000' }))).toEqual({ rest: native, pressed: '#000000', type: 'standard' }); + expect(flexColor([native, '#000000']).rest).toEqual([native, '#000000']); + }); + + it('validates tuples, options, and types', () => { + expect(() => flexColor(['#ffffff'] as unknown as FlexColorInput)).toThrow('exactly two colors'); + expect(() => flexColor(['#ffffff', '#000000', '#111111'] as unknown as FlexColorInput)).toThrow('exactly two colors'); + expect(() => flexColor({ rest: '#ffffff', focused: '#000000' } as unknown as FlexColorInput)).toThrow('unknown option "focused"'); + expect(() => flexColor({ hover: '#000000' } as unknown as FlexColorInput)).toThrow('must include rest'); + expect(() => flexColor({ rest: { rest: '#000000' } } as unknown as FlexColorInput)).toThrow('not nested interaction options'); + expect(() => flexColor({ rest: ['#ffffff', { rest: '#000000' }] } as unknown as FlexColorInput)).toThrow( + 'not nested interaction options', + ); + expect(() => flexColor({ rest: '#ffffff', type: 'loud' as InteractiveColorType })).toThrow('invalid type loud'); + expect(() => flexColor('#ffffff', 'loud' as InteractiveColorType)).toThrow('invalid type loud'); + expect(() => flexColor(true as unknown as FlexColorInput)).toThrow('must be a color value'); + }); + + it('rejects resolved colors as authored input', () => { + const resolved = createInteractiveColor('#ffffff', '#eeeeee', '#dddddd'); + + expect(() => flexColor(resolved as unknown as FlexColorInput)).toThrow('resolved InteractiveColor'); + expect(() => flexColor({ rest: resolved } as unknown as FlexColorInput)).toThrow('resolved InteractiveColor'); + }); +}); + +describe('normalizeFlexColor', () => { + it('returns a package-normalized description unchanged', () => { + const description = flexColor('#123456', 'inverted'); + + expect(normalizeFlexColor(description)).toBe(description); + expect(normalizeFlexColor(description, 'fixed')).toBe(description); + }); + + it('uses the default type for plain inputs', () => { + expect(normalizeFlexColor('#123456')).toEqual({ rest: '#123456', type: 'standard' }); + expect(normalizeFlexColor({ rest: '#123456' }, 'inverted')).toEqual({ rest: '#123456', type: 'inverted' }); + }); + + it('labels validation errors with the token path', () => { + expect(() => normalizeFlexColor({ hover: '#000000' } as unknown as FlexColorInput, 'standard', 'color.backgroundBrandHeavy')).toThrow( + 'color.backgroundBrandHeavy must include rest', + ); + }); +}); + +describe('selectColorEntry', () => { + it('uses a single value for every scheme', () => { + expect(selectColorEntry('#123456', light)).toBe('#123456'); + expect(selectColorEntry('#123456', dark)).toBe('#123456'); + }); + + it('selects light at index zero and dark at index one', () => { + expect(selectColorEntry(['#ffffff', '#000000'], light)).toBe('#ffffff'); + expect(selectColorEntry(['#ffffff', '#000000'], dark)).toBe('#000000'); + }); + + it('rejects malformed tuples', () => { + expect(() => selectColorEntry(['#ffffff'] as unknown as readonly [string, string], light)).toThrow('exactly [light, dark]'); + }); +}); + +describe('resolveExplicitFlexColor', () => { + it('resolves omitted states to rest and keeps explicit states', () => { + const resolved = resolveExplicitFlexColor(normalizeFlexColor({ rest: ['#ffffff', '#000000'], pressed: ['#dddddd', '#222222'] }), dark); + + expect(resolved).toEqual({ rest: '#000000', hover: '#000000', pressed: '#222222' }); + expect(Object.isFrozen(resolved)).toBe(true); + }); +}); diff --git a/packages/agentic/design/src/flex/colors/flexColor.ts b/packages/agentic/design/src/flex/colors/flexColor.ts new file mode 100644 index 0000000000..bf084449aa --- /dev/null +++ b/packages/agentic/design/src/flex/colors/flexColor.ts @@ -0,0 +1,163 @@ +import type { ColorValue } from 'react-native'; + +import type { ThemeColorScheme } from '../../types/appearance.types'; +import type { + ColorEntry, + ColorTuple, + FlexColorDescription, + FlexColorInput, + InteractiveColor, + InteractiveColorOptions, + InteractiveColorType, +} from '../tokens.types'; +import { createInteractiveColor, isInteractiveColor } from './interactiveColor'; + +/** The appearance field that selects a light/dark color tuple entry. */ +export type ColorSchemeSelector = { readonly colorScheme: ThemeColorScheme }; + +type MutableDescription = { rest: ColorEntry; hover?: ColorEntry; pressed?: ColorEntry; type: InteractiveColorType }; + +const colorTypes: ReadonlySet = new Set(['standard', 'inverted', 'fixed']); +const optionKeys: ReadonlySet = new Set(['rest', 'hover', 'pressed', 'type']); +const descriptions = new WeakSet(); + +function isPlainObject(value: unknown): value is Record { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + return false; + } + const prototype = Object.getPrototypeOf(value); + return prototype === Object.prototype || prototype === null; +} + +function hasOptionKey(value: Record): boolean { + return Object.keys(value).some((key) => optionKeys.has(key)); +} + +function rejectResolved(value: unknown, label: string): void { + if (isInteractiveColor(value)) { + throw new TypeError( + `${label} is a resolved InteractiveColor. Resolved colors are appearance-bound outputs; author rest and any explicit hover or pressed values instead.`, + ); + } +} + +function validateColorType(type: unknown, label: string): InteractiveColorType { + if (typeof type !== 'string' || !colorTypes.has(type)) { + throw new TypeError(`${label} has invalid type ${String(type)}. Expected "standard", "inverted", or "fixed".`); + } + return type as InteractiveColorType; +} + +function normalizeColorValue(value: unknown, label: string): ColorValue { + if (typeof value === 'string' || typeof value === 'number') { + return value as ColorValue; + } + if (typeof value === 'object' && value !== null && !Array.isArray(value)) { + rejectResolved(value, label); + if (isPlainObject(value) && hasOptionKey(value)) { + throw new TypeError(`${label} must be a color value, not nested interaction options.`); + } + return value as ColorValue; + } + throw new TypeError(`${label} must be a color value.`); +} + +function normalizeColorEntry(value: unknown, label: string): ColorEntry { + if (!Array.isArray(value)) { + return normalizeColorValue(value, label); + } + if (value.length !== 2) { + throw new TypeError(`${label} must be a [light, dark] tuple with exactly two colors.`); + } + return Object.freeze([normalizeColorValue(value[0], `${label}[0]`), normalizeColorValue(value[1], `${label}[1]`)]) as ColorTuple; +} + +function createDescription(rest: ColorEntry, hover: ColorEntry | undefined, pressed: ColorEntry | undefined, type: InteractiveColorType) { + const description: MutableDescription = { rest } as MutableDescription; + if (hover !== undefined) { + description.hover = hover; + } + if (pressed !== undefined) { + description.pressed = pressed; + } + description.type = type; + Object.freeze(description); + descriptions.add(description); + return description as FlexColorDescription; +} + +function normalizeOptions(options: Record, defaultType: InteractiveColorType, label: string): FlexColorDescription { + for (const key of Object.keys(options)) { + if (!optionKeys.has(key)) { + throw new TypeError(`${label} has unknown option "${key}". Expected rest, hover, pressed, or type.`); + } + } + if (options.rest === undefined) { + throw new TypeError(`${label} must include rest when it supplies interaction options.`); + } + return createDescription( + normalizeColorEntry(options.rest, `${label}.rest`), + options.hover === undefined ? undefined : normalizeColorEntry(options.hover, `${label}.hover`), + options.pressed === undefined ? undefined : normalizeColorEntry(options.pressed, `${label}.pressed`), + options.type === undefined ? defaultType : validateColorType(options.type, label), + ); +} + +/** + * Normalize one authored color into a frozen description with an explicit + * type. Package-normalized descriptions are returned unchanged. + * @internal + */ +export function normalizeFlexColor( + value: FlexColorInput, + defaultType: InteractiveColorType = 'standard', + label = 'Flex color', +): FlexColorDescription { + if (typeof value === 'object' && value !== null && descriptions.has(value)) { + return value as FlexColorDescription; + } + rejectResolved(value, label); + const type = validateColorType(defaultType, label); + if (isPlainObject(value) && hasOptionKey(value)) { + return normalizeOptions(value, type, label); + } + return createDescription(normalizeColorEntry(value, label), undefined, undefined, type); +} + +/** + * Normalize an authored Flex color. A single value applies to every scheme, + * and a tuple selects `[light, dark]`. The second argument sets the + * interaction type unless `value.type` is supplied. Arguments are never + * mutated; the result is a new frozen options object. + */ +export function flexColor(value: FlexColorInput, colorType: InteractiveColorType = 'standard'): InteractiveColorOptions { + return normalizeFlexColor(value, colorType, 'flexColor value'); +} + +/** + * Select the color for a scheme from an authored rest or explicit state entry. + */ +export function selectColorEntry(entry: ColorEntry, appearance: ColorSchemeSelector): ColorValue { + if (!Array.isArray(entry)) { + return entry as ColorValue; + } + if (entry.length !== 2) { + throw new TypeError('A Flex color tuple must contain exactly [light, dark].'); + } + return entry[appearance.colorScheme === 'dark' ? 1 : 0]; +} + +/** + * Resolve a description without interaction algorithms: omitted states equal + * rest. Used by defaults and legacy adapters, whose fallback ownership must + * not change. + * @internal + */ +export function resolveExplicitFlexColor(description: FlexColorDescription, appearance: ColorSchemeSelector): InteractiveColor { + const rest = selectColorEntry(description.rest, appearance); + return createInteractiveColor( + rest, + description.hover === undefined ? rest : selectColorEntry(description.hover, appearance), + description.pressed === undefined ? rest : selectColorEntry(description.pressed, appearance), + ); +} diff --git a/packages/agentic/design/src/flex/colors/interactionLaziness.test.tsx b/packages/agentic/design/src/flex/colors/interactionLaziness.test.tsx new file mode 100644 index 0000000000..e12454fbc9 --- /dev/null +++ b/packages/agentic/design/src/flex/colors/interactionLaziness.test.tsx @@ -0,0 +1,116 @@ +import { act, create } from 'react-test-renderer'; +import type { ReactTestRenderer } from 'react-test-renderer'; + +import * as interaction from '../../color-lib/interaction'; +import { ThemedRoot } from '../../theming/ThemedRoot'; +import type { NormalizedThemeAppearance } from '../../types/appearance.types'; +import { defaultFlexTokenDescription } from '../defaults/defaultTokens'; +import { FlexThemeReference } from '../flexThemeReference'; +import { mergeFlexTokenDescription } from '../flexTokenDescription'; +import type { FlexTokens } from '../tokens.types'; +import { useThemeState } from '../useThemeState'; +import { flexColor, normalizeFlexColor } from './flexColor'; +import { resolveFlexColor, resolveFlexTokenDescription } from './interactionPolicy'; + +const lightCool: NormalizedThemeAppearance = { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base', colorTone: 'cool' }; + +describe('interaction derivation laziness', () => { + let engine: jest.SpyInstance; + + beforeEach(() => { + engine = jest.spyOn(interaction, 'getInteractionColor'); + }); + + afterEach(() => { + engine.mockRestore(); + }); + + it('computes nothing when tokens resolve and only rest values are read', () => { + const description = mergeFlexTokenDescription(defaultFlexTokenDescription, { + color: { backgroundBrandHeavy: flexColor('#123456', 'inverted'), backgroundNeutralSubtle: '#fafafa' }, + }); + + const tokens = resolveFlexTokenDescription(description, lightCool); + for (const color of Object.values(tokens.color)) { + void color.rest; + } + + expect(Object.keys(tokens.color)).toContain('backgroundBrandHeavy'); + expect(engine).not.toHaveBeenCalled(); + }); + + it('computes only the read state, once', () => { + const color = resolveFlexColor('backgroundBrandHeavy', normalizeFlexColor('#123456', 'inverted'), lightCool); + + const first = color.hover; + const second = color.hover; + + expect(second).toBe(first); + expect(engine).toHaveBeenCalledTimes(1); + expect(engine).toHaveBeenCalledWith('#123456', 'light', 'hover', expect.objectContaining({ direction: 'inverted' })); + + void color.pressed; + void color.pressed; + + expect(engine).toHaveBeenCalledTimes(2); + expect(engine).toHaveBeenLastCalledWith('#123456', 'light', 'pressed', expect.objectContaining({ direction: 'inverted' })); + }); + + it('never computes explicit states', () => { + const color = resolveFlexColor( + 'backgroundBrandHeavy', + normalizeFlexColor({ rest: '#123456', hover: '#234567', pressed: '#345678' }), + lightCool, + ); + + expect(color).toEqual({ rest: '#123456', hover: '#234567', pressed: '#345678' }); + expect(engine).not.toHaveBeenCalled(); + }); + + it('does not compute states while merging descriptions or resolving a theme reference', () => { + const reference = new FlexThemeReference({ base: { color: { backgroundBrandHeavy: flexColor('#123456', 'inverted') } } }); + const child = new FlexThemeReference({ base: reference }, { color: { backgroundBrandSoft: '#eeeeff' } }); + + const tokens = child.resolveFlexTokens(lightCool); + + expect(tokens.color.backgroundBrandHeavy.rest).toBe('#123456'); + expect(engine).not.toHaveBeenCalled(); + + void tokens.color.backgroundBrandSoft.hover; + expect(engine).toHaveBeenCalledTimes(1); + }); + + it('computes nothing when a provider mounts and a consumer reads rest', () => { + const reference = new FlexThemeReference({ base: { color: { backgroundBrandHeavy: flexColor('#123456', 'inverted') } } }); + const seen: FlexTokens[] = []; + function Probe() { + const { tokens } = useThemeState(); + seen.push(tokens); + void tokens.color.backgroundBrandHeavy.rest; + return null; + } + + let component: ReactTestRenderer; + act(() => { + component = create( + + + , + ); + }); + + expect(seen[0].color.backgroundBrandHeavy.rest).toBe('#123456'); + expect(engine).not.toHaveBeenCalled(); + act(() => component!.unmount()); + }); + + it('does not read states when resolved colors are copied by reference', () => { + const reference = new FlexThemeReference({ base: { color: { backgroundBrandHeavy: flexColor('#123456', 'inverted') } } }); + const tokens = reference.resolveFlexTokens(lightCool); + + const copy = { ...tokens, color: { ...tokens.color } }; + + expect(copy.color.backgroundBrandHeavy).toBe(tokens.color.backgroundBrandHeavy); + expect(engine).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts b/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts index 798d425418..ca613e2670 100644 --- a/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts +++ b/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts @@ -1,6 +1,6 @@ import { PlatformColor } from 'react-native'; -import { getInteractionColorOverrides } from '../../test/fixtures/interactionColors'; +import { getInteractionColorOverrides, restColorValues } from '../../test/fixtures/interactionColors'; import { x3BebopWarmInteractionConformance, x3InteractionConformance, @@ -9,9 +9,10 @@ import { import type { InteractionConformanceVector } from '../../test/fixtures/x3InteractionConformance'; import type { ColorMode } from '../../color-lib/types'; import type { ColorTone, NormalizedThemeAppearance } from '../../types/appearance.types'; -import { defaultFlexTokens } from '../defaults/defaultTokens'; -import type { SemanticColors, SemanticColorTokenValues } from '../tokens.types'; -import { deriveInteractionColor, withDerivedInteractionColors } from './interactionPolicy'; +import { defaultFlexTokenDescription, defaultFlexTokens } from '../defaults/defaultTokens'; +import type { SemanticColorTokenValues } from '../tokens.types'; +import { normalizeFlexColor } from './flexColor'; +import { deriveInteractionColor, resolveFlexColor, resolveFlexTokenDescription } from './interactionPolicy'; import { getInteractionCompositing, getInteractionDirection, @@ -32,12 +33,12 @@ function appearance(colorScheme: ColorMode, colorTone: ColorTone = 'cool'): Norm function restColors( mode: ColorMode, conformance: Readonly> = x3InteractionConformance, -): SemanticColors { - const colors: SemanticColorTokenValues = { ...defaultFlexTokens.color }; +): SemanticColorTokenValues { + const colors = restColorValues(defaultFlexTokens.color); for (const token of INTERACTIVE_COLOR_TOKENS) { colors[token] = conformance[token][modeIndexes[mode].rest]; } - return { ...colors, hover: {}, pressed: {} }; + return colors; } describe('interactive token classification', () => { @@ -91,10 +92,12 @@ describe.each(['light', 'dark'] as const)('%s Flex interaction policy', (mode) = const deviation = x3WarmToneDeviations[deviationKey]; const upstreamValue = vector[modeIndexes[mode][state]]; - expect(deriveInteractionColor(vector[modeIndexes[mode].rest], token, state, appearance(mode))).toBe( + const direction = getInteractionDirection(token); + + expect(deriveInteractionColor(vector[modeIndexes[mode].rest], token, state, direction, appearance(mode))).toBe( deviation?.defaultValue ?? upstreamValue, ); - expect(deriveInteractionColor(warmVector[modeIndexes[mode].rest], token, state, appearance(mode, 'warm'))).toBe( + expect(deriveInteractionColor(warmVector[modeIndexes[mode].rest], token, state, direction, appearance(mode, 'warm'))).toBe( warmVector[modeIndexes[mode][state]], ); if (deviation) { @@ -115,14 +118,17 @@ describe.each(['light', 'dark'] as const)('%s Flex interaction policy', (mode) = describe('deriveInteractionColor', () => { it('returns rest in high contrast', () => { expect( - deriveInteractionColor('#ebebeb', 'surfaceNeutralFarther', 'hover', { ...appearance('light', 'warm'), contrast: 'highContrast' }), + deriveInteractionColor('#ebebeb', 'surfaceNeutralFarther', 'hover', 'standard', { + ...appearance('light', 'warm'), + contrast: 'highContrast', + }), ).toBe('#ebebeb'); }); it('returns the same rest value when the engine cannot resolve it', () => { const rest = PlatformColor('labelColor'); - expect(deriveInteractionColor(rest, 'foregroundNeutralPrimary', 'pressed', appearance('dark'))).toBe(rest); + expect(deriveInteractionColor(rest, 'foregroundNeutralPrimary', 'pressed', 'standard', appearance('dark'))).toBe(rest); }); it('does not swallow unexpected engine failures', () => { @@ -134,51 +140,101 @@ describe('deriveInteractionColor', () => { })); const policy = require('./interactionPolicy') as typeof import('./interactionPolicy'); - expect(() => policy.deriveInteractionColor('#ebebeb', 'surfaceNeutralFarther', 'hover', appearance('light'))).toThrow( + expect(() => policy.deriveInteractionColor('#ebebeb', 'surfaceNeutralFarther', 'hover', 'standard', appearance('light'))).toThrow( 'engine failure', ); }); }); }); -describe('withDerivedInteractionColors', () => { - it('fills omitted states without replacing authored values', () => { - const input = { ...restColors('light'), hover: { surfaceNeutralFarther: '#123456' } }; - const result = withDerivedInteractionColors(input, appearance('light')); +describe('resolveFlexColor', () => { + it('derives omitted interactive states from rest and keeps explicit states', () => { + const color = resolveFlexColor('surfaceNeutralFarther', normalizeFlexColor({ rest: '#ffffff', hover: '#123456' }), appearance('light')); + + expect(color.rest).toBe('#ffffff'); + expect(color.hover).toBe('#123456'); + expect(color.pressed).toBe(deriveInteractionColor('#ffffff', 'surfaceNeutralFarther', 'pressed', 'standard', appearance('light'))); + expect(color.pressed).not.toBe('#ffffff'); + }); + + it('uses the description type as the direction', () => { + const rest = x3InteractionConformance.backgroundBrandHeavy[modeIndexes.light.rest]; + const inverted = resolveFlexColor('backgroundBrandHeavy', normalizeFlexColor(rest, 'inverted'), appearance('light')); + const standard = resolveFlexColor('backgroundBrandHeavy', normalizeFlexColor(rest), appearance('light')); + + expect(inverted.hover).toBe(deriveInteractionColor(rest, 'backgroundBrandHeavy', 'hover', 'inverted', appearance('light'))); + expect(standard.hover).toBe(deriveInteractionColor(rest, 'backgroundBrandHeavy', 'hover', 'standard', appearance('light'))); + expect(standard.hover).not.toBe(inverted.hover); + }); + + it('selects tuple entries for the appearance scheme', () => { + const description = normalizeFlexColor({ rest: ['#ffffff', '#000000'], hover: ['#eeeeee', '#111111'] }); - expect(result).not.toBe(input); - expect(result.hover.surfaceNeutralFarther).toBe('#123456'); - expect(result.hover.surfaceNeutralFar).toBe('#e8e8e8'); - expect(result.pressed.surfaceNeutralFarther).toBe('#d7d7d7'); - expect(Object.keys(result.hover)).toHaveLength(59); - expect(Object.keys(result.pressed)).toHaveLength(59); - expect(input.hover).toEqual({ surfaceNeutralFarther: '#123456' }); + expect(resolveFlexColor('surfaceNeutralFarther', description, appearance('light'))).toMatchObject({ + rest: '#ffffff', + hover: '#eeeeee', + }); + expect(resolveFlexColor('surfaceNeutralFarther', description, appearance('dark'))).toMatchObject({ rest: '#000000', hover: '#111111' }); }); - it('preserves identity when every interaction value is authored', () => { - const colors = restColors('light'); - const input = { - ...colors, - hover: getInteractionColorOverrides(colors, 'light', 'hover').overrides, - pressed: getInteractionColorOverrides(colors, 'light', 'pressed').overrides, - }; + it('resolves omitted states to rest in high contrast and for non-interactive tokens', () => { + const highContrast = resolveFlexColor('surfaceNeutralFarther', normalizeFlexColor('#ffffff'), { + ...appearance('dark'), + contrast: 'highContrast', + }); + const nonInteractive = resolveFlexColor('fixedBlack', normalizeFlexColor('#000000'), appearance('light')); - expect(withDerivedInteractionColors(input, appearance('light'))).toBe(input); + expect([highContrast.hover, highContrast.pressed]).toEqual(['#ffffff', '#ffffff']); + expect([nonInteractive.hover, nonInteractive.pressed]).toEqual(['#000000', '#000000']); }); - it('uses the appearance tone', () => { - const colors = restColors('light', x3BebopWarmInteractionConformance); - const result = withDerivedInteractionColors(colors, appearance('light', 'warm')); + it('keeps an unmappable native rest value by identity', () => { + const rest = PlatformColor('controlAccentColor'); + const color = resolveFlexColor('backgroundBrandHeavy', normalizeFlexColor(rest, 'inverted'), appearance('light')); + + expect(color.rest).toBe(rest); + expect(color.hover).toBe(rest); + expect(color.pressed).toBe(rest); + }); + + it('requires explicit states for a fixed derivable color', () => { + const fixed = normalizeFlexColor({ rest: '#0f6cbd', hover: '#115ea3', type: 'fixed' }); + const complete = normalizeFlexColor({ rest: '#0f6cbd', hover: '#115ea3', pressed: '#0c3b5e', type: 'fixed' }); + + expect(() => resolveFlexColor('backgroundBrandHeavy', fixed, appearance('light'))).toThrow( + 'type "fixed" and no explicit pressed value', + ); + expect(() => resolveFlexColor('backgroundBrandHeavy', fixed, { ...appearance('light'), contrast: 'highContrast' })).toThrow( + 'type "fixed"', + ); + expect(resolveFlexColor('backgroundBrandHeavy', complete, appearance('light'))).toEqual({ + rest: '#0f6cbd', + hover: '#115ea3', + pressed: '#0c3b5e', + }); + }); + + it('accepts a fixed native color without explicit states', () => { + const rest = PlatformColor('controlAccentColor'); + const color = resolveFlexColor('backgroundBrandHeavy', normalizeFlexColor(rest, 'fixed'), appearance('light')); + + expect(color.hover).toBe(rest); + }); +}); + +describe('resolveFlexTokenDescription', () => { + it('resolves every default color and shares non-color groups', () => { + const tokens = resolveFlexTokenDescription(defaultFlexTokenDescription, appearance('light')); - expect(result.hover.backgroundNeutralTranslucent).toBe(x3BebopWarmInteractionConformance.backgroundNeutralTranslucent[1]); + expect(Object.keys(tokens.color)).toEqual(Object.keys(defaultFlexTokenDescription.color)); + expect(tokens.spacing).toBe(defaultFlexTokenDescription.spacing); + expect(Object.isFrozen(tokens)).toBe(true); + expect(Object.isFrozen(tokens.color)).toBe(true); }); - it('skips tokens without a rest value', () => { - const { surfaceNeutralFarther: _omitted, ...colors } = restColors('dark'); - const result = withDerivedInteractionColors(colors as SemanticColors, appearance('dark')); + it('matches the default explicit states', () => { + const tokens = resolveFlexTokenDescription(defaultFlexTokenDescription, appearance('light')); - expect(result.hover).not.toHaveProperty('surfaceNeutralFarther'); - expect(result.pressed).not.toHaveProperty('surfaceNeutralFarther'); - expect(Object.keys(result.hover)).toHaveLength(58); + expect(tokens.color).toEqual(defaultFlexTokens.color); }); }); diff --git a/packages/agentic/design/src/flex/colors/interactionPolicy.ts b/packages/agentic/design/src/flex/colors/interactionPolicy.ts index 861c4ebe94..8127202f63 100644 --- a/packages/agentic/design/src/flex/colors/interactionPolicy.ts +++ b/packages/agentic/design/src/flex/colors/interactionPolicy.ts @@ -1,21 +1,27 @@ import type { ColorValue } from 'react-native'; import { getInteractionColor } from '../../color-lib/interaction'; -import type { InteractionColorState } from '../../color-lib/types'; +import { parseColorValue } from '../../color-lib/parsing'; +import type { InteractionColorState, InteractionDirection } from '../../color-lib/types'; import type { NormalizedThemeAppearance } from '../../types/appearance.types'; -import type { InteractiveColorOverrides, SemanticColors } from '../tokens.types'; -import { getInteractionCompositing, getInteractionDirection, INTERACTIVE_COLOR_TOKENS } from './interactiveTokens'; +import { resolveFlexTokenDescriptionWith } from '../flexTokenDescription'; +import type { FlexColorDescription, FlexTokenDescription, FlexTokens, InteractiveColor } from '../tokens.types'; +import { selectColorEntry } from './flexColor'; +import { createInteractiveColor } from './interactiveColor'; +import type { InteractiveColorState } from './interactiveColor'; +import { getInteractionCompositing, isInteractiveColorToken } from './interactiveTokens'; import type { InteractiveColorToken } from './interactiveTokens'; /** - * Resolve an omitted interaction state for one Flex token from its rest value. - * High contrast and rest values the raw engine cannot map, such as native - * platform colors, resolve to the rest value itself. + * Compute one interaction state for a Flex token from its rest value. High + * contrast and rest values the raw engine cannot map, such as native platform + * colors, resolve to the rest value itself. */ export function deriveInteractionColor( rest: ColorValue, token: InteractiveColorToken, state: InteractionColorState, + direction: InteractionDirection, appearance: Readonly, ): ColorValue { if (appearance.contrast === 'highContrast') { @@ -24,34 +30,66 @@ export function deriveInteractionColor( const result = getInteractionColor(rest, appearance.colorScheme, state, { colorTone: appearance.colorTone, - direction: getInteractionDirection(token), + direction, compositing: getInteractionCompositing(token), }); return result.status === 'derived' ? result.value : rest; } -/** - * Fill each omitted hover and pressed value for the interactive tokens while - * keeping authored values. Returns the input when nothing is omitted. - */ -export function withDerivedInteractionColors(colors: SemanticColors, appearance: Readonly): SemanticColors { - let hover: InteractiveColorOverrides | undefined; - let pressed: InteractiveColorOverrides | undefined; +function resolveState( + token: string, + description: FlexColorDescription, + state: InteractionColorState, + rest: ColorValue, + appearance: Readonly, +): InteractiveColorState { + const explicit = description[state]; + if (explicit !== undefined) { + return selectColorEntry(explicit, appearance); + } + if (!isInteractiveColorToken(token)) { + return rest; + } - for (const token of INTERACTIVE_COLOR_TOKENS) { - const rest = colors[token]; - if (rest === undefined) { - continue; - } - if (colors.hover?.[token] === undefined) { - hover ??= { ...colors.hover }; - hover[token] = deriveInteractionColor(rest, token, 'hover', appearance); - } - if (colors.pressed?.[token] === undefined) { - pressed ??= { ...colors.pressed }; - pressed[token] = deriveInteractionColor(rest, token, 'pressed', appearance); + const { type } = description; + if (type === 'fixed') { + if (parseColorValue(rest).status === 'resolved') { + throw new Error( + `Flex color "${token}" has type "fixed" and no explicit ${state} value. Fixed interaction derivation is not defined; author explicit hover and pressed values.`, + ); } + return rest; } + if (appearance.contrast === 'highContrast') { + return rest; + } + return () => deriveInteractionColor(rest, token, state, type, appearance); +} + +/** + * Resolve one authored color for an appearance. Explicit states win. Omitted + * states of interactive tokens are computed on first read from rest, using the + * description's type for direction; other tokens and high contrast use rest. + * A fixed interactive color whose rest the engine can map must author every + * state, and throws here otherwise. + */ +export function resolveFlexColor( + token: string, + description: FlexColorDescription, + appearance: Readonly, +): InteractiveColor { + const rest = selectColorEntry(description.rest, appearance); + return createInteractiveColor( + rest, + resolveState(token, description, 'hover', rest, appearance), + resolveState(token, description, 'pressed', rest, appearance), + ); +} - return hover || pressed ? { ...colors, hover: hover ?? colors.hover, pressed: pressed ?? colors.pressed } : colors; +/** Resolve a normalized token description for an appearance. */ +export function resolveFlexTokenDescription( + description: FlexTokenDescription, + appearance: Readonly, +): FlexTokens { + return resolveFlexTokenDescriptionWith(description, appearance, resolveFlexColor); } diff --git a/packages/agentic/design/src/flex/colors/interactiveColor.ts b/packages/agentic/design/src/flex/colors/interactiveColor.ts new file mode 100644 index 0000000000..f981fb2410 --- /dev/null +++ b/packages/agentic/design/src/flex/colors/interactiveColor.ts @@ -0,0 +1,48 @@ +import type { ColorValue } from 'react-native'; + +import type { InteractiveColor } from '../tokens.types'; + +/** An explicit state value, or a function that computes it on first read. */ +export type InteractiveColorState = ColorValue | (() => ColorValue); + +// Used only to reject resolved envelopes passed back as authored input. +const resolvedColors = new WeakSet(); + +/** Return whether a value is a package-created resolved `InteractiveColor`. */ +export function isInteractiveColor(value: unknown): value is InteractiveColor { + return typeof value === 'object' && value !== null && resolvedColors.has(value); +} + +function defineState(target: object, name: 'hover' | 'pressed', state: InteractiveColorState): void { + if (typeof state !== 'function') { + Object.defineProperty(target, name, { value: state, enumerable: true }); + return; + } + + let resolved = false; + let value: ColorValue; + Object.defineProperty(target, name, { + enumerable: true, + get: () => { + if (!resolved) { + value = state(); + resolved = true; + } + return value; + }, + }); +} + +/** + * Create a frozen resolved color. Function states run on first read and are + * memoized independently. + */ +export function createInteractiveColor(rest: ColorValue, hover: InteractiveColorState, pressed: InteractiveColorState): InteractiveColor { + const color = {}; + Object.defineProperty(color, 'rest', { value: rest, enumerable: true }); + defineState(color, 'hover', hover); + defineState(color, 'pressed', pressed); + Object.freeze(color); + resolvedColors.add(color); + return color as InteractiveColor; +} diff --git a/packages/agentic/design/src/flex/colors/interactiveTokens.ts b/packages/agentic/design/src/flex/colors/interactiveTokens.ts index 8f2e9fe4d0..058eeb2495 100644 --- a/packages/agentic/design/src/flex/colors/interactiveTokens.ts +++ b/packages/agentic/design/src/flex/colors/interactiveTokens.ts @@ -1,11 +1,10 @@ import type { InteractionCompositing, InteractionDirection } from '../../color-lib/types'; -import type { InteractiveColorOverrides } from '../tokens.types'; - -/** A Flex semantic color token that has hover and pressed states. */ -export type InteractiveColorToken = keyof InteractiveColorOverrides; +import type { SemanticColorName } from '../tokens.types'; /** - * Interactive subset of the Flex semantic color tokens. + * Interactive subset of the Flex semantic color tokens. Only these tokens + * compute omitted hover and pressed states; every other token's states equal + * rest unless authored explicitly. * * Source: x3-design/fluent-design@d334acf5cbad813f2b7cd554da942b09a7ff8f10. */ @@ -69,11 +68,23 @@ export const INTERACTIVE_COLOR_TOKENS = [ 'foregroundWarningOnloud', 'foregroundSuccessPrimary', 'foregroundSuccessOnloud', -] as const satisfies readonly InteractiveColorToken[]; +] as const satisfies readonly SemanticColorName[]; + +/** A Flex semantic color token whose omitted hover and pressed states are computed. */ +export type InteractiveColorToken = (typeof INTERACTIVE_COLOR_TOKENS)[number]; + +const interactiveColorTokens: ReadonlySet = new Set(INTERACTIVE_COLOR_TOKENS); + +/** Return whether a color token computes omitted hover and pressed states. */ +export function isInteractiveColorToken(token: string): token is InteractiveColorToken { + return interactiveColorTokens.has(token); +} /** - * Return whether an interactive token shifts opposite the standard lightness - * direction. Heavy, loud, and on-loud roles are inverted. + * Return whether an interactive token's default color type is inverted. Heavy, + * loud, and on-loud roles shift opposite the standard lightness direction. + * Defaults and legacy adapters use this classification; newly authored colors + * declare their type explicitly. */ export function isInverseInteractionToken(token: InteractiveColorToken): boolean { const name = token.toLowerCase(); diff --git a/packages/agentic/design/src/flex/defaults/defaultTokens.ts b/packages/agentic/design/src/flex/defaults/defaultTokens.ts index 14ffb8ec22..1cd93ddebf 100644 --- a/packages/agentic/design/src/flex/defaults/defaultTokens.ts +++ b/packages/agentic/design/src/flex/defaults/defaultTokens.ts @@ -52,25 +52,20 @@ import { strokeWidth30, strokeWidth40, } from '../../tokens/global.generated'; -import type { FlexTokens, InteractiveColorOverrides, SemanticColorTokenValues } from '../tokens.types'; +import { defaultResolvedThemeAppearance } from '../../theming/appearance'; +import { createFlexTokenDescription, resolveExplicitFlexTokenDescription } from '../flexTokenDescription'; +import type { FlexTokenDescription, FlexTokens, PartialFlexTokens } from '../tokens.types'; -type NonFluentFlexTokens = { - [Group in Exclude]?: Partial; -} & { - color?: Partial & { - hover?: Partial; - pressed?: Partial; - }; -}; +type NonFluentFlexTokens = Omit; /** * Default values for Flex tokens that cannot be populated from a FURN Theme. */ export const nonFluentFlexTokens = { color: { - surfaceNeutralTranslucent: '#ffffff80', - backgroundNeutralSoft: '#0000001a', - backgroundNeutralTranslucent: '#ffffff80', + surfaceNeutralTranslucent: { rest: '#ffffff80', hover: '#ffffff80', pressed: '#ffffff80' }, + backgroundNeutralSoft: { rest: '#0000001a', hover: '#0000001a', pressed: '#0000001a' }, + backgroundNeutralTranslucent: { rest: '#ffffff80', hover: '#ffffff80', pressed: '#ffffff80' }, expressionAccentHeavy: '#242424', expressionAccentLoud: '#707070', expressionAccentSoft: '#0000001a', @@ -119,16 +114,6 @@ export const nonFluentFlexTokens = { materialBackgroundThick: '#ffffffe6', materialBackgroundRegular: '#ffffffcc', materialBackgroundThin: '#ffffff80', - hover: { - surfaceNeutralTranslucent: '#ffffff80', - backgroundNeutralSoft: '#0000001a', - backgroundNeutralTranslucent: '#ffffff80', - }, - pressed: { - surfaceNeutralTranslucent: '#ffffff80', - backgroundNeutralSoft: '#0000001a', - backgroundNeutralTranslucent: '#ffffff80', - }, }, lineHeight: { functionalDisplay: fontLineHeight1000, @@ -197,69 +182,70 @@ export const nonFluentFlexTokens = { } satisfies NonFluentFlexTokens; /** - * Default grouped Flex token values. Theme-backed values use the current native - * defaults, layered over values that have no FURN Theme source. + * Authored default Flex token values. Theme-backed values use the current + * native defaults, layered over values that have no FURN Theme source. + * Heavy, loud, and on-loud interactive roles are inverted. */ -export const defaultFlexTokens: FlexTokens = { +export const defaultFlexTokenDescription: FlexTokenDescription = createFlexTokenDescription({ ...nonFluentFlexTokens, color: { ...nonFluentFlexTokens.color, - surfaceNeutralFarther: '#ebebeb', - surfaceNeutralFar: '#f5f5f5', - surfaceNeutralNear: '#fafafa', - surfaceNeutralNearer: '#ffffff', - backgroundNeutralHeavy: '#616161', - backgroundNeutralLoud: '#616161', - backgroundNeutralSubtle: '#fafafa', - backgroundNeutralTransparent: '#00000000', - backgroundBrandHeavy: '#185abd', - backgroundBrandLoud: '#185abd', - backgroundBrandSoft: '#d2e0f4', - backgroundBrandSubtle: '#d2e0f4', - backgroundBrandTransparent: '#00000000', - backgroundDangerLoud: '#d13438', - backgroundDangerSoft: '#f1bbbc', - backgroundDangerSubtle: '#fdf6f6', - backgroundWarningLoud: '#fde300', - backgroundWarningSoft: '#fef7b2', - backgroundWarningSubtle: '#fffef5', - backgroundSuccessLoud: '#107c10', - backgroundSuccessSoft: '#9fd89f', - backgroundSuccessSubtle: '#f1faf1', - strokeNeutralHeavy: '#616161', - strokeNeutralLoud: '#d1d1d1', - strokeNeutralSoft: '#d1d1d1', - strokeNeutralSubtle: '#e0e0e0', - strokeNeutralTransparent: '#00000000', - strokeNeutralOnloud: '#ffffff', - strokeBrandLoud: '#185abd', - strokeBrandSoft: '#185abd', - strokeBrandSubtle: '#6794d7', - strokeBrandOnloud: '#ffffff', - strokeDangerLoud: '#d13438', - strokeDangerSoft: '#f1bbbc', - strokeDangerSubtle: '#f1bbbc', - strokeDangerOnloud: '#ffffff', - strokeWarningLoud: '#fde300', - strokeWarningSoft: '#fef7b2', - strokeWarningSubtle: '#fef7b2', - strokeWarningOnloud: '#ffffff', - strokeSuccessLoud: '#107c10', - strokeSuccessSoft: '#9fd89f', - strokeSuccessSubtle: '#9fd89f', - strokeSuccessOnloud: '#ffffff', - foregroundNeutralPrimary: '#242424', - foregroundNeutralSecondary: '#424242', - foregroundNeutralTertiary: '#616161', - foregroundNeutralOnloud: '#ffffff', - foregroundBrandPrimary: '#185abd', - foregroundBrandOnloud: '#ffffff', - foregroundDangerPrimary: '#bc2f32', - foregroundDangerOnloud: '#ffffff', - foregroundWarningPrimary: '#817400', - foregroundWarningOnloud: '#ffffff', - foregroundSuccessPrimary: '#0e700e', - foregroundSuccessOnloud: '#ffffff', + surfaceNeutralFarther: { rest: '#ebebeb', hover: '#f5f5f5', pressed: '#f0f0f0' }, + surfaceNeutralFar: { rest: '#f5f5f5', hover: '#ebebeb', pressed: '#d6d6d6' }, + surfaceNeutralNear: { rest: '#fafafa', hover: '#f0f0f0', pressed: '#dbdbdb' }, + surfaceNeutralNearer: { rest: '#ffffff', hover: '#f5f5f5', pressed: '#e0e0e0' }, + backgroundNeutralHeavy: { rest: '#616161', hover: '#616161', pressed: '#616161', type: 'inverted' }, + backgroundNeutralLoud: { rest: '#616161', hover: '#616161', pressed: '#616161', type: 'inverted' }, + backgroundNeutralSubtle: { rest: '#fafafa', hover: '#f0f0f0', pressed: '#dbdbdb' }, + backgroundNeutralTransparent: { rest: '#00000000', hover: '#00000000', pressed: '#00000000' }, + backgroundBrandHeavy: { rest: '#185abd', hover: '#1651aa', pressed: '#0e336a', type: 'inverted' }, + backgroundBrandLoud: { rest: '#185abd', hover: '#1651aa', pressed: '#0e336a', type: 'inverted' }, + backgroundBrandSoft: { rest: '#d2e0f4', hover: '#d2e0f4', pressed: '#d2e0f4' }, + backgroundBrandSubtle: { rest: '#d2e0f4', hover: '#d2e0f4', pressed: '#d2e0f4' }, + backgroundBrandTransparent: { rest: '#00000000', hover: '#00000000', pressed: '#00000000' }, + backgroundDangerLoud: { rest: '#d13438', hover: '#d13438', pressed: '#d13438', type: 'inverted' }, + backgroundDangerSoft: { rest: '#f1bbbc', hover: '#f1bbbc', pressed: '#f1bbbc' }, + backgroundDangerSubtle: { rest: '#fdf6f6', hover: '#fdf6f6', pressed: '#fdf6f6' }, + backgroundWarningLoud: { rest: '#fde300', hover: '#fde300', pressed: '#fde300', type: 'inverted' }, + backgroundWarningSoft: { rest: '#fef7b2', hover: '#fef7b2', pressed: '#fef7b2' }, + backgroundWarningSubtle: { rest: '#fffef5', hover: '#fffef5', pressed: '#fffef5' }, + backgroundSuccessLoud: { rest: '#107c10', hover: '#107c10', pressed: '#107c10', type: 'inverted' }, + backgroundSuccessSoft: { rest: '#9fd89f', hover: '#9fd89f', pressed: '#9fd89f' }, + backgroundSuccessSubtle: { rest: '#f1faf1', hover: '#f1faf1', pressed: '#f1faf1' }, + strokeNeutralHeavy: { rest: '#616161', hover: '#575757', pressed: '#4d4d4d', type: 'inverted' }, + strokeNeutralLoud: { rest: '#d1d1d1', hover: '#c7c7c7', pressed: '#b3b3b3', type: 'inverted' }, + strokeNeutralSoft: { rest: '#d1d1d1', hover: '#c7c7c7', pressed: '#b3b3b3' }, + strokeNeutralSubtle: { rest: '#e0e0e0', hover: '#e0e0e0', pressed: '#e0e0e0' }, + strokeNeutralTransparent: { rest: '#00000000', hover: '#00000000', pressed: '#00000000' }, + strokeNeutralOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + strokeBrandLoud: { rest: '#185abd', hover: '#185abd', pressed: '#185abd', type: 'inverted' }, + strokeBrandSoft: { rest: '#185abd', hover: '#185abd', pressed: '#185abd' }, + strokeBrandSubtle: { rest: '#6794d7', hover: '#6794d7', pressed: '#6794d7' }, + strokeBrandOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + strokeDangerLoud: { rest: '#d13438', hover: '#d13438', pressed: '#d13438', type: 'inverted' }, + strokeDangerSoft: { rest: '#f1bbbc', hover: '#f1bbbc', pressed: '#f1bbbc' }, + strokeDangerSubtle: { rest: '#f1bbbc', hover: '#f1bbbc', pressed: '#f1bbbc' }, + strokeDangerOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + strokeWarningLoud: { rest: '#fde300', hover: '#fde300', pressed: '#fde300', type: 'inverted' }, + strokeWarningSoft: { rest: '#fef7b2', hover: '#fef7b2', pressed: '#fef7b2' }, + strokeWarningSubtle: { rest: '#fef7b2', hover: '#fef7b2', pressed: '#fef7b2' }, + strokeWarningOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + strokeSuccessLoud: { rest: '#107c10', hover: '#107c10', pressed: '#107c10', type: 'inverted' }, + strokeSuccessSoft: { rest: '#9fd89f', hover: '#9fd89f', pressed: '#9fd89f' }, + strokeSuccessSubtle: { rest: '#9fd89f', hover: '#9fd89f', pressed: '#9fd89f' }, + strokeSuccessOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + foregroundNeutralPrimary: { rest: '#242424', hover: '#242424', pressed: '#242424' }, + foregroundNeutralSecondary: { rest: '#424242', hover: '#242424', pressed: '#242424' }, + foregroundNeutralTertiary: { rest: '#616161', hover: '#424242', pressed: '#424242' }, + foregroundNeutralOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + foregroundBrandPrimary: { rest: '#185abd', hover: '#185abd', pressed: '#185abd' }, + foregroundBrandOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + foregroundDangerPrimary: { rest: '#bc2f32', hover: '#bc2f32', pressed: '#bc2f32' }, + foregroundDangerOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + foregroundWarningPrimary: { rest: '#817400', hover: '#817400', pressed: '#817400' }, + foregroundWarningOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + foregroundSuccessPrimary: { rest: '#0e700e', hover: '#0e700e', pressed: '#0e700e' }, + foregroundSuccessOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, fixedWhite: '#ffffff', fixedBlack: '#000000', expressionAchromaticHeavy: '#000000', @@ -272,124 +258,6 @@ export const defaultFlexTokens: FlexTokens = { strokeFocusInner: '#ffffff', strokeFocusOuter: '#000000', shadow: '#000000', - hover: { - ...nonFluentFlexTokens.color.hover, - surfaceNeutralFarther: '#f5f5f5', - surfaceNeutralFar: '#ebebeb', - surfaceNeutralNear: '#f0f0f0', - surfaceNeutralNearer: '#f5f5f5', - backgroundNeutralHeavy: '#616161', - backgroundNeutralLoud: '#616161', - backgroundNeutralSubtle: '#f0f0f0', - backgroundNeutralTransparent: '#00000000', - backgroundBrandHeavy: '#1651aa', - backgroundBrandLoud: '#1651aa', - backgroundBrandSoft: '#d2e0f4', - backgroundBrandSubtle: '#d2e0f4', - backgroundBrandTransparent: '#00000000', - backgroundDangerLoud: '#d13438', - backgroundDangerSoft: '#f1bbbc', - backgroundDangerSubtle: '#fdf6f6', - backgroundWarningLoud: '#fde300', - backgroundWarningSoft: '#fef7b2', - backgroundWarningSubtle: '#fffef5', - backgroundSuccessLoud: '#107c10', - backgroundSuccessSoft: '#9fd89f', - backgroundSuccessSubtle: '#f1faf1', - strokeNeutralHeavy: '#575757', - strokeNeutralLoud: '#c7c7c7', - strokeNeutralSoft: '#c7c7c7', - strokeNeutralSubtle: '#e0e0e0', - strokeNeutralTransparent: '#00000000', - strokeNeutralOnloud: '#ffffff', - strokeBrandLoud: '#185abd', - strokeBrandSoft: '#185abd', - strokeBrandSubtle: '#6794d7', - strokeBrandOnloud: '#ffffff', - strokeDangerLoud: '#d13438', - strokeDangerSoft: '#f1bbbc', - strokeDangerSubtle: '#f1bbbc', - strokeDangerOnloud: '#ffffff', - strokeWarningLoud: '#fde300', - strokeWarningSoft: '#fef7b2', - strokeWarningSubtle: '#fef7b2', - strokeWarningOnloud: '#ffffff', - strokeSuccessLoud: '#107c10', - strokeSuccessSoft: '#9fd89f', - strokeSuccessSubtle: '#9fd89f', - strokeSuccessOnloud: '#ffffff', - foregroundNeutralPrimary: '#242424', - foregroundNeutralSecondary: '#242424', - foregroundNeutralTertiary: '#424242', - foregroundNeutralOnloud: '#ffffff', - foregroundBrandPrimary: '#185abd', - foregroundBrandOnloud: '#ffffff', - foregroundDangerPrimary: '#bc2f32', - foregroundDangerOnloud: '#ffffff', - foregroundWarningPrimary: '#817400', - foregroundWarningOnloud: '#ffffff', - foregroundSuccessPrimary: '#0e700e', - foregroundSuccessOnloud: '#ffffff', - }, - pressed: { - ...nonFluentFlexTokens.color.pressed, - surfaceNeutralFarther: '#f0f0f0', - surfaceNeutralFar: '#d6d6d6', - surfaceNeutralNear: '#dbdbdb', - surfaceNeutralNearer: '#e0e0e0', - backgroundNeutralHeavy: '#616161', - backgroundNeutralLoud: '#616161', - backgroundNeutralSubtle: '#dbdbdb', - backgroundNeutralTransparent: '#00000000', - backgroundBrandHeavy: '#0e336a', - backgroundBrandLoud: '#0e336a', - backgroundBrandSoft: '#d2e0f4', - backgroundBrandSubtle: '#d2e0f4', - backgroundBrandTransparent: '#00000000', - backgroundDangerLoud: '#d13438', - backgroundDangerSoft: '#f1bbbc', - backgroundDangerSubtle: '#fdf6f6', - backgroundWarningLoud: '#fde300', - backgroundWarningSoft: '#fef7b2', - backgroundWarningSubtle: '#fffef5', - backgroundSuccessLoud: '#107c10', - backgroundSuccessSoft: '#9fd89f', - backgroundSuccessSubtle: '#f1faf1', - strokeNeutralHeavy: '#4d4d4d', - strokeNeutralLoud: '#b3b3b3', - strokeNeutralSoft: '#b3b3b3', - strokeNeutralSubtle: '#e0e0e0', - strokeNeutralTransparent: '#00000000', - strokeNeutralOnloud: '#ffffff', - strokeBrandLoud: '#185abd', - strokeBrandSoft: '#185abd', - strokeBrandSubtle: '#6794d7', - strokeBrandOnloud: '#ffffff', - strokeDangerLoud: '#d13438', - strokeDangerSoft: '#f1bbbc', - strokeDangerSubtle: '#f1bbbc', - strokeDangerOnloud: '#ffffff', - strokeWarningLoud: '#fde300', - strokeWarningSoft: '#fef7b2', - strokeWarningSubtle: '#fef7b2', - strokeWarningOnloud: '#ffffff', - strokeSuccessLoud: '#107c10', - strokeSuccessSoft: '#9fd89f', - strokeSuccessSubtle: '#9fd89f', - strokeSuccessOnloud: '#ffffff', - foregroundNeutralPrimary: '#242424', - foregroundNeutralSecondary: '#242424', - foregroundNeutralTertiary: '#424242', - foregroundNeutralOnloud: '#ffffff', - foregroundBrandPrimary: '#185abd', - foregroundBrandOnloud: '#ffffff', - foregroundDangerPrimary: '#bc2f32', - foregroundDangerOnloud: '#ffffff', - foregroundWarningPrimary: '#817400', - foregroundWarningOnloud: '#ffffff', - foregroundSuccessPrimary: '#0e700e', - foregroundSuccessOnloud: '#ffffff', - }, }, shadow: { lowest: { @@ -470,4 +338,13 @@ export const defaultFlexTokens: FlexTokens = { base200: cornerRadius40, base300: cornerRadius40, }, -}; +}); + +/** + * Default resolved Flex tokens for the default appearance. Every interactive + * default authors explicit states, so no interaction algorithm runs. + */ +export const defaultFlexTokens: FlexTokens = resolveExplicitFlexTokenDescription( + defaultFlexTokenDescription, + defaultResolvedThemeAppearance, +); diff --git a/packages/agentic/design/src/flex/flexThemeReference.test.ts b/packages/agentic/design/src/flex/flexThemeReference.test.ts index 8aa94dfe77..ba591f6c78 100644 --- a/packages/agentic/design/src/flex/flexThemeReference.test.ts +++ b/packages/agentic/design/src/flex/flexThemeReference.test.ts @@ -2,9 +2,11 @@ import { PlatformColor } from 'react-native'; import type { ColorValue } from 'react-native'; import { defaultResolvedThemeAppearance } from '../theming/appearance'; -import { defaultFlexTokens } from './defaults/defaultTokens'; +import { flexColor, selectColorEntry } from './colors/flexColor'; +import { deriveInteractionColor } from './colors/interactionPolicy'; +import { defaultFlexTokenDescription, defaultFlexTokens } from './defaults/defaultTokens'; import { FlexThemeReference } from './flexThemeReference'; -import type { PartialFlexTokens } from './flexThemeReference'; +import type { FlexTokenDescription, PartialFlexTokens } from './tokens.types'; const darkAppearance = { colorScheme: 'dark', @@ -14,7 +16,7 @@ const darkAppearance = { describe('FlexThemeReference', () => { it('resolves one stable token object per appearance', () => { - const reference = new FlexThemeReference({}, (_tokens, appearance) => ({ + const reference = new FlexThemeReference({}, (_description, appearance) => ({ color: { backgroundBrandHeavy: appearance.colorScheme === 'dark' ? '#111111' : '#eeeeee', }, @@ -26,8 +28,8 @@ describe('FlexThemeReference', () => { expect(lightAgain).toBe(light); expect(dark).not.toBe(light); - expect(light.color.backgroundBrandHeavy).toBe('#eeeeee'); - expect(dark.color.backgroundBrandHeavy).toBe('#111111'); + expect(light.color.backgroundBrandHeavy.rest).toBe('#eeeeee'); + expect(dark.color.backgroundBrandHeavy.rest).toBe('#111111'); }); it('replaces all appearance identities after invalidation', () => { @@ -48,7 +50,7 @@ describe('FlexThemeReference', () => { reference.update({ color: { backgroundBrandHeavy: '#123456' } }); expect(listener).toHaveBeenCalledTimes(1); - expect(reference.resolveFlexTokens(defaultResolvedThemeAppearance).color.backgroundBrandHeavy).toBe('#123456'); + expect(reference.resolveFlexTokens(defaultResolvedThemeAppearance).color.backgroundBrandHeavy.rest).toBe('#123456'); }); it('inherits source configuration and composes legacy fallbacks from a parent reference', () => { @@ -100,7 +102,7 @@ describe('FlexThemeReference color tone', () => { return {}; }, }, - (_tokens, appearance) => { + (_description, appearance) => { tones.push(`recipe:${appearance.colorTone}`); return {}; }, @@ -118,41 +120,37 @@ describe('FlexThemeReference color tone', () => { for (const colorTone of ['cool', 'warm'] as const) { for (const colorScheme of ['light', 'dark'] as const) { const tokens = reference.resolveFlexTokens({ ...lightAppearance, colorScheme, colorTone }); - expect(tokens.color).toBe(defaultFlexTokens.color); + expect(tokens.color).toEqual(defaultFlexTokens.color); } } }); }); describe('FlexThemeReference interaction derivation', () => { - const omitInteraction = (rest: ColorValue) => - ({ - color: { - backgroundNeutralTranslucent: rest, - hover: { backgroundNeutralTranslucent: undefined }, - pressed: { backgroundNeutralTranslucent: undefined }, - }, - }) as PartialFlexTokens; + const omitInteraction = (rest: ColorValue): PartialFlexTokens => ({ color: { backgroundNeutralTranslucent: rest } }); it('derives omitted states from rest with the appearance tone', () => { const reference = new FlexThemeReference({}, omitInteraction('#e9e9e980')); const cool = reference.resolveFlexTokens(defaultResolvedThemeAppearance).color; const warm = reference.resolveFlexTokens({ ...defaultResolvedThemeAppearance, colorTone: 'warm' }).color; - expect(cool.hover.backgroundNeutralTranslucent).toBe('#dfdfdf8a'); - expect(cool.pressed.backgroundNeutralTranslucent).toBe('#d5d5d594'); - expect(warm.hover.backgroundNeutralTranslucent).toBe('#dcdcd68a'); - expect(warm.pressed.backgroundNeutralTranslucent).toBe('#d2cfc894'); + expect(cool.backgroundNeutralTranslucent.hover).toBe('#dfdfdf8a'); + expect(cool.backgroundNeutralTranslucent.pressed).toBe('#d5d5d594'); + expect(warm.backgroundNeutralTranslucent.hover).toBe('#dcdcd68a'); + expect(warm.backgroundNeutralTranslucent.pressed).toBe('#d2cfc894'); }); it('keeps authored interaction values', () => { - const reference = new FlexThemeReference({}, omitInteraction('#e9e9e980'), { - color: { hover: { backgroundNeutralTranslucent: '#123456' } }, - }); + const reference = new FlexThemeReference( + {}, + { + color: { backgroundNeutralTranslucent: { rest: '#e9e9e980', hover: '#123456' } }, + }, + ); const colors = reference.resolveFlexTokens(defaultResolvedThemeAppearance).color; - expect(colors.hover.backgroundNeutralTranslucent).toBe('#123456'); - expect(colors.pressed.backgroundNeutralTranslucent).toBe('#d5d5d594'); + expect(colors.backgroundNeutralTranslucent.hover).toBe('#123456'); + expect(colors.backgroundNeutralTranslucent.pressed).toBe('#d5d5d594'); }); it('falls back to the same rest value when it cannot be derived', () => { @@ -160,15 +158,96 @@ describe('FlexThemeReference interaction derivation', () => { const reference = new FlexThemeReference({}, omitInteraction(rest)); const colors = reference.resolveFlexTokens({ ...defaultResolvedThemeAppearance, colorTone: 'warm' }).color; - expect(colors.hover.backgroundNeutralTranslucent).toBe(rest); - expect(colors.pressed.backgroundNeutralTranslucent).toBe(rest); + expect(colors.backgroundNeutralTranslucent.rest).toBe(rest); + expect(colors.backgroundNeutralTranslucent.hover).toBe(rest); + expect(colors.backgroundNeutralTranslucent.pressed).toBe(rest); }); it('uses rest in high contrast', () => { const reference = new FlexThemeReference({}, omitInteraction('#e9e9e980')); const colors = reference.resolveFlexTokens({ ...defaultResolvedThemeAppearance, contrast: 'highContrast' }).color; - expect(colors.hover.backgroundNeutralTranslucent).toBe('#e9e9e980'); - expect(colors.pressed.backgroundNeutralTranslucent).toBe('#e9e9e980'); + expect(colors.backgroundNeutralTranslucent.hover).toBe('#e9e9e980'); + expect(colors.backgroundNeutralTranslucent.pressed).toBe('#e9e9e980'); + }); + + it('replaces a color atomically so earlier explicit states do not leak', () => { + const parent = new FlexThemeReference({ + base: { color: { backgroundBrandHeavy: { rest: '#0f6cbd', hover: '#111111', pressed: '#222222' } } }, + }); + const child = new FlexThemeReference({ base: parent }, { color: { backgroundBrandHeavy: flexColor('#0f6cbd', 'inverted') } }); + const color = child.resolveFlexTokens(defaultResolvedThemeAppearance).color.backgroundBrandHeavy; + + expect(parent.resolveFlexTokens(defaultResolvedThemeAppearance).color.backgroundBrandHeavy.hover).toBe('#111111'); + expect(color.hover).toBe( + deriveInteractionColor('#0f6cbd', 'backgroundBrandHeavy', 'hover', 'inverted', defaultResolvedThemeAppearance), + ); + expect(color.hover).not.toBe('#111111'); + }); + + it('derives a plain override as standard unless flexColor marks it inverted', () => { + const plain = new FlexThemeReference({}, { color: { backgroundBrandHeavy: '#0f6cbd' } }); + const inverted = new FlexThemeReference({}, { color: { backgroundBrandHeavy: flexColor('#0f6cbd', 'inverted') } }); + const appearance = { ...defaultResolvedThemeAppearance, colorTone: 'cool' } as const; + + expect(plain.resolveFlexTokens(appearance).color.backgroundBrandHeavy.hover).toBe( + deriveInteractionColor('#0f6cbd', 'backgroundBrandHeavy', 'hover', 'standard', appearance), + ); + expect(inverted.resolveFlexTokens(appearance).color.backgroundBrandHeavy.hover).toBe( + deriveInteractionColor('#0f6cbd', 'backgroundBrandHeavy', 'hover', 'inverted', appearance), + ); + }); + + it('selects light and dark tuple entries for each scheme', () => { + const reference = new FlexThemeReference({ + base: { color: { surfaceNeutralFarther: { rest: ['#fafafa', '#1f1f1f'], hover: ['#f0f0f0', '#292929'] } } }, + }); + + expect(reference.resolveFlexTokens(defaultResolvedThemeAppearance).color.surfaceNeutralFarther).toMatchObject({ + rest: '#fafafa', + hover: '#f0f0f0', + }); + expect(reference.resolveFlexTokens(darkAppearance).color.surfaceNeutralFarther).toMatchObject({ rest: '#1f1f1f', hover: '#292929' }); + }); +}); + +describe('FlexThemeReference authored descriptions', () => { + it('passes recipes the accumulated authored description', () => { + const descriptions: FlexTokenDescription[] = []; + const reference = new FlexThemeReference( + { base: { color: { surfaceNeutralFarther: ['#fafafa', '#1f1f1f'] } } }, + (description, appearance) => { + descriptions.push(description); + return { color: { foregroundNeutralPrimary: selectColorEntry(description.color.surfaceNeutralFarther.rest, appearance) } }; + }, + ); + + expect(reference.resolveFlexTokens(darkAppearance).color.foregroundNeutralPrimary.rest).toBe('#1f1f1f'); + expect(descriptions[0].color.backgroundBrandHeavy).toBe(defaultFlexTokenDescription.color.backgroundBrandHeavy); + expect(descriptions[0].color.backgroundBrandHeavy.type).toBe('inverted'); + expect(Object.isFrozen(descriptions[0].color.surfaceNeutralFarther)).toBe(true); + }); + + it('shares the default description when nothing is authored', () => { + const descriptions: FlexTokenDescription[] = []; + const reference = new FlexThemeReference({}, (description) => { + descriptions.push(description); + return {}; + }); + reference.resolveFlexTokens(defaultResolvedThemeAppearance); + + expect(descriptions[0]).toBe(defaultFlexTokenDescription); + }); + + it('rejects resolved tokens as authored input', () => { + const reference = new FlexThemeReference({}, defaultFlexTokens as unknown as PartialFlexTokens); + + expect(() => reference.resolveFlexTokens(defaultResolvedThemeAppearance)).toThrow('resolved InteractiveColor'); + }); + + it('rejects the removed color state maps with a migration message', () => { + const reference = new FlexThemeReference({}, { color: { hover: { backgroundBrandHeavy: '#123456' } } } as unknown as PartialFlexTokens); + + expect(() => reference.resolveFlexTokens(defaultResolvedThemeAppearance)).toThrow('color.hover maps are no longer supported'); }); }); diff --git a/packages/agentic/design/src/flex/flexThemeReference.ts b/packages/agentic/design/src/flex/flexThemeReference.ts index fd9ae6b021..060bc96297 100644 --- a/packages/agentic/design/src/flex/flexThemeReference.ts +++ b/packages/agentic/design/src/flex/flexThemeReference.ts @@ -1,20 +1,9 @@ import { immutableMerge } from '@fluentui-react-native/framework-base'; -import { defaultFlexTokens } from './defaults/defaultTokens'; -import type { - FlexTokens, - InteractiveColorOverrides, - SemanticBorderRadii, - SemanticColorTokenValues, - SemanticFontFamilies, - SemanticFontSizes, - SemanticFontWeights, - SemanticLineHeights, - SemanticShadows, - SemanticSpacing, - SemanticStrokeWidths, -} from './tokens.types'; -import { withDerivedInteractionColors } from './colors/interactionPolicy'; +import { defaultFlexTokenDescription } from './defaults/defaultTokens'; +import { mergeFlexTokenDescription } from './flexTokenDescription'; +import type { FlexTokenDescription, FlexTokens, PartialFlexTokens } from './tokens.types'; +import { resolveFlexTokenDescription } from './colors/interactionPolicy'; import { internResolvedThemeAppearance, themeAppearanceKey } from '../theming/appearance'; import type { NormalizedThemeAppearance, @@ -25,29 +14,20 @@ import type { import type { FlexThemeSource, OnThemeChange } from '../theming/themeSource'; import type { PartialTheme, Theme } from '../fluent/types/Theme.types'; -export type PartialFlexTokens = { - color?: Partial & { - hover?: Partial; - pressed?: Partial; - }; - shadow?: Partial; - fontWeight?: Partial; - fontFamily?: Partial; - fontSize?: Partial; - lineHeight?: Partial; - borderRadius?: Partial; - spacing?: Partial; - strokeWidth?: Partial; -}; - -export type FlexThemeInput = - | FlexTokens - | PartialFlexTokens - | ((appearance: Readonly) => FlexTokens | PartialFlexTokens); - +/** + * Authored base tokens layered over the package defaults. Resolved + * `FlexTokens` are appearance-bound outputs and are not accepted. + */ +export type FlexThemeInput = PartialFlexTokens | ((appearance: Readonly) => PartialFlexTokens); + +/** + * Authored overrides, or a function of the accumulated authored description + * and the appearance that returns overrides. Use `selectColorEntry` to read an + * appearance-specific authored color. + */ export type FlexThemeRecipe = | PartialFlexTokens - | ((parent: FlexTokens, appearance: Readonly) => PartialFlexTokens); + | ((description: FlexTokenDescription, appearance: Readonly) => PartialFlexTokens); export type LegacyThemeFallback = Theme | PartialTheme | ((appearance: Readonly) => Theme | PartialTheme); @@ -70,6 +50,7 @@ export class FlexThemeReference implements FlexThemeSource { private readonly legacyFallback?: LegacyThemeFallback; private recipes: FlexThemeRecipe[]; private readonly listeners = new Set(); + private readonly descriptionsByAppearance = new Map(); private readonly tokensByAppearance = new Map(); private parentListener?: OnThemeChange; private parentRevision?: number; @@ -92,7 +73,7 @@ export class FlexThemeReference implements FlexThemeSource { /** * Resolve the tokens for one appearance. A missing tone means cool. Omitted - * interactive hover and pressed values are derived from rest automatically. + * interactive hover and pressed values are computed from rest on first read. */ public resolveFlexTokens(requestedAppearance: ResolvedThemeAppearance): FlexTokens { this.syncParentRevision(); @@ -103,11 +84,7 @@ export class FlexThemeReference implements FlexThemeSource { return cached; } - let tokens = this.resolveBase(appearance); - for (const recipe of this.recipes) { - tokens = immutableMerge(tokens, typeof recipe === 'function' ? recipe(tokens, appearance) : recipe); - } - tokens = { ...tokens, color: withDerivedInteractionColors(tokens.color, appearance) }; + const tokens = resolveFlexTokenDescription(this.resolveDescription(appearance, key), appearance); this.tokensByAppearance.set(key, tokens); return tokens; } @@ -140,6 +117,7 @@ export class FlexThemeReference implements FlexThemeSource { public invalidate(): void { this.revisionValue += 1; + this.descriptionsByAppearance.clear(); this.tokensByAppearance.clear(); for (const listener of this.listeners) { listener(); @@ -151,12 +129,28 @@ export class FlexThemeReference implements FlexThemeSource { this.invalidate(); } - private resolveBase(appearance: Readonly): FlexTokens { + // Parents supply authored descriptions, never appearance-bound resolved tokens. + private resolveDescription(appearance: Readonly, key: string): FlexTokenDescription { + const cached = this.descriptionsByAppearance.get(key); + if (cached) { + return cached; + } + + let description = this.resolveBaseDescription(appearance, key); + for (const recipe of this.recipes) { + description = mergeFlexTokenDescription(description, typeof recipe === 'function' ? recipe(description, appearance) : recipe); + } + this.descriptionsByAppearance.set(key, description); + return description; + } + + private resolveBaseDescription(appearance: Readonly, key: string): FlexTokenDescription { if (this.base instanceof FlexThemeReference) { - return this.base.resolveFlexTokens(appearance); + this.base.syncParentRevision(); + return this.base.resolveDescription(appearance, key); } const base = typeof this.base === 'function' ? this.base(appearance) : this.base; - return base ? immutableMerge(defaultFlexTokens, base) : defaultFlexTokens; + return mergeFlexTokenDescription(defaultFlexTokenDescription, base); } private syncParentRevision(): void { diff --git a/packages/agentic/design/src/flex/flexTokenDescription.ts b/packages/agentic/design/src/flex/flexTokenDescription.ts new file mode 100644 index 0000000000..50e6448c33 --- /dev/null +++ b/packages/agentic/design/src/flex/flexTokenDescription.ts @@ -0,0 +1,109 @@ +import { immutableMerge } from '@fluentui-react-native/framework-base'; + +import type { + CompleteFlexTokenInput, + FlexColorDescription, + FlexTokenDescription, + FlexTokens, + InteractiveColor, + PartialFlexTokens, + SemanticColorDescriptions, + SemanticColors, +} from './tokens.types'; +import { normalizeFlexColor, resolveExplicitFlexColor } from './colors/flexColor'; +import type { ColorSchemeSelector } from './colors/flexColor'; + +/** Resolve one normalized color for an appearance. */ +export type FlexColorResolver = ( + token: string, + description: FlexColorDescription, + appearance: TAppearance, +) => InteractiveColor; + +const emptyColors = Object.freeze({}) as SemanticColorDescriptions; + +function mergeColors(base: SemanticColorDescriptions, colors: unknown): SemanticColorDescriptions { + if (typeof colors !== 'object' || colors === null || Array.isArray(colors)) { + throw new TypeError('Flex color overrides must be an object keyed by semantic color name.'); + } + + let merged: Record | undefined; + for (const name of Object.keys(colors)) { + const value = (colors as Record)[name]; + if (value === undefined) { + continue; + } + if (name === 'hover' || name === 'pressed') { + throw new TypeError(`color.${name} maps are no longer supported. Author { rest, ${name} } on each color instead.`); + } + const description = normalizeFlexColor(value as never, 'standard', `color.${name}`); + if (description !== (base as Record)[name]) { + merged ??= { ...base }; + merged[name] = description; + } + } + return merged ? (Object.freeze(merged) as SemanticColorDescriptions) : base; +} + +/** + * Merge authored overrides into a description. Each color replaces the + * previous description atomically, so omitted states never inherit stale + * explicit values. `undefined` colors are not overrides. Non-color groups keep + * deep-merge semantics. + * @internal + */ +export function mergeFlexTokenDescription(base: FlexTokenDescription, overrides: PartialFlexTokens | undefined): FlexTokenDescription { + if (overrides === undefined) { + return base; + } + if (typeof overrides !== 'object' || overrides === null || Array.isArray(overrides)) { + throw new TypeError('Flex token overrides must be an object.'); + } + + const { color, ...groups } = overrides; + const mergedColors = color === undefined ? base.color : mergeColors(base.color, color); + const hasGroups = Object.keys(groups).length > 0; + if (mergedColors === base.color && !hasGroups) { + return base; + } + + const { color: _baseColor, ...baseGroups } = base; + const mergedGroups = hasGroups ? immutableMerge(baseGroups as object, groups as object) : baseGroups; + return Object.freeze({ color: mergedColors, ...mergedGroups }) as FlexTokenDescription; +} + +/** + * Normalize a complete authored token set. + * @internal + */ +export function createFlexTokenDescription(tokens: CompleteFlexTokenInput): FlexTokenDescription { + const { color, ...groups } = tokens; + return Object.freeze({ color: mergeColors(emptyColors, color), ...groups }) as FlexTokenDescription; +} + +/** + * Resolve every color in a description with a color policy. Non-color groups + * are shared with the description. + * @internal + */ +export function resolveFlexTokenDescriptionWith( + description: FlexTokenDescription, + appearance: TAppearance, + resolveColor: FlexColorResolver, +): FlexTokens { + const color: Record = {}; + for (const name of Object.keys(description.color)) { + color[name] = resolveColor(name, (description.color as Record)[name], appearance); + } + const { color: _descriptionColor, ...groups } = description; + return Object.freeze({ color: Object.freeze(color) as SemanticColors, ...groups }) as FlexTokens; +} + +/** + * Resolve a description without interaction algorithms; omitted states equal + * rest. + * @internal + */ +export function resolveExplicitFlexTokenDescription(description: FlexTokenDescription, appearance: ColorSchemeSelector): FlexTokens { + return resolveFlexTokenDescriptionWith(description, appearance, (_token, color, selected) => resolveExplicitFlexColor(color, selected)); +} diff --git a/packages/agentic/design/src/flex/styling/colorStyles.test.ts b/packages/agentic/design/src/flex/styling/colorStyles.test.ts index 23ec0b76fd..8224f7e323 100644 --- a/packages/agentic/design/src/flex/styling/colorStyles.test.ts +++ b/packages/agentic/design/src/flex/styling/colorStyles.test.ts @@ -1,3 +1,4 @@ +import { createInteractiveColor } from '../colors/interactiveColor'; import type { FlexTokens } from '../tokens.types'; import { defaultFlexTokens } from '../defaults/defaultTokens'; import { defaultResolvedThemeAppearance } from '../../theming/appearance'; @@ -40,14 +41,14 @@ describe('colorStyles', () => { const tokens = defaultFlexTokens; const styles = colorStyleDef(definition, stateLevels)(tokens); - expect(styles.backgroundColor).toBe(tokens.color.backgroundNeutralSubtle); - expect(styles.borderColor).toBe(tokens.color.strokeNeutralTransparent); + expect(styles.backgroundColor).toBe(tokens.color.backgroundNeutralSubtle.rest); + expect(styles.borderColor).toBe(tokens.color.strokeNeutralTransparent.rest); expect(styles.selected).toMatchObject({ - backgroundColor: tokens.color.backgroundNeutralHeavy, + backgroundColor: tokens.color.backgroundNeutralHeavy.rest, }); expect(styles.disabled).toEqual({ - backgroundColor: tokens.color.backgroundNeutralSubtleDisabled, - borderColor: tokens.color.strokeNeutralDisabled, + backgroundColor: tokens.color.backgroundNeutralSubtleDisabled.rest, + borderColor: tokens.color.strokeNeutralDisabled.rest, }); }); @@ -56,24 +57,24 @@ describe('colorStyles', () => { const styles = colorStyleDef(definition, stateLevels)(tokens); expect(styles.hovered).toEqual({ - backgroundColor: tokens.color.hover.backgroundNeutralSubtle, - borderColor: tokens.color.hover.strokeNeutralTransparent, + backgroundColor: tokens.color.backgroundNeutralSubtle.hover, + borderColor: tokens.color.strokeNeutralTransparent.hover, }); expect(styles.pressed).toEqual({ - backgroundColor: tokens.color.pressed.backgroundNeutralSubtle, - borderColor: tokens.color.pressed.strokeNeutralTransparent, + backgroundColor: tokens.color.backgroundNeutralSubtle.pressed, + borderColor: tokens.color.strokeNeutralTransparent.pressed, }); expect(styles.selected?.hovered).toEqual({ - backgroundColor: tokens.color.hover.backgroundNeutralHeavy, - borderColor: tokens.color.hover.strokeNeutralHeavy, + backgroundColor: tokens.color.backgroundNeutralHeavy.hover, + borderColor: tokens.color.strokeNeutralHeavy.hover, }); expect(styles.selected?.pressed).toEqual({ - backgroundColor: tokens.color.pressed.backgroundNeutralHeavy, - borderColor: tokens.color.pressed.strokeNeutralTransparent, + backgroundColor: tokens.color.backgroundNeutralHeavy.pressed, + borderColor: tokens.color.strokeNeutralTransparent.pressed, }); }); - it('falls back to rest colors when an interaction map does not override a semantic key', () => { + it('uses the rest value in hovered nodes for colors without interaction states', () => { const tokens = defaultFlexTokens; const levels = [['hovered']] as const; const styles = colorStyleDef( @@ -86,7 +87,7 @@ describe('colorStyles', () => { levels, )(tokens); - expect(styles.hovered?.backgroundColor).toBe(tokens.color.backgroundNeutralHeavyDisabled); + expect(styles.hovered?.backgroundColor).toBe(tokens.color.backgroundNeutralHeavyDisabled.rest); }); it('preserves valid falsy color values', () => { @@ -95,7 +96,7 @@ describe('colorStyles', () => { ...tokens, color: { ...tokens.color, - backgroundBrandHeavy: '', + backgroundBrandHeavy: createInteractiveColor('', '', ''), }, } satisfies FlexTokens; const levels = [['disabled']] as const; @@ -127,8 +128,8 @@ describe('colorStyles', () => { const styles = colorStyleDef(threeLevelDefinition, levels)(tokens); expect(styles.selected?.pressed?.highContrast).toEqual({ - backgroundColor: tokens.color.pressed.backgroundNeutralHeavy, - borderColor: tokens.color.pressed.strokeNeutralHeavy, + backgroundColor: tokens.color.backgroundNeutralHeavy.pressed, + borderColor: tokens.color.strokeNeutralHeavy.pressed, }); }); @@ -138,14 +139,14 @@ describe('colorStyles', () => { const getStyle = getThemedColorStyleFactory('test.colors', definition, stateLevels); expect(getStyle(themeState, { selected: true, hovered: true })).toEqual({ - backgroundColor: colors.hover.backgroundNeutralHeavy, - borderColor: colors.hover.strokeNeutralHeavy, + backgroundColor: colors.backgroundNeutralHeavy.hover, + borderColor: colors.strokeNeutralHeavy.hover, }); const cachedEntries = Reflect.ownKeys(themeState.themeStyles).length; expect(getStyle(themeState, { selected: true, disabled: true })).toEqual({ - backgroundColor: colors.backgroundNeutralHeavyDisabled, - borderColor: colors.strokeNeutralDisabled, + backgroundColor: colors.backgroundNeutralHeavyDisabled.rest, + borderColor: colors.strokeNeutralDisabled.rest, }); expect(Reflect.ownKeys(themeState.themeStyles)).toHaveLength(cachedEntries); }); diff --git a/packages/agentic/design/src/flex/styling/colorStyles.ts b/packages/agentic/design/src/flex/styling/colorStyles.ts index 1a8ceb3a67..286028f758 100644 --- a/packages/agentic/design/src/flex/styling/colorStyles.ts +++ b/packages/agentic/design/src/flex/styling/colorStyles.ts @@ -1,6 +1,6 @@ -import type { ColorValue, TextStyle, ViewStyle } from 'react-native'; +import type { TextStyle, ViewStyle } from 'react-native'; -import type { FlexTokens, SemanticColors } from '../tokens.types'; +import type { FlexTokens, InteractiveColor, SemanticColorName, SemanticColors } from '../tokens.types'; import type { ThemeState } from '../../types/themeState.types'; import { createStateLevelMap, getThemedStateStyleFactory } from '../../styling/branchedStyle'; @@ -15,7 +15,7 @@ const colorStyleKeys: readonly ColorStyleKeys[] = ['backgroundColor', 'borderCol /** * A semantic color key available in the Flex tokens. */ -export type ColorKey = keyof Omit; +export type ColorKey = SemanticColorName; type AnyColorStyle = ViewColorStyle | TextColorStyle; type ColorKeysForStyle = { [K in keyof StyleType]: ColorKey }; @@ -39,7 +39,7 @@ interface RawColorDef { } type InheritedColorKeys = Partial>; type RawStyleDef = Record; -type InteractionColors = Partial>; +type ColorState = Exclude; function getColorKey(definition: RawColorDef, key: ColorStyleKeys): ColorKey | undefined { const value = definition[key]; @@ -51,19 +51,21 @@ function getStateDefinition(definition: RawColorDef, key: string): RawColorDef | return typeof value === 'object' && value !== null ? value : undefined; } -function getInteractionColors(colors: SemanticColors, state: string | undefined): InteractionColors | undefined { +function getColorState(state: string | undefined): ColorState | undefined { if (state === 'hovered') { - return colors.hover; + return 'hover'; } if (state === 'pressed') { - return colors.pressed; + return 'pressed'; } return undefined; } /** * Converts semantic color keys into resolved style values while synthesizing - * hovered and pressed nodes wherever those states are declared. + * hovered and pressed nodes wherever those states are declared. Hovered and + * pressed nodes read each color's matching state, so a derived state is + * computed when the style is first built for a theme state. */ function convertToStyleDef( name: string | undefined, @@ -72,18 +74,17 @@ function convertToStyleDef( rawColorDef: RawColorDef, stateLevels: StateLevels, nextLevel: number, - activeInteractionState?: string, + activeInteractionState?: ColorState, ): RawStyleDef { const result: RawStyleDef = {}; const inheritedKeys: InheritedColorKeys = { ...parent }; - const interactionState = getInteractionColors(colors, name) ? name : activeInteractionState; - const interactionColors = getInteractionColors(colors, interactionState); + const interactionState = getColorState(name) ?? activeInteractionState; for (const styleKey of colorStyleKeys) { - const colorKey = getColorKey(rawColorDef, styleKey) ?? (interactionColors ? parent?.[styleKey] : undefined); + const colorKey = getColorKey(rawColorDef, styleKey) ?? (interactionState ? parent?.[styleKey] : undefined); if (colorKey !== undefined) { inheritedKeys[styleKey] = colorKey; - const colorValue = interactionColors?.[colorKey] ?? colors[colorKey]; + const colorValue = colors[colorKey]?.[interactionState ?? 'rest']; if (colorValue !== undefined) { result[styleKey] = colorValue; } diff --git a/packages/agentic/design/src/flex/themeState.ts b/packages/agentic/design/src/flex/themeState.ts index 5ac9463b38..4e79fb8008 100644 --- a/packages/agentic/design/src/flex/themeState.ts +++ b/packages/agentic/design/src/flex/themeState.ts @@ -24,7 +24,7 @@ export function getFlexTokens(source: ThemeSource, appearance: Readonly>('../tokens/mappings/flex-from-theme.json'); -function getTokenPaths(tokens: object, color: { hover: object; pressed: object }): string[] { - const colorPaths = Object.keys(color) - .filter((name) => name !== 'hover' && name !== 'pressed') - .map((name) => `color.${name}`); - const interactiveColorPaths = ['hover', 'pressed'].flatMap((state) => Object.keys(color[state]).map((name) => `color.${state}.${name}`)); +function isColorOptions(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value) && 'rest' in value; +} + +// Authored color paths: rest always, and hover or pressed only when explicit. +function getTokenPaths(tokens: object, colors: object): string[] { + const colorPaths = Object.entries(colors).flatMap(([name, value]) => { + const states = isColorOptions(value) ? ['rest', 'hover', 'pressed'].filter((state) => value[state] !== undefined) : ['rest']; + return states.map((state) => `color.${name}.${state}`); + }); const groupPaths = Object.entries(tokens) .filter(([group]) => group !== 'color') .flatMap(([group, values]) => Object.keys(values).map((name) => `${group}.${name}`)); - return [...colorPaths, ...interactiveColorPaths, ...groupPaths].sort(); + return [...colorPaths, ...groupPaths].sort(); } describe('FlexTokens', () => { it('groups tokens and removes category prefixes from their names', () => { - expect(flexTokens.color.surfaceNeutralFarther).toBe('#ebebeb'); - expect(flexTokens.color.hover.surfaceNeutralFarther).toBe('#f5f5f5'); - expect(flexTokens.color.pressed.surfaceNeutralFarther).toBe('#f0f0f0'); + expect(flexTokens.color.surfaceNeutralFarther).toEqual({ rest: '#ebebeb', hover: '#f5f5f5', pressed: '#f0f0f0' }); expect(flexTokens.shadow.lowest.key.blur).toBe(2); expect(flexTokens.fontWeight.functionalRegular).toBe('400'); expect(flexTokens.fontFamily.functional).toBeTruthy(); @@ -30,38 +33,57 @@ describe('FlexTokens', () => { expect(flexTokens.borderRadius.base100).toBeGreaterThan(0); expect(flexTokens.spacing.componentBase100).toBeGreaterThan(0); expect(flexTokens.strokeWidth.thin).toBeGreaterThan(0); - expect(colorTokens.backgroundBrandHeavy).toBe('#185abd'); + expect(flexTokens.color.backgroundBrandHeavy.rest).toBe('#185abd'); }); - it('does not expose the previous flat token names', () => { + it('does not expose the previous flat token names or state maps', () => { expect('colorSurfaceNeutralFarther' in flexTokens).toBe(false); expect('shadowLowest' in flexTokens).toBe(false); expect('fontWeightFunctionalRegular' in flexTokens).toBe(false); + expect('hover' in flexTokens.color).toBe(false); + expect('pressed' in flexTokens.color).toBe(false); + }); + + it('resolves every default color with all three states', () => { + for (const [name, color] of Object.entries(defaultFlexTokens.color)) { + expect([name, Object.keys(color)]).toEqual([name, ['rest', 'hover', 'pressed']]); + } + expect(defaultFlexTokens.color.fixedBlack.hover).toBe(defaultFlexTokens.color.fixedBlack.rest); + expect(Object.isFrozen(defaultFlexTokens.color)).toBe(true); + }); + + it('authors inverse interaction metadata and explicit states on every interactive default', () => { + const colors = defaultFlexTokenDescription.color; + const inverted = Object.keys(colors).filter((name) => colors[name as keyof typeof colors].type === 'inverted'); + + expect(inverted).toEqual(INTERACTIVE_COLOR_TOKENS.filter(isInverseInteractionToken)); + for (const token of INTERACTIVE_COLOR_TOKENS) { + expect([token, colors[token].hover !== undefined, colors[token].pressed !== undefined]).toEqual([token, true, true]); + } }); it('builds defaults from values without FURN Theme sources', () => { const themeBackedPaths = new Set(Object.keys(flexFromTheme)); - const expectedNonFluentPaths = getTokenPaths(defaultFlexTokens, defaultFlexTokens.color).filter((path) => { + const expectedNonFluentPaths = getTokenPaths(defaultFlexTokens, defaultFlexTokenDescription.color).filter((path) => { if (themeBackedPaths.has(path)) { return false; } - const interactiveColor = path.match(/^color\.(?:hover|pressed)\.(.+)$/); - return !interactiveColor || !themeBackedPaths.has(`color.${interactiveColor[1]}`); + const interactiveColor = /^color\.([^.]+)\.(?:hover|pressed)$/.exec(path); + return !interactiveColor || !themeBackedPaths.has(`color.${interactiveColor[1]}.rest`); }); expect(getTokenPaths(nonFluentFlexTokens, nonFluentFlexTokens.color)).toEqual(expectedNonFluentPaths); expect(Object.keys(nonFluentFlexTokens)).toEqual(['color', 'lineHeight', 'borderRadius', 'spacing', 'strokeWidth']); - expect(nonFluentFlexTokens.color.backgroundNeutralSoft).toBe('#0000001a'); - expect(nonFluentFlexTokens.color.hover.backgroundNeutralSoft).toBe('#0000001a'); + expect(nonFluentFlexTokens.color.backgroundNeutralSoft).toEqual({ rest: '#0000001a', hover: '#0000001a', pressed: '#0000001a' }); expect(nonFluentFlexTokens.borderRadius.base100).toBe(2); expect('backgroundBrandHeavy' in nonFluentFlexTokens.color).toBe(false); - expect('backgroundBrandSoft' in nonFluentFlexTokens.color.hover).toBe(false); - expect('surfaceNeutralFarther' in nonFluentFlexTokens.color.hover).toBe(false); + expect('backgroundBrandSoft' in nonFluentFlexTokens.color).toBe(false); + expect('surfaceNeutralFarther' in nonFluentFlexTokens.color).toBe(false); expect('base200' in nonFluentFlexTokens.borderRadius).toBe(false); expect(defaultFlexTokens.lineHeight).toBe(nonFluentFlexTokens.lineHeight); - expect(defaultFlexTokens.color.backgroundNeutralSoft).toBe(nonFluentFlexTokens.color.backgroundNeutralSoft); - expect(defaultFlexTokens.color.backgroundBrandHeavy).toBe('#185abd'); - expect(defaultFlexTokens.color.hover.backgroundBrandSoft).toBe('#d2e0f4'); + expect(defaultFlexTokens.color.backgroundNeutralSoft.rest).toBe(nonFluentFlexTokens.color.backgroundNeutralSoft.rest); + expect(defaultFlexTokens.color.backgroundBrandHeavy.rest).toBe('#185abd'); + expect(defaultFlexTokens.color.backgroundBrandSoft.hover).toBe('#d2e0f4'); }); }); diff --git a/packages/agentic/design/src/flex/tokens.types.ts b/packages/agentic/design/src/flex/tokens.types.ts index 7329face10..ee57c3339f 100644 --- a/packages/agentic/design/src/flex/tokens.types.ts +++ b/packages/agentic/design/src/flex/tokens.types.ts @@ -6,278 +6,254 @@ type FontSize = TextStyle['fontSize']; type BorderRadius = ViewStyle['borderRadius']; type StrokeWidth = ViewStyle['borderWidth']; +/** A color that selects light at index zero and dark at index one. */ +export type ColorTuple = readonly [light: ColorValue, dark: ColorValue]; + +/** One authored color for every scheme, or a light/dark tuple. */ +export type ColorEntry = ColorValue | ColorTuple; + /** - * Every semantic color token's rest value. Interactive tokens carry only their - * rest value here; their `hover`/`pressed` states live in `SemanticColors`. + * How omitted interaction states derive from rest. Standard and inverted use + * opposite scheme-dependent lightness directions. Fixed requires explicit + * states for derivable literal colors. */ -export type SemanticColorTokenValues = { +export type InteractiveColorType = 'standard' | 'inverted' | 'fixed'; + +/** An authored color with optional explicit interaction states. */ +export type InteractiveColorOptions = { + rest: ColorEntry; + hover?: ColorEntry; + pressed?: ColorEntry; + type?: InteractiveColorType; +}; + +/** Any authored Flex color. */ +export type FlexColorInput = ColorEntry | InteractiveColorOptions; + +/** + * A normalized, frozen authored color. Omitted states stay omitted until the + * color resolves for an appearance. + */ +export type FlexColorDescription = { + readonly rest: ColorEntry; + readonly hover?: ColorEntry; + readonly pressed?: ColorEntry; + readonly type: InteractiveColorType; +}; + +/** + * A resolved Flex color for one appearance. Omitted states are computed on + * first read and memoized. + */ +export type InteractiveColor = { + readonly rest: ColorValue; + readonly hover: ColorValue; + readonly pressed: ColorValue; +}; + +/** + * Every semantic color token, resolved for one appearance. + */ +export type SemanticColors = { // surface / neutral - surfaceNeutralFarther: ColorValue; - surfaceNeutralFar: ColorValue; - surfaceNeutralNear: ColorValue; - surfaceNeutralNearer: ColorValue; - surfaceNeutralTranslucent: ColorValue; + surfaceNeutralFarther: InteractiveColor; + surfaceNeutralFar: InteractiveColor; + surfaceNeutralNear: InteractiveColor; + surfaceNeutralNearer: InteractiveColor; + surfaceNeutralTranslucent: InteractiveColor; // background / neutral - backgroundNeutralHeavy: ColorValue; - backgroundNeutralLoud: ColorValue; - backgroundNeutralSoft: ColorValue; - backgroundNeutralSubtle: ColorValue; - backgroundNeutralTransparent: ColorValue; - backgroundNeutralTranslucent: ColorValue; + backgroundNeutralHeavy: InteractiveColor; + backgroundNeutralLoud: InteractiveColor; + backgroundNeutralSoft: InteractiveColor; + backgroundNeutralSubtle: InteractiveColor; + backgroundNeutralTransparent: InteractiveColor; + backgroundNeutralTranslucent: InteractiveColor; // background / brand - backgroundBrandHeavy: ColorValue; - backgroundBrandLoud: ColorValue; - backgroundBrandSoft: ColorValue; - backgroundBrandSubtle: ColorValue; - backgroundBrandTransparent: ColorValue; + backgroundBrandHeavy: InteractiveColor; + backgroundBrandLoud: InteractiveColor; + backgroundBrandSoft: InteractiveColor; + backgroundBrandSubtle: InteractiveColor; + backgroundBrandTransparent: InteractiveColor; // background / danger - backgroundDangerLoud: ColorValue; - backgroundDangerSoft: ColorValue; - backgroundDangerSubtle: ColorValue; + backgroundDangerLoud: InteractiveColor; + backgroundDangerSoft: InteractiveColor; + backgroundDangerSubtle: InteractiveColor; // background / warning - backgroundWarningLoud: ColorValue; - backgroundWarningSoft: ColorValue; - backgroundWarningSubtle: ColorValue; + backgroundWarningLoud: InteractiveColor; + backgroundWarningSoft: InteractiveColor; + backgroundWarningSubtle: InteractiveColor; // background / success - backgroundSuccessLoud: ColorValue; - backgroundSuccessSoft: ColorValue; - backgroundSuccessSubtle: ColorValue; + backgroundSuccessLoud: InteractiveColor; + backgroundSuccessSoft: InteractiveColor; + backgroundSuccessSubtle: InteractiveColor; // stroke / neutral - strokeNeutralHeavy: ColorValue; - strokeNeutralLoud: ColorValue; - strokeNeutralSoft: ColorValue; - strokeNeutralSubtle: ColorValue; - strokeNeutralTransparent: ColorValue; - strokeNeutralOnloud: ColorValue; + strokeNeutralHeavy: InteractiveColor; + strokeNeutralLoud: InteractiveColor; + strokeNeutralSoft: InteractiveColor; + strokeNeutralSubtle: InteractiveColor; + strokeNeutralTransparent: InteractiveColor; + strokeNeutralOnloud: InteractiveColor; // stroke / brand - strokeBrandLoud: ColorValue; - strokeBrandSoft: ColorValue; - strokeBrandSubtle: ColorValue; - strokeBrandOnloud: ColorValue; + strokeBrandLoud: InteractiveColor; + strokeBrandSoft: InteractiveColor; + strokeBrandSubtle: InteractiveColor; + strokeBrandOnloud: InteractiveColor; // stroke / danger - strokeDangerLoud: ColorValue; - strokeDangerSoft: ColorValue; - strokeDangerSubtle: ColorValue; - strokeDangerOnloud: ColorValue; + strokeDangerLoud: InteractiveColor; + strokeDangerSoft: InteractiveColor; + strokeDangerSubtle: InteractiveColor; + strokeDangerOnloud: InteractiveColor; // stroke / warning - strokeWarningLoud: ColorValue; - strokeWarningSoft: ColorValue; - strokeWarningSubtle: ColorValue; - strokeWarningOnloud: ColorValue; + strokeWarningLoud: InteractiveColor; + strokeWarningSoft: InteractiveColor; + strokeWarningSubtle: InteractiveColor; + strokeWarningOnloud: InteractiveColor; // stroke / success - strokeSuccessLoud: ColorValue; - strokeSuccessSoft: ColorValue; - strokeSuccessSubtle: ColorValue; - strokeSuccessOnloud: ColorValue; + strokeSuccessLoud: InteractiveColor; + strokeSuccessSoft: InteractiveColor; + strokeSuccessSubtle: InteractiveColor; + strokeSuccessOnloud: InteractiveColor; // foreground / neutral - foregroundNeutralPrimary: ColorValue; - foregroundNeutralSecondary: ColorValue; - foregroundNeutralTertiary: ColorValue; - foregroundNeutralOnloud: ColorValue; + foregroundNeutralPrimary: InteractiveColor; + foregroundNeutralSecondary: InteractiveColor; + foregroundNeutralTertiary: InteractiveColor; + foregroundNeutralOnloud: InteractiveColor; // foreground / brand - foregroundBrandPrimary: ColorValue; - foregroundBrandOnloud: ColorValue; + foregroundBrandPrimary: InteractiveColor; + foregroundBrandOnloud: InteractiveColor; // foreground / danger - foregroundDangerPrimary: ColorValue; - foregroundDangerOnloud: ColorValue; + foregroundDangerPrimary: InteractiveColor; + foregroundDangerOnloud: InteractiveColor; // foreground / warning - foregroundWarningPrimary: ColorValue; - foregroundWarningOnloud: ColorValue; + foregroundWarningPrimary: InteractiveColor; + foregroundWarningOnloud: InteractiveColor; // foreground / success - foregroundSuccessPrimary: ColorValue; - foregroundSuccessOnloud: ColorValue; + foregroundSuccessPrimary: InteractiveColor; + foregroundSuccessOnloud: InteractiveColor; // fixed - fixedWhite: ColorValue; - fixedBlack: ColorValue; + fixedWhite: InteractiveColor; + fixedBlack: InteractiveColor; // expression / accent - expressionAccentHeavy: ColorValue; - expressionAccentLoud: ColorValue; - expressionAccentSoft: ColorValue; - expressionAccentSubtle: ColorValue; + expressionAccentHeavy: InteractiveColor; + expressionAccentLoud: InteractiveColor; + expressionAccentSoft: InteractiveColor; + expressionAccentSubtle: InteractiveColor; // expression / achromatic - expressionAchromaticHeavy: ColorValue; - expressionAchromaticSubtle: ColorValue; + expressionAchromaticHeavy: InteractiveColor; + expressionAchromaticSubtle: InteractiveColor; // expression / gray - expressionGrayHeavy: ColorValue; - expressionGrayLoud: ColorValue; - expressionGraySoft: ColorValue; - expressionGraySubtle: ColorValue; + expressionGrayHeavy: InteractiveColor; + expressionGrayLoud: InteractiveColor; + expressionGraySoft: InteractiveColor; + expressionGraySubtle: InteractiveColor; // expression / navy - expressionNavyHeavy: ColorValue; - expressionNavyLoud: ColorValue; - expressionNavySoft: ColorValue; - expressionNavySubtle: ColorValue; + expressionNavyHeavy: InteractiveColor; + expressionNavyLoud: InteractiveColor; + expressionNavySoft: InteractiveColor; + expressionNavySubtle: InteractiveColor; // expression / blue - expressionBlueHeavy: ColorValue; - expressionBlueLoud: ColorValue; - expressionBlueSoft: ColorValue; - expressionBlueSubtle: ColorValue; + expressionBlueHeavy: InteractiveColor; + expressionBlueLoud: InteractiveColor; + expressionBlueSoft: InteractiveColor; + expressionBlueSubtle: InteractiveColor; // expression / green - expressionGreenHeavy: ColorValue; - expressionGreenLoud: ColorValue; - expressionGreenSoft: ColorValue; - expressionGreenSubtle: ColorValue; + expressionGreenHeavy: InteractiveColor; + expressionGreenLoud: InteractiveColor; + expressionGreenSoft: InteractiveColor; + expressionGreenSubtle: InteractiveColor; // expression / lime - expressionLimeHeavy: ColorValue; - expressionLimeLoud: ColorValue; - expressionLimeSoft: ColorValue; - expressionLimeSubtle: ColorValue; + expressionLimeHeavy: InteractiveColor; + expressionLimeLoud: InteractiveColor; + expressionLimeSoft: InteractiveColor; + expressionLimeSubtle: InteractiveColor; // expression / yellow - expressionYellowHeavy: ColorValue; - expressionYellowLoud: ColorValue; - expressionYellowSoft: ColorValue; - expressionYellowSubtle: ColorValue; + expressionYellowHeavy: InteractiveColor; + expressionYellowLoud: InteractiveColor; + expressionYellowSoft: InteractiveColor; + expressionYellowSubtle: InteractiveColor; // expression / pumpkin - expressionPumpkinHeavy: ColorValue; - expressionPumpkinLoud: ColorValue; - expressionPumpkinSoft: ColorValue; - expressionPumpkinSubtle: ColorValue; + expressionPumpkinHeavy: InteractiveColor; + expressionPumpkinLoud: InteractiveColor; + expressionPumpkinSoft: InteractiveColor; + expressionPumpkinSubtle: InteractiveColor; // expression / red - expressionRedHeavy: ColorValue; - expressionRedLoud: ColorValue; - expressionRedSoft: ColorValue; - expressionRedSubtle: ColorValue; + expressionRedHeavy: InteractiveColor; + expressionRedLoud: InteractiveColor; + expressionRedSoft: InteractiveColor; + expressionRedSubtle: InteractiveColor; // expression / pink - expressionPinkHeavy: ColorValue; - expressionPinkLoud: ColorValue; - expressionPinkSoft: ColorValue; - expressionPinkSubtle: ColorValue; + expressionPinkHeavy: InteractiveColor; + expressionPinkLoud: InteractiveColor; + expressionPinkSoft: InteractiveColor; + expressionPinkSubtle: InteractiveColor; // expression / purple - expressionPurpleHeavy: ColorValue; - expressionPurpleLoud: ColorValue; - expressionPurpleSoft: ColorValue; - expressionPurpleSubtle: ColorValue; + expressionPurpleHeavy: InteractiveColor; + expressionPurpleLoud: InteractiveColor; + expressionPurpleSoft: InteractiveColor; + expressionPurpleSubtle: InteractiveColor; // overlay - overlayNeutralTranslucent: ColorValue; + overlayNeutralTranslucent: InteractiveColor; // material / background - materialBackgroundThick: ColorValue; - materialBackgroundRegular: ColorValue; - materialBackgroundThin: ColorValue; + materialBackgroundThick: InteractiveColor; + materialBackgroundRegular: InteractiveColor; + materialBackgroundThin: InteractiveColor; // disabled - backgroundNeutralDisabled: ColorValue; - backgroundNeutralHeavyDisabled: ColorValue; - backgroundNeutralSubtleDisabled: ColorValue; - strokeNeutralDisabled: ColorValue; - foregroundNeutralDisabled: ColorValue; + backgroundNeutralDisabled: InteractiveColor; + backgroundNeutralHeavyDisabled: InteractiveColor; + backgroundNeutralSubtleDisabled: InteractiveColor; + strokeNeutralDisabled: InteractiveColor; + foregroundNeutralDisabled: InteractiveColor; // focus strokes - strokeFocusInner: ColorValue; - strokeFocusOuter: ColorValue; + strokeFocusInner: InteractiveColor; + strokeFocusOuter: InteractiveColor; // shadow - shadow: ColorValue; + shadow: InteractiveColor; }; -/** - * The subset of `SemanticColorTokenValues` that has interaction states. Used to - * shape the `hover` and `pressed` override maps on `SemanticColors`. - * - * Source of truth: `dev/web/flex-themes/css/interaction-fallback.css`. - */ -export type InteractiveColorOverrides = Partial< - Pick< - SemanticColorTokenValues, - | 'surfaceNeutralFarther' - | 'surfaceNeutralFar' - | 'surfaceNeutralNear' - | 'surfaceNeutralNearer' - | 'surfaceNeutralTranslucent' - | 'backgroundNeutralHeavy' - | 'backgroundNeutralLoud' - | 'backgroundNeutralSoft' - | 'backgroundNeutralSubtle' - | 'backgroundNeutralTransparent' - | 'backgroundNeutralTranslucent' - | 'backgroundBrandHeavy' - | 'backgroundBrandLoud' - | 'backgroundBrandSoft' - | 'backgroundBrandSubtle' - | 'backgroundBrandTransparent' - | 'backgroundDangerLoud' - | 'backgroundDangerSoft' - | 'backgroundDangerSubtle' - | 'backgroundWarningLoud' - | 'backgroundWarningSoft' - | 'backgroundWarningSubtle' - | 'backgroundSuccessLoud' - | 'backgroundSuccessSoft' - | 'backgroundSuccessSubtle' - | 'strokeNeutralHeavy' - | 'strokeNeutralLoud' - | 'strokeNeutralSoft' - | 'strokeNeutralSubtle' - | 'strokeNeutralTransparent' - | 'strokeNeutralOnloud' - | 'strokeBrandLoud' - | 'strokeBrandSoft' - | 'strokeBrandSubtle' - | 'strokeBrandOnloud' - | 'strokeDangerLoud' - | 'strokeDangerSoft' - | 'strokeDangerSubtle' - | 'strokeDangerOnloud' - | 'strokeWarningLoud' - | 'strokeWarningSoft' - | 'strokeWarningSubtle' - | 'strokeWarningOnloud' - | 'strokeSuccessLoud' - | 'strokeSuccessSoft' - | 'strokeSuccessSubtle' - | 'strokeSuccessOnloud' - | 'foregroundNeutralPrimary' - | 'foregroundNeutralSecondary' - | 'foregroundNeutralTertiary' - | 'foregroundNeutralOnloud' - | 'foregroundBrandPrimary' - | 'foregroundBrandOnloud' - | 'foregroundDangerPrimary' - | 'foregroundDangerOnloud' - | 'foregroundWarningPrimary' - | 'foregroundWarningOnloud' - | 'foregroundSuccessPrimary' - | 'foregroundSuccessOnloud' - > ->; +/** A semantic color token name. */ +export type SemanticColorName = keyof SemanticColors; -/** - * The full semantic color token set: every token's rest value, plus `hover` and - * `pressed` maps that override only the interactive tokens. - */ -export type SemanticColors = SemanticColorTokenValues & { - hover: InteractiveColorOverrides; - pressed: InteractiveColorOverrides; -}; +/** One selected color value for each semantic color token. */ +export type SemanticColorTokenValues = { [Name in SemanticColorName]: ColorValue }; + +/** Authored semantic colors. `undefined` means no override. */ +export type PartialSemanticColors = { [Name in SemanticColorName]?: FlexColorInput }; + +/** Normalized authored semantic colors. */ +export type SemanticColorDescriptions = { readonly [Name in SemanticColorName]: FlexColorDescription }; /** * The semantic shadow token set @@ -435,6 +411,27 @@ export type FlexTokens = { export type SemanticTokens = FlexTokens; +type NonColorFlexTokenGroup = Exclude; + +/** + * Authored Flex token overrides. Each color is an atomic replacement; non-color + * groups deep merge. + */ +export type PartialFlexTokens = { color?: PartialSemanticColors } & { + [Group in NonColorFlexTokenGroup]?: Partial; +}; + +/** A complete authored Flex token set. */ +export type CompleteFlexTokenInput = { color: { [Name in SemanticColorName]: FlexColorInput } } & Pick; + +/** + * A complete, normalized authored token set before appearance resolution. + * Recipes receive this form. + */ +export type FlexTokenDescription = { readonly color: SemanticColorDescriptions } & { + readonly [Group in NonColorFlexTokenGroup]: FlexTokens[Group]; +}; + /** * These are flex tokens from web that are not supported on native. */ diff --git a/packages/agentic/design/src/flex/useThemeState.test.ts b/packages/agentic/design/src/flex/useThemeState.test.ts index a2f276c81c..6425bb1b2f 100644 --- a/packages/agentic/design/src/flex/useThemeState.test.ts +++ b/packages/agentic/design/src/flex/useThemeState.test.ts @@ -89,7 +89,7 @@ describe('useThemeState', () => { createCount += 1; return StyleSheet.create({ root: { - backgroundColor: tokens.color.backgroundNeutralSubtle, + backgroundColor: tokens.color.backgroundNeutralSubtle.rest, }, }); }); @@ -114,7 +114,7 @@ describe('useThemeState', () => { createCount += 1; return StyleSheet.create({ root: { - backgroundColor: tokens.color.backgroundNeutralSubtle, + backgroundColor: tokens.color.backgroundNeutralSubtle.rest, }, }); }); @@ -123,7 +123,7 @@ describe('useThemeState', () => { const second = getStyles(states[0]); expect(first).toBe(second); - expect(first.root.backgroundColor).toBe(states[0].tokens.color.backgroundNeutralSubtle); + expect(first.root.backgroundColor).toBe(states[0].tokens.color.backgroundNeutralSubtle.rest); expect(createCount).toBe(1); act(() => component!.unmount()); }); @@ -151,7 +151,7 @@ describe('useThemeState', () => { expect(states).toHaveLength(2); expect(states[0]).toBe(states[1]); - expect(states[0].tokens.color.backgroundNeutralSubtle).toBe('#123456'); + expect(states[0].tokens.color.backgroundNeutralSubtle.rest).toBe('#123456'); expect(states[0].highContrast).toBe(true); expect(states[0].appearance.contrast).toBe('highContrast'); expect(states[0].appearance.colorTone).toBe('cool'); @@ -185,7 +185,7 @@ describe('useThemeState', () => { }); expect(states[1]).not.toBe(states[0]); - expect(states[1].tokens.color.backgroundNeutralSubtle).toBe('#222222'); + expect(states[1].tokens.color.backgroundNeutralSubtle.rest).toBe('#222222'); act(() => component!.unmount()); }); @@ -217,7 +217,7 @@ describe('useThemeState', () => { }); expect(resolver).toHaveBeenCalledTimes(1); - expect(states[0].tokens.color.backgroundBrandHeavy).toBe('#123456'); + expect(states[0].tokens.color.backgroundBrandHeavy.rest).toBe('#123456'); expect(states[0].appearance).toBe(defaultResolvedThemeAppearance); act(() => component!.unmount()); }); diff --git a/packages/agentic/design/src/fluent/compat/index.ts b/packages/agentic/design/src/fluent/compat/index.ts index d64415b3b3..af898637d1 100644 --- a/packages/agentic/design/src/fluent/compat/index.ts +++ b/packages/agentic/design/src/fluent/compat/index.ts @@ -1,3 +1,3 @@ export { getDefaultLegacyTheme } from './defaultLegacyTheme'; export { themeFromFlexTokens } from './themeFromFlexTokens'; -export type { ThemeFromFlexTokensOptions } from './themeFromFlexTokens'; +export type { FlatFlexTokens, ThemeFromFlexTokensOptions } from './themeFromFlexTokens'; diff --git a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts index 5f83dee99e..f39b792434 100644 --- a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts +++ b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts @@ -1,8 +1,11 @@ +import { createInteractiveColor } from '../../flex/colors/interactiveColor'; import { defaultFlexTokens } from '../../flex/defaults/defaultTokens'; -import type { FlexTokens } from '../../flex/tokens.types'; +import type { FlexTokens, SemanticColorTokenValues } from '../../flex/tokens.types'; +import { restColorValues } from '../../test/fixtures/interactionColors'; import type { PartialTheme } from '../types/Theme.types'; import { themeFromFlexTokens } from './themeFromFlexTokens'; +import type { FlatFlexTokens } from './themeFromFlexTokens'; const light = { colorScheme: 'light', @@ -10,21 +13,21 @@ const light = { interfaceLevel: 'base', } as const; -function createTokens(): FlexTokens { - const hover = { ...defaultFlexTokens.color.hover }; - delete hover.surfaceNeutralNear; +function solid(value: string) { + return createInteractiveColor(value, value, value); +} +function createTokens(): FlexTokens { return { ...defaultFlexTokens, color: { ...defaultFlexTokens.color, - backgroundBrandSoft: '#111111', - backgroundBrandSubtle: '#222222', - backgroundNeutralSubtle: '#333333', - surfaceNeutralNear: '#444444', - fixedBlack: '#050505', - expressionAchromaticHeavy: '#060606', - hover, + backgroundBrandSoft: solid('#111111'), + backgroundBrandSubtle: solid('#222222'), + backgroundNeutralSubtle: solid('#333333'), + surfaceNeutralNear: createInteractiveColor('#444444', '#454545', '#464646'), + fixedBlack: solid('#050505'), + expressionAchromaticHeavy: solid('#060606'), }, borderRadius: { ...defaultFlexTokens.borderRadius, @@ -72,7 +75,8 @@ describe('themeFromFlexTokens', () => { expect(theme.colors.customLegacyColor).toBe('#abcdef'); expect(theme.colors.brandBackground2).toBe('#111111'); expect(theme.colors.neutralBackground2).toBe('#444444'); - expect(theme.colors.neutralBackground2Hover).toBe('#444444'); + expect(theme.colors.neutralBackground2Hover).toBe('#454545'); + expect(theme.colors.neutralBackground2Pressed).toBe('#464646'); expect(theme.colors.black).toBe('#050505'); expect(theme.components.Button.tokens).toMatchObject({ borderRadius: 12, @@ -111,6 +115,39 @@ describe('themeFromFlexTokens', () => { expect(first).not.toBe(second); expect(first.colors.customLegacyColor).toBe('#abcdef'); - expect(tokens.color.surfaceNeutralNear).toBe('#444444'); + expect(tokens.color.surfaceNeutralNear.rest).toBe('#444444'); + }); + + it('accepts the deprecated flat representation with optional state maps', () => { + const color: FlatFlexTokens['color'] = { + ...restColorValues(defaultFlexTokens.color), + surfaceNeutralNear: '#444444', + backgroundBrandHeavy: '#0f6cbd', + hover: { backgroundBrandHeavy: '#115ea3' } satisfies Partial, + }; + const flat: FlatFlexTokens = { ...defaultFlexTokens, color }; + + const theme = themeFromFlexTokens(flat, light); + + expect(theme.colors.neutralBackground2).toBe('#444444'); + expect(theme.colors.neutralBackground2Hover).toBe('#444444'); + expect(theme.colors.brandBackground).toBe('#0f6cbd'); + expect(theme.colors.brandBackgroundHover).toBe('#115ea3'); + expect(theme.colors.brandBackgroundPressed).toBe('#0f6cbd'); + }); + + it('projects the same legacy theme from resolved and equivalent flat tokens', () => { + const resolved = themeFromFlexTokens(defaultFlexTokens, light); + const values = restColorValues(defaultFlexTokens.color); + const flat: FlatFlexTokens = { + ...defaultFlexTokens, + color: { + ...values, + hover: Object.fromEntries(Object.entries(defaultFlexTokens.color).map(([name, entry]) => [name, entry.hover])), + pressed: Object.fromEntries(Object.entries(defaultFlexTokens.color).map(([name, entry]) => [name, entry.pressed])), + }, + }; + + expect(themeFromFlexTokens(flat, light)).toEqual(resolved); }); }); diff --git a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts index 6922fb6ea7..55968e2507 100644 --- a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts +++ b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts @@ -1,8 +1,8 @@ -import type { FlexTokens } from '../../flex/tokens.types'; +import type { FlexTokens, SemanticColorTokenValues } from '../../flex/tokens.types'; import reverseProjection from '../../tokens/mappings/theme-from-flex.json' with { type: 'json' }; import { appearanceOptionFromResolved } from '../../theming/appearance'; import type { ResolvedThemeAppearance } from '../../types/appearance.types'; -import { ensureParentRecord, getValueAtSegments, splitObjectPath } from '../../utilities/objects'; +import { ensureParentRecord, getValueAtSegments, isRecord, splitObjectPath } from '../../utilities/objects'; import { mergeTheme } from '../mergeTheme'; import type { PartialTheme, Theme } from '../types/Theme.types'; @@ -20,11 +20,49 @@ export interface ThemeFromFlexTokensOptions { fallback?: Theme | PartialTheme; } +/** + * Flex tokens in the representation used before interactive colors: each color + * is its rest value, and optional `color.hover` and `color.pressed` maps hold + * explicit states. + * + * @deprecated Pass resolved {@link FlexTokens}, whose colors carry + * `rest`, `hover`, and `pressed`. + */ +export type FlatFlexTokens = Omit & { + color: SemanticColorTokenValues & { + hover?: Partial; + pressed?: Partial; + }; +}; + +const colorStatePathPattern = /^color\.([^.]+)\.(rest|hover|pressed)$/; + +function getOwnValue(source: unknown, key: string): unknown { + return isRecord(source) && Object.prototype.hasOwnProperty.call(source, key) ? source[key] : undefined; +} + +/** + * Read a color state from resolved tokens, or from the flat representation + * where the color is its rest value and states live in `color.` maps. + */ +function getColorState(tokens: FlexTokens | FlatFlexTokens, name: string, state: string): unknown { + const colors = getOwnValue(tokens, 'color'); + const entry = getOwnValue(colors, name); + if (isRecord(entry) && Object.prototype.hasOwnProperty.call(entry, 'rest')) { + return entry[state]; + } + return state === 'rest' ? entry : getOwnValue(getOwnValue(colors, state), name); +} + function getPathSegments(path: string): string[] { return splitObjectPath(path, () => new Error(`Invalid generated theme projection path "${path}".`)); } -function getValueAtPath(source: object, path: string): unknown { +function getValueAtPath(source: FlexTokens | FlatFlexTokens, path: string): unknown { + const colorState = colorStatePathPattern.exec(path); + if (colorState) { + return getColorState(source, colorState[1], colorState[2]); + } return getValueAtSegments(source, getPathSegments(path)); } @@ -45,7 +83,7 @@ function applyTransform(value: unknown, transform?: ReverseTransform): unknown { return value; } -function projectThemeValues(tokens: FlexTokens): PartialTheme { +function projectThemeValues(tokens: FlexTokens | FlatFlexTokens): PartialTheme { const projected: Record = {}; for (const [themePath, descriptor] of Object.entries(reverseProjection as Record)) { let value = getValueAtPath(tokens, descriptor.source); @@ -64,10 +102,11 @@ function projectThemeValues(tokens: FlexTokens): PartialTheme { * * The compatibility base fills legacy-only values, the optional fallback adds * author or host metadata, mapped Flex values remain authoritative, and the - * final host appearance reflects the resolved structured appearance. + * final host appearance reflects the resolved structured appearance. Reading + * a derived interaction state computes it. */ export function themeFromFlexTokens( - tokens: FlexTokens, + tokens: FlexTokens | FlatFlexTokens, appearance: ResolvedThemeAppearance, options?: { fallback?: Theme | PartialTheme }, ): Theme { diff --git a/packages/agentic/design/src/fluent/useTheme.test.ts b/packages/agentic/design/src/fluent/useTheme.test.ts index 2618e3ac7f..264451bce3 100644 --- a/packages/agentic/design/src/fluent/useTheme.test.ts +++ b/packages/agentic/design/src/fluent/useTheme.test.ts @@ -112,7 +112,7 @@ describe('useTheme', () => { }); expect(themes[0]).toBe(rawTheme); - expect(states[0].tokens.color.backgroundNeutralSubtle).toBe('#654321'); + expect(states[0].tokens.color.backgroundNeutralSubtle.rest).toBe('#654321'); act(() => component!.unmount()); }); }); diff --git a/packages/agentic/design/src/index.ts b/packages/agentic/design/src/index.ts index 9332b6e8be..bb12fe9119 100644 --- a/packages/agentic/design/src/index.ts +++ b/packages/agentic/design/src/index.ts @@ -1,9 +1,19 @@ export type { FontSize, FontWeight } from './tokens/textAttributes'; export { fontSize, fontWeight } from './tokens/textAttributes'; export type { + ColorEntry, + ColorTuple, + FlexColorDescription, + FlexColorInput, + FlexTokenDescription, FlexTokens, - InteractiveColorOverrides, + InteractiveColor, + InteractiveColorOptions, + InteractiveColorType, + PartialSemanticColors, SemanticBorderRadii, + SemanticColorDescriptions, + SemanticColorName, SemanticColors, SemanticColorTokenValues, SemanticFontFamilies, @@ -16,7 +26,9 @@ export type { SemanticTokens, UnsupportedFlexTokens, } from './flex/tokens.types'; -export { INTERACTIVE_COLOR_TOKENS, isInverseInteractionToken } from './flex/colors/interactiveTokens'; +export { INTERACTIVE_COLOR_TOKENS, isInteractiveColorToken, isInverseInteractionToken } from './flex/colors/interactiveTokens'; +export { flexColor, selectColorEntry } from './flex/colors/flexColor'; +export type { ColorSchemeSelector } from './flex/colors/flexColor'; export type { InteractiveColorToken } from './flex/colors/interactiveTokens'; export { flexTokensFromTheme } from './flex/adapters/flexTokensFromTheme'; export { diff --git a/packages/agentic/design/src/test/color-validation/validation.test.ts b/packages/agentic/design/src/test/color-validation/validation.test.ts index c85c793566..b926a3e334 100644 --- a/packages/agentic/design/src/test/color-validation/validation.test.ts +++ b/packages/agentic/design/src/test/color-validation/validation.test.ts @@ -6,7 +6,7 @@ import { defaultFlexTokens } from '../../flex/defaults/defaultTokens'; import type { SemanticColorTokenValues } from '../../flex/tokens.types'; import type { ColorTone } from '../../types/appearance.types'; import { getContrastFailures, getUnresolvableContrastPairs, MODE_SURFACE, PAIRINGS, validateContrastPairs, WCAG } from '../index'; -import { getInteractionColorOverrides } from '../fixtures/interactionColors'; +import { getInteractionColorOverrides, restColorValues } from '../fixtures/interactionColors'; import { x3BebopWarmInteractionConformance, x3InteractionConformance } from '../fixtures/x3InteractionConformance'; function conformanceColors( @@ -14,7 +14,7 @@ function conformanceColors( conformance: typeof x3InteractionConformance | typeof x3BebopWarmInteractionConformance = x3InteractionConformance, ): SemanticColorTokenValues { const restIndex = mode === 'light' ? 0 : 3; - const { hover: _hover, pressed: _pressed, ...colors } = defaultFlexTokens.color; + const colors = restColorValues(defaultFlexTokens.color); for (const token of INTERACTIVE_COLOR_TOKENS) { colors[token] = conformance[token][restIndex]; } @@ -115,6 +115,14 @@ describe.each(['light', 'dark'] as const)('%s contrast validation', (mode) => { }); }); +describe('resolved color validation', () => { + it('audits resolved Flex colors at rest', () => { + expect(validateContrastPairs(defaultFlexTokens.color, 'light')).toEqual( + validateContrastPairs(restColorValues(defaultFlexTokens.color), 'light'), + ); + }); +}); + describe('unresolvable color validation', () => { it('identifies native foreground colors', () => { const colors = conformanceColors('light'); diff --git a/packages/agentic/design/src/test/color-validation/validation.ts b/packages/agentic/design/src/test/color-validation/validation.ts index 134dc98c27..33924cfc4c 100644 --- a/packages/agentic/design/src/test/color-validation/validation.ts +++ b/packages/agentic/design/src/test/color-validation/validation.ts @@ -1,6 +1,8 @@ import { parseColorValue, resolveContrastColors } from '../../color-lib'; import type { ColorDiagnostic, ColorMode } from '../../color-lib'; -import type { SemanticColorTokenValues } from '../../flex/tokens.types'; +import type { ColorValue } from 'react-native'; + +import type { InteractiveColor, SemanticColors, SemanticColorTokenValues } from '../../flex/tokens.types'; import { MODE_SURFACE } from './constants'; import { PAIRINGS } from './pairings'; import type { @@ -24,23 +26,33 @@ function diagnosticFor( }; } +function isResolvedColor(value: ColorValue | InteractiveColor): value is InteractiveColor { + return typeof value === 'object' && value !== null && 'rest' in value; +} + +function colorValue(colors: SemanticColorTokenValues | SemanticColors, token: ContrastColorToken): ColorValue { + const value = colors[token]; + return isResolvedColor(value) ? value.rest : value; +} + /** * Audit semantic colors against canonical or caller-supplied contrast - * pairings. This helper is intended for tests and design validation tooling, - * not component render paths. + * pairings. Resolved Flex colors are audited at rest; pass a flat map of hover + * or pressed values to audit an interaction state. This helper is intended for + * tests and design validation tooling, not component render paths. */ export function validateContrastPairs( - colors: SemanticColorTokenValues, + colors: SemanticColorTokenValues | SemanticColors, mode: ColorMode, pairings: readonly ContrastPairing[] = PAIRINGS, ): ContrastPairResult[] { const results: ContrastPairResult[] = []; for (const pairing of pairings) { - const foregroundValue = colors[pairing.foreground.token]; + const foregroundValue = colorValue(colors, pairing.foreground.token); const foreground = parseColorValue(foregroundValue); for (const backgroundReference of pairing.backgrounds) { - const backgroundValue = colors[backgroundReference.token]; + const backgroundValue = colorValue(colors, backgroundReference.token); const background = parseColorValue(backgroundValue); const base = { pairing, diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap index 0c6aa3b1bc..2b30281f80 100644 --- a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap @@ -9,12 +9,15 @@ exports[`public entry points . keeps its runtime export names 1`] = ` "ThemeProvider: function", "ThemedRoot: object", "createThemeAppearanceSource: function", + "flexColor: function", "flexTokensFromTheme: function", "fontSize: function", "fontWeight: function", + "isInteractiveColorToken: function", "isInverseInteractionToken: function", "normalizeThemeAppearanceRequest: function", "resolveThemeAppearance: function", + "selectColorEntry: function", "themedStyleSheetFactory: function", "useRootInputModality: function", "useRootSettings: function", @@ -106,6 +109,7 @@ exports[`public entry points ./theming keeps its runtime export names 1`] = ` "appearanceOptionFromResolved: function", "appearanceOptionsFromLegacy: function", "createThemeAppearanceSource: function", + "flexColor: function", "getCurrentAppearance: function", "isHighContrast: function", "mapFontPipelineToTheme: function", @@ -113,6 +117,7 @@ exports[`public entry points ./theming keeps its runtime export names 1`] = ` "mapPipelineToTheme: function", "normalizeThemeAppearanceRequest: function", "resolveThemeAppearance: function", + "selectColorEntry: function", "setIsHighContrast: function", "themeAppearanceKey: function", "useRootInputModality: function", diff --git a/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts b/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts index 35c29b1b46..93a5015d41 100644 --- a/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts +++ b/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts @@ -44,8 +44,8 @@ describe('legacy compatibility baseline', () => { }; const tokens = flexTokensFromTheme(theme); - expect(tokens.color.backgroundBrandHeavy).toEqual(rest); - expect(tokens.color.hover.backgroundBrandHeavy).toEqual(hover); + expect(tokens.color.backgroundBrandHeavy.rest).toBe(rest); + expect(tokens.color.backgroundBrandHeavy.hover).toBe(hover); const projected = themeFromFlexTokens(tokens, appearances[0][1]); expect(projected.colors.brandBackground).toEqual(rest); diff --git a/packages/agentic/design/src/test/compatibility/fingerprint.ts b/packages/agentic/design/src/test/compatibility/fingerprint.ts index 2ddda6025c..6d869658c3 100644 --- a/packages/agentic/design/src/test/compatibility/fingerprint.ts +++ b/packages/agentic/design/src/test/compatibility/fingerprint.ts @@ -41,15 +41,8 @@ export function fingerprint(value: unknown): string { export function effectiveFlexColors(color: FlexTokens['color']): Record { const result: Record = {}; for (const name of Object.keys(color).sort()) { - if (name === 'hover' || name === 'pressed') { - continue; - } - const rest = color[name as keyof typeof color]; - result[name] = { - rest, - hover: color.hover?.[name as keyof typeof color.hover] ?? rest, - pressed: color.pressed?.[name as keyof typeof color.pressed] ?? rest, - }; + const { rest, hover, pressed } = color[name as keyof typeof color]; + result[name] = { rest, hover, pressed }; } return result; } diff --git a/packages/agentic/design/src/test/fixtures/interactionColors.ts b/packages/agentic/design/src/test/fixtures/interactionColors.ts index b20d882158..005187e3a6 100644 --- a/packages/agentic/design/src/test/fixtures/interactionColors.ts +++ b/packages/agentic/design/src/test/fixtures/interactionColors.ts @@ -1,16 +1,20 @@ +import type { ColorValue } from 'react-native'; + import { getInteractionColor } from '../../color-lib/interaction'; import type { ColorMode, InteractionColorDiagnostic, InteractionColorState } from '../../color-lib/types'; import { getInteractionCompositing, getInteractionDirection, INTERACTIVE_COLOR_TOKENS } from '../../flex/colors/interactiveTokens'; import type { InteractiveColorToken } from '../../flex/colors/interactiveTokens'; -import type { InteractiveColorOverrides, SemanticColorTokenValues } from '../../flex/tokens.types'; +import type { SemanticColors, SemanticColorTokenValues } from '../../flex/tokens.types'; import type { ColorTone } from '../../types/appearance.types'; export interface InteractionAuditDiagnostic extends InteractionColorDiagnostic { readonly token: InteractiveColorToken; } +export type InteractionColorOverrides = Partial>; + export interface InteractionOverridesResult { - readonly overrides: InteractiveColorOverrides; + readonly overrides: InteractionColorOverrides; readonly diagnostics: readonly InteractionAuditDiagnostic[]; } @@ -25,7 +29,7 @@ export function getInteractionColorOverrides( state: InteractionColorState, colorTone: ColorTone = 'cool', ): InteractionOverridesResult { - const overrides: InteractiveColorOverrides = {}; + const overrides: InteractionColorOverrides = {}; const diagnostics: InteractionAuditDiagnostic[] = []; for (const token of INTERACTIVE_COLOR_TOKENS) { @@ -43,3 +47,10 @@ export function getInteractionColorOverrides( return { overrides, diagnostics }; } + +/** + * The rest value of every resolved color, keyed by token. + */ +export function restColorValues(colors: SemanticColors): SemanticColorTokenValues { + return Object.fromEntries(Object.entries(colors).map(([name, color]) => [name, color.rest])) as SemanticColorTokenValues; +} diff --git a/packages/agentic/design/src/theming/ThemedRoot.test.tsx b/packages/agentic/design/src/theming/ThemedRoot.test.tsx index e4bec4d363..448f7c277c 100644 --- a/packages/agentic/design/src/theming/ThemedRoot.test.tsx +++ b/packages/agentic/design/src/theming/ThemedRoot.test.tsx @@ -264,7 +264,7 @@ describe('ThemedRoot', () => { , ); - expect(nestedThemes[0].tokens.color.backgroundBrandHeavy).toBe('#111111'); + expect(nestedThemes[0].tokens.color.backgroundBrandHeavy.rest).toBe('#111111'); expect(nestedThemes[0].appearance).toEqual({ colorScheme: 'dark', contrast: 'highContrast', @@ -461,7 +461,7 @@ describe('ThemedRoot', () => { , ); - expect(themes[0].tokens.color.backgroundNeutralSubtle).toBe('#123456'); + expect(themes[0].tokens.color.backgroundNeutralSubtle.rest).toBe('#123456'); expect(themes[0].appearance.colorScheme).toBe('dark'); expect(themes[0].appearance.colorTone).toBe('cool'); }); diff --git a/packages/agentic/design/src/theming/index.ts b/packages/agentic/design/src/theming/index.ts index e6dec96df8..bcddc3f6ff 100644 --- a/packages/agentic/design/src/theming/index.ts +++ b/packages/agentic/design/src/theming/index.ts @@ -68,13 +68,10 @@ export { RootInputBoundary } from './RootInputBoundary'; export { useRootInputModality } from './useRootInputModality'; export type { InputModality, RootSettings } from './rootContext'; export { FlexThemeReference } from '../flex/flexThemeReference'; -export type { - FlexThemeInput, - FlexThemeRecipe, - FlexThemeReferenceOptions, - LegacyThemeFallback, - PartialFlexTokens, -} from '../flex/flexThemeReference'; +export type { FlexThemeInput, FlexThemeRecipe, FlexThemeReferenceOptions, LegacyThemeFallback } from '../flex/flexThemeReference'; +export { flexColor, selectColorEntry } from '../flex/colors/flexColor'; +export type { ColorSchemeSelector } from '../flex/colors/flexColor'; +export type { FlexTokenDescription, PartialFlexTokens } from '../flex/tokens.types'; export { ThemeReference } from '../fluent/themeReference'; export type { OnThemeChange, ThemeRecipe, ThemeReferenceOptions, ThemeTransform } from '../fluent/themeReference'; export type { FlexThemeSource, LegacyThemeSource, ThemeSource, ThemeSourceBase } from './themeSource'; diff --git a/packages/agentic/design/src/theming/modern.ts b/packages/agentic/design/src/theming/modern.ts index 06ec0e499d..baf7259ce7 100644 --- a/packages/agentic/design/src/theming/modern.ts +++ b/packages/agentic/design/src/theming/modern.ts @@ -21,13 +21,10 @@ export { } from './appearance'; export { createThemeAppearanceSource } from './appearanceSource'; export { FlexThemeReference } from '../flex/flexThemeReference'; -export type { - FlexThemeInput, - FlexThemeRecipe, - FlexThemeReferenceOptions, - LegacyThemeFallback, - PartialFlexTokens, -} from '../flex/flexThemeReference'; +export type { FlexThemeInput, FlexThemeRecipe, FlexThemeReferenceOptions, LegacyThemeFallback } from '../flex/flexThemeReference'; +export { flexColor, selectColorEntry } from '../flex/colors/flexColor'; +export type { ColorSchemeSelector } from '../flex/colors/flexColor'; +export type { FlexTokenDescription, PartialFlexTokens } from '../flex/tokens.types'; export { ThemeProvider } from './ThemeProvider'; export type { ThemeProviderProps } from './ThemeProvider'; export { ThemedRoot } from './ThemedRoot'; diff --git a/packages/agentic/design/src/tokens/mappings/flex-from-theme.json b/packages/agentic/design/src/tokens/mappings/flex-from-theme.json index 4e9a0a3760..e6683e6bc3 100644 --- a/packages/agentic/design/src/tokens/mappings/flex-from-theme.json +++ b/packages/agentic/design/src/tokens/mappings/flex-from-theme.json @@ -1,125 +1,125 @@ { "borderRadius.base200": "components.Button.tokens.borderRadius", "borderRadius.base300": "components.Button.tokens.borderRadius", - "color.backgroundBrandHeavy": "colors.brandBackground", - "color.backgroundBrandLoud": "colors.compoundBrandBackground1", - "color.backgroundBrandSoft": "colors.brandBackground2", - "color.backgroundBrandSubtle": "colors.brandBackground2", - "color.backgroundBrandTransparent": "colors.transparentBackground", - "color.backgroundDangerLoud": "colors.dangerBackground3", - "color.backgroundDangerSoft": "colors.dangerBackground2", - "color.backgroundDangerSubtle": "colors.dangerBackground1", - "color.backgroundNeutralDisabled": "colors.neutralBackgroundDisabled", - "color.backgroundNeutralHeavy": "colors.neutralBackgroundInverted", - "color.backgroundNeutralHeavyDisabled": "colors.neutralBackgroundDisabled", - "color.backgroundNeutralLoud": "colors.neutralBackgroundInverted", - "color.backgroundNeutralSubtle": "colors.neutralBackground2", - "color.backgroundNeutralSubtleDisabled": "colors.neutralBackgroundDisabled", - "color.backgroundNeutralTransparent": "colors.transparentBackground", - "color.backgroundSuccessLoud": "colors.successBackground3", - "color.backgroundSuccessSoft": "colors.successBackground2", - "color.backgroundSuccessSubtle": "colors.successBackground1", - "color.backgroundWarningLoud": "colors.warningBackground3", - "color.backgroundWarningSoft": "colors.warningBackground2", - "color.backgroundWarningSubtle": "colors.warningBackground1", - "color.expressionAchromaticHeavy": "colors.black", - "color.expressionAchromaticSubtle": "colors.white", - "color.fixedBlack": "colors.black", - "color.fixedWhite": "colors.white", - "color.foregroundBrandOnloud": "colors.neutralForegroundOnBrand", - "color.foregroundBrandPrimary": "colors.brandForeground1", - "color.foregroundDangerOnloud": "colors.neutralForegroundOnBrand", - "color.foregroundDangerPrimary": "colors.dangerForeground1", - "color.foregroundNeutralDisabled": "colors.neutralForegroundDisabled", - "color.foregroundNeutralOnloud": "colors.neutralForegroundOnBrand", - "color.foregroundNeutralPrimary": "colors.neutralForeground1", - "color.foregroundNeutralSecondary": "colors.neutralForeground2", - "color.foregroundNeutralTertiary": "colors.neutralForeground3", - "color.foregroundSuccessOnloud": "colors.neutralForegroundOnBrand", - "color.foregroundSuccessPrimary": "colors.successForeground1", - "color.foregroundWarningOnloud": "colors.neutralForegroundOnBrand", - "color.foregroundWarningPrimary": "colors.warningForeground1", - "color.hover.backgroundBrandHeavy": "colors.brandBackgroundHover", - "color.hover.backgroundBrandLoud": "colors.compoundBrandBackground1Hover", - "color.hover.backgroundBrandTransparent": "colors.transparentBackgroundHover", - "color.hover.backgroundNeutralSubtle": "colors.neutralBackground2Hover", - "color.hover.backgroundNeutralTransparent": "colors.transparentBackgroundHover", - "color.hover.foregroundBrandOnloud": "colors.neutralForegroundOnBrandHover", - "color.hover.foregroundDangerOnloud": "colors.neutralForegroundOnBrandHover", - "color.hover.foregroundNeutralOnloud": "colors.neutralForegroundOnBrandHover", - "color.hover.foregroundNeutralPrimary": "colors.neutralForeground1Hover", - "color.hover.foregroundNeutralSecondary": "colors.neutralForeground2Hover", - "color.hover.foregroundNeutralTertiary": "colors.neutralForeground3Hover", - "color.hover.foregroundSuccessOnloud": "colors.neutralForegroundOnBrandHover", - "color.hover.foregroundWarningOnloud": "colors.neutralForegroundOnBrandHover", - "color.hover.strokeBrandOnloud": "colors.neutralForegroundOnBrandHover", - "color.hover.strokeDangerOnloud": "colors.neutralForegroundOnBrandHover", - "color.hover.strokeNeutralHeavy": "colors.neutralStrokeAccessibleHover", - "color.hover.strokeNeutralLoud": "colors.neutralStroke1Hover", - "color.hover.strokeNeutralOnloud": "colors.neutralForegroundOnBrandHover", - "color.hover.strokeNeutralSoft": "colors.neutralStroke1Hover", - "color.hover.strokeNeutralTransparent": "colors.transparentStrokeInteractive", - "color.hover.strokeSuccessOnloud": "colors.neutralForegroundOnBrandHover", - "color.hover.strokeWarningOnloud": "colors.neutralForegroundOnBrandHover", - "color.hover.surfaceNeutralFar": "colors.neutralBackground3Hover", - "color.hover.surfaceNeutralFarther": "colors.neutralBackground5Hover", - "color.hover.surfaceNeutralNear": "colors.neutralBackground2Hover", - "color.hover.surfaceNeutralNearer": "colors.neutralBackground1Hover", - "color.pressed.backgroundBrandHeavy": "colors.brandBackgroundPressed", - "color.pressed.backgroundBrandLoud": "colors.compoundBrandBackground1Pressed", - "color.pressed.backgroundBrandTransparent": "colors.transparentBackgroundPressed", - "color.pressed.backgroundNeutralSubtle": "colors.neutralBackground2Pressed", - "color.pressed.backgroundNeutralTransparent": "colors.transparentBackgroundPressed", - "color.pressed.foregroundBrandOnloud": "colors.neutralForegroundOnBrandPressed", - "color.pressed.foregroundDangerOnloud": "colors.neutralForegroundOnBrandPressed", - "color.pressed.foregroundNeutralOnloud": "colors.neutralForegroundOnBrandPressed", - "color.pressed.foregroundNeutralPrimary": "colors.neutralForeground1Pressed", - "color.pressed.foregroundNeutralSecondary": "colors.neutralForeground2Pressed", - "color.pressed.foregroundNeutralTertiary": "colors.neutralForeground3Pressed", - "color.pressed.foregroundSuccessOnloud": "colors.neutralForegroundOnBrandPressed", - "color.pressed.foregroundWarningOnloud": "colors.neutralForegroundOnBrandPressed", - "color.pressed.strokeBrandOnloud": "colors.neutralForegroundOnBrandPressed", - "color.pressed.strokeDangerOnloud": "colors.neutralForegroundOnBrandPressed", - "color.pressed.strokeNeutralHeavy": "colors.neutralStrokeAccessiblePressed", - "color.pressed.strokeNeutralLoud": "colors.neutralStroke1Pressed", - "color.pressed.strokeNeutralOnloud": "colors.neutralForegroundOnBrandPressed", - "color.pressed.strokeNeutralSoft": "colors.neutralStroke1Pressed", - "color.pressed.strokeSuccessOnloud": "colors.neutralForegroundOnBrandPressed", - "color.pressed.strokeWarningOnloud": "colors.neutralForegroundOnBrandPressed", - "color.pressed.surfaceNeutralFar": "colors.neutralBackground3Pressed", - "color.pressed.surfaceNeutralFarther": "colors.neutralBackground5Pressed", - "color.pressed.surfaceNeutralNear": "colors.neutralBackground2Pressed", - "color.pressed.surfaceNeutralNearer": "colors.neutralBackground1Pressed", - "color.shadow": "colors.black", - "color.strokeBrandLoud": "colors.brandStroke1", - "color.strokeBrandOnloud": "colors.neutralForegroundOnBrand", - "color.strokeBrandSoft": "colors.brandStroke1", - "color.strokeBrandSubtle": "colors.brandStroke2", - "color.strokeDangerLoud": "colors.dangerBorder2", - "color.strokeDangerOnloud": "colors.neutralForegroundOnBrand", - "color.strokeDangerSoft": "colors.dangerBorder1", - "color.strokeDangerSubtle": "colors.dangerBorder1", - "color.strokeFocusInner": "colors.strokeFocus1", - "color.strokeFocusOuter": "colors.strokeFocus2", - "color.strokeNeutralDisabled": "colors.neutralStrokeDisabled", - "color.strokeNeutralHeavy": "colors.neutralStrokeAccessible", - "color.strokeNeutralLoud": "colors.neutralStroke1", - "color.strokeNeutralOnloud": "colors.neutralForegroundOnBrand", - "color.strokeNeutralSoft": "colors.neutralStroke1", - "color.strokeNeutralSubtle": "colors.neutralStroke2", - "color.strokeNeutralTransparent": "colors.transparentStroke", - "color.strokeSuccessLoud": "colors.successBorder2", - "color.strokeSuccessOnloud": "colors.neutralForegroundOnBrand", - "color.strokeSuccessSoft": "colors.successBorder1", - "color.strokeSuccessSubtle": "colors.successBorder1", - "color.strokeWarningLoud": "colors.warningBorder2", - "color.strokeWarningOnloud": "colors.neutralForegroundOnBrand", - "color.strokeWarningSoft": "colors.warningBorder1", - "color.strokeWarningSubtle": "colors.warningBorder1", - "color.surfaceNeutralFar": "colors.neutralBackground3", - "color.surfaceNeutralFarther": "colors.neutralBackground5", - "color.surfaceNeutralNear": "colors.neutralBackground2", - "color.surfaceNeutralNearer": "colors.neutralBackground1", + "color.backgroundBrandHeavy.hover": "colors.brandBackgroundHover", + "color.backgroundBrandHeavy.pressed": "colors.brandBackgroundPressed", + "color.backgroundBrandHeavy.rest": "colors.brandBackground", + "color.backgroundBrandLoud.hover": "colors.compoundBrandBackground1Hover", + "color.backgroundBrandLoud.pressed": "colors.compoundBrandBackground1Pressed", + "color.backgroundBrandLoud.rest": "colors.compoundBrandBackground1", + "color.backgroundBrandSoft.rest": "colors.brandBackground2", + "color.backgroundBrandSubtle.rest": "colors.brandBackground2", + "color.backgroundBrandTransparent.hover": "colors.transparentBackgroundHover", + "color.backgroundBrandTransparent.pressed": "colors.transparentBackgroundPressed", + "color.backgroundBrandTransparent.rest": "colors.transparentBackground", + "color.backgroundDangerLoud.rest": "colors.dangerBackground3", + "color.backgroundDangerSoft.rest": "colors.dangerBackground2", + "color.backgroundDangerSubtle.rest": "colors.dangerBackground1", + "color.backgroundNeutralDisabled.rest": "colors.neutralBackgroundDisabled", + "color.backgroundNeutralHeavy.rest": "colors.neutralBackgroundInverted", + "color.backgroundNeutralHeavyDisabled.rest": "colors.neutralBackgroundDisabled", + "color.backgroundNeutralLoud.rest": "colors.neutralBackgroundInverted", + "color.backgroundNeutralSubtle.hover": "colors.neutralBackground2Hover", + "color.backgroundNeutralSubtle.pressed": "colors.neutralBackground2Pressed", + "color.backgroundNeutralSubtle.rest": "colors.neutralBackground2", + "color.backgroundNeutralSubtleDisabled.rest": "colors.neutralBackgroundDisabled", + "color.backgroundNeutralTransparent.hover": "colors.transparentBackgroundHover", + "color.backgroundNeutralTransparent.pressed": "colors.transparentBackgroundPressed", + "color.backgroundNeutralTransparent.rest": "colors.transparentBackground", + "color.backgroundSuccessLoud.rest": "colors.successBackground3", + "color.backgroundSuccessSoft.rest": "colors.successBackground2", + "color.backgroundSuccessSubtle.rest": "colors.successBackground1", + "color.backgroundWarningLoud.rest": "colors.warningBackground3", + "color.backgroundWarningSoft.rest": "colors.warningBackground2", + "color.backgroundWarningSubtle.rest": "colors.warningBackground1", + "color.expressionAchromaticHeavy.rest": "colors.black", + "color.expressionAchromaticSubtle.rest": "colors.white", + "color.fixedBlack.rest": "colors.black", + "color.fixedWhite.rest": "colors.white", + "color.foregroundBrandOnloud.hover": "colors.neutralForegroundOnBrandHover", + "color.foregroundBrandOnloud.pressed": "colors.neutralForegroundOnBrandPressed", + "color.foregroundBrandOnloud.rest": "colors.neutralForegroundOnBrand", + "color.foregroundBrandPrimary.rest": "colors.brandForeground1", + "color.foregroundDangerOnloud.hover": "colors.neutralForegroundOnBrandHover", + "color.foregroundDangerOnloud.pressed": "colors.neutralForegroundOnBrandPressed", + "color.foregroundDangerOnloud.rest": "colors.neutralForegroundOnBrand", + "color.foregroundDangerPrimary.rest": "colors.dangerForeground1", + "color.foregroundNeutralDisabled.rest": "colors.neutralForegroundDisabled", + "color.foregroundNeutralOnloud.hover": "colors.neutralForegroundOnBrandHover", + "color.foregroundNeutralOnloud.pressed": "colors.neutralForegroundOnBrandPressed", + "color.foregroundNeutralOnloud.rest": "colors.neutralForegroundOnBrand", + "color.foregroundNeutralPrimary.hover": "colors.neutralForeground1Hover", + "color.foregroundNeutralPrimary.pressed": "colors.neutralForeground1Pressed", + "color.foregroundNeutralPrimary.rest": "colors.neutralForeground1", + "color.foregroundNeutralSecondary.hover": "colors.neutralForeground2Hover", + "color.foregroundNeutralSecondary.pressed": "colors.neutralForeground2Pressed", + "color.foregroundNeutralSecondary.rest": "colors.neutralForeground2", + "color.foregroundNeutralTertiary.hover": "colors.neutralForeground3Hover", + "color.foregroundNeutralTertiary.pressed": "colors.neutralForeground3Pressed", + "color.foregroundNeutralTertiary.rest": "colors.neutralForeground3", + "color.foregroundSuccessOnloud.hover": "colors.neutralForegroundOnBrandHover", + "color.foregroundSuccessOnloud.pressed": "colors.neutralForegroundOnBrandPressed", + "color.foregroundSuccessOnloud.rest": "colors.neutralForegroundOnBrand", + "color.foregroundSuccessPrimary.rest": "colors.successForeground1", + "color.foregroundWarningOnloud.hover": "colors.neutralForegroundOnBrandHover", + "color.foregroundWarningOnloud.pressed": "colors.neutralForegroundOnBrandPressed", + "color.foregroundWarningOnloud.rest": "colors.neutralForegroundOnBrand", + "color.foregroundWarningPrimary.rest": "colors.warningForeground1", + "color.shadow.rest": "colors.black", + "color.strokeBrandLoud.rest": "colors.brandStroke1", + "color.strokeBrandOnloud.hover": "colors.neutralForegroundOnBrandHover", + "color.strokeBrandOnloud.pressed": "colors.neutralForegroundOnBrandPressed", + "color.strokeBrandOnloud.rest": "colors.neutralForegroundOnBrand", + "color.strokeBrandSoft.rest": "colors.brandStroke1", + "color.strokeBrandSubtle.rest": "colors.brandStroke2", + "color.strokeDangerLoud.rest": "colors.dangerBorder2", + "color.strokeDangerOnloud.hover": "colors.neutralForegroundOnBrandHover", + "color.strokeDangerOnloud.pressed": "colors.neutralForegroundOnBrandPressed", + "color.strokeDangerOnloud.rest": "colors.neutralForegroundOnBrand", + "color.strokeDangerSoft.rest": "colors.dangerBorder1", + "color.strokeDangerSubtle.rest": "colors.dangerBorder1", + "color.strokeFocusInner.rest": "colors.strokeFocus1", + "color.strokeFocusOuter.rest": "colors.strokeFocus2", + "color.strokeNeutralDisabled.rest": "colors.neutralStrokeDisabled", + "color.strokeNeutralHeavy.hover": "colors.neutralStrokeAccessibleHover", + "color.strokeNeutralHeavy.pressed": "colors.neutralStrokeAccessiblePressed", + "color.strokeNeutralHeavy.rest": "colors.neutralStrokeAccessible", + "color.strokeNeutralLoud.hover": "colors.neutralStroke1Hover", + "color.strokeNeutralLoud.pressed": "colors.neutralStroke1Pressed", + "color.strokeNeutralLoud.rest": "colors.neutralStroke1", + "color.strokeNeutralOnloud.hover": "colors.neutralForegroundOnBrandHover", + "color.strokeNeutralOnloud.pressed": "colors.neutralForegroundOnBrandPressed", + "color.strokeNeutralOnloud.rest": "colors.neutralForegroundOnBrand", + "color.strokeNeutralSoft.hover": "colors.neutralStroke1Hover", + "color.strokeNeutralSoft.pressed": "colors.neutralStroke1Pressed", + "color.strokeNeutralSoft.rest": "colors.neutralStroke1", + "color.strokeNeutralSubtle.rest": "colors.neutralStroke2", + "color.strokeNeutralTransparent.hover": "colors.transparentStrokeInteractive", + "color.strokeNeutralTransparent.rest": "colors.transparentStroke", + "color.strokeSuccessLoud.rest": "colors.successBorder2", + "color.strokeSuccessOnloud.hover": "colors.neutralForegroundOnBrandHover", + "color.strokeSuccessOnloud.pressed": "colors.neutralForegroundOnBrandPressed", + "color.strokeSuccessOnloud.rest": "colors.neutralForegroundOnBrand", + "color.strokeSuccessSoft.rest": "colors.successBorder1", + "color.strokeSuccessSubtle.rest": "colors.successBorder1", + "color.strokeWarningLoud.rest": "colors.warningBorder2", + "color.strokeWarningOnloud.hover": "colors.neutralForegroundOnBrandHover", + "color.strokeWarningOnloud.pressed": "colors.neutralForegroundOnBrandPressed", + "color.strokeWarningOnloud.rest": "colors.neutralForegroundOnBrand", + "color.strokeWarningSoft.rest": "colors.warningBorder1", + "color.strokeWarningSubtle.rest": "colors.warningBorder1", + "color.surfaceNeutralFar.hover": "colors.neutralBackground3Hover", + "color.surfaceNeutralFar.pressed": "colors.neutralBackground3Pressed", + "color.surfaceNeutralFar.rest": "colors.neutralBackground3", + "color.surfaceNeutralFarther.hover": "colors.neutralBackground5Hover", + "color.surfaceNeutralFarther.pressed": "colors.neutralBackground5Pressed", + "color.surfaceNeutralFarther.rest": "colors.neutralBackground5", + "color.surfaceNeutralNear.hover": "colors.neutralBackground2Hover", + "color.surfaceNeutralNear.pressed": "colors.neutralBackground2Pressed", + "color.surfaceNeutralNear.rest": "colors.neutralBackground2", + "color.surfaceNeutralNearer.hover": "colors.neutralBackground1Hover", + "color.surfaceNeutralNearer.pressed": "colors.neutralBackground1Pressed", + "color.surfaceNeutralNearer.rest": "colors.neutralBackground1", "fontFamily.content": "typography.families.primary", "fontFamily.contentCode": "typography.families.monospace", "fontFamily.contentEditorial": "typography.families.serif", diff --git a/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml b/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml index 83a9cea7bb..9660237a2d 100644 --- a/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml +++ b/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml @@ -30,9 +30,9 @@ rules: colorStates: shape: Each color has a required rest mapping and optional hover and pressed mappings. projection: - rest: color. - hover: color.hover. - pressed: color.pressed. + rest: color..rest + hover: color..hover + pressed: color..pressed fluentAliases: Alias references identify explicit state leaves such as alias.brandBackground.rest, alias.brandBackground.hover, and alias.brandBackground.pressed. matching: @@ -59,12 +59,14 @@ rules: - scripts/token-mappings/check-mappings.cjs enforces that flex-from-theme.json exactly matches the furn-theme mappings in this file. - ../../flex/adapters/flexTokensFromTheme.ts consumes flex-from-theme.json and merges the projected - Theme values over nonFluentFlexTokens. + Theme values over nonFluentFlexTokens. An interaction state the Theme does not map + resolves to the Theme's rest value; the forward adapter never runs the interaction + algorithm. - The same check enforces that nonFluentFlexTokens in ../../flex/defaults/defaultTokens.ts covers - unmapped supported destinations. An unmapped hover or pressed fallback is + unmapped supported destinations. An unmapped hover or pressed value is included only when its rest destination is also unmapped; otherwise the state - value remains only in defaultFlexTokens so a Theme-provided rest value does - not inherit a mismatched fallback interaction color. + value remains only in defaultFlexTokenDescription so a Theme-provided rest value + does not inherit a mismatched fallback interaction color. - Button uses borderRadius.base200 / base300 / base400 for small / medium / large. The FURN Theme exposes its shared small/medium Button radius, but its large size-specific radius remains sourced from Fluent global tokens. @@ -77,135 +79,135 @@ reverse: transforms: {} canonical: colors.black: - source: color.fixedBlack + source: color.fixedBlack.rest omitted: - - color.expressionAchromaticHeavy - - color.shadow + - color.expressionAchromaticHeavy.rest + - color.shadow.rest reason: The fixed invariant is the canonical legacy black value; expression and shadow roles may diverge in Flex themes. colors.brandBackground2: - source: color.backgroundBrandSoft + source: color.backgroundBrandSoft.rest omitted: - - color.backgroundBrandSubtle + - color.backgroundBrandSubtle.rest reason: The soft brand background is the closest general-purpose match for legacy brandBackground2. colors.brandStroke1: - source: color.strokeBrandLoud + source: color.strokeBrandLoud.rest omitted: - - color.strokeBrandSoft + - color.strokeBrandSoft.rest reason: The loud brand stroke is the primary stroke role represented by legacy brandStroke1. colors.dangerBorder1: - source: color.strokeDangerSoft + source: color.strokeDangerSoft.rest omitted: - - color.strokeDangerSubtle + - color.strokeDangerSubtle.rest reason: The soft danger stroke is the closest general-purpose match for legacy dangerBorder1. colors.neutralBackground2: - source: color.surfaceNeutralNear + source: color.surfaceNeutralNear.rest omitted: - - color.backgroundNeutralSubtle + - color.backgroundNeutralSubtle.rest reason: The near neutral surface preserves the legacy neutralBackground2 surface progression. colors.neutralBackground2Hover: - source: color.hover.surfaceNeutralNear + source: color.surfaceNeutralNear.hover omitted: - - color.hover.backgroundNeutralSubtle + - color.backgroundNeutralSubtle.hover reason: Use the interaction state paired with the canonical near neutral surface. colors.neutralBackground2Pressed: - source: color.pressed.surfaceNeutralNear + source: color.surfaceNeutralNear.pressed omitted: - - color.pressed.backgroundNeutralSubtle + - color.backgroundNeutralSubtle.pressed reason: Use the interaction state paired with the canonical near neutral surface. colors.neutralBackgroundDisabled: - source: color.backgroundNeutralDisabled + source: color.backgroundNeutralDisabled.rest omitted: - - color.backgroundNeutralHeavyDisabled - - color.backgroundNeutralSubtleDisabled + - color.backgroundNeutralHeavyDisabled.rest + - color.backgroundNeutralSubtleDisabled.rest reason: The unqualified disabled background is the canonical general legacy disabled value. colors.neutralBackgroundInverted: - source: color.backgroundNeutralHeavy + source: color.backgroundNeutralHeavy.rest omitted: - - color.backgroundNeutralLoud + - color.backgroundNeutralLoud.rest reason: The heavy neutral background is the strongest general inverted background role. colors.neutralForegroundOnBrand: - source: color.foregroundNeutralOnloud + source: color.foregroundNeutralOnloud.rest omitted: - - color.foregroundBrandOnloud - - color.foregroundDangerOnloud - - color.foregroundSuccessOnloud - - color.foregroundWarningOnloud - - color.strokeBrandOnloud - - color.strokeDangerOnloud - - color.strokeNeutralOnloud - - color.strokeSuccessOnloud - - color.strokeWarningOnloud + - color.foregroundBrandOnloud.rest + - color.foregroundDangerOnloud.rest + - color.foregroundSuccessOnloud.rest + - color.foregroundWarningOnloud.rest + - color.strokeBrandOnloud.rest + - color.strokeDangerOnloud.rest + - color.strokeNeutralOnloud.rest + - color.strokeSuccessOnloud.rest + - color.strokeWarningOnloud.rest reason: The neutral on-loud foreground is the generic on-color legacy foreground role. colors.neutralForegroundOnBrandHover: - source: color.hover.foregroundNeutralOnloud + source: color.foregroundNeutralOnloud.hover omitted: - - color.hover.foregroundBrandOnloud - - color.hover.foregroundDangerOnloud - - color.hover.foregroundSuccessOnloud - - color.hover.foregroundWarningOnloud - - color.hover.strokeBrandOnloud - - color.hover.strokeDangerOnloud - - color.hover.strokeNeutralOnloud - - color.hover.strokeSuccessOnloud - - color.hover.strokeWarningOnloud + - color.foregroundBrandOnloud.hover + - color.foregroundDangerOnloud.hover + - color.foregroundSuccessOnloud.hover + - color.foregroundWarningOnloud.hover + - color.strokeBrandOnloud.hover + - color.strokeDangerOnloud.hover + - color.strokeNeutralOnloud.hover + - color.strokeSuccessOnloud.hover + - color.strokeWarningOnloud.hover reason: Use the interaction state paired with the canonical neutral on-loud foreground. colors.neutralForegroundOnBrandPressed: - source: color.pressed.foregroundNeutralOnloud + source: color.foregroundNeutralOnloud.pressed omitted: - - color.pressed.foregroundBrandOnloud - - color.pressed.foregroundDangerOnloud - - color.pressed.foregroundSuccessOnloud - - color.pressed.foregroundWarningOnloud - - color.pressed.strokeBrandOnloud - - color.pressed.strokeDangerOnloud - - color.pressed.strokeNeutralOnloud - - color.pressed.strokeSuccessOnloud - - color.pressed.strokeWarningOnloud + - color.foregroundBrandOnloud.pressed + - color.foregroundDangerOnloud.pressed + - color.foregroundSuccessOnloud.pressed + - color.foregroundWarningOnloud.pressed + - color.strokeBrandOnloud.pressed + - color.strokeDangerOnloud.pressed + - color.strokeNeutralOnloud.pressed + - color.strokeSuccessOnloud.pressed + - color.strokeWarningOnloud.pressed reason: Use the interaction state paired with the canonical neutral on-loud foreground. colors.neutralStroke1: - source: color.strokeNeutralLoud + source: color.strokeNeutralLoud.rest omitted: - - color.strokeNeutralSoft + - color.strokeNeutralSoft.rest reason: The loud neutral stroke is the primary stroke role represented by legacy neutralStroke1. colors.neutralStroke1Hover: - source: color.hover.strokeNeutralLoud + source: color.strokeNeutralLoud.hover omitted: - - color.hover.strokeNeutralSoft + - color.strokeNeutralSoft.hover reason: Use the interaction state paired with the canonical loud neutral stroke. colors.neutralStroke1Pressed: - source: color.pressed.strokeNeutralLoud + source: color.strokeNeutralLoud.pressed omitted: - - color.pressed.strokeNeutralSoft + - color.strokeNeutralSoft.pressed reason: Use the interaction state paired with the canonical loud neutral stroke. colors.successBorder1: - source: color.strokeSuccessSoft + source: color.strokeSuccessSoft.rest omitted: - - color.strokeSuccessSubtle + - color.strokeSuccessSubtle.rest reason: The soft success stroke is the closest general-purpose match for legacy successBorder1. colors.transparentBackground: - source: color.backgroundNeutralTransparent + source: color.backgroundNeutralTransparent.rest omitted: - - color.backgroundBrandTransparent + - color.backgroundBrandTransparent.rest reason: The neutral transparent background is the generic legacy transparent background role. colors.transparentBackgroundHover: - source: color.hover.backgroundNeutralTransparent + source: color.backgroundNeutralTransparent.hover omitted: - - color.hover.backgroundBrandTransparent + - color.backgroundBrandTransparent.hover reason: Use the interaction state paired with the canonical neutral transparent background. colors.transparentBackgroundPressed: - source: color.pressed.backgroundNeutralTransparent + source: color.backgroundNeutralTransparent.pressed omitted: - - color.pressed.backgroundBrandTransparent + - color.backgroundBrandTransparent.pressed reason: Use the interaction state paired with the canonical neutral transparent background. colors.warningBorder1: - source: color.strokeWarningSoft + source: color.strokeWarningSoft.rest omitted: - - color.strokeWarningSubtle + - color.strokeWarningSubtle.rest reason: The soft warning stroke is the closest general-purpose match for legacy warningBorder1. colors.white: - source: color.fixedWhite + source: color.fixedWhite.rest omitted: - - color.expressionAchromaticSubtle + - color.expressionAchromaticSubtle.rest reason: The fixed invariant is the canonical legacy white value; expression roles may diverge in Flex themes. components.Button.tokens.borderRadius: source: borderRadius.base200 diff --git a/packages/agentic/design/src/tokens/mappings/flexTokenMappings.test.ts b/packages/agentic/design/src/tokens/mappings/flexTokenMappings.test.ts index 5e42afa849..884c670174 100644 --- a/packages/agentic/design/src/tokens/mappings/flexTokenMappings.test.ts +++ b/packages/agentic/design/src/tokens/mappings/flexTokenMappings.test.ts @@ -109,12 +109,12 @@ describe('Flex token mapping consistency', () => { it('rejects interaction fallbacks when the rest destination is Theme-backed', () => { const changed = cloneInputs(inputs); - changed.nonFluentValues.set('color.hover.backgroundBrandSoft', "'#000000'"); + changed.nonFluentValues.set('color.backgroundBrandSoft.hover', "'#000000'"); expect(validateMappingInputs(changed)).toContainEqual({ rule: 'interaction-fallback', - path: 'color.hover.backgroundBrandSoft', - expected: 'color.backgroundBrandSoft to be absent from flex-from-theme.json', + path: 'color.backgroundBrandSoft.hover', + expected: 'color.backgroundBrandSoft.rest to be absent from flex-from-theme.json', actual: 'colors.brandBackground2', }); }); @@ -164,14 +164,14 @@ describe('Flex token mapping consistency', () => { expect(validateMappingInputs(changed)).toContainEqual({ rule: 'reverse-canonical', path: 'colors.black', - expected: 'one of ["color.expressionAchromaticHeavy","color.fixedBlack","color.shadow"]', + expected: 'one of ["color.expressionAchromaticHeavy.rest","color.fixedBlack.rest","color.shadow.rest"]', actual: 'color.notARealToken', }); }); it('requires every non-canonical candidate and an omission reason', () => { const changed = cloneInputs(inputs); - changed.mapping.reverse.canonical['colors.black'].omitted = ['color.expressionAchromaticHeavy']; + changed.mapping.reverse.canonical['colors.black'].omitted = ['color.expressionAchromaticHeavy.rest']; changed.mapping.reverse.canonical['colors.white'].reason = ''; const violations = validateMappingInputs(changed); @@ -179,8 +179,8 @@ describe('Flex token mapping consistency', () => { expect(violations).toContainEqual({ rule: 'reverse-omission', path: 'colors.black', - expected: ['color.expressionAchromaticHeavy', 'color.shadow'], - actual: ['color.expressionAchromaticHeavy'], + expected: ['color.expressionAchromaticHeavy.rest', 'color.shadow.rest'], + actual: ['color.expressionAchromaticHeavy.rest'], }); expect(violations).toContainEqual({ rule: 'reverse-omission', @@ -192,13 +192,13 @@ describe('Flex token mapping consistency', () => { it('validates generated interaction fallbacks against declared Flex paths', () => { const changed = cloneInputs(inputs); - changed.supportedTypePaths.delete('color.backgroundBrandHeavy'); + changed.supportedTypePaths.delete('color.backgroundBrandHeavy.rest'); expect(validateMappingInputs(changed)).toContainEqual({ rule: 'reverse-fallback', path: 'colors.brandBackgroundHover', expected: 'a declared Flex rest path', - actual: 'color.backgroundBrandHeavy', + actual: 'color.backgroundBrandHeavy.rest', }); }); @@ -229,16 +229,32 @@ describe('Flex token mapping consistency', () => { it('reports drift in the checked-in reverse projection', () => { const changed = cloneInputs(inputs); - changed.reverseProjection['colors.black'] = { source: 'color.shadow' }; + changed.reverseProjection['colors.black'] = { source: 'color.shadow.rest' }; expect(validateMappingInputs(changed)).toContainEqual({ rule: 'reverse-projection', path: 'colors.black', - expected: { source: 'color.fixedBlack' }, - actual: { source: 'color.shadow' }, + expected: { source: 'color.fixedBlack.rest' }, + actual: { source: 'color.shadow.rest' }, }); }); + it('projects color states to nested Flex paths', () => { + expect(inputs.themeProjection['color.backgroundBrandHeavy.rest']).toBe('colors.brandBackground'); + expect(inputs.themeProjection['color.backgroundBrandHeavy.hover']).toBe('colors.brandBackgroundHover'); + expect(inputs.reverseProjection['colors.brandBackgroundHover']).toEqual({ + source: 'color.backgroundBrandHeavy.hover', + fallback: 'color.backgroundBrandHeavy.rest', + }); + expect(Object.keys(inputs.themeProjection).filter((path) => /^color\.(?:hover|pressed)\./.test(path))).toEqual([]); + }); + + it('reads non-Fluent colors as rest values and explicit interaction states', () => { + expect(inputs.nonFluentValues.get('color.expressionAccentHeavy.rest')).toBe("'#242424'"); + expect(inputs.nonFluentValues.get('color.backgroundNeutralSoft.hover')).toBe("'#0000001a'"); + expect(inputs.nonFluentValues.has('color.expressionAccentHeavy')).toBe(false); + }); + it('rejects unknown mapping schema versions', () => { const changed = cloneInputs(inputs); changed.mapping.schemaVersion = 3; diff --git a/packages/agentic/design/src/tokens/mappings/theme-from-flex.json b/packages/agentic/design/src/tokens/mappings/theme-from-flex.json index 7ce60c8a65..d94ff3bf3d 100644 --- a/packages/agentic/design/src/tokens/mappings/theme-from-flex.json +++ b/packages/agentic/design/src/tokens/mappings/theme-from-flex.json @@ -1,246 +1,246 @@ { "colors.black": { - "source": "color.fixedBlack" + "source": "color.fixedBlack.rest" }, "colors.brandBackground": { - "source": "color.backgroundBrandHeavy" + "source": "color.backgroundBrandHeavy.rest" }, "colors.brandBackground2": { - "source": "color.backgroundBrandSoft" + "source": "color.backgroundBrandSoft.rest" }, "colors.brandBackgroundHover": { - "source": "color.hover.backgroundBrandHeavy", - "fallback": "color.backgroundBrandHeavy" + "source": "color.backgroundBrandHeavy.hover", + "fallback": "color.backgroundBrandHeavy.rest" }, "colors.brandBackgroundPressed": { - "source": "color.pressed.backgroundBrandHeavy", - "fallback": "color.backgroundBrandHeavy" + "source": "color.backgroundBrandHeavy.pressed", + "fallback": "color.backgroundBrandHeavy.rest" }, "colors.brandForeground1": { - "source": "color.foregroundBrandPrimary" + "source": "color.foregroundBrandPrimary.rest" }, "colors.brandStroke1": { - "source": "color.strokeBrandLoud" + "source": "color.strokeBrandLoud.rest" }, "colors.brandStroke2": { - "source": "color.strokeBrandSubtle" + "source": "color.strokeBrandSubtle.rest" }, "colors.compoundBrandBackground1": { - "source": "color.backgroundBrandLoud" + "source": "color.backgroundBrandLoud.rest" }, "colors.compoundBrandBackground1Hover": { - "source": "color.hover.backgroundBrandLoud", - "fallback": "color.backgroundBrandLoud" + "source": "color.backgroundBrandLoud.hover", + "fallback": "color.backgroundBrandLoud.rest" }, "colors.compoundBrandBackground1Pressed": { - "source": "color.pressed.backgroundBrandLoud", - "fallback": "color.backgroundBrandLoud" + "source": "color.backgroundBrandLoud.pressed", + "fallback": "color.backgroundBrandLoud.rest" }, "colors.dangerBackground1": { - "source": "color.backgroundDangerSubtle" + "source": "color.backgroundDangerSubtle.rest" }, "colors.dangerBackground2": { - "source": "color.backgroundDangerSoft" + "source": "color.backgroundDangerSoft.rest" }, "colors.dangerBackground3": { - "source": "color.backgroundDangerLoud" + "source": "color.backgroundDangerLoud.rest" }, "colors.dangerBorder1": { - "source": "color.strokeDangerSoft" + "source": "color.strokeDangerSoft.rest" }, "colors.dangerBorder2": { - "source": "color.strokeDangerLoud" + "source": "color.strokeDangerLoud.rest" }, "colors.dangerForeground1": { - "source": "color.foregroundDangerPrimary" + "source": "color.foregroundDangerPrimary.rest" }, "colors.neutralBackground1": { - "source": "color.surfaceNeutralNearer" + "source": "color.surfaceNeutralNearer.rest" }, "colors.neutralBackground1Hover": { - "source": "color.hover.surfaceNeutralNearer", - "fallback": "color.surfaceNeutralNearer" + "source": "color.surfaceNeutralNearer.hover", + "fallback": "color.surfaceNeutralNearer.rest" }, "colors.neutralBackground1Pressed": { - "source": "color.pressed.surfaceNeutralNearer", - "fallback": "color.surfaceNeutralNearer" + "source": "color.surfaceNeutralNearer.pressed", + "fallback": "color.surfaceNeutralNearer.rest" }, "colors.neutralBackground2": { - "source": "color.surfaceNeutralNear" + "source": "color.surfaceNeutralNear.rest" }, "colors.neutralBackground2Hover": { - "source": "color.hover.surfaceNeutralNear", - "fallback": "color.surfaceNeutralNear" + "source": "color.surfaceNeutralNear.hover", + "fallback": "color.surfaceNeutralNear.rest" }, "colors.neutralBackground2Pressed": { - "source": "color.pressed.surfaceNeutralNear", - "fallback": "color.surfaceNeutralNear" + "source": "color.surfaceNeutralNear.pressed", + "fallback": "color.surfaceNeutralNear.rest" }, "colors.neutralBackground3": { - "source": "color.surfaceNeutralFar" + "source": "color.surfaceNeutralFar.rest" }, "colors.neutralBackground3Hover": { - "source": "color.hover.surfaceNeutralFar", - "fallback": "color.surfaceNeutralFar" + "source": "color.surfaceNeutralFar.hover", + "fallback": "color.surfaceNeutralFar.rest" }, "colors.neutralBackground3Pressed": { - "source": "color.pressed.surfaceNeutralFar", - "fallback": "color.surfaceNeutralFar" + "source": "color.surfaceNeutralFar.pressed", + "fallback": "color.surfaceNeutralFar.rest" }, "colors.neutralBackground5": { - "source": "color.surfaceNeutralFarther" + "source": "color.surfaceNeutralFarther.rest" }, "colors.neutralBackground5Hover": { - "source": "color.hover.surfaceNeutralFarther", - "fallback": "color.surfaceNeutralFarther" + "source": "color.surfaceNeutralFarther.hover", + "fallback": "color.surfaceNeutralFarther.rest" }, "colors.neutralBackground5Pressed": { - "source": "color.pressed.surfaceNeutralFarther", - "fallback": "color.surfaceNeutralFarther" + "source": "color.surfaceNeutralFarther.pressed", + "fallback": "color.surfaceNeutralFarther.rest" }, "colors.neutralBackgroundDisabled": { - "source": "color.backgroundNeutralDisabled" + "source": "color.backgroundNeutralDisabled.rest" }, "colors.neutralBackgroundInverted": { - "source": "color.backgroundNeutralHeavy" + "source": "color.backgroundNeutralHeavy.rest" }, "colors.neutralForeground1": { - "source": "color.foregroundNeutralPrimary" + "source": "color.foregroundNeutralPrimary.rest" }, "colors.neutralForeground1Hover": { - "source": "color.hover.foregroundNeutralPrimary", - "fallback": "color.foregroundNeutralPrimary" + "source": "color.foregroundNeutralPrimary.hover", + "fallback": "color.foregroundNeutralPrimary.rest" }, "colors.neutralForeground1Pressed": { - "source": "color.pressed.foregroundNeutralPrimary", - "fallback": "color.foregroundNeutralPrimary" + "source": "color.foregroundNeutralPrimary.pressed", + "fallback": "color.foregroundNeutralPrimary.rest" }, "colors.neutralForeground2": { - "source": "color.foregroundNeutralSecondary" + "source": "color.foregroundNeutralSecondary.rest" }, "colors.neutralForeground2Hover": { - "source": "color.hover.foregroundNeutralSecondary", - "fallback": "color.foregroundNeutralSecondary" + "source": "color.foregroundNeutralSecondary.hover", + "fallback": "color.foregroundNeutralSecondary.rest" }, "colors.neutralForeground2Pressed": { - "source": "color.pressed.foregroundNeutralSecondary", - "fallback": "color.foregroundNeutralSecondary" + "source": "color.foregroundNeutralSecondary.pressed", + "fallback": "color.foregroundNeutralSecondary.rest" }, "colors.neutralForeground3": { - "source": "color.foregroundNeutralTertiary" + "source": "color.foregroundNeutralTertiary.rest" }, "colors.neutralForeground3Hover": { - "source": "color.hover.foregroundNeutralTertiary", - "fallback": "color.foregroundNeutralTertiary" + "source": "color.foregroundNeutralTertiary.hover", + "fallback": "color.foregroundNeutralTertiary.rest" }, "colors.neutralForeground3Pressed": { - "source": "color.pressed.foregroundNeutralTertiary", - "fallback": "color.foregroundNeutralTertiary" + "source": "color.foregroundNeutralTertiary.pressed", + "fallback": "color.foregroundNeutralTertiary.rest" }, "colors.neutralForegroundDisabled": { - "source": "color.foregroundNeutralDisabled" + "source": "color.foregroundNeutralDisabled.rest" }, "colors.neutralForegroundOnBrand": { - "source": "color.foregroundNeutralOnloud" + "source": "color.foregroundNeutralOnloud.rest" }, "colors.neutralForegroundOnBrandHover": { - "source": "color.hover.foregroundNeutralOnloud", - "fallback": "color.foregroundNeutralOnloud" + "source": "color.foregroundNeutralOnloud.hover", + "fallback": "color.foregroundNeutralOnloud.rest" }, "colors.neutralForegroundOnBrandPressed": { - "source": "color.pressed.foregroundNeutralOnloud", - "fallback": "color.foregroundNeutralOnloud" + "source": "color.foregroundNeutralOnloud.pressed", + "fallback": "color.foregroundNeutralOnloud.rest" }, "colors.neutralStroke1": { - "source": "color.strokeNeutralLoud" + "source": "color.strokeNeutralLoud.rest" }, "colors.neutralStroke1Hover": { - "source": "color.hover.strokeNeutralLoud", - "fallback": "color.strokeNeutralLoud" + "source": "color.strokeNeutralLoud.hover", + "fallback": "color.strokeNeutralLoud.rest" }, "colors.neutralStroke1Pressed": { - "source": "color.pressed.strokeNeutralLoud", - "fallback": "color.strokeNeutralLoud" + "source": "color.strokeNeutralLoud.pressed", + "fallback": "color.strokeNeutralLoud.rest" }, "colors.neutralStroke2": { - "source": "color.strokeNeutralSubtle" + "source": "color.strokeNeutralSubtle.rest" }, "colors.neutralStrokeAccessible": { - "source": "color.strokeNeutralHeavy" + "source": "color.strokeNeutralHeavy.rest" }, "colors.neutralStrokeAccessibleHover": { - "source": "color.hover.strokeNeutralHeavy", - "fallback": "color.strokeNeutralHeavy" + "source": "color.strokeNeutralHeavy.hover", + "fallback": "color.strokeNeutralHeavy.rest" }, "colors.neutralStrokeAccessiblePressed": { - "source": "color.pressed.strokeNeutralHeavy", - "fallback": "color.strokeNeutralHeavy" + "source": "color.strokeNeutralHeavy.pressed", + "fallback": "color.strokeNeutralHeavy.rest" }, "colors.neutralStrokeDisabled": { - "source": "color.strokeNeutralDisabled" + "source": "color.strokeNeutralDisabled.rest" }, "colors.strokeFocus1": { - "source": "color.strokeFocusInner" + "source": "color.strokeFocusInner.rest" }, "colors.strokeFocus2": { - "source": "color.strokeFocusOuter" + "source": "color.strokeFocusOuter.rest" }, "colors.successBackground1": { - "source": "color.backgroundSuccessSubtle" + "source": "color.backgroundSuccessSubtle.rest" }, "colors.successBackground2": { - "source": "color.backgroundSuccessSoft" + "source": "color.backgroundSuccessSoft.rest" }, "colors.successBackground3": { - "source": "color.backgroundSuccessLoud" + "source": "color.backgroundSuccessLoud.rest" }, "colors.successBorder1": { - "source": "color.strokeSuccessSoft" + "source": "color.strokeSuccessSoft.rest" }, "colors.successBorder2": { - "source": "color.strokeSuccessLoud" + "source": "color.strokeSuccessLoud.rest" }, "colors.successForeground1": { - "source": "color.foregroundSuccessPrimary" + "source": "color.foregroundSuccessPrimary.rest" }, "colors.transparentBackground": { - "source": "color.backgroundNeutralTransparent" + "source": "color.backgroundNeutralTransparent.rest" }, "colors.transparentBackgroundHover": { - "source": "color.hover.backgroundNeutralTransparent", - "fallback": "color.backgroundNeutralTransparent" + "source": "color.backgroundNeutralTransparent.hover", + "fallback": "color.backgroundNeutralTransparent.rest" }, "colors.transparentBackgroundPressed": { - "source": "color.pressed.backgroundNeutralTransparent", - "fallback": "color.backgroundNeutralTransparent" + "source": "color.backgroundNeutralTransparent.pressed", + "fallback": "color.backgroundNeutralTransparent.rest" }, "colors.transparentStroke": { - "source": "color.strokeNeutralTransparent" + "source": "color.strokeNeutralTransparent.rest" }, "colors.transparentStrokeInteractive": { - "source": "color.hover.strokeNeutralTransparent", - "fallback": "color.strokeNeutralTransparent" + "source": "color.strokeNeutralTransparent.hover", + "fallback": "color.strokeNeutralTransparent.rest" }, "colors.warningBackground1": { - "source": "color.backgroundWarningSubtle" + "source": "color.backgroundWarningSubtle.rest" }, "colors.warningBackground2": { - "source": "color.backgroundWarningSoft" + "source": "color.backgroundWarningSoft.rest" }, "colors.warningBackground3": { - "source": "color.backgroundWarningLoud" + "source": "color.backgroundWarningLoud.rest" }, "colors.warningBorder1": { - "source": "color.strokeWarningSoft" + "source": "color.strokeWarningSoft.rest" }, "colors.warningBorder2": { - "source": "color.strokeWarningLoud" + "source": "color.strokeWarningLoud.rest" }, "colors.warningForeground1": { - "source": "color.foregroundWarningPrimary" + "source": "color.foregroundWarningPrimary.rest" }, "colors.white": { - "source": "color.fixedWhite" + "source": "color.fixedWhite.rest" }, "components.Button.tokens.borderRadius": { "source": "borderRadius.base200" diff --git a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx index c4e5532fca..66e903011f 100644 --- a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx +++ b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx @@ -104,9 +104,9 @@ describe('Storybook app theme root', () => { const state = themes[themes.length - 1]; const calls = jest.mocked(StorybookUIComponent).mock.calls; const theme = calls[calls.length - 1][0].theme; - expect(theme.background.content).toBe(state.tokens.color.surfaceNeutralFar); + expect(theme.background.content).toBe(state.tokens.color.surfaceNeutralFar.rest); expect(theme.background.content).toBe(theme.background.preview); - expect(theme.background.content).not.toBe(state.tokens.color.backgroundNeutralSubtle); + expect(theme.background.content).not.toBe(state.tokens.color.backgroundNeutralSubtle.rest); }); it.each(['#ffeedd', 'transparent'])('preserves the explicit %s story background across theme changes', async (storyBackgroundColor) => { @@ -125,7 +125,7 @@ describe('Storybook app theme root', () => { const { App, roots, themes, mounted, unmounted, getStorybookUI } = createTestApp(); const scene = await render(); const root = roots[0]; - const defaultBackground = themes[0].tokens.color.surfaceNeutralFar; + const defaultBackground = themes[0].tokens.color.surfaceNeutralFar.rest; const backgrounds: Record = {}; await fireEvent(scene.getByTestId('test-app-root'), 'keyDownCapture', { nativeEvent: { key: 'Tab' } }); @@ -138,18 +138,18 @@ describe('Storybook app theme root', () => { expect(scene.getByTestId(`test-theme-${choice}`).props.accessibilityState.selected).toBe(true); expect(StyleSheet.flatten(scene.getByTestId('test-theme-toolbar').props.style).backgroundColor).toBe( - state.tokens.color.backgroundNeutralSubtle, + state.tokens.color.backgroundNeutralSubtle.rest, ); - expect(StyleSheet.flatten(scene.getByText('Theme').props.style).color).toBe(state.tokens.color.foregroundNeutralPrimary); - const foreground = theme.base === 'dark' ? state.tokens.color.fixedWhite : state.tokens.color.fixedBlack; - const background = theme.base === 'dark' ? state.tokens.color.fixedBlack : state.tokens.color.fixedWhite; + expect(StyleSheet.flatten(scene.getByText('Theme').props.style).color).toBe(state.tokens.color.foregroundNeutralPrimary.rest); + const foreground = theme.base === 'dark' ? state.tokens.color.fixedWhite.rest : state.tokens.color.fixedBlack.rest; + const background = theme.base === 'dark' ? state.tokens.color.fixedBlack.rest : state.tokens.color.fixedWhite.rest; const literal = (value: unknown, fallback: unknown) => (typeof value === 'string' ? value : fallback); - expect(theme.background.app).toBe(literal(state.tokens.color.surfaceNeutralFar, background)); - expect(theme.background.content).toBe(literal(state.tokens.color.surfaceNeutralFar, background)); - expect(theme.background.preview).toBe(literal(state.tokens.color.surfaceNeutralFar, background)); - expect(theme.color.defaultText).toBe(literal(state.tokens.color.foregroundNeutralPrimary, foreground)); - expect(theme.input.color).toBe(literal(state.tokens.color.foregroundNeutralPrimary, foreground)); - expect(theme.button.background).toBe(literal(state.tokens.color.backgroundNeutralLoud, background)); + expect(theme.background.app).toBe(literal(state.tokens.color.surfaceNeutralFar.rest, background)); + expect(theme.background.content).toBe(literal(state.tokens.color.surfaceNeutralFar.rest, background)); + expect(theme.background.preview).toBe(literal(state.tokens.color.surfaceNeutralFar.rest, background)); + expect(theme.color.defaultText).toBe(literal(state.tokens.color.foregroundNeutralPrimary.rest, foreground)); + expect(theme.input.color).toBe(literal(state.tokens.color.foregroundNeutralPrimary.rest, foreground)); + expect(theme.button.background).toBe(literal(state.tokens.color.backgroundNeutralLoud.rest, background)); expect(root.inputModality).toBe('keyboard'); expect(roots.every((settings) => settings === root)).toBe(true); } diff --git a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx index 5904b7f039..8f87f55e2b 100644 --- a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx +++ b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx @@ -80,12 +80,12 @@ const getStyles = themedStyleSheetFactory('StorybookTheme', ({ tokens }) => StyleSheet.create({ root: { flex: 1, - backgroundColor: tokens.color.surfaceNeutralFar, + backgroundColor: tokens.color.surfaceNeutralFar.rest, }, header: { alignItems: 'center', - backgroundColor: tokens.color.backgroundNeutralSubtle, - borderBottomColor: tokens.color.strokeNeutralSubtle, + backgroundColor: tokens.color.backgroundNeutralSubtle.rest, + borderBottomColor: tokens.color.strokeNeutralSubtle.rest, borderBottomWidth: 1, flexDirection: 'row', flexWrap: 'wrap', @@ -95,32 +95,32 @@ const getStyles = themedStyleSheetFactory('StorybookTheme', ({ tokens }) => paddingVertical: 6, }, label: { - color: tokens.color.foregroundNeutralPrimary, + color: tokens.color.foregroundNeutralPrimary.rest, fontSize: 14, fontWeight: '600', marginEnd: 4, }, option: { - backgroundColor: tokens.color.backgroundNeutralLoud, - borderColor: tokens.color.strokeNeutralSoft, + backgroundColor: tokens.color.backgroundNeutralLoud.rest, + borderColor: tokens.color.strokeNeutralSoft.rest, borderRadius: 4, borderWidth: 1, paddingHorizontal: 10, paddingVertical: 5, }, selectedOption: { - backgroundColor: tokens.color.backgroundBrandHeavy, - borderColor: tokens.color.strokeBrandLoud, + backgroundColor: tokens.color.backgroundBrandHeavy.rest, + borderColor: tokens.color.strokeBrandLoud.rest, }, pressedOption: { opacity: 0.75, }, optionText: { - color: tokens.color.foregroundNeutralPrimary, + color: tokens.color.foregroundNeutralPrimary.rest, fontSize: 12, }, selectedOptionText: { - color: tokens.color.foregroundBrandOnloud, + color: tokens.color.foregroundBrandOnloud.rest, fontWeight: '600', }, }), diff --git a/packages/agentic/storybook-desktop-runtime/src/useStorybookTheme.test.tsx b/packages/agentic/storybook-desktop-runtime/src/useStorybookTheme.test.tsx index 1118ab7d3a..c69b42709d 100644 --- a/packages/agentic/storybook-desktop-runtime/src/useStorybookTheme.test.tsx +++ b/packages/agentic/storybook-desktop-runtime/src/useStorybookTheme.test.tsx @@ -47,7 +47,7 @@ describe('Storybook theme palette', () => { expect(themes[themes.length - 1].background.content).toBe('#654321'); expect(themes[themes.length - 1].background.preview).toBe('#654321'); expect(themes[themes.length - 1]).not.toBe(themes[0]); - expect(themes[themes.length - 1].appBorderColor).toBe(states[states.length - 1].tokens.color.strokeNeutralSubtle); + expect(themes[themes.length - 1].appBorderColor).toBe(states[states.length - 1].tokens.color.strokeNeutralSubtle.rest); }); it('warns and substitutes a contrasting theme color for native opaque colors', async () => { @@ -60,7 +60,7 @@ describe('Storybook theme palette', () => { , ); - expect(themes[0].color.primary).toBe(states[0].tokens.color.fixedBlack); + expect(themes[0].color.primary).toBe(states[0].tokens.color.fixedBlack.rest); expect(warn).toHaveBeenCalledTimes(1); expect(warn).toHaveBeenCalledWith(expect.stringContaining('foregroundBrandPrimary')); }); @@ -84,8 +84,8 @@ describe('Storybook theme palette', () => { , ); - expect(themes[0].background.content).toBe(states[0].tokens.color[fallback]); - expect(themes[0].background.preview).toBe(states[0].tokens.color[fallback]); + expect(themes[0].background.content).toBe(states[0].tokens.color[fallback].rest); + expect(themes[0].background.preview).toBe(states[0].tokens.color[fallback].rest); expect(warn).toHaveBeenCalledTimes(1); expect(warn).toHaveBeenCalledWith(expect.stringContaining('surfaceNeutralFar')); }); diff --git a/packages/agentic/storybook-desktop-runtime/src/useStorybookTheme.ts b/packages/agentic/storybook-desktop-runtime/src/useStorybookTheme.ts index 840cc7d9e9..4cfe02a578 100644 --- a/packages/agentic/storybook-desktop-runtime/src/useStorybookTheme.ts +++ b/packages/agentic/storybook-desktop-runtime/src/useStorybookTheme.ts @@ -24,14 +24,14 @@ function storybookThemeFromThemeState({ appearance, highContrast, tokens }: Them const background = base.base === 'dark' ? 'fixedBlack' : 'fixedWhite'; const nativeColors = new Set(); const color = (name: keyof SemanticColorTokenValues, role: 'foreground' | 'background' = 'foreground'): string => { - const value = tokens.color[name]; + const value = tokens.color[name].rest; // Storybook also passes these colors to JS color utilities, not just native styles. if (typeof value === 'string') { return value; } nativeColors.add(name); const fallbackName = role === 'foreground' ? foreground : background; - const fallback = tokens.color[fallbackName]; + const fallback = tokens.color[fallbackName].rest; if (typeof fallback !== 'string') { throw new Error(`Storybook chrome requires a literal "${fallbackName}" fallback for the "${name}" theme token.`); } From 4e0cb739fdfda507dabe0a977a3d69945478f957 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 23 Oct 2026 20:32:46 -0700 Subject: [PATCH 06/18] design: current x3 defaults and non-color tokens (refactor phase 5) Refresh the x3 pin to 206e890b and generate rest-first cool and warm Flex defaults from the pinned sources. Interactive colors author a hover or pressed state only where the runtime interaction policy cannot reproduce the source; a coverage ledger records every destination, its state treatment, and native adaptations. FlexThemeReference selects the default by colorTone. Close the approved non-color gaps: layered, scheme-aware shadows with atomic merging and selectShadowEntry, motion durations and easings, and spacing.componentBase800. Legacy { ambient, key } Theme shadows project to and from layers; the legacy projection keeps its Fluent fallbacks. The forward Theme adapter keeps Fluent-native fallbacks in flex/adapters/fluentFallbackTokens and stays engine-free, guarded by a new import-boundary test. The default theme state now reaches the interaction policy, so the legacy-source bundle scenario requires it instead of forbidding it. Component tests read defaults from the testing entry point. Bundle deltas against phase 4 (macOS, raw/gzip): theme-state +17.3k/+2.7k, themed-root +17.3k/+2.7k, components-button +24.4k/+5.5k, catalog +24.5k/+5.5k, legacy-source +24.4k/+5.4k, legacy-theme-from-flex +7.6k/+0.9k; legacy-theme and color-lib are unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5030bce5-d7f7-4fb1-93de-68599b79269f --- apps/bundle-size/scenarios.json | 15 +- .../references/styles-and-tokens.md | 4 +- .../button/__snapshots__/button.test.tsx.snap | 180 +- .../src/components/button/button.test.tsx | 24 +- .../__snapshots__/list-item.test.tsx.snap | 4 +- .../components/menu-item/menu-item.test.tsx | 9 +- .../progress-bar/progress-bar.test.tsx | 6 +- .../__snapshots__/skeleton.test.tsx.snap | 4 +- .../src/components/tag/tag.test.tsx | 16 +- packages/agentic/design/package.json | 1 + .../agentic/design/references/color-lib.md | 2 +- .../agentic/design/references/contributing.md | 15 +- .../agentic/design/references/flex-colors.md | 10 +- .../design/references/remaining-work.md | 11 +- packages/agentic/design/references/testing.md | 7 +- packages/agentic/design/references/theming.md | 14 +- packages/agentic/design/references/tokens.md | 77 +- .../flex-defaults/coverage.generated.json | 531 ++++ .../flex-defaults/generate-defaults.mjs | 749 ++++++ .../x3/interaction-fallback-dark.css | 130 + .../x3/interaction-fallback-light.css | 130 + .../__fixtures__/x3/mappings.json | 8 +- .../__fixtures__/x3/semantic-dark.css | 283 ++ .../__fixtures__/x3/semantic-light.css | 283 ++ .../__fixtures__/x3/semantic.css | 3 +- .../__fixtures__/x3/tokens.json | 2320 +++++++++++++++++ .../x3/warm/interaction-fallback-dark.css | 130 + .../x3/warm/interaction-fallback-light.css | 130 + .../x3/warm/interaction-fallback.css | 130 + .../__fixtures__/x3/warm/semantic-dark.css | 283 ++ .../__fixtures__/x3/warm/semantic-light.css | 283 ++ .../__fixtures__/x3/warm/semantic.css | 351 +++ .../scripts/token-mappings/check-mappings.cjs | 49 +- .../scripts/token-mappings/upstream-drift.cjs | 101 +- .../design/src/color-lib/interaction.ts | 2 +- .../flex/adapters/flexTokensFromTheme.test.ts | 24 + .../src/flex/adapters/flexTokensFromTheme.ts | 34 +- .../adapters/fluentFallbackTokens.test.ts | 73 + .../src/flex/adapters/fluentFallbackTokens.ts | 354 +++ .../src/flex/colors/interactionPolicy.test.ts | 41 +- .../src/flex/colors/interactiveTokens.ts | 2 +- .../flex/defaults/defaultTokens.generated.ts | 463 ++++ .../design/src/flex/defaults/defaultTokens.ts | 363 +-- .../flex/defaults/generateDefaults.test.ts | 16 + .../src/flex/defaults/x3Defaults.test.ts | 273 ++ .../design/src/flex/flexShadow.test.ts | 109 + .../agentic/design/src/flex/flexShadow.ts | 84 + .../src/flex/flexThemeReference.test.ts | 25 +- .../design/src/flex/flexThemeReference.ts | 4 +- .../design/src/flex/flexTokenDescription.ts | 32 +- .../agentic/design/src/flex/tokens.test.ts | 98 +- .../agentic/design/src/flex/tokens.types.ts | 75 +- .../fluent/compat/themeFromFlexTokens.test.ts | 29 + .../src/fluent/compat/themeFromFlexTokens.ts | 26 +- packages/agentic/design/src/index.ts | 7 + .../src/test/color-validation/pairings.ts | 2 +- .../test/color-validation/validation.test.ts | 45 +- .../compatibilityBaseline.test.ts.snap | 62 +- .../__snapshots__/entryPoints.test.ts.snap | 2 + .../compatibility/importBoundaries.test.ts | 8 + .../src/test/fixtures/interactionColors.ts | 9 +- .../test/fixtures/x3InteractionConformance.ts | 78 +- packages/agentic/design/src/theming/index.ts | 1 + packages/agentic/design/src/theming/modern.ts | 1 + .../src/tokens/mappings/flex-token-map.yaml | 72 +- .../tokens/mappings/flexTokenMappings.test.ts | 50 +- .../src/tokens/mappings/theme-from-flex.json | 18 +- .../src/tokens/mappings/upstream-pin.json | 74 +- 68 files changed, 8065 insertions(+), 784 deletions(-) create mode 100644 packages/agentic/design/scripts/flex-defaults/coverage.generated.json create mode 100644 packages/agentic/design/scripts/flex-defaults/generate-defaults.mjs create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/interaction-fallback-dark.css create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/interaction-fallback-light.css create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic-dark.css create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic-light.css create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/tokens.json create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback-dark.css create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback-light.css create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback.css create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic-dark.css create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic-light.css create mode 100644 packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic.css create mode 100644 packages/agentic/design/src/flex/adapters/fluentFallbackTokens.test.ts create mode 100644 packages/agentic/design/src/flex/adapters/fluentFallbackTokens.ts create mode 100644 packages/agentic/design/src/flex/defaults/defaultTokens.generated.ts create mode 100644 packages/agentic/design/src/flex/defaults/generateDefaults.test.ts create mode 100644 packages/agentic/design/src/flex/defaults/x3Defaults.test.ts create mode 100644 packages/agentic/design/src/flex/flexShadow.test.ts create mode 100644 packages/agentic/design/src/flex/flexShadow.ts diff --git a/apps/bundle-size/scenarios.json b/apps/bundle-size/scenarios.json index 5a8cfed141..0f55e0eb37 100644 --- a/apps/bundle-size/scenarios.json +++ b/apps/bundle-size/scenarios.json @@ -49,14 +49,15 @@ "exports": ["ThemeReference"] } ], - "forbiddenInputPatterns": ["/design/src/fluent/compat/", "/design/src/fluent/tokens/", "/design/src/test/"], + "forbiddenInputPatterns": [ + "/design/src/fluent/compat/", + "/design/src/fluent/tokens/", + "/design/src/test/", + "/color-lib/compositing." + ], "requiredInputPatterns": ["/design/src/fluent/themeReference."], - "forbiddenOutputPatterns": [ - "/color-lib/", - "/design/src/flex/colors/interactionPolicy.", - "/design/src/flex/colors/interactiveTokens.", - "/design/src/flex/flexThemeReference." - ] + "forbiddenOutputPatterns": ["/design/src/flex/flexThemeReference."], + "requiredOutputPatterns": ["/color-lib/interaction.", "/design/src/flex/colors/interactionPolicy."] }, { "name": "design-legacy-theme", diff --git a/packages/agentic/components/references/styles-and-tokens.md b/packages/agentic/components/references/styles-and-tokens.md index cb0b60ddb9..8d34ff0748 100644 --- a/packages/agentic/components/references/styles-and-tokens.md +++ b/packages/agentic/components/references/styles-and-tokens.md @@ -23,7 +23,9 @@ value. styles and `.hover` or `.pressed` only for those states, because an omitted state is computed on first read. The design Flex color reference (`@fluentui-react-native/design/references/flex-colors.md`) owns the color contract. - Read grouped categories from `tokens.borderRadius`, `tokens.spacing`, `tokens.strokeWidth`, `tokens.fontFamily`, - `tokens.fontSize`, `tokens.fontWeight`, `tokens.lineHeight`, and `tokens.shadow`. + `tokens.fontSize`, `tokens.fontWeight`, `tokens.lineHeight`, `tokens.shadow`, and `tokens.motion`. Each shadow is an + array of layers; the design token reference (`@fluentui-react-native/design/references/tokens.md`) describes shadow + and motion values. - Prefer Flex tokens for every mapped semantic value. - Import named global tokens only when Flex has no equivalent, such as current Button icon dimensions or a true zero. - Record a genuine token gap in the component spec. Do not replace it with a nearby token or numeric literal. diff --git a/packages/agentic/components/src/components/button/__snapshots__/button.test.tsx.snap b/packages/agentic/components/src/components/button/__snapshots__/button.test.tsx.snap index 99fa028ba6..483162a1ea 100644 --- a/packages/agentic/components/src/components/button/__snapshots__/button.test.tsx.snap +++ b/packages/agentic/components/src/components/button/__snapshots__/button.test.tsx.snap @@ -6,7 +6,7 @@ exports[`Button matches the disabled visual state snapshot across appearances 1` "appearance": "primary", "contentStyles": [ { - "color": "#bdbdbd", + "color": "#0000006d", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -18,9 +18,9 @@ exports[`Button matches the disabled visual state snapshot across appearances 1` "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#f0f0f0", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#0000001a", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -36,7 +36,7 @@ exports[`Button matches the disabled visual state snapshot across appearances 1` "appearance": "secondary", "contentStyles": [ { - "color": "#bdbdbd", + "color": "#0000006d", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -48,9 +48,9 @@ exports[`Button matches the disabled visual state snapshot across appearances 1` "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#f0f0f0", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#00000008", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -66,7 +66,7 @@ exports[`Button matches the disabled visual state snapshot across appearances 1` "appearance": "outline", "contentStyles": [ { - "color": "#bdbdbd", + "color": "#0000006d", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -78,9 +78,9 @@ exports[`Button matches the disabled visual state snapshot across appearances 1` "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#00000000", - "borderColor": "#e0e0e0", - "borderRadius": 4, + "backgroundColor": "#24242400", + "borderColor": "#00000014", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -96,7 +96,7 @@ exports[`Button matches the disabled visual state snapshot across appearances 1` "appearance": "subtle", "contentStyles": [ { - "color": "#bdbdbd", + "color": "#0000006d", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -108,9 +108,9 @@ exports[`Button matches the disabled visual state snapshot across appearances 1` "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#00000000", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#24242400", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -143,9 +143,9 @@ exports[`Button matches the focused visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#185abd", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#242424", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -161,7 +161,7 @@ exports[`Button matches the focused visual state snapshot across appearances 1`] "appearance": "secondary", "contentStyles": [ { - "color": "#242424", + "color": "#000000db", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -173,9 +173,9 @@ exports[`Button matches the focused visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#fafafa", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#0000000d", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -191,7 +191,7 @@ exports[`Button matches the focused visual state snapshot across appearances 1`] "appearance": "outline", "contentStyles": [ { - "color": "#242424", + "color": "#000000db", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -203,9 +203,9 @@ exports[`Button matches the focused visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#00000000", - "borderColor": "#d1d1d1", - "borderRadius": 4, + "backgroundColor": "#24242400", + "borderColor": "#6f6f6f", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -221,7 +221,7 @@ exports[`Button matches the focused visual state snapshot across appearances 1`] "appearance": "subtle", "contentStyles": [ { - "color": "#242424", + "color": "#000000db", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -233,9 +233,9 @@ exports[`Button matches the focused visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#00000000", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#24242400", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -268,9 +268,9 @@ exports[`Button matches the hovered visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#1651aa", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#363636", + "borderColor": "#1313130a", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -286,7 +286,7 @@ exports[`Button matches the hovered visual state snapshot across appearances 1`] "appearance": "secondary", "contentStyles": [ { - "color": "#242424", + "color": "#000000e5", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -298,9 +298,9 @@ exports[`Button matches the hovered visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#f0f0f0", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#00000017", + "borderColor": "#1313130a", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -316,7 +316,7 @@ exports[`Button matches the hovered visual state snapshot across appearances 1`] "appearance": "outline", "contentStyles": [ { - "color": "#242424", + "color": "#000000e5", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -328,9 +328,9 @@ exports[`Button matches the hovered visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#00000000", - "borderColor": "#c7c7c7", - "borderRadius": 4, + "backgroundColor": "#1313130a", + "borderColor": "#787878", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -346,7 +346,7 @@ exports[`Button matches the hovered visual state snapshot across appearances 1`] "appearance": "subtle", "contentStyles": [ { - "color": "#242424", + "color": "#000000e5", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -358,9 +358,9 @@ exports[`Button matches the hovered visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#f0f0f0", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#00000017", + "borderColor": "#1313130a", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -393,9 +393,9 @@ exports[`Button matches the pressed visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#0e336a", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#494949", + "borderColor": "#05050514", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -411,7 +411,7 @@ exports[`Button matches the pressed visual state snapshot across appearances 1`] "appearance": "secondary", "contentStyles": [ { - "color": "#242424", + "color": "#000000ef", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -423,9 +423,9 @@ exports[`Button matches the pressed visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#dbdbdb", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#00000021", + "borderColor": "#05050514", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -441,7 +441,7 @@ exports[`Button matches the pressed visual state snapshot across appearances 1`] "appearance": "outline", "contentStyles": [ { - "color": "#242424", + "color": "#000000ef", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -453,9 +453,9 @@ exports[`Button matches the pressed visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#00000000", - "borderColor": "#b3b3b3", - "borderRadius": 4, + "backgroundColor": "#05050514", + "borderColor": "#818181", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -471,7 +471,7 @@ exports[`Button matches the pressed visual state snapshot across appearances 1`] "appearance": "subtle", "contentStyles": [ { - "color": "#242424", + "color": "#000000ef", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -483,9 +483,9 @@ exports[`Button matches the pressed visual state snapshot across appearances 1`] "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#dbdbdb", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#00000021", + "borderColor": "#05050514", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -518,9 +518,9 @@ exports[`Button matches the rest visual state snapshot across appearances 1`] = "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#185abd", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#242424", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -536,7 +536,7 @@ exports[`Button matches the rest visual state snapshot across appearances 1`] = "appearance": "secondary", "contentStyles": [ { - "color": "#242424", + "color": "#000000db", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -548,9 +548,9 @@ exports[`Button matches the rest visual state snapshot across appearances 1`] = "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#fafafa", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#0000000d", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -566,7 +566,7 @@ exports[`Button matches the rest visual state snapshot across appearances 1`] = "appearance": "outline", "contentStyles": [ { - "color": "#242424", + "color": "#000000db", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -578,9 +578,9 @@ exports[`Button matches the rest visual state snapshot across appearances 1`] = "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#00000000", - "borderColor": "#d1d1d1", - "borderRadius": 4, + "backgroundColor": "#24242400", + "borderColor": "#6f6f6f", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -596,7 +596,7 @@ exports[`Button matches the rest visual state snapshot across appearances 1`] = "appearance": "subtle", "contentStyles": [ { - "color": "#242424", + "color": "#000000db", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -608,9 +608,9 @@ exports[`Button matches the rest visual state snapshot across appearances 1`] = "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#00000000", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#24242400", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -653,9 +653,9 @@ exports[`Button matches the selected visual state snapshot across appearances 1` "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#185abd", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#242424", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -693,9 +693,9 @@ exports[`Button matches the selected visual state snapshot across appearances 1` "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#616161", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#242424", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -733,9 +733,9 @@ exports[`Button matches the selected visual state snapshot across appearances 1` "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#616161", - "borderColor": "#616161", - "borderRadius": 4, + "backgroundColor": "#242424", + "borderColor": "#242424", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", @@ -751,7 +751,7 @@ exports[`Button matches the selected visual state snapshot across appearances 1` "appearance": "subtle", "contentStyles": [ { - "color": "#242424", + "color": "#000000db", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -761,7 +761,7 @@ exports[`Button matches the selected visual state snapshot across appearances 1` "textAlign": "center", }, { - "color": "#242424", + "color": "#000000db", "flexShrink": 1, "fontFamily": "Helvetica Neue", "fontSize": 14, @@ -773,9 +773,9 @@ exports[`Button matches the selected visual state snapshot across appearances 1` "rootStyle": { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#0000001a", - "borderColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#00000014", + "borderColor": "#24242400", + "borderRadius": 12, "borderStyle": "solid", "borderWidth": 1, "flexDirection": "row", diff --git a/packages/agentic/components/src/components/button/button.test.tsx b/packages/agentic/components/src/components/button/button.test.tsx index ed9c98875f..c55776efd4 100644 --- a/packages/agentic/components/src/components/button/button.test.tsx +++ b/packages/agentic/components/src/components/button/button.test.tsx @@ -54,7 +54,7 @@ describe('Button', () => { expect(component.getByText('Save')).toBeOnTheScreen(); expect(getRootStyle(component)).toMatchObject({ alignItems: 'center', - backgroundColor: '#fafafa', + backgroundColor: defaultFlexTokens.color.backgroundNeutralSubtle.rest, minHeight: 24, minWidth: 24, }); @@ -72,7 +72,7 @@ describe('Button', () => { expect(getRootStyle(component).backgroundColor).not.toBe(restBackground); await fireEvent(root, 'pressIn', {}); - expect(getRootStyle(component).backgroundColor).toBe('#dbdbdb'); + expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralSubtle.pressed); await fireEvent.press(root); expect(onPress).toHaveBeenCalledTimes(1); @@ -127,7 +127,7 @@ describe('Button', () => { expect(root).toBeDisabled(); expect(root.props.focusable).toBe(false); expect(root.props.accessibilityState).toEqual({ disabled: true }); - expect(getRootStyle(component).backgroundColor).toBe('#f0f0f0'); + expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralSubtleDisabled.rest); await fireEvent.press(root); expect(onPress).not.toHaveBeenCalled(); }); @@ -323,13 +323,13 @@ describe('Button', () => { }); it.each([ - ['primary', '#185abd'], - ['secondary', '#fafafa'], - ['outline', '#00000000'], - ['subtle', '#00000000'], - ] as const)('resolves the %s appearance', async (appearance, backgroundColor) => { + ['primary', 'backgroundBrandHeavy'], + ['secondary', 'backgroundNeutralSubtle'], + ['outline', 'backgroundNeutralTransparent'], + ['subtle', 'backgroundNeutralTransparent'], + ] as const)('resolves the %s appearance', async (appearance, backgroundToken) => { const component = await renderButton({ appearance, content: appearance }); - expect(getRootStyle(component).backgroundColor).toBe(backgroundColor); + expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color[backgroundToken].rest); }); it.each([ @@ -446,9 +446,9 @@ describe('Button', () => { ); it.each([ - ['small', 12, 8, 4], - ['medium', 14, 10, 4], - ['large', 16, 12, 6], + ['small', 12, 8, defaultFlexTokens.borderRadius.base200], + ['medium', 14, 10, defaultFlexTokens.borderRadius.base300], + ['large', 16, 12, defaultFlexTokens.borderRadius.base400], ] as const)('resolves the %s size', async (size, fontSize, paddingHorizontal, borderRadius) => { const component = await renderButton({ content: size, size }); expect(StyleSheet.flatten(component.getByText(size).props.style)).toMatchObject({ diff --git a/packages/agentic/components/src/components/list-item/__snapshots__/list-item.test.tsx.snap b/packages/agentic/components/src/components/list-item/__snapshots__/list-item.test.tsx.snap index 43aa51c6e8..7a88ae632a 100644 --- a/packages/agentic/components/src/components/list-item/__snapshots__/list-item.test.tsx.snap +++ b/packages/agentic/components/src/components/list-item/__snapshots__/list-item.test.tsx.snap @@ -4,8 +4,8 @@ exports[`ListItem renders the default row with selection hidden and stable conte { "alignItems": "center", "alignSelf": "stretch", - "backgroundColor": "#00000000", - "borderRadius": 4, + "backgroundColor": "#24242400", + "borderRadius": 12, "flexDirection": "row", "justifyContent": "flex-start", "paddingHorizontal": 12, diff --git a/packages/agentic/components/src/components/menu-item/menu-item.test.tsx b/packages/agentic/components/src/components/menu-item/menu-item.test.tsx index ae1e638eb4..5050570678 100644 --- a/packages/agentic/components/src/components/menu-item/menu-item.test.tsx +++ b/packages/agentic/components/src/components/menu-item/menu-item.test.tsx @@ -5,6 +5,7 @@ import { fireEvent } from '@testing-library/react-native'; import { render } from '../../common/renderWithTheme'; import type { RenderResult } from '@testing-library/react-native'; +import { defaultFlexTokens } from '@fluentui-react-native/design/testing'; import { MenuItem } from './menu-item'; import type { MenuItemProps } from './menu-item.types'; import { MenuItemMenuContext } from './menuItemContext'; @@ -40,7 +41,7 @@ describe('MenuItem', () => { expect(component.getAllByText('Save', { includeHiddenElements: true })).toHaveLength(2); expect(component.getAllByText('Secondary', { includeHiddenElements: true })).toHaveLength(2); expect(getRootStyle(component)).toMatchObject({ - backgroundColor: '#00000000', + backgroundColor: defaultFlexTokens.color.backgroundNeutralTransparent.rest, minHeight: 40, }); }); @@ -55,7 +56,7 @@ describe('MenuItem', () => { expect(component.queryByTestId('regular-icon')).toBeNull(); expect(component.getByTestId('selected-icon')).toBeOnTheScreen(); - expect(getRootStyle(component).backgroundColor).toBe('#0000001a'); + expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralSoft.rest); expect( component .getAllByText('Favorite', { includeHiddenElements: true }) @@ -69,7 +70,7 @@ describe('MenuItem', () => { expect(getRoot(component, 'menuitemradio').props.accessibilityRole).toBe('menuitemradio'); expect(getRoot(component, 'menuitemradio').props.accessibilityState).toMatchObject({ checked: false }); - expect(getRootStyle(component, 'menuitemradio').backgroundColor).toBe('#00000000'); + expect(getRootStyle(component, 'menuitemradio').backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralTransparent.rest); }); it('renders a multiselect checkbox and keeps the row background transparent', async () => { @@ -81,7 +82,7 @@ describe('MenuItem', () => { expect(getRoot(component, 'menuitemcheckbox').props.accessibilityRole).toBe('menuitemcheckbox'); expect(getRoot(component, 'menuitemcheckbox').props.accessibilityState).toMatchObject({ checked: true }); - expect(getRootStyle(component, 'menuitemcheckbox').backgroundColor).toBe('#00000000'); + expect(getRootStyle(component, 'menuitemcheckbox').backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralTransparent.rest); }); it('supports section headers, loading skeletons, and no focusability', async () => { diff --git a/packages/agentic/components/src/components/progress-bar/progress-bar.test.tsx b/packages/agentic/components/src/components/progress-bar/progress-bar.test.tsx index 35fef0f146..3a57613868 100644 --- a/packages/agentic/components/src/components/progress-bar/progress-bar.test.tsx +++ b/packages/agentic/components/src/components/progress-bar/progress-bar.test.tsx @@ -6,6 +6,7 @@ import { render } from '../../common/renderWithTheme'; import { useReducedMotion } from '@fluentui-react-native/framework-base'; import { defaultFlexTokens } from '@fluentui-react-native/design/testing'; +import { defaultFlexTokens } from '@fluentui-react-native/design/testing'; import { ProgressBar } from './progress-bar'; jest.mock('@fluentui-react-native/framework-base', () => ({ @@ -188,7 +189,10 @@ describe('ProgressBar', () => { nativeEvent: { layout: { height: 4, width: 200, x: 0, y: 0 } }, }); - expect(getIndicatorStyle(component)).toMatchObject({ backgroundColor: '#185abd', width: 100 }); + expect(getIndicatorStyle(component)).toMatchObject({ + backgroundColor: defaultFlexTokens.color.foregroundBrandPrimary.rest, + width: 100, + }); expect(StyleSheet.flatten(getRoot(component).props.style)).toMatchObject({ backgroundColor: 'hotpink' }); expect(component.getByText('Halfway there')).toBeOnTheScreen(); }); diff --git a/packages/agentic/components/src/components/skeleton/__snapshots__/skeleton.test.tsx.snap b/packages/agentic/components/src/components/skeleton/__snapshots__/skeleton.test.tsx.snap index ea42617909..1c8e1bdf0b 100644 --- a/packages/agentic/components/src/components/skeleton/__snapshots__/skeleton.test.tsx.snap +++ b/packages/agentic/components/src/components/skeleton/__snapshots__/skeleton.test.tsx.snap @@ -2,8 +2,8 @@ exports[`Skeleton renders a decorative bar with themed fill and rounded corners 1`] = ` { - "backgroundColor": "#0000001a", - "borderRadius": 2, + "backgroundColor": "#00000014", + "borderRadius": 4, "height": 16, "overflow": "hidden", "position": "relative", diff --git a/packages/agentic/components/src/components/tag/tag.test.tsx b/packages/agentic/components/src/components/tag/tag.test.tsx index 28f69bce08..1fc32ae74d 100644 --- a/packages/agentic/components/src/components/tag/tag.test.tsx +++ b/packages/agentic/components/src/components/tag/tag.test.tsx @@ -104,7 +104,7 @@ describe('Tag', () => { expect(component.getByText('Engineering')).toBeOnTheScreen(); expect(getRootStyle(component)).toMatchObject({ alignItems: 'center', - backgroundColor: '#fafafa', + backgroundColor: defaultFlexTokens.color.backgroundNeutralSubtle.rest, minHeight: 24, minWidth: 24, }); @@ -136,7 +136,7 @@ describe('Tag', () => { expect(root).toBeDisabled(); expect(root.props.focusable).toBe(false); expect(root.props.accessibilityState).toEqual({ disabled: true }); - expect(getRootStyle(component).backgroundColor).toBe('#f0f0f0'); + expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralSubtleDisabled.rest); await fireEvent.press(root); expect(onPress).not.toHaveBeenCalled(); }); @@ -220,11 +220,11 @@ describe('Tag', () => { }); it.each([ - ['primary', '#185abd'], - ['secondary', '#fafafa'], - ] as const)('resolves the %s appearance', async (appearance, backgroundColor) => { + ['primary', 'backgroundBrandHeavy'], + ['secondary', 'backgroundNeutralSubtle'], + ] as const)('resolves the %s appearance', async (appearance, backgroundToken) => { const component = await renderTag({ appearance, content: appearance }); - expect(getRootStyle(component).backgroundColor).toBe(backgroundColor); + expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color[backgroundToken].rest); }); it.each([ @@ -247,8 +247,8 @@ describe('Tag', () => { }); it.each([ - ['rounded', 4], - ['circular', 9999], + ['rounded', defaultFlexTokens.borderRadius.base300], + ['circular', defaultFlexTokens.borderRadius.circular], ] as const)('resolves the %s shape', async (shape, borderRadius) => { const component = await renderTag({ content: shape, shape }); expect(getRootStyle(component).borderRadius).toBe(borderRadius); diff --git a/packages/agentic/design/package.json b/packages/agentic/design/package.json index 6e3459c7f6..f4d938a68c 100644 --- a/packages/agentic/design/package.json +++ b/packages/agentic/design/package.json @@ -104,6 +104,7 @@ "scripts": { "build": "tsc -b", "check:mappings": "node ./scripts/token-mappings/check-mappings.cjs", + "gen:flex-defaults": "node ./scripts/flex-defaults/generate-defaults.mjs", "clean": "fluentui-scripts clean", "format": "fluentui-scripts format", "gen:upstream-drift": "node ./scripts/token-mappings/upstream-drift.cjs", diff --git a/packages/agentic/design/references/color-lib.md b/packages/agentic/design/references/color-lib.md index aec5215bcb..766f2d72d7 100644 --- a/packages/agentic/design/references/color-lib.md +++ b/packages/agentic/design/references/color-lib.md @@ -24,7 +24,7 @@ colors. Direct compositing and contrast operations throw descriptive errors for unsupported values. The algorithms are ported from -[`x3-design/fluent-design@d334acf5cbad813f2b7cd554da942b09a7ff8f10`](https://github.com/x3-design/fluent-design/tree/d334acf5cbad813f2b7cd554da942b09a7ff8f10/dev/web/flex-themes). +[`x3-design/fluent-design@206e890b645fb450ad7c5df2ff981765349a2b58`](https://github.com/x3-design/fluent-design/tree/206e890b645fb450ad7c5df2ff981765349a2b58/dev/web/flex-themes). The interaction API knows nothing about Flex tokens. Its options select: | Option | Values | Effect | diff --git a/packages/agentic/design/references/contributing.md b/packages/agentic/design/references/contributing.md index 971d0a423f..5227fe2895 100644 --- a/packages/agentic/design/references/contributing.md +++ b/packages/agentic/design/references/contributing.md @@ -13,7 +13,9 @@ owner_paths: | ---------------------- | ----------------------------------------------------------------------------------------------------------- | | `src/types/` | Type-only contracts shared by the Flex and Fluent models, such as appearance and theme state | | `src/theming/` | Shared theme sources, providers, boundaries, appearance, runtime caches, and the `theming` facades | -| `src/flex/` | Flex token types, defaults, the Theme-to-Flex adapter, `FlexThemeReference`, `useThemeState`, and styles | +| `src/flex/` | Flex token types, `FlexThemeReference`, `useThemeState`, layered shadows, and styles | +| `src/flex/defaults/` | The generated x3 cool and warm defaults and their parity tests; see `tokens.md` | +| `src/flex/adapters/` | The engine-free Theme-to-Flex adapter and its Fluent-native fallbacks | | `src/flex/colors/` | Authored color normalization, the resolved color envelope, token classification, and the interaction policy | | `src/fluent/` | Legacy Fluent theme types, `ThemeReference`, `useTheme`, platform utilities, and legacy styling | | `src/fluent/compat/` | The Flex-to-legacy projection and complete legacy defaults; never reachable from the root | @@ -31,17 +33,18 @@ Shared modules may import types from either model. At runtime, only the `theming Production code never imports `src/test/`. Source paths are private: consumers use the package subpaths in `entry-points.md`, never `src/` or `lib/` paths. -The package's scripts directory holds `codegen.cts`, which runs before every build, and the token-mapping check and -upstream drift tools described in `tokens.md`. Generated token and projection files are committed; change their inputs -and rebuild rather than editing them. +The package's scripts directory holds `codegen.cts`, which runs before every build, the token-mapping check and +upstream drift tools, and the x3 defaults generator, all described in `tokens.md`. Generated token, projection, and +default files are committed; change their inputs and regenerate rather than editing them. ## Invariants - Keep the root import graph modern: it must not reach `useTheme` or anything under `src/fluent/`. It reaches `color-lib/interaction` (with its parsing and conversion dependencies) only through `src/flex/colors/`, never `color-lib/compositing`. The legacy `ThemeReference`, `useTheme`, and `ThemeProvider` graphs must not reach - `src/flex/` or `src/color-lib/`. `src/test/compatibility/importBoundaries.test.ts` checks the entry graphs; run the - bundle-size scenarios too when changing imports between these areas. + `src/flex/` or `src/color-lib/`, and the Theme-to-Flex adapter in `src/flex/adapters/` must not reach the interaction + policy, the x3 defaults, or `src/color-lib/`. `src/test/compatibility/importBoundaries.test.ts` checks these graphs; + run the bundle-size scenarios too when changing imports between these areas. - Never mutate author-owned theme inputs; caches are external and keyed by source, revision, and resolved appearance. - Keep color resolution lazy: resolving tokens, reading rest, merging, and copying the color map must not run the interaction algorithm, and a derived state computes at most once per resolved color. `flex-colors.md` owns the color diff --git a/packages/agentic/design/references/flex-colors.md b/packages/agentic/design/references/flex-colors.md index d73ad97c2c..d9e74ec9e1 100644 --- a/packages/agentic/design/references/flex-colors.md +++ b/packages/agentic/design/references/flex-colors.md @@ -73,14 +73,16 @@ For each color and resolved appearance: setting, or registration is required. When JavaScript cannot map rest, such as a `PlatformColor`, the state is the identical rest value; unexpected algorithm failures still throw. -The default description and the Theme-to-Flex adapter never derive states: their omitted states equal rest, so -existing default and legacy-projected values are unchanged. +The default descriptions are rest-first: they author a hover or pressed state only where the policy cannot reproduce the +x3 source (see `tokens.md`), so their other states are derived like any authored color. The Theme-to-Flex adapter never +derives states: its omitted states equal rest, so legacy-projected values are unchanged. ## Merging and recipes `FlexThemeReference` merges the package defaults, its `base`, and its recipes in order. A color override replaces the -previous color atomically, including its explicit states and type, so a stale state never survives a new rest. An -`undefined` color is not an override. Other token groups keep deep-merge semantics. +previous color atomically, including its explicit states and type, so a stale state never survives a new rest. Shadow +overrides also replace the whole layered shadow. An `undefined` color or shadow is not an override. Other token groups +keep deep-merge semantics. Because replacement is atomic, a plain override uses the `standard` type even where the default color is inverted. Use `flexColor(value, 'inverted')` when overriding a heavy, loud, or on-loud role that should keep inverted interaction diff --git a/packages/agentic/design/references/remaining-work.md b/packages/agentic/design/references/remaining-work.md index 641ea2503c..e624a23c64 100644 --- a/packages/agentic/design/references/remaining-work.md +++ b/packages/agentic/design/references/remaining-work.md @@ -37,10 +37,13 @@ behavior is documented in `theming.md`, `tokens.md`, and `entry-points.md`. - **Issue:** [#4263](https://github.com/microsoft/fluentui-react-native/issues/4263) - **Outcome:** default Flex tokens vary by resolved color scheme, contrast, and interface level. -- **Current state:** `FlexThemeReference` resolves every appearance from the same `defaultFlexTokens`. Authors must - supply appearance-aware bases or recipes for dark or high-contrast values. -- **Done when:** generated defaults exist for each supported appearance and `FlexThemeReference` selects them by the - resolved appearance without changing its laziness or identity guarantees. +- **Current state:** the generated x3 defaults vary by color scheme and color tone. The pinned x3 sources define no + high-contrast or elevated values, so those appearances use the light or dark defaults, and high contrast only + suppresses derived interaction states. Authors must supply appearance-aware bases or recipes for high-contrast or + elevated values. +- **Done when:** x3 publishes, or the owner approves, high-contrast and elevated values, the defaults generator emits + them, and `FlexThemeReference` selects them by the resolved appearance without changing its laziness or identity + guarantees. - **Review draft:** repository-only `packages/agentic/design/refactoring.md` coordinates package reorganization, tone-aware interactive colors, verified x3 defaults, and the legacy compatibility gates. It is an explicitly requested review artifact, not a second open-work index; remove the draft and this pointer when its durable contract diff --git a/packages/agentic/design/references/testing.md b/packages/agentic/design/references/testing.md index aeadd869c5..9f06ce82c3 100644 --- a/packages/agentic/design/references/testing.md +++ b/packages/agentic/design/references/testing.md @@ -12,7 +12,7 @@ owner_paths: `@fluentui-react-native/design/testing` is the test-only entry point for fixtures and validation helpers associated with the design package. It exports: -- the generated `defaultFlexTokens` fixture and default resolved appearance; +- the x3 cool `defaultFlexTokens` and the default resolved appearance; - `mockTheme` for tests that need a legacy-compatible theme; - WCAG thresholds and canonical semantic color pairings; - structured contrast audits and filters for failed or unresolvable pairs. @@ -38,6 +38,11 @@ The package's internal validation suite audits rest, hover, and pressed values for both the cool and warm color tones. Its pinned conformance fixtures and the bulk `getInteractionColorOverrides` helper under `src/test/fixtures` are implementation evidence rather than public testing exports. +`x3InteractionConformance` and `x3WarmInteractionConformance` record each +tone's x3 rest, hover, and pressed values, and `x3CoolExplicitStates` records +the cool states the interaction policy does not reproduce, with the reason each +default authors them. The x3 default parity tests under `src/flex/defaults` are +described in `tokens.md`. `validateContrastPairs` accepts a flat map of color values or resolved `InteractiveColor` envelopes, which it audits at rest. To audit an interaction diff --git a/packages/agentic/design/references/theming.md b/packages/agentic/design/references/theming.md index ca2455f236..f8fa97081c 100644 --- a/packages/agentic/design/references/theming.md +++ b/packages/agentic/design/references/theming.md @@ -23,10 +23,11 @@ both models. Modern consumers read Flex tokens through `useThemeState`; legacy c | `ThemeReference` | `legacy` | One legacy `Theme` per resolved appearance | `@fluentui-react-native/design/theming` or `@fluentui-react-native/design/theming/legacy-source` | `FlexThemeReference` accepts `base`, `appearance`, `fallbackAppearance`, `appearanceSource`, and `legacyFallback` -options followed by recipes. It merges the design package's default Flex token description, then the base input, then -recipes in declaration order, and resolves the result once per appearance. A base may be a function of the resolved -appearance, which always has a concrete `colorTone`. A recipe receives the accumulated authored description and the -resolved appearance. `PartialFlexTokens` is shape-aware so opaque React Native colors stay leaves. +options followed by recipes. It merges the design package's x3 default Flex token description for the resolved +`colorTone`, then the base input, then recipes in declaration order, and resolves the result once per appearance. A base +may be a function of the resolved appearance, which always has a concrete `colorTone`. A recipe receives the accumulated +authored description and the resolved appearance. `PartialFlexTokens` is shape-aware so opaque React Native colors stay +leaves. `tokens.md` describes the defaults. Each color is authored as a value, a `[light, dark]` tuple, or `flexColor` options with explicit states and an interaction type, and replaces the previous color atomically. Each resolved color is an `InteractiveColor` with `rest`, @@ -125,8 +126,9 @@ The package root exports only the modern authoring and consumption APIs. It reac which `useThemeState` needs for legacy sources, and the Flex interaction policy with the raw `color-lib` interaction algorithm, but not `useTheme`, the reverse converter, the complete legacy defaults, or legacy token payloads. The legacy `ThemeReference`, `useTheme`, and `ThemeProvider` graphs reach neither Flex nor `color-lib`. An app that pairs a legacy -`ThemeReference` with `useThemeState` reaches the forward adapter and the engine-free color envelope, but not -`FlexThemeReference`, the interaction policy, or `color-lib`. `entry-points.md` lists every subpath. +`ThemeReference` with `useThemeState` reaches the forward adapter and, through the default theme state, the x3 defaults +and the interaction policy with `color-lib/interaction`, but not `FlexThemeReference`, `color-lib/compositing`, or the +compatibility projection. `entry-points.md` lists every subpath. `themeFromFlexTokens` in `theming/compat` builds a complete `Theme` in this order: diff --git a/packages/agentic/design/references/tokens.md b/packages/agentic/design/references/tokens.md index 4790864ef5..6562666f3e 100644 --- a/packages/agentic/design/references/tokens.md +++ b/packages/agentic/design/references/tokens.md @@ -19,22 +19,57 @@ owner_paths: component, use the Win32, macOS, or Windows implementation as the compatibility reference; use iOS only when the work explicitly targets iOS. -| Tokens | Entry point | Source | -| ------------------------------ | ------------------------------------------------- | ---------------------------------------------------------------------------- | -| Flex semantic tokens | `FlexTokens` from `@fluentui-react-native/design` | `src/flex/tokens.types.ts`; defaults in `src/flex/defaults/defaultTokens.ts` | -| Platform global tokens | `@fluentui-react-native/design/tokens/global` | Generated into `src/tokens/global.generated.ts` and `src/tokens/generated/` | -| Legacy alias and shadow tokens | `@fluentui-react-native/design/tokens/legacy` | `src/fluent/tokens/`, for legacy themes only | +| Tokens | Entry point | Source | +| ------------------------------ | ------------------------------------------------- | --------------------------------------------------------------------------- | +| Flex semantic tokens | `FlexTokens` from `@fluentui-react-native/design` | `src/flex/tokens.types.ts`; x3 defaults in `src/flex/defaults/` | +| Platform global tokens | `@fluentui-react-native/design/tokens/global` | Generated into `src/tokens/global.generated.ts` and `src/tokens/generated/` | +| Legacy alias and shadow tokens | `@fluentui-react-native/design/tokens/legacy` | `src/fluent/tokens/`, for legacy themes only | `FlexTokens` groups `color` (one `InteractiveColor` with `rest`, `hover`, and `pressed` per semantic color; see -`flex-colors.md`), `shadow`, `fontWeight`, `fontFamily`, `fontSize`, -`lineHeight`, `borderRadius`, `spacing`, and `strokeWidth`. Components read the active values from -`useThemeState().tokens`; `theming.md` explains how they are resolved. The defaults currently do not vary by -appearance; see `remaining-work.md`. +`flex-colors.md`), `shadow`, `fontWeight`, `fontFamily`, `fontSize`, `lineHeight`, `borderRadius`, `spacing`, +`strokeWidth`, and `motion`. Components read the active values from `useThemeState().tokens`; `theming.md` explains how +they are resolved. + +Each shadow is a `FlexShadow`: an array of `{ x, y, blur, color }` layers in CSS `box-shadow` order, from the contour +layer to the key shadow, with offsets and blur in density-independent pixels. The tokens keep every source layer. An +authored shadow is one layered shadow or a `[light, dark]` tuple of them; `selectShadowEntry` selects the shadow for an +appearance. A shadow override replaces the whole entry, and an `undefined` entry keeps the base. A legacy +`{ ambient, key }` shadow is authored as `[ambient, key]`, and the former `ambient` and `key` are the first and last +layers. Motion durations are milliseconds, and each easing is an `[x1, y1, x2, y2]` tuple for `Easing.bezier`. Only +colors and shadows vary by color scheme. The package's `prebuild` script (`codegen.cts`) generates the global token files from the platform `@fluentui-react-native/design-tokens-*` packages and regenerates both mapping projections. Do not edit generated files; change their inputs and rebuild. +## Default tokens + +`src/flex/defaults/defaultTokens.generated.ts` holds the cool and warm x3 defaults, and `defaultTokens.ts` normalizes +them. `FlexThemeReference` merges the default for the resolved `colorTone` under its base and recipes. The x3 sources +define no high-contrast or elevated values, so those appearances use the light or dark default. Defaults do not +otherwise vary by contrast or interface level; see `remaining-work.md`. Tests that assert default values should read +them from `defaultFlexTokens` in the `testing` entry point rather than repeating literals. + +The defaults are rest-first. The generator omits a hover or pressed state when the runtime interaction policy +reproduces its source value in both schemes, and authors the state otherwise, so changing the policy can change which +states are explicit. The coverage ledger, `coverage.generated.json` beside the generator in the package's +`flex-defaults` scripts directory, records for every Flex destination the x3 variable, each tone's light and dark +values, whether each interaction state is computed or explicit, and any native adaptation. Adaptations convert `rem` to +16 density-independent pixels, durations to milliseconds, `cubic-bezier()` to tuples, variable font weights to native +static weights, and relative `oklch` shadow alphas to `#rrggbbaa`. Opaque colors are emitted as `#rrggbb`. + +Regenerate both files from the pinned snapshots, or verify that they are current: + +```sh +yarn workspace @fluentui-react-native/design gen:flex-defaults +yarn workspace @fluentui-react-native/design gen:flex-defaults --check +``` + +The generator imports the interaction policy's TypeScript source and requires Node 22.18 or later. `--check` exits 1 +when an output is stale. `src/flex/defaults/generateDefaults.test.ts` runs the check, and `x3Defaults.test.ts` +independently parses the pinned CSS to verify every resolved default for each tone and scheme, that each explicit state +differs from the policy's result, and that every x3 variable has a Flex destination. + ## Flex token mapping `flex-token-map.yaml` is the authoring source for the grouped Flex token contract @@ -50,10 +85,16 @@ deprecated `FlatFlexTokens` input they fall back to rest when the state map has no entry for that token. `reverse.transforms` owns any value conversion required by a target path. -`nonFluentFlexTokens` supplies values for supported Flex destinations without a -Theme source. A complete legacy Theme also requires values that Flex cannot -represent; those values are supplied by the lazy compatibility base under -`src/fluent/compat`. +`src/flex/adapters/fluentFallbackTokens.ts` holds the forward adapter's +Fluent-native fallbacks, not the x3 defaults. `nonFluentFlexTokens` supplies +values for supported Flex destinations without a Theme source, and +`fluentFallbackFlexTokens` supplies mapped values a Theme omits. The adapter +never derives states: a state that neither the Theme nor a fallback supplies +equals rest. X3 default changes therefore never alter projected legacy themes. +Legacy +`{ ambient, key }` Theme shadows become `[ambient, key]` layers. A complete +legacy Theme also requires values that Flex cannot represent; those values are +supplied by the lazy compatibility base under `src/fluent/compat`. ### Internal consistency @@ -100,10 +141,12 @@ without changing the pin, pass `--ref `. yarn workspace @fluentui-react-native/design update:upstream-snapshots ``` - The command refreshes the three snapshots and their `blobSha` values. + The command refreshes every snapshot listed in `files` and its `blobSha`. 3. Run `gen:upstream-drift --offline` and confirm that `hasDrift` is `false` and every `snapshotIntegrity` entry reports `matches: true`. -4. Run `check:mappings` and the design package test suite. -5. Commit the pin record, all three refreshed snapshots, and a changeset - describing the upstream change together. +4. Run `gen:flex-defaults`, then `check:mappings` and the design package test + suite. Review value changes in the coverage ledger, and update source-commit + citations in code comments and references. +5. Commit the pin record, the refreshed snapshots, the regenerated defaults and + ledger, and a changeset describing the upstream change together. diff --git a/packages/agentic/design/scripts/flex-defaults/coverage.generated.json b/packages/agentic/design/scripts/flex-defaults/coverage.generated.json new file mode 100644 index 0000000000..baa3bc8a48 --- /dev/null +++ b/packages/agentic/design/scripts/flex-defaults/coverage.generated.json @@ -0,0 +1,531 @@ +{ + "generator": "scripts/flex-defaults/generate-defaults.mjs", + "source": { + "repository": "x3-design/fluent-design", + "commit": "206e890b645fb450ad7c5df2ff981765349a2b58", + "files": { + "cool": [ + "dev/web/flex-themes/css/semantic.css", + "dev/web/flex-themes/css/interaction-fallback.css" + ], + "warm": [ + "dev/web/flex-themes/css/warm/semantic.css", + "dev/web/flex-themes/css/warm/interaction-fallback.css" + ] + } + }, + "mapping": "src/tokens/mappings/flex-token-map.yaml", + "notes": [ + "Each tone records the light and dark source values after resolving light-dark() and [data-theme] overrides.", + "computed: the runtime interaction policy reproduces the source state from rest, so the default omits it. explicit: the default authors the source state.", + "Computed states equal rest in high contrast; explicit states apply in every contrast.", + "The x3 semantic sources define no native high-contrast or elevated values; those appearances reuse the light or dark defaults.", + "native: the emitted value; adaptation: how the source value converts to it.", + "Theme shadows project to legacy { ambient, key } pairs from the first and last layers; that projection is lossy." + ], + "destinations": [ + {"path":"color.surfaceNeutralFarther.rest","source":"--gnrc-color-surface-neutral-farther","type":"standard","cool":{"light":"#ebebeb","dark":"#1b1b1b"},"warm":{"light":"#f0eae5","dark":"#1e1916"}}, + {"path":"color.surfaceNeutralFarther.hover","source":"--gnrc-color-surface-neutral-farther-hover","cool":{"light":"#e1e1e1","dark":"#2f2f2f","state":"computed"},"warm":{"light":"#e8e0d9","dark":"#342d29","state":"computed"}}, + {"path":"color.surfaceNeutralFarther.pressed","source":"--gnrc-color-surface-neutral-farther-pressed","cool":{"light":"#d7d7d7","dark":"#454545","state":"computed"},"warm":{"light":"#dfd6ce","dark":"#4b423d","state":"computed"}}, + {"path":"color.surfaceNeutralFar.rest","source":"--gnrc-color-surface-neutral-far","type":"standard","cool":{"light":"#f2f2f2","dark":"#1f1f1f"},"warm":{"light":"#faf4f0","dark":"#231e1a"}}, + {"path":"color.surfaceNeutralFar.hover","source":"--gnrc-color-surface-neutral-far-hover","cool":{"light":"#e8e8e8","dark":"#323232","state":"computed"},"warm":{"light":"#f2eae4","dark":"#38312b","state":"computed"}}, + {"path":"color.surfaceNeutralFar.pressed","source":"--gnrc-color-surface-neutral-far-pressed","cool":{"light":"#dedede","dark":"#464646","state":"computed"},"warm":{"light":"#e9dfd9","dark":"#4d453e","state":"computed"}}, + {"path":"color.surfaceNeutralNear.rest","source":"--gnrc-color-surface-neutral-near","type":"standard","cool":{"light":"#fcfcfc","dark":"#181818"},"warm":{"light":"#f6f1ec","dark":"#1c1714"}}, + {"path":"color.surfaceNeutralNear.hover","source":"--gnrc-color-surface-neutral-near-hover","cool":{"light":"#f2f2f2","dark":"#2d2d2d","state":"computed"},"warm":{"light":"#ede7e0","dark":"#322b27","state":"computed"}}, + {"path":"color.surfaceNeutralNear.pressed","source":"--gnrc-color-surface-neutral-near-pressed","cool":{"light":"#e8e8e8","dark":"#434343","state":"computed"},"warm":{"light":"#e5ddd4","dark":"#4b413c","state":"computed"}}, + {"path":"color.surfaceNeutralNearer.rest","source":"--gnrc-color-surface-neutral-nearer","type":"standard","cool":{"light":"#ffffff","dark":"#292929"},"warm":{"light":"#ffffff","dark":"#2e2823"}}, + {"path":"color.surfaceNeutralNearer.hover","source":"--gnrc-color-surface-neutral-nearer-hover","cool":{"light":"#f5f5f5","dark":"#3a3a3a","state":"computed"},"warm":{"light":"#f6f5f3","dark":"#403832","state":"computed"}}, + {"path":"color.surfaceNeutralNearer.pressed","source":"--gnrc-color-surface-neutral-nearer-pressed","cool":{"light":"#ebebeb","dark":"#4b4b4b","state":"computed"},"warm":{"light":"#edebe7","dark":"#534941","state":"computed"}}, + {"path":"color.surfaceNeutralTranslucent.rest","source":"--gnrc-color-surface-neutral-translucent","type":"standard","cool":{"light":"#ffffff80","dark":"#3c3c3c80"},"warm":{"light":"#ffffff80","dark":"#00000080"}}, + {"path":"color.surfaceNeutralTranslucent.hover","source":"--gnrc-color-surface-neutral-translucent-hover","cool":{"light":"#f5f5f58a","dark":"#47474788","state":"computed"},"warm":{"light":"#f7f6f48a","dark":"#02010188","state":"computed"}}, + {"path":"color.surfaceNeutralTranslucent.pressed","source":"--gnrc-color-surface-neutral-translucent-pressed","cool":{"light":"#ebebeb94","dark":"#5353538f","state":"computed"},"warm":{"light":"#f0eeea94","dark":"#0e0b0c8f","state":"computed"}}, + {"path":"color.backgroundNeutralHeavy.rest","source":"--gnrc-color-background-neutral-heavy","type":"inverted","cool":{"light":"#242424","dark":"#ffffff"},"warm":{"light":"#28231e","dark":"#ffffff"}}, + {"path":"color.backgroundNeutralHeavy.hover","source":"--gnrc-color-background-neutral-heavy-hover","cool":{"light":"#363636","dark":"#f5f5f5","state":"computed"},"warm":{"light":"#3b352e","dark":"#f6f5f3","state":"computed"}}, + {"path":"color.backgroundNeutralHeavy.pressed","source":"--gnrc-color-background-neutral-heavy-pressed","cool":{"light":"#494949","dark":"#ebebeb","state":"computed"},"warm":{"light":"#50473f","dark":"#edebe7","state":"computed"}}, + {"path":"color.backgroundNeutralLoud.rest","source":"--gnrc-color-background-neutral-loud","type":"inverted","cool":{"light":"#6f6f6f","dark":"#929292"},"warm":{"light":"#1e0d009a","dark":"#ffeee39a"}}, + {"path":"color.backgroundNeutralLoud.hover","source":"--gnrc-color-background-neutral-loud-hover","cool":{"light":"#787878","dark":"#898989","state":"computed"},"warm":{"light":"#2e1a0a9a","dark":"#f3dfd29a","state":"computed"}}, + {"path":"color.backgroundNeutralLoud.pressed","source":"--gnrc-color-background-neutral-loud-pressed","cool":{"light":"#818181","dark":"#808080","state":"computed"},"warm":{"light":"#3f28169a","dark":"#e6d0c09a","state":"computed"}}, + {"path":"color.backgroundNeutralSoft.rest","source":"--gnrc-color-background-neutral-soft","type":"standard","cool":{"light":"#00000014","dark":"#ffffff1f"},"warm":{"light":"#4d200028","dark":"#ffe3cb40"}}, + {"path":"color.backgroundNeutralSoft.hover","source":"--gnrc-color-background-neutral-soft-hover","cool":{"light":"#0000001e","dark":"#ffffff27","state":"computed"},"warm":{"light":"#61330f32","dark":"#fde1c548","state":"computed"}}, + {"path":"color.backgroundNeutralSoft.pressed","source":"--gnrc-color-background-neutral-soft-pressed","cool":{"light":"#00000028","dark":"#ffffff2e","state":"computed"},"warm":{"light":"#6a3b193c","dark":"#ffdec44f","state":"computed"}}, + {"path":"color.backgroundNeutralSubtle.rest","source":"--gnrc-color-background-neutral-subtle","type":"standard","cool":{"light":"#0000000d","dark":"#ffffff14"},"warm":{"light":"#6c31001a","dark":"#fff4ef14"}}, + {"path":"color.backgroundNeutralSubtle.hover","source":"--gnrc-color-background-neutral-subtle-hover","cool":{"light":"#00000017","dark":"#ffffff1c","state":"computed"},"warm":{"light":"#7f471c24","dark":"#ffe8e81c","state":"computed"}}, + {"path":"color.backgroundNeutralSubtle.pressed","source":"--gnrc-color-background-neutral-subtle-pressed","cool":{"light":"#00000021","dark":"#ffffff23","state":"computed"},"warm":{"light":"#8b53272e","dark":"#ffdfdf23","state":"computed"}}, + {"path":"color.backgroundNeutralTransparent.rest","source":"--gnrc-color-background-neutral-transparent","type":"standard","cool":{"light":"#24242400","dark":"#ffffff00"},"warm":{"light":"#28231e00","dark":"#ffffff00"}}, + {"path":"color.backgroundNeutralTransparent.hover","source":"--gnrc-color-background-neutral-transparent-hover","cool":{"light":"#1313130a","dark":"#ffffff08","state":"computed"},"warm":{"light":"#231d170a","dark":"#fbfaf808","state":"computed"}}, + {"path":"color.backgroundNeutralTransparent.pressed","source":"--gnrc-color-background-neutral-transparent-pressed","cool":{"light":"#05050514","dark":"#ffffff0f","state":"computed"},"warm":{"light":"#1e170f14","dark":"#fefcf80f","state":"computed"}}, + {"path":"color.backgroundNeutralTranslucent.rest","source":"--gnrc-color-background-neutral-translucent","type":"standard","cool":{"light":"#e9e9e980","dark":"#3c3c3c80"},"warm":{"light":"#e9e9e980","dark":"#3c3c3c80"}}, + {"path":"color.backgroundNeutralTranslucent.hover","source":"--gnrc-color-background-neutral-translucent-hover","cool":{"light":"#d8d8d88a","dark":"#56565688","state":"explicit"},"warm":{"light":"#dcdcd68a","dark":"#52524e88","state":"computed"}}, + {"path":"color.backgroundNeutralTranslucent.pressed","source":"--gnrc-color-background-neutral-translucent-pressed","cool":{"light":"#cacaca94","dark":"#6d6d6d8f","state":"explicit"},"warm":{"light":"#d2cfc894","dark":"#67665e8f","state":"computed"}}, + {"path":"color.backgroundBrandHeavy.rest","source":"--gnrc-color-background-brand-heavy","type":"inverted","cool":{"light":"#242424","dark":"#ffffff"},"warm":{"light":"#28231e","dark":"#ffffff"}}, + {"path":"color.backgroundBrandHeavy.hover","source":"--gnrc-color-background-brand-heavy-hover","cool":{"light":"#363636","dark":"#f5f5f5","state":"computed"},"warm":{"light":"#3b352e","dark":"#f6f5f3","state":"computed"}}, + {"path":"color.backgroundBrandHeavy.pressed","source":"--gnrc-color-background-brand-heavy-pressed","cool":{"light":"#494949","dark":"#ebebeb","state":"computed"},"warm":{"light":"#50473f","dark":"#edebe7","state":"computed"}}, + {"path":"color.backgroundBrandLoud.rest","source":"--gnrc-color-background-brand-loud","type":"inverted","cool":{"light":"#6f6f6f","dark":"#929292"},"warm":{"light":"#1e0d009a","dark":"#ffeee39a"}}, + {"path":"color.backgroundBrandLoud.hover","source":"--gnrc-color-background-brand-loud-hover","cool":{"light":"#787878","dark":"#898989","state":"computed"},"warm":{"light":"#2e1a0a9a","dark":"#f3dfd29a","state":"computed"}}, + {"path":"color.backgroundBrandLoud.pressed","source":"--gnrc-color-background-brand-loud-pressed","cool":{"light":"#818181","dark":"#808080","state":"computed"},"warm":{"light":"#3f28169a","dark":"#e6d0c09a","state":"computed"}}, + {"path":"color.backgroundBrandSoft.rest","source":"--gnrc-color-background-brand-soft","type":"standard","cool":{"light":"#00000014","dark":"#ffffff1f"},"warm":{"light":"#4d200028","dark":"#ffe3cb40"}}, + {"path":"color.backgroundBrandSoft.hover","source":"--gnrc-color-background-brand-soft-hover","cool":{"light":"#0000001e","dark":"#ffffff27","state":"computed"},"warm":{"light":"#61330f32","dark":"#fde1c548","state":"computed"}}, + {"path":"color.backgroundBrandSoft.pressed","source":"--gnrc-color-background-brand-soft-pressed","cool":{"light":"#00000028","dark":"#ffffff2e","state":"computed"},"warm":{"light":"#6a3b193c","dark":"#ffdec44f","state":"computed"}}, + {"path":"color.backgroundBrandSubtle.rest","source":"--gnrc-color-background-brand-subtle","type":"standard","cool":{"light":"#0000000a","dark":"#ffffff14"},"warm":{"light":"#6c31001a","dark":"#fff4ef14"}}, + {"path":"color.backgroundBrandSubtle.hover","source":"--gnrc-color-background-brand-subtle-hover","cool":{"light":"#00000014","dark":"#ffffff1c","state":"computed"},"warm":{"light":"#7f471c24","dark":"#ffe8e81c","state":"computed"}}, + {"path":"color.backgroundBrandSubtle.pressed","source":"--gnrc-color-background-brand-subtle-pressed","cool":{"light":"#0000001e","dark":"#ffffff23","state":"computed"},"warm":{"light":"#8b53272e","dark":"#ffdfdf23","state":"computed"}}, + {"path":"color.backgroundBrandTransparent.rest","source":"--gnrc-color-background-brand-transparent","type":"standard","cool":{"light":"#24242400","dark":"#ffffff00"},"warm":{"light":"#28231e00","dark":"#ffffff00"}}, + {"path":"color.backgroundBrandTransparent.hover","source":"--gnrc-color-background-brand-transparent-hover","cool":{"light":"#1313130a","dark":"#ffffff08","state":"computed"},"warm":{"light":"#231d170a","dark":"#fbfaf808","state":"computed"}}, + {"path":"color.backgroundBrandTransparent.pressed","source":"--gnrc-color-background-brand-transparent-pressed","cool":{"light":"#05050514","dark":"#ffffff0f","state":"computed"},"warm":{"light":"#1e170f14","dark":"#fefcf80f","state":"computed"}}, + {"path":"color.backgroundDangerLoud.rest","source":"--gnrc-color-background-danger-loud","type":"inverted","cool":{"light":"#c02e56","dark":"#e55e7a"},"warm":{"light":"#c02e56","dark":"#e55e7a"}}, + {"path":"color.backgroundDangerLoud.hover","source":"--gnrc-color-background-danger-loud-hover","cool":{"light":"#cb395e","dark":"#da5471","state":"computed"},"warm":{"light":"#cd355e","dark":"#dd5170","state":"computed"}}, + {"path":"color.backgroundDangerLoud.pressed","source":"--gnrc-color-background-danger-loud-pressed","cool":{"light":"#d54467","dark":"#d04b69","state":"computed"},"warm":{"light":"#da3c65","dark":"#d54467","state":"computed"}}, + {"path":"color.backgroundDangerSoft.rest","source":"--gnrc-color-background-danger-soft","type":"standard","cool":{"light":"#ffe3e6","dark":"#5a2932"},"warm":{"light":"#ffe3e6","dark":"#5a2932"}}, + {"path":"color.backgroundDangerSoft.hover","source":"--gnrc-color-background-danger-soft-hover","cool":{"light":"#f5d9dc","dark":"#67353e","state":"computed"},"warm":{"light":"#f7d8dc","dark":"#68343d","state":"computed"}}, + {"path":"color.backgroundDangerSoft.pressed","source":"--gnrc-color-background-danger-soft-pressed","cool":{"light":"#ebcfd2","dark":"#754149","state":"computed"},"warm":{"light":"#efced1","dark":"#773f49","state":"computed"}}, + {"path":"color.backgroundDangerSubtle.rest","source":"--gnrc-color-background-danger-subtle","type":"standard","cool":{"light":"#fff1f3","dark":"#402529"},"warm":{"light":"#fff1f3","dark":"#402529"}}, + {"path":"color.backgroundDangerSubtle.hover","source":"--gnrc-color-background-danger-subtle-hover","cool":{"light":"#f5e7e9","dark":"#503438","state":"computed"},"warm":{"light":"#f7e6e9","dark":"#523338","state":"computed"}}, + {"path":"color.backgroundDangerSubtle.pressed","source":"--gnrc-color-background-danger-subtle-pressed","cool":{"light":"#ebdddf","dark":"#614448","state":"computed"},"warm":{"light":"#efdcde","dark":"#644247","state":"computed"}}, + {"path":"color.backgroundWarningLoud.rest","source":"--gnrc-color-background-warning-loud","type":"inverted","cool":{"light":"#bb4001","dark":"#e56738"},"warm":{"light":"#bb4001","dark":"#e56738"}}, + {"path":"color.backgroundWarningLoud.hover","source":"--gnrc-color-background-warning-loud-hover","cool":{"light":"#c54a14","dark":"#da5d2e","state":"computed"},"warm":{"light":"#c84709","dark":"#dd5b28","state":"computed"}}, + {"path":"color.backgroundWarningLoud.pressed","source":"--gnrc-color-background-warning-loud-pressed","cool":{"light":"#d05321","dark":"#d05422","state":"computed"},"warm":{"light":"#d54e11","dark":"#d54f13","state":"computed"}}, + {"path":"color.backgroundWarningSoft.rest","source":"--gnrc-color-background-warning-soft","type":"standard","cool":{"light":"#ffe5dc","dark":"#592c1c"},"warm":{"light":"#ffe5dc","dark":"#592c1c"}}, + {"path":"color.backgroundWarningSoft.hover","source":"--gnrc-color-background-warning-soft-hover","cool":{"light":"#f5dbd2","dark":"#663828","state":"computed"},"warm":{"light":"#f7dbd1","dark":"#673726","state":"computed"}}, + {"path":"color.backgroundWarningSoft.pressed","source":"--gnrc-color-background-warning-soft-pressed","cool":{"light":"#ebd1c9","dark":"#744434","state":"computed"},"warm":{"light":"#eed0c6","dark":"#764331","state":"computed"}}, + {"path":"color.backgroundWarningSubtle.rest","source":"--gnrc-color-background-warning-subtle","type":"standard","cool":{"light":"#fff2ee","dark":"#40261d"},"warm":{"light":"#fff2ee","dark":"#40261d"}}, + {"path":"color.backgroundWarningSubtle.hover","source":"--gnrc-color-background-warning-subtle-hover","cool":{"light":"#f5e8e4","dark":"#51352c","state":"computed"},"warm":{"light":"#f7e7e3","dark":"#52352b","state":"computed"}}, + {"path":"color.backgroundWarningSubtle.pressed","source":"--gnrc-color-background-warning-subtle-pressed","cool":{"light":"#ebdeda","dark":"#62453b","state":"computed"},"warm":{"light":"#efddd7","dark":"#644439","state":"computed"}}, + {"path":"color.backgroundSuccessLoud.rest","source":"--gnrc-color-background-success-loud","type":"inverted","cool":{"light":"#008455","dark":"#05ad72"},"warm":{"light":"#008455","dark":"#05ad72"}}, + {"path":"color.backgroundSuccessLoud.hover","source":"--gnrc-color-background-success-loud-hover","cool":{"light":"#188d5d","dark":"#00a369","state":"computed"},"warm":{"light":"#088e5c","dark":"#00a468","state":"computed"}}, + {"path":"color.backgroundSuccessLoud.pressed","source":"--gnrc-color-background-success-loud-pressed","cool":{"light":"#279666","dark":"#009a60","state":"computed"},"warm":{"light":"#119864","dark":"#009c5e","state":"computed"}}, + {"path":"color.backgroundSuccessSoft.rest","source":"--gnrc-color-background-success-soft","type":"standard","cool":{"light":"#c9f8dd","dark":"#0c462d"},"warm":{"light":"#c9f8dd","dark":"#0c462d"}}, + {"path":"color.backgroundSuccessSoft.hover","source":"--gnrc-color-background-success-soft-hover","cool":{"light":"#bfeed3","dark":"#1c5238","state":"computed"},"warm":{"light":"#bdefd3","dark":"#185338","state":"computed"}}, + {"path":"color.backgroundSuccessSoft.pressed","source":"--gnrc-color-background-success-soft-pressed","cool":{"light":"#b6e4ca","dark":"#295f44","state":"computed"},"warm":{"light":"#b2e5c8","dark":"#246043","state":"computed"}}, + {"path":"color.backgroundSuccessSubtle.rest","source":"--gnrc-color-background-success-subtle","type":"standard","cool":{"light":"#e3fcee","dark":"#193426"},"warm":{"light":"#e3fcee","dark":"#193426"}}, + {"path":"color.backgroundSuccessSubtle.hover","source":"--gnrc-color-background-success-subtle-hover","cool":{"light":"#d9f2e4","dark":"#294435","state":"computed"},"warm":{"light":"#d7f3e3","dark":"#274435","state":"computed"}}, + {"path":"color.backgroundSuccessSubtle.pressed","source":"--gnrc-color-background-success-subtle-pressed","cool":{"light":"#cfe8da","dark":"#385445","state":"computed"},"warm":{"light":"#cce9d9","dark":"#355544","state":"computed"}}, + {"path":"color.strokeNeutralHeavy.rest","source":"--gnrc-color-stroke-neutral-heavy","type":"inverted","cool":{"light":"#242424","dark":"#dedede"},"warm":{"light":"#28231e","dark":"#e3dcd7"}}, + {"path":"color.strokeNeutralHeavy.hover","source":"--gnrc-color-stroke-neutral-heavy-hover","cool":{"light":"#363636","dark":"#d4d4d4","state":"computed"},"warm":{"light":"#3b352e","dark":"#dbd2cb","state":"computed"}}, + {"path":"color.strokeNeutralHeavy.pressed","source":"--gnrc-color-stroke-neutral-heavy-pressed","cool":{"light":"#494949","dark":"#cbcbcb","state":"computed"},"warm":{"light":"#50473f","dark":"#d3c8c0","state":"computed"}}, + {"path":"color.strokeNeutralLoud.rest","source":"--gnrc-color-stroke-neutral-loud","type":"inverted","cool":{"light":"#6f6f6f","dark":"#929292"},"warm":{"light":"#776d65","dark":"#9a9089"}}, + {"path":"color.strokeNeutralLoud.hover","source":"--gnrc-color-stroke-neutral-loud-hover","cool":{"light":"#787878","dark":"#898989","state":"computed"},"warm":{"light":"#81756c","dark":"#92877e","state":"computed"}}, + {"path":"color.strokeNeutralLoud.pressed","source":"--gnrc-color-stroke-neutral-loud-pressed","cool":{"light":"#818181","dark":"#808080","state":"computed"},"warm":{"light":"#8c7e73","dark":"#8b7d74","state":"computed"}}, + {"path":"color.strokeNeutralSoft.rest","source":"--gnrc-color-stroke-neutral-soft","type":"standard","cool":{"light":"#0000006d","dark":"#ffffff61"},"warm":{"light":"#250f0076","dark":"#ffe6d35c"}}, + {"path":"color.strokeNeutralSoft.hover","source":"--gnrc-color-stroke-neutral-soft-hover","cool":{"light":"#02020277","dark":"#ffffff69","state":"explicit"},"warm":{"light":"#2a120280","dark":"#ffe6cf64","state":"computed"}}, + {"path":"color.strokeNeutralSoft.pressed","source":"--gnrc-color-stroke-neutral-soft-pressed","cool":{"light":"#04040481","dark":"#ffffff70","state":"explicit"},"warm":{"light":"#2e16048a","dark":"#ffe8d06b","state":"computed"}}, + {"path":"color.strokeNeutralSubtle.rest","source":"--gnrc-color-stroke-neutral-subtle","type":"standard","cool":{"light":"#00000021","dark":"#ffffff48"},"warm":{"light":"#4d200028","dark":"#ffe3cb40"}}, + {"path":"color.strokeNeutralSubtle.hover","source":"--gnrc-color-stroke-neutral-subtle-hover","cool":{"light":"#0000002b","dark":"#ffffff50","state":"computed"},"warm":{"light":"#61330f32","dark":"#fde1c548","state":"computed"}}, + {"path":"color.strokeNeutralSubtle.pressed","source":"--gnrc-color-stroke-neutral-subtle-pressed","cool":{"light":"#05050535","dark":"#ffffff57","state":"explicit"},"warm":{"light":"#6a3b193c","dark":"#ffdec44f","state":"computed"}}, + {"path":"color.strokeNeutralTransparent.rest","source":"--gnrc-color-stroke-neutral-transparent","type":"standard","cool":{"light":"#24242400","dark":"#ffffff00"},"warm":{"light":"#28231e00","dark":"#ffffff00"}}, + {"path":"color.strokeNeutralTransparent.hover","source":"--gnrc-color-stroke-neutral-transparent-hover","cool":{"light":"#1313130a","dark":"#ffffff08","state":"computed"},"warm":{"light":"#231d170a","dark":"#fbfaf808","state":"computed"}}, + {"path":"color.strokeNeutralTransparent.pressed","source":"--gnrc-color-stroke-neutral-transparent-pressed","cool":{"light":"#05050514","dark":"#ffffff0f","state":"computed"},"warm":{"light":"#1e170f14","dark":"#fefcf80f","state":"computed"}}, + {"path":"color.strokeNeutralOnloud.rest","source":"--gnrc-color-stroke-neutral-onloud","type":"inverted","cool":{"light":"#ffffff","dark":"#000000db"},"warm":{"light":"#ffffff","dark":"#0b0600e1"}}, + {"path":"color.strokeNeutralOnloud.hover","source":"--gnrc-color-stroke-neutral-onloud-hover","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffd","dark":"#000000e1","state":"computed"}}, + {"path":"color.strokeNeutralOnloud.pressed","source":"--gnrc-color-stroke-neutral-onloud-pressed","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffb","dark":"#000000e1","state":"computed"}}, + {"path":"color.strokeBrandLoud.rest","source":"--gnrc-color-stroke-brand-loud","type":"inverted","cool":{"light":"#6f6f6f","dark":"#929292"},"warm":{"light":"#776d65","dark":"#9a9089"}}, + {"path":"color.strokeBrandLoud.hover","source":"--gnrc-color-stroke-brand-loud-hover","cool":{"light":"#787878","dark":"#898989","state":"computed"},"warm":{"light":"#81756c","dark":"#92877e","state":"computed"}}, + {"path":"color.strokeBrandLoud.pressed","source":"--gnrc-color-stroke-brand-loud-pressed","cool":{"light":"#818181","dark":"#808080","state":"computed"},"warm":{"light":"#8c7e73","dark":"#8b7d74","state":"computed"}}, + {"path":"color.strokeBrandSoft.rest","source":"--gnrc-color-stroke-brand-soft","type":"standard","cool":{"light":"#0000006d","dark":"#ffffff61"},"warm":{"light":"#250f0076","dark":"#ffe6d35c"}}, + {"path":"color.strokeBrandSoft.hover","source":"--gnrc-color-stroke-brand-soft-hover","cool":{"light":"#02020277","dark":"#ffffff69","state":"explicit"},"warm":{"light":"#2a120280","dark":"#ffe6cf64","state":"computed"}}, + {"path":"color.strokeBrandSoft.pressed","source":"--gnrc-color-stroke-brand-soft-pressed","cool":{"light":"#04040481","dark":"#ffffff70","state":"explicit"},"warm":{"light":"#2e16048a","dark":"#ffe8d06b","state":"computed"}}, + {"path":"color.strokeBrandSubtle.rest","source":"--gnrc-color-stroke-brand-subtle","type":"standard","cool":{"light":"#00000021","dark":"#ffffff48"},"warm":{"light":"#4d200028","dark":"#ffe3cb40"}}, + {"path":"color.strokeBrandSubtle.hover","source":"--gnrc-color-stroke-brand-subtle-hover","cool":{"light":"#0000002b","dark":"#ffffff50","state":"computed"},"warm":{"light":"#61330f32","dark":"#fde1c548","state":"computed"}}, + {"path":"color.strokeBrandSubtle.pressed","source":"--gnrc-color-stroke-brand-subtle-pressed","cool":{"light":"#05050535","dark":"#ffffff57","state":"explicit"},"warm":{"light":"#6a3b193c","dark":"#ffdec44f","state":"computed"}}, + {"path":"color.strokeBrandOnloud.rest","source":"--gnrc-color-stroke-brand-onloud","type":"inverted","cool":{"light":"#ffffff","dark":"#242424"},"warm":{"light":"#ffffff","dark":"#0b0600e1"}}, + {"path":"color.strokeBrandOnloud.hover","source":"--gnrc-color-stroke-brand-onloud-hover","cool":{"light":"#ffffff","dark":"#131313","state":"computed"},"warm":{"light":"#fffffd","dark":"#000000e1","state":"computed"}}, + {"path":"color.strokeBrandOnloud.pressed","source":"--gnrc-color-stroke-brand-onloud-pressed","cool":{"light":"#ffffff","dark":"#050505","state":"computed"},"warm":{"light":"#fffffb","dark":"#000000e1","state":"computed"}}, + {"path":"color.strokeDangerLoud.rest","source":"--gnrc-color-stroke-danger-loud","type":"inverted","cool":{"light":"#c02e56","dark":"#e55e7a"},"warm":{"light":"#c02e56","dark":"#e55e7a"}}, + {"path":"color.strokeDangerLoud.hover","source":"--gnrc-color-stroke-danger-loud-hover","cool":{"light":"#cb395e","dark":"#da5471","state":"computed"},"warm":{"light":"#cd355e","dark":"#dd5170","state":"computed"}}, + {"path":"color.strokeDangerLoud.pressed","source":"--gnrc-color-stroke-danger-loud-pressed","cool":{"light":"#d54467","dark":"#d04b69","state":"computed"},"warm":{"light":"#da3c65","dark":"#d54467","state":"computed"}}, + {"path":"color.strokeDangerSoft.rest","source":"--gnrc-color-stroke-danger-soft","type":"standard","cool":{"light":"#e55e7a","dark":"#d14164"},"warm":{"light":"#e55e7a","dark":"#d14164"}}, + {"path":"color.strokeDangerSoft.hover","source":"--gnrc-color-stroke-danger-soft-hover","cool":{"light":"#da5471","dark":"#dc4b6d","state":"computed"},"warm":{"light":"#dd5170","dark":"#de486c","state":"computed"}}, + {"path":"color.strokeDangerSoft.pressed","source":"--gnrc-color-stroke-danger-soft-pressed","cool":{"light":"#d04b69","dark":"#e65575","state":"computed"},"warm":{"light":"#d54467","dark":"#eb4f74","state":"computed"}}, + {"path":"color.strokeDangerSubtle.rest","source":"--gnrc-color-stroke-danger-subtle","type":"standard","cool":{"light":"#ffd0d6","dark":"#76293a"},"warm":{"light":"#ffd0d6","dark":"#76293a"}}, + {"path":"color.strokeDangerSubtle.hover","source":"--gnrc-color-stroke-danger-subtle-hover","cool":{"light":"#f5c6cc","dark":"#803242","state":"computed"},"warm":{"light":"#f7c5cc","dark":"#813041","state":"computed"}}, + {"path":"color.strokeDangerSubtle.pressed","source":"--gnrc-color-stroke-danger-subtle-pressed","cool":{"light":"#ebbdc3","dark":"#893a4a","state":"computed"},"warm":{"light":"#eebbc2","dark":"#8c3749","state":"computed"}}, + {"path":"color.strokeDangerOnloud.rest","source":"--gnrc-color-stroke-danger-onloud","type":"inverted","cool":{"light":"#ffffff","dark":"#242424"},"warm":{"light":"#ffffff","dark":"#242424"}}, + {"path":"color.strokeDangerOnloud.hover","source":"--gnrc-color-stroke-danger-onloud-hover","cool":{"light":"#ffffff","dark":"#131313","state":"computed"},"warm":{"light":"#fffffd","dark":"#141312","state":"computed"}}, + {"path":"color.strokeDangerOnloud.pressed","source":"--gnrc-color-stroke-danger-onloud-pressed","cool":{"light":"#ffffff","dark":"#050505","state":"computed"},"warm":{"light":"#fffffb","dark":"#060504","state":"computed"}}, + {"path":"color.strokeWarningLoud.rest","source":"--gnrc-color-stroke-warning-loud","type":"inverted","cool":{"light":"#cd4808","dark":"#e56738"},"warm":{"light":"#cd4808","dark":"#e56738"}}, + {"path":"color.strokeWarningLoud.hover","source":"--gnrc-color-stroke-warning-loud-hover","cool":{"light":"#d8521a","dark":"#da5d2e","state":"computed"},"warm":{"light":"#da4f11","dark":"#dd5b28","state":"computed"}}, + {"path":"color.strokeWarningLoud.pressed","source":"--gnrc-color-stroke-warning-loud-pressed","cool":{"light":"#e25c27","dark":"#d05422","state":"computed"},"warm":{"light":"#e75618","dark":"#d54f13","state":"computed"}}, + {"path":"color.strokeWarningSoft.rest","source":"--gnrc-color-stroke-warning-soft","type":"standard","cool":{"light":"#fc9571","dark":"#cd4808"},"warm":{"light":"#fc9571","dark":"#cd4808"}}, + {"path":"color.strokeWarningSoft.hover","source":"--gnrc-color-stroke-warning-soft-hover","cool":{"light":"#f28c68","dark":"#d8521a","state":"computed"},"warm":{"light":"#f48a65","dark":"#da4f11","state":"computed"}}, + {"path":"color.strokeWarningSoft.pressed","source":"--gnrc-color-stroke-warning-soft-pressed","cool":{"light":"#e7825f","dark":"#e25c27","state":"computed"},"warm":{"light":"#ec7f58","dark":"#e75618","state":"computed"}}, + {"path":"color.strokeWarningSubtle.rest","source":"--gnrc-color-stroke-warning-subtle","type":"standard","cool":{"light":"#ffd3c4","dark":"#762e12"},"warm":{"light":"#ffd3c4","dark":"#762e12"}}, + {"path":"color.strokeWarningSubtle.hover","source":"--gnrc-color-stroke-warning-subtle-hover","cool":{"light":"#f5c9ba","dark":"#7f371b","state":"computed"},"warm":{"light":"#f7c9b9","dark":"#813518","state":"computed"}}, + {"path":"color.strokeWarningSubtle.pressed","source":"--gnrc-color-stroke-warning-subtle-pressed","cool":{"light":"#ebc0b1","dark":"#893f24","state":"computed"},"warm":{"light":"#eebeae","dark":"#8c3c1e","state":"computed"}}, + {"path":"color.strokeWarningOnloud.rest","source":"--gnrc-color-stroke-warning-onloud","type":"inverted","cool":{"light":"#ffffff","dark":"#242424"},"warm":{"light":"#ffffff","dark":"#242424"}}, + {"path":"color.strokeWarningOnloud.hover","source":"--gnrc-color-stroke-warning-onloud-hover","cool":{"light":"#ffffff","dark":"#131313","state":"computed"},"warm":{"light":"#fffffd","dark":"#141312","state":"computed"}}, + {"path":"color.strokeWarningOnloud.pressed","source":"--gnrc-color-stroke-warning-onloud-pressed","cool":{"light":"#ffffff","dark":"#050505","state":"computed"},"warm":{"light":"#fffffb","dark":"#060504","state":"computed"}}, + {"path":"color.strokeSuccessLoud.rest","source":"--gnrc-color-stroke-success-loud","type":"inverted","cool":{"light":"#008455","dark":"#05ad72"},"warm":{"light":"#008455","dark":"#05ad72"}}, + {"path":"color.strokeSuccessLoud.hover","source":"--gnrc-color-stroke-success-loud-hover","cool":{"light":"#188d5d","dark":"#00a369","state":"computed"},"warm":{"light":"#088e5c","dark":"#00a468","state":"computed"}}, + {"path":"color.strokeSuccessLoud.pressed","source":"--gnrc-color-stroke-success-loud-pressed","cool":{"light":"#279666","dark":"#009a60","state":"computed"},"warm":{"light":"#119864","dark":"#009c5e","state":"computed"}}, + {"path":"color.strokeSuccessSoft.rest","source":"--gnrc-color-stroke-success-soft","type":"standard","cool":{"light":"#5dce97","dark":"#008e5c"},"warm":{"light":"#5dce97","dark":"#008e5c"}}, + {"path":"color.strokeSuccessSoft.hover","source":"--gnrc-color-stroke-success-soft-hover","cool":{"light":"#52c48e","dark":"#1a9765","state":"computed"},"warm":{"light":"#4cc58d","dark":"#089863","state":"computed"}}, + {"path":"color.strokeSuccessSoft.pressed","source":"--gnrc-color-stroke-success-soft-pressed","cool":{"light":"#47bb85","dark":"#2aa16d","state":"computed"},"warm":{"light":"#39bc82","dark":"#11a26b","state":"computed"}}, + {"path":"color.strokeSuccessSubtle.rest","source":"--gnrc-color-stroke-success-subtle","type":"standard","cool":{"light":"#b1efcc","dark":"#025636"},"warm":{"light":"#b1efcc","dark":"#025636"}}, + {"path":"color.strokeSuccessSubtle.hover","source":"--gnrc-color-stroke-success-subtle-hover","cool":{"light":"#a7e5c2","dark":"#125f3e","state":"computed"},"warm":{"light":"#a5e6c2","dark":"#0a5f3d","state":"computed"}}, + {"path":"color.strokeSuccessSubtle.pressed","source":"--gnrc-color-stroke-success-subtle-pressed","cool":{"light":"#9edbb9","dark":"#1e6746","state":"computed"},"warm":{"light":"#9adcb7","dark":"#136844","state":"computed"}}, + {"path":"color.strokeSuccessOnloud.rest","source":"--gnrc-color-stroke-success-onloud","type":"inverted","cool":{"light":"#ffffff","dark":"#242424"},"warm":{"light":"#ffffff","dark":"#242424"}}, + {"path":"color.strokeSuccessOnloud.hover","source":"--gnrc-color-stroke-success-onloud-hover","cool":{"light":"#ffffff","dark":"#131313","state":"computed"},"warm":{"light":"#fffffd","dark":"#141312","state":"computed"}}, + {"path":"color.strokeSuccessOnloud.pressed","source":"--gnrc-color-stroke-success-onloud-pressed","cool":{"light":"#ffffff","dark":"#050505","state":"computed"},"warm":{"light":"#fffffb","dark":"#060504","state":"computed"}}, + {"path":"color.foregroundNeutralPrimary.rest","source":"--gnrc-color-foreground-neutral-primary","type":"standard","cool":{"light":"#000000db","dark":"#ffffffde"},"warm":{"light":"#0b0600e1","dark":"#fff7f2e3"}}, + {"path":"color.foregroundNeutralPrimary.hover","source":"--gnrc-color-foreground-neutral-primary-hover","cool":{"light":"#000000e5","dark":"#ffffffe6","state":"computed"},"warm":{"light":"#060300eb","dark":"#fff8f2eb","state":"computed"}}, + {"path":"color.foregroundNeutralPrimary.pressed","source":"--gnrc-color-foreground-neutral-primary-pressed","cool":{"light":"#000000ef","dark":"#ffffffed","state":"computed"},"warm":{"light":"#040100f5","dark":"#fffaf2f2","state":"computed"}}, + {"path":"color.foregroundNeutralSecondary.rest","source":"--gnrc-color-foreground-neutral-secondary","type":"standard","cool":{"light":"#000000a2","dark":"#ffffffa1"},"warm":{"light":"#190c00ab","dark":"#fff2e8b5"}}, + {"path":"color.foregroundNeutralSecondary.hover","source":"--gnrc-color-foreground-neutral-secondary-hover","cool":{"light":"#000000ac","dark":"#ffffffa9","state":"computed"},"warm":{"light":"#0a0100b5","dark":"#fff7ebbd","state":"computed"}}, + {"path":"color.foregroundNeutralSecondary.pressed","source":"--gnrc-color-foreground-neutral-secondary-pressed","cool":{"light":"#000000b6","dark":"#ffffffb0","state":"computed"},"warm":{"light":"#060000bf","dark":"#fff9ecc4","state":"computed"}}, + {"path":"color.foregroundNeutralTertiary.rest","source":"--gnrc-color-foreground-neutral-tertiary","type":"standard","cool":{"light":"#00000090","dark":"#ffffff80"},"warm":{"light":"#1e0d009a","dark":"#ffeee39a"}}, + {"path":"color.foregroundNeutralTertiary.hover","source":"--gnrc-color-foreground-neutral-tertiary-hover","cool":{"light":"#0000009a","dark":"#ffffff88","state":"computed"},"warm":{"light":"#0c0100a4","dark":"#fff6eaa2","state":"computed"}}, + {"path":"color.foregroundNeutralTertiary.pressed","source":"--gnrc-color-foreground-neutral-tertiary-pressed","cool":{"light":"#000000a4","dark":"#ffffff8f","state":"computed"},"warm":{"light":"#080000ae","dark":"#fff8eaa9","state":"computed"}}, + {"path":"color.foregroundNeutralOnloud.rest","source":"--gnrc-color-foreground-neutral-onloud","type":"inverted","cool":{"light":"#ffffff","dark":"#000000db"},"warm":{"light":"#ffffff","dark":"#0b0600e1"}}, + {"path":"color.foregroundNeutralOnloud.hover","source":"--gnrc-color-foreground-neutral-onloud-hover","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffd","dark":"#010000e1","state":"computed"}}, + {"path":"color.foregroundNeutralOnloud.pressed","source":"--gnrc-color-foreground-neutral-onloud-pressed","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffb","dark":"#000000e1","state":"computed"}}, + {"path":"color.foregroundBrandPrimary.rest","source":"--gnrc-color-foreground-brand-primary","type":"standard","cool":{"light":"#242424","dark":"#dedede"},"warm":{"light":"#0b0600e1","dark":"#fff7f2e3"}}, + {"path":"color.foregroundBrandPrimary.hover","source":"--gnrc-color-foreground-brand-primary-hover","cool":{"light":"#131313","dark":"#e8e8e8","state":"computed"},"warm":{"light":"#060300eb","dark":"#fff8f2eb","state":"computed"}}, + {"path":"color.foregroundBrandPrimary.pressed","source":"--gnrc-color-foreground-brand-primary-pressed","cool":{"light":"#050505","dark":"#f2f2f2","state":"computed"},"warm":{"light":"#040100f5","dark":"#fffaf2f2","state":"computed"}}, + {"path":"color.foregroundBrandOnloud.rest","source":"--gnrc-color-foreground-brand-onloud","type":"inverted","cool":{"light":"#ffffff","dark":"#000000db"},"warm":{"light":"#ffffff","dark":"#0b0600e1"}}, + {"path":"color.foregroundBrandOnloud.hover","source":"--gnrc-color-foreground-brand-onloud-hover","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffd","dark":"#010000e1","state":"computed"}}, + {"path":"color.foregroundBrandOnloud.pressed","source":"--gnrc-color-foreground-brand-onloud-pressed","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffb","dark":"#000000e1","state":"computed"}}, + {"path":"color.foregroundDangerPrimary.rest","source":"--gnrc-color-foreground-danger-primary","type":"standard","cool":{"light":"#a62147","dark":"#fd8ea1"},"warm":{"light":"#a62147","dark":"#fd8ea1"}}, + {"path":"color.foregroundDangerPrimary.hover","source":"--gnrc-color-foreground-danger-primary-hover","cool":{"light":"#9c133f","dark":"#ff97aa","state":"computed"},"warm":{"light":"#9e0b3e","dark":"#ff96aa","state":"computed"}}, + {"path":"color.foregroundDangerPrimary.pressed","source":"--gnrc-color-foreground-danger-primary-pressed","cool":{"light":"#910037","dark":"#ffa1b4","state":"computed"},"warm":{"light":"#950035","dark":"#ff9db2","state":"computed"}}, + {"path":"color.foregroundDangerOnloud.rest","source":"--gnrc-color-foreground-danger-onloud","type":"inverted","cool":{"light":"#ffffff","dark":"#000000db"},"warm":{"light":"#ffffff","dark":"#000000db"}}, + {"path":"color.foregroundDangerOnloud.hover","source":"--gnrc-color-foreground-danger-onloud-hover","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffd","dark":"#000000db","state":"computed"}}, + {"path":"color.foregroundDangerOnloud.pressed","source":"--gnrc-color-foreground-danger-onloud-pressed","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffb","dark":"#000000db","state":"computed"}}, + {"path":"color.foregroundWarningPrimary.rest","source":"--gnrc-color-foreground-warning-primary","type":"standard","cool":{"light":"#a93901","dark":"#fc9571"},"warm":{"light":"#a93901","dark":"#fc9571"}}, + {"path":"color.foregroundWarningPrimary.hover","source":"--gnrc-color-foreground-warning-primary-hover","cool":{"light":"#9f2f00","dark":"#ff9f7a","state":"computed"},"warm":{"light":"#a12c00","dark":"#ff9d77","state":"computed"}}, + {"path":"color.foregroundWarningPrimary.pressed","source":"--gnrc-color-foreground-warning-primary-pressed","cool":{"light":"#952500","dark":"#ffa884","state":"computed"},"warm":{"light":"#991c00","dark":"#ffa57d","state":"computed"}}, + {"path":"color.foregroundWarningOnloud.rest","source":"--gnrc-color-foreground-warning-onloud","type":"inverted","cool":{"light":"#ffffff","dark":"#000000db"},"warm":{"light":"#ffffff","dark":"#000000db"}}, + {"path":"color.foregroundWarningOnloud.hover","source":"--gnrc-color-foreground-warning-onloud-hover","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffd","dark":"#000000db","state":"computed"}}, + {"path":"color.foregroundWarningOnloud.pressed","source":"--gnrc-color-foreground-warning-onloud-pressed","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffb","dark":"#000000db","state":"computed"}}, + {"path":"color.foregroundSuccessPrimary.rest","source":"--gnrc-color-foreground-success-primary","type":"standard","cool":{"light":"#017048","dark":"#5dce97"},"warm":{"light":"#017048","dark":"#5dce97"}}, + {"path":"color.foregroundSuccessPrimary.hover","source":"--gnrc-color-foreground-success-primary-hover","cool":{"light":"#006740","dark":"#67d8a0","state":"computed"},"warm":{"light":"#00683f","dark":"#62d99f","state":"computed"}}, + {"path":"color.foregroundSuccessPrimary.pressed","source":"--gnrc-color-foreground-success-primary-pressed","cool":{"light":"#005f38","dark":"#72e2aa","state":"computed"},"warm":{"light":"#006036","dark":"#67e4a7","state":"computed"}}, + {"path":"color.foregroundSuccessOnloud.rest","source":"--gnrc-color-foreground-success-onloud","type":"inverted","cool":{"light":"#ffffff","dark":"#000000db"},"warm":{"light":"#ffffff","dark":"#000000db"}}, + {"path":"color.foregroundSuccessOnloud.hover","source":"--gnrc-color-foreground-success-onloud-hover","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffd","dark":"#000000db","state":"computed"}}, + {"path":"color.foregroundSuccessOnloud.pressed","source":"--gnrc-color-foreground-success-onloud-pressed","cool":{"light":"#ffffff","dark":"#000000db","state":"computed"},"warm":{"light":"#fffffb","dark":"#000000db","state":"computed"}}, + {"path":"color.fixedWhite.rest","source":"--gnrc-color-fixed-white","cool":{"light":"#ffffff","dark":"#ffffff"},"warm":{"light":"#ffffff","dark":"#ffffff"}}, + {"path":"color.fixedWhite.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.fixedWhite.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.fixedBlack.rest","source":"--gnrc-color-fixed-black","cool":{"light":"#000000","dark":"#000000"},"warm":{"light":"#000000","dark":"#000000"}}, + {"path":"color.fixedBlack.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.fixedBlack.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAccentHeavy.rest","source":"--gnrc-color-expression-accent-heavy","cool":{"light":"#242424","dark":"#ffffff"},"warm":{"light":"#28231e","dark":"#ffffff"}}, + {"path":"color.expressionAccentHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAccentHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAccentLoud.rest","source":"--gnrc-color-expression-accent-loud","cool":{"light":"#6f6f6f","dark":"#929292"},"warm":{"light":"#1e0d009a","dark":"#ffeee39a"}}, + {"path":"color.expressionAccentLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAccentLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAccentSoft.rest","source":"--gnrc-color-expression-accent-soft","cool":{"light":"#00000014","dark":"#ffffff1f"},"warm":{"light":"#4d200028","dark":"#ffe3cb40"}}, + {"path":"color.expressionAccentSoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAccentSoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAccentSubtle.rest","source":"--gnrc-color-expression-accent-subtle","cool":{"light":"#0000000d","dark":"#ffffff14"},"warm":{"light":"#6c31001a","dark":"#fff4ef14"}}, + {"path":"color.expressionAccentSubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAccentSubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAchromaticHeavy.rest","source":"--gnrc-color-expression-achromatic-heavy","cool":{"light":"#000000","dark":"#ffffff"},"warm":{"light":"#000000","dark":"#ffffff"}}, + {"path":"color.expressionAchromaticHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAchromaticHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAchromaticSubtle.rest","source":"--gnrc-color-expression-achromatic-subtle","cool":{"light":"#ffffff","dark":"#000000"},"warm":{"light":"#ffffff","dark":"#000000"}}, + {"path":"color.expressionAchromaticSubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionAchromaticSubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGrayHeavy.rest","source":"--gnrc-color-expression-gray-heavy","cool":{"light":"#484848","dark":"#f5f5f5"},"warm":{"light":"#484848","dark":"#f5f5f5"}}, + {"path":"color.expressionGrayHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGrayHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGrayLoud.rest","source":"--gnrc-color-expression-gray-loud","cool":{"light":"#929292","dark":"#dedede"},"warm":{"light":"#929292","dark":"#dedede"}}, + {"path":"color.expressionGrayLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGrayLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGraySoft.rest","source":"--gnrc-color-expression-gray-soft","cool":{"light":"#dedede","dark":"#929292"},"warm":{"light":"#dedede","dark":"#929292"}}, + {"path":"color.expressionGraySoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGraySoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGraySubtle.rest","source":"--gnrc-color-expression-gray-subtle","cool":{"light":"#f5f5f5","dark":"#484848"},"warm":{"light":"#f5f5f5","dark":"#484848"}}, + {"path":"color.expressionGraySubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGraySubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionNavyHeavy.rest","source":"--gnrc-color-expression-navy-heavy","cool":{"light":"#294482","dark":"#f0f5ff"},"warm":{"light":"#294482","dark":"#f0f5ff"}}, + {"path":"color.expressionNavyHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionNavyHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionNavyLoud.rest","source":"--gnrc-color-expression-navy-loud","cool":{"light":"#5c8df8","dark":"#cedeff"},"warm":{"light":"#5c8df8","dark":"#cedeff"}}, + {"path":"color.expressionNavyLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionNavyLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionNavySoft.rest","source":"--gnrc-color-expression-navy-soft","cool":{"light":"#cedeff","dark":"#5c8df8"},"warm":{"light":"#cedeff","dark":"#5c8df8"}}, + {"path":"color.expressionNavySoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionNavySoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionNavySubtle.rest","source":"--gnrc-color-expression-navy-subtle","cool":{"light":"#f0f5ff","dark":"#294482"},"warm":{"light":"#f0f5ff","dark":"#294482"}}, + {"path":"color.expressionNavySubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionNavySubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionBlueHeavy.rest","source":"--gnrc-color-expression-blue-heavy","cool":{"light":"#0b497f","dark":"#eef6ff"},"warm":{"light":"#0b497f","dark":"#eef6ff"}}, + {"path":"color.expressionBlueHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionBlueHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionBlueLoud.rest","source":"--gnrc-color-expression-blue-loud","cool":{"light":"#2f95f4","dark":"#c6e1ff"},"warm":{"light":"#2f95f4","dark":"#c6e1ff"}}, + {"path":"color.expressionBlueLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionBlueLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionBlueSoft.rest","source":"--gnrc-color-expression-blue-soft","cool":{"light":"#c6e1ff","dark":"#2f95f4"},"warm":{"light":"#c6e1ff","dark":"#2f95f4"}}, + {"path":"color.expressionBlueSoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionBlueSoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionBlueSubtle.rest","source":"--gnrc-color-expression-blue-subtle","cool":{"light":"#eef6ff","dark":"#0b497f"},"warm":{"light":"#eef6ff","dark":"#0b497f"}}, + {"path":"color.expressionBlueSubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionBlueSubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGreenHeavy.rest","source":"--gnrc-color-expression-green-heavy","cool":{"light":"#0c5722","dark":"#e7fce9"},"warm":{"light":"#0c5722","dark":"#e7fce9"}}, + {"path":"color.expressionGreenHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGreenHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGreenLoud.rest","source":"--gnrc-color-expression-green-loud","cool":{"light":"#32ad52","dark":"#baedc1"},"warm":{"light":"#32ad52","dark":"#baedc1"}}, + {"path":"color.expressionGreenLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGreenLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGreenSoft.rest","source":"--gnrc-color-expression-green-soft","cool":{"light":"#baedc1","dark":"#32ad52"},"warm":{"light":"#baedc1","dark":"#32ad52"}}, + {"path":"color.expressionGreenSoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGreenSoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGreenSubtle.rest","source":"--gnrc-color-expression-green-subtle","cool":{"light":"#e7fce9","dark":"#0c5722"},"warm":{"light":"#e7fce9","dark":"#0c5722"}}, + {"path":"color.expressionGreenSubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionGreenSubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionLimeHeavy.rest","source":"--gnrc-color-expression-lime-heavy","cool":{"light":"#345200","dark":"#e6ffcf"},"warm":{"light":"#345200","dark":"#e6ffcf"}}, + {"path":"color.expressionLimeHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionLimeHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionLimeLoud.rest","source":"--gnrc-color-expression-lime-loud","cool":{"light":"#6da603","dark":"#cbff93"},"warm":{"light":"#6da603","dark":"#cbff93"}}, + {"path":"color.expressionLimeLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionLimeLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionLimeSoft.rest","source":"--gnrc-color-expression-lime-soft","cool":{"light":"#cbff93","dark":"#6da603"},"warm":{"light":"#cbff93","dark":"#6da603"}}, + {"path":"color.expressionLimeSoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionLimeSoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionLimeSubtle.rest","source":"--gnrc-color-expression-lime-subtle","cool":{"light":"#e6ffcf","dark":"#345200"},"warm":{"light":"#e6ffcf","dark":"#345200"}}, + {"path":"color.expressionLimeSubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionLimeSubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionYellowHeavy.rest","source":"--gnrc-color-expression-yellow-heavy","cool":{"light":"#524800","dark":"#fff7c4"},"warm":{"light":"#524800","dark":"#fff7c4"}}, + {"path":"color.expressionYellowHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionYellowHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionYellowLoud.rest","source":"--gnrc-color-expression-yellow-loud","cool":{"light":"#fbdf06","dark":"#ffed85"},"warm":{"light":"#fbdf06","dark":"#ffed85"}}, + {"path":"color.expressionYellowLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionYellowLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionYellowSoft.rest","source":"--gnrc-color-expression-yellow-soft","cool":{"light":"#ffed85","dark":"#fbdf06"},"warm":{"light":"#ffed85","dark":"#fbdf06"}}, + {"path":"color.expressionYellowSoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionYellowSoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionYellowSubtle.rest","source":"--gnrc-color-expression-yellow-subtle","cool":{"light":"#fff7c4","dark":"#524800"},"warm":{"light":"#fff7c4","dark":"#524800"}}, + {"path":"color.expressionYellowSubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionYellowSubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPumpkinHeavy.rest","source":"--gnrc-color-expression-pumpkin-heavy","cool":{"light":"#762f0e","dark":"#fef2ee"},"warm":{"light":"#762f0e","dark":"#fef2ee"}}, + {"path":"color.expressionPumpkinHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPumpkinHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPumpkinLoud.rest","source":"--gnrc-color-expression-pumpkin-loud","cool":{"light":"#fb966e","dark":"#ffd3c2"},"warm":{"light":"#fb966e","dark":"#ffd3c2"}}, + {"path":"color.expressionPumpkinLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPumpkinLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPumpkinSoft.rest","source":"--gnrc-color-expression-pumpkin-soft","cool":{"light":"#ffd3c2","dark":"#fb966e"},"warm":{"light":"#ffd3c2","dark":"#fb966e"}}, + {"path":"color.expressionPumpkinSoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPumpkinSoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPumpkinSubtle.rest","source":"--gnrc-color-expression-pumpkin-subtle","cool":{"light":"#fef2ee","dark":"#762f0e"},"warm":{"light":"#fef2ee","dark":"#762f0e"}}, + {"path":"color.expressionPumpkinSubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPumpkinSubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionRedHeavy.rest","source":"--gnrc-color-expression-red-heavy","cool":{"light":"#772b28","dark":"#fff2f0"},"warm":{"light":"#772b28","dark":"#fff2f0"}}, + {"path":"color.expressionRedHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionRedHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionRedLoud.rest","source":"--gnrc-color-expression-red-loud","cool":{"light":"#e7615b","dark":"#ffd2cd"},"warm":{"light":"#e7615b","dark":"#ffd2cd"}}, + {"path":"color.expressionRedLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionRedLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionRedSoft.rest","source":"--gnrc-color-expression-red-soft","cool":{"light":"#ffd2cd","dark":"#e7615b"},"warm":{"light":"#ffd2cd","dark":"#e7615b"}}, + {"path":"color.expressionRedSoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionRedSoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionRedSubtle.rest","source":"--gnrc-color-expression-red-subtle","cool":{"light":"#fff2f0","dark":"#772b28"},"warm":{"light":"#fff2f0","dark":"#772b28"}}, + {"path":"color.expressionRedSubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionRedSubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPinkHeavy.rest","source":"--gnrc-color-expression-pink-heavy","cool":{"light":"#6f2b53","dark":"#fff1f7"},"warm":{"light":"#6f2b53","dark":"#fff1f7"}}, + {"path":"color.expressionPinkHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPinkHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPinkLoud.rest","source":"--gnrc-color-expression-pink-loud","cool":{"light":"#d961a6","dark":"#ffcee6"},"warm":{"light":"#d961a6","dark":"#ffcee6"}}, + {"path":"color.expressionPinkLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPinkLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPinkSoft.rest","source":"--gnrc-color-expression-pink-soft","cool":{"light":"#ffcee6","dark":"#d961a6"},"warm":{"light":"#ffcee6","dark":"#d961a6"}}, + {"path":"color.expressionPinkSoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPinkSoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPinkSubtle.rest","source":"--gnrc-color-expression-pink-subtle","cool":{"light":"#fff1f7","dark":"#6f2b53"},"warm":{"light":"#fff1f7","dark":"#6f2b53"}}, + {"path":"color.expressionPinkSubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPinkSubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPurpleHeavy.rest","source":"--gnrc-color-expression-purple-heavy","cool":{"light":"#523778","dark":"#f7f3ff"},"warm":{"light":"#523778","dark":"#f7f3ff"}}, + {"path":"color.expressionPurpleHeavy.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPurpleHeavy.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPurpleLoud.rest","source":"--gnrc-color-expression-purple-loud","cool":{"light":"#a575e8","dark":"#e4d6ff"},"warm":{"light":"#a575e8","dark":"#e4d6ff"}}, + {"path":"color.expressionPurpleLoud.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPurpleLoud.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPurpleSoft.rest","source":"--gnrc-color-expression-purple-soft","cool":{"light":"#e4d6ff","dark":"#a575e8"},"warm":{"light":"#e4d6ff","dark":"#a575e8"}}, + {"path":"color.expressionPurpleSoft.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPurpleSoft.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPurpleSubtle.rest","source":"--gnrc-color-expression-purple-subtle","cool":{"light":"#f7f3ff","dark":"#523778"},"warm":{"light":"#f7f3ff","dark":"#523778"}}, + {"path":"color.expressionPurpleSubtle.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.expressionPurpleSubtle.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.overlayNeutralTranslucent.rest","source":"--gnrc-color-overlay-neutral-translucent","cool":{"light":"#00000026","dark":"#00000099"},"warm":{"light":"#00000026","dark":"#00000099"}}, + {"path":"color.overlayNeutralTranslucent.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.overlayNeutralTranslucent.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.materialBackgroundThick.rest","source":"--gnrc-material-background-thick","cool":{"light":"#fffffff1","dark":"#262626ea"},"warm":{"light":"#fffffff1","dark":"#262626ea"}}, + {"path":"color.materialBackgroundThick.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.materialBackgroundThick.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.materialBackgroundRegular.rest","source":"--gnrc-material-background-regular","cool":{"light":"#ffffffd7","dark":"#2f2f2fd1"},"warm":{"light":"#ffffffd7","dark":"#2f2f2fd1"}}, + {"path":"color.materialBackgroundRegular.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.materialBackgroundRegular.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.materialBackgroundThin.rest","source":"--gnrc-material-background-thin","cool":{"light":"#ffffff7e","dark":"#3434348b"},"warm":{"light":"#ffffff7e","dark":"#3434348b"}}, + {"path":"color.materialBackgroundThin.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.materialBackgroundThin.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.backgroundNeutralDisabled.rest","source":"--gnrc-color-background-neutral-disabled","cool":{"light":"#00000008","dark":"#ffffff07"},"warm":{"light":"#00000008","dark":"#ffffff07"}}, + {"path":"color.backgroundNeutralDisabled.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.backgroundNeutralDisabled.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.backgroundNeutralHeavyDisabled.rest","source":"--gnrc-color-background-neutral-heavy-disabled","cool":{"light":"#0000001a","dark":"#ffffff20"},"warm":{"light":"#0000001a","dark":"#ffffff20"}}, + {"path":"color.backgroundNeutralHeavyDisabled.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.backgroundNeutralHeavyDisabled.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.backgroundNeutralSubtleDisabled.rest","source":"--gnrc-color-background-neutral-subtle-disabled","cool":{"light":"#00000008","dark":"#ffffff07"},"warm":{"light":"#0000000d","dark":"#ffffff1b"}}, + {"path":"color.backgroundNeutralSubtleDisabled.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.backgroundNeutralSubtleDisabled.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.strokeNeutralDisabled.rest","source":"--gnrc-color-stroke-neutral-disabled","cool":{"light":"#00000014","dark":"#ffffff24"},"warm":{"light":"#00000014","dark":"#ffffff24"}}, + {"path":"color.strokeNeutralDisabled.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.strokeNeutralDisabled.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.foregroundNeutralDisabled.rest","source":"--gnrc-color-foreground-neutral-disabled","cool":{"light":"#0000006d","dark":"#ffffff61"},"warm":{"light":"#0000006d","dark":"#ffffff61"}}, + {"path":"color.foregroundNeutralDisabled.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.foregroundNeutralDisabled.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.strokeFocusInner.rest","source":"--gnrc-color-stroke-focus-inner","cool":{"light":"#ffffff","dark":"#000000"},"warm":{"light":"#ffffff","dark":"#000000"}}, + {"path":"color.strokeFocusInner.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.strokeFocusInner.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.strokeFocusOuter.rest","source":"--gnrc-color-stroke-focus-outer","cool":{"light":"#000000","dark":"#ffffff"},"warm":{"light":"#000000","dark":"#ffffff"}}, + {"path":"color.strokeFocusOuter.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.strokeFocusOuter.pressed","state":"rest","reason":"non-interactive"}, + {"path":"color.shadow.rest","source":"--gnrc-color-shadow","cool":{"light":"#000000","dark":"#000000"},"warm":{"light":"#000000","dark":"#000000"}}, + {"path":"color.shadow.hover","state":"rest","reason":"non-interactive"}, + {"path":"color.shadow.pressed","state":"rest","reason":"non-interactive"}, + {"path":"shadow.lowest","source":"--gnrc-shadow-lowest","adaptation":"Relative oklch alpha resolves to #rrggbbaa; every layer is preserved.","cool":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 5%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":1,"blur":2,"color":"#0000000d"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":1,"blur":2,"color":"#0000001a"}]]},"warm":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 5%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":1,"blur":2,"color":"#0000000d"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":1,"blur":2,"color":"#0000001a"}]]}}, + {"path":"shadow.lower","source":"--gnrc-shadow-lower","adaptation":"Relative oklch alpha resolves to #rrggbbaa; every layer is preserved.","cool":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 8%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 16%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":2,"blur":4,"color":"#00000014"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":2,"blur":4,"color":"#00000029"}]]},"warm":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 8%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 16%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":2,"blur":4,"color":"#00000014"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":2,"blur":4,"color":"#00000029"}]]}}, + {"path":"shadow.low","source":"--gnrc-shadow-low","adaptation":"Relative oklch alpha resolves to #rrggbbaa; every layer is preserved.","cool":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 8%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 16%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":2,"blur":4,"color":"#00000008"},{"x":0,"y":4,"blur":8,"color":"#00000014"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":2,"blur":4,"color":"#0000001f"},{"x":0,"y":4,"blur":8,"color":"#00000029"}]]},"warm":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 8%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 16%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":2,"blur":4,"color":"#00000008"},{"x":0,"y":4,"blur":8,"color":"#00000014"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":2,"blur":4,"color":"#0000001f"},{"x":0,"y":4,"blur":8,"color":"#00000029"}]]}}, + {"path":"shadow.high","source":"--gnrc-shadow-high","adaptation":"Relative oklch alpha resolves to #rrggbbaa; every layer is preserved.","cool":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 6%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":4,"blur":8,"color":"#00000008"},{"x":0,"y":8,"blur":16,"color":"#0000000f"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":4,"blur":8,"color":"#0000001f"},{"x":0,"y":8,"blur":16,"color":"#0000001f"}]]},"warm":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 6%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":4,"blur":8,"color":"#00000008"},{"x":0,"y":8,"blur":16,"color":"#0000000f"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":4,"blur":8,"color":"#0000001f"},{"x":0,"y":8,"blur":16,"color":"#0000001f"}]]}}, + {"path":"shadow.higher","source":"--gnrc-shadow-higher","adaptation":"Relative oklch alpha resolves to #rrggbbaa; every layer is preserved.","cool":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 6%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 12%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":8,"blur":16,"color":"#00000008"},{"x":0,"y":16,"blur":32,"color":"#0000000f"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":8,"blur":16,"color":"#0000001f"},{"x":0,"y":16,"blur":32,"color":"#0000001f"}]]},"warm":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 6%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 12%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":8,"blur":16,"color":"#00000008"},{"x":0,"y":16,"blur":32,"color":"#0000000f"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":8,"blur":16,"color":"#0000001f"},{"x":0,"y":16,"blur":32,"color":"#0000001f"}]]}}, + {"path":"shadow.highest","source":"--gnrc-shadow-highest","adaptation":"Relative oklch alpha resolves to #rrggbbaa; every layer is preserved.","cool":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 6%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 12%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":8,"blur":16,"color":"#00000008"},{"x":0,"y":32,"blur":64,"color":"#0000000f"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":8,"blur":16,"color":"#0000001f"},{"x":0,"y":32,"blur":64,"color":"#0000001f"}]]},"warm":{"light":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 6%)","dark":"0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 12%)","native":[[{"x":0,"y":0,"blur":2,"color":"#0000001a"},{"x":0,"y":8,"blur":16,"color":"#00000008"},{"x":0,"y":32,"blur":64,"color":"#0000000f"}],[{"x":0,"y":0,"blur":2,"color":"#00000033"},{"x":0,"y":8,"blur":16,"color":"#0000001f"},{"x":0,"y":32,"blur":64,"color":"#0000001f"}]]}}, + {"path":"fontWeight.functionalRegular","source":"--gnrc-font-weight-functional-regular","adaptation":"The x3 variable weight 420 uses the native static regular weight.","cool":{"light":"420","dark":"420","native":"fontWeightRegular ('400')"},"warm":{"light":"420","dark":"420","native":"fontWeightRegular ('400')"}}, + {"path":"fontWeight.functionalMedium","source":"--gnrc-font-weight-functional-medium","adaptation":"The x3 variable weight 550 uses the native static medium weight.","cool":{"light":"550","dark":"550","native":"fontWeightMedium ('500')"},"warm":{"light":"550","dark":"550","native":"fontWeightMedium ('500')"}}, + {"path":"fontWeight.functionalSemibold","source":"--gnrc-font-weight-functional-semibold","adaptation":"The x3 variable weight 600 uses the native static semibold weight.","cool":{"light":"600","dark":"600","native":"fontWeightSemibold ('600')"},"warm":{"light":"600","dark":"600","native":"fontWeightSemibold ('600')"}}, + {"path":"fontWeight.functionalBold","source":"--gnrc-font-weight-functional-bold","adaptation":"The x3 variable weight 625 uses the native static bold weight.","cool":{"light":"625","dark":"625","native":"fontWeightBold ('700')"},"warm":{"light":"625","dark":"625","native":"fontWeightBold ('700')"}}, + {"path":"fontWeight.contentRegular","source":"--gnrc-font-weight-content-regular","adaptation":"The x3 variable weight 420 uses the native static regular weight.","cool":{"light":"420","dark":"420","native":"fontWeightRegular ('400')"},"warm":{"light":"420","dark":"420","native":"fontWeightRegular ('400')"}}, + {"path":"fontWeight.contentMedium","source":"--gnrc-font-weight-content-medium","adaptation":"The x3 variable weight 550 uses the native static medium weight.","cool":{"light":"550","dark":"550","native":"fontWeightMedium ('500')"},"warm":{"light":"550","dark":"550","native":"fontWeightMedium ('500')"}}, + {"path":"fontWeight.contentSemibold","source":"--gnrc-font-weight-content-semibold","adaptation":"The x3 variable weight 600 uses the native static semibold weight.","cool":{"light":"600","dark":"600","native":"fontWeightSemibold ('600')"},"warm":{"light":"600","dark":"600","native":"fontWeightSemibold ('600')"}}, + {"path":"fontWeight.contentBold","source":"--gnrc-font-weight-content-bold","adaptation":"The x3 variable weight 625 uses the native static bold weight.","cool":{"light":"625","dark":"625","native":"fontWeightBold ('700')"},"warm":{"light":"625","dark":"625","native":"fontWeightBold ('700')"}}, + {"path":"fontWeight.contentEditorialRegular","source":"--gnrc-font-weight-content-editorial-regular","adaptation":"The x3 variable weight 420 uses the native static regular weight.","cool":{"light":"420","dark":"420","native":"fontWeightRegular ('400')"},"warm":{"light":"420","dark":"420","native":"fontWeightRegular ('400')"}}, + {"path":"fontWeight.contentEditorialMedium","source":"--gnrc-font-weight-content-editorial-medium","adaptation":"The x3 variable weight 550 uses the native static medium weight.","cool":{"light":"550","dark":"550","native":"fontWeightMedium ('500')"},"warm":{"light":"550","dark":"550","native":"fontWeightMedium ('500')"}}, + {"path":"fontWeight.contentEditorialSemibold","source":"--gnrc-font-weight-content-editorial-semibold","adaptation":"The x3 variable weight 600 uses the native static semibold weight.","cool":{"light":"600","dark":"600","native":"fontWeightSemibold ('600')"},"warm":{"light":"600","dark":"600","native":"fontWeightSemibold ('600')"}}, + {"path":"fontWeight.contentEditorialBold","source":"--gnrc-font-weight-content-editorial-bold","adaptation":"The x3 variable weight 625 uses the native static bold weight.","cool":{"light":"625","dark":"625","native":"fontWeightBold ('700')"},"warm":{"light":"625","dark":"625","native":"fontWeightBold ('700')"}}, + {"path":"fontFamily.functional","source":"--gnrc-font-family-functional","adaptation":"The x3 sans-serif stack uses the native platform base family.","cool":{"light":"'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif","dark":"'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif","native":"fontFamilyBase"},"warm":{"light":"'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif","dark":"'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif","native":"fontFamilyBase"}}, + {"path":"fontFamily.content","source":"--gnrc-font-family-content","adaptation":"The x3 sans-serif stack uses the native platform base family.","cool":{"light":"'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif","dark":"'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif","native":"fontFamilyBase"},"warm":{"light":"'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif","dark":"'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif","native":"fontFamilyBase"}}, + {"path":"fontFamily.contentEditorial","source":"--gnrc-font-family-content-editorial","adaptation":"The x3 serif stack has no portable native serif family, so it uses the platform base family.","cool":{"light":"'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif","dark":"'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif","native":"fontFamilyBase"},"warm":{"light":"'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif","dark":"'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif","native":"fontFamilyBase"}}, + {"path":"fontFamily.contentCode","source":"--gnrc-font-family-content-code","adaptation":"The x3 monospace stack uses the native platform monospace family.","cool":{"light":"'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace","dark":"'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace","native":"fontFamilyMonospace"},"warm":{"light":"'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace","dark":"'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace","native":"fontFamilyMonospace"}}, + {"path":"fontSize.functionalDisplay","source":"--gnrc-font-size-functional-display","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"4.25rem","dark":"4.25rem","native":68},"warm":{"light":"4.25rem","dark":"4.25rem","native":68}}, + {"path":"fontSize.functionalPagetitle","source":"--gnrc-font-size-functional-pagetitle","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"2.5rem","dark":"2.5rem","native":40},"warm":{"light":"2.5rem","dark":"2.5rem","native":40}}, + {"path":"fontSize.functionalTitleLarge","source":"--gnrc-font-size-functional-title-large","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"2rem","dark":"2rem","native":32},"warm":{"light":"2rem","dark":"2rem","native":32}}, + {"path":"fontSize.functionalTitleMedium","source":"--gnrc-font-size-functional-title-medium","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1.75rem","dark":"1.75rem","native":28},"warm":{"light":"1.75rem","dark":"1.75rem","native":28}}, + {"path":"fontSize.functionalTitleSmall","source":"--gnrc-font-size-functional-title-small","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1.5rem","dark":"1.5rem","native":24},"warm":{"light":"1.5rem","dark":"1.5rem","native":24}}, + {"path":"fontSize.functionalSubtitle","source":"--gnrc-font-size-functional-subtitle","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1.25rem","dark":"1.25rem","native":20},"warm":{"light":"1.25rem","dark":"1.25rem","native":20}}, + {"path":"fontSize.functionalBodyLarge","source":"--gnrc-font-size-functional-body-large","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1rem","dark":"1rem","native":16},"warm":{"light":"1rem","dark":"1rem","native":16}}, + {"path":"fontSize.functionalBodyMedium","source":"--gnrc-font-size-functional-body-medium","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"0.875rem","dark":"0.875rem","native":14},"warm":{"light":"0.875rem","dark":"0.875rem","native":14}}, + {"path":"fontSize.functionalBodySmall","source":"--gnrc-font-size-functional-body-small","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"0.75rem","dark":"0.75rem","native":12},"warm":{"light":"0.75rem","dark":"0.75rem","native":12}}, + {"path":"fontSize.functionalCaption","source":"--gnrc-font-size-functional-caption","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"0.625rem","dark":"0.625rem","native":10},"warm":{"light":"0.625rem","dark":"0.625rem","native":10}}, + {"path":"fontSize.contentStatement","source":"--gnrc-font-size-content-statement","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"3.5rem","dark":"3.5rem","native":56},"warm":{"light":"3.5rem","dark":"3.5rem","native":56}}, + {"path":"fontSize.contentExpressiveLarge","source":"--gnrc-font-size-content-expressive-large","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"3rem","dark":"3rem","native":48},"warm":{"light":"3rem","dark":"3rem","native":48}}, + {"path":"fontSize.contentExpressiveMedium","source":"--gnrc-font-size-content-expressive-medium","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"2.25rem","dark":"2.25rem","native":36},"warm":{"light":"2.25rem","dark":"2.25rem","native":36}}, + {"path":"fontSize.contentExpressiveSmall","source":"--gnrc-font-size-content-expressive-small","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1.75rem","dark":"1.75rem","native":28},"warm":{"light":"1.75rem","dark":"1.75rem","native":28}}, + {"path":"fontSize.contentH1","source":"--gnrc-font-size-content-h1","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"2.25rem","dark":"2.25rem","native":36},"warm":{"light":"2.25rem","dark":"2.25rem","native":36}}, + {"path":"fontSize.contentH2","source":"--gnrc-font-size-content-h2","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"2rem","dark":"2rem","native":32},"warm":{"light":"2rem","dark":"2rem","native":32}}, + {"path":"fontSize.contentH3","source":"--gnrc-font-size-content-h3","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1.75rem","dark":"1.75rem","native":28},"warm":{"light":"1.75rem","dark":"1.75rem","native":28}}, + {"path":"fontSize.contentH4","source":"--gnrc-font-size-content-h4","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1.5rem","dark":"1.5rem","native":24},"warm":{"light":"1.5rem","dark":"1.5rem","native":24}}, + {"path":"fontSize.contentH5","source":"--gnrc-font-size-content-h5","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1.25rem","dark":"1.25rem","native":20},"warm":{"light":"1.25rem","dark":"1.25rem","native":20}}, + {"path":"fontSize.contentSubheadline","source":"--gnrc-font-size-content-subheadline","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1rem","dark":"1rem","native":16},"warm":{"light":"1rem","dark":"1rem","native":16}}, + {"path":"fontSize.contentParagraphLarge","source":"--gnrc-font-size-content-paragraph-large","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1.25rem","dark":"1.25rem","native":20},"warm":{"light":"1.25rem","dark":"1.25rem","native":20}}, + {"path":"fontSize.contentParagraphMedium","source":"--gnrc-font-size-content-paragraph-medium","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1rem","dark":"1rem","native":16},"warm":{"light":"1rem","dark":"1rem","native":16}}, + {"path":"fontSize.contentParagraphSmall","source":"--gnrc-font-size-content-paragraph-small","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"0.75rem","dark":"0.75rem","native":12},"warm":{"light":"0.75rem","dark":"0.75rem","native":12}}, + {"path":"fontSize.contentSubtext","source":"--gnrc-font-size-content-subtext","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"0.625rem","dark":"0.625rem","native":10},"warm":{"light":"0.625rem","dark":"0.625rem","native":10}}, + {"path":"fontSize.contentTable","source":"--gnrc-font-size-content-table","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1rem","dark":"1rem","native":16},"warm":{"light":"1rem","dark":"1rem","native":16}}, + {"path":"fontSize.contentCode","source":"--gnrc-font-size-content-code","adaptation":"1rem is 16 density-independent pixels.","cool":{"light":"1rem","dark":"1rem","native":16},"warm":{"light":"1rem","dark":"1rem","native":16}}, + {"path":"lineHeight.functionalDisplay","source":"--gnrc-line-height-functional-display","adaptation":"Resolved against fontSize.functionalDisplay (68).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":82},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":82}}, + {"path":"lineHeight.functionalPagetitle","source":"--gnrc-line-height-functional-pagetitle","adaptation":"Resolved against fontSize.functionalPagetitle (40).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":48},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":48}}, + {"path":"lineHeight.functionalTitleLarge","source":"--gnrc-line-height-functional-title-large","adaptation":"Resolved against fontSize.functionalTitleLarge (32).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":38},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":38}}, + {"path":"lineHeight.functionalTitleMedium","source":"--gnrc-line-height-functional-title-medium","adaptation":"Resolved against fontSize.functionalTitleMedium (28).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":34},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":34}}, + {"path":"lineHeight.functionalTitleSmall","source":"--gnrc-line-height-functional-title-small","adaptation":"Resolved against fontSize.functionalTitleSmall (24).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":28},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":28}}, + {"path":"lineHeight.functionalSubtitle","source":"--gnrc-line-height-functional-subtitle","adaptation":"Resolved against fontSize.functionalSubtitle (20).","cool":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":28},"warm":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":28}}, + {"path":"lineHeight.functionalBodyLarge","source":"--gnrc-line-height-functional-body-large","adaptation":"Resolved against fontSize.functionalBodyLarge (16).","cool":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":22},"warm":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":22}}, + {"path":"lineHeight.functionalBodyMedium","source":"--gnrc-line-height-functional-body-medium","adaptation":"Resolved against fontSize.functionalBodyMedium (14).","cool":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":20},"warm":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":20}}, + {"path":"lineHeight.functionalBodySmall","source":"--gnrc-line-height-functional-body-small","adaptation":"Resolved against fontSize.functionalBodySmall (12).","cool":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":16},"warm":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":16}}, + {"path":"lineHeight.functionalCaption","source":"--gnrc-line-height-functional-caption","adaptation":"Resolved against fontSize.functionalCaption (10).","cool":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":14},"warm":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":14}}, + {"path":"lineHeight.contentStatement","source":"--gnrc-line-height-content-statement","adaptation":"Resolved against fontSize.contentStatement (56).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":68},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":68}}, + {"path":"lineHeight.contentExpressiveLarge","source":"--gnrc-line-height-content-expressive-large","adaptation":"Resolved against fontSize.contentExpressiveLarge (48).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":58},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":58}}, + {"path":"lineHeight.contentExpressiveMedium","source":"--gnrc-line-height-content-expressive-medium","adaptation":"Resolved against fontSize.contentExpressiveMedium (36).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":44},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":44}}, + {"path":"lineHeight.contentExpressiveSmall","source":"--gnrc-line-height-content-expressive-small","adaptation":"Resolved against fontSize.contentExpressiveSmall (28).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":34},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":34}}, + {"path":"lineHeight.contentH1","source":"--gnrc-line-height-content-h1","adaptation":"Resolved against fontSize.contentH1 (36).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":44},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":44}}, + {"path":"lineHeight.contentH2","source":"--gnrc-line-height-content-h2","adaptation":"Resolved against fontSize.contentH2 (32).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":38},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":38}}, + {"path":"lineHeight.contentH3","source":"--gnrc-line-height-content-h3","adaptation":"Resolved against fontSize.contentH3 (28).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":34},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":34}}, + {"path":"lineHeight.contentH4","source":"--gnrc-line-height-content-h4","adaptation":"Resolved against fontSize.contentH4 (24).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":28},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":28}}, + {"path":"lineHeight.contentH5","source":"--gnrc-line-height-content-h5","adaptation":"Resolved against fontSize.contentH5 (20).","cool":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":24},"warm":{"light":"round(120%, 2px)","dark":"round(120%, 2px)","native":24}}, + {"path":"lineHeight.contentSubheadline","source":"--gnrc-line-height-content-subheadline","adaptation":"Resolved against fontSize.contentSubheadline (16).","cool":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":22},"warm":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":22}}, + {"path":"lineHeight.contentParagraphLarge","source":"--gnrc-line-height-content-paragraph-large","adaptation":"Resolved against fontSize.contentParagraphLarge (20).","cool":{"light":"round(170%, 2px)","dark":"round(170%, 2px)","native":34},"warm":{"light":"round(170%, 2px)","dark":"round(170%, 2px)","native":34}}, + {"path":"lineHeight.contentParagraphMedium","source":"--gnrc-line-height-content-paragraph-medium","adaptation":"Resolved against fontSize.contentParagraphMedium (16).","cool":{"light":"round(170%, 2px)","dark":"round(170%, 2px)","native":28},"warm":{"light":"round(170%, 2px)","dark":"round(170%, 2px)","native":28}}, + {"path":"lineHeight.contentParagraphSmall","source":"--gnrc-line-height-content-paragraph-small","adaptation":"Resolved against fontSize.contentParagraphSmall (12).","cool":{"light":"round(170%, 2px)","dark":"round(170%, 2px)","native":20},"warm":{"light":"round(170%, 2px)","dark":"round(170%, 2px)","native":20}}, + {"path":"lineHeight.contentSubtext","source":"--gnrc-line-height-content-subtext","adaptation":"Resolved against fontSize.contentSubtext (10).","cool":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":14},"warm":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":14}}, + {"path":"lineHeight.contentTable","source":"--gnrc-line-height-content-table","adaptation":"Resolved against fontSize.contentTable (16).","cool":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":22},"warm":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":22}}, + {"path":"lineHeight.contentCode","source":"--gnrc-line-height-content-code","adaptation":"Resolved against fontSize.contentCode (16).","cool":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":22},"warm":{"light":"round(140%, 2px)","dark":"round(140%, 2px)","native":22}}, + {"path":"borderRadius.base100","source":"--gnrc-border-radius-base-100","adaptation":"CSS px are density-independent pixels.","cool":{"light":"4px","dark":"4px","native":4},"warm":{"light":"4px","dark":"4px","native":4}}, + {"path":"borderRadius.base200","source":"--gnrc-border-radius-base-200","adaptation":"CSS px are density-independent pixels.","cool":{"light":"8px","dark":"8px","native":8},"warm":{"light":"8px","dark":"8px","native":8}}, + {"path":"borderRadius.base300","source":"--gnrc-border-radius-base-300","adaptation":"CSS px are density-independent pixels.","cool":{"light":"12px","dark":"12px","native":12},"warm":{"light":"12px","dark":"12px","native":12}}, + {"path":"borderRadius.base400","source":"--gnrc-border-radius-base-400","adaptation":"CSS px are density-independent pixels.","cool":{"light":"16px","dark":"16px","native":16},"warm":{"light":"16px","dark":"16px","native":16}}, + {"path":"borderRadius.base600","source":"--gnrc-border-radius-base-600","adaptation":"CSS px are density-independent pixels.","cool":{"light":"24px","dark":"24px","native":24},"warm":{"light":"24px","dark":"24px","native":24}}, + {"path":"borderRadius.base700","source":"--gnrc-border-radius-base-700","adaptation":"CSS px are density-independent pixels.","cool":{"light":"28px","dark":"28px","native":28},"warm":{"light":"28px","dark":"28px","native":28}}, + {"path":"borderRadius.circular","source":"--gnrc-border-radius-circular","adaptation":"CSS px are density-independent pixels.","cool":{"light":"9999px","dark":"9999px","native":9999},"warm":{"light":"9999px","dark":"9999px","native":9999}}, + {"path":"spacing.componentBase50","source":"--gnrc-spacing-component-base-50","adaptation":"CSS px are density-independent pixels.","cool":{"light":"2px","dark":"2px","native":2},"warm":{"light":"2px","dark":"2px","native":2}}, + {"path":"spacing.componentBase100","source":"--gnrc-spacing-component-base-100","adaptation":"CSS px are density-independent pixels.","cool":{"light":"4px","dark":"4px","native":4},"warm":{"light":"4px","dark":"4px","native":4}}, + {"path":"spacing.componentBase150","source":"--gnrc-spacing-component-base-150","adaptation":"CSS px are density-independent pixels.","cool":{"light":"6px","dark":"6px","native":6},"warm":{"light":"6px","dark":"6px","native":6}}, + {"path":"spacing.componentBase200","source":"--gnrc-spacing-component-base-200","adaptation":"CSS px are density-independent pixels.","cool":{"light":"8px","dark":"8px","native":8},"warm":{"light":"8px","dark":"8px","native":8}}, + {"path":"spacing.componentBase250","source":"--gnrc-spacing-component-base-250","adaptation":"CSS px are density-independent pixels.","cool":{"light":"10px","dark":"10px","native":10},"warm":{"light":"10px","dark":"10px","native":10}}, + {"path":"spacing.componentBase300","source":"--gnrc-spacing-component-base-300","adaptation":"CSS px are density-independent pixels.","cool":{"light":"12px","dark":"12px","native":12},"warm":{"light":"12px","dark":"12px","native":12}}, + {"path":"spacing.componentBase400","source":"--gnrc-spacing-component-base-400","adaptation":"CSS px are density-independent pixels.","cool":{"light":"16px","dark":"16px","native":16},"warm":{"light":"16px","dark":"16px","native":16}}, + {"path":"spacing.componentBase500","source":"--gnrc-spacing-component-base-500","adaptation":"CSS px are density-independent pixels.","cool":{"light":"20px","dark":"20px","native":20},"warm":{"light":"20px","dark":"20px","native":20}}, + {"path":"spacing.componentBase600","source":"--gnrc-spacing-component-base-600","adaptation":"CSS px are density-independent pixels.","cool":{"light":"24px","dark":"24px","native":24},"warm":{"light":"24px","dark":"24px","native":24}}, + {"path":"spacing.componentBase700","source":"--gnrc-spacing-component-base-700","adaptation":"CSS px are density-independent pixels.","cool":{"light":"28px","dark":"28px","native":28},"warm":{"light":"28px","dark":"28px","native":28}}, + {"path":"spacing.componentBase800","source":"--gnrc-spacing-component-base-800","adaptation":"CSS px are density-independent pixels.","cool":{"light":"32px","dark":"32px","native":32},"warm":{"light":"32px","dark":"32px","native":32}}, + {"path":"spacing.layoutBase100","source":"--gnrc-spacing-layout-base-100","adaptation":"CSS px are density-independent pixels.","cool":{"light":"8px","dark":"8px","native":8},"warm":{"light":"8px","dark":"8px","native":8}}, + {"path":"spacing.layoutBase200","source":"--gnrc-spacing-layout-base-200","adaptation":"CSS px are density-independent pixels.","cool":{"light":"16px","dark":"16px","native":16},"warm":{"light":"16px","dark":"16px","native":16}}, + {"path":"spacing.layoutBase300","source":"--gnrc-spacing-layout-base-300","adaptation":"CSS px are density-independent pixels.","cool":{"light":"24px","dark":"24px","native":24},"warm":{"light":"24px","dark":"24px","native":24}}, + {"path":"spacing.layoutBase400","source":"--gnrc-spacing-layout-base-400","adaptation":"CSS px are density-independent pixels.","cool":{"light":"32px","dark":"32px","native":32},"warm":{"light":"32px","dark":"32px","native":32}}, + {"path":"spacing.layoutBase450","source":"--gnrc-spacing-layout-base-450","adaptation":"CSS px are density-independent pixels.","cool":{"light":"36px","dark":"36px","native":36},"warm":{"light":"36px","dark":"36px","native":36}}, + {"path":"spacing.layoutBase500","source":"--gnrc-spacing-layout-base-500","adaptation":"CSS px are density-independent pixels.","cool":{"light":"40px","dark":"40px","native":40},"warm":{"light":"40px","dark":"40px","native":40}}, + {"path":"spacing.layoutBase600","source":"--gnrc-spacing-layout-base-600","adaptation":"CSS px are density-independent pixels.","cool":{"light":"48px","dark":"48px","native":48},"warm":{"light":"48px","dark":"48px","native":48}}, + {"path":"spacing.layoutBase700","source":"--gnrc-spacing-layout-base-700","adaptation":"CSS px are density-independent pixels.","cool":{"light":"56px","dark":"56px","native":56},"warm":{"light":"56px","dark":"56px","native":56}}, + {"path":"spacing.layoutBase800","source":"--gnrc-spacing-layout-base-800","adaptation":"CSS px are density-independent pixels.","cool":{"light":"64px","dark":"64px","native":64},"warm":{"light":"64px","dark":"64px","native":64}}, + {"path":"spacing.layoutBase1000","source":"--gnrc-spacing-layout-base-1000","adaptation":"CSS px are density-independent pixels.","cool":{"light":"80px","dark":"80px","native":80},"warm":{"light":"80px","dark":"80px","native":80}}, + {"path":"spacing.layoutBase1200","source":"--gnrc-spacing-layout-base-1200","adaptation":"CSS px are density-independent pixels.","cool":{"light":"96px","dark":"96px","native":96},"warm":{"light":"96px","dark":"96px","native":96}}, + {"path":"strokeWidth.thin","source":"--gnrc-stroke-width-thin","adaptation":"CSS px are density-independent pixels.","cool":{"light":"1px","dark":"1px","native":1},"warm":{"light":"1px","dark":"1px","native":1}}, + {"path":"strokeWidth.thick","source":"--gnrc-stroke-width-thick","adaptation":"CSS px are density-independent pixels.","cool":{"light":"2px","dark":"2px","native":2},"warm":{"light":"2px","dark":"2px","native":2}}, + {"path":"strokeWidth.thicker","source":"--gnrc-stroke-width-thicker","adaptation":"CSS px are density-independent pixels.","cool":{"light":"3px","dark":"3px","native":3},"warm":{"light":"3px","dark":"3px","native":3}}, + {"path":"strokeWidth.thickest","source":"--gnrc-stroke-width-thickest","adaptation":"CSS px are density-independent pixels.","cool":{"light":"4px","dark":"4px","native":4},"warm":{"light":"4px","dark":"4px","native":4}}, + {"path":"motion.durationBase50","source":"--gnrc-motion-duration-base-50","adaptation":"Durations are milliseconds.","cool":{"light":"50ms","dark":"50ms","native":50},"warm":{"light":"50ms","dark":"50ms","native":50}}, + {"path":"motion.durationBase100","source":"--gnrc-motion-duration-base-100","adaptation":"Durations are milliseconds.","cool":{"light":"100ms","dark":"100ms","native":100},"warm":{"light":"100ms","dark":"100ms","native":100}}, + {"path":"motion.durationBase200","source":"--gnrc-motion-duration-base-200","adaptation":"Durations are milliseconds.","cool":{"light":"200ms","dark":"200ms","native":200},"warm":{"light":"200ms","dark":"200ms","native":200}}, + {"path":"motion.durationBase300","source":"--gnrc-motion-duration-base-300","adaptation":"Durations are milliseconds.","cool":{"light":"300ms","dark":"300ms","native":300},"warm":{"light":"300ms","dark":"300ms","native":300}}, + {"path":"motion.durationBase500","source":"--gnrc-motion-duration-base-500","adaptation":"Durations are milliseconds.","cool":{"light":"500ms","dark":"500ms","native":500},"warm":{"light":"500ms","dark":"500ms","native":500}}, + {"path":"motion.durationBase1000","source":"--gnrc-motion-duration-base-1000","adaptation":"Durations are milliseconds.","cool":{"light":"1000ms","dark":"1000ms","native":1000},"warm":{"light":"1000ms","dark":"1000ms","native":1000}}, + {"path":"motion.easingFunctionalEnter","source":"--gnrc-motion-easing-functional-enter","adaptation":"cubic-bezier() becomes [x1, y1, x2, y2].","cool":{"light":"cubic-bezier(0, 0, 0, 1)","dark":"cubic-bezier(0, 0, 0, 1)","native":[0,0,0,1]},"warm":{"light":"cubic-bezier(0, 0, 0, 1)","dark":"cubic-bezier(0, 0, 0, 1)","native":[0,0,0,1]}}, + {"path":"motion.easingFunctionalExit","source":"--gnrc-motion-easing-functional-exit","adaptation":"cubic-bezier() becomes [x1, y1, x2, y2].","cool":{"light":"cubic-bezier(0.6, 0, 0.75, 0.4)","dark":"cubic-bezier(0.6, 0, 0.75, 0.4)","native":[0.6,0,0.75,0.4]},"warm":{"light":"cubic-bezier(0.6, 0, 0.75, 0.4)","dark":"cubic-bezier(0.6, 0, 0.75, 0.4)","native":[0.6,0,0.75,0.4]}}, + {"path":"motion.easingFunctionalTransition","source":"--gnrc-motion-easing-functional-transition","adaptation":"cubic-bezier() becomes [x1, y1, x2, y2].","cool":{"light":"cubic-bezier(0.33, 0, 0, 1)","dark":"cubic-bezier(0.33, 0, 0, 1)","native":[0.33,0,0,1]},"warm":{"light":"cubic-bezier(0.33, 0, 0, 1)","dark":"cubic-bezier(0.33, 0, 0, 1)","native":[0.33,0,0,1]}}, + {"path":"motion.easingFunctionalLinear","source":"--gnrc-motion-easing-functional-linear","adaptation":"cubic-bezier() becomes [x1, y1, x2, y2].","cool":{"light":"cubic-bezier(0, 0, 1, 1)","dark":"cubic-bezier(0, 0, 1, 1)","native":[0,0,1,1]},"warm":{"light":"cubic-bezier(0, 0, 1, 1)","dark":"cubic-bezier(0, 0, 1, 1)","native":[0,0,1,1]}}, + {"path":"motion.easingExpressiveEnter","source":"--gnrc-motion-easing-expressive-enter","adaptation":"cubic-bezier() becomes [x1, y1, x2, y2].","cool":{"light":"cubic-bezier(0, 0, 0, 1)","dark":"cubic-bezier(0, 0, 0, 1)","native":[0,0,0,1]},"warm":{"light":"cubic-bezier(0, 0, 0, 1)","dark":"cubic-bezier(0, 0, 0, 1)","native":[0,0,0,1]}}, + {"path":"motion.easingExpressiveExit","source":"--gnrc-motion-easing-expressive-exit","adaptation":"cubic-bezier() becomes [x1, y1, x2, y2].","cool":{"light":"cubic-bezier(0.6, 0, 0.75, 0.4)","dark":"cubic-bezier(0.6, 0, 0.75, 0.4)","native":[0.6,0,0.75,0.4]},"warm":{"light":"cubic-bezier(0.6, 0, 0.75, 0.4)","dark":"cubic-bezier(0.6, 0, 0.75, 0.4)","native":[0.6,0,0.75,0.4]}}, + {"path":"motion.easingExpressiveTransition","source":"--gnrc-motion-easing-expressive-transition","adaptation":"cubic-bezier() becomes [x1, y1, x2, y2].","cool":{"light":"cubic-bezier(0.33, 0, 0, 1)","dark":"cubic-bezier(0.33, 0, 0, 1)","native":[0.33,0,0,1]},"warm":{"light":"cubic-bezier(0.33, 0, 0, 1)","dark":"cubic-bezier(0.33, 0, 0, 1)","native":[0.33,0,0,1]}}, + {"path":"letterSpacing.functionalDisplay","source":"--gnrc-letter-spacing-functional-display","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0075em","dark":"-0.0075em"},"warm":{"light":"-0.0075em","dark":"-0.0075em"}}, + {"path":"letterSpacing.functionalPagetitle","source":"--gnrc-letter-spacing-functional-pagetitle","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0075em","dark":"-0.0075em"},"warm":{"light":"-0.0075em","dark":"-0.0075em"}}, + {"path":"letterSpacing.functionalTitleLarge","source":"--gnrc-letter-spacing-functional-title-large","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.functionalTitleMedium","source":"--gnrc-letter-spacing-functional-title-medium","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.functionalTitleSmall","source":"--gnrc-letter-spacing-functional-title-small","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.functionalSubtitle","source":"--gnrc-letter-spacing-functional-subtitle","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.functionalBodyLarge","source":"--gnrc-letter-spacing-functional-body-large","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}}, + {"path":"letterSpacing.functionalBodyMedium","source":"--gnrc-letter-spacing-functional-body-medium","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}}, + {"path":"letterSpacing.functionalBodySmall","source":"--gnrc-letter-spacing-functional-body-small","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}}, + {"path":"letterSpacing.functionalCaption","source":"--gnrc-letter-spacing-functional-caption","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}}, + {"path":"letterSpacing.contentStatement","source":"--gnrc-letter-spacing-content-statement","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0075em","dark":"-0.0075em"},"warm":{"light":"-0.0075em","dark":"-0.0075em"}}, + {"path":"letterSpacing.contentExpressiveLarge","source":"--gnrc-letter-spacing-content-expressive-large","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0075em","dark":"-0.0075em"},"warm":{"light":"-0.0075em","dark":"-0.0075em"}}, + {"path":"letterSpacing.contentExpressiveMedium","source":"--gnrc-letter-spacing-content-expressive-medium","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.contentExpressiveSmall","source":"--gnrc-letter-spacing-content-expressive-small","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.contentH1","source":"--gnrc-letter-spacing-content-h1","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.contentH2","source":"--gnrc-letter-spacing-content-h2","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.contentH3","source":"--gnrc-letter-spacing-content-h3","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.contentH4","source":"--gnrc-letter-spacing-content-h4","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.contentH5","source":"--gnrc-letter-spacing-content-h5","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"-0.0015em","dark":"-0.0015em"},"warm":{"light":"-0.0015em","dark":"-0.0015em"}}, + {"path":"letterSpacing.contentSubheadline","source":"--gnrc-letter-spacing-content-subheadline","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}}, + {"path":"letterSpacing.contentParagraphLarge","source":"--gnrc-letter-spacing-content-paragraph-large","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}}, + {"path":"letterSpacing.contentParagraphMedium","source":"--gnrc-letter-spacing-content-paragraph-medium","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}}, + {"path":"letterSpacing.contentParagraphSmall","source":"--gnrc-letter-spacing-content-paragraph-small","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}}, + {"path":"letterSpacing.contentSubtext","source":"--gnrc-letter-spacing-content-subtext","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}}, + {"path":"letterSpacing.contentTable","source":"--gnrc-letter-spacing-content-table","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}}, + {"path":"letterSpacing.contentCode","source":"--gnrc-letter-spacing-content-code","status":"unsupported","reason":"The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.","cool":{"light":"0em","dark":"0em"},"warm":{"light":"0em","dark":"0em"}} + ] +} diff --git a/packages/agentic/design/scripts/flex-defaults/generate-defaults.mjs b/packages/agentic/design/scripts/flex-defaults/generate-defaults.mjs new file mode 100644 index 0000000000..ef2f60fd7a --- /dev/null +++ b/packages/agentic/design/scripts/flex-defaults/generate-defaults.mjs @@ -0,0 +1,749 @@ +// Generates the x3 Flex token defaults and their coverage ledger from the pinned x3 snapshots. +// +// node ./scripts/flex-defaults/generate-defaults.mjs write the outputs +// node ./scripts/flex-defaults/generate-defaults.mjs --check exit 1 when an output is stale +// +// Each supported Flex destination reads the generic custom property declared in flex-token-map.yaml. +// Interaction states are omitted wherever the runtime interaction policy reproduces the source value, +// so the generator imports that policy's TypeScript sources and requires Node TypeScript type stripping. +import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import * as nodeModule from 'node:module'; +import path from 'node:path'; +import { fileURLToPath, pathToFileURL } from 'node:url'; + +const scriptDir = path.dirname(fileURLToPath(import.meta.url)); +const packageRoot = path.resolve(scriptDir, '../..'); +const outputPaths = { + defaults: path.join(packageRoot, 'src/flex/defaults/defaultTokens.generated.ts'), + ledger: path.join(scriptDir, 'coverage.generated.json'), +}; +const pinPath = path.join(packageRoot, 'src/tokens/mappings/upstream-pin.json'); +const globalTokensPath = path.join(packageRoot, 'src/tokens/global.generated.ts'); +const mappingPath = 'src/tokens/mappings/flex-token-map.yaml'; +const generatorPath = 'scripts/flex-defaults/generate-defaults.mjs'; +const printWidth = 140; + +if (typeof nodeModule.registerHooks !== 'function' || !process.features.typescript) { + throw new Error(`${generatorPath} requires Node 22.18 or later with TypeScript type stripping; found ${process.version}.`); +} + +const scriptExtension = /\.[cm]?[jt]sx?$/; +// Package sources use extensionless relative imports, which Node ESM does not resolve. +nodeModule.registerHooks({ + resolve(specifier, context, nextResolve) { + if ( + (specifier.startsWith('./') || specifier.startsWith('../')) && + !scriptExtension.test(specifier) && + context.parentURL?.endsWith('.ts') + ) { + const candidate = new URL(`${specifier}.ts`, context.parentURL); + if (existsSync(fileURLToPath(candidate))) { + return nextResolve(candidate.href, context); + } + } + return nextResolve(specifier, context); + }, +}); + +const require = nodeModule.createRequire(import.meta.url); +const { createMappingProjections, loadMappingInputs } = require('../token-mappings/check-mappings.cjs'); +const { getInteractionColor } = await import(pathToFileURL(path.join(packageRoot, 'src/color-lib/interaction.ts')).href); +const { getInteractionCompositing, getInteractionDirection, isInteractiveColorToken } = await import( + pathToFileURL(path.join(packageRoot, 'src/flex/colors/interactiveTokens.ts')).href +); + +const tones = [ + { name: 'cool', exportName: 'coolFlexTokenInput', semantic: 'semanticCss', fallback: 'interactionFallbackCss' }, + { name: 'warm', exportName: 'warmFlexTokenInput', semantic: 'warmSemanticCss', fallback: 'warmInteractionFallbackCss' }, +]; +const schemes = ['light', 'dark']; +const interactionStates = ['hover', 'pressed']; + +// CSS parsing. Every scan is linear; no regular expression runs over source text. + +function stripComments(text) { + let result = ''; + let index = 0; + while (index < text.length) { + const start = text.indexOf('/*', index); + if (start === -1) { + return result + text.slice(index); + } + const end = text.indexOf('*/', start + 2); + if (end === -1) { + throw new Error('Unterminated CSS comment.'); + } + result += text.slice(index, start); + index = end + 2; + } + return result; +} + +function parseRules(text) { + const rules = []; + let depth = 0; + let selectorStart = 0; + let bodyStart = 0; + let selector = ''; + for (let index = 0; index < text.length; index++) { + const character = text[index]; + if (character === '{') { + if (depth === 0) { + selector = text.slice(selectorStart, index).trim(); + bodyStart = index + 1; + } + depth++; + } else if (character === '}') { + depth--; + if (depth < 0) { + throw new Error('Unbalanced CSS braces.'); + } + if (depth === 0) { + rules.push({ selector, body: text.slice(bodyStart, index) }); + selectorStart = index + 1; + } + } + } + if (depth !== 0 || text.slice(selectorStart).trim() !== '') { + throw new Error('Unbalanced CSS braces.'); + } + return rules; +} + +function parseDeclarations(body) { + const declarations = new Map(); + for (const part of body.split(';')) { + const text = part.trim(); + if (text === '') { + continue; + } + const colon = text.indexOf(':'); + if (colon === -1) { + throw new Error(`Malformed CSS declaration: ${text}`); + } + const name = text.slice(0, colon).trim(); + if (name.startsWith('--')) { + declarations.set(name, text.slice(colon + 1).trim()); + } + } + return declarations; +} + +function findClosingParenthesis(text, from) { + let depth = 1; + for (let index = from; index < text.length; index++) { + if (text[index] === '(') { + depth++; + } else if (text[index] === ')') { + depth--; + if (depth === 0) { + return index; + } + } + } + throw new Error(`Unbalanced parentheses in CSS value: ${text}`); +} + +function splitTopLevel(text, separator) { + const parts = []; + let depth = 0; + let start = 0; + for (let index = 0; index < text.length; index++) { + const character = text[index]; + if (character === '(') { + depth++; + } else if (character === ')') { + depth--; + } else if (character === separator && depth === 0) { + parts.push(text.slice(start, index).trim()); + start = index + 1; + } + } + parts.push(text.slice(start).trim()); + return parts; +} + +function selectScheme(value, scheme) { + const marker = 'light-dark('; + let result = ''; + let index = 0; + for (;;) { + const start = value.indexOf(marker, index); + if (start === -1) { + return result + value.slice(index); + } + const argumentsStart = start + marker.length; + const end = findClosingParenthesis(value, argumentsStart); + const choices = splitTopLevel(value.slice(argumentsStart, end), ','); + if (choices.length !== 2) { + throw new Error(`light-dark() needs two values: ${value}`); + } + result += value.slice(index, start) + selectScheme(choices[scheme === 'dark' ? 1 : 0], scheme); + index = end + 1; + } +} + +function sameDeclarations(left, right) { + return left.size === right.size && [...left].every(([name, value]) => right.get(name) === value); +} + +const mediaDarkSelector = '@media (prefers-color-scheme: dark)'; +const knownSelectors = new Set([':root', '[data-theme="light"]', '[data-theme="dark"]', mediaDarkSelector]); + +/** Read one adaptive sheet as resolved light and dark declarations. */ +function readAdaptiveSheet(filePath) { + const blocks = new Map(); + for (const { selector, body } of parseRules(stripComments(readFileSync(filePath, 'utf8')))) { + if (!knownSelectors.has(selector) || blocks.has(selector)) { + throw new Error(`Unexpected CSS rule "${selector}" in ${filePath}.`); + } + blocks.set(selector, body); + } + if (!blocks.has(':root')) { + throw new Error(`Missing :root rule in ${filePath}.`); + } + + const root = parseDeclarations(blocks.get(':root')); + const overrides = { + light: parseDeclarations(blocks.get('[data-theme="light"]') ?? ''), + dark: parseDeclarations(blocks.get('[data-theme="dark"]') ?? ''), + }; + if (blocks.has(mediaDarkSelector)) { + const media = parseRules(blocks.get(mediaDarkSelector)); + if (media.length !== 1 || media[0].selector !== ':root' || !sameDeclarations(parseDeclarations(media[0].body), overrides.dark)) { + throw new Error(`The prefers-color-scheme dark rule in ${filePath} must equal its [data-theme="dark"] rule.`); + } + } + + const sheet = {}; + for (const scheme of schemes) { + const declarations = new Map(); + for (const [name, value] of new Map([...root, ...overrides[scheme]])) { + declarations.set(name, selectScheme(value, scheme)); + } + sheet[scheme] = declarations; + } + return sheet; +} + +// Value conversion. + +const hexColorPattern = /^#(?:[0-9a-f]{6}|[0-9a-f]{8})$/; + +function parseHexColor(value, source) { + if (!hexColorPattern.test(value)) { + throw new Error(`${source} must be a lowercase #rrggbb or #rrggbbaa color; found "${value}".`); + } + return value; +} + +function normalizeHex(value) { + const lower = String(value).toLowerCase(); + return lower.length === 9 && lower.endsWith('ff') ? lower.slice(0, 7) : lower; +} + +function parseNumber(text, source) { + const value = Number(text); + if (text.trim() === '' || !Number.isFinite(value)) { + throw new Error(`${source} has a non-numeric value "${text}".`); + } + return value; +} + +function parseUnit(value, unit, source) { + if (!value.endsWith(unit)) { + throw new Error(`${source} must use ${unit}; found "${value}".`); + } + return parseNumber(value.slice(0, -unit.length), source); +} + +function parsePixels(value, source) { + return value.endsWith('rem') ? parseUnit(value, 'rem', source) * 16 : parseUnit(value, 'px', source); +} + +function parseFunction(value, name, source) { + const prefix = `${name}(`; + if (!value.startsWith(prefix) || !value.endsWith(')')) { + throw new Error(`${source} must be ${name}(); found "${value}".`); + } + return splitTopLevel(value.slice(prefix.length, -1), ','); +} + +function parseShadowColor(value, declarations, source) { + const prefix = 'oklch(from var('; + if (!value.startsWith(prefix)) { + return parseHexColor(value, source); + } + if (!value.endsWith(')')) { + throw new Error(`${source} has an unsupported shadow color "${value}".`); + } + const inner = value.slice(prefix.length, -1); + const close = inner.indexOf(')'); + const channels = inner.slice(close + 1).trim(); + const channelPrefix = 'l c h / '; + if (close === -1 || !channels.startsWith(channelPrefix) || !channels.endsWith('%')) { + throw new Error(`${source} may only change the alpha of a relative shadow color; found "${value}".`); + } + const baseName = inner.slice(0, close); + const base = normalizeHex(parseHexColor(declarations.get(baseName) ?? '', `${source} base ${baseName}`)); + if (base.length !== 7) { + throw new Error(`${source} base ${baseName} must be opaque.`); + } + const alpha = Math.round((parseNumber(channels.slice(channelPrefix.length, -1), source) * 255) / 100); + return `${base}${alpha.toString(16).padStart(2, '0')}`; +} + +function parseShadow(value, declarations, source) { + return splitTopLevel(value, ',').map((layer) => { + const lengths = []; + let index = 0; + while (lengths.length < 3) { + const end = layer.indexOf(' ', index); + if (end === -1) { + throw new Error(`${source} shadow layers need x, y, blur, and color; found "${layer}".`); + } + lengths.push(parsePixels(layer.slice(index, end), source)); + index = end + 1; + } + const [x, y, blur] = lengths; + return { x, y, blur, color: parseShadowColor(layer.slice(index).trim(), declarations, source) }; + }); +} + +/** An identifier emitted as code rather than as a literal. */ +class Raw { + constructor(code) { + this.code = code; + } +} + +function readFontWeights() { + const prefix = 'export const '; + const weights = new Map(); + for (const line of readFileSync(globalTokensPath, 'utf8').split('\n')) { + if (line.startsWith(`${prefix}fontWeight`)) { + const [name, value] = line.slice(prefix.length).split(' = '); + weights.set(name, value.trim().slice(1, -2)); + } + } + return weights; +} + +const nativeFontWeights = readFontWeights(); +const fontWeightRoles = [ + ['Semibold', 600, 'fontWeightSemibold'], + ['Regular', 420, 'fontWeightRegular'], + ['Medium', 550, 'fontWeightMedium'], + ['Bold', 625, 'fontWeightBold'], +]; +const fontFamilies = new Map([ + ['sans-serif', ['fontFamilyBase', 'The x3 sans-serif stack uses the native platform base family.']], + ['serif', ['fontFamilyBase', 'The x3 serif stack has no portable native serif family, so it uses the platform base family.']], + ['monospace', ['fontFamilyMonospace', 'The x3 monospace stack uses the native platform monospace family.']], +]); + +/** + * Convert one non-color source value. Returns the native value, an optional + * representation for values emitted as identifiers, and the ledger adaptation. + */ +function convertValue(group, token, value, context) { + const source = `${group}.${token}`; + switch (group) { + case 'shadow': + return { + value: parseShadow(value, context.declarations, source), + adaptation: 'Relative oklch alpha resolves to #rrggbbaa; every layer is preserved.', + }; + case 'fontWeight': { + const role = fontWeightRoles.find(([suffix]) => token.endsWith(suffix)); + if (!role) { + throw new Error(`${source} has no native font weight role.`); + } + const [roleName, sourceWeight, identifier] = role; + if (parseNumber(value, source) !== sourceWeight) { + throw new Error(`${source} changed from ${sourceWeight} to ${value}; review its native weight role.`); + } + return { + value: new Raw(identifier), + representation: `${identifier} ('${nativeFontWeights.get(identifier)}')`, + adaptation: `The x3 variable weight ${value} uses the native static ${roleName.toLowerCase()} weight.`, + }; + } + case 'fontFamily': { + const families = splitTopLevel(value, ','); + const family = fontFamilies.get(families[families.length - 1]); + if (!family) { + throw new Error(`${source} has an unsupported generic family in "${value}".`); + } + return { value: new Raw(family[0]), representation: family[0], adaptation: family[1] }; + } + case 'fontSize': + return { + value: parsePixels(value, source), + adaptation: value.endsWith('rem') ? '1rem is 16 density-independent pixels.' : 'CSS px are density-independent pixels.', + }; + case 'lineHeight': { + const [percentage, step] = parseFunction(value, 'round', source); + const fontSize = context.fontSize(token); + const stepSize = parsePixels(step, source); + return { + value: Math.round((fontSize * parseUnit(percentage, '%', source)) / (100 * stepSize)) * stepSize, + adaptation: `Resolved against fontSize.${token} (${fontSize}).`, + }; + } + case 'borderRadius': + case 'spacing': + case 'strokeWidth': + return { value: parsePixels(value, source), adaptation: 'CSS px are density-independent pixels.' }; + case 'motion': + if (token.startsWith('duration')) { + return { + value: value.endsWith('ms') ? parseUnit(value, 'ms', source) : parseUnit(value, 's', source) * 1000, + adaptation: 'Durations are milliseconds.', + }; + } + return { + value: parseFunction(value, 'cubic-bezier', source).map((part) => parseNumber(part, source)), + adaptation: 'cubic-bezier() becomes [x1, y1, x2, y2].', + }; + default: + throw new Error(`No conversion is defined for ${source}.`); + } +} + +// Resolution. + +function sameValue(left, right) { + return JSON.stringify(left) === JSON.stringify(right); +} + +function schemeEntry(light, dark) { + return sameValue(light, dark) ? light : [light, dark]; +} + +function readSource(sheet, scheme, name, source) { + const value = sheet[scheme].get(name); + if (value === undefined) { + throw new Error(`${source} reads ${name}, which the ${scheme} source does not declare.`); + } + return value; +} + +function deriveState(rest, token, state, scheme, tone) { + const result = getInteractionColor(rest, scheme, state, { + colorTone: tone, + direction: getInteractionDirection(token), + compositing: getInteractionCompositing(token), + }); + return result.status === 'derived' ? result.value : rest; +} + +function getGeneric(mappingEntries, tokenPath) { + const source = mappingEntries.get(tokenPath)?.genericSource; + if (source === undefined) { + throw new Error(`${tokenPath} has no generic source in ${mappingPath}.`); + } + return source; +} + +function resolveColor(token, context) { + const { fallback, ledger, mappingEntries, semantic, tone } = context; + const tokenPath = `color.${token}.rest`; + const record = ledger.entry(tokenPath); + const source = getGeneric(mappingEntries, tokenPath); + const rest = {}; + for (const scheme of schemes) { + rest[scheme] = normalizeHex(parseHexColor(readSource(semantic, scheme, source, tokenPath), tokenPath)); + } + record.source = source; + record[tone.name] = { light: rest.light, dark: rest.dark }; + const restEntry = schemeEntry(rest.light, rest.dark); + + if (!isInteractiveColorToken(token)) { + for (const state of interactionStates) { + const statePath = `color.${token}.${state}`; + if (mappingEntries.has(statePath)) { + throw new Error(`${statePath} is mapped, but ${token} is not interactive.`); + } + Object.assign(ledger.entry(statePath), { state: 'rest', reason: 'non-interactive' }); + } + return restEntry; + } + + const type = getInteractionDirection(token); + record.type = type; + const description = { rest: restEntry }; + for (const state of interactionStates) { + const statePath = `color.${token}.${state}`; + const stateSource = getGeneric(mappingEntries, statePath); + const values = {}; + let explicit = false; + for (const scheme of schemes) { + values[scheme] = normalizeHex(parseHexColor(readSource(fallback, scheme, stateSource, statePath), statePath)); + if (normalizeHex(deriveState(rest[scheme], token, state, scheme, tone.name)) !== values[scheme]) { + explicit = true; + } + } + const stateRecord = ledger.entry(statePath); + stateRecord.source = stateSource; + stateRecord[tone.name] = { light: values.light, dark: values.dark, state: explicit ? 'explicit' : 'computed' }; + if (explicit) { + description[state] = schemeEntry(values.light, values.dark); + } + } + if (type !== 'standard') { + description.type = type; + } + return Object.keys(description).length === 1 ? restEntry : description; +} + +function resolveTone(tone, inputs, mappingEntries, ledger) { + const semantic = readAdaptiveSheet(path.join(packageRoot, inputs.pin.get(tone.semantic).snapshotPath)); + const fallback = readAdaptiveSheet(path.join(packageRoot, inputs.pin.get(tone.fallback).snapshotPath)); + const tokens = { color: {} }; + const fontSize = (scheme) => (token) => { + const tokenPath = `fontSize.${token}`; + return convertValue('fontSize', token, readSource(semantic, scheme, getGeneric(mappingEntries, tokenPath), tokenPath)).value; + }; + + for (const tokenPath of inputs.supportedTypePaths) { + const [group, token, state] = tokenPath.split('.'); + if (group === 'color') { + if (state === 'rest') { + tokens.color[token] = resolveColor(token, { fallback, ledger, mappingEntries, semantic, tone }); + } + continue; + } + + const source = getGeneric(mappingEntries, tokenPath); + const sourceValues = {}; + const converted = {}; + for (const scheme of schemes) { + sourceValues[scheme] = readSource(semantic, scheme, source, tokenPath); + converted[scheme] = convertValue(group, token, sourceValues[scheme], { declarations: semantic[scheme], fontSize: fontSize(scheme) }); + } + if (group !== 'shadow' && !sameValue(converted.light.value, converted.dark.value)) { + throw new Error(`${tokenPath} varies by scheme; only colors and shadows may.`); + } + const value = schemeEntry(converted.light.value, converted.dark.value); + const record = ledger.entry(tokenPath); + record.source = source; + record[tone.name] = { light: sourceValues.light, dark: sourceValues.dark, native: converted.light.representation ?? value }; + record.adaptation = converted.light.adaptation; + (tokens[group] ??= {})[token] = value; + } + + for (const tokenPath of inputs.unsupportedTypePaths) { + const source = getGeneric(mappingEntries, tokenPath); + const record = ledger.entry(tokenPath); + Object.assign(record, { + source, + status: 'unsupported', + reason: 'The source is em-relative; React Native letterSpacing takes absolute points, so UnsupportedFlexTokens excludes it.', + }); + record[tone.name] = { light: readSource(semantic, 'light', source, tokenPath), dark: readSource(semantic, 'dark', source, tokenPath) }; + } + + return tokens; +} + +// Emission. + +const identifierPattern = /^[A-Za-z_$][\w$]*$/; + +function quote(value) { + return `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'")}'`; +} + +function propertyKey(key) { + return identifierPattern.test(key) ? key : quote(key); +} + +function isComposite(value) { + return typeof value === 'object' && value !== null && !(value instanceof Raw); +} + +function inline(value) { + if (value instanceof Raw) { + return value.code; + } + if (typeof value === 'string') { + return quote(value); + } + if (typeof value === 'number') { + return String(value); + } + if (Array.isArray(value)) { + return `[${value.map(inline).join(', ')}]`; + } + const entries = Object.entries(value); + return entries.length === 0 ? '{}' : `{ ${entries.map(([key, item]) => `${propertyKey(key)}: ${inline(item)}`).join(', ')} }`; +} + +/** + * Format a value starting at `column`. The outermost `forcedDepth` composite + * levels are always multiline; deeper values are inline when they fit. + */ +function format(value, depth, column, forcedDepth = 0) { + const single = inline(value); + if (!isComposite(value) || (forcedDepth <= 0 && column + single.length + 1 <= printWidth)) { + return single; + } + const indent = ' '.repeat(depth + 1); + const lines = Array.isArray(value) + ? value.map((item) => `${indent}${format(item, depth + 1, indent.length, forcedDepth - 1)},`) + : Object.entries(value).map(([key, item]) => { + const prefix = `${indent}${propertyKey(key)}: `; + return `${prefix}${format(item, depth + 1, prefix.length, forcedDepth - 1)},`; + }); + const [open, close] = Array.isArray(value) ? ['[', ']'] : ['{', '}']; + return `${open}\n${lines.join('\n')}\n${' '.repeat(depth)}${close}`; +} + +function collectRawIdentifiers(value, identifiers) { + if (value instanceof Raw) { + identifiers.add(value.code); + } else if (isComposite(value)) { + for (const item of Object.values(value)) { + collectRawIdentifiers(item, identifiers); + } + } +} + +function formatImport(names, from) { + const single = `import { ${names.join(', ')} } from '${from}';`; + return single.length <= printWidth ? [single] : ['import {', ...names.map((name) => ` ${name},`), `} from '${from}';`]; +} + +function emitDefaults(pin, files, toneTokens) { + const groupNames = Object.keys(toneTokens[0].tokens).filter((group) => group !== 'color'); + const shared = {}; + for (const group of groupNames) { + if (toneTokens.every(({ tokens }) => sameValue(tokens[group], toneTokens[0].tokens[group]))) { + shared[group] = toneTokens[0].tokens[group]; + } + } + const identifiers = new Set(); + collectRawIdentifiers( + toneTokens.map(({ tokens }) => tokens), + identifiers, + ); + + const lines = [ + `// Generated by ${generatorPath}. Do not edit; run \`yarn gen:flex-defaults\`.`, + `// Source: ${pin.repository}@${pin.commit}`, + ...tones.map((tone) => `// ${tone.name}: ${files[tone.name].join(', ')}`), + `// Generic sources: ${mappingPath}`, + `// Coverage: ${path.relative(packageRoot, outputPaths.ledger).replaceAll('\\', '/')}`, + '', + ...formatImport([...identifiers].sort(), '../../tokens/global.generated'), + "import type { CompleteFlexTokenInput } from '../tokens.types';", + '', + `const sharedTokens = ${format(shared, 0, 0, 2)} satisfies Partial>;`, + ]; + + for (const { tone, tokens } of toneTokens) { + const own = { color: tokens.color }; + for (const group of groupNames) { + if (!Object.hasOwn(shared, group)) { + own[group] = tokens[group]; + } + } + const [open, ...body] = format(own, 0, 0, 2).split('\n'); + body[body.length - 1] += ';'; + lines.push( + '', + `/** The x3 ${tone.name}-tone defaults. Omitted interaction states are computed from rest. */`, + `export const ${tone.exportName}: CompleteFlexTokenInput = ${open}`, + ' ...sharedTokens,', + ...body, + ); + } + return `${lines.join('\n')}\n`; +} + +function createLedger(supportedTypePaths, unsupportedTypePaths) { + const entries = new Map(); + for (const tokenPath of [...supportedTypePaths, ...unsupportedTypePaths]) { + entries.set(tokenPath, { path: tokenPath }); + } + return { + entries, + entry(tokenPath) { + const entry = entries.get(tokenPath); + if (!entry) { + throw new Error(`${tokenPath} is not a declared Flex destination.`); + } + return entry; + }, + }; +} + +const ledgerKeys = ['path', 'source', 'status', 'type', 'state', 'reason', 'adaptation', ...tones.map((tone) => tone.name)]; + +function emitLedger(pin, files, ledger) { + const header = { + generator: generatorPath, + source: { repository: pin.repository, commit: pin.commit, files }, + mapping: mappingPath, + notes: [ + 'Each tone records the light and dark source values after resolving light-dark() and [data-theme] overrides.', + 'computed: the runtime interaction policy reproduces the source state from rest, so the default omits it. explicit: the default authors the source state.', + 'Computed states equal rest in high contrast; explicit states apply in every contrast.', + 'The x3 semantic sources define no native high-contrast or elevated values; those appearances reuse the light or dark defaults.', + 'native: the emitted value; adaptation: how the source value converts to it.', + 'Theme shadows project to legacy { ambient, key } pairs from the first and last layers; that projection is lossy.', + ], + }; + const headerText = JSON.stringify(header, null, 2); + const destinations = [...ledger.entries.values()].map((entry) => { + const unknown = Object.keys(entry).filter((key) => !ledgerKeys.includes(key)); + if (unknown.length > 0) { + throw new Error(`Unordered ledger fields: ${unknown.join(', ')}.`); + } + const ordered = Object.fromEntries(ledgerKeys.filter((key) => Object.hasOwn(entry, key)).map((key) => [key, entry[key]])); + return ` ${JSON.stringify(ordered)}`; + }); + return `${headerText.slice(0, -2)},\n "destinations": [\n${destinations.join(',\n')}\n ]\n}\n`; +} + +function generate() { + const inputs = loadMappingInputs(); + const pin = JSON.parse(readFileSync(pinPath, 'utf8')); + inputs.pin = new Map(pin.files.map((file) => [file.id, file])); + const { mappingEntries, violations } = createMappingProjections(inputs.mapping, inputs.supportedTypePaths); + if (violations.length > 0) { + throw new Error(`${mappingPath} is invalid; run yarn check:mappings.`); + } + + const ledger = createLedger(inputs.supportedTypePaths, inputs.unsupportedTypePaths); + const files = {}; + const toneTokens = tones.map((tone) => { + files[tone.name] = [tone.semantic, tone.fallback].map((id) => inputs.pin.get(id).upstreamPath); + return { tone, tokens: resolveTone(tone, inputs, mappingEntries, ledger) }; + }); + + return new Map([ + [outputPaths.defaults, emitDefaults(pin, files, toneTokens)], + [outputPaths.ledger, emitLedger(pin, files, ledger)], + ]); +} + +const check = process.argv.includes('--check'); +const stale = []; +for (const [filePath, contents] of generate()) { + if (existsSync(filePath) && readFileSync(filePath, 'utf8') === contents) { + continue; + } + stale.push(path.relative(packageRoot, filePath).replaceAll('\\', '/')); + if (!check) { + writeFileSync(filePath, contents); + } +} + +if (check && stale.length > 0) { + console.error(`Stale generated Flex defaults: ${stale.join(', ')}. Run yarn gen:flex-defaults.`); + process.exitCode = 1; +} else if (!check) { + console.log(stale.length > 0 ? `Updated ${stale.join(', ')}.` : 'Generated Flex defaults are current.'); +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/interaction-fallback-dark.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/interaction-fallback-dark.css new file mode 100644 index 0000000000..f4d6af7fdc --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/interaction-fallback-dark.css @@ -0,0 +1,130 @@ +/* Fluent Design — Interaction Fallback (Dark Theme) — precomputed hex and shadows for non-OKLCH environments + * Auto-generated by scripts/build.mjs — do not edit manually. + */ + +[data-theme="dark"] { + --gnrc-color-surface-neutral-farther-hover: #2f2f2f; + --gnrc-color-surface-neutral-farther-pressed: #454545; + --gnrc-color-surface-neutral-far-hover: #323232; + --gnrc-color-surface-neutral-far-pressed: #464646; + --gnrc-color-surface-neutral-near-hover: #2d2d2d; + --gnrc-color-surface-neutral-near-pressed: #434343; + --gnrc-color-surface-neutral-nearer-hover: #3a3a3a; + --gnrc-color-surface-neutral-nearer-pressed: #4b4b4b; + --gnrc-color-surface-neutral-translucent-hover: #47474788; + --gnrc-color-surface-neutral-translucent-pressed: #5353538f; + --gnrc-color-background-neutral-heavy-hover: #f5f5f5; + --gnrc-color-background-neutral-heavy-pressed: #ebebeb; + --gnrc-color-background-neutral-loud-hover: #898989; + --gnrc-color-background-neutral-loud-pressed: #808080; + --gnrc-color-background-neutral-soft-hover: #ffffff27; + --gnrc-color-background-neutral-soft-pressed: #ffffff2e; + --gnrc-color-background-neutral-subtle-hover: #ffffff1c; + --gnrc-color-background-neutral-subtle-pressed: #ffffff23; + --gnrc-color-background-neutral-transparent-hover: #ffffff08; + --gnrc-color-background-neutral-transparent-pressed: #ffffff0f; + --gnrc-color-background-neutral-translucent-hover: #56565688; + --gnrc-color-background-neutral-translucent-pressed: #6d6d6d8f; + --gnrc-color-background-brand-heavy-hover: #f5f5f5; + --gnrc-color-background-brand-heavy-pressed: #ebebeb; + --gnrc-color-background-brand-loud-hover: #898989; + --gnrc-color-background-brand-loud-pressed: #808080; + --gnrc-color-background-brand-soft-hover: #ffffff27; + --gnrc-color-background-brand-soft-pressed: #ffffff2e; + --gnrc-color-background-brand-subtle-hover: #ffffff1c; + --gnrc-color-background-brand-subtle-pressed: #ffffff23; + --gnrc-color-background-brand-transparent-hover: #ffffff08; + --gnrc-color-background-brand-transparent-pressed: #ffffff0f; + --gnrc-color-background-danger-loud-hover: #da5471; + --gnrc-color-background-danger-loud-pressed: #d04b69; + --gnrc-color-background-danger-soft-hover: #67353e; + --gnrc-color-background-danger-soft-pressed: #754149; + --gnrc-color-background-danger-subtle-hover: #503438; + --gnrc-color-background-danger-subtle-pressed: #614448; + --gnrc-color-background-warning-loud-hover: #da5d2e; + --gnrc-color-background-warning-loud-pressed: #d05422; + --gnrc-color-background-warning-soft-hover: #663828; + --gnrc-color-background-warning-soft-pressed: #744434; + --gnrc-color-background-warning-subtle-hover: #51352c; + --gnrc-color-background-warning-subtle-pressed: #62453b; + --gnrc-color-background-success-loud-hover: #00a369; + --gnrc-color-background-success-loud-pressed: #009a60; + --gnrc-color-background-success-soft-hover: #1c5238; + --gnrc-color-background-success-soft-pressed: #295f44; + --gnrc-color-background-success-subtle-hover: #294435; + --gnrc-color-background-success-subtle-pressed: #385445; + --gnrc-color-stroke-neutral-heavy-hover: #d4d4d4; + --gnrc-color-stroke-neutral-heavy-pressed: #cbcbcb; + --gnrc-color-stroke-neutral-loud-hover: #898989; + --gnrc-color-stroke-neutral-loud-pressed: #808080; + --gnrc-color-stroke-neutral-soft-hover: #ffffff69; + --gnrc-color-stroke-neutral-soft-pressed: #ffffff70; + --gnrc-color-stroke-neutral-subtle-hover: #ffffff50; + --gnrc-color-stroke-neutral-subtle-pressed: #ffffff57; + --gnrc-color-stroke-neutral-transparent-hover: #ffffff08; + --gnrc-color-stroke-neutral-transparent-pressed: #ffffff0f; + --gnrc-color-stroke-neutral-onloud-hover: #000000db; + --gnrc-color-stroke-neutral-onloud-pressed: #000000db; + --gnrc-color-stroke-brand-loud-hover: #898989; + --gnrc-color-stroke-brand-loud-pressed: #808080; + --gnrc-color-stroke-brand-soft-hover: #ffffff69; + --gnrc-color-stroke-brand-soft-pressed: #ffffff70; + --gnrc-color-stroke-brand-subtle-hover: #ffffff50; + --gnrc-color-stroke-brand-subtle-pressed: #ffffff57; + --gnrc-color-stroke-brand-onloud-hover: #131313; + --gnrc-color-stroke-brand-onloud-pressed: #050505; + --gnrc-color-stroke-danger-loud-hover: #da5471; + --gnrc-color-stroke-danger-loud-pressed: #d04b69; + --gnrc-color-stroke-danger-soft-hover: #dc4b6d; + --gnrc-color-stroke-danger-soft-pressed: #e65575; + --gnrc-color-stroke-danger-subtle-hover: #803242; + --gnrc-color-stroke-danger-subtle-pressed: #893a4a; + --gnrc-color-stroke-danger-onloud-hover: #131313; + --gnrc-color-stroke-danger-onloud-pressed: #050505; + --gnrc-color-stroke-warning-loud-hover: #da5d2e; + --gnrc-color-stroke-warning-loud-pressed: #d05422; + --gnrc-color-stroke-warning-soft-hover: #d8521a; + --gnrc-color-stroke-warning-soft-pressed: #e25c27; + --gnrc-color-stroke-warning-subtle-hover: #7f371b; + --gnrc-color-stroke-warning-subtle-pressed: #893f24; + --gnrc-color-stroke-warning-onloud-hover: #131313; + --gnrc-color-stroke-warning-onloud-pressed: #050505; + --gnrc-color-stroke-success-loud-hover: #00a369; + --gnrc-color-stroke-success-loud-pressed: #009a60; + --gnrc-color-stroke-success-soft-hover: #1a9765; + --gnrc-color-stroke-success-soft-pressed: #2aa16d; + --gnrc-color-stroke-success-subtle-hover: #125f3e; + --gnrc-color-stroke-success-subtle-pressed: #1e6746; + --gnrc-color-stroke-success-onloud-hover: #131313; + --gnrc-color-stroke-success-onloud-pressed: #050505; + --gnrc-color-foreground-neutral-primary-hover: #ffffffe6; + --gnrc-color-foreground-neutral-primary-pressed: #ffffffed; + --gnrc-color-foreground-neutral-secondary-hover: #ffffffa9; + --gnrc-color-foreground-neutral-secondary-pressed: #ffffffb0; + --gnrc-color-foreground-neutral-tertiary-hover: #ffffff88; + --gnrc-color-foreground-neutral-tertiary-pressed: #ffffff8f; + --gnrc-color-foreground-neutral-onloud-hover: #000000db; + --gnrc-color-foreground-neutral-onloud-pressed: #000000db; + --gnrc-color-foreground-brand-primary-hover: #e8e8e8; + --gnrc-color-foreground-brand-primary-pressed: #f2f2f2; + --gnrc-color-foreground-brand-onloud-hover: #000000db; + --gnrc-color-foreground-brand-onloud-pressed: #000000db; + --gnrc-color-foreground-danger-primary-hover: #ff97aa; + --gnrc-color-foreground-danger-primary-pressed: #ffa1b4; + --gnrc-color-foreground-danger-onloud-hover: #000000db; + --gnrc-color-foreground-danger-onloud-pressed: #000000db; + --gnrc-color-foreground-warning-primary-hover: #ff9f7a; + --gnrc-color-foreground-warning-primary-pressed: #ffa884; + --gnrc-color-foreground-warning-onloud-hover: #000000db; + --gnrc-color-foreground-warning-onloud-pressed: #000000db; + --gnrc-color-foreground-success-primary-hover: #67d8a0; + --gnrc-color-foreground-success-primary-pressed: #72e2aa; + --gnrc-color-foreground-success-onloud-hover: #000000db; + --gnrc-color-foreground-success-onloud-pressed: #000000db; + --gnrc-shadow-lowest: 0px 0px 2px #00000033, 0px 1px 2px #0000001a; + --gnrc-shadow-lower: 0px 0px 2px #00000033, 0px 2px 4px #00000029; + --gnrc-shadow-low: 0px 0px 2px #00000033, 0px 2px 4px #0000001f, 0px 4px 8px #00000029; + --gnrc-shadow-high: 0px 0px 2px #00000033, 0px 4px 8px #0000001f, 0px 8px 16px #0000001f; + --gnrc-shadow-higher: 0px 0px 2px #00000033, 0px 8px 16px #0000001f, 0px 16px 32px #0000001f; + --gnrc-shadow-highest: 0px 0px 2px #00000033, 0px 8px 16px #0000001f, 0px 32px 64px #0000001f; +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/interaction-fallback-light.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/interaction-fallback-light.css new file mode 100644 index 0000000000..87f488d731 --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/interaction-fallback-light.css @@ -0,0 +1,130 @@ +/* Fluent Design — Interaction Fallback (Light Theme) — precomputed hex and shadows for non-OKLCH environments + * Auto-generated by scripts/build.mjs — do not edit manually. + */ + +:root, [data-theme="light"] { + --gnrc-color-surface-neutral-farther-hover: #e1e1e1; + --gnrc-color-surface-neutral-farther-pressed: #d7d7d7; + --gnrc-color-surface-neutral-far-hover: #e8e8e8; + --gnrc-color-surface-neutral-far-pressed: #dedede; + --gnrc-color-surface-neutral-near-hover: #f2f2f2; + --gnrc-color-surface-neutral-near-pressed: #e8e8e8; + --gnrc-color-surface-neutral-nearer-hover: #f5f5f5; + --gnrc-color-surface-neutral-nearer-pressed: #ebebeb; + --gnrc-color-surface-neutral-translucent-hover: #f5f5f58a; + --gnrc-color-surface-neutral-translucent-pressed: #ebebeb94; + --gnrc-color-background-neutral-heavy-hover: #363636; + --gnrc-color-background-neutral-heavy-pressed: #494949; + --gnrc-color-background-neutral-loud-hover: #787878; + --gnrc-color-background-neutral-loud-pressed: #818181; + --gnrc-color-background-neutral-soft-hover: #0000001e; + --gnrc-color-background-neutral-soft-pressed: #00000028; + --gnrc-color-background-neutral-subtle-hover: #00000017; + --gnrc-color-background-neutral-subtle-pressed: #00000021; + --gnrc-color-background-neutral-transparent-hover: #1313130a; + --gnrc-color-background-neutral-transparent-pressed: #05050514; + --gnrc-color-background-neutral-translucent-hover: #d8d8d88a; + --gnrc-color-background-neutral-translucent-pressed: #cacaca94; + --gnrc-color-background-brand-heavy-hover: #363636; + --gnrc-color-background-brand-heavy-pressed: #494949; + --gnrc-color-background-brand-loud-hover: #787878; + --gnrc-color-background-brand-loud-pressed: #818181; + --gnrc-color-background-brand-soft-hover: #0000001e; + --gnrc-color-background-brand-soft-pressed: #00000028; + --gnrc-color-background-brand-subtle-hover: #00000014; + --gnrc-color-background-brand-subtle-pressed: #0000001e; + --gnrc-color-background-brand-transparent-hover: #1313130a; + --gnrc-color-background-brand-transparent-pressed: #05050514; + --gnrc-color-background-danger-loud-hover: #cb395e; + --gnrc-color-background-danger-loud-pressed: #d54467; + --gnrc-color-background-danger-soft-hover: #f5d9dc; + --gnrc-color-background-danger-soft-pressed: #ebcfd2; + --gnrc-color-background-danger-subtle-hover: #f5e7e9; + --gnrc-color-background-danger-subtle-pressed: #ebdddf; + --gnrc-color-background-warning-loud-hover: #c54a14; + --gnrc-color-background-warning-loud-pressed: #d05321; + --gnrc-color-background-warning-soft-hover: #f5dbd2; + --gnrc-color-background-warning-soft-pressed: #ebd1c9; + --gnrc-color-background-warning-subtle-hover: #f5e8e4; + --gnrc-color-background-warning-subtle-pressed: #ebdeda; + --gnrc-color-background-success-loud-hover: #188d5d; + --gnrc-color-background-success-loud-pressed: #279666; + --gnrc-color-background-success-soft-hover: #bfeed3; + --gnrc-color-background-success-soft-pressed: #b6e4ca; + --gnrc-color-background-success-subtle-hover: #d9f2e4; + --gnrc-color-background-success-subtle-pressed: #cfe8da; + --gnrc-color-stroke-neutral-heavy-hover: #363636; + --gnrc-color-stroke-neutral-heavy-pressed: #494949; + --gnrc-color-stroke-neutral-loud-hover: #787878; + --gnrc-color-stroke-neutral-loud-pressed: #818181; + --gnrc-color-stroke-neutral-soft-hover: #02020277; + --gnrc-color-stroke-neutral-soft-pressed: #04040481; + --gnrc-color-stroke-neutral-subtle-hover: #0000002b; + --gnrc-color-stroke-neutral-subtle-pressed: #05050535; + --gnrc-color-stroke-neutral-transparent-hover: #1313130a; + --gnrc-color-stroke-neutral-transparent-pressed: #05050514; + --gnrc-color-stroke-neutral-onloud-hover: #ffffff; + --gnrc-color-stroke-neutral-onloud-pressed: #ffffff; + --gnrc-color-stroke-brand-loud-hover: #787878; + --gnrc-color-stroke-brand-loud-pressed: #818181; + --gnrc-color-stroke-brand-soft-hover: #02020277; + --gnrc-color-stroke-brand-soft-pressed: #04040481; + --gnrc-color-stroke-brand-subtle-hover: #0000002b; + --gnrc-color-stroke-brand-subtle-pressed: #05050535; + --gnrc-color-stroke-brand-onloud-hover: #ffffff; + --gnrc-color-stroke-brand-onloud-pressed: #ffffff; + --gnrc-color-stroke-danger-loud-hover: #cb395e; + --gnrc-color-stroke-danger-loud-pressed: #d54467; + --gnrc-color-stroke-danger-soft-hover: #da5471; + --gnrc-color-stroke-danger-soft-pressed: #d04b69; + --gnrc-color-stroke-danger-subtle-hover: #f5c6cc; + --gnrc-color-stroke-danger-subtle-pressed: #ebbdc3; + --gnrc-color-stroke-danger-onloud-hover: #ffffff; + --gnrc-color-stroke-danger-onloud-pressed: #ffffff; + --gnrc-color-stroke-warning-loud-hover: #d8521a; + --gnrc-color-stroke-warning-loud-pressed: #e25c27; + --gnrc-color-stroke-warning-soft-hover: #f28c68; + --gnrc-color-stroke-warning-soft-pressed: #e7825f; + --gnrc-color-stroke-warning-subtle-hover: #f5c9ba; + --gnrc-color-stroke-warning-subtle-pressed: #ebc0b1; + --gnrc-color-stroke-warning-onloud-hover: #ffffff; + --gnrc-color-stroke-warning-onloud-pressed: #ffffff; + --gnrc-color-stroke-success-loud-hover: #188d5d; + --gnrc-color-stroke-success-loud-pressed: #279666; + --gnrc-color-stroke-success-soft-hover: #52c48e; + --gnrc-color-stroke-success-soft-pressed: #47bb85; + --gnrc-color-stroke-success-subtle-hover: #a7e5c2; + --gnrc-color-stroke-success-subtle-pressed: #9edbb9; + --gnrc-color-stroke-success-onloud-hover: #ffffff; + --gnrc-color-stroke-success-onloud-pressed: #ffffff; + --gnrc-color-foreground-neutral-primary-hover: #000000e5; + --gnrc-color-foreground-neutral-primary-pressed: #000000ef; + --gnrc-color-foreground-neutral-secondary-hover: #000000ac; + --gnrc-color-foreground-neutral-secondary-pressed: #000000b6; + --gnrc-color-foreground-neutral-tertiary-hover: #0000009a; + --gnrc-color-foreground-neutral-tertiary-pressed: #000000a4; + --gnrc-color-foreground-neutral-onloud-hover: #ffffff; + --gnrc-color-foreground-neutral-onloud-pressed: #ffffff; + --gnrc-color-foreground-brand-primary-hover: #131313; + --gnrc-color-foreground-brand-primary-pressed: #050505; + --gnrc-color-foreground-brand-onloud-hover: #ffffff; + --gnrc-color-foreground-brand-onloud-pressed: #ffffff; + --gnrc-color-foreground-danger-primary-hover: #9c133f; + --gnrc-color-foreground-danger-primary-pressed: #910037; + --gnrc-color-foreground-danger-onloud-hover: #ffffff; + --gnrc-color-foreground-danger-onloud-pressed: #ffffff; + --gnrc-color-foreground-warning-primary-hover: #9f2f00; + --gnrc-color-foreground-warning-primary-pressed: #952500; + --gnrc-color-foreground-warning-onloud-hover: #ffffff; + --gnrc-color-foreground-warning-onloud-pressed: #ffffff; + --gnrc-color-foreground-success-primary-hover: #006740; + --gnrc-color-foreground-success-primary-pressed: #005f38; + --gnrc-color-foreground-success-onloud-hover: #ffffff; + --gnrc-color-foreground-success-onloud-pressed: #ffffff; + --gnrc-shadow-lowest: 0px 0px 2px #0000001a, 0px 1px 2px #0000000d; + --gnrc-shadow-lower: 0px 0px 2px #0000001a, 0px 2px 4px #00000014; + --gnrc-shadow-low: 0px 0px 2px #0000001a, 0px 2px 4px #00000008, 0px 4px 8px #00000014; + --gnrc-shadow-high: 0px 0px 2px #0000001a, 0px 4px 8px #00000008, 0px 8px 16px #0000000f; + --gnrc-shadow-higher: 0px 0px 2px #0000001a, 0px 8px 16px #00000008, 0px 16px 32px #0000000f; + --gnrc-shadow-highest: 0px 0px 2px #0000001a, 0px 8px 16px #00000008, 0px 32px 64px #0000000f; +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/mappings.json b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/mappings.json index 4b917a8c93..33c7a100a2 100644 --- a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/mappings.json +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/mappings.json @@ -549,6 +549,7 @@ "prmt-duration-200": "200ms", "prmt-duration-300": "300ms", "prmt-duration-500": "500ms", + "prmt-duration-1000": "1000ms", "prmt-easing-immediate": "cubic-bezier(0, 0, 0, 1)", "prmt-easing-standard": "cubic-bezier(0.33, 0, 0, 1)", "prmt-easing-emphasized": "cubic-bezier(0.6, 0, 0.75, 0.4)", @@ -581,6 +582,7 @@ "prmt-breakpoint-1440": "1440px", "prmt-breakpoint-1920": "1920px", "prmt-font-family-segoe-sans": "'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif", + "prmt-font-family-segoe-serif": "'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif", "prmt-font-family-georgia-pro": "'Georgia Pro', Georgia, 'Times New Roman', serif", "prmt-font-family-consolas": "'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace", "prmt-font-size-10": "0.625rem", @@ -1494,7 +1496,7 @@ }, { "name": "--gnrc-font-family-content-editorial", - "primitive": "prmt-font-family-georgia-pro" + "primitive": "prmt-font-family-segoe-serif" }, { "name": "--gnrc-font-family-content-code", @@ -1989,6 +1991,10 @@ "name": "--gnrc-motion-duration-base-500", "primitive": "prmt-duration-500" }, + { + "name": "--gnrc-motion-duration-base-1000", + "primitive": "prmt-duration-1000" + }, { "name": "--gnrc-motion-easing-functional-enter", "primitive": "prmt-easing-immediate" diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic-dark.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic-dark.css new file mode 100644 index 0000000000..d9ae7355fc --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic-dark.css @@ -0,0 +1,283 @@ +/* Fluent Design — Semantic Tokens (Dark Theme) + * Auto-generated by scripts/build.mjs — do not edit manually. + */ + +[data-theme="dark"] { + --gnrc-color-fixed-white: #ffffff; + --gnrc-color-fixed-black: #000000; + --gnrc-color-expression-accent-heavy: #ffffff; + --gnrc-color-expression-accent-loud: #929292; + --gnrc-color-expression-accent-soft: #ffffff1f; + --gnrc-color-expression-accent-subtle: #ffffff14; + --gnrc-color-expression-achromatic-heavy: #ffffff; + --gnrc-color-expression-achromatic-subtle: #000000; + --gnrc-color-expression-gray-heavy: #f5f5f5; + --gnrc-color-expression-gray-loud: #dedede; + --gnrc-color-expression-gray-soft: #929292; + --gnrc-color-expression-gray-subtle: #484848; + --gnrc-color-expression-navy-heavy: #f0f5ff; + --gnrc-color-expression-navy-loud: #cedeff; + --gnrc-color-expression-navy-soft: #5c8df8; + --gnrc-color-expression-navy-subtle: #294482; + --gnrc-color-expression-blue-heavy: #eef6ff; + --gnrc-color-expression-blue-loud: #c6e1ff; + --gnrc-color-expression-blue-soft: #2f95f4; + --gnrc-color-expression-blue-subtle: #0b497f; + --gnrc-color-expression-green-heavy: #e7fce9; + --gnrc-color-expression-green-loud: #baedc1; + --gnrc-color-expression-green-soft: #32ad52; + --gnrc-color-expression-green-subtle: #0c5722; + --gnrc-color-expression-lime-heavy: #e6ffcf; + --gnrc-color-expression-lime-loud: #cbff93; + --gnrc-color-expression-lime-soft: #6da603; + --gnrc-color-expression-lime-subtle: #345200; + --gnrc-color-expression-yellow-heavy: #fff7c4; + --gnrc-color-expression-yellow-loud: #ffed85; + --gnrc-color-expression-yellow-soft: #fbdf06; + --gnrc-color-expression-yellow-subtle: #524800; + --gnrc-color-expression-pumpkin-heavy: #fef2ee; + --gnrc-color-expression-pumpkin-loud: #ffd3c2; + --gnrc-color-expression-pumpkin-soft: #fb966e; + --gnrc-color-expression-pumpkin-subtle: #762f0e; + --gnrc-color-expression-red-heavy: #fff2f0; + --gnrc-color-expression-red-loud: #ffd2cd; + --gnrc-color-expression-red-soft: #e7615b; + --gnrc-color-expression-red-subtle: #772b28; + --gnrc-color-expression-pink-heavy: #fff1f7; + --gnrc-color-expression-pink-loud: #ffcee6; + --gnrc-color-expression-pink-soft: #d961a6; + --gnrc-color-expression-pink-subtle: #6f2b53; + --gnrc-color-expression-purple-heavy: #f7f3ff; + --gnrc-color-expression-purple-loud: #e4d6ff; + --gnrc-color-expression-purple-soft: #a575e8; + --gnrc-color-expression-purple-subtle: #523778; + --gnrc-color-overlay-neutral-translucent: #00000099; + --gnrc-color-surface-neutral-farther: #1b1b1b; + --gnrc-color-surface-neutral-far: #1f1f1f; + --gnrc-color-surface-neutral-near: #181818; + --gnrc-color-surface-neutral-nearer: #292929; + --gnrc-color-surface-neutral-translucent: #3c3c3c80; + --gnrc-material-background-thick: #262626ea; + --gnrc-material-background-regular: #2f2f2fd1; + --gnrc-material-background-thin: #3434348b; + --gnrc-color-background-neutral-heavy: #ffffff; + --gnrc-color-background-neutral-loud: #929292; + --gnrc-color-background-neutral-soft: #ffffff1f; + --gnrc-color-background-neutral-subtle: #ffffff14; + --gnrc-color-background-neutral-transparent: #ffffff00; + --gnrc-color-background-neutral-translucent: #3c3c3c80; + --gnrc-color-background-neutral-disabled: #ffffff07; + --gnrc-color-background-neutral-heavy-disabled: #ffffff20; + --gnrc-color-background-neutral-subtle-disabled: #ffffff07; + --gnrc-color-background-brand-heavy: #ffffff; + --gnrc-color-background-brand-loud: #929292; + --gnrc-color-background-brand-soft: #ffffff1f; + --gnrc-color-background-brand-subtle: #ffffff14; + --gnrc-color-background-brand-transparent: #ffffff00; + --gnrc-color-background-danger-loud: #e55e7a; + --gnrc-color-background-danger-soft: #5a2932; + --gnrc-color-background-danger-subtle: #402529; + --gnrc-color-background-warning-loud: #e56738; + --gnrc-color-background-warning-soft: #592c1c; + --gnrc-color-background-warning-subtle: #40261d; + --gnrc-color-background-success-loud: #05ad72; + --gnrc-color-background-success-soft: #0c462d; + --gnrc-color-background-success-subtle: #193426; + --gnrc-color-stroke-neutral-heavy: #dedede; + --gnrc-color-stroke-neutral-loud: #929292; + --gnrc-color-stroke-neutral-soft: #ffffff61; + --gnrc-color-stroke-neutral-subtle: #ffffff48; + --gnrc-color-stroke-neutral-transparent: #ffffff00; + --gnrc-color-stroke-neutral-onloud: #000000db; + --gnrc-color-stroke-neutral-disabled: #ffffff24; + --gnrc-color-stroke-brand-loud: #929292; + --gnrc-color-stroke-brand-soft: #ffffff61; + --gnrc-color-stroke-brand-subtle: #ffffff48; + --gnrc-color-stroke-brand-onloud: #242424; + --gnrc-color-stroke-danger-loud: #e55e7a; + --gnrc-color-stroke-danger-soft: #d14164; + --gnrc-color-stroke-danger-subtle: #76293a; + --gnrc-color-stroke-danger-onloud: #242424; + --gnrc-color-stroke-warning-loud: #e56738; + --gnrc-color-stroke-warning-soft: #cd4808; + --gnrc-color-stroke-warning-subtle: #762e12; + --gnrc-color-stroke-warning-onloud: #242424; + --gnrc-color-stroke-success-loud: #05ad72; + --gnrc-color-stroke-success-soft: #008e5c; + --gnrc-color-stroke-success-subtle: #025636; + --gnrc-color-stroke-success-onloud: #242424; + --gnrc-color-stroke-focus-inner: #000000; + --gnrc-color-stroke-focus-outer: #ffffff; + --gnrc-color-foreground-neutral-primary: #ffffffde; + --gnrc-color-foreground-neutral-secondary: #ffffffa1; + --gnrc-color-foreground-neutral-tertiary: #ffffff80; + --gnrc-color-foreground-neutral-onloud: #000000db; + --gnrc-color-foreground-neutral-disabled: #ffffff61; + --gnrc-color-foreground-brand-primary: #dedede; + --gnrc-color-foreground-brand-onloud: #000000db; + --gnrc-color-foreground-danger-primary: #fd8ea1; + --gnrc-color-foreground-danger-onloud: #000000db; + --gnrc-color-foreground-warning-primary: #fc9571; + --gnrc-color-foreground-warning-onloud: #000000db; + --gnrc-color-foreground-success-primary: #5dce97; + --gnrc-color-foreground-success-onloud: #000000db; + --gnrc-color-shadow: #000000; + --gnrc-shadow-lowest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%); + --gnrc-shadow-lower: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 16%); + --gnrc-shadow-low: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 16%); + --gnrc-shadow-high: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%); + --gnrc-shadow-higher: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 12%); + --gnrc-shadow-highest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 12%); + --gnrc-font-weight-functional-regular: 420; + --gnrc-font-weight-functional-medium: 550; + --gnrc-font-weight-functional-semibold: 600; + --gnrc-font-weight-functional-bold: 625; + --gnrc-font-weight-content-regular: 420; + --gnrc-font-weight-content-medium: 550; + --gnrc-font-weight-content-semibold: 600; + --gnrc-font-weight-content-bold: 625; + --gnrc-font-weight-content-editorial-regular: 420; + --gnrc-font-weight-content-editorial-medium: 550; + --gnrc-font-weight-content-editorial-semibold: 600; + --gnrc-font-weight-content-editorial-bold: 625; + --gnrc-font-family-functional: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; + --gnrc-font-family-content: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; + --gnrc-font-family-content-editorial: 'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif; + --gnrc-font-family-content-code: 'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace; + --gnrc-letter-spacing-functional-display: -0.0075em; + --gnrc-letter-spacing-functional-pagetitle: -0.0075em; + --gnrc-letter-spacing-functional-title-large: -0.0015em; + --gnrc-letter-spacing-functional-title-medium: -0.0015em; + --gnrc-letter-spacing-functional-title-small: -0.0015em; + --gnrc-letter-spacing-functional-subtitle: -0.0015em; + --gnrc-letter-spacing-functional-body-large: 0em; + --gnrc-letter-spacing-functional-body-medium: 0em; + --gnrc-letter-spacing-functional-body-small: 0em; + --gnrc-letter-spacing-functional-caption: 0em; + --gnrc-letter-spacing-content-statement: -0.0075em; + --gnrc-letter-spacing-content-expressive-large: -0.0075em; + --gnrc-letter-spacing-content-expressive-medium: -0.0015em; + --gnrc-letter-spacing-content-expressive-small: -0.0015em; + --gnrc-letter-spacing-content-h1: -0.0015em; + --gnrc-letter-spacing-content-h2: -0.0015em; + --gnrc-letter-spacing-content-h3: -0.0015em; + --gnrc-letter-spacing-content-h4: -0.0015em; + --gnrc-letter-spacing-content-h5: -0.0015em; + --gnrc-letter-spacing-content-subheadline: 0em; + --gnrc-letter-spacing-content-paragraph-large: 0em; + --gnrc-letter-spacing-content-paragraph-medium: 0em; + --gnrc-letter-spacing-content-paragraph-small: 0em; + --gnrc-letter-spacing-content-subtext: 0em; + --gnrc-letter-spacing-content-table: 0em; + --gnrc-letter-spacing-content-code: 0em; + --gnrc-font-size-functional-display: 4.25rem; + --gnrc-font-size-functional-pagetitle: 2.5rem; + --gnrc-font-size-functional-title-large: 2rem; + --gnrc-font-size-functional-title-medium: 1.75rem; + --gnrc-font-size-functional-title-small: 1.5rem; + --gnrc-font-size-functional-subtitle: 1.25rem; + --gnrc-font-size-functional-body-large: 1rem; + --gnrc-font-size-functional-body-medium: 0.875rem; + --gnrc-font-size-functional-body-small: 0.75rem; + --gnrc-font-size-functional-caption: 0.625rem; + --gnrc-font-size-content-statement: 3.5rem; + --gnrc-font-size-content-expressive-large: 3rem; + --gnrc-font-size-content-expressive-medium: 2.25rem; + --gnrc-font-size-content-expressive-small: 1.75rem; + --gnrc-font-size-content-h1: 2.25rem; + --gnrc-font-size-content-h2: 2rem; + --gnrc-font-size-content-h3: 1.75rem; + --gnrc-font-size-content-h4: 1.5rem; + --gnrc-font-size-content-h5: 1.25rem; + --gnrc-font-size-content-subheadline: 1rem; + --gnrc-font-size-content-paragraph-large: 1.25rem; + --gnrc-font-size-content-paragraph-medium: 1rem; + --gnrc-font-size-content-paragraph-small: 0.75rem; + --gnrc-font-size-content-subtext: 0.625rem; + --gnrc-font-size-content-table: 1rem; + --gnrc-font-size-content-code: 1rem; + --gnrc-line-height-functional-display: round(120%, 2px); + --gnrc-line-height-functional-pagetitle: round(120%, 2px); + --gnrc-line-height-functional-title-large: round(120%, 2px); + --gnrc-line-height-functional-title-medium: round(120%, 2px); + --gnrc-line-height-functional-title-small: round(120%, 2px); + --gnrc-line-height-functional-subtitle: round(140%, 2px); + --gnrc-line-height-functional-body-large: round(140%, 2px); + --gnrc-line-height-functional-body-medium: round(140%, 2px); + --gnrc-line-height-functional-body-small: round(140%, 2px); + --gnrc-line-height-functional-caption: round(140%, 2px); + --gnrc-line-height-content-statement: round(120%, 2px); + --gnrc-line-height-content-expressive-large: round(120%, 2px); + --gnrc-line-height-content-expressive-medium: round(120%, 2px); + --gnrc-line-height-content-expressive-small: round(120%, 2px); + --gnrc-line-height-content-h1: round(120%, 2px); + --gnrc-line-height-content-h2: round(120%, 2px); + --gnrc-line-height-content-h3: round(120%, 2px); + --gnrc-line-height-content-h4: round(120%, 2px); + --gnrc-line-height-content-h5: round(120%, 2px); + --gnrc-line-height-content-subheadline: round(140%, 2px); + --gnrc-line-height-content-paragraph-large: round(170%, 2px); + --gnrc-line-height-content-paragraph-medium: round(170%, 2px); + --gnrc-line-height-content-paragraph-small: round(170%, 2px); + --gnrc-line-height-content-subtext: round(140%, 2px); + --gnrc-line-height-content-table: round(140%, 2px); + --gnrc-line-height-content-code: round(140%, 2px); + --gnrc-border-radius-base-100: 4px; + --gnrc-border-radius-base-200: 8px; + --gnrc-border-radius-base-300: 12px; + --gnrc-border-radius-base-400: 16px; + --gnrc-border-radius-base-600: 24px; + --gnrc-border-radius-base-700: 28px; + --gnrc-border-radius-circular: 9999px; + --gnrc-spacing-component-base-50: 2px; + --gnrc-spacing-component-base-100: 4px; + --gnrc-spacing-component-base-150: 6px; + --gnrc-spacing-component-base-200: 8px; + --gnrc-spacing-component-base-250: 10px; + --gnrc-spacing-component-base-300: 12px; + --gnrc-spacing-component-base-400: 16px; + --gnrc-spacing-component-base-500: 20px; + --gnrc-spacing-component-base-600: 24px; + --gnrc-spacing-component-base-700: 28px; + --gnrc-spacing-component-base-800: 32px; + --gnrc-spacing-layout-base-100: 8px; + --gnrc-spacing-layout-base-200: 16px; + --gnrc-spacing-layout-base-300: 24px; + --gnrc-spacing-layout-base-400: 32px; + --gnrc-spacing-layout-base-450: 36px; + --gnrc-spacing-layout-base-500: 40px; + --gnrc-spacing-layout-base-600: 48px; + --gnrc-spacing-layout-base-700: 56px; + --gnrc-spacing-layout-base-800: 64px; + --gnrc-spacing-layout-base-1000: 80px; + --gnrc-spacing-layout-base-1200: 96px; + --gnrc-stroke-width-thin: 1px; + --gnrc-stroke-width-thick: 2px; + --gnrc-stroke-width-thicker: 3px; + --gnrc-stroke-width-thickest: 4px; + --gnrc-motion-duration-base-50: 50ms; + --gnrc-motion-duration-base-100: 100ms; + --gnrc-motion-duration-base-200: 200ms; + --gnrc-motion-duration-base-300: 300ms; + --gnrc-motion-duration-base-500: 500ms; + --gnrc-motion-duration-base-1000: 1000ms; + --gnrc-motion-easing-functional-enter: cubic-bezier(0, 0, 0, 1); + --gnrc-motion-easing-functional-exit: cubic-bezier(0.6, 0, 0.75, 0.4); + --gnrc-motion-easing-functional-transition: cubic-bezier(0.33, 0, 0, 1); + --gnrc-motion-easing-functional-linear: cubic-bezier(0, 0, 1, 1); + --gnrc-motion-easing-expressive-enter: cubic-bezier(0, 0, 0, 1); + --gnrc-motion-easing-expressive-exit: cubic-bezier(0.6, 0, 0.75, 0.4); + --gnrc-motion-easing-expressive-transition: cubic-bezier(0.33, 0, 0, 1); + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-hover: 0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-press: 0.06; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-hover: 0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-press: 0.06; + --interaction-standard-hover: calc(l + 0.03 * clamp(1,(.5 - l)/.1,3)) c h / calc(alpha + 0.03); + --interaction-standard-pressed: calc(l + 0.06 * clamp(1,(.5 - l)/.1,3)) c h / calc(alpha + 0.06); + --interaction-inverse-hover: calc(l - 0.03 * clamp(1,(.5 - l)/.1,3)) c h / alpha; + --interaction-inverse-pressed: calc(l - 0.06 * clamp(1,(.5 - l)/.1,3)) c h / alpha; +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic-light.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic-light.css new file mode 100644 index 0000000000..633b87a634 --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic-light.css @@ -0,0 +1,283 @@ +/* Fluent Design — Semantic Tokens (Light Theme) + * Auto-generated by scripts/build.mjs — do not edit manually. + */ + +:root, [data-theme="light"] { + --gnrc-color-fixed-white: #ffffff; + --gnrc-color-fixed-black: #000000; + --gnrc-color-expression-accent-heavy: #242424; + --gnrc-color-expression-accent-loud: #6f6f6f; + --gnrc-color-expression-accent-soft: #00000014; + --gnrc-color-expression-accent-subtle: #0000000d; + --gnrc-color-expression-achromatic-heavy: #000000; + --gnrc-color-expression-achromatic-subtle: #ffffff; + --gnrc-color-expression-gray-heavy: #484848; + --gnrc-color-expression-gray-loud: #929292; + --gnrc-color-expression-gray-soft: #dedede; + --gnrc-color-expression-gray-subtle: #f5f5f5; + --gnrc-color-expression-navy-heavy: #294482; + --gnrc-color-expression-navy-loud: #5c8df8; + --gnrc-color-expression-navy-soft: #cedeff; + --gnrc-color-expression-navy-subtle: #f0f5ff; + --gnrc-color-expression-blue-heavy: #0b497f; + --gnrc-color-expression-blue-loud: #2f95f4; + --gnrc-color-expression-blue-soft: #c6e1ff; + --gnrc-color-expression-blue-subtle: #eef6ff; + --gnrc-color-expression-green-heavy: #0c5722; + --gnrc-color-expression-green-loud: #32ad52; + --gnrc-color-expression-green-soft: #baedc1; + --gnrc-color-expression-green-subtle: #e7fce9; + --gnrc-color-expression-lime-heavy: #345200; + --gnrc-color-expression-lime-loud: #6da603; + --gnrc-color-expression-lime-soft: #cbff93; + --gnrc-color-expression-lime-subtle: #e6ffcf; + --gnrc-color-expression-yellow-heavy: #524800; + --gnrc-color-expression-yellow-loud: #fbdf06; + --gnrc-color-expression-yellow-soft: #ffed85; + --gnrc-color-expression-yellow-subtle: #fff7c4; + --gnrc-color-expression-pumpkin-heavy: #762f0e; + --gnrc-color-expression-pumpkin-loud: #fb966e; + --gnrc-color-expression-pumpkin-soft: #ffd3c2; + --gnrc-color-expression-pumpkin-subtle: #fef2ee; + --gnrc-color-expression-red-heavy: #772b28; + --gnrc-color-expression-red-loud: #e7615b; + --gnrc-color-expression-red-soft: #ffd2cd; + --gnrc-color-expression-red-subtle: #fff2f0; + --gnrc-color-expression-pink-heavy: #6f2b53; + --gnrc-color-expression-pink-loud: #d961a6; + --gnrc-color-expression-pink-soft: #ffcee6; + --gnrc-color-expression-pink-subtle: #fff1f7; + --gnrc-color-expression-purple-heavy: #523778; + --gnrc-color-expression-purple-loud: #a575e8; + --gnrc-color-expression-purple-soft: #e4d6ff; + --gnrc-color-expression-purple-subtle: #f7f3ff; + --gnrc-color-overlay-neutral-translucent: #00000026; + --gnrc-color-surface-neutral-farther: #ebebeb; + --gnrc-color-surface-neutral-far: #f2f2f2; + --gnrc-color-surface-neutral-near: #fcfcfc; + --gnrc-color-surface-neutral-nearer: #ffffff; + --gnrc-color-surface-neutral-translucent: #ffffff80; + --gnrc-material-background-thick: #fffffff1; + --gnrc-material-background-regular: #ffffffd7; + --gnrc-material-background-thin: #ffffff7e; + --gnrc-color-background-neutral-heavy: #242424; + --gnrc-color-background-neutral-loud: #6f6f6f; + --gnrc-color-background-neutral-soft: #00000014; + --gnrc-color-background-neutral-subtle: #0000000d; + --gnrc-color-background-neutral-transparent: #24242400; + --gnrc-color-background-neutral-translucent: #e9e9e980; + --gnrc-color-background-neutral-disabled: #00000008; + --gnrc-color-background-neutral-heavy-disabled: #0000001a; + --gnrc-color-background-neutral-subtle-disabled: #00000008; + --gnrc-color-background-brand-heavy: #242424; + --gnrc-color-background-brand-loud: #6f6f6f; + --gnrc-color-background-brand-soft: #00000014; + --gnrc-color-background-brand-subtle: #0000000a; + --gnrc-color-background-brand-transparent: #24242400; + --gnrc-color-background-danger-loud: #c02e56; + --gnrc-color-background-danger-soft: #ffe3e6; + --gnrc-color-background-danger-subtle: #fff1f3; + --gnrc-color-background-warning-loud: #bb4001; + --gnrc-color-background-warning-soft: #ffe5dc; + --gnrc-color-background-warning-subtle: #fff2ee; + --gnrc-color-background-success-loud: #008455; + --gnrc-color-background-success-soft: #c9f8dd; + --gnrc-color-background-success-subtle: #e3fcee; + --gnrc-color-stroke-neutral-heavy: #242424; + --gnrc-color-stroke-neutral-loud: #6f6f6f; + --gnrc-color-stroke-neutral-soft: #0000006d; + --gnrc-color-stroke-neutral-subtle: #00000021; + --gnrc-color-stroke-neutral-transparent: #24242400; + --gnrc-color-stroke-neutral-onloud: #ffffffff; + --gnrc-color-stroke-neutral-disabled: #00000014; + --gnrc-color-stroke-brand-loud: #6f6f6f; + --gnrc-color-stroke-brand-soft: #0000006d; + --gnrc-color-stroke-brand-subtle: #00000021; + --gnrc-color-stroke-brand-onloud: #ffffff; + --gnrc-color-stroke-danger-loud: #c02e56; + --gnrc-color-stroke-danger-soft: #e55e7a; + --gnrc-color-stroke-danger-subtle: #ffd0d6; + --gnrc-color-stroke-danger-onloud: #ffffff; + --gnrc-color-stroke-warning-loud: #cd4808; + --gnrc-color-stroke-warning-soft: #fc9571; + --gnrc-color-stroke-warning-subtle: #ffd3c4; + --gnrc-color-stroke-warning-onloud: #ffffff; + --gnrc-color-stroke-success-loud: #008455; + --gnrc-color-stroke-success-soft: #5dce97; + --gnrc-color-stroke-success-subtle: #b1efcc; + --gnrc-color-stroke-success-onloud: #ffffff; + --gnrc-color-stroke-focus-inner: #ffffff; + --gnrc-color-stroke-focus-outer: #000000; + --gnrc-color-foreground-neutral-primary: #000000db; + --gnrc-color-foreground-neutral-secondary: #000000a2; + --gnrc-color-foreground-neutral-tertiary: #00000090; + --gnrc-color-foreground-neutral-onloud: #ffffffff; + --gnrc-color-foreground-neutral-disabled: #0000006d; + --gnrc-color-foreground-brand-primary: #242424; + --gnrc-color-foreground-brand-onloud: #ffffff; + --gnrc-color-foreground-danger-primary: #a62147; + --gnrc-color-foreground-danger-onloud: #ffffff; + --gnrc-color-foreground-warning-primary: #a93901; + --gnrc-color-foreground-warning-onloud: #ffffff; + --gnrc-color-foreground-success-primary: #017048; + --gnrc-color-foreground-success-onloud: #ffffff; + --gnrc-color-shadow: #000000; + --gnrc-shadow-lowest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 5%); + --gnrc-shadow-lower: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 8%); + --gnrc-shadow-low: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 8%); + --gnrc-shadow-high: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-shadow-higher: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-shadow-highest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-font-weight-functional-regular: 420; + --gnrc-font-weight-functional-medium: 550; + --gnrc-font-weight-functional-semibold: 600; + --gnrc-font-weight-functional-bold: 625; + --gnrc-font-weight-content-regular: 420; + --gnrc-font-weight-content-medium: 550; + --gnrc-font-weight-content-semibold: 600; + --gnrc-font-weight-content-bold: 625; + --gnrc-font-weight-content-editorial-regular: 420; + --gnrc-font-weight-content-editorial-medium: 550; + --gnrc-font-weight-content-editorial-semibold: 600; + --gnrc-font-weight-content-editorial-bold: 625; + --gnrc-font-family-functional: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; + --gnrc-font-family-content: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; + --gnrc-font-family-content-editorial: 'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif; + --gnrc-font-family-content-code: 'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace; + --gnrc-letter-spacing-functional-display: -0.0075em; + --gnrc-letter-spacing-functional-pagetitle: -0.0075em; + --gnrc-letter-spacing-functional-title-large: -0.0015em; + --gnrc-letter-spacing-functional-title-medium: -0.0015em; + --gnrc-letter-spacing-functional-title-small: -0.0015em; + --gnrc-letter-spacing-functional-subtitle: -0.0015em; + --gnrc-letter-spacing-functional-body-large: 0em; + --gnrc-letter-spacing-functional-body-medium: 0em; + --gnrc-letter-spacing-functional-body-small: 0em; + --gnrc-letter-spacing-functional-caption: 0em; + --gnrc-letter-spacing-content-statement: -0.0075em; + --gnrc-letter-spacing-content-expressive-large: -0.0075em; + --gnrc-letter-spacing-content-expressive-medium: -0.0015em; + --gnrc-letter-spacing-content-expressive-small: -0.0015em; + --gnrc-letter-spacing-content-h1: -0.0015em; + --gnrc-letter-spacing-content-h2: -0.0015em; + --gnrc-letter-spacing-content-h3: -0.0015em; + --gnrc-letter-spacing-content-h4: -0.0015em; + --gnrc-letter-spacing-content-h5: -0.0015em; + --gnrc-letter-spacing-content-subheadline: 0em; + --gnrc-letter-spacing-content-paragraph-large: 0em; + --gnrc-letter-spacing-content-paragraph-medium: 0em; + --gnrc-letter-spacing-content-paragraph-small: 0em; + --gnrc-letter-spacing-content-subtext: 0em; + --gnrc-letter-spacing-content-table: 0em; + --gnrc-letter-spacing-content-code: 0em; + --gnrc-font-size-functional-display: 4.25rem; + --gnrc-font-size-functional-pagetitle: 2.5rem; + --gnrc-font-size-functional-title-large: 2rem; + --gnrc-font-size-functional-title-medium: 1.75rem; + --gnrc-font-size-functional-title-small: 1.5rem; + --gnrc-font-size-functional-subtitle: 1.25rem; + --gnrc-font-size-functional-body-large: 1rem; + --gnrc-font-size-functional-body-medium: 0.875rem; + --gnrc-font-size-functional-body-small: 0.75rem; + --gnrc-font-size-functional-caption: 0.625rem; + --gnrc-font-size-content-statement: 3.5rem; + --gnrc-font-size-content-expressive-large: 3rem; + --gnrc-font-size-content-expressive-medium: 2.25rem; + --gnrc-font-size-content-expressive-small: 1.75rem; + --gnrc-font-size-content-h1: 2.25rem; + --gnrc-font-size-content-h2: 2rem; + --gnrc-font-size-content-h3: 1.75rem; + --gnrc-font-size-content-h4: 1.5rem; + --gnrc-font-size-content-h5: 1.25rem; + --gnrc-font-size-content-subheadline: 1rem; + --gnrc-font-size-content-paragraph-large: 1.25rem; + --gnrc-font-size-content-paragraph-medium: 1rem; + --gnrc-font-size-content-paragraph-small: 0.75rem; + --gnrc-font-size-content-subtext: 0.625rem; + --gnrc-font-size-content-table: 1rem; + --gnrc-font-size-content-code: 1rem; + --gnrc-line-height-functional-display: round(120%, 2px); + --gnrc-line-height-functional-pagetitle: round(120%, 2px); + --gnrc-line-height-functional-title-large: round(120%, 2px); + --gnrc-line-height-functional-title-medium: round(120%, 2px); + --gnrc-line-height-functional-title-small: round(120%, 2px); + --gnrc-line-height-functional-subtitle: round(140%, 2px); + --gnrc-line-height-functional-body-large: round(140%, 2px); + --gnrc-line-height-functional-body-medium: round(140%, 2px); + --gnrc-line-height-functional-body-small: round(140%, 2px); + --gnrc-line-height-functional-caption: round(140%, 2px); + --gnrc-line-height-content-statement: round(120%, 2px); + --gnrc-line-height-content-expressive-large: round(120%, 2px); + --gnrc-line-height-content-expressive-medium: round(120%, 2px); + --gnrc-line-height-content-expressive-small: round(120%, 2px); + --gnrc-line-height-content-h1: round(120%, 2px); + --gnrc-line-height-content-h2: round(120%, 2px); + --gnrc-line-height-content-h3: round(120%, 2px); + --gnrc-line-height-content-h4: round(120%, 2px); + --gnrc-line-height-content-h5: round(120%, 2px); + --gnrc-line-height-content-subheadline: round(140%, 2px); + --gnrc-line-height-content-paragraph-large: round(170%, 2px); + --gnrc-line-height-content-paragraph-medium: round(170%, 2px); + --gnrc-line-height-content-paragraph-small: round(170%, 2px); + --gnrc-line-height-content-subtext: round(140%, 2px); + --gnrc-line-height-content-table: round(140%, 2px); + --gnrc-line-height-content-code: round(140%, 2px); + --gnrc-border-radius-base-100: 4px; + --gnrc-border-radius-base-200: 8px; + --gnrc-border-radius-base-300: 12px; + --gnrc-border-radius-base-400: 16px; + --gnrc-border-radius-base-600: 24px; + --gnrc-border-radius-base-700: 28px; + --gnrc-border-radius-circular: 9999px; + --gnrc-spacing-component-base-50: 2px; + --gnrc-spacing-component-base-100: 4px; + --gnrc-spacing-component-base-150: 6px; + --gnrc-spacing-component-base-200: 8px; + --gnrc-spacing-component-base-250: 10px; + --gnrc-spacing-component-base-300: 12px; + --gnrc-spacing-component-base-400: 16px; + --gnrc-spacing-component-base-500: 20px; + --gnrc-spacing-component-base-600: 24px; + --gnrc-spacing-component-base-700: 28px; + --gnrc-spacing-component-base-800: 32px; + --gnrc-spacing-layout-base-100: 8px; + --gnrc-spacing-layout-base-200: 16px; + --gnrc-spacing-layout-base-300: 24px; + --gnrc-spacing-layout-base-400: 32px; + --gnrc-spacing-layout-base-450: 36px; + --gnrc-spacing-layout-base-500: 40px; + --gnrc-spacing-layout-base-600: 48px; + --gnrc-spacing-layout-base-700: 56px; + --gnrc-spacing-layout-base-800: 64px; + --gnrc-spacing-layout-base-1000: 80px; + --gnrc-spacing-layout-base-1200: 96px; + --gnrc-stroke-width-thin: 1px; + --gnrc-stroke-width-thick: 2px; + --gnrc-stroke-width-thicker: 3px; + --gnrc-stroke-width-thickest: 4px; + --gnrc-motion-duration-base-50: 50ms; + --gnrc-motion-duration-base-100: 100ms; + --gnrc-motion-duration-base-200: 200ms; + --gnrc-motion-duration-base-300: 300ms; + --gnrc-motion-duration-base-500: 500ms; + --gnrc-motion-duration-base-1000: 1000ms; + --gnrc-motion-easing-functional-enter: cubic-bezier(0, 0, 0, 1); + --gnrc-motion-easing-functional-exit: cubic-bezier(0.6, 0, 0.75, 0.4); + --gnrc-motion-easing-functional-transition: cubic-bezier(0.33, 0, 0, 1); + --gnrc-motion-easing-functional-linear: cubic-bezier(0, 0, 1, 1); + --gnrc-motion-easing-expressive-enter: cubic-bezier(0, 0, 0, 1); + --gnrc-motion-easing-expressive-exit: cubic-bezier(0.6, 0, 0.75, 0.4); + --gnrc-motion-easing-expressive-transition: cubic-bezier(0.33, 0, 0, 1); + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-hover: -0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-press: -0.06; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-hover: 0.04; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-press: 0.08; + --interaction-standard-hover: calc(l - 0.03 * clamp(1,(.5 - l)/.1,3)) c h / calc(alpha + 0.04); + --interaction-standard-pressed: calc(l - 0.06 * clamp(1,(.5 - l)/.1,3)) c h / calc(alpha + 0.08); + --interaction-inverse-hover: calc(l + 0.03 * clamp(1,(.5 - l)/.1,3)) c h / alpha; + --interaction-inverse-pressed: calc(l + 0.06 * clamp(1,(.5 - l)/.1,3)) c h / alpha; +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic.css index 6dac670ac8..4c9f3e0a70 100644 --- a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic.css +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/semantic.css @@ -143,7 +143,7 @@ --gnrc-font-weight-content-editorial-bold: 625; --gnrc-font-family-functional: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; --gnrc-font-family-content: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; - --gnrc-font-family-content-editorial: 'Georgia Pro', Georgia, 'Times New Roman', serif; + --gnrc-font-family-content-editorial: 'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif; --gnrc-font-family-content-code: 'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace; --gnrc-letter-spacing-functional-display: -0.0075em; --gnrc-letter-spacing-functional-pagetitle: -0.0075em; @@ -261,6 +261,7 @@ --gnrc-motion-duration-base-200: 200ms; --gnrc-motion-duration-base-300: 300ms; --gnrc-motion-duration-base-500: 500ms; + --gnrc-motion-duration-base-1000: 1000ms; --gnrc-motion-easing-functional-enter: cubic-bezier(0, 0, 0, 1); --gnrc-motion-easing-functional-exit: cubic-bezier(0.6, 0, 0.75, 0.4); --gnrc-motion-easing-functional-transition: cubic-bezier(0.33, 0, 0, 1); diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/tokens.json b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/tokens.json new file mode 100644 index 0000000000..49bec466b8 --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/tokens.json @@ -0,0 +1,2320 @@ +{ + "generics": [ + { + "name": "--gnrc-color-fixed-white", + "light": "#ffffff", + "dark": "#ffffff" + }, + { + "name": "--gnrc-color-fixed-black", + "light": "#000000", + "dark": "#000000" + }, + { + "name": "--gnrc-color-expression-accent-heavy", + "light": "#242424", + "dark": "#ffffff" + }, + { + "name": "--gnrc-color-expression-accent-loud", + "light": "#6f6f6f", + "dark": "#929292" + }, + { + "name": "--gnrc-color-expression-accent-soft", + "light": "#00000014", + "dark": "#ffffff1f" + }, + { + "name": "--gnrc-color-expression-accent-subtle", + "light": "#0000000d", + "dark": "#ffffff14" + }, + { + "name": "--gnrc-color-expression-achromatic-heavy", + "light": "#000000", + "dark": "#ffffff" + }, + { + "name": "--gnrc-color-expression-achromatic-subtle", + "light": "#ffffff", + "dark": "#000000" + }, + { + "name": "--gnrc-color-expression-gray-heavy", + "light": "#484848", + "dark": "#f5f5f5" + }, + { + "name": "--gnrc-color-expression-gray-loud", + "light": "#929292", + "dark": "#dedede" + }, + { + "name": "--gnrc-color-expression-gray-soft", + "light": "#dedede", + "dark": "#929292" + }, + { + "name": "--gnrc-color-expression-gray-subtle", + "light": "#f5f5f5", + "dark": "#484848" + }, + { + "name": "--gnrc-color-expression-navy-heavy", + "light": "#294482", + "dark": "#f0f5ff" + }, + { + "name": "--gnrc-color-expression-navy-loud", + "light": "#5c8df8", + "dark": "#cedeff" + }, + { + "name": "--gnrc-color-expression-navy-soft", + "light": "#cedeff", + "dark": "#5c8df8" + }, + { + "name": "--gnrc-color-expression-navy-subtle", + "light": "#f0f5ff", + "dark": "#294482" + }, + { + "name": "--gnrc-color-expression-blue-heavy", + "light": "#0b497f", + "dark": "#eef6ff" + }, + { + "name": "--gnrc-color-expression-blue-loud", + "light": "#2f95f4", + "dark": "#c6e1ff" + }, + { + "name": "--gnrc-color-expression-blue-soft", + "light": "#c6e1ff", + "dark": "#2f95f4" + }, + { + "name": "--gnrc-color-expression-blue-subtle", + "light": "#eef6ff", + "dark": "#0b497f" + }, + { + "name": "--gnrc-color-expression-green-heavy", + "light": "#0c5722", + "dark": "#e7fce9" + }, + { + "name": "--gnrc-color-expression-green-loud", + "light": "#32ad52", + "dark": "#baedc1" + }, + { + "name": "--gnrc-color-expression-green-soft", + "light": "#baedc1", + "dark": "#32ad52" + }, + { + "name": "--gnrc-color-expression-green-subtle", + "light": "#e7fce9", + "dark": "#0c5722" + }, + { + "name": "--gnrc-color-expression-lime-heavy", + "light": "#345200", + "dark": "#e6ffcf" + }, + { + "name": "--gnrc-color-expression-lime-loud", + "light": "#6da603", + "dark": "#cbff93" + }, + { + "name": "--gnrc-color-expression-lime-soft", + "light": "#cbff93", + "dark": "#6da603" + }, + { + "name": "--gnrc-color-expression-lime-subtle", + "light": "#e6ffcf", + "dark": "#345200" + }, + { + "name": "--gnrc-color-expression-yellow-heavy", + "light": "#524800", + "dark": "#fff7c4" + }, + { + "name": "--gnrc-color-expression-yellow-loud", + "light": "#fbdf06", + "dark": "#ffed85" + }, + { + "name": "--gnrc-color-expression-yellow-soft", + "light": "#ffed85", + "dark": "#fbdf06" + }, + { + "name": "--gnrc-color-expression-yellow-subtle", + "light": "#fff7c4", + "dark": "#524800" + }, + { + "name": "--gnrc-color-expression-pumpkin-heavy", + "light": "#762f0e", + "dark": "#fef2ee" + }, + { + "name": "--gnrc-color-expression-pumpkin-loud", + "light": "#fb966e", + "dark": "#ffd3c2" + }, + { + "name": "--gnrc-color-expression-pumpkin-soft", + "light": "#ffd3c2", + "dark": "#fb966e" + }, + { + "name": "--gnrc-color-expression-pumpkin-subtle", + "light": "#fef2ee", + "dark": "#762f0e" + }, + { + "name": "--gnrc-color-expression-red-heavy", + "light": "#772b28", + "dark": "#fff2f0" + }, + { + "name": "--gnrc-color-expression-red-loud", + "light": "#e7615b", + "dark": "#ffd2cd" + }, + { + "name": "--gnrc-color-expression-red-soft", + "light": "#ffd2cd", + "dark": "#e7615b" + }, + { + "name": "--gnrc-color-expression-red-subtle", + "light": "#fff2f0", + "dark": "#772b28" + }, + { + "name": "--gnrc-color-expression-pink-heavy", + "light": "#6f2b53", + "dark": "#fff1f7" + }, + { + "name": "--gnrc-color-expression-pink-loud", + "light": "#d961a6", + "dark": "#ffcee6" + }, + { + "name": "--gnrc-color-expression-pink-soft", + "light": "#ffcee6", + "dark": "#d961a6" + }, + { + "name": "--gnrc-color-expression-pink-subtle", + "light": "#fff1f7", + "dark": "#6f2b53" + }, + { + "name": "--gnrc-color-expression-purple-heavy", + "light": "#523778", + "dark": "#f7f3ff" + }, + { + "name": "--gnrc-color-expression-purple-loud", + "light": "#a575e8", + "dark": "#e4d6ff" + }, + { + "name": "--gnrc-color-expression-purple-soft", + "light": "#e4d6ff", + "dark": "#a575e8" + }, + { + "name": "--gnrc-color-expression-purple-subtle", + "light": "#f7f3ff", + "dark": "#523778" + }, + { + "name": "--gnrc-color-overlay-neutral-translucent", + "light": "#00000026", + "dark": "#00000099" + }, + { + "name": "--gnrc-color-surface-neutral-farther", + "light": "#ebebeb", + "dark": "#1b1b1b" + }, + { + "name": "--gnrc-color-surface-neutral-far", + "light": "#f2f2f2", + "dark": "#1f1f1f" + }, + { + "name": "--gnrc-color-surface-neutral-near", + "light": "#fcfcfc", + "dark": "#181818" + }, + { + "name": "--gnrc-color-surface-neutral-nearer", + "light": "#ffffff", + "dark": "#292929" + }, + { + "name": "--gnrc-color-surface-neutral-translucent", + "light": "#ffffff80", + "dark": "#3c3c3c80" + }, + { + "name": "--gnrc-material-background-thick", + "light": "#fffffff1", + "dark": "#262626ea" + }, + { + "name": "--gnrc-material-background-regular", + "light": "#ffffffd7", + "dark": "#2f2f2fd1" + }, + { + "name": "--gnrc-material-background-thin", + "light": "#ffffff7e", + "dark": "#3434348b" + }, + { + "name": "--gnrc-color-background-neutral-heavy", + "light": "#242424", + "dark": "#ffffff" + }, + { + "name": "--gnrc-color-background-neutral-loud", + "light": "#6f6f6f", + "dark": "#929292" + }, + { + "name": "--gnrc-color-background-neutral-soft", + "light": "#00000014", + "dark": "#ffffff1f" + }, + { + "name": "--gnrc-color-background-neutral-subtle", + "light": "#0000000d", + "dark": "#ffffff14" + }, + { + "name": "--gnrc-color-background-neutral-transparent", + "light": "#24242400", + "dark": "#ffffff00" + }, + { + "name": "--gnrc-color-background-neutral-translucent", + "light": "#e9e9e980", + "dark": "#3c3c3c80" + }, + { + "name": "--gnrc-color-background-neutral-disabled", + "light": "#00000008", + "dark": "#ffffff07", + "deprecated": "Use --gnrc-color-background-neutral-subtle-disabled for subtle disabled fills, or --gnrc-color-background-neutral-heavy-disabled for high-emphasis disabled fills." + }, + { + "name": "--gnrc-color-background-neutral-heavy-disabled", + "light": "#0000001a", + "dark": "#ffffff20" + }, + { + "name": "--gnrc-color-background-neutral-subtle-disabled", + "light": "#00000008", + "dark": "#ffffff07" + }, + { + "name": "--gnrc-color-background-brand-heavy", + "light": "#242424", + "dark": "#ffffff" + }, + { + "name": "--gnrc-color-background-brand-loud", + "light": "#6f6f6f", + "dark": "#929292" + }, + { + "name": "--gnrc-color-background-brand-soft", + "light": "#00000014", + "dark": "#ffffff1f" + }, + { + "name": "--gnrc-color-background-brand-subtle", + "light": "#0000000a", + "dark": "#ffffff14" + }, + { + "name": "--gnrc-color-background-brand-transparent", + "light": "#24242400", + "dark": "#ffffff00" + }, + { + "name": "--gnrc-color-background-danger-loud", + "light": "#c02e56", + "dark": "#e55e7a" + }, + { + "name": "--gnrc-color-background-danger-soft", + "light": "#ffe3e6", + "dark": "#5a2932" + }, + { + "name": "--gnrc-color-background-danger-subtle", + "light": "#fff1f3", + "dark": "#402529" + }, + { + "name": "--gnrc-color-background-warning-loud", + "light": "#bb4001", + "dark": "#e56738" + }, + { + "name": "--gnrc-color-background-warning-soft", + "light": "#ffe5dc", + "dark": "#592c1c" + }, + { + "name": "--gnrc-color-background-warning-subtle", + "light": "#fff2ee", + "dark": "#40261d" + }, + { + "name": "--gnrc-color-background-success-loud", + "light": "#008455", + "dark": "#05ad72" + }, + { + "name": "--gnrc-color-background-success-soft", + "light": "#c9f8dd", + "dark": "#0c462d" + }, + { + "name": "--gnrc-color-background-success-subtle", + "light": "#e3fcee", + "dark": "#193426" + }, + { + "name": "--gnrc-color-stroke-neutral-heavy", + "light": "#242424", + "dark": "#dedede" + }, + { + "name": "--gnrc-color-stroke-neutral-loud", + "light": "#6f6f6f", + "dark": "#929292" + }, + { + "name": "--gnrc-color-stroke-neutral-soft", + "light": "#0000006d", + "dark": "#ffffff61" + }, + { + "name": "--gnrc-color-stroke-neutral-subtle", + "light": "#00000021", + "dark": "#ffffff48" + }, + { + "name": "--gnrc-color-stroke-neutral-transparent", + "light": "#24242400", + "dark": "#ffffff00" + }, + { + "name": "--gnrc-color-stroke-neutral-onloud", + "light": "#ffffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-stroke-neutral-disabled", + "light": "#00000014", + "dark": "#ffffff24" + }, + { + "name": "--gnrc-color-stroke-brand-loud", + "light": "#6f6f6f", + "dark": "#929292" + }, + { + "name": "--gnrc-color-stroke-brand-soft", + "light": "#0000006d", + "dark": "#ffffff61" + }, + { + "name": "--gnrc-color-stroke-brand-subtle", + "light": "#00000021", + "dark": "#ffffff48" + }, + { + "name": "--gnrc-color-stroke-brand-onloud", + "light": "#ffffff", + "dark": "#242424" + }, + { + "name": "--gnrc-color-stroke-danger-loud", + "light": "#c02e56", + "dark": "#e55e7a" + }, + { + "name": "--gnrc-color-stroke-danger-soft", + "light": "#e55e7a", + "dark": "#d14164" + }, + { + "name": "--gnrc-color-stroke-danger-subtle", + "light": "#ffd0d6", + "dark": "#76293a" + }, + { + "name": "--gnrc-color-stroke-danger-onloud", + "light": "#ffffff", + "dark": "#242424" + }, + { + "name": "--gnrc-color-stroke-warning-loud", + "light": "#cd4808", + "dark": "#e56738" + }, + { + "name": "--gnrc-color-stroke-warning-soft", + "light": "#fc9571", + "dark": "#cd4808" + }, + { + "name": "--gnrc-color-stroke-warning-subtle", + "light": "#ffd3c4", + "dark": "#762e12" + }, + { + "name": "--gnrc-color-stroke-warning-onloud", + "light": "#ffffff", + "dark": "#242424" + }, + { + "name": "--gnrc-color-stroke-success-loud", + "light": "#008455", + "dark": "#05ad72" + }, + { + "name": "--gnrc-color-stroke-success-soft", + "light": "#5dce97", + "dark": "#008e5c" + }, + { + "name": "--gnrc-color-stroke-success-subtle", + "light": "#b1efcc", + "dark": "#025636" + }, + { + "name": "--gnrc-color-stroke-success-onloud", + "light": "#ffffff", + "dark": "#242424" + }, + { + "name": "--gnrc-color-stroke-focus-inner", + "light": "#ffffff", + "dark": "#000000" + }, + { + "name": "--gnrc-color-stroke-focus-outer", + "light": "#000000", + "dark": "#ffffff" + }, + { + "name": "--gnrc-color-foreground-neutral-primary", + "light": "#000000db", + "dark": "#ffffffde" + }, + { + "name": "--gnrc-color-foreground-neutral-secondary", + "light": "#000000a2", + "dark": "#ffffffa1" + }, + { + "name": "--gnrc-color-foreground-neutral-tertiary", + "light": "#00000090", + "dark": "#ffffff80" + }, + { + "name": "--gnrc-color-foreground-neutral-onloud", + "light": "#ffffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-neutral-disabled", + "light": "#0000006d", + "dark": "#ffffff61" + }, + { + "name": "--gnrc-color-foreground-brand-primary", + "light": "#242424", + "dark": "#dedede" + }, + { + "name": "--gnrc-color-foreground-brand-onloud", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-danger-primary", + "light": "#a62147", + "dark": "#fd8ea1" + }, + { + "name": "--gnrc-color-foreground-danger-onloud", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-warning-primary", + "light": "#a93901", + "dark": "#fc9571" + }, + { + "name": "--gnrc-color-foreground-warning-onloud", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-success-primary", + "light": "#017048", + "dark": "#5dce97" + }, + { + "name": "--gnrc-color-foreground-success-onloud", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-shadow", + "light": "#000000", + "dark": "#000000" + }, + { + "name": "--gnrc-shadow-lowest", + "light": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 5%)", + "dark": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%)" + }, + { + "name": "--gnrc-shadow-lower", + "light": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 8%)", + "dark": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 16%)" + }, + { + "name": "--gnrc-shadow-low", + "light": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 8%)", + "dark": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 16%)" + }, + { + "name": "--gnrc-shadow-high", + "light": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 6%)", + "dark": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%)" + }, + { + "name": "--gnrc-shadow-higher", + "light": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 6%)", + "dark": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 12%)" + }, + { + "name": "--gnrc-shadow-highest", + "light": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 6%)", + "dark": "0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 12%)" + }, + { + "name": "--gnrc-font-weight-functional-regular", + "light": 420, + "dark": 420 + }, + { + "name": "--gnrc-font-weight-functional-medium", + "light": 550, + "dark": 550 + }, + { + "name": "--gnrc-font-weight-functional-semibold", + "light": 600, + "dark": 600 + }, + { + "name": "--gnrc-font-weight-functional-bold", + "light": 625, + "dark": 625 + }, + { + "name": "--gnrc-font-weight-content-regular", + "light": 420, + "dark": 420 + }, + { + "name": "--gnrc-font-weight-content-medium", + "light": 550, + "dark": 550 + }, + { + "name": "--gnrc-font-weight-content-semibold", + "light": 600, + "dark": 600 + }, + { + "name": "--gnrc-font-weight-content-bold", + "light": 625, + "dark": 625 + }, + { + "name": "--gnrc-font-weight-content-editorial-regular", + "light": 420, + "dark": 420 + }, + { + "name": "--gnrc-font-weight-content-editorial-medium", + "light": 550, + "dark": 550 + }, + { + "name": "--gnrc-font-weight-content-editorial-semibold", + "light": 600, + "dark": 600 + }, + { + "name": "--gnrc-font-weight-content-editorial-bold", + "light": 625, + "dark": 625 + }, + { + "name": "--gnrc-font-family-functional", + "light": "'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif", + "dark": "'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif" + }, + { + "name": "--gnrc-font-family-content", + "light": "'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif", + "dark": "'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif" + }, + { + "name": "--gnrc-font-family-content-editorial", + "light": "'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif", + "dark": "'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif" + }, + { + "name": "--gnrc-font-family-content-code", + "light": "'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace", + "dark": "'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace" + }, + { + "name": "--gnrc-letter-spacing-functional-display", + "light": "-0.75%", + "dark": "-0.75%" + }, + { + "name": "--gnrc-letter-spacing-functional-pagetitle", + "light": "-0.75%", + "dark": "-0.75%" + }, + { + "name": "--gnrc-letter-spacing-functional-title-large", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-functional-title-medium", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-functional-title-small", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-functional-subtitle", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-functional-body-large", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-letter-spacing-functional-body-medium", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-letter-spacing-functional-body-small", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-letter-spacing-functional-caption", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-letter-spacing-content-statement", + "light": "-0.75%", + "dark": "-0.75%" + }, + { + "name": "--gnrc-letter-spacing-content-expressive-large", + "light": "-0.75%", + "dark": "-0.75%" + }, + { + "name": "--gnrc-letter-spacing-content-expressive-medium", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-content-expressive-small", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-content-h1", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-content-h2", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-content-h3", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-content-h4", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-content-h5", + "light": "-0.15%", + "dark": "-0.15%" + }, + { + "name": "--gnrc-letter-spacing-content-subheadline", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-letter-spacing-content-paragraph-large", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-letter-spacing-content-paragraph-medium", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-letter-spacing-content-paragraph-small", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-letter-spacing-content-subtext", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-letter-spacing-content-table", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-letter-spacing-content-code", + "light": "0%", + "dark": "0%" + }, + { + "name": "--gnrc-font-size-functional-display", + "light": "4.25rem", + "dark": "4.25rem" + }, + { + "name": "--gnrc-font-size-functional-pagetitle", + "light": "2.5rem", + "dark": "2.5rem" + }, + { + "name": "--gnrc-font-size-functional-title-large", + "light": "2rem", + "dark": "2rem" + }, + { + "name": "--gnrc-font-size-functional-title-medium", + "light": "1.75rem", + "dark": "1.75rem" + }, + { + "name": "--gnrc-font-size-functional-title-small", + "light": "1.5rem", + "dark": "1.5rem" + }, + { + "name": "--gnrc-font-size-functional-subtitle", + "light": "1.25rem", + "dark": "1.25rem" + }, + { + "name": "--gnrc-font-size-functional-body-large", + "light": "1rem", + "dark": "1rem" + }, + { + "name": "--gnrc-font-size-functional-body-medium", + "light": "0.875rem", + "dark": "0.875rem" + }, + { + "name": "--gnrc-font-size-functional-body-small", + "light": "0.75rem", + "dark": "0.75rem" + }, + { + "name": "--gnrc-font-size-functional-caption", + "light": "0.625rem", + "dark": "0.625rem" + }, + { + "name": "--gnrc-font-size-content-statement", + "light": "3.5rem", + "dark": "3.5rem" + }, + { + "name": "--gnrc-font-size-content-expressive-large", + "light": "3rem", + "dark": "3rem" + }, + { + "name": "--gnrc-font-size-content-expressive-medium", + "light": "2.25rem", + "dark": "2.25rem" + }, + { + "name": "--gnrc-font-size-content-expressive-small", + "light": "1.75rem", + "dark": "1.75rem" + }, + { + "name": "--gnrc-font-size-content-h1", + "light": "2.25rem", + "dark": "2.25rem" + }, + { + "name": "--gnrc-font-size-content-h2", + "light": "2rem", + "dark": "2rem" + }, + { + "name": "--gnrc-font-size-content-h3", + "light": "1.75rem", + "dark": "1.75rem" + }, + { + "name": "--gnrc-font-size-content-h4", + "light": "1.5rem", + "dark": "1.5rem" + }, + { + "name": "--gnrc-font-size-content-h5", + "light": "1.25rem", + "dark": "1.25rem" + }, + { + "name": "--gnrc-font-size-content-subheadline", + "light": "1rem", + "dark": "1rem" + }, + { + "name": "--gnrc-font-size-content-paragraph-large", + "light": "1.25rem", + "dark": "1.25rem" + }, + { + "name": "--gnrc-font-size-content-paragraph-medium", + "light": "1rem", + "dark": "1rem" + }, + { + "name": "--gnrc-font-size-content-paragraph-small", + "light": "0.75rem", + "dark": "0.75rem" + }, + { + "name": "--gnrc-font-size-content-subtext", + "light": "0.625rem", + "dark": "0.625rem" + }, + { + "name": "--gnrc-font-size-content-table", + "light": "1rem", + "dark": "1rem" + }, + { + "name": "--gnrc-font-size-content-code", + "light": "1rem", + "dark": "1rem" + }, + { + "name": "--gnrc-line-height-functional-display", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-functional-pagetitle", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-functional-title-large", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-functional-title-medium", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-functional-title-small", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-functional-subtitle", + "light": "140%", + "dark": "140%" + }, + { + "name": "--gnrc-line-height-functional-body-large", + "light": "140%", + "dark": "140%" + }, + { + "name": "--gnrc-line-height-functional-body-medium", + "light": "140%", + "dark": "140%" + }, + { + "name": "--gnrc-line-height-functional-body-small", + "light": "140%", + "dark": "140%" + }, + { + "name": "--gnrc-line-height-functional-caption", + "light": "140%", + "dark": "140%" + }, + { + "name": "--gnrc-line-height-content-statement", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-content-expressive-large", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-content-expressive-medium", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-content-expressive-small", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-content-h1", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-content-h2", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-content-h3", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-content-h4", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-content-h5", + "light": "120%", + "dark": "120%" + }, + { + "name": "--gnrc-line-height-content-subheadline", + "light": "140%", + "dark": "140%" + }, + { + "name": "--gnrc-line-height-content-paragraph-large", + "light": "170%", + "dark": "170%" + }, + { + "name": "--gnrc-line-height-content-paragraph-medium", + "light": "170%", + "dark": "170%" + }, + { + "name": "--gnrc-line-height-content-paragraph-small", + "light": "170%", + "dark": "170%" + }, + { + "name": "--gnrc-line-height-content-subtext", + "light": "140%", + "dark": "140%" + }, + { + "name": "--gnrc-line-height-content-table", + "light": "140%", + "dark": "140%" + }, + { + "name": "--gnrc-line-height-content-code", + "light": "140%", + "dark": "140%" + }, + { + "name": "--gnrc-border-radius-base-100", + "light": "4px", + "dark": "4px" + }, + { + "name": "--gnrc-border-radius-base-200", + "light": "8px", + "dark": "8px" + }, + { + "name": "--gnrc-border-radius-base-300", + "light": "12px", + "dark": "12px" + }, + { + "name": "--gnrc-border-radius-base-400", + "light": "16px", + "dark": "16px" + }, + { + "name": "--gnrc-border-radius-base-600", + "light": "24px", + "dark": "24px" + }, + { + "name": "--gnrc-border-radius-base-700", + "light": "28px", + "dark": "28px" + }, + { + "name": "--gnrc-border-radius-circular", + "light": "9999px", + "dark": "9999px" + }, + { + "name": "--gnrc-spacing-component-base-50", + "light": "2px", + "dark": "2px" + }, + { + "name": "--gnrc-spacing-component-base-100", + "light": "4px", + "dark": "4px" + }, + { + "name": "--gnrc-spacing-component-base-150", + "light": "6px", + "dark": "6px" + }, + { + "name": "--gnrc-spacing-component-base-200", + "light": "8px", + "dark": "8px" + }, + { + "name": "--gnrc-spacing-component-base-250", + "light": "10px", + "dark": "10px" + }, + { + "name": "--gnrc-spacing-component-base-300", + "light": "12px", + "dark": "12px" + }, + { + "name": "--gnrc-spacing-component-base-400", + "light": "16px", + "dark": "16px" + }, + { + "name": "--gnrc-spacing-component-base-500", + "light": "20px", + "dark": "20px" + }, + { + "name": "--gnrc-spacing-component-base-600", + "light": "24px", + "dark": "24px" + }, + { + "name": "--gnrc-spacing-component-base-700", + "light": "28px", + "dark": "28px" + }, + { + "name": "--gnrc-spacing-component-base-800", + "light": "32px", + "dark": "32px" + }, + { + "name": "--gnrc-spacing-layout-base-100", + "light": "8px", + "dark": "8px" + }, + { + "name": "--gnrc-spacing-layout-base-200", + "light": "16px", + "dark": "16px" + }, + { + "name": "--gnrc-spacing-layout-base-300", + "light": "24px", + "dark": "24px" + }, + { + "name": "--gnrc-spacing-layout-base-400", + "light": "32px", + "dark": "32px" + }, + { + "name": "--gnrc-spacing-layout-base-450", + "light": "36px", + "dark": "36px" + }, + { + "name": "--gnrc-spacing-layout-base-500", + "light": "40px", + "dark": "40px" + }, + { + "name": "--gnrc-spacing-layout-base-600", + "light": "48px", + "dark": "48px" + }, + { + "name": "--gnrc-spacing-layout-base-700", + "light": "56px", + "dark": "56px" + }, + { + "name": "--gnrc-spacing-layout-base-800", + "light": "64px", + "dark": "64px" + }, + { + "name": "--gnrc-spacing-layout-base-1000", + "light": "80px", + "dark": "80px" + }, + { + "name": "--gnrc-spacing-layout-base-1200", + "light": "96px", + "dark": "96px" + }, + { + "name": "--gnrc-stroke-width-thin", + "light": "1px", + "dark": "1px" + }, + { + "name": "--gnrc-stroke-width-thick", + "light": "2px", + "dark": "2px" + }, + { + "name": "--gnrc-stroke-width-thicker", + "light": "3px", + "dark": "3px" + }, + { + "name": "--gnrc-stroke-width-thickest", + "light": "4px", + "dark": "4px" + }, + { + "name": "--gnrc-motion-duration-base-50", + "light": "50ms", + "dark": "50ms" + }, + { + "name": "--gnrc-motion-duration-base-100", + "light": "100ms", + "dark": "100ms" + }, + { + "name": "--gnrc-motion-duration-base-200", + "light": "200ms", + "dark": "200ms" + }, + { + "name": "--gnrc-motion-duration-base-300", + "light": "300ms", + "dark": "300ms" + }, + { + "name": "--gnrc-motion-duration-base-500", + "light": "500ms", + "dark": "500ms" + }, + { + "name": "--gnrc-motion-duration-base-1000", + "light": "1000ms", + "dark": "1000ms" + }, + { + "name": "--gnrc-motion-easing-functional-enter", + "light": "cubic-bezier(0, 0, 0, 1)", + "dark": "cubic-bezier(0, 0, 0, 1)" + }, + { + "name": "--gnrc-motion-easing-functional-exit", + "light": "cubic-bezier(0.6, 0, 0.75, 0.4)", + "dark": "cubic-bezier(0.6, 0, 0.75, 0.4)" + }, + { + "name": "--gnrc-motion-easing-functional-transition", + "light": "cubic-bezier(0.33, 0, 0, 1)", + "dark": "cubic-bezier(0.33, 0, 0, 1)" + }, + { + "name": "--gnrc-motion-easing-functional-linear", + "light": "cubic-bezier(0, 0, 1, 1)", + "dark": "cubic-bezier(0, 0, 1, 1)" + }, + { + "name": "--gnrc-motion-easing-expressive-enter", + "light": "cubic-bezier(0, 0, 0, 1)", + "dark": "cubic-bezier(0, 0, 0, 1)" + }, + { + "name": "--gnrc-motion-easing-expressive-exit", + "light": "cubic-bezier(0.6, 0, 0.75, 0.4)", + "dark": "cubic-bezier(0.6, 0, 0.75, 0.4)" + }, + { + "name": "--gnrc-motion-easing-expressive-transition", + "light": "cubic-bezier(0.33, 0, 0, 1)", + "dark": "cubic-bezier(0.33, 0, 0, 1)" + } + ], + "interaction": [ + { + "name": "--gnrc-color-surface-neutral-farther-hover", + "light": "#e1e1e1", + "dark": "#2f2f2f" + }, + { + "name": "--gnrc-color-surface-neutral-farther-pressed", + "light": "#d7d7d7", + "dark": "#454545" + }, + { + "name": "--gnrc-color-surface-neutral-far-hover", + "light": "#e8e8e8", + "dark": "#323232" + }, + { + "name": "--gnrc-color-surface-neutral-far-pressed", + "light": "#dedede", + "dark": "#464646" + }, + { + "name": "--gnrc-color-surface-neutral-near-hover", + "light": "#f2f2f2", + "dark": "#2d2d2d" + }, + { + "name": "--gnrc-color-surface-neutral-near-pressed", + "light": "#e8e8e8", + "dark": "#434343" + }, + { + "name": "--gnrc-color-surface-neutral-nearer-hover", + "light": "#f5f5f5", + "dark": "#3a3a3a" + }, + { + "name": "--gnrc-color-surface-neutral-nearer-pressed", + "light": "#ebebeb", + "dark": "#4b4b4b" + }, + { + "name": "--gnrc-color-surface-neutral-translucent-hover", + "light": "#f5f5f58a", + "dark": "#47474788" + }, + { + "name": "--gnrc-color-surface-neutral-translucent-pressed", + "light": "#ebebeb94", + "dark": "#5353538f" + }, + { + "name": "--gnrc-color-background-neutral-heavy-hover", + "light": "#363636", + "dark": "#f5f5f5" + }, + { + "name": "--gnrc-color-background-neutral-heavy-pressed", + "light": "#494949", + "dark": "#ebebeb" + }, + { + "name": "--gnrc-color-background-neutral-loud-hover", + "light": "#787878", + "dark": "#898989" + }, + { + "name": "--gnrc-color-background-neutral-loud-pressed", + "light": "#818181", + "dark": "#808080" + }, + { + "name": "--gnrc-color-background-neutral-soft-hover", + "light": "#0000001e", + "dark": "#ffffff27" + }, + { + "name": "--gnrc-color-background-neutral-soft-pressed", + "light": "#00000028", + "dark": "#ffffff2e" + }, + { + "name": "--gnrc-color-background-neutral-subtle-hover", + "light": "#00000017", + "dark": "#ffffff1c" + }, + { + "name": "--gnrc-color-background-neutral-subtle-pressed", + "light": "#00000021", + "dark": "#ffffff23" + }, + { + "name": "--gnrc-color-background-neutral-transparent-hover", + "light": "#1313130a", + "dark": "#ffffff08" + }, + { + "name": "--gnrc-color-background-neutral-transparent-pressed", + "light": "#05050514", + "dark": "#ffffff0f" + }, + { + "name": "--gnrc-color-background-neutral-translucent-hover", + "light": "#d8d8d88a", + "dark": "#56565688" + }, + { + "name": "--gnrc-color-background-neutral-translucent-pressed", + "light": "#cacaca94", + "dark": "#6d6d6d8f" + }, + { + "name": "--gnrc-color-background-brand-heavy-hover", + "light": "#363636", + "dark": "#f5f5f5" + }, + { + "name": "--gnrc-color-background-brand-heavy-pressed", + "light": "#494949", + "dark": "#ebebeb" + }, + { + "name": "--gnrc-color-background-brand-loud-hover", + "light": "#787878", + "dark": "#898989" + }, + { + "name": "--gnrc-color-background-brand-loud-pressed", + "light": "#818181", + "dark": "#808080" + }, + { + "name": "--gnrc-color-background-brand-soft-hover", + "light": "#0000001e", + "dark": "#ffffff27" + }, + { + "name": "--gnrc-color-background-brand-soft-pressed", + "light": "#00000028", + "dark": "#ffffff2e" + }, + { + "name": "--gnrc-color-background-brand-subtle-hover", + "light": "#00000014", + "dark": "#ffffff1c" + }, + { + "name": "--gnrc-color-background-brand-subtle-pressed", + "light": "#0000001e", + "dark": "#ffffff23" + }, + { + "name": "--gnrc-color-background-brand-transparent-hover", + "light": "#1313130a", + "dark": "#ffffff08" + }, + { + "name": "--gnrc-color-background-brand-transparent-pressed", + "light": "#05050514", + "dark": "#ffffff0f" + }, + { + "name": "--gnrc-color-background-danger-loud-hover", + "light": "#cb395e", + "dark": "#da5471" + }, + { + "name": "--gnrc-color-background-danger-loud-pressed", + "light": "#d54467", + "dark": "#d04b69" + }, + { + "name": "--gnrc-color-background-danger-soft-hover", + "light": "#f5d9dc", + "dark": "#67353e" + }, + { + "name": "--gnrc-color-background-danger-soft-pressed", + "light": "#ebcfd2", + "dark": "#754149" + }, + { + "name": "--gnrc-color-background-danger-subtle-hover", + "light": "#f5e7e9", + "dark": "#503438" + }, + { + "name": "--gnrc-color-background-danger-subtle-pressed", + "light": "#ebdddf", + "dark": "#614448" + }, + { + "name": "--gnrc-color-background-warning-loud-hover", + "light": "#c54a14", + "dark": "#da5d2e" + }, + { + "name": "--gnrc-color-background-warning-loud-pressed", + "light": "#d05321", + "dark": "#d05422" + }, + { + "name": "--gnrc-color-background-warning-soft-hover", + "light": "#f5dbd2", + "dark": "#663828" + }, + { + "name": "--gnrc-color-background-warning-soft-pressed", + "light": "#ebd1c9", + "dark": "#744434" + }, + { + "name": "--gnrc-color-background-warning-subtle-hover", + "light": "#f5e8e4", + "dark": "#51352c" + }, + { + "name": "--gnrc-color-background-warning-subtle-pressed", + "light": "#ebdeda", + "dark": "#62453b" + }, + { + "name": "--gnrc-color-background-success-loud-hover", + "light": "#188d5d", + "dark": "#00a369" + }, + { + "name": "--gnrc-color-background-success-loud-pressed", + "light": "#279666", + "dark": "#009a60" + }, + { + "name": "--gnrc-color-background-success-soft-hover", + "light": "#bfeed3", + "dark": "#1c5238" + }, + { + "name": "--gnrc-color-background-success-soft-pressed", + "light": "#b6e4ca", + "dark": "#295f44" + }, + { + "name": "--gnrc-color-background-success-subtle-hover", + "light": "#d9f2e4", + "dark": "#294435" + }, + { + "name": "--gnrc-color-background-success-subtle-pressed", + "light": "#cfe8da", + "dark": "#385445" + }, + { + "name": "--gnrc-color-stroke-neutral-heavy-hover", + "light": "#363636", + "dark": "#d4d4d4" + }, + { + "name": "--gnrc-color-stroke-neutral-heavy-pressed", + "light": "#494949", + "dark": "#cbcbcb" + }, + { + "name": "--gnrc-color-stroke-neutral-loud-hover", + "light": "#787878", + "dark": "#898989" + }, + { + "name": "--gnrc-color-stroke-neutral-loud-pressed", + "light": "#818181", + "dark": "#808080" + }, + { + "name": "--gnrc-color-stroke-neutral-soft-hover", + "light": "#02020277", + "dark": "#ffffff69" + }, + { + "name": "--gnrc-color-stroke-neutral-soft-pressed", + "light": "#04040481", + "dark": "#ffffff70" + }, + { + "name": "--gnrc-color-stroke-neutral-subtle-hover", + "light": "#0000002b", + "dark": "#ffffff50" + }, + { + "name": "--gnrc-color-stroke-neutral-subtle-pressed", + "light": "#05050535", + "dark": "#ffffff57" + }, + { + "name": "--gnrc-color-stroke-neutral-transparent-hover", + "light": "#1313130a", + "dark": "#ffffff08" + }, + { + "name": "--gnrc-color-stroke-neutral-transparent-pressed", + "light": "#05050514", + "dark": "#ffffff0f" + }, + { + "name": "--gnrc-color-stroke-neutral-onloud-hover", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-stroke-neutral-onloud-pressed", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-stroke-brand-loud-hover", + "light": "#787878", + "dark": "#898989" + }, + { + "name": "--gnrc-color-stroke-brand-loud-pressed", + "light": "#818181", + "dark": "#808080" + }, + { + "name": "--gnrc-color-stroke-brand-soft-hover", + "light": "#02020277", + "dark": "#ffffff69" + }, + { + "name": "--gnrc-color-stroke-brand-soft-pressed", + "light": "#04040481", + "dark": "#ffffff70" + }, + { + "name": "--gnrc-color-stroke-brand-subtle-hover", + "light": "#0000002b", + "dark": "#ffffff50" + }, + { + "name": "--gnrc-color-stroke-brand-subtle-pressed", + "light": "#05050535", + "dark": "#ffffff57" + }, + { + "name": "--gnrc-color-stroke-brand-onloud-hover", + "light": "#ffffff", + "dark": "#131313" + }, + { + "name": "--gnrc-color-stroke-brand-onloud-pressed", + "light": "#ffffff", + "dark": "#050505" + }, + { + "name": "--gnrc-color-stroke-danger-loud-hover", + "light": "#cb395e", + "dark": "#da5471" + }, + { + "name": "--gnrc-color-stroke-danger-loud-pressed", + "light": "#d54467", + "dark": "#d04b69" + }, + { + "name": "--gnrc-color-stroke-danger-soft-hover", + "light": "#da5471", + "dark": "#dc4b6d" + }, + { + "name": "--gnrc-color-stroke-danger-soft-pressed", + "light": "#d04b69", + "dark": "#e65575" + }, + { + "name": "--gnrc-color-stroke-danger-subtle-hover", + "light": "#f5c6cc", + "dark": "#803242" + }, + { + "name": "--gnrc-color-stroke-danger-subtle-pressed", + "light": "#ebbdc3", + "dark": "#893a4a" + }, + { + "name": "--gnrc-color-stroke-danger-onloud-hover", + "light": "#ffffff", + "dark": "#131313" + }, + { + "name": "--gnrc-color-stroke-danger-onloud-pressed", + "light": "#ffffff", + "dark": "#050505" + }, + { + "name": "--gnrc-color-stroke-warning-loud-hover", + "light": "#d8521a", + "dark": "#da5d2e" + }, + { + "name": "--gnrc-color-stroke-warning-loud-pressed", + "light": "#e25c27", + "dark": "#d05422" + }, + { + "name": "--gnrc-color-stroke-warning-soft-hover", + "light": "#f28c68", + "dark": "#d8521a" + }, + { + "name": "--gnrc-color-stroke-warning-soft-pressed", + "light": "#e7825f", + "dark": "#e25c27" + }, + { + "name": "--gnrc-color-stroke-warning-subtle-hover", + "light": "#f5c9ba", + "dark": "#7f371b" + }, + { + "name": "--gnrc-color-stroke-warning-subtle-pressed", + "light": "#ebc0b1", + "dark": "#893f24" + }, + { + "name": "--gnrc-color-stroke-warning-onloud-hover", + "light": "#ffffff", + "dark": "#131313" + }, + { + "name": "--gnrc-color-stroke-warning-onloud-pressed", + "light": "#ffffff", + "dark": "#050505" + }, + { + "name": "--gnrc-color-stroke-success-loud-hover", + "light": "#188d5d", + "dark": "#00a369" + }, + { + "name": "--gnrc-color-stroke-success-loud-pressed", + "light": "#279666", + "dark": "#009a60" + }, + { + "name": "--gnrc-color-stroke-success-soft-hover", + "light": "#52c48e", + "dark": "#1a9765" + }, + { + "name": "--gnrc-color-stroke-success-soft-pressed", + "light": "#47bb85", + "dark": "#2aa16d" + }, + { + "name": "--gnrc-color-stroke-success-subtle-hover", + "light": "#a7e5c2", + "dark": "#125f3e" + }, + { + "name": "--gnrc-color-stroke-success-subtle-pressed", + "light": "#9edbb9", + "dark": "#1e6746" + }, + { + "name": "--gnrc-color-stroke-success-onloud-hover", + "light": "#ffffff", + "dark": "#131313" + }, + { + "name": "--gnrc-color-stroke-success-onloud-pressed", + "light": "#ffffff", + "dark": "#050505" + }, + { + "name": "--gnrc-color-foreground-neutral-primary-hover", + "light": "#000000e5", + "dark": "#ffffffe6" + }, + { + "name": "--gnrc-color-foreground-neutral-primary-pressed", + "light": "#000000ef", + "dark": "#ffffffed" + }, + { + "name": "--gnrc-color-foreground-neutral-secondary-hover", + "light": "#000000ac", + "dark": "#ffffffa9" + }, + { + "name": "--gnrc-color-foreground-neutral-secondary-pressed", + "light": "#000000b6", + "dark": "#ffffffb0" + }, + { + "name": "--gnrc-color-foreground-neutral-tertiary-hover", + "light": "#0000009a", + "dark": "#ffffff88" + }, + { + "name": "--gnrc-color-foreground-neutral-tertiary-pressed", + "light": "#000000a4", + "dark": "#ffffff8f" + }, + { + "name": "--gnrc-color-foreground-neutral-onloud-hover", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-neutral-onloud-pressed", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-brand-primary-hover", + "light": "#131313", + "dark": "#e8e8e8" + }, + { + "name": "--gnrc-color-foreground-brand-primary-pressed", + "light": "#050505", + "dark": "#f2f2f2" + }, + { + "name": "--gnrc-color-foreground-brand-onloud-hover", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-brand-onloud-pressed", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-danger-primary-hover", + "light": "#9c133f", + "dark": "#ff97aa" + }, + { + "name": "--gnrc-color-foreground-danger-primary-pressed", + "light": "#910037", + "dark": "#ffa1b4" + }, + { + "name": "--gnrc-color-foreground-danger-onloud-hover", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-danger-onloud-pressed", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-warning-primary-hover", + "light": "#9f2f00", + "dark": "#ff9f7a" + }, + { + "name": "--gnrc-color-foreground-warning-primary-pressed", + "light": "#952500", + "dark": "#ffa884" + }, + { + "name": "--gnrc-color-foreground-warning-onloud-hover", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-warning-onloud-pressed", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-success-primary-hover", + "light": "#006740", + "dark": "#67d8a0" + }, + { + "name": "--gnrc-color-foreground-success-primary-pressed", + "light": "#005f38", + "dark": "#72e2aa" + }, + { + "name": "--gnrc-color-foreground-success-onloud-hover", + "light": "#ffffff", + "dark": "#000000db" + }, + { + "name": "--gnrc-color-foreground-success-onloud-pressed", + "light": "#ffffff", + "dark": "#000000db" + } + ], + "textstyle": [ + { + "name": "textstyle-functional-display", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-medium", + "font_size": "--gnrc-font-size-functional-display", + "line_height": "--gnrc-line-height-functional-display", + "letter_spacing": "--gnrc-letter-spacing-functional-display", + "optical_size": 36 + }, + { + "name": "textstyle-functional-pagetitle", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-medium", + "font_size": "--gnrc-font-size-functional-pagetitle", + "line_height": "--gnrc-line-height-functional-pagetitle", + "letter_spacing": "--gnrc-letter-spacing-functional-pagetitle", + "optical_size": 36 + }, + { + "name": "textstyle-functional-title-large", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-semibold", + "font_size": "--gnrc-font-size-functional-title-large", + "line_height": "--gnrc-line-height-functional-title-large", + "letter_spacing": "--gnrc-letter-spacing-functional-title-large", + "optical_size": 36 + }, + { + "name": "textstyle-functional-title-medium", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-semibold", + "font_size": "--gnrc-font-size-functional-title-medium", + "line_height": "--gnrc-line-height-functional-title-medium", + "letter_spacing": "--gnrc-letter-spacing-functional-title-medium", + "optical_size": 36 + }, + { + "name": "textstyle-functional-title-small", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-semibold", + "font_size": "--gnrc-font-size-functional-title-small", + "line_height": "--gnrc-line-height-functional-title-small", + "letter_spacing": "--gnrc-letter-spacing-functional-title-small", + "optical_size": 36 + }, + { + "name": "textstyle-functional-subtitle", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-semibold", + "font_size": "--gnrc-font-size-functional-subtitle", + "line_height": "--gnrc-line-height-functional-subtitle", + "letter_spacing": "--gnrc-letter-spacing-functional-subtitle", + "optical_size": 36 + }, + { + "name": "textstyle-functional-body-large", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-regular", + "font_size": "--gnrc-font-size-functional-body-large", + "line_height": "--gnrc-line-height-functional-body-large", + "letter_spacing": "--gnrc-letter-spacing-functional-body-large", + "optical_size": 8 + }, + { + "name": "textstyle-functional-body-large-strong", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-bold", + "font_size": "--gnrc-font-size-functional-body-large", + "line_height": "--gnrc-line-height-functional-body-large", + "letter_spacing": "--gnrc-letter-spacing-functional-body-large", + "optical_size": 8 + }, + { + "name": "textstyle-functional-body-medium", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-regular", + "font_size": "--gnrc-font-size-functional-body-medium", + "line_height": "--gnrc-line-height-functional-body-medium", + "letter_spacing": "--gnrc-letter-spacing-functional-body-medium", + "optical_size": 8 + }, + { + "name": "textstyle-functional-body-medium-strong", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-bold", + "font_size": "--gnrc-font-size-functional-body-medium", + "line_height": "--gnrc-line-height-functional-body-medium", + "letter_spacing": "--gnrc-letter-spacing-functional-body-medium", + "optical_size": 8 + }, + { + "name": "textstyle-functional-body-small", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-regular", + "font_size": "--gnrc-font-size-functional-body-small", + "line_height": "--gnrc-line-height-functional-body-small", + "letter_spacing": "--gnrc-letter-spacing-functional-body-small", + "optical_size": 8 + }, + { + "name": "textstyle-functional-body-small-strong", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-bold", + "font_size": "--gnrc-font-size-functional-body-small", + "line_height": "--gnrc-line-height-functional-body-small", + "letter_spacing": "--gnrc-letter-spacing-functional-body-small", + "optical_size": 8 + }, + { + "name": "textstyle-functional-caption", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-regular", + "font_size": "--gnrc-font-size-functional-caption", + "line_height": "--gnrc-line-height-functional-caption", + "letter_spacing": "--gnrc-letter-spacing-functional-caption", + "optical_size": 8 + }, + { + "name": "textstyle-functional-caption-strong", + "font_family": "--gnrc-font-family-functional", + "font_weight": "--gnrc-font-weight-functional-bold", + "font_size": "--gnrc-font-size-functional-caption", + "line_height": "--gnrc-line-height-functional-caption", + "letter_spacing": "--gnrc-letter-spacing-functional-caption", + "optical_size": 8 + }, + { + "name": "textstyle-content-statement", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-statement", + "line_height": "--gnrc-line-height-content-statement", + "letter_spacing": "--gnrc-letter-spacing-content-statement", + "optical_size": 36 + }, + { + "name": "textstyle-content-expressive-large", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-expressive-large", + "line_height": "--gnrc-line-height-content-expressive-large", + "letter_spacing": "--gnrc-letter-spacing-content-expressive-large", + "optical_size": 36 + }, + { + "name": "textstyle-content-expressive-medium", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-expressive-medium", + "line_height": "--gnrc-line-height-content-expressive-medium", + "letter_spacing": "--gnrc-letter-spacing-content-expressive-medium", + "optical_size": 36 + }, + { + "name": "textstyle-content-expressive-small", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-expressive-small", + "line_height": "--gnrc-line-height-content-expressive-small", + "letter_spacing": "--gnrc-letter-spacing-content-expressive-small", + "optical_size": 36 + }, + { + "name": "textstyle-content-h1", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-medium", + "font_size": "--gnrc-font-size-content-h1", + "line_height": "--gnrc-line-height-content-h1", + "letter_spacing": "--gnrc-letter-spacing-content-h1", + "optical_size": 36 + }, + { + "name": "textstyle-content-h2", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-medium", + "font_size": "--gnrc-font-size-content-h2", + "line_height": "--gnrc-line-height-content-h2", + "letter_spacing": "--gnrc-letter-spacing-content-h2", + "optical_size": 36 + }, + { + "name": "textstyle-content-h3", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-medium", + "font_size": "--gnrc-font-size-content-h3", + "line_height": "--gnrc-line-height-content-h3", + "letter_spacing": "--gnrc-letter-spacing-content-h3", + "optical_size": 36 + }, + { + "name": "textstyle-content-h4", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-medium", + "font_size": "--gnrc-font-size-content-h4", + "line_height": "--gnrc-line-height-content-h4", + "letter_spacing": "--gnrc-letter-spacing-content-h4", + "optical_size": 36 + }, + { + "name": "textstyle-content-h5", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-medium", + "font_size": "--gnrc-font-size-content-h5", + "line_height": "--gnrc-line-height-content-h5", + "letter_spacing": "--gnrc-letter-spacing-content-h5", + "optical_size": 36 + }, + { + "name": "textstyle-content-subheadline", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-subheadline", + "line_height": "--gnrc-line-height-content-subheadline", + "letter_spacing": "--gnrc-letter-spacing-content-subheadline", + "optical_size": 36 + }, + { + "name": "textstyle-content-paragraph-large", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-paragraph-large", + "line_height": "--gnrc-line-height-content-paragraph-large", + "letter_spacing": "--gnrc-letter-spacing-content-paragraph-large", + "optical_size": 8 + }, + { + "name": "textstyle-content-paragraph-large-strong", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-bold", + "font_size": "--gnrc-font-size-content-paragraph-large", + "line_height": "--gnrc-line-height-content-paragraph-large", + "letter_spacing": "--gnrc-letter-spacing-content-paragraph-large", + "optical_size": 8 + }, + { + "name": "textstyle-content-paragraph-medium", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-paragraph-medium", + "line_height": "--gnrc-line-height-content-paragraph-medium", + "letter_spacing": "--gnrc-letter-spacing-content-paragraph-medium", + "optical_size": 8 + }, + { + "name": "textstyle-content-paragraph-medium-strong", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-bold", + "font_size": "--gnrc-font-size-content-paragraph-medium", + "line_height": "--gnrc-line-height-content-paragraph-medium", + "letter_spacing": "--gnrc-letter-spacing-content-paragraph-medium", + "optical_size": 8 + }, + { + "name": "textstyle-content-paragraph-small", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-paragraph-small", + "line_height": "--gnrc-line-height-content-paragraph-small", + "letter_spacing": "--gnrc-letter-spacing-content-paragraph-small", + "optical_size": 8 + }, + { + "name": "textstyle-content-paragraph-small-strong", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-bold", + "font_size": "--gnrc-font-size-content-paragraph-small", + "line_height": "--gnrc-line-height-content-paragraph-small", + "letter_spacing": "--gnrc-letter-spacing-content-paragraph-small", + "optical_size": 8 + }, + { + "name": "textstyle-content-subtext", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-subtext", + "line_height": "--gnrc-line-height-content-subtext", + "letter_spacing": "--gnrc-letter-spacing-content-subtext", + "optical_size": 8 + }, + { + "name": "textstyle-content-table", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-table", + "line_height": "--gnrc-line-height-content-table", + "letter_spacing": "--gnrc-letter-spacing-content-table", + "optical_size": 8 + }, + { + "name": "textstyle-content-table-strong", + "font_family": "--gnrc-font-family-content", + "font_weight": "--gnrc-font-weight-content-bold", + "font_size": "--gnrc-font-size-content-table", + "line_height": "--gnrc-line-height-content-table", + "letter_spacing": "--gnrc-letter-spacing-content-table", + "optical_size": 8 + }, + { + "name": "textstyle-content-code", + "font_family": "--gnrc-font-family-content-code", + "font_weight": "--gnrc-font-weight-content-regular", + "font_size": "--gnrc-font-size-content-code", + "line_height": "--gnrc-line-height-content-code", + "letter_spacing": "--gnrc-letter-spacing-content-code", + "optical_size": 8 + }, + { + "name": "textstyle-content-editorial-statement", + "font_family": "--gnrc-font-family-content-editorial", + "font_weight": "--gnrc-font-weight-content-editorial-regular", + "font_size": "--gnrc-font-size-content-statement", + "line_height": "--gnrc-line-height-content-statement", + "letter_spacing": "--gnrc-letter-spacing-content-statement", + "optical_size": 36 + }, + { + "name": "textstyle-content-editorial-expressive-large", + "font_family": "--gnrc-font-family-content-editorial", + "font_weight": "--gnrc-font-weight-content-editorial-regular", + "font_size": "--gnrc-font-size-content-expressive-large", + "line_height": "--gnrc-line-height-content-expressive-large", + "letter_spacing": "--gnrc-letter-spacing-content-expressive-large", + "optical_size": 36 + }, + { + "name": "textstyle-content-editorial-expressive-medium", + "font_family": "--gnrc-font-family-content-editorial", + "font_weight": "--gnrc-font-weight-content-editorial-regular", + "font_size": "--gnrc-font-size-content-expressive-medium", + "line_height": "--gnrc-line-height-content-expressive-medium", + "letter_spacing": "--gnrc-letter-spacing-content-expressive-medium", + "optical_size": 36 + }, + { + "name": "textstyle-content-editorial-expressive-small", + "font_family": "--gnrc-font-family-content-editorial", + "font_weight": "--gnrc-font-weight-content-editorial-regular", + "font_size": "--gnrc-font-size-content-expressive-small", + "line_height": "--gnrc-line-height-content-expressive-small", + "letter_spacing": "--gnrc-letter-spacing-content-expressive-small", + "optical_size": 36 + }, + { + "name": "textstyle-content-editorial-h1", + "font_family": "--gnrc-font-family-content-editorial", + "font_weight": "--gnrc-font-weight-content-editorial-medium", + "font_size": "--gnrc-font-size-content-h1", + "line_height": "--gnrc-line-height-content-h1", + "letter_spacing": "--gnrc-letter-spacing-content-h1", + "optical_size": 36 + }, + { + "name": "textstyle-content-editorial-h2", + "font_family": "--gnrc-font-family-content-editorial", + "font_weight": "--gnrc-font-weight-content-editorial-medium", + "font_size": "--gnrc-font-size-content-h2", + "line_height": "--gnrc-line-height-content-h2", + "letter_spacing": "--gnrc-letter-spacing-content-h2", + "optical_size": 36 + }, + { + "name": "textstyle-content-editorial-h3", + "font_family": "--gnrc-font-family-content-editorial", + "font_weight": "--gnrc-font-weight-content-editorial-medium", + "font_size": "--gnrc-font-size-content-h3", + "line_height": "--gnrc-line-height-content-h3", + "letter_spacing": "--gnrc-letter-spacing-content-h3", + "optical_size": 36 + }, + { + "name": "textstyle-content-editorial-h4", + "font_family": "--gnrc-font-family-content-editorial", + "font_weight": "--gnrc-font-weight-content-editorial-medium", + "font_size": "--gnrc-font-size-content-h4", + "line_height": "--gnrc-line-height-content-h4", + "letter_spacing": "--gnrc-letter-spacing-content-h4", + "optical_size": 36 + }, + { + "name": "textstyle-content-editorial-h5", + "font_family": "--gnrc-font-family-content-editorial", + "font_weight": "--gnrc-font-weight-content-editorial-medium", + "font_size": "--gnrc-font-size-content-h5", + "line_height": "--gnrc-line-height-content-h5", + "letter_spacing": "--gnrc-letter-spacing-content-h5", + "optical_size": 36 + }, + { + "name": "textstyle-content-editorial-subheadline", + "font_family": "--gnrc-font-family-content-editorial", + "font_weight": "--gnrc-font-weight-content-editorial-regular", + "font_size": "--gnrc-font-size-content-subheadline", + "line_height": "--gnrc-line-height-content-subheadline", + "letter_spacing": "--gnrc-letter-spacing-content-subheadline", + "optical_size": 36 + } + ] +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback-dark.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback-dark.css new file mode 100644 index 0000000000..6d51a1eb18 --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback-dark.css @@ -0,0 +1,130 @@ +/* Fluent Design — Warm Interaction Fallback (Dark Theme) — precomputed hex and shadows for non-OKLCH environments + * Auto-generated by scripts/build.mjs — do not edit manually. + */ + +[data-theme="dark"] { + --gnrc-color-surface-neutral-farther-hover: #342d29; + --gnrc-color-surface-neutral-farther-pressed: #4b423d; + --gnrc-color-surface-neutral-far-hover: #38312b; + --gnrc-color-surface-neutral-far-pressed: #4d453e; + --gnrc-color-surface-neutral-near-hover: #322b27; + --gnrc-color-surface-neutral-near-pressed: #4b413c; + --gnrc-color-surface-neutral-nearer-hover: #403832; + --gnrc-color-surface-neutral-nearer-pressed: #534941; + --gnrc-color-surface-neutral-translucent-hover: #02010188; + --gnrc-color-surface-neutral-translucent-pressed: #0e0b0c8f; + --gnrc-color-background-neutral-heavy-hover: #f6f5f3; + --gnrc-color-background-neutral-heavy-pressed: #edebe7; + --gnrc-color-background-neutral-loud-hover: #f3dfd29a; + --gnrc-color-background-neutral-loud-pressed: #e6d0c09a; + --gnrc-color-background-neutral-soft-hover: #fde1c548; + --gnrc-color-background-neutral-soft-pressed: #ffdec44f; + --gnrc-color-background-neutral-subtle-hover: #ffe8e81c; + --gnrc-color-background-neutral-subtle-pressed: #ffdfdf23; + --gnrc-color-background-neutral-transparent-hover: #fbfaf808; + --gnrc-color-background-neutral-transparent-pressed: #fefcf80f; + --gnrc-color-background-neutral-translucent-hover: #52524e88; + --gnrc-color-background-neutral-translucent-pressed: #67665e8f; + --gnrc-color-background-brand-heavy-hover: #f6f5f3; + --gnrc-color-background-brand-heavy-pressed: #edebe7; + --gnrc-color-background-brand-loud-hover: #f3dfd29a; + --gnrc-color-background-brand-loud-pressed: #e6d0c09a; + --gnrc-color-background-brand-soft-hover: #fde1c548; + --gnrc-color-background-brand-soft-pressed: #ffdec44f; + --gnrc-color-background-brand-subtle-hover: #ffe8e81c; + --gnrc-color-background-brand-subtle-pressed: #ffdfdf23; + --gnrc-color-background-brand-transparent-hover: #fbfaf808; + --gnrc-color-background-brand-transparent-pressed: #fefcf80f; + --gnrc-color-background-danger-loud-hover: #dd5170; + --gnrc-color-background-danger-loud-pressed: #d54467; + --gnrc-color-background-danger-soft-hover: #68343d; + --gnrc-color-background-danger-soft-pressed: #773f49; + --gnrc-color-background-danger-subtle-hover: #523338; + --gnrc-color-background-danger-subtle-pressed: #644247; + --gnrc-color-background-warning-loud-hover: #dd5b28; + --gnrc-color-background-warning-loud-pressed: #d54f13; + --gnrc-color-background-warning-soft-hover: #673726; + --gnrc-color-background-warning-soft-pressed: #764331; + --gnrc-color-background-warning-subtle-hover: #52352b; + --gnrc-color-background-warning-subtle-pressed: #644439; + --gnrc-color-background-success-loud-hover: #00a468; + --gnrc-color-background-success-loud-pressed: #009c5e; + --gnrc-color-background-success-soft-hover: #185338; + --gnrc-color-background-success-soft-pressed: #246043; + --gnrc-color-background-success-subtle-hover: #274435; + --gnrc-color-background-success-subtle-pressed: #355544; + --gnrc-color-stroke-neutral-heavy-hover: #dbd2cb; + --gnrc-color-stroke-neutral-heavy-pressed: #d3c8c0; + --gnrc-color-stroke-neutral-loud-hover: #92877e; + --gnrc-color-stroke-neutral-loud-pressed: #8b7d74; + --gnrc-color-stroke-neutral-soft-hover: #ffe6cf64; + --gnrc-color-stroke-neutral-soft-pressed: #ffe8d06b; + --gnrc-color-stroke-neutral-subtle-hover: #fde1c548; + --gnrc-color-stroke-neutral-subtle-pressed: #ffdec44f; + --gnrc-color-stroke-neutral-transparent-hover: #fbfaf808; + --gnrc-color-stroke-neutral-transparent-pressed: #fefcf80f; + --gnrc-color-stroke-neutral-onloud-hover: #000000e1; + --gnrc-color-stroke-neutral-onloud-pressed: #000000e1; + --gnrc-color-stroke-brand-loud-hover: #92877e; + --gnrc-color-stroke-brand-loud-pressed: #8b7d74; + --gnrc-color-stroke-brand-soft-hover: #ffe6cf64; + --gnrc-color-stroke-brand-soft-pressed: #ffe8d06b; + --gnrc-color-stroke-brand-subtle-hover: #fde1c548; + --gnrc-color-stroke-brand-subtle-pressed: #ffdec44f; + --gnrc-color-stroke-brand-onloud-hover: #000000e1; + --gnrc-color-stroke-brand-onloud-pressed: #000000e1; + --gnrc-color-stroke-danger-loud-hover: #dd5170; + --gnrc-color-stroke-danger-loud-pressed: #d54467; + --gnrc-color-stroke-danger-soft-hover: #de486c; + --gnrc-color-stroke-danger-soft-pressed: #eb4f74; + --gnrc-color-stroke-danger-subtle-hover: #813041; + --gnrc-color-stroke-danger-subtle-pressed: #8c3749; + --gnrc-color-stroke-danger-onloud-hover: #141312; + --gnrc-color-stroke-danger-onloud-pressed: #060504; + --gnrc-color-stroke-warning-loud-hover: #dd5b28; + --gnrc-color-stroke-warning-loud-pressed: #d54f13; + --gnrc-color-stroke-warning-soft-hover: #da4f11; + --gnrc-color-stroke-warning-soft-pressed: #e75618; + --gnrc-color-stroke-warning-subtle-hover: #813518; + --gnrc-color-stroke-warning-subtle-pressed: #8c3c1e; + --gnrc-color-stroke-warning-onloud-hover: #141312; + --gnrc-color-stroke-warning-onloud-pressed: #060504; + --gnrc-color-stroke-success-loud-hover: #00a468; + --gnrc-color-stroke-success-loud-pressed: #009c5e; + --gnrc-color-stroke-success-soft-hover: #089863; + --gnrc-color-stroke-success-soft-pressed: #11a26b; + --gnrc-color-stroke-success-subtle-hover: #0a5f3d; + --gnrc-color-stroke-success-subtle-pressed: #136844; + --gnrc-color-stroke-success-onloud-hover: #141312; + --gnrc-color-stroke-success-onloud-pressed: #060504; + --gnrc-color-foreground-neutral-primary-hover: #fff8f2eb; + --gnrc-color-foreground-neutral-primary-pressed: #fffaf2f2; + --gnrc-color-foreground-neutral-secondary-hover: #fff7ebbd; + --gnrc-color-foreground-neutral-secondary-pressed: #fff9ecc4; + --gnrc-color-foreground-neutral-tertiary-hover: #fff6eaa2; + --gnrc-color-foreground-neutral-tertiary-pressed: #fff8eaa9; + --gnrc-color-foreground-neutral-onloud-hover: #010000e1; + --gnrc-color-foreground-neutral-onloud-pressed: #000000e1; + --gnrc-color-foreground-brand-primary-hover: #fff8f2eb; + --gnrc-color-foreground-brand-primary-pressed: #fffaf2f2; + --gnrc-color-foreground-brand-onloud-hover: #010000e1; + --gnrc-color-foreground-brand-onloud-pressed: #000000e1; + --gnrc-color-foreground-danger-primary-hover: #ff96aa; + --gnrc-color-foreground-danger-primary-pressed: #ff9db2; + --gnrc-color-foreground-danger-onloud-hover: #000000db; + --gnrc-color-foreground-danger-onloud-pressed: #000000db; + --gnrc-color-foreground-warning-primary-hover: #ff9d77; + --gnrc-color-foreground-warning-primary-pressed: #ffa57d; + --gnrc-color-foreground-warning-onloud-hover: #000000db; + --gnrc-color-foreground-warning-onloud-pressed: #000000db; + --gnrc-color-foreground-success-primary-hover: #62d99f; + --gnrc-color-foreground-success-primary-pressed: #67e4a7; + --gnrc-color-foreground-success-onloud-hover: #000000db; + --gnrc-color-foreground-success-onloud-pressed: #000000db; + --gnrc-shadow-lowest: 0px 0px 2px #00000033, 0px 1px 2px #0000001a; + --gnrc-shadow-lower: 0px 0px 2px #00000033, 0px 2px 4px #00000029; + --gnrc-shadow-low: 0px 0px 2px #00000033, 0px 2px 4px #0000001f, 0px 4px 8px #00000029; + --gnrc-shadow-high: 0px 0px 2px #00000033, 0px 4px 8px #0000001f, 0px 8px 16px #0000001f; + --gnrc-shadow-higher: 0px 0px 2px #00000033, 0px 8px 16px #0000001f, 0px 16px 32px #0000001f; + --gnrc-shadow-highest: 0px 0px 2px #00000033, 0px 8px 16px #0000001f, 0px 32px 64px #0000001f; +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback-light.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback-light.css new file mode 100644 index 0000000000..ffb1ef7e3e --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback-light.css @@ -0,0 +1,130 @@ +/* Fluent Design — Warm Interaction Fallback (Light Theme) — precomputed hex and shadows for non-OKLCH environments + * Auto-generated by scripts/build.mjs — do not edit manually. + */ + +:root, [data-theme="light"] { + --gnrc-color-surface-neutral-farther-hover: #e8e0d9; + --gnrc-color-surface-neutral-farther-pressed: #dfd6ce; + --gnrc-color-surface-neutral-far-hover: #f2eae4; + --gnrc-color-surface-neutral-far-pressed: #e9dfd9; + --gnrc-color-surface-neutral-near-hover: #ede7e0; + --gnrc-color-surface-neutral-near-pressed: #e5ddd4; + --gnrc-color-surface-neutral-nearer-hover: #f6f5f3; + --gnrc-color-surface-neutral-nearer-pressed: #edebe7; + --gnrc-color-surface-neutral-translucent-hover: #f7f6f48a; + --gnrc-color-surface-neutral-translucent-pressed: #f0eeea94; + --gnrc-color-background-neutral-heavy-hover: #3b352e; + --gnrc-color-background-neutral-heavy-pressed: #50473f; + --gnrc-color-background-neutral-loud-hover: #2e1a0a9a; + --gnrc-color-background-neutral-loud-pressed: #3f28169a; + --gnrc-color-background-neutral-soft-hover: #61330f32; + --gnrc-color-background-neutral-soft-pressed: #6a3b193c; + --gnrc-color-background-neutral-subtle-hover: #7f471c24; + --gnrc-color-background-neutral-subtle-pressed: #8b53272e; + --gnrc-color-background-neutral-transparent-hover: #231d170a; + --gnrc-color-background-neutral-transparent-pressed: #1e170f14; + --gnrc-color-background-neutral-translucent-hover: #dcdcd68a; + --gnrc-color-background-neutral-translucent-pressed: #d2cfc894; + --gnrc-color-background-brand-heavy-hover: #3b352e; + --gnrc-color-background-brand-heavy-pressed: #50473f; + --gnrc-color-background-brand-loud-hover: #2e1a0a9a; + --gnrc-color-background-brand-loud-pressed: #3f28169a; + --gnrc-color-background-brand-soft-hover: #61330f32; + --gnrc-color-background-brand-soft-pressed: #6a3b193c; + --gnrc-color-background-brand-subtle-hover: #7f471c24; + --gnrc-color-background-brand-subtle-pressed: #8b53272e; + --gnrc-color-background-brand-transparent-hover: #231d170a; + --gnrc-color-background-brand-transparent-pressed: #1e170f14; + --gnrc-color-background-danger-loud-hover: #cd355e; + --gnrc-color-background-danger-loud-pressed: #da3c65; + --gnrc-color-background-danger-soft-hover: #f7d8dc; + --gnrc-color-background-danger-soft-pressed: #efced1; + --gnrc-color-background-danger-subtle-hover: #f7e6e9; + --gnrc-color-background-danger-subtle-pressed: #efdcde; + --gnrc-color-background-warning-loud-hover: #c84709; + --gnrc-color-background-warning-loud-pressed: #d54e11; + --gnrc-color-background-warning-soft-hover: #f7dbd1; + --gnrc-color-background-warning-soft-pressed: #eed0c6; + --gnrc-color-background-warning-subtle-hover: #f7e7e3; + --gnrc-color-background-warning-subtle-pressed: #efddd7; + --gnrc-color-background-success-loud-hover: #088e5c; + --gnrc-color-background-success-loud-pressed: #119864; + --gnrc-color-background-success-soft-hover: #bdefd3; + --gnrc-color-background-success-soft-pressed: #b2e5c8; + --gnrc-color-background-success-subtle-hover: #d7f3e3; + --gnrc-color-background-success-subtle-pressed: #cce9d9; + --gnrc-color-stroke-neutral-heavy-hover: #3b352e; + --gnrc-color-stroke-neutral-heavy-pressed: #50473f; + --gnrc-color-stroke-neutral-loud-hover: #81756c; + --gnrc-color-stroke-neutral-loud-pressed: #8c7e73; + --gnrc-color-stroke-neutral-soft-hover: #2a120280; + --gnrc-color-stroke-neutral-soft-pressed: #2e16048a; + --gnrc-color-stroke-neutral-subtle-hover: #61330f32; + --gnrc-color-stroke-neutral-subtle-pressed: #6a3b193c; + --gnrc-color-stroke-neutral-transparent-hover: #231d170a; + --gnrc-color-stroke-neutral-transparent-pressed: #1e170f14; + --gnrc-color-stroke-neutral-onloud-hover: #fffffd; + --gnrc-color-stroke-neutral-onloud-pressed: #fffffb; + --gnrc-color-stroke-brand-loud-hover: #81756c; + --gnrc-color-stroke-brand-loud-pressed: #8c7e73; + --gnrc-color-stroke-brand-soft-hover: #2a120280; + --gnrc-color-stroke-brand-soft-pressed: #2e16048a; + --gnrc-color-stroke-brand-subtle-hover: #61330f32; + --gnrc-color-stroke-brand-subtle-pressed: #6a3b193c; + --gnrc-color-stroke-brand-onloud-hover: #fffffd; + --gnrc-color-stroke-brand-onloud-pressed: #fffffb; + --gnrc-color-stroke-danger-loud-hover: #cd355e; + --gnrc-color-stroke-danger-loud-pressed: #da3c65; + --gnrc-color-stroke-danger-soft-hover: #dd5170; + --gnrc-color-stroke-danger-soft-pressed: #d54467; + --gnrc-color-stroke-danger-subtle-hover: #f7c5cc; + --gnrc-color-stroke-danger-subtle-pressed: #eebbc2; + --gnrc-color-stroke-danger-onloud-hover: #fffffd; + --gnrc-color-stroke-danger-onloud-pressed: #fffffb; + --gnrc-color-stroke-warning-loud-hover: #da4f11; + --gnrc-color-stroke-warning-loud-pressed: #e75618; + --gnrc-color-stroke-warning-soft-hover: #f48a65; + --gnrc-color-stroke-warning-soft-pressed: #ec7f58; + --gnrc-color-stroke-warning-subtle-hover: #f7c9b9; + --gnrc-color-stroke-warning-subtle-pressed: #eebeae; + --gnrc-color-stroke-warning-onloud-hover: #fffffd; + --gnrc-color-stroke-warning-onloud-pressed: #fffffb; + --gnrc-color-stroke-success-loud-hover: #088e5c; + --gnrc-color-stroke-success-loud-pressed: #119864; + --gnrc-color-stroke-success-soft-hover: #4cc58d; + --gnrc-color-stroke-success-soft-pressed: #39bc82; + --gnrc-color-stroke-success-subtle-hover: #a5e6c2; + --gnrc-color-stroke-success-subtle-pressed: #9adcb7; + --gnrc-color-stroke-success-onloud-hover: #fffffd; + --gnrc-color-stroke-success-onloud-pressed: #fffffb; + --gnrc-color-foreground-neutral-primary-hover: #060300eb; + --gnrc-color-foreground-neutral-primary-pressed: #040100f5; + --gnrc-color-foreground-neutral-secondary-hover: #0a0100b5; + --gnrc-color-foreground-neutral-secondary-pressed: #060000bf; + --gnrc-color-foreground-neutral-tertiary-hover: #0c0100a4; + --gnrc-color-foreground-neutral-tertiary-pressed: #080000ae; + --gnrc-color-foreground-neutral-onloud-hover: #fffffd; + --gnrc-color-foreground-neutral-onloud-pressed: #fffffb; + --gnrc-color-foreground-brand-primary-hover: #060300eb; + --gnrc-color-foreground-brand-primary-pressed: #040100f5; + --gnrc-color-foreground-brand-onloud-hover: #fffffd; + --gnrc-color-foreground-brand-onloud-pressed: #fffffb; + --gnrc-color-foreground-danger-primary-hover: #9e0b3e; + --gnrc-color-foreground-danger-primary-pressed: #950035; + --gnrc-color-foreground-danger-onloud-hover: #fffffd; + --gnrc-color-foreground-danger-onloud-pressed: #fffffb; + --gnrc-color-foreground-warning-primary-hover: #a12c00; + --gnrc-color-foreground-warning-primary-pressed: #991c00; + --gnrc-color-foreground-warning-onloud-hover: #fffffd; + --gnrc-color-foreground-warning-onloud-pressed: #fffffb; + --gnrc-color-foreground-success-primary-hover: #00683f; + --gnrc-color-foreground-success-primary-pressed: #006036; + --gnrc-color-foreground-success-onloud-hover: #fffffd; + --gnrc-color-foreground-success-onloud-pressed: #fffffb; + --gnrc-shadow-lowest: 0px 0px 2px #0000001a, 0px 1px 2px #0000000d; + --gnrc-shadow-lower: 0px 0px 2px #0000001a, 0px 2px 4px #00000014; + --gnrc-shadow-low: 0px 0px 2px #0000001a, 0px 2px 4px #00000008, 0px 4px 8px #00000014; + --gnrc-shadow-high: 0px 0px 2px #0000001a, 0px 4px 8px #00000008, 0px 8px 16px #0000000f; + --gnrc-shadow-higher: 0px 0px 2px #0000001a, 0px 8px 16px #00000008, 0px 16px 32px #0000000f; + --gnrc-shadow-highest: 0px 0px 2px #0000001a, 0px 8px 16px #00000008, 0px 32px 64px #0000000f; +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback.css new file mode 100644 index 0000000000..6dbe4a963f --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback.css @@ -0,0 +1,130 @@ +/* Fluent Design — Warm Interaction Fallback (Light-Dark Adaptive) — precomputed hex and shadows for non-OKLCH environments + * Auto-generated by scripts/build.mjs — do not edit manually. + */ + +:root { + --gnrc-color-surface-neutral-farther-hover: light-dark(#e8e0d9, #342d29); + --gnrc-color-surface-neutral-farther-pressed: light-dark(#dfd6ce, #4b423d); + --gnrc-color-surface-neutral-far-hover: light-dark(#f2eae4, #38312b); + --gnrc-color-surface-neutral-far-pressed: light-dark(#e9dfd9, #4d453e); + --gnrc-color-surface-neutral-near-hover: light-dark(#ede7e0, #322b27); + --gnrc-color-surface-neutral-near-pressed: light-dark(#e5ddd4, #4b413c); + --gnrc-color-surface-neutral-nearer-hover: light-dark(#f6f5f3, #403832); + --gnrc-color-surface-neutral-nearer-pressed: light-dark(#edebe7, #534941); + --gnrc-color-surface-neutral-translucent-hover: light-dark(#f7f6f48a, #02010188); + --gnrc-color-surface-neutral-translucent-pressed: light-dark(#f0eeea94, #0e0b0c8f); + --gnrc-color-background-neutral-heavy-hover: light-dark(#3b352e, #f6f5f3); + --gnrc-color-background-neutral-heavy-pressed: light-dark(#50473f, #edebe7); + --gnrc-color-background-neutral-loud-hover: light-dark(#2e1a0a9a, #f3dfd29a); + --gnrc-color-background-neutral-loud-pressed: light-dark(#3f28169a, #e6d0c09a); + --gnrc-color-background-neutral-soft-hover: light-dark(#61330f32, #fde1c548); + --gnrc-color-background-neutral-soft-pressed: light-dark(#6a3b193c, #ffdec44f); + --gnrc-color-background-neutral-subtle-hover: light-dark(#7f471c24, #ffe8e81c); + --gnrc-color-background-neutral-subtle-pressed: light-dark(#8b53272e, #ffdfdf23); + --gnrc-color-background-neutral-transparent-hover: light-dark(#231d170a, #fbfaf808); + --gnrc-color-background-neutral-transparent-pressed: light-dark(#1e170f14, #fefcf80f); + --gnrc-color-background-neutral-translucent-hover: light-dark(#dcdcd68a, #52524e88); + --gnrc-color-background-neutral-translucent-pressed: light-dark(#d2cfc894, #67665e8f); + --gnrc-color-background-brand-heavy-hover: light-dark(#3b352e, #f6f5f3); + --gnrc-color-background-brand-heavy-pressed: light-dark(#50473f, #edebe7); + --gnrc-color-background-brand-loud-hover: light-dark(#2e1a0a9a, #f3dfd29a); + --gnrc-color-background-brand-loud-pressed: light-dark(#3f28169a, #e6d0c09a); + --gnrc-color-background-brand-soft-hover: light-dark(#61330f32, #fde1c548); + --gnrc-color-background-brand-soft-pressed: light-dark(#6a3b193c, #ffdec44f); + --gnrc-color-background-brand-subtle-hover: light-dark(#7f471c24, #ffe8e81c); + --gnrc-color-background-brand-subtle-pressed: light-dark(#8b53272e, #ffdfdf23); + --gnrc-color-background-brand-transparent-hover: light-dark(#231d170a, #fbfaf808); + --gnrc-color-background-brand-transparent-pressed: light-dark(#1e170f14, #fefcf80f); + --gnrc-color-background-danger-loud-hover: light-dark(#cd355e, #dd5170); + --gnrc-color-background-danger-loud-pressed: light-dark(#da3c65, #d54467); + --gnrc-color-background-danger-soft-hover: light-dark(#f7d8dc, #68343d); + --gnrc-color-background-danger-soft-pressed: light-dark(#efced1, #773f49); + --gnrc-color-background-danger-subtle-hover: light-dark(#f7e6e9, #523338); + --gnrc-color-background-danger-subtle-pressed: light-dark(#efdcde, #644247); + --gnrc-color-background-warning-loud-hover: light-dark(#c84709, #dd5b28); + --gnrc-color-background-warning-loud-pressed: light-dark(#d54e11, #d54f13); + --gnrc-color-background-warning-soft-hover: light-dark(#f7dbd1, #673726); + --gnrc-color-background-warning-soft-pressed: light-dark(#eed0c6, #764331); + --gnrc-color-background-warning-subtle-hover: light-dark(#f7e7e3, #52352b); + --gnrc-color-background-warning-subtle-pressed: light-dark(#efddd7, #644439); + --gnrc-color-background-success-loud-hover: light-dark(#088e5c, #00a468); + --gnrc-color-background-success-loud-pressed: light-dark(#119864, #009c5e); + --gnrc-color-background-success-soft-hover: light-dark(#bdefd3, #185338); + --gnrc-color-background-success-soft-pressed: light-dark(#b2e5c8, #246043); + --gnrc-color-background-success-subtle-hover: light-dark(#d7f3e3, #274435); + --gnrc-color-background-success-subtle-pressed: light-dark(#cce9d9, #355544); + --gnrc-color-stroke-neutral-heavy-hover: light-dark(#3b352e, #dbd2cb); + --gnrc-color-stroke-neutral-heavy-pressed: light-dark(#50473f, #d3c8c0); + --gnrc-color-stroke-neutral-loud-hover: light-dark(#81756c, #92877e); + --gnrc-color-stroke-neutral-loud-pressed: light-dark(#8c7e73, #8b7d74); + --gnrc-color-stroke-neutral-soft-hover: light-dark(#2a120280, #ffe6cf64); + --gnrc-color-stroke-neutral-soft-pressed: light-dark(#2e16048a, #ffe8d06b); + --gnrc-color-stroke-neutral-subtle-hover: light-dark(#61330f32, #fde1c548); + --gnrc-color-stroke-neutral-subtle-pressed: light-dark(#6a3b193c, #ffdec44f); + --gnrc-color-stroke-neutral-transparent-hover: light-dark(#231d170a, #fbfaf808); + --gnrc-color-stroke-neutral-transparent-pressed: light-dark(#1e170f14, #fefcf80f); + --gnrc-color-stroke-neutral-onloud-hover: light-dark(#fffffd, #000000e1); + --gnrc-color-stroke-neutral-onloud-pressed: light-dark(#fffffb, #000000e1); + --gnrc-color-stroke-brand-loud-hover: light-dark(#81756c, #92877e); + --gnrc-color-stroke-brand-loud-pressed: light-dark(#8c7e73, #8b7d74); + --gnrc-color-stroke-brand-soft-hover: light-dark(#2a120280, #ffe6cf64); + --gnrc-color-stroke-brand-soft-pressed: light-dark(#2e16048a, #ffe8d06b); + --gnrc-color-stroke-brand-subtle-hover: light-dark(#61330f32, #fde1c548); + --gnrc-color-stroke-brand-subtle-pressed: light-dark(#6a3b193c, #ffdec44f); + --gnrc-color-stroke-brand-onloud-hover: light-dark(#fffffd, #000000e1); + --gnrc-color-stroke-brand-onloud-pressed: light-dark(#fffffb, #000000e1); + --gnrc-color-stroke-danger-loud-hover: light-dark(#cd355e, #dd5170); + --gnrc-color-stroke-danger-loud-pressed: light-dark(#da3c65, #d54467); + --gnrc-color-stroke-danger-soft-hover: light-dark(#dd5170, #de486c); + --gnrc-color-stroke-danger-soft-pressed: light-dark(#d54467, #eb4f74); + --gnrc-color-stroke-danger-subtle-hover: light-dark(#f7c5cc, #813041); + --gnrc-color-stroke-danger-subtle-pressed: light-dark(#eebbc2, #8c3749); + --gnrc-color-stroke-danger-onloud-hover: light-dark(#fffffd, #141312); + --gnrc-color-stroke-danger-onloud-pressed: light-dark(#fffffb, #060504); + --gnrc-color-stroke-warning-loud-hover: light-dark(#da4f11, #dd5b28); + --gnrc-color-stroke-warning-loud-pressed: light-dark(#e75618, #d54f13); + --gnrc-color-stroke-warning-soft-hover: light-dark(#f48a65, #da4f11); + --gnrc-color-stroke-warning-soft-pressed: light-dark(#ec7f58, #e75618); + --gnrc-color-stroke-warning-subtle-hover: light-dark(#f7c9b9, #813518); + --gnrc-color-stroke-warning-subtle-pressed: light-dark(#eebeae, #8c3c1e); + --gnrc-color-stroke-warning-onloud-hover: light-dark(#fffffd, #141312); + --gnrc-color-stroke-warning-onloud-pressed: light-dark(#fffffb, #060504); + --gnrc-color-stroke-success-loud-hover: light-dark(#088e5c, #00a468); + --gnrc-color-stroke-success-loud-pressed: light-dark(#119864, #009c5e); + --gnrc-color-stroke-success-soft-hover: light-dark(#4cc58d, #089863); + --gnrc-color-stroke-success-soft-pressed: light-dark(#39bc82, #11a26b); + --gnrc-color-stroke-success-subtle-hover: light-dark(#a5e6c2, #0a5f3d); + --gnrc-color-stroke-success-subtle-pressed: light-dark(#9adcb7, #136844); + --gnrc-color-stroke-success-onloud-hover: light-dark(#fffffd, #141312); + --gnrc-color-stroke-success-onloud-pressed: light-dark(#fffffb, #060504); + --gnrc-color-foreground-neutral-primary-hover: light-dark(#060300eb, #fff8f2eb); + --gnrc-color-foreground-neutral-primary-pressed: light-dark(#040100f5, #fffaf2f2); + --gnrc-color-foreground-neutral-secondary-hover: light-dark(#0a0100b5, #fff7ebbd); + --gnrc-color-foreground-neutral-secondary-pressed: light-dark(#060000bf, #fff9ecc4); + --gnrc-color-foreground-neutral-tertiary-hover: light-dark(#0c0100a4, #fff6eaa2); + --gnrc-color-foreground-neutral-tertiary-pressed: light-dark(#080000ae, #fff8eaa9); + --gnrc-color-foreground-neutral-onloud-hover: light-dark(#fffffd, #010000e1); + --gnrc-color-foreground-neutral-onloud-pressed: light-dark(#fffffb, #000000e1); + --gnrc-color-foreground-brand-primary-hover: light-dark(#060300eb, #fff8f2eb); + --gnrc-color-foreground-brand-primary-pressed: light-dark(#040100f5, #fffaf2f2); + --gnrc-color-foreground-brand-onloud-hover: light-dark(#fffffd, #010000e1); + --gnrc-color-foreground-brand-onloud-pressed: light-dark(#fffffb, #000000e1); + --gnrc-color-foreground-danger-primary-hover: light-dark(#9e0b3e, #ff96aa); + --gnrc-color-foreground-danger-primary-pressed: light-dark(#950035, #ff9db2); + --gnrc-color-foreground-danger-onloud-hover: light-dark(#fffffd, #000000db); + --gnrc-color-foreground-danger-onloud-pressed: light-dark(#fffffb, #000000db); + --gnrc-color-foreground-warning-primary-hover: light-dark(#a12c00, #ff9d77); + --gnrc-color-foreground-warning-primary-pressed: light-dark(#991c00, #ffa57d); + --gnrc-color-foreground-warning-onloud-hover: light-dark(#fffffd, #000000db); + --gnrc-color-foreground-warning-onloud-pressed: light-dark(#fffffb, #000000db); + --gnrc-color-foreground-success-primary-hover: light-dark(#00683f, #62d99f); + --gnrc-color-foreground-success-primary-pressed: light-dark(#006036, #67e4a7); + --gnrc-color-foreground-success-onloud-hover: light-dark(#fffffd, #000000db); + --gnrc-color-foreground-success-onloud-pressed: light-dark(#fffffb, #000000db); + --gnrc-shadow-lowest: 0px 0px 2px light-dark(#0000001a, #00000033), 0px 1px 2px light-dark(#0000000d, #0000001a); + --gnrc-shadow-lower: 0px 0px 2px light-dark(#0000001a, #00000033), 0px 2px 4px light-dark(#00000014, #00000029); + --gnrc-shadow-low: 0px 0px 2px light-dark(#0000001a, #00000033), 0px 2px 4px light-dark(#00000008, #0000001f), 0px 4px 8px light-dark(#00000014, #00000029); + --gnrc-shadow-high: 0px 0px 2px light-dark(#0000001a, #00000033), 0px 4px 8px light-dark(#00000008, #0000001f), 0px 8px 16px light-dark(#0000000f, #0000001f); + --gnrc-shadow-higher: 0px 0px 2px light-dark(#0000001a, #00000033), 0px 8px 16px light-dark(#00000008, #0000001f), 0px 16px 32px light-dark(#0000000f, #0000001f); + --gnrc-shadow-highest: 0px 0px 2px light-dark(#0000001a, #00000033), 0px 8px 16px light-dark(#00000008, #0000001f), 0px 32px 64px light-dark(#0000000f, #0000001f); +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic-dark.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic-dark.css new file mode 100644 index 0000000000..cacec7d267 --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic-dark.css @@ -0,0 +1,283 @@ +/* Fluent Design — Warm Semantic Tokens (Dark Theme) + * Auto-generated by scripts/build.mjs — do not edit manually. + */ + +[data-theme="dark"] { + --gnrc-color-fixed-white: #ffffff; + --gnrc-color-fixed-black: #000000; + --gnrc-color-expression-accent-heavy: #ffffff; + --gnrc-color-expression-accent-loud: #ffeee39a; + --gnrc-color-expression-accent-soft: #ffe3cb40; + --gnrc-color-expression-accent-subtle: #fff4ef14; + --gnrc-color-expression-achromatic-heavy: #ffffff; + --gnrc-color-expression-achromatic-subtle: #000000; + --gnrc-color-expression-gray-heavy: #f5f5f5; + --gnrc-color-expression-gray-loud: #dedede; + --gnrc-color-expression-gray-soft: #929292; + --gnrc-color-expression-gray-subtle: #484848; + --gnrc-color-expression-navy-heavy: #f0f5ff; + --gnrc-color-expression-navy-loud: #cedeff; + --gnrc-color-expression-navy-soft: #5c8df8; + --gnrc-color-expression-navy-subtle: #294482; + --gnrc-color-expression-blue-heavy: #eef6ff; + --gnrc-color-expression-blue-loud: #c6e1ff; + --gnrc-color-expression-blue-soft: #2f95f4; + --gnrc-color-expression-blue-subtle: #0b497f; + --gnrc-color-expression-green-heavy: #e7fce9; + --gnrc-color-expression-green-loud: #baedc1; + --gnrc-color-expression-green-soft: #32ad52; + --gnrc-color-expression-green-subtle: #0c5722; + --gnrc-color-expression-lime-heavy: #e6ffcf; + --gnrc-color-expression-lime-loud: #cbff93; + --gnrc-color-expression-lime-soft: #6da603; + --gnrc-color-expression-lime-subtle: #345200; + --gnrc-color-expression-yellow-heavy: #fff7c4; + --gnrc-color-expression-yellow-loud: #ffed85; + --gnrc-color-expression-yellow-soft: #fbdf06; + --gnrc-color-expression-yellow-subtle: #524800; + --gnrc-color-expression-pumpkin-heavy: #fef2ee; + --gnrc-color-expression-pumpkin-loud: #ffd3c2; + --gnrc-color-expression-pumpkin-soft: #fb966e; + --gnrc-color-expression-pumpkin-subtle: #762f0e; + --gnrc-color-expression-red-heavy: #fff2f0; + --gnrc-color-expression-red-loud: #ffd2cd; + --gnrc-color-expression-red-soft: #e7615b; + --gnrc-color-expression-red-subtle: #772b28; + --gnrc-color-expression-pink-heavy: #fff1f7; + --gnrc-color-expression-pink-loud: #ffcee6; + --gnrc-color-expression-pink-soft: #d961a6; + --gnrc-color-expression-pink-subtle: #6f2b53; + --gnrc-color-expression-purple-heavy: #f7f3ff; + --gnrc-color-expression-purple-loud: #e4d6ff; + --gnrc-color-expression-purple-soft: #a575e8; + --gnrc-color-expression-purple-subtle: #523778; + --gnrc-color-overlay-neutral-translucent: #00000099; + --gnrc-color-surface-neutral-farther: #1e1916; + --gnrc-color-surface-neutral-far: #231e1a; + --gnrc-color-surface-neutral-near: #1c1714; + --gnrc-color-surface-neutral-nearer: #2e2823; + --gnrc-color-surface-neutral-translucent: #00000080; + --gnrc-material-background-thick: #262626ea; + --gnrc-material-background-regular: #2f2f2fd1; + --gnrc-material-background-thin: #3434348b; + --gnrc-color-background-neutral-heavy: #ffffff; + --gnrc-color-background-neutral-loud: #ffeee39a; + --gnrc-color-background-neutral-soft: #ffe3cb40; + --gnrc-color-background-neutral-subtle: #fff4ef14; + --gnrc-color-background-neutral-transparent: #ffffff00; + --gnrc-color-background-neutral-translucent: #3c3c3c80; + --gnrc-color-background-neutral-disabled: #ffffff07; + --gnrc-color-background-neutral-heavy-disabled: #ffffff20; + --gnrc-color-background-neutral-subtle-disabled: #ffffff1b; + --gnrc-color-background-brand-heavy: #ffffff; + --gnrc-color-background-brand-loud: #ffeee39a; + --gnrc-color-background-brand-soft: #ffe3cb40; + --gnrc-color-background-brand-subtle: #fff4ef14; + --gnrc-color-background-brand-transparent: #ffffff00; + --gnrc-color-background-danger-loud: #e55e7a; + --gnrc-color-background-danger-soft: #5a2932; + --gnrc-color-background-danger-subtle: #402529; + --gnrc-color-background-warning-loud: #e56738; + --gnrc-color-background-warning-soft: #592c1c; + --gnrc-color-background-warning-subtle: #40261d; + --gnrc-color-background-success-loud: #05ad72; + --gnrc-color-background-success-soft: #0c462d; + --gnrc-color-background-success-subtle: #193426; + --gnrc-color-stroke-neutral-heavy: #e3dcd7; + --gnrc-color-stroke-neutral-loud: #9a9089; + --gnrc-color-stroke-neutral-soft: #ffe6d35c; + --gnrc-color-stroke-neutral-subtle: #ffe3cb40; + --gnrc-color-stroke-neutral-transparent: #ffffff00; + --gnrc-color-stroke-neutral-onloud: #0b0600e1; + --gnrc-color-stroke-neutral-disabled: #ffffff24; + --gnrc-color-stroke-brand-loud: #9a9089; + --gnrc-color-stroke-brand-soft: #ffe6d35c; + --gnrc-color-stroke-brand-subtle: #ffe3cb40; + --gnrc-color-stroke-brand-onloud: #0b0600e1; + --gnrc-color-stroke-danger-loud: #e55e7a; + --gnrc-color-stroke-danger-soft: #d14164; + --gnrc-color-stroke-danger-subtle: #76293a; + --gnrc-color-stroke-danger-onloud: #242424; + --gnrc-color-stroke-warning-loud: #e56738; + --gnrc-color-stroke-warning-soft: #cd4808; + --gnrc-color-stroke-warning-subtle: #762e12; + --gnrc-color-stroke-warning-onloud: #242424; + --gnrc-color-stroke-success-loud: #05ad72; + --gnrc-color-stroke-success-soft: #008e5c; + --gnrc-color-stroke-success-subtle: #025636; + --gnrc-color-stroke-success-onloud: #242424; + --gnrc-color-stroke-focus-inner: #000000; + --gnrc-color-stroke-focus-outer: #ffffff; + --gnrc-color-foreground-neutral-primary: #fff7f2e3; + --gnrc-color-foreground-neutral-secondary: #fff2e8b5; + --gnrc-color-foreground-neutral-tertiary: #ffeee39a; + --gnrc-color-foreground-neutral-onloud: #0b0600e1; + --gnrc-color-foreground-neutral-disabled: #ffffff61; + --gnrc-color-foreground-brand-primary: #fff7f2e3; + --gnrc-color-foreground-brand-onloud: #0b0600e1; + --gnrc-color-foreground-danger-primary: #fd8ea1; + --gnrc-color-foreground-danger-onloud: #000000db; + --gnrc-color-foreground-warning-primary: #fc9571; + --gnrc-color-foreground-warning-onloud: #000000db; + --gnrc-color-foreground-success-primary: #5dce97; + --gnrc-color-foreground-success-onloud: #000000db; + --gnrc-color-shadow: #000000; + --gnrc-shadow-lowest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%); + --gnrc-shadow-lower: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 16%); + --gnrc-shadow-low: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 16%); + --gnrc-shadow-high: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%); + --gnrc-shadow-higher: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 12%); + --gnrc-shadow-highest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 12%); + --gnrc-font-weight-functional-regular: 420; + --gnrc-font-weight-functional-medium: 550; + --gnrc-font-weight-functional-semibold: 600; + --gnrc-font-weight-functional-bold: 625; + --gnrc-font-weight-content-regular: 420; + --gnrc-font-weight-content-medium: 550; + --gnrc-font-weight-content-semibold: 600; + --gnrc-font-weight-content-bold: 625; + --gnrc-font-weight-content-editorial-regular: 420; + --gnrc-font-weight-content-editorial-medium: 550; + --gnrc-font-weight-content-editorial-semibold: 600; + --gnrc-font-weight-content-editorial-bold: 625; + --gnrc-font-family-functional: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; + --gnrc-font-family-content: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; + --gnrc-font-family-content-editorial: 'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif; + --gnrc-font-family-content-code: 'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace; + --gnrc-letter-spacing-functional-display: -0.0075em; + --gnrc-letter-spacing-functional-pagetitle: -0.0075em; + --gnrc-letter-spacing-functional-title-large: -0.0015em; + --gnrc-letter-spacing-functional-title-medium: -0.0015em; + --gnrc-letter-spacing-functional-title-small: -0.0015em; + --gnrc-letter-spacing-functional-subtitle: -0.0015em; + --gnrc-letter-spacing-functional-body-large: 0em; + --gnrc-letter-spacing-functional-body-medium: 0em; + --gnrc-letter-spacing-functional-body-small: 0em; + --gnrc-letter-spacing-functional-caption: 0em; + --gnrc-letter-spacing-content-statement: -0.0075em; + --gnrc-letter-spacing-content-expressive-large: -0.0075em; + --gnrc-letter-spacing-content-expressive-medium: -0.0015em; + --gnrc-letter-spacing-content-expressive-small: -0.0015em; + --gnrc-letter-spacing-content-h1: -0.0015em; + --gnrc-letter-spacing-content-h2: -0.0015em; + --gnrc-letter-spacing-content-h3: -0.0015em; + --gnrc-letter-spacing-content-h4: -0.0015em; + --gnrc-letter-spacing-content-h5: -0.0015em; + --gnrc-letter-spacing-content-subheadline: 0em; + --gnrc-letter-spacing-content-paragraph-large: 0em; + --gnrc-letter-spacing-content-paragraph-medium: 0em; + --gnrc-letter-spacing-content-paragraph-small: 0em; + --gnrc-letter-spacing-content-subtext: 0em; + --gnrc-letter-spacing-content-table: 0em; + --gnrc-letter-spacing-content-code: 0em; + --gnrc-font-size-functional-display: 4.25rem; + --gnrc-font-size-functional-pagetitle: 2.5rem; + --gnrc-font-size-functional-title-large: 2rem; + --gnrc-font-size-functional-title-medium: 1.75rem; + --gnrc-font-size-functional-title-small: 1.5rem; + --gnrc-font-size-functional-subtitle: 1.25rem; + --gnrc-font-size-functional-body-large: 1rem; + --gnrc-font-size-functional-body-medium: 0.875rem; + --gnrc-font-size-functional-body-small: 0.75rem; + --gnrc-font-size-functional-caption: 0.625rem; + --gnrc-font-size-content-statement: 3.5rem; + --gnrc-font-size-content-expressive-large: 3rem; + --gnrc-font-size-content-expressive-medium: 2.25rem; + --gnrc-font-size-content-expressive-small: 1.75rem; + --gnrc-font-size-content-h1: 2.25rem; + --gnrc-font-size-content-h2: 2rem; + --gnrc-font-size-content-h3: 1.75rem; + --gnrc-font-size-content-h4: 1.5rem; + --gnrc-font-size-content-h5: 1.25rem; + --gnrc-font-size-content-subheadline: 1rem; + --gnrc-font-size-content-paragraph-large: 1.25rem; + --gnrc-font-size-content-paragraph-medium: 1rem; + --gnrc-font-size-content-paragraph-small: 0.75rem; + --gnrc-font-size-content-subtext: 0.625rem; + --gnrc-font-size-content-table: 1rem; + --gnrc-font-size-content-code: 1rem; + --gnrc-line-height-functional-display: round(120%, 2px); + --gnrc-line-height-functional-pagetitle: round(120%, 2px); + --gnrc-line-height-functional-title-large: round(120%, 2px); + --gnrc-line-height-functional-title-medium: round(120%, 2px); + --gnrc-line-height-functional-title-small: round(120%, 2px); + --gnrc-line-height-functional-subtitle: round(140%, 2px); + --gnrc-line-height-functional-body-large: round(140%, 2px); + --gnrc-line-height-functional-body-medium: round(140%, 2px); + --gnrc-line-height-functional-body-small: round(140%, 2px); + --gnrc-line-height-functional-caption: round(140%, 2px); + --gnrc-line-height-content-statement: round(120%, 2px); + --gnrc-line-height-content-expressive-large: round(120%, 2px); + --gnrc-line-height-content-expressive-medium: round(120%, 2px); + --gnrc-line-height-content-expressive-small: round(120%, 2px); + --gnrc-line-height-content-h1: round(120%, 2px); + --gnrc-line-height-content-h2: round(120%, 2px); + --gnrc-line-height-content-h3: round(120%, 2px); + --gnrc-line-height-content-h4: round(120%, 2px); + --gnrc-line-height-content-h5: round(120%, 2px); + --gnrc-line-height-content-subheadline: round(140%, 2px); + --gnrc-line-height-content-paragraph-large: round(170%, 2px); + --gnrc-line-height-content-paragraph-medium: round(170%, 2px); + --gnrc-line-height-content-paragraph-small: round(170%, 2px); + --gnrc-line-height-content-subtext: round(140%, 2px); + --gnrc-line-height-content-table: round(140%, 2px); + --gnrc-line-height-content-code: round(140%, 2px); + --gnrc-border-radius-base-100: 4px; + --gnrc-border-radius-base-200: 8px; + --gnrc-border-radius-base-300: 12px; + --gnrc-border-radius-base-400: 16px; + --gnrc-border-radius-base-600: 24px; + --gnrc-border-radius-base-700: 28px; + --gnrc-border-radius-circular: 9999px; + --gnrc-spacing-component-base-50: 2px; + --gnrc-spacing-component-base-100: 4px; + --gnrc-spacing-component-base-150: 6px; + --gnrc-spacing-component-base-200: 8px; + --gnrc-spacing-component-base-250: 10px; + --gnrc-spacing-component-base-300: 12px; + --gnrc-spacing-component-base-400: 16px; + --gnrc-spacing-component-base-500: 20px; + --gnrc-spacing-component-base-600: 24px; + --gnrc-spacing-component-base-700: 28px; + --gnrc-spacing-component-base-800: 32px; + --gnrc-spacing-layout-base-100: 8px; + --gnrc-spacing-layout-base-200: 16px; + --gnrc-spacing-layout-base-300: 24px; + --gnrc-spacing-layout-base-400: 32px; + --gnrc-spacing-layout-base-450: 36px; + --gnrc-spacing-layout-base-500: 40px; + --gnrc-spacing-layout-base-600: 48px; + --gnrc-spacing-layout-base-700: 56px; + --gnrc-spacing-layout-base-800: 64px; + --gnrc-spacing-layout-base-1000: 80px; + --gnrc-spacing-layout-base-1200: 96px; + --gnrc-stroke-width-thin: 1px; + --gnrc-stroke-width-thick: 2px; + --gnrc-stroke-width-thicker: 3px; + --gnrc-stroke-width-thickest: 4px; + --gnrc-motion-duration-base-50: 50ms; + --gnrc-motion-duration-base-100: 100ms; + --gnrc-motion-duration-base-200: 200ms; + --gnrc-motion-duration-base-300: 300ms; + --gnrc-motion-duration-base-500: 500ms; + --gnrc-motion-duration-base-1000: 1000ms; + --gnrc-motion-easing-functional-enter: cubic-bezier(0, 0, 0, 1); + --gnrc-motion-easing-functional-exit: cubic-bezier(0.6, 0, 0.75, 0.4); + --gnrc-motion-easing-functional-transition: cubic-bezier(0.33, 0, 0, 1); + --gnrc-motion-easing-functional-linear: cubic-bezier(0, 0, 1, 1); + --gnrc-motion-easing-expressive-enter: cubic-bezier(0, 0, 0, 1); + --gnrc-motion-easing-expressive-exit: cubic-bezier(0.6, 0, 0.75, 0.4); + --gnrc-motion-easing-expressive-transition: cubic-bezier(0.33, 0, 0, 1); + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-hover: 0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-press: 0.06; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-hover: 0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-press: 0.06; + --interaction-standard-hover: min(calc(l + 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.985) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / calc(alpha + 0.03); + --interaction-standard-pressed: min(calc(l + 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.992) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / calc(alpha + 0.06); + --interaction-inverse-hover: calc(l - 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / alpha; + --interaction-inverse-pressed: calc(l - 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / alpha; +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic-light.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic-light.css new file mode 100644 index 0000000000..0c155116e8 --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic-light.css @@ -0,0 +1,283 @@ +/* Fluent Design — Warm Semantic Tokens (Light Theme) + * Auto-generated by scripts/build.mjs — do not edit manually. + */ + +:root, [data-theme="light"] { + --gnrc-color-fixed-white: #ffffff; + --gnrc-color-fixed-black: #000000; + --gnrc-color-expression-accent-heavy: #28231e; + --gnrc-color-expression-accent-loud: #1e0d009a; + --gnrc-color-expression-accent-soft: #4d200028; + --gnrc-color-expression-accent-subtle: #6c31001a; + --gnrc-color-expression-achromatic-heavy: #000000; + --gnrc-color-expression-achromatic-subtle: #ffffff; + --gnrc-color-expression-gray-heavy: #484848; + --gnrc-color-expression-gray-loud: #929292; + --gnrc-color-expression-gray-soft: #dedede; + --gnrc-color-expression-gray-subtle: #f5f5f5; + --gnrc-color-expression-navy-heavy: #294482; + --gnrc-color-expression-navy-loud: #5c8df8; + --gnrc-color-expression-navy-soft: #cedeff; + --gnrc-color-expression-navy-subtle: #f0f5ff; + --gnrc-color-expression-blue-heavy: #0b497f; + --gnrc-color-expression-blue-loud: #2f95f4; + --gnrc-color-expression-blue-soft: #c6e1ff; + --gnrc-color-expression-blue-subtle: #eef6ff; + --gnrc-color-expression-green-heavy: #0c5722; + --gnrc-color-expression-green-loud: #32ad52; + --gnrc-color-expression-green-soft: #baedc1; + --gnrc-color-expression-green-subtle: #e7fce9; + --gnrc-color-expression-lime-heavy: #345200; + --gnrc-color-expression-lime-loud: #6da603; + --gnrc-color-expression-lime-soft: #cbff93; + --gnrc-color-expression-lime-subtle: #e6ffcf; + --gnrc-color-expression-yellow-heavy: #524800; + --gnrc-color-expression-yellow-loud: #fbdf06; + --gnrc-color-expression-yellow-soft: #ffed85; + --gnrc-color-expression-yellow-subtle: #fff7c4; + --gnrc-color-expression-pumpkin-heavy: #762f0e; + --gnrc-color-expression-pumpkin-loud: #fb966e; + --gnrc-color-expression-pumpkin-soft: #ffd3c2; + --gnrc-color-expression-pumpkin-subtle: #fef2ee; + --gnrc-color-expression-red-heavy: #772b28; + --gnrc-color-expression-red-loud: #e7615b; + --gnrc-color-expression-red-soft: #ffd2cd; + --gnrc-color-expression-red-subtle: #fff2f0; + --gnrc-color-expression-pink-heavy: #6f2b53; + --gnrc-color-expression-pink-loud: #d961a6; + --gnrc-color-expression-pink-soft: #ffcee6; + --gnrc-color-expression-pink-subtle: #fff1f7; + --gnrc-color-expression-purple-heavy: #523778; + --gnrc-color-expression-purple-loud: #a575e8; + --gnrc-color-expression-purple-soft: #e4d6ff; + --gnrc-color-expression-purple-subtle: #f7f3ff; + --gnrc-color-overlay-neutral-translucent: #00000026; + --gnrc-color-surface-neutral-farther: #f0eae5; + --gnrc-color-surface-neutral-far: #faf4f0; + --gnrc-color-surface-neutral-near: #f6f1ec; + --gnrc-color-surface-neutral-nearer: #ffffff; + --gnrc-color-surface-neutral-translucent: #ffffff80; + --gnrc-material-background-thick: #fffffff1; + --gnrc-material-background-regular: #ffffffd7; + --gnrc-material-background-thin: #ffffff7e; + --gnrc-color-background-neutral-heavy: #28231e; + --gnrc-color-background-neutral-loud: #1e0d009a; + --gnrc-color-background-neutral-soft: #4d200028; + --gnrc-color-background-neutral-subtle: #6c31001a; + --gnrc-color-background-neutral-transparent: #28231e00; + --gnrc-color-background-neutral-translucent: #e9e9e980; + --gnrc-color-background-neutral-disabled: #00000008; + --gnrc-color-background-neutral-heavy-disabled: #0000001a; + --gnrc-color-background-neutral-subtle-disabled: #0000000d; + --gnrc-color-background-brand-heavy: #28231e; + --gnrc-color-background-brand-loud: #1e0d009a; + --gnrc-color-background-brand-soft: #4d200028; + --gnrc-color-background-brand-subtle: #6c31001a; + --gnrc-color-background-brand-transparent: #28231e00; + --gnrc-color-background-danger-loud: #c02e56; + --gnrc-color-background-danger-soft: #ffe3e6; + --gnrc-color-background-danger-subtle: #fff1f3; + --gnrc-color-background-warning-loud: #bb4001; + --gnrc-color-background-warning-soft: #ffe5dc; + --gnrc-color-background-warning-subtle: #fff2ee; + --gnrc-color-background-success-loud: #008455; + --gnrc-color-background-success-soft: #c9f8dd; + --gnrc-color-background-success-subtle: #e3fcee; + --gnrc-color-stroke-neutral-heavy: #28231e; + --gnrc-color-stroke-neutral-loud: #776d65; + --gnrc-color-stroke-neutral-soft: #250f0076; + --gnrc-color-stroke-neutral-subtle: #4d200028; + --gnrc-color-stroke-neutral-transparent: #28231e00; + --gnrc-color-stroke-neutral-onloud: #ffffffff; + --gnrc-color-stroke-neutral-disabled: #00000014; + --gnrc-color-stroke-brand-loud: #776d65; + --gnrc-color-stroke-brand-soft: #250f0076; + --gnrc-color-stroke-brand-subtle: #4d200028; + --gnrc-color-stroke-brand-onloud: #ffffffff; + --gnrc-color-stroke-danger-loud: #c02e56; + --gnrc-color-stroke-danger-soft: #e55e7a; + --gnrc-color-stroke-danger-subtle: #ffd0d6; + --gnrc-color-stroke-danger-onloud: #ffffff; + --gnrc-color-stroke-warning-loud: #cd4808; + --gnrc-color-stroke-warning-soft: #fc9571; + --gnrc-color-stroke-warning-subtle: #ffd3c4; + --gnrc-color-stroke-warning-onloud: #ffffff; + --gnrc-color-stroke-success-loud: #008455; + --gnrc-color-stroke-success-soft: #5dce97; + --gnrc-color-stroke-success-subtle: #b1efcc; + --gnrc-color-stroke-success-onloud: #ffffff; + --gnrc-color-stroke-focus-inner: #ffffff; + --gnrc-color-stroke-focus-outer: #000000; + --gnrc-color-foreground-neutral-primary: #0b0600e1; + --gnrc-color-foreground-neutral-secondary: #190c00ab; + --gnrc-color-foreground-neutral-tertiary: #1e0d009a; + --gnrc-color-foreground-neutral-onloud: #ffffffff; + --gnrc-color-foreground-neutral-disabled: #0000006d; + --gnrc-color-foreground-brand-primary: #0b0600e1; + --gnrc-color-foreground-brand-onloud: #ffffffff; + --gnrc-color-foreground-danger-primary: #a62147; + --gnrc-color-foreground-danger-onloud: #ffffff; + --gnrc-color-foreground-warning-primary: #a93901; + --gnrc-color-foreground-warning-onloud: #ffffff; + --gnrc-color-foreground-success-primary: #017048; + --gnrc-color-foreground-success-onloud: #ffffff; + --gnrc-color-shadow: #000000; + --gnrc-shadow-lowest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 5%); + --gnrc-shadow-lower: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 8%); + --gnrc-shadow-low: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 8%); + --gnrc-shadow-high: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-shadow-higher: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-shadow-highest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-font-weight-functional-regular: 420; + --gnrc-font-weight-functional-medium: 550; + --gnrc-font-weight-functional-semibold: 600; + --gnrc-font-weight-functional-bold: 625; + --gnrc-font-weight-content-regular: 420; + --gnrc-font-weight-content-medium: 550; + --gnrc-font-weight-content-semibold: 600; + --gnrc-font-weight-content-bold: 625; + --gnrc-font-weight-content-editorial-regular: 420; + --gnrc-font-weight-content-editorial-medium: 550; + --gnrc-font-weight-content-editorial-semibold: 600; + --gnrc-font-weight-content-editorial-bold: 625; + --gnrc-font-family-functional: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; + --gnrc-font-family-content: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; + --gnrc-font-family-content-editorial: 'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif; + --gnrc-font-family-content-code: 'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace; + --gnrc-letter-spacing-functional-display: -0.0075em; + --gnrc-letter-spacing-functional-pagetitle: -0.0075em; + --gnrc-letter-spacing-functional-title-large: -0.0015em; + --gnrc-letter-spacing-functional-title-medium: -0.0015em; + --gnrc-letter-spacing-functional-title-small: -0.0015em; + --gnrc-letter-spacing-functional-subtitle: -0.0015em; + --gnrc-letter-spacing-functional-body-large: 0em; + --gnrc-letter-spacing-functional-body-medium: 0em; + --gnrc-letter-spacing-functional-body-small: 0em; + --gnrc-letter-spacing-functional-caption: 0em; + --gnrc-letter-spacing-content-statement: -0.0075em; + --gnrc-letter-spacing-content-expressive-large: -0.0075em; + --gnrc-letter-spacing-content-expressive-medium: -0.0015em; + --gnrc-letter-spacing-content-expressive-small: -0.0015em; + --gnrc-letter-spacing-content-h1: -0.0015em; + --gnrc-letter-spacing-content-h2: -0.0015em; + --gnrc-letter-spacing-content-h3: -0.0015em; + --gnrc-letter-spacing-content-h4: -0.0015em; + --gnrc-letter-spacing-content-h5: -0.0015em; + --gnrc-letter-spacing-content-subheadline: 0em; + --gnrc-letter-spacing-content-paragraph-large: 0em; + --gnrc-letter-spacing-content-paragraph-medium: 0em; + --gnrc-letter-spacing-content-paragraph-small: 0em; + --gnrc-letter-spacing-content-subtext: 0em; + --gnrc-letter-spacing-content-table: 0em; + --gnrc-letter-spacing-content-code: 0em; + --gnrc-font-size-functional-display: 4.25rem; + --gnrc-font-size-functional-pagetitle: 2.5rem; + --gnrc-font-size-functional-title-large: 2rem; + --gnrc-font-size-functional-title-medium: 1.75rem; + --gnrc-font-size-functional-title-small: 1.5rem; + --gnrc-font-size-functional-subtitle: 1.25rem; + --gnrc-font-size-functional-body-large: 1rem; + --gnrc-font-size-functional-body-medium: 0.875rem; + --gnrc-font-size-functional-body-small: 0.75rem; + --gnrc-font-size-functional-caption: 0.625rem; + --gnrc-font-size-content-statement: 3.5rem; + --gnrc-font-size-content-expressive-large: 3rem; + --gnrc-font-size-content-expressive-medium: 2.25rem; + --gnrc-font-size-content-expressive-small: 1.75rem; + --gnrc-font-size-content-h1: 2.25rem; + --gnrc-font-size-content-h2: 2rem; + --gnrc-font-size-content-h3: 1.75rem; + --gnrc-font-size-content-h4: 1.5rem; + --gnrc-font-size-content-h5: 1.25rem; + --gnrc-font-size-content-subheadline: 1rem; + --gnrc-font-size-content-paragraph-large: 1.25rem; + --gnrc-font-size-content-paragraph-medium: 1rem; + --gnrc-font-size-content-paragraph-small: 0.75rem; + --gnrc-font-size-content-subtext: 0.625rem; + --gnrc-font-size-content-table: 1rem; + --gnrc-font-size-content-code: 1rem; + --gnrc-line-height-functional-display: round(120%, 2px); + --gnrc-line-height-functional-pagetitle: round(120%, 2px); + --gnrc-line-height-functional-title-large: round(120%, 2px); + --gnrc-line-height-functional-title-medium: round(120%, 2px); + --gnrc-line-height-functional-title-small: round(120%, 2px); + --gnrc-line-height-functional-subtitle: round(140%, 2px); + --gnrc-line-height-functional-body-large: round(140%, 2px); + --gnrc-line-height-functional-body-medium: round(140%, 2px); + --gnrc-line-height-functional-body-small: round(140%, 2px); + --gnrc-line-height-functional-caption: round(140%, 2px); + --gnrc-line-height-content-statement: round(120%, 2px); + --gnrc-line-height-content-expressive-large: round(120%, 2px); + --gnrc-line-height-content-expressive-medium: round(120%, 2px); + --gnrc-line-height-content-expressive-small: round(120%, 2px); + --gnrc-line-height-content-h1: round(120%, 2px); + --gnrc-line-height-content-h2: round(120%, 2px); + --gnrc-line-height-content-h3: round(120%, 2px); + --gnrc-line-height-content-h4: round(120%, 2px); + --gnrc-line-height-content-h5: round(120%, 2px); + --gnrc-line-height-content-subheadline: round(140%, 2px); + --gnrc-line-height-content-paragraph-large: round(170%, 2px); + --gnrc-line-height-content-paragraph-medium: round(170%, 2px); + --gnrc-line-height-content-paragraph-small: round(170%, 2px); + --gnrc-line-height-content-subtext: round(140%, 2px); + --gnrc-line-height-content-table: round(140%, 2px); + --gnrc-line-height-content-code: round(140%, 2px); + --gnrc-border-radius-base-100: 4px; + --gnrc-border-radius-base-200: 8px; + --gnrc-border-radius-base-300: 12px; + --gnrc-border-radius-base-400: 16px; + --gnrc-border-radius-base-600: 24px; + --gnrc-border-radius-base-700: 28px; + --gnrc-border-radius-circular: 9999px; + --gnrc-spacing-component-base-50: 2px; + --gnrc-spacing-component-base-100: 4px; + --gnrc-spacing-component-base-150: 6px; + --gnrc-spacing-component-base-200: 8px; + --gnrc-spacing-component-base-250: 10px; + --gnrc-spacing-component-base-300: 12px; + --gnrc-spacing-component-base-400: 16px; + --gnrc-spacing-component-base-500: 20px; + --gnrc-spacing-component-base-600: 24px; + --gnrc-spacing-component-base-700: 28px; + --gnrc-spacing-component-base-800: 32px; + --gnrc-spacing-layout-base-100: 8px; + --gnrc-spacing-layout-base-200: 16px; + --gnrc-spacing-layout-base-300: 24px; + --gnrc-spacing-layout-base-400: 32px; + --gnrc-spacing-layout-base-450: 36px; + --gnrc-spacing-layout-base-500: 40px; + --gnrc-spacing-layout-base-600: 48px; + --gnrc-spacing-layout-base-700: 56px; + --gnrc-spacing-layout-base-800: 64px; + --gnrc-spacing-layout-base-1000: 80px; + --gnrc-spacing-layout-base-1200: 96px; + --gnrc-stroke-width-thin: 1px; + --gnrc-stroke-width-thick: 2px; + --gnrc-stroke-width-thicker: 3px; + --gnrc-stroke-width-thickest: 4px; + --gnrc-motion-duration-base-50: 50ms; + --gnrc-motion-duration-base-100: 100ms; + --gnrc-motion-duration-base-200: 200ms; + --gnrc-motion-duration-base-300: 300ms; + --gnrc-motion-duration-base-500: 500ms; + --gnrc-motion-duration-base-1000: 1000ms; + --gnrc-motion-easing-functional-enter: cubic-bezier(0, 0, 0, 1); + --gnrc-motion-easing-functional-exit: cubic-bezier(0.6, 0, 0.75, 0.4); + --gnrc-motion-easing-functional-transition: cubic-bezier(0.33, 0, 0, 1); + --gnrc-motion-easing-functional-linear: cubic-bezier(0, 0, 1, 1); + --gnrc-motion-easing-expressive-enter: cubic-bezier(0, 0, 0, 1); + --gnrc-motion-easing-expressive-exit: cubic-bezier(0.6, 0, 0.75, 0.4); + --gnrc-motion-easing-expressive-transition: cubic-bezier(0.33, 0, 0, 1); + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-hover: -0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-press: -0.06; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-hover: 0.04; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-press: 0.08; + --interaction-standard-hover: max(calc(l - 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.1) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / calc(alpha + 0.04); + --interaction-standard-pressed: max(calc(l - 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.08) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / calc(alpha + 0.08); + --interaction-inverse-hover: calc(l + 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / alpha; + --interaction-inverse-pressed: calc(l + 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / alpha; +} diff --git a/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic.css b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic.css new file mode 100644 index 0000000000..dfe8416dff --- /dev/null +++ b/packages/agentic/design/scripts/token-mappings/__fixtures__/x3/warm/semantic.css @@ -0,0 +1,351 @@ +/* Fluent Design — Warm Semantic Tokens (Light-Dark Adaptive) + * Auto-generated by scripts/build.mjs — do not edit manually. + */ + +:root { + color-scheme: light dark; + --gnrc-color-fixed-white: #ffffff; + --gnrc-color-fixed-black: #000000; + --gnrc-color-expression-accent-heavy: light-dark(#28231e, #ffffff); + --gnrc-color-expression-accent-loud: light-dark(#1e0d009a, #ffeee39a); + --gnrc-color-expression-accent-soft: light-dark(#4d200028, #ffe3cb40); + --gnrc-color-expression-accent-subtle: light-dark(#6c31001a, #fff4ef14); + --gnrc-color-expression-achromatic-heavy: light-dark(#000000, #ffffff); + --gnrc-color-expression-achromatic-subtle: light-dark(#ffffff, #000000); + --gnrc-color-expression-gray-heavy: light-dark(#484848, #f5f5f5); + --gnrc-color-expression-gray-loud: light-dark(#929292, #dedede); + --gnrc-color-expression-gray-soft: light-dark(#dedede, #929292); + --gnrc-color-expression-gray-subtle: light-dark(#f5f5f5, #484848); + --gnrc-color-expression-navy-heavy: light-dark(#294482, #f0f5ff); + --gnrc-color-expression-navy-loud: light-dark(#5c8df8, #cedeff); + --gnrc-color-expression-navy-soft: light-dark(#cedeff, #5c8df8); + --gnrc-color-expression-navy-subtle: light-dark(#f0f5ff, #294482); + --gnrc-color-expression-blue-heavy: light-dark(#0b497f, #eef6ff); + --gnrc-color-expression-blue-loud: light-dark(#2f95f4, #c6e1ff); + --gnrc-color-expression-blue-soft: light-dark(#c6e1ff, #2f95f4); + --gnrc-color-expression-blue-subtle: light-dark(#eef6ff, #0b497f); + --gnrc-color-expression-green-heavy: light-dark(#0c5722, #e7fce9); + --gnrc-color-expression-green-loud: light-dark(#32ad52, #baedc1); + --gnrc-color-expression-green-soft: light-dark(#baedc1, #32ad52); + --gnrc-color-expression-green-subtle: light-dark(#e7fce9, #0c5722); + --gnrc-color-expression-lime-heavy: light-dark(#345200, #e6ffcf); + --gnrc-color-expression-lime-loud: light-dark(#6da603, #cbff93); + --gnrc-color-expression-lime-soft: light-dark(#cbff93, #6da603); + --gnrc-color-expression-lime-subtle: light-dark(#e6ffcf, #345200); + --gnrc-color-expression-yellow-heavy: light-dark(#524800, #fff7c4); + --gnrc-color-expression-yellow-loud: light-dark(#fbdf06, #ffed85); + --gnrc-color-expression-yellow-soft: light-dark(#ffed85, #fbdf06); + --gnrc-color-expression-yellow-subtle: light-dark(#fff7c4, #524800); + --gnrc-color-expression-pumpkin-heavy: light-dark(#762f0e, #fef2ee); + --gnrc-color-expression-pumpkin-loud: light-dark(#fb966e, #ffd3c2); + --gnrc-color-expression-pumpkin-soft: light-dark(#ffd3c2, #fb966e); + --gnrc-color-expression-pumpkin-subtle: light-dark(#fef2ee, #762f0e); + --gnrc-color-expression-red-heavy: light-dark(#772b28, #fff2f0); + --gnrc-color-expression-red-loud: light-dark(#e7615b, #ffd2cd); + --gnrc-color-expression-red-soft: light-dark(#ffd2cd, #e7615b); + --gnrc-color-expression-red-subtle: light-dark(#fff2f0, #772b28); + --gnrc-color-expression-pink-heavy: light-dark(#6f2b53, #fff1f7); + --gnrc-color-expression-pink-loud: light-dark(#d961a6, #ffcee6); + --gnrc-color-expression-pink-soft: light-dark(#ffcee6, #d961a6); + --gnrc-color-expression-pink-subtle: light-dark(#fff1f7, #6f2b53); + --gnrc-color-expression-purple-heavy: light-dark(#523778, #f7f3ff); + --gnrc-color-expression-purple-loud: light-dark(#a575e8, #e4d6ff); + --gnrc-color-expression-purple-soft: light-dark(#e4d6ff, #a575e8); + --gnrc-color-expression-purple-subtle: light-dark(#f7f3ff, #523778); + --gnrc-color-overlay-neutral-translucent: light-dark(#00000026, #00000099); + --gnrc-color-surface-neutral-farther: light-dark(#f0eae5, #1e1916); + --gnrc-color-surface-neutral-far: light-dark(#faf4f0, #231e1a); + --gnrc-color-surface-neutral-near: light-dark(#f6f1ec, #1c1714); + --gnrc-color-surface-neutral-nearer: light-dark(#ffffff, #2e2823); + --gnrc-color-surface-neutral-translucent: light-dark(#ffffff80, #00000080); + --gnrc-material-background-thick: light-dark(#fffffff1, #262626ea); + --gnrc-material-background-regular: light-dark(#ffffffd7, #2f2f2fd1); + --gnrc-material-background-thin: light-dark(#ffffff7e, #3434348b); + --gnrc-color-background-neutral-heavy: light-dark(#28231e, #ffffff); + --gnrc-color-background-neutral-loud: light-dark(#1e0d009a, #ffeee39a); + --gnrc-color-background-neutral-soft: light-dark(#4d200028, #ffe3cb40); + --gnrc-color-background-neutral-subtle: light-dark(#6c31001a, #fff4ef14); + --gnrc-color-background-neutral-transparent: light-dark(#28231e00, #ffffff00); + --gnrc-color-background-neutral-translucent: light-dark(#e9e9e980, #3c3c3c80); + --gnrc-color-background-neutral-disabled: light-dark(#00000008, #ffffff07); + --gnrc-color-background-neutral-heavy-disabled: light-dark(#0000001a, #ffffff20); + --gnrc-color-background-neutral-subtle-disabled: light-dark(#0000000d, #ffffff1b); + --gnrc-color-background-brand-heavy: light-dark(#28231e, #ffffff); + --gnrc-color-background-brand-loud: light-dark(#1e0d009a, #ffeee39a); + --gnrc-color-background-brand-soft: light-dark(#4d200028, #ffe3cb40); + --gnrc-color-background-brand-subtle: light-dark(#6c31001a, #fff4ef14); + --gnrc-color-background-brand-transparent: light-dark(#28231e00, #ffffff00); + --gnrc-color-background-danger-loud: light-dark(#c02e56, #e55e7a); + --gnrc-color-background-danger-soft: light-dark(#ffe3e6, #5a2932); + --gnrc-color-background-danger-subtle: light-dark(#fff1f3, #402529); + --gnrc-color-background-warning-loud: light-dark(#bb4001, #e56738); + --gnrc-color-background-warning-soft: light-dark(#ffe5dc, #592c1c); + --gnrc-color-background-warning-subtle: light-dark(#fff2ee, #40261d); + --gnrc-color-background-success-loud: light-dark(#008455, #05ad72); + --gnrc-color-background-success-soft: light-dark(#c9f8dd, #0c462d); + --gnrc-color-background-success-subtle: light-dark(#e3fcee, #193426); + --gnrc-color-stroke-neutral-heavy: light-dark(#28231e, #e3dcd7); + --gnrc-color-stroke-neutral-loud: light-dark(#776d65, #9a9089); + --gnrc-color-stroke-neutral-soft: light-dark(#250f0076, #ffe6d35c); + --gnrc-color-stroke-neutral-subtle: light-dark(#4d200028, #ffe3cb40); + --gnrc-color-stroke-neutral-transparent: light-dark(#28231e00, #ffffff00); + --gnrc-color-stroke-neutral-onloud: light-dark(#ffffffff, #0b0600e1); + --gnrc-color-stroke-neutral-disabled: light-dark(#00000014, #ffffff24); + --gnrc-color-stroke-brand-loud: light-dark(#776d65, #9a9089); + --gnrc-color-stroke-brand-soft: light-dark(#250f0076, #ffe6d35c); + --gnrc-color-stroke-brand-subtle: light-dark(#4d200028, #ffe3cb40); + --gnrc-color-stroke-brand-onloud: light-dark(#ffffffff, #0b0600e1); + --gnrc-color-stroke-danger-loud: light-dark(#c02e56, #e55e7a); + --gnrc-color-stroke-danger-soft: light-dark(#e55e7a, #d14164); + --gnrc-color-stroke-danger-subtle: light-dark(#ffd0d6, #76293a); + --gnrc-color-stroke-danger-onloud: light-dark(#ffffff, #242424); + --gnrc-color-stroke-warning-loud: light-dark(#cd4808, #e56738); + --gnrc-color-stroke-warning-soft: light-dark(#fc9571, #cd4808); + --gnrc-color-stroke-warning-subtle: light-dark(#ffd3c4, #762e12); + --gnrc-color-stroke-warning-onloud: light-dark(#ffffff, #242424); + --gnrc-color-stroke-success-loud: light-dark(#008455, #05ad72); + --gnrc-color-stroke-success-soft: light-dark(#5dce97, #008e5c); + --gnrc-color-stroke-success-subtle: light-dark(#b1efcc, #025636); + --gnrc-color-stroke-success-onloud: light-dark(#ffffff, #242424); + --gnrc-color-stroke-focus-inner: light-dark(#ffffff, #000000); + --gnrc-color-stroke-focus-outer: light-dark(#000000, #ffffff); + --gnrc-color-foreground-neutral-primary: light-dark(#0b0600e1, #fff7f2e3); + --gnrc-color-foreground-neutral-secondary: light-dark(#190c00ab, #fff2e8b5); + --gnrc-color-foreground-neutral-tertiary: light-dark(#1e0d009a, #ffeee39a); + --gnrc-color-foreground-neutral-onloud: light-dark(#ffffffff, #0b0600e1); + --gnrc-color-foreground-neutral-disabled: light-dark(#0000006d, #ffffff61); + --gnrc-color-foreground-brand-primary: light-dark(#0b0600e1, #fff7f2e3); + --gnrc-color-foreground-brand-onloud: light-dark(#ffffffff, #0b0600e1); + --gnrc-color-foreground-danger-primary: light-dark(#a62147, #fd8ea1); + --gnrc-color-foreground-danger-onloud: light-dark(#ffffff, #000000db); + --gnrc-color-foreground-warning-primary: light-dark(#a93901, #fc9571); + --gnrc-color-foreground-warning-onloud: light-dark(#ffffff, #000000db); + --gnrc-color-foreground-success-primary: light-dark(#017048, #5dce97); + --gnrc-color-foreground-success-onloud: light-dark(#ffffff, #000000db); + --gnrc-color-shadow: #000000; + --gnrc-shadow-lowest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 5%); + --gnrc-shadow-lower: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 8%); + --gnrc-shadow-low: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 8%); + --gnrc-shadow-high: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-shadow-higher: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-shadow-highest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-font-weight-functional-regular: 420; + --gnrc-font-weight-functional-medium: 550; + --gnrc-font-weight-functional-semibold: 600; + --gnrc-font-weight-functional-bold: 625; + --gnrc-font-weight-content-regular: 420; + --gnrc-font-weight-content-medium: 550; + --gnrc-font-weight-content-semibold: 600; + --gnrc-font-weight-content-bold: 625; + --gnrc-font-weight-content-editorial-regular: 420; + --gnrc-font-weight-content-editorial-medium: 550; + --gnrc-font-weight-content-editorial-semibold: 600; + --gnrc-font-weight-content-editorial-bold: 625; + --gnrc-font-family-functional: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; + --gnrc-font-family-content: 'Segoe Sans', 'Segoe UI', 'Helvetica Neue', 'Arial', sans-serif; + --gnrc-font-family-content-editorial: 'Segoe Serif', 'Georgia Pro', Georgia, 'Times New Roman', serif; + --gnrc-font-family-content-code: 'Consolas', 'Courier New', 'Monaco', 'Lucida Console', monospace; + --gnrc-letter-spacing-functional-display: -0.0075em; + --gnrc-letter-spacing-functional-pagetitle: -0.0075em; + --gnrc-letter-spacing-functional-title-large: -0.0015em; + --gnrc-letter-spacing-functional-title-medium: -0.0015em; + --gnrc-letter-spacing-functional-title-small: -0.0015em; + --gnrc-letter-spacing-functional-subtitle: -0.0015em; + --gnrc-letter-spacing-functional-body-large: 0em; + --gnrc-letter-spacing-functional-body-medium: 0em; + --gnrc-letter-spacing-functional-body-small: 0em; + --gnrc-letter-spacing-functional-caption: 0em; + --gnrc-letter-spacing-content-statement: -0.0075em; + --gnrc-letter-spacing-content-expressive-large: -0.0075em; + --gnrc-letter-spacing-content-expressive-medium: -0.0015em; + --gnrc-letter-spacing-content-expressive-small: -0.0015em; + --gnrc-letter-spacing-content-h1: -0.0015em; + --gnrc-letter-spacing-content-h2: -0.0015em; + --gnrc-letter-spacing-content-h3: -0.0015em; + --gnrc-letter-spacing-content-h4: -0.0015em; + --gnrc-letter-spacing-content-h5: -0.0015em; + --gnrc-letter-spacing-content-subheadline: 0em; + --gnrc-letter-spacing-content-paragraph-large: 0em; + --gnrc-letter-spacing-content-paragraph-medium: 0em; + --gnrc-letter-spacing-content-paragraph-small: 0em; + --gnrc-letter-spacing-content-subtext: 0em; + --gnrc-letter-spacing-content-table: 0em; + --gnrc-letter-spacing-content-code: 0em; + --gnrc-font-size-functional-display: 4.25rem; + --gnrc-font-size-functional-pagetitle: 2.5rem; + --gnrc-font-size-functional-title-large: 2rem; + --gnrc-font-size-functional-title-medium: 1.75rem; + --gnrc-font-size-functional-title-small: 1.5rem; + --gnrc-font-size-functional-subtitle: 1.25rem; + --gnrc-font-size-functional-body-large: 1rem; + --gnrc-font-size-functional-body-medium: 0.875rem; + --gnrc-font-size-functional-body-small: 0.75rem; + --gnrc-font-size-functional-caption: 0.625rem; + --gnrc-font-size-content-statement: 3.5rem; + --gnrc-font-size-content-expressive-large: 3rem; + --gnrc-font-size-content-expressive-medium: 2.25rem; + --gnrc-font-size-content-expressive-small: 1.75rem; + --gnrc-font-size-content-h1: 2.25rem; + --gnrc-font-size-content-h2: 2rem; + --gnrc-font-size-content-h3: 1.75rem; + --gnrc-font-size-content-h4: 1.5rem; + --gnrc-font-size-content-h5: 1.25rem; + --gnrc-font-size-content-subheadline: 1rem; + --gnrc-font-size-content-paragraph-large: 1.25rem; + --gnrc-font-size-content-paragraph-medium: 1rem; + --gnrc-font-size-content-paragraph-small: 0.75rem; + --gnrc-font-size-content-subtext: 0.625rem; + --gnrc-font-size-content-table: 1rem; + --gnrc-font-size-content-code: 1rem; + --gnrc-line-height-functional-display: round(120%, 2px); + --gnrc-line-height-functional-pagetitle: round(120%, 2px); + --gnrc-line-height-functional-title-large: round(120%, 2px); + --gnrc-line-height-functional-title-medium: round(120%, 2px); + --gnrc-line-height-functional-title-small: round(120%, 2px); + --gnrc-line-height-functional-subtitle: round(140%, 2px); + --gnrc-line-height-functional-body-large: round(140%, 2px); + --gnrc-line-height-functional-body-medium: round(140%, 2px); + --gnrc-line-height-functional-body-small: round(140%, 2px); + --gnrc-line-height-functional-caption: round(140%, 2px); + --gnrc-line-height-content-statement: round(120%, 2px); + --gnrc-line-height-content-expressive-large: round(120%, 2px); + --gnrc-line-height-content-expressive-medium: round(120%, 2px); + --gnrc-line-height-content-expressive-small: round(120%, 2px); + --gnrc-line-height-content-h1: round(120%, 2px); + --gnrc-line-height-content-h2: round(120%, 2px); + --gnrc-line-height-content-h3: round(120%, 2px); + --gnrc-line-height-content-h4: round(120%, 2px); + --gnrc-line-height-content-h5: round(120%, 2px); + --gnrc-line-height-content-subheadline: round(140%, 2px); + --gnrc-line-height-content-paragraph-large: round(170%, 2px); + --gnrc-line-height-content-paragraph-medium: round(170%, 2px); + --gnrc-line-height-content-paragraph-small: round(170%, 2px); + --gnrc-line-height-content-subtext: round(140%, 2px); + --gnrc-line-height-content-table: round(140%, 2px); + --gnrc-line-height-content-code: round(140%, 2px); + --gnrc-border-radius-base-100: 4px; + --gnrc-border-radius-base-200: 8px; + --gnrc-border-radius-base-300: 12px; + --gnrc-border-radius-base-400: 16px; + --gnrc-border-radius-base-600: 24px; + --gnrc-border-radius-base-700: 28px; + --gnrc-border-radius-circular: 9999px; + --gnrc-spacing-component-base-50: 2px; + --gnrc-spacing-component-base-100: 4px; + --gnrc-spacing-component-base-150: 6px; + --gnrc-spacing-component-base-200: 8px; + --gnrc-spacing-component-base-250: 10px; + --gnrc-spacing-component-base-300: 12px; + --gnrc-spacing-component-base-400: 16px; + --gnrc-spacing-component-base-500: 20px; + --gnrc-spacing-component-base-600: 24px; + --gnrc-spacing-component-base-700: 28px; + --gnrc-spacing-component-base-800: 32px; + --gnrc-spacing-layout-base-100: 8px; + --gnrc-spacing-layout-base-200: 16px; + --gnrc-spacing-layout-base-300: 24px; + --gnrc-spacing-layout-base-400: 32px; + --gnrc-spacing-layout-base-450: 36px; + --gnrc-spacing-layout-base-500: 40px; + --gnrc-spacing-layout-base-600: 48px; + --gnrc-spacing-layout-base-700: 56px; + --gnrc-spacing-layout-base-800: 64px; + --gnrc-spacing-layout-base-1000: 80px; + --gnrc-spacing-layout-base-1200: 96px; + --gnrc-stroke-width-thin: 1px; + --gnrc-stroke-width-thick: 2px; + --gnrc-stroke-width-thicker: 3px; + --gnrc-stroke-width-thickest: 4px; + --gnrc-motion-duration-base-50: 50ms; + --gnrc-motion-duration-base-100: 100ms; + --gnrc-motion-duration-base-200: 200ms; + --gnrc-motion-duration-base-300: 300ms; + --gnrc-motion-duration-base-500: 500ms; + --gnrc-motion-duration-base-1000: 1000ms; + --gnrc-motion-easing-functional-enter: cubic-bezier(0, 0, 0, 1); + --gnrc-motion-easing-functional-exit: cubic-bezier(0.6, 0, 0.75, 0.4); + --gnrc-motion-easing-functional-transition: cubic-bezier(0.33, 0, 0, 1); + --gnrc-motion-easing-functional-linear: cubic-bezier(0, 0, 1, 1); + --gnrc-motion-easing-expressive-enter: cubic-bezier(0, 0, 0, 1); + --gnrc-motion-easing-expressive-exit: cubic-bezier(0.6, 0, 0.75, 0.4); + --gnrc-motion-easing-expressive-transition: cubic-bezier(0.33, 0, 0, 1); + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-hover: -0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-press: -0.06; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-hover: 0.04; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-press: 0.08; + --interaction-standard-hover: max(calc(l - 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.1) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / calc(alpha + 0.04); + --interaction-standard-pressed: max(calc(l - 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.08) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / calc(alpha + 0.08); + --interaction-inverse-hover: calc(l + 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / alpha; + --interaction-inverse-pressed: calc(l + 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / alpha; +} + +@media (prefers-color-scheme: dark) { + :root { + --gnrc-shadow-lowest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%); + --gnrc-shadow-lower: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 16%); + --gnrc-shadow-low: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 16%); + --gnrc-shadow-high: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%); + --gnrc-shadow-higher: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 12%); + --gnrc-shadow-highest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 12%); + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-hover: 0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-press: 0.06; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-hover: 0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-press: 0.06; + --interaction-standard-hover: min(calc(l + 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.985) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / calc(alpha + 0.03); + --interaction-standard-pressed: min(calc(l + 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.992) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / calc(alpha + 0.06); + --interaction-inverse-hover: calc(l - 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / alpha; + --interaction-inverse-pressed: calc(l - 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / alpha; + } +} + +[data-theme="light"] { + color-scheme: light; + --gnrc-shadow-lowest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 5%); + --gnrc-shadow-lower: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 8%); + --gnrc-shadow-low: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 8%); + --gnrc-shadow-high: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-shadow-higher: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 6%); + --gnrc-shadow-highest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 3%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 6%); + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-hover: -0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-press: -0.06; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-hover: 0.04; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-press: 0.08; + --interaction-standard-hover: max(calc(l - 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.1) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / calc(alpha + 0.04); + --interaction-standard-pressed: max(calc(l - 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.08) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / calc(alpha + 0.08); + --interaction-inverse-hover: calc(l + 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / alpha; + --interaction-inverse-pressed: calc(l + 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / alpha; +} + +[data-theme="dark"] { + color-scheme: dark; + --gnrc-shadow-lowest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 1px 2px oklch(from var(--gnrc-color-shadow) l c h / 10%); + --gnrc-shadow-lower: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 16%); + --gnrc-shadow-low: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 2px 4px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 16%); + --gnrc-shadow-high: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 4px 8px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%); + --gnrc-shadow-higher: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 16px 32px oklch(from var(--gnrc-color-shadow) l c h / 12%); + --gnrc-shadow-highest: 0px 0px 2px oklch(from var(--gnrc-color-shadow) l c h / 20%), 0px 8px 16px oklch(from var(--gnrc-color-shadow) l c h / 12%), 0px 32px 64px oklch(from var(--gnrc-color-shadow) l c h / 12%); + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-hover: 0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --lightness-press: 0.06; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-hover: 0.03; + /* @deprecated Interaction fragments now contain mode-specific values directly. Retained for compatibility; remove in 1.0.0. */ + --alpha-press: 0.06; + --interaction-standard-hover: min(calc(l + 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.985) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / calc(alpha + 0.03); + --interaction-standard-pressed: min(calc(l + 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)), 0.992) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / calc(alpha + 0.06); + --interaction-inverse-hover: calc(l - 0.03 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.003,calc(c * .04)),0.006)) h / alpha; + --interaction-inverse-pressed: calc(l - 0.06 * clamp(1,(.5 - l)/.1,3) * clamp(.35,calc(alpha + .35),1)) calc(c + min(max(0.006,calc(c * .08)),0.012)) h / alpha; +} diff --git a/packages/agentic/design/scripts/token-mappings/check-mappings.cjs b/packages/agentic/design/scripts/token-mappings/check-mappings.cjs index 8111821beb..52d2e05776 100644 --- a/packages/agentic/design/scripts/token-mappings/check-mappings.cjs +++ b/packages/agentic/design/scripts/token-mappings/check-mappings.cjs @@ -9,14 +9,15 @@ const { parse: parseYaml } = nodeRequire(path.join(yamlPackageRoot, 'dist/index. const packageRoot = path.resolve(__dirname, '../..'); const defaultPaths = { - defaultTokens: path.join(packageRoot, 'src/flex/defaults/defaultTokens.ts'), + defaultTokens: path.join(packageRoot, 'src/flex/adapters/fluentFallbackTokens.ts'), flexFromTheme: path.join(packageRoot, 'src/tokens/mappings/flex-from-theme.json'), flexTokenMap: path.join(packageRoot, 'src/tokens/mappings/flex-token-map.yaml'), flexTypes: path.join(packageRoot, 'src/flex/tokens.types.ts'), themeFromFlex: path.join(packageRoot, 'src/tokens/mappings/theme-from-flex.json'), }; -const reverseTransforms = new Set(['identity', 'numberToPx']); +const reverseTransforms = new Set(['identity', 'numberToPx', 'shadowLayersToToken']); +const shadowReverseTransform = 'shadowLayersToToken'; function isRecord(value) { return value !== null && typeof value === 'object' && !Array.isArray(value); @@ -44,6 +45,27 @@ function getThemeSource(entry, tokenPath, violations) { return source; } +function getGenericSource(entry, tokenPath, violations) { + if (!Object.hasOwn(entry, 'generic') || entry.generic === null) { + return undefined; + } + + const source = entry.generic; + if (typeof source !== 'string' || !source.startsWith('--gnrc-')) { + addViolation(violations, 'schema', tokenPath, 'a --gnrc-* custom property name or no generic field', source); + return undefined; + } + + return source; +} + +function createMappingEntry(entry, tokenPath, violations) { + return { + genericSource: getGenericSource(entry, tokenPath, violations), + themeSource: getThemeSource(entry, tokenPath, violations), + }; +} + function flattenTokenMappings(mapping, violations) { const entries = new Map(); if (!isRecord(mapping.tokens)) { @@ -70,15 +92,11 @@ function flattenTokenMappings(mapping, violations) { continue; } - entries.set(destination, { - themeSource: getThemeSource(stateEntry, destination, violations), - }); + entries.set(destination, createMappingEntry(stateEntry, destination, violations)); } } else { const destination = basePath.startsWith('color.') ? `${basePath}.rest` : basePath; - entries.set(destination, { - themeSource: getThemeSource(mappingEntry, destination, violations), - }); + entries.set(destination, createMappingEntry(mappingEntry, destination, violations)); } } @@ -209,6 +227,9 @@ function buildReverseProjection(mapping, mappingEntries, supportedTypePaths, vio descriptor.transform = transform; } } + if (source.startsWith('shadow.') && descriptor.transform !== shadowReverseTransform) { + addViolation(violations, 'reverse-transform', themePath, shadowReverseTransform, transform ?? ''); + } projectionEntries.push([themePath, descriptor]); } @@ -516,6 +537,18 @@ function validateMappingInputs(inputs) { } } + // Every rest and non-color destination needs a generic source for generated defaults; interaction states are optional. + for (const tokenPath of supportedTypePaths) { + if (getInteractionRestPath(tokenPath) === undefined && !supportedEntries.has(tokenPath)) { + addViolation(violations, 'mapping-coverage', tokenPath, 'a destination in flex-token-map.yaml', ''); + } + } + for (const [tokenPath, entry] of supportedEntries) { + if (entry.genericSource === undefined) { + addViolation(violations, 'generic-source', tokenPath, 'a generic custom property', ''); + } + } + for (const [tokenPath, entry] of supportedEntries) { const projectedSource = themeProjection[tokenPath]; if (entry.themeSource === undefined) { diff --git a/packages/agentic/design/scripts/token-mappings/upstream-drift.cjs b/packages/agentic/design/scripts/token-mappings/upstream-drift.cjs index 96fe89570c..de2d38a22b 100644 --- a/packages/agentic/design/scripts/token-mappings/upstream-drift.cjs +++ b/packages/agentic/design/scripts/token-mappings/upstream-drift.cjs @@ -4,7 +4,26 @@ const path = require('node:path'); const packageRoot = path.resolve(__dirname, '../..'); const pinPath = path.join(packageRoot, 'src/tokens/mappings/upstream-pin.json'); -const requiredFileIds = ['semanticCss', 'interactionFallbackCss', 'mappings']; +// Every pinned source and how its contents are compared. `css` sources compare custom-property declarations; +// `tokenSections` sources compare the token names listed in their generics and interaction sections. +const requiredFileKinds = { + semanticCss: 'css', + semanticLightCss: 'css', + semanticDarkCss: 'css', + interactionFallbackCss: 'css', + interactionFallbackLightCss: 'css', + interactionFallbackDarkCss: 'css', + warmSemanticCss: 'css', + warmSemanticLightCss: 'css', + warmSemanticDarkCss: 'css', + warmInteractionFallbackCss: 'css', + warmInteractionFallbackLightCss: 'css', + warmInteractionFallbackDarkCss: 'css', + mappings: 'tokenSections', + tokens: 'tokenSections', +}; +const requiredFileIds = Object.keys(requiredFileKinds); +const tokenSectionNames = ['generics', 'interaction']; class UpstreamFetchError extends Error {} @@ -163,17 +182,17 @@ function gitBlobSha(source) { return crypto.createHash('sha1').update(`blob ${content.length}\0`).update(content).digest('hex'); } -function namesFromMappingSection(source, sectionName) { +function namesFromTokenSection(fileId, source, sectionName) { const parsed = JSON.parse(source); const section = parsed[sectionName]; if (!Array.isArray(section)) { - throw new Error(`Upstream mappings.json section ${sectionName} must be an array.`); + throw new Error(`Upstream ${fileId} section ${sectionName} must be an array.`); } return new Set( section.map((entry, index) => { if (!entry || typeof entry.name !== 'string') { - throw new Error(`Upstream mappings.json ${sectionName}[${index}] must have a string name.`); + throw new Error(`Upstream ${fileId} ${sectionName}[${index}] must have a string name.`); } return entry.name; }), @@ -200,17 +219,19 @@ function validateUpstreamContents(contents) { } } - for (const sectionName of ['generics', 'interaction']) { - if (namesFromMappingSection(contents.mappings, sectionName).size === 0) { - throw new Error(`Upstream mappings.json section ${sectionName} must not be empty.`); + for (const [fileId, kind] of Object.entries(requiredFileKinds)) { + if (kind === 'css') { + if (cssDeclarations(contents[fileId]).size === 0) { + throw new Error(`Upstream ${fileId} must declare at least one custom property.`); + } + } else { + for (const sectionName of tokenSectionNames) { + if (namesFromTokenSection(fileId, contents[fileId], sectionName).size === 0) { + throw new Error(`Upstream ${fileId} section ${sectionName} must not be empty.`); + } + } } } - if (cssDeclarations(contents.semanticCss).size === 0) { - throw new Error('Upstream semantic.css must declare at least one custom property.'); - } - if (cssDeclarations(contents.interactionFallbackCss).size === 0) { - throw new Error('Upstream interaction-fallback.css must declare at least one custom property.'); - } } function compareNames(baseline, candidate) { @@ -240,22 +261,25 @@ function hasNameChanges(comparison) { function createReport(pin, baseline, candidate, candidateRef, mode) { const normalizedBaseline = Object.fromEntries(Object.entries(baseline).map(([id, source]) => [id, normalizeSourceContent(source)])); const normalizedCandidate = Object.fromEntries(Object.entries(candidate).map(([id, source]) => [id, normalizeSourceContent(source)])); - const genericTokens = compareNames( - namesFromMappingSection(normalizedBaseline.mappings, 'generics'), - namesFromMappingSection(normalizedCandidate.mappings, 'generics'), - ); - const interactionTokens = compareNames( - namesFromMappingSection(normalizedBaseline.mappings, 'interaction'), - namesFromMappingSection(normalizedCandidate.mappings, 'interaction'), - ); - const semanticProperties = compareNames( - new Set(cssDeclarations(normalizedBaseline.semanticCss).keys()), - new Set(cssDeclarations(normalizedCandidate.semanticCss).keys()), - ); - const interactionFallbackTokens = compareDeclarations( - cssDeclarations(normalizedBaseline.interactionFallbackCss), - cssDeclarations(normalizedCandidate.interactionFallbackCss), - ); + const tokenSections = {}; + const css = {}; + for (const [fileId, kind] of Object.entries(requiredFileKinds)) { + if (kind === 'css') { + css[fileId] = { + customProperties: compareDeclarations(cssDeclarations(normalizedBaseline[fileId]), cssDeclarations(normalizedCandidate[fileId])), + }; + } else { + tokenSections[fileId] = Object.fromEntries( + tokenSectionNames.map((sectionName) => [ + sectionName, + compareNames( + namesFromTokenSection(fileId, normalizedBaseline[fileId], sectionName), + namesFromTokenSection(fileId, normalizedCandidate[fileId], sectionName), + ), + ]), + ); + } + } const contentChangedFiles = pin.files .filter((file) => normalizedBaseline[file.id] !== normalizedCandidate[file.id]) .map((file) => file.upstreamPath); @@ -271,11 +295,8 @@ function createReport(pin, baseline, candidate, candidateRef, mode) { const hasDrift = contentChangedFiles.length > 0 || snapshotIntegrity.some((file) => !file.matches) || - hasNameChanges(genericTokens) || - hasNameChanges(interactionTokens) || - hasNameChanges(semanticProperties) || - hasNameChanges(interactionFallbackTokens) || - interactionFallbackTokens.changed.length > 0; + Object.values(tokenSections).some((sections) => Object.values(sections).some(hasNameChanges)) || + Object.values(css).some(({ customProperties }) => hasNameChanges(customProperties) || customProperties.changed.length > 0); return { repository: pin.repository, @@ -286,16 +307,8 @@ function createReport(pin, baseline, candidate, candidateRef, mode) { hasDrift, contentChangedFiles, snapshotIntegrity, - mappings: { - generics: genericTokens, - interaction: interactionTokens, - }, - semanticCss: { - customProperties: semanticProperties, - }, - interactionFallbackCss: { - tokens: interactionFallbackTokens, - }, + tokenSections, + css, }; } diff --git a/packages/agentic/design/src/color-lib/interaction.ts b/packages/agentic/design/src/color-lib/interaction.ts index d8932338f5..d86a04948b 100644 --- a/packages/agentic/design/src/color-lib/interaction.ts +++ b/packages/agentic/design/src/color-lib/interaction.ts @@ -8,7 +8,7 @@ import type { ColorMode, InteractionColorOptions, InteractionColorResult, Intera /** * Default interaction lightness and alpha shifts for each state and mode. * - * Source: x3-design/fluent-design@d334acf5cbad813f2b7cd554da942b09a7ff8f10. + * Source: x3-design/fluent-design@206e890b645fb450ad7c5df2ff981765349a2b58. */ export const INTERACTION_COLOR_DELTAS = { hover: { diff --git a/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts index 928905e00e..cbb1a1f4b4 100644 --- a/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts +++ b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.test.ts @@ -2,6 +2,7 @@ import * as interaction from '../../color-lib/interaction'; import type { Theme } from '../../theming'; import { mockTheme } from '../../test/fixtures/mockTheme'; import { defaultFlexTokens } from '../defaults/defaultTokens'; +import { fluentFallbackFlexTokens } from './fluentFallbackTokens'; import { flexTokensFromTheme } from './flexTokensFromTheme'; function createTheme(): Theme { @@ -48,6 +49,29 @@ describe('flexTokensFromTheme', () => { expect(tokens.color.backgroundBrandHeavy.rest).toBe('#185abd'); }); + it('converts legacy { ambient, key } Theme shadows to [ambient, key] layers', () => { + const tokens = flexTokensFromTheme(createTheme()); + + expect(tokens.shadow.lowest).toEqual([mockTheme.shadows.shadow2.ambient, mockTheme.shadows.shadow2.key]); + expect(tokens.shadow.highest).toEqual([mockTheme.shadows.shadow64.ambient, mockTheme.shadows.shadow64.key]); + }); + + it('keeps layered shadows and drops missing legacy layers', () => { + const layers = [mockTheme.shadows.shadow4.key, mockTheme.shadows.shadow8.key, mockTheme.shadows.shadow16.key]; + const shadows = { ...mockTheme.shadows, shadow4: layers, shadow8: { ambient: mockTheme.shadows.shadow8.ambient } }; + const tokens = flexTokensFromTheme({ ...createTheme(), shadows } as unknown as Theme); + + expect(tokens.shadow.lower).toBe(layers); + expect(tokens.shadow.low).toEqual([mockTheme.shadows.shadow8.ambient]); + }); + + it('uses the Fluent fallback shadow when the Theme omits one', () => { + const { shadow2: _omitted, ...shadows } = mockTheme.shadows; + const tokens = flexTokensFromTheme({ ...createTheme(), shadows } as Theme); + + expect(tokens.shadow.lowest).toEqual(fluentFallbackFlexTokens.shadow.lowest); + }); + it('resolves every color and never runs the interaction engine', () => { const spy = jest.spyOn(interaction, 'getInteractionColor'); try { diff --git a/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts index 4bf922114b..54aff51fc2 100644 --- a/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts +++ b/packages/agentic/design/src/flex/adapters/flexTokensFromTheme.ts @@ -1,21 +1,22 @@ import { immutableMerge } from '@fluentui-react-native/framework-base'; import type { ColorValue } from 'react-native'; +import type { ShadowToken } from '../../fluent/types/Shadow.types'; import type { Theme } from '../../fluent/types/Theme.types'; import { defaultResolvedThemeAppearance } from '../../theming/appearance'; import { mapObjectFromObject } from '../../utilities/objects'; import { normalizeFlexColor, resolveExplicitFlexColor } from '../colors/flexColor'; import type { ColorSchemeSelector } from '../colors/flexColor'; import { createInteractiveColor } from '../colors/interactiveColor'; -import { defaultFlexTokens, nonFluentFlexTokens } from '../defaults/defaultTokens'; -import type { FlexColorInput, FlexTokens, InteractiveColor, SemanticColors } from '../tokens.types'; +import type { FlexColorInput, FlexShadow, FlexShadowLayer, FlexTokens, InteractiveColor, SemanticColors } from '../tokens.types'; +import { fluentFallbackFlexTokens, nonFluentFlexTokens } from './fluentFallbackTokens'; import flexFromTheme from '../../tokens/mappings/flex-from-theme.json' with { type: 'json' }; type MappedColor = { rest: ColorValue; hover?: ColorValue; pressed?: ColorValue }; type MappedFlexTokens = Omit, 'color'> & { color?: Record }; const defaultMappedFlexTokens = mapObjectFromObject( - defaultFlexTokens, + fluentFallbackFlexTokens, Object.fromEntries(Object.keys(flexFromTheme).map((destinationPath) => [destinationPath, destinationPath])), ); @@ -24,16 +25,35 @@ const nonFluentColorDescriptions = Object.entries(nonFluentColors as Record [name, normalizeFlexColor(value, 'standard', `color.${name}`)] as const, ); +/** Convert a legacy Theme { ambient, key } shadow to [ambient, key] layers. */ +function shadowLayersFromTheme(shadow: Partial | FlexShadow): FlexShadow { + if (Array.isArray(shadow)) { + return shadow; + } + const { ambient, key } = shadow as Partial; + return [ambient, key].filter((layer): layer is FlexShadowLayer => layer !== undefined); +} + +function mapThemeTokens(theme: Theme): MappedFlexTokens { + const mapped = mapObjectFromObject(theme, flexFromTheme); + if (mapped.shadow === undefined) { + return mapped; + } + const shadow: Record = {}; + for (const [name, value] of Object.entries(mapped.shadow)) { + shadow[name] = shadowLayersFromTheme(value); + } + return { ...mapped, shadow: shadow as MappedFlexTokens['shadow'] }; +} + /** * Build Flex tokens from the values exposed by a FURN Theme. Interaction * states the Theme does not map equal rest; no interaction algorithm runs. + * Legacy { ambient, key } Theme shadows become [ambient, key] layers. * The scheme selects light/dark tuples in values without a Theme source. */ export function flexTokensFromTheme(theme: Theme, appearance: ColorSchemeSelector = defaultResolvedThemeAppearance): FlexTokens { - const { color: mappedColors = {}, ...mappedGroups } = immutableMerge( - defaultMappedFlexTokens, - mapObjectFromObject(theme, flexFromTheme), - ) as MappedFlexTokens; + const { color: mappedColors = {}, ...mappedGroups } = immutableMerge(defaultMappedFlexTokens, mapThemeTokens(theme)) as MappedFlexTokens; const color: Record = {}; for (const [name, description] of nonFluentColorDescriptions) { diff --git a/packages/agentic/design/src/flex/adapters/fluentFallbackTokens.test.ts b/packages/agentic/design/src/flex/adapters/fluentFallbackTokens.test.ts new file mode 100644 index 0000000000..9c6ecc64a0 --- /dev/null +++ b/packages/agentic/design/src/flex/adapters/fluentFallbackTokens.test.ts @@ -0,0 +1,73 @@ +import { INTERACTIVE_COLOR_TOKENS } from '../colors/interactiveTokens'; +import { fluentFallbackFlexTokens, nonFluentFlexTokens } from './fluentFallbackTokens'; + +const flexFromTheme = jest.requireActual>('../../tokens/mappings/flex-from-theme.json'); +const interactiveTokens = new Set(INTERACTIVE_COLOR_TOKENS); + +function isColorOptions(value: unknown): value is Record { + return typeof value === 'object' && value !== null && !Array.isArray(value) && 'rest' in value; +} + +function getGroupPaths(tokens: object): string[] { + return Object.entries(tokens) + .filter(([group]) => group !== 'color') + .flatMap(([group, values]) => Object.keys(values).map((name) => `${group}.${name}`)); +} + +// Authored color paths: rest always, and hover or pressed only when present. +function getAuthoredPaths(tokens: { color: object }): string[] { + const colorPaths = Object.entries(tokens.color).flatMap(([name, value]) => { + const states = isColorOptions(value) ? ['rest', 'hover', 'pressed'].filter((state) => value[state] !== undefined) : ['rest']; + return states.map((state) => `color.${name}.${state}`); + }); + return [...colorPaths, ...getGroupPaths(tokens)].sort(); +} + +// Every interactive fallback authors explicit states; other colors author rest only. +function getFallbackPaths(tokens: { color: object }): string[] { + const colorPaths = Object.keys(tokens.color).flatMap((name) => + (interactiveTokens.has(name) ? ['rest', 'hover', 'pressed'] : ['rest']).map((state) => `color.${name}.${state}`), + ); + return [...colorPaths, ...getGroupPaths(tokens)].sort(); +} + +describe('Fluent fallback Flex tokens', () => { + it('builds fallbacks from values without FURN Theme sources', () => { + const themeBackedPaths = new Set(Object.keys(flexFromTheme)); + const expectedNonFluentPaths = getFallbackPaths(fluentFallbackFlexTokens).filter((path) => { + if (themeBackedPaths.has(path)) { + return false; + } + + const interactiveColor = /^color\.([^.]+)\.(?:hover|pressed)$/.exec(path); + return !interactiveColor || !themeBackedPaths.has(`color.${interactiveColor[1]}.rest`); + }); + + expect(getAuthoredPaths(nonFluentFlexTokens)).toEqual(expectedNonFluentPaths); + expect(Object.keys(nonFluentFlexTokens)).toEqual(['color', 'lineHeight', 'borderRadius', 'spacing', 'strokeWidth', 'motion']); + expect(nonFluentFlexTokens.color.backgroundNeutralSoft).toEqual({ rest: '#0000001a', hover: '#0000001a', pressed: '#0000001a' }); + expect(nonFluentFlexTokens.borderRadius.base100).toBe(2); + expect('backgroundBrandHeavy' in nonFluentFlexTokens.color).toBe(false); + expect('backgroundBrandSoft' in nonFluentFlexTokens.color).toBe(false); + expect('surfaceNeutralFarther' in nonFluentFlexTokens.color).toBe(false); + expect('base200' in nonFluentFlexTokens.borderRadius).toBe(false); + expect(fluentFallbackFlexTokens.lineHeight).toBe(nonFluentFlexTokens.lineHeight); + expect(fluentFallbackFlexTokens.motion).toBe(nonFluentFlexTokens.motion); + expect(fluentFallbackFlexTokens.color.backgroundNeutralSoft.rest).toBe(nonFluentFlexTokens.color.backgroundNeutralSoft.rest); + }); + + it('keeps the Fluent-native fallback values', () => { + expect(fluentFallbackFlexTokens.color.surfaceNeutralFarther).toEqual({ rest: '#ebebeb', hover: '#f5f5f5', pressed: '#f0f0f0' }); + expect(fluentFallbackFlexTokens.color.backgroundBrandHeavy.rest).toBe('#185abd'); + expect(fluentFallbackFlexTokens.color.backgroundBrandSoft.hover).toBe('#d2e0f4'); + expect(fluentFallbackFlexTokens.spacing.componentBase800).toBe(32); + expect(fluentFallbackFlexTokens.shadow.lowest).toEqual([ + { x: 0, y: 0, blur: 2, color: '#0000001f' }, + { x: 0, y: 1, blur: 2, color: '#00000024' }, + ]); + expect(fluentFallbackFlexTokens.shadow.highest).toEqual([ + { x: 0, y: 0, blur: 8, color: '#00000033' }, + { x: 0, y: 32, blur: 64, color: '#0000003d' }, + ]); + }); +}); diff --git a/packages/agentic/design/src/flex/adapters/fluentFallbackTokens.ts b/packages/agentic/design/src/flex/adapters/fluentFallbackTokens.ts new file mode 100644 index 0000000000..4d7d3f2762 --- /dev/null +++ b/packages/agentic/design/src/flex/adapters/fluentFallbackTokens.ts @@ -0,0 +1,354 @@ +import { + cornerRadius120, + cornerRadius20, + cornerRadius40, + cornerRadius60, + cornerRadius80, + cornerRadiusCircular, + fontFamilyBase, + fontFamilyMonospace, + fontLineHeight100, + fontLineHeight200, + fontLineHeight300, + fontLineHeight400, + fontLineHeight500, + fontLineHeight600, + fontLineHeight800, + fontLineHeight900, + fontLineHeight1000, + fontSize100, + fontSize200, + fontSize300, + fontSize400, + fontSize500, + fontSize600, + fontSize700, + fontSize800, + fontSize900, + fontSize1000, + fontWeightBold, + fontWeightMedium, + fontWeightRegular, + fontWeightSemibold, + size20, + size40, + size60, + size80, + size100, + size120, + size160, + size200, + size240, + size280, + size320, + size360, + size400, + size480, + size560, + size640, + size800, + strokeWidth10, + strokeWidth20, + strokeWidth30, + strokeWidth40, +} from '../../tokens/global.generated'; +import { defaultResolvedThemeAppearance } from '../../theming/appearance'; +import { createFlexTokenDescription, resolveExplicitFlexTokenDescription } from '../flexTokenDescription'; +import type { FlexTokens, PartialFlexTokens } from '../tokens.types'; + +type NonFluentFlexTokens = Omit; + +/** + * Fallback values for Flex tokens that cannot be populated from a FURN Theme. + * The forward Theme adapter layers projected Theme values over these. They are + * Fluent-native values, not the x3 defaults. Fluent and Theme have no motion + * tokens, so motion uses the x3 values pinned at 206e890b. + */ +export const nonFluentFlexTokens = { + color: { + surfaceNeutralTranslucent: { rest: '#ffffff80', hover: '#ffffff80', pressed: '#ffffff80' }, + backgroundNeutralSoft: { rest: '#0000001a', hover: '#0000001a', pressed: '#0000001a' }, + backgroundNeutralTranslucent: { rest: '#ffffff80', hover: '#ffffff80', pressed: '#ffffff80' }, + expressionAccentHeavy: '#242424', + expressionAccentLoud: '#707070', + expressionAccentSoft: '#0000001a', + expressionAccentSubtle: '#0000000d', + expressionGrayHeavy: '#474747', + expressionGrayLoud: '#949494', + expressionGraySoft: '#e0e0e0', + expressionGraySubtle: '#f5f5f5', + expressionNavyHeavy: '#001e89', + expressionNavyLoud: '#546fd2', + expressionNavySoft: '#ccd5f3', + expressionNavySubtle: '#f2f4fc', + expressionBlueHeavy: '#004377', + expressionBlueLoud: '#3595de', + expressionBlueSoft: '#d0e7f8', + expressionBlueSubtle: '#f3f9fd', + expressionGreenHeavy: '#0c5e0c', + expressionGreenLoud: '#54b054', + expressionGreenSoft: '#c9eac9', + expressionGreenSubtle: '#f1faf1', + expressionLimeHeavy: '#405f14', + expressionLimeLoud: '#689920', + expressionLimeSoft: '#cfe5af', + expressionLimeSubtle: '#e5f1d3', + expressionYellowHeavy: '#4c4400', + expressionYellowLoud: '#fde300', + expressionYellowSoft: '#feee66', + expressionYellowSubtle: '#fef7b2', + expressionPumpkinHeavy: '#712d09', + expressionPumpkinLoud: '#df8e64', + expressionPumpkinSoft: '#f7dfd2', + expressionPumpkinSubtle: '#fdf7f4', + expressionRedHeavy: '#751d1f', + expressionRedLoud: '#dc5e62', + expressionRedSoft: '#f8dadb', + expressionRedSubtle: '#fdf6f6', + expressionPinkHeavy: '#80215d', + expressionPinkLoud: '#e750b0', + expressionPinkSoft: '#f7c0e3', + expressionPinkSubtle: '#fef6fb', + expressionPurpleHeavy: '#532982', + expressionPurpleLoud: '#9470bd', + expressionPurpleSoft: '#e0d3ed', + expressionPurpleSubtle: '#f7f4fb', + overlayNeutralTranslucent: '#ffffff80', + materialBackgroundThick: '#ffffffe6', + materialBackgroundRegular: '#ffffffcc', + materialBackgroundThin: '#ffffff80', + }, + lineHeight: { + functionalDisplay: fontLineHeight1000, + functionalPagetitle: fontLineHeight900, + functionalTitleLarge: fontLineHeight800, + functionalTitleMedium: fontLineHeight600, + functionalTitleSmall: fontLineHeight500, + functionalSubtitle: fontLineHeight500, + functionalBodyLarge: fontLineHeight400, + functionalBodyMedium: fontLineHeight300, + functionalBodySmall: fontLineHeight200, + functionalCaption: fontLineHeight100, + contentStatement: fontLineHeight900, + contentExpressiveLarge: fontLineHeight900, + contentExpressiveMedium: fontLineHeight800, + contentExpressiveSmall: fontLineHeight600, + contentH1: fontLineHeight800, + contentH2: fontLineHeight800, + contentH3: fontLineHeight600, + contentH4: fontLineHeight500, + contentH5: fontLineHeight400, + contentSubheadline: fontLineHeight400, + contentParagraphLarge: fontLineHeight600, + contentParagraphMedium: fontLineHeight500, + contentParagraphSmall: fontLineHeight300, + contentSubtext: fontLineHeight100, + contentTable: fontLineHeight400, + contentCode: fontLineHeight400, + }, + borderRadius: { + base100: cornerRadius20, + base400: cornerRadius60, + base600: cornerRadius80, + base700: cornerRadius120, + circular: cornerRadiusCircular, + }, + spacing: { + componentBase50: size20, + componentBase100: size40, + componentBase150: size60, + componentBase200: size80, + componentBase250: size100, + componentBase300: size120, + componentBase400: size160, + componentBase500: size200, + componentBase600: size240, + componentBase700: size280, + componentBase800: size320, + layoutBase100: size80, + layoutBase200: size160, + layoutBase300: size240, + layoutBase400: size320, + layoutBase450: size360, + layoutBase500: size400, + layoutBase600: size480, + layoutBase700: size560, + layoutBase800: size640, + layoutBase1000: size800, + layoutBase1200: size800, + }, + strokeWidth: { + thin: strokeWidth10, + thick: strokeWidth20, + thicker: strokeWidth30, + thickest: strokeWidth40, + }, + motion: { + durationBase50: 50, + durationBase100: 100, + durationBase200: 200, + durationBase300: 300, + durationBase500: 500, + durationBase1000: 1000, + easingFunctionalEnter: [0, 0, 0, 1], + easingFunctionalExit: [0.6, 0, 0.75, 0.4], + easingFunctionalTransition: [0.33, 0, 0, 1], + easingFunctionalLinear: [0, 0, 1, 1], + easingExpressiveEnter: [0, 0, 0, 1], + easingExpressiveExit: [0.6, 0, 0.75, 0.4], + easingExpressiveTransition: [0.33, 0, 0, 1], + }, +} satisfies NonFluentFlexTokens; + +const ambient = { x: 0, y: 0, blur: 2, color: '#0000001f' }; +const ambientHigh = { x: 0, y: 0, blur: 8, color: '#00000033' }; + +/** + * Fluent-native fallback token values for the default appearance, layered + * under values that have no FURN Theme source. The forward Theme adapter uses + * them when a Theme omits a mapped value. Every interactive fallback authors + * explicit states, so no interaction algorithm runs. + */ +const fluentFallbackFlexTokenDescription = createFlexTokenDescription({ + ...nonFluentFlexTokens, + color: { + ...nonFluentFlexTokens.color, + surfaceNeutralFarther: { rest: '#ebebeb', hover: '#f5f5f5', pressed: '#f0f0f0' }, + surfaceNeutralFar: { rest: '#f5f5f5', hover: '#ebebeb', pressed: '#d6d6d6' }, + surfaceNeutralNear: { rest: '#fafafa', hover: '#f0f0f0', pressed: '#dbdbdb' }, + surfaceNeutralNearer: { rest: '#ffffff', hover: '#f5f5f5', pressed: '#e0e0e0' }, + backgroundNeutralHeavy: { rest: '#616161', hover: '#616161', pressed: '#616161', type: 'inverted' }, + backgroundNeutralLoud: { rest: '#616161', hover: '#616161', pressed: '#616161', type: 'inverted' }, + backgroundNeutralSubtle: { rest: '#fafafa', hover: '#f0f0f0', pressed: '#dbdbdb' }, + backgroundNeutralTransparent: { rest: '#00000000', hover: '#00000000', pressed: '#00000000' }, + backgroundBrandHeavy: { rest: '#185abd', hover: '#1651aa', pressed: '#0e336a', type: 'inverted' }, + backgroundBrandLoud: { rest: '#185abd', hover: '#1651aa', pressed: '#0e336a', type: 'inverted' }, + backgroundBrandSoft: { rest: '#d2e0f4', hover: '#d2e0f4', pressed: '#d2e0f4' }, + backgroundBrandSubtle: { rest: '#d2e0f4', hover: '#d2e0f4', pressed: '#d2e0f4' }, + backgroundBrandTransparent: { rest: '#00000000', hover: '#00000000', pressed: '#00000000' }, + backgroundDangerLoud: { rest: '#d13438', hover: '#d13438', pressed: '#d13438', type: 'inverted' }, + backgroundDangerSoft: { rest: '#f1bbbc', hover: '#f1bbbc', pressed: '#f1bbbc' }, + backgroundDangerSubtle: { rest: '#fdf6f6', hover: '#fdf6f6', pressed: '#fdf6f6' }, + backgroundWarningLoud: { rest: '#fde300', hover: '#fde300', pressed: '#fde300', type: 'inverted' }, + backgroundWarningSoft: { rest: '#fef7b2', hover: '#fef7b2', pressed: '#fef7b2' }, + backgroundWarningSubtle: { rest: '#fffef5', hover: '#fffef5', pressed: '#fffef5' }, + backgroundSuccessLoud: { rest: '#107c10', hover: '#107c10', pressed: '#107c10', type: 'inverted' }, + backgroundSuccessSoft: { rest: '#9fd89f', hover: '#9fd89f', pressed: '#9fd89f' }, + backgroundSuccessSubtle: { rest: '#f1faf1', hover: '#f1faf1', pressed: '#f1faf1' }, + strokeNeutralHeavy: { rest: '#616161', hover: '#575757', pressed: '#4d4d4d', type: 'inverted' }, + strokeNeutralLoud: { rest: '#d1d1d1', hover: '#c7c7c7', pressed: '#b3b3b3', type: 'inverted' }, + strokeNeutralSoft: { rest: '#d1d1d1', hover: '#c7c7c7', pressed: '#b3b3b3' }, + strokeNeutralSubtle: { rest: '#e0e0e0', hover: '#e0e0e0', pressed: '#e0e0e0' }, + strokeNeutralTransparent: { rest: '#00000000', hover: '#00000000', pressed: '#00000000' }, + strokeNeutralOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + strokeBrandLoud: { rest: '#185abd', hover: '#185abd', pressed: '#185abd', type: 'inverted' }, + strokeBrandSoft: { rest: '#185abd', hover: '#185abd', pressed: '#185abd' }, + strokeBrandSubtle: { rest: '#6794d7', hover: '#6794d7', pressed: '#6794d7' }, + strokeBrandOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + strokeDangerLoud: { rest: '#d13438', hover: '#d13438', pressed: '#d13438', type: 'inverted' }, + strokeDangerSoft: { rest: '#f1bbbc', hover: '#f1bbbc', pressed: '#f1bbbc' }, + strokeDangerSubtle: { rest: '#f1bbbc', hover: '#f1bbbc', pressed: '#f1bbbc' }, + strokeDangerOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + strokeWarningLoud: { rest: '#fde300', hover: '#fde300', pressed: '#fde300', type: 'inverted' }, + strokeWarningSoft: { rest: '#fef7b2', hover: '#fef7b2', pressed: '#fef7b2' }, + strokeWarningSubtle: { rest: '#fef7b2', hover: '#fef7b2', pressed: '#fef7b2' }, + strokeWarningOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + strokeSuccessLoud: { rest: '#107c10', hover: '#107c10', pressed: '#107c10', type: 'inverted' }, + strokeSuccessSoft: { rest: '#9fd89f', hover: '#9fd89f', pressed: '#9fd89f' }, + strokeSuccessSubtle: { rest: '#9fd89f', hover: '#9fd89f', pressed: '#9fd89f' }, + strokeSuccessOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + foregroundNeutralPrimary: { rest: '#242424', hover: '#242424', pressed: '#242424' }, + foregroundNeutralSecondary: { rest: '#424242', hover: '#242424', pressed: '#242424' }, + foregroundNeutralTertiary: { rest: '#616161', hover: '#424242', pressed: '#424242' }, + foregroundNeutralOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + foregroundBrandPrimary: { rest: '#185abd', hover: '#185abd', pressed: '#185abd' }, + foregroundBrandOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + foregroundDangerPrimary: { rest: '#bc2f32', hover: '#bc2f32', pressed: '#bc2f32' }, + foregroundDangerOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + foregroundWarningPrimary: { rest: '#817400', hover: '#817400', pressed: '#817400' }, + foregroundWarningOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + foregroundSuccessPrimary: { rest: '#0e700e', hover: '#0e700e', pressed: '#0e700e' }, + foregroundSuccessOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, + fixedWhite: '#ffffff', + fixedBlack: '#000000', + expressionAchromaticHeavy: '#000000', + expressionAchromaticSubtle: '#ffffff', + backgroundNeutralDisabled: '#f0f0f0', + backgroundNeutralHeavyDisabled: '#f0f0f0', + backgroundNeutralSubtleDisabled: '#f0f0f0', + strokeNeutralDisabled: '#e0e0e0', + foregroundNeutralDisabled: '#bdbdbd', + strokeFocusInner: '#ffffff', + strokeFocusOuter: '#000000', + shadow: '#000000', + }, + shadow: { + lowest: [ambient, { x: 0, y: 1, blur: 2, color: '#00000024' }], + lower: [ambient, { x: 0, y: 2, blur: 4, color: '#00000024' }], + low: [ambient, { x: 0, y: 4, blur: 8, color: '#00000024' }], + high: [ambient, { x: 0, y: 8, blur: 16, color: '#00000024' }], + higher: [ambientHigh, { x: 0, y: 14, blur: 28, color: '#0000003d' }], + highest: [ambientHigh, { x: 0, y: 32, blur: 64, color: '#0000003d' }], + }, + fontWeight: { + functionalRegular: fontWeightRegular, + functionalMedium: fontWeightMedium, + functionalSemibold: fontWeightSemibold, + functionalBold: fontWeightBold, + contentRegular: fontWeightRegular, + contentMedium: fontWeightMedium, + contentSemibold: fontWeightSemibold, + contentBold: fontWeightBold, + contentEditorialRegular: fontWeightRegular, + contentEditorialMedium: fontWeightMedium, + contentEditorialSemibold: fontWeightSemibold, + contentEditorialBold: fontWeightBold, + }, + fontFamily: { + functional: fontFamilyBase, + content: fontFamilyBase, + contentEditorial: fontFamilyBase, + contentCode: fontFamilyMonospace, + }, + fontSize: { + functionalDisplay: fontSize1000, + functionalPagetitle: fontSize900, + functionalTitleLarge: fontSize800, + functionalTitleMedium: fontSize700, + functionalTitleSmall: fontSize600, + functionalSubtitle: fontSize500, + functionalBodyLarge: fontSize400, + functionalBodyMedium: fontSize300, + functionalBodySmall: fontSize200, + functionalCaption: fontSize100, + contentStatement: fontSize1000, + contentExpressiveLarge: fontSize900, + contentExpressiveMedium: fontSize800, + contentExpressiveSmall: fontSize700, + contentH1: fontSize800, + contentH2: fontSize800, + contentH3: fontSize700, + contentH4: fontSize600, + contentH5: fontSize500, + contentSubheadline: fontSize400, + contentParagraphLarge: fontSize500, + contentParagraphMedium: fontSize400, + contentParagraphSmall: fontSize200, + contentSubtext: fontSize100, + contentTable: fontSize400, + contentCode: fontSize400, + }, + borderRadius: { + ...nonFluentFlexTokens.borderRadius, + base200: cornerRadius40, + base300: cornerRadius40, + }, +}); + +/** + * Fluent-native fallback tokens resolved for the default appearance. + */ +export const fluentFallbackFlexTokens: FlexTokens = resolveExplicitFlexTokenDescription( + fluentFallbackFlexTokenDescription, + defaultResolvedThemeAppearance, +); diff --git a/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts b/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts index ca613e2670..e84c1f19a3 100644 --- a/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts +++ b/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts @@ -1,17 +1,13 @@ import { PlatformColor } from 'react-native'; import { getInteractionColorOverrides, restColorValues } from '../../test/fixtures/interactionColors'; -import { - x3BebopWarmInteractionConformance, - x3InteractionConformance, - x3WarmToneDeviations, -} from '../../test/fixtures/x3InteractionConformance'; +import { x3WarmInteractionConformance, x3InteractionConformance, x3CoolExplicitStates } from '../../test/fixtures/x3InteractionConformance'; import type { InteractionConformanceVector } from '../../test/fixtures/x3InteractionConformance'; import type { ColorMode } from '../../color-lib/types'; import type { ColorTone, NormalizedThemeAppearance } from '../../types/appearance.types'; import { defaultFlexTokenDescription, defaultFlexTokens } from '../defaults/defaultTokens'; import type { SemanticColorTokenValues } from '../tokens.types'; -import { normalizeFlexColor } from './flexColor'; +import { normalizeFlexColor, selectColorEntry } from './flexColor'; import { deriveInteractionColor, resolveFlexColor, resolveFlexTokenDescription } from './interactionPolicy'; import { getInteractionCompositing, @@ -72,7 +68,7 @@ describe('interactive token classification', () => { expect(INTERACTIVE_COLOR_TOKENS.filter(isInverseInteractionToken)).toEqual(expected); expect(INTERACTIVE_COLOR_TOKENS.filter((token) => getInteractionDirection(token) === 'inverted')).toEqual(expected); expect(INTERACTIVE_COLOR_TOKENS).toHaveLength(59); - expect(Object.keys(x3WarmToneDeviations)).toHaveLength(10); + expect(Object.keys(x3CoolExplicitStates)).toHaveLength(10); }); it('composites only background and stroke tokens against the warm backdrop', () => { @@ -83,31 +79,48 @@ describe('interactive token classification', () => { }); }); +describe('default explicit interaction states', () => { + it('authors exactly the cool table states the policy cannot reproduce', () => { + const authored = Object.entries(defaultFlexTokenDescription.color).flatMap(([token, color]) => + (['hover', 'pressed'] as const).filter((state) => color[state] !== undefined).map((state) => `${token}.${state}`), + ); + const fixtureStates = new Set(Object.keys(x3CoolExplicitStates).map((key) => key.slice(0, key.lastIndexOf('.')))); + + expect(authored.sort()).toEqual([...fixtureStates].sort()); + for (const [key, { sourceValue }] of Object.entries(x3CoolExplicitStates)) { + const [token, state, mode] = key.split('.') as [keyof SemanticColorTokenValues, 'hover' | 'pressed', ColorMode]; + const entry = defaultFlexTokenDescription.color[token][state]; + + expect([key, entry === undefined ? undefined : selectColorEntry(entry, appearance(mode))]).toEqual([key, sourceValue]); + } + }); +}); + describe.each(['light', 'dark'] as const)('%s Flex interaction policy', (mode) => { it.each(INTERACTIVE_COLOR_TOKENS)('matches the cool and warm conformance values for %s', (token) => { const vector = x3InteractionConformance[token]; - const warmVector = x3BebopWarmInteractionConformance[token]; + const warmVector = x3WarmInteractionConformance[token]; for (const state of ['hover', 'pressed'] as const) { - const deviationKey = `${token}.${state}.${mode}` as keyof typeof x3WarmToneDeviations; - const deviation = x3WarmToneDeviations[deviationKey]; + const explicitKey = `${token}.${state}.${mode}` as keyof typeof x3CoolExplicitStates; + const explicitState = x3CoolExplicitStates[explicitKey]; const upstreamValue = vector[modeIndexes[mode][state]]; const direction = getInteractionDirection(token); expect(deriveInteractionColor(vector[modeIndexes[mode].rest], token, state, direction, appearance(mode))).toBe( - deviation?.defaultValue ?? upstreamValue, + explicitState?.derivedValue ?? upstreamValue, ); expect(deriveInteractionColor(warmVector[modeIndexes[mode].rest], token, state, direction, appearance(mode, 'warm'))).toBe( warmVector[modeIndexes[mode][state]], ); - if (deviation) { - expect(upstreamValue).toBe(deviation.warmValue); + if (explicitState) { + expect(upstreamValue).toBe(explicitState.sourceValue); } } }); it.each(['cool', 'warm'] as const)('derives a complete %s override map', (colorTone) => { - const conformance = colorTone === 'warm' ? x3BebopWarmInteractionConformance : x3InteractionConformance; + const conformance = colorTone === 'warm' ? x3WarmInteractionConformance : x3InteractionConformance; const result = getInteractionColorOverrides(restColors(mode, conformance), mode, 'hover', colorTone); expect(result.diagnostics).toEqual([]); diff --git a/packages/agentic/design/src/flex/colors/interactiveTokens.ts b/packages/agentic/design/src/flex/colors/interactiveTokens.ts index 058eeb2495..e780bc9b7a 100644 --- a/packages/agentic/design/src/flex/colors/interactiveTokens.ts +++ b/packages/agentic/design/src/flex/colors/interactiveTokens.ts @@ -6,7 +6,7 @@ import type { SemanticColorName } from '../tokens.types'; * compute omitted hover and pressed states; every other token's states equal * rest unless authored explicitly. * - * Source: x3-design/fluent-design@d334acf5cbad813f2b7cd554da942b09a7ff8f10. + * Source: x3-design/fluent-design@206e890b645fb450ad7c5df2ff981765349a2b58. */ export const INTERACTIVE_COLOR_TOKENS = [ 'surfaceNeutralFarther', diff --git a/packages/agentic/design/src/flex/defaults/defaultTokens.generated.ts b/packages/agentic/design/src/flex/defaults/defaultTokens.generated.ts new file mode 100644 index 0000000000..25aa8ae64d --- /dev/null +++ b/packages/agentic/design/src/flex/defaults/defaultTokens.generated.ts @@ -0,0 +1,463 @@ +// Generated by scripts/flex-defaults/generate-defaults.mjs. Do not edit; run `yarn gen:flex-defaults`. +// Source: x3-design/fluent-design@206e890b645fb450ad7c5df2ff981765349a2b58 +// cool: dev/web/flex-themes/css/semantic.css, dev/web/flex-themes/css/interaction-fallback.css +// warm: dev/web/flex-themes/css/warm/semantic.css, dev/web/flex-themes/css/warm/interaction-fallback.css +// Generic sources: src/tokens/mappings/flex-token-map.yaml +// Coverage: scripts/flex-defaults/coverage.generated.json + +import { + fontFamilyBase, + fontFamilyMonospace, + fontWeightBold, + fontWeightMedium, + fontWeightRegular, + fontWeightSemibold, +} from '../../tokens/global.generated'; +import type { CompleteFlexTokenInput } from '../tokens.types'; + +const sharedTokens = { + shadow: { + lowest: [ + [{ x: 0, y: 0, blur: 2, color: '#0000001a' }, { x: 0, y: 1, blur: 2, color: '#0000000d' }], + [{ x: 0, y: 0, blur: 2, color: '#00000033' }, { x: 0, y: 1, blur: 2, color: '#0000001a' }], + ], + lower: [ + [{ x: 0, y: 0, blur: 2, color: '#0000001a' }, { x: 0, y: 2, blur: 4, color: '#00000014' }], + [{ x: 0, y: 0, blur: 2, color: '#00000033' }, { x: 0, y: 2, blur: 4, color: '#00000029' }], + ], + low: [ + [ + { x: 0, y: 0, blur: 2, color: '#0000001a' }, + { x: 0, y: 2, blur: 4, color: '#00000008' }, + { x: 0, y: 4, blur: 8, color: '#00000014' }, + ], + [ + { x: 0, y: 0, blur: 2, color: '#00000033' }, + { x: 0, y: 2, blur: 4, color: '#0000001f' }, + { x: 0, y: 4, blur: 8, color: '#00000029' }, + ], + ], + high: [ + [ + { x: 0, y: 0, blur: 2, color: '#0000001a' }, + { x: 0, y: 4, blur: 8, color: '#00000008' }, + { x: 0, y: 8, blur: 16, color: '#0000000f' }, + ], + [ + { x: 0, y: 0, blur: 2, color: '#00000033' }, + { x: 0, y: 4, blur: 8, color: '#0000001f' }, + { x: 0, y: 8, blur: 16, color: '#0000001f' }, + ], + ], + higher: [ + [ + { x: 0, y: 0, blur: 2, color: '#0000001a' }, + { x: 0, y: 8, blur: 16, color: '#00000008' }, + { x: 0, y: 16, blur: 32, color: '#0000000f' }, + ], + [ + { x: 0, y: 0, blur: 2, color: '#00000033' }, + { x: 0, y: 8, blur: 16, color: '#0000001f' }, + { x: 0, y: 16, blur: 32, color: '#0000001f' }, + ], + ], + highest: [ + [ + { x: 0, y: 0, blur: 2, color: '#0000001a' }, + { x: 0, y: 8, blur: 16, color: '#00000008' }, + { x: 0, y: 32, blur: 64, color: '#0000000f' }, + ], + [ + { x: 0, y: 0, blur: 2, color: '#00000033' }, + { x: 0, y: 8, blur: 16, color: '#0000001f' }, + { x: 0, y: 32, blur: 64, color: '#0000001f' }, + ], + ], + }, + fontWeight: { + functionalRegular: fontWeightRegular, + functionalMedium: fontWeightMedium, + functionalSemibold: fontWeightSemibold, + functionalBold: fontWeightBold, + contentRegular: fontWeightRegular, + contentMedium: fontWeightMedium, + contentSemibold: fontWeightSemibold, + contentBold: fontWeightBold, + contentEditorialRegular: fontWeightRegular, + contentEditorialMedium: fontWeightMedium, + contentEditorialSemibold: fontWeightSemibold, + contentEditorialBold: fontWeightBold, + }, + fontFamily: { + functional: fontFamilyBase, + content: fontFamilyBase, + contentEditorial: fontFamilyBase, + contentCode: fontFamilyMonospace, + }, + fontSize: { + functionalDisplay: 68, + functionalPagetitle: 40, + functionalTitleLarge: 32, + functionalTitleMedium: 28, + functionalTitleSmall: 24, + functionalSubtitle: 20, + functionalBodyLarge: 16, + functionalBodyMedium: 14, + functionalBodySmall: 12, + functionalCaption: 10, + contentStatement: 56, + contentExpressiveLarge: 48, + contentExpressiveMedium: 36, + contentExpressiveSmall: 28, + contentH1: 36, + contentH2: 32, + contentH3: 28, + contentH4: 24, + contentH5: 20, + contentSubheadline: 16, + contentParagraphLarge: 20, + contentParagraphMedium: 16, + contentParagraphSmall: 12, + contentSubtext: 10, + contentTable: 16, + contentCode: 16, + }, + lineHeight: { + functionalDisplay: 82, + functionalPagetitle: 48, + functionalTitleLarge: 38, + functionalTitleMedium: 34, + functionalTitleSmall: 28, + functionalSubtitle: 28, + functionalBodyLarge: 22, + functionalBodyMedium: 20, + functionalBodySmall: 16, + functionalCaption: 14, + contentStatement: 68, + contentExpressiveLarge: 58, + contentExpressiveMedium: 44, + contentExpressiveSmall: 34, + contentH1: 44, + contentH2: 38, + contentH3: 34, + contentH4: 28, + contentH5: 24, + contentSubheadline: 22, + contentParagraphLarge: 34, + contentParagraphMedium: 28, + contentParagraphSmall: 20, + contentSubtext: 14, + contentTable: 22, + contentCode: 22, + }, + borderRadius: { + base100: 4, + base200: 8, + base300: 12, + base400: 16, + base600: 24, + base700: 28, + circular: 9999, + }, + spacing: { + componentBase50: 2, + componentBase100: 4, + componentBase150: 6, + componentBase200: 8, + componentBase250: 10, + componentBase300: 12, + componentBase400: 16, + componentBase500: 20, + componentBase600: 24, + componentBase700: 28, + componentBase800: 32, + layoutBase100: 8, + layoutBase200: 16, + layoutBase300: 24, + layoutBase400: 32, + layoutBase450: 36, + layoutBase500: 40, + layoutBase600: 48, + layoutBase700: 56, + layoutBase800: 64, + layoutBase1000: 80, + layoutBase1200: 96, + }, + strokeWidth: { + thin: 1, + thick: 2, + thicker: 3, + thickest: 4, + }, + motion: { + durationBase50: 50, + durationBase100: 100, + durationBase200: 200, + durationBase300: 300, + durationBase500: 500, + durationBase1000: 1000, + easingFunctionalEnter: [0, 0, 0, 1], + easingFunctionalExit: [0.6, 0, 0.75, 0.4], + easingFunctionalTransition: [0.33, 0, 0, 1], + easingFunctionalLinear: [0, 0, 1, 1], + easingExpressiveEnter: [0, 0, 0, 1], + easingExpressiveExit: [0.6, 0, 0.75, 0.4], + easingExpressiveTransition: [0.33, 0, 0, 1], + }, +} satisfies Partial>; + +/** The x3 cool-tone defaults. Omitted interaction states are computed from rest. */ +export const coolFlexTokenInput: CompleteFlexTokenInput = { + ...sharedTokens, + color: { + surfaceNeutralFarther: ['#ebebeb', '#1b1b1b'], + surfaceNeutralFar: ['#f2f2f2', '#1f1f1f'], + surfaceNeutralNear: ['#fcfcfc', '#181818'], + surfaceNeutralNearer: ['#ffffff', '#292929'], + surfaceNeutralTranslucent: ['#ffffff80', '#3c3c3c80'], + backgroundNeutralHeavy: { rest: ['#242424', '#ffffff'], type: 'inverted' }, + backgroundNeutralLoud: { rest: ['#6f6f6f', '#929292'], type: 'inverted' }, + backgroundNeutralSoft: ['#00000014', '#ffffff1f'], + backgroundNeutralSubtle: ['#0000000d', '#ffffff14'], + backgroundNeutralTransparent: ['#24242400', '#ffffff00'], + backgroundNeutralTranslucent: { + rest: ['#e9e9e980', '#3c3c3c80'], + hover: ['#d8d8d88a', '#56565688'], + pressed: ['#cacaca94', '#6d6d6d8f'], + }, + backgroundBrandHeavy: { rest: ['#242424', '#ffffff'], type: 'inverted' }, + backgroundBrandLoud: { rest: ['#6f6f6f', '#929292'], type: 'inverted' }, + backgroundBrandSoft: ['#00000014', '#ffffff1f'], + backgroundBrandSubtle: ['#0000000a', '#ffffff14'], + backgroundBrandTransparent: ['#24242400', '#ffffff00'], + backgroundDangerLoud: { rest: ['#c02e56', '#e55e7a'], type: 'inverted' }, + backgroundDangerSoft: ['#ffe3e6', '#5a2932'], + backgroundDangerSubtle: ['#fff1f3', '#402529'], + backgroundWarningLoud: { rest: ['#bb4001', '#e56738'], type: 'inverted' }, + backgroundWarningSoft: ['#ffe5dc', '#592c1c'], + backgroundWarningSubtle: ['#fff2ee', '#40261d'], + backgroundSuccessLoud: { rest: ['#008455', '#05ad72'], type: 'inverted' }, + backgroundSuccessSoft: ['#c9f8dd', '#0c462d'], + backgroundSuccessSubtle: ['#e3fcee', '#193426'], + strokeNeutralHeavy: { rest: ['#242424', '#dedede'], type: 'inverted' }, + strokeNeutralLoud: { rest: ['#6f6f6f', '#929292'], type: 'inverted' }, + strokeNeutralSoft: { rest: ['#0000006d', '#ffffff61'], hover: ['#02020277', '#ffffff69'], pressed: ['#04040481', '#ffffff70'] }, + strokeNeutralSubtle: { rest: ['#00000021', '#ffffff48'], pressed: ['#05050535', '#ffffff57'] }, + strokeNeutralTransparent: ['#24242400', '#ffffff00'], + strokeNeutralOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, + strokeBrandLoud: { rest: ['#6f6f6f', '#929292'], type: 'inverted' }, + strokeBrandSoft: { rest: ['#0000006d', '#ffffff61'], hover: ['#02020277', '#ffffff69'], pressed: ['#04040481', '#ffffff70'] }, + strokeBrandSubtle: { rest: ['#00000021', '#ffffff48'], pressed: ['#05050535', '#ffffff57'] }, + strokeBrandOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, + strokeDangerLoud: { rest: ['#c02e56', '#e55e7a'], type: 'inverted' }, + strokeDangerSoft: ['#e55e7a', '#d14164'], + strokeDangerSubtle: ['#ffd0d6', '#76293a'], + strokeDangerOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, + strokeWarningLoud: { rest: ['#cd4808', '#e56738'], type: 'inverted' }, + strokeWarningSoft: ['#fc9571', '#cd4808'], + strokeWarningSubtle: ['#ffd3c4', '#762e12'], + strokeWarningOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, + strokeSuccessLoud: { rest: ['#008455', '#05ad72'], type: 'inverted' }, + strokeSuccessSoft: ['#5dce97', '#008e5c'], + strokeSuccessSubtle: ['#b1efcc', '#025636'], + strokeSuccessOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, + foregroundNeutralPrimary: ['#000000db', '#ffffffde'], + foregroundNeutralSecondary: ['#000000a2', '#ffffffa1'], + foregroundNeutralTertiary: ['#00000090', '#ffffff80'], + foregroundNeutralOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, + foregroundBrandPrimary: ['#242424', '#dedede'], + foregroundBrandOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, + foregroundDangerPrimary: ['#a62147', '#fd8ea1'], + foregroundDangerOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, + foregroundWarningPrimary: ['#a93901', '#fc9571'], + foregroundWarningOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, + foregroundSuccessPrimary: ['#017048', '#5dce97'], + foregroundSuccessOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, + fixedWhite: '#ffffff', + fixedBlack: '#000000', + expressionAccentHeavy: ['#242424', '#ffffff'], + expressionAccentLoud: ['#6f6f6f', '#929292'], + expressionAccentSoft: ['#00000014', '#ffffff1f'], + expressionAccentSubtle: ['#0000000d', '#ffffff14'], + expressionAchromaticHeavy: ['#000000', '#ffffff'], + expressionAchromaticSubtle: ['#ffffff', '#000000'], + expressionGrayHeavy: ['#484848', '#f5f5f5'], + expressionGrayLoud: ['#929292', '#dedede'], + expressionGraySoft: ['#dedede', '#929292'], + expressionGraySubtle: ['#f5f5f5', '#484848'], + expressionNavyHeavy: ['#294482', '#f0f5ff'], + expressionNavyLoud: ['#5c8df8', '#cedeff'], + expressionNavySoft: ['#cedeff', '#5c8df8'], + expressionNavySubtle: ['#f0f5ff', '#294482'], + expressionBlueHeavy: ['#0b497f', '#eef6ff'], + expressionBlueLoud: ['#2f95f4', '#c6e1ff'], + expressionBlueSoft: ['#c6e1ff', '#2f95f4'], + expressionBlueSubtle: ['#eef6ff', '#0b497f'], + expressionGreenHeavy: ['#0c5722', '#e7fce9'], + expressionGreenLoud: ['#32ad52', '#baedc1'], + expressionGreenSoft: ['#baedc1', '#32ad52'], + expressionGreenSubtle: ['#e7fce9', '#0c5722'], + expressionLimeHeavy: ['#345200', '#e6ffcf'], + expressionLimeLoud: ['#6da603', '#cbff93'], + expressionLimeSoft: ['#cbff93', '#6da603'], + expressionLimeSubtle: ['#e6ffcf', '#345200'], + expressionYellowHeavy: ['#524800', '#fff7c4'], + expressionYellowLoud: ['#fbdf06', '#ffed85'], + expressionYellowSoft: ['#ffed85', '#fbdf06'], + expressionYellowSubtle: ['#fff7c4', '#524800'], + expressionPumpkinHeavy: ['#762f0e', '#fef2ee'], + expressionPumpkinLoud: ['#fb966e', '#ffd3c2'], + expressionPumpkinSoft: ['#ffd3c2', '#fb966e'], + expressionPumpkinSubtle: ['#fef2ee', '#762f0e'], + expressionRedHeavy: ['#772b28', '#fff2f0'], + expressionRedLoud: ['#e7615b', '#ffd2cd'], + expressionRedSoft: ['#ffd2cd', '#e7615b'], + expressionRedSubtle: ['#fff2f0', '#772b28'], + expressionPinkHeavy: ['#6f2b53', '#fff1f7'], + expressionPinkLoud: ['#d961a6', '#ffcee6'], + expressionPinkSoft: ['#ffcee6', '#d961a6'], + expressionPinkSubtle: ['#fff1f7', '#6f2b53'], + expressionPurpleHeavy: ['#523778', '#f7f3ff'], + expressionPurpleLoud: ['#a575e8', '#e4d6ff'], + expressionPurpleSoft: ['#e4d6ff', '#a575e8'], + expressionPurpleSubtle: ['#f7f3ff', '#523778'], + overlayNeutralTranslucent: ['#00000026', '#00000099'], + materialBackgroundThick: ['#fffffff1', '#262626ea'], + materialBackgroundRegular: ['#ffffffd7', '#2f2f2fd1'], + materialBackgroundThin: ['#ffffff7e', '#3434348b'], + backgroundNeutralDisabled: ['#00000008', '#ffffff07'], + backgroundNeutralHeavyDisabled: ['#0000001a', '#ffffff20'], + backgroundNeutralSubtleDisabled: ['#00000008', '#ffffff07'], + strokeNeutralDisabled: ['#00000014', '#ffffff24'], + foregroundNeutralDisabled: ['#0000006d', '#ffffff61'], + strokeFocusInner: ['#ffffff', '#000000'], + strokeFocusOuter: ['#000000', '#ffffff'], + shadow: '#000000', + }, +}; + +/** The x3 warm-tone defaults. Omitted interaction states are computed from rest. */ +export const warmFlexTokenInput: CompleteFlexTokenInput = { + ...sharedTokens, + color: { + surfaceNeutralFarther: ['#f0eae5', '#1e1916'], + surfaceNeutralFar: ['#faf4f0', '#231e1a'], + surfaceNeutralNear: ['#f6f1ec', '#1c1714'], + surfaceNeutralNearer: ['#ffffff', '#2e2823'], + surfaceNeutralTranslucent: ['#ffffff80', '#00000080'], + backgroundNeutralHeavy: { rest: ['#28231e', '#ffffff'], type: 'inverted' }, + backgroundNeutralLoud: { rest: ['#1e0d009a', '#ffeee39a'], type: 'inverted' }, + backgroundNeutralSoft: ['#4d200028', '#ffe3cb40'], + backgroundNeutralSubtle: ['#6c31001a', '#fff4ef14'], + backgroundNeutralTransparent: ['#28231e00', '#ffffff00'], + backgroundNeutralTranslucent: ['#e9e9e980', '#3c3c3c80'], + backgroundBrandHeavy: { rest: ['#28231e', '#ffffff'], type: 'inverted' }, + backgroundBrandLoud: { rest: ['#1e0d009a', '#ffeee39a'], type: 'inverted' }, + backgroundBrandSoft: ['#4d200028', '#ffe3cb40'], + backgroundBrandSubtle: ['#6c31001a', '#fff4ef14'], + backgroundBrandTransparent: ['#28231e00', '#ffffff00'], + backgroundDangerLoud: { rest: ['#c02e56', '#e55e7a'], type: 'inverted' }, + backgroundDangerSoft: ['#ffe3e6', '#5a2932'], + backgroundDangerSubtle: ['#fff1f3', '#402529'], + backgroundWarningLoud: { rest: ['#bb4001', '#e56738'], type: 'inverted' }, + backgroundWarningSoft: ['#ffe5dc', '#592c1c'], + backgroundWarningSubtle: ['#fff2ee', '#40261d'], + backgroundSuccessLoud: { rest: ['#008455', '#05ad72'], type: 'inverted' }, + backgroundSuccessSoft: ['#c9f8dd', '#0c462d'], + backgroundSuccessSubtle: ['#e3fcee', '#193426'], + strokeNeutralHeavy: { rest: ['#28231e', '#e3dcd7'], type: 'inverted' }, + strokeNeutralLoud: { rest: ['#776d65', '#9a9089'], type: 'inverted' }, + strokeNeutralSoft: ['#250f0076', '#ffe6d35c'], + strokeNeutralSubtle: ['#4d200028', '#ffe3cb40'], + strokeNeutralTransparent: ['#28231e00', '#ffffff00'], + strokeNeutralOnloud: { rest: ['#ffffff', '#0b0600e1'], type: 'inverted' }, + strokeBrandLoud: { rest: ['#776d65', '#9a9089'], type: 'inverted' }, + strokeBrandSoft: ['#250f0076', '#ffe6d35c'], + strokeBrandSubtle: ['#4d200028', '#ffe3cb40'], + strokeBrandOnloud: { rest: ['#ffffff', '#0b0600e1'], type: 'inverted' }, + strokeDangerLoud: { rest: ['#c02e56', '#e55e7a'], type: 'inverted' }, + strokeDangerSoft: ['#e55e7a', '#d14164'], + strokeDangerSubtle: ['#ffd0d6', '#76293a'], + strokeDangerOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, + strokeWarningLoud: { rest: ['#cd4808', '#e56738'], type: 'inverted' }, + strokeWarningSoft: ['#fc9571', '#cd4808'], + strokeWarningSubtle: ['#ffd3c4', '#762e12'], + strokeWarningOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, + strokeSuccessLoud: { rest: ['#008455', '#05ad72'], type: 'inverted' }, + strokeSuccessSoft: ['#5dce97', '#008e5c'], + strokeSuccessSubtle: ['#b1efcc', '#025636'], + strokeSuccessOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, + foregroundNeutralPrimary: ['#0b0600e1', '#fff7f2e3'], + foregroundNeutralSecondary: ['#190c00ab', '#fff2e8b5'], + foregroundNeutralTertiary: ['#1e0d009a', '#ffeee39a'], + foregroundNeutralOnloud: { rest: ['#ffffff', '#0b0600e1'], type: 'inverted' }, + foregroundBrandPrimary: ['#0b0600e1', '#fff7f2e3'], + foregroundBrandOnloud: { rest: ['#ffffff', '#0b0600e1'], type: 'inverted' }, + foregroundDangerPrimary: ['#a62147', '#fd8ea1'], + foregroundDangerOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, + foregroundWarningPrimary: ['#a93901', '#fc9571'], + foregroundWarningOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, + foregroundSuccessPrimary: ['#017048', '#5dce97'], + foregroundSuccessOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, + fixedWhite: '#ffffff', + fixedBlack: '#000000', + expressionAccentHeavy: ['#28231e', '#ffffff'], + expressionAccentLoud: ['#1e0d009a', '#ffeee39a'], + expressionAccentSoft: ['#4d200028', '#ffe3cb40'], + expressionAccentSubtle: ['#6c31001a', '#fff4ef14'], + expressionAchromaticHeavy: ['#000000', '#ffffff'], + expressionAchromaticSubtle: ['#ffffff', '#000000'], + expressionGrayHeavy: ['#484848', '#f5f5f5'], + expressionGrayLoud: ['#929292', '#dedede'], + expressionGraySoft: ['#dedede', '#929292'], + expressionGraySubtle: ['#f5f5f5', '#484848'], + expressionNavyHeavy: ['#294482', '#f0f5ff'], + expressionNavyLoud: ['#5c8df8', '#cedeff'], + expressionNavySoft: ['#cedeff', '#5c8df8'], + expressionNavySubtle: ['#f0f5ff', '#294482'], + expressionBlueHeavy: ['#0b497f', '#eef6ff'], + expressionBlueLoud: ['#2f95f4', '#c6e1ff'], + expressionBlueSoft: ['#c6e1ff', '#2f95f4'], + expressionBlueSubtle: ['#eef6ff', '#0b497f'], + expressionGreenHeavy: ['#0c5722', '#e7fce9'], + expressionGreenLoud: ['#32ad52', '#baedc1'], + expressionGreenSoft: ['#baedc1', '#32ad52'], + expressionGreenSubtle: ['#e7fce9', '#0c5722'], + expressionLimeHeavy: ['#345200', '#e6ffcf'], + expressionLimeLoud: ['#6da603', '#cbff93'], + expressionLimeSoft: ['#cbff93', '#6da603'], + expressionLimeSubtle: ['#e6ffcf', '#345200'], + expressionYellowHeavy: ['#524800', '#fff7c4'], + expressionYellowLoud: ['#fbdf06', '#ffed85'], + expressionYellowSoft: ['#ffed85', '#fbdf06'], + expressionYellowSubtle: ['#fff7c4', '#524800'], + expressionPumpkinHeavy: ['#762f0e', '#fef2ee'], + expressionPumpkinLoud: ['#fb966e', '#ffd3c2'], + expressionPumpkinSoft: ['#ffd3c2', '#fb966e'], + expressionPumpkinSubtle: ['#fef2ee', '#762f0e'], + expressionRedHeavy: ['#772b28', '#fff2f0'], + expressionRedLoud: ['#e7615b', '#ffd2cd'], + expressionRedSoft: ['#ffd2cd', '#e7615b'], + expressionRedSubtle: ['#fff2f0', '#772b28'], + expressionPinkHeavy: ['#6f2b53', '#fff1f7'], + expressionPinkLoud: ['#d961a6', '#ffcee6'], + expressionPinkSoft: ['#ffcee6', '#d961a6'], + expressionPinkSubtle: ['#fff1f7', '#6f2b53'], + expressionPurpleHeavy: ['#523778', '#f7f3ff'], + expressionPurpleLoud: ['#a575e8', '#e4d6ff'], + expressionPurpleSoft: ['#e4d6ff', '#a575e8'], + expressionPurpleSubtle: ['#f7f3ff', '#523778'], + overlayNeutralTranslucent: ['#00000026', '#00000099'], + materialBackgroundThick: ['#fffffff1', '#262626ea'], + materialBackgroundRegular: ['#ffffffd7', '#2f2f2fd1'], + materialBackgroundThin: ['#ffffff7e', '#3434348b'], + backgroundNeutralDisabled: ['#00000008', '#ffffff07'], + backgroundNeutralHeavyDisabled: ['#0000001a', '#ffffff20'], + backgroundNeutralSubtleDisabled: ['#0000000d', '#ffffff1b'], + strokeNeutralDisabled: ['#00000014', '#ffffff24'], + foregroundNeutralDisabled: ['#0000006d', '#ffffff61'], + strokeFocusInner: ['#ffffff', '#000000'], + strokeFocusOuter: ['#000000', '#ffffff'], + shadow: '#000000', + }, +}; diff --git a/packages/agentic/design/src/flex/defaults/defaultTokens.ts b/packages/agentic/design/src/flex/defaults/defaultTokens.ts index 1cd93ddebf..7dbc434388 100644 --- a/packages/agentic/design/src/flex/defaults/defaultTokens.ts +++ b/packages/agentic/design/src/flex/defaults/defaultTokens.ts @@ -1,350 +1,29 @@ -import { - cornerRadius120, - cornerRadius20, - cornerRadius40, - cornerRadius60, - cornerRadius80, - cornerRadiusCircular, - fontFamilyBase, - fontFamilyMonospace, - fontLineHeight100, - fontLineHeight200, - fontLineHeight300, - fontLineHeight400, - fontLineHeight500, - fontLineHeight600, - fontLineHeight800, - fontLineHeight900, - fontLineHeight1000, - fontSize100, - fontSize200, - fontSize300, - fontSize400, - fontSize500, - fontSize600, - fontSize700, - fontSize800, - fontSize900, - fontSize1000, - fontWeightBold, - fontWeightMedium, - fontWeightRegular, - fontWeightSemibold, - size20, - size40, - size60, - size80, - size100, - size120, - size160, - size200, - size240, - size280, - size320, - size360, - size400, - size480, - size560, - size640, - size800, - strokeWidth10, - strokeWidth20, - strokeWidth30, - strokeWidth40, -} from '../../tokens/global.generated'; import { defaultResolvedThemeAppearance } from '../../theming/appearance'; -import { createFlexTokenDescription, resolveExplicitFlexTokenDescription } from '../flexTokenDescription'; -import type { FlexTokenDescription, FlexTokens, PartialFlexTokens } from '../tokens.types'; - -type NonFluentFlexTokens = Omit; +import type { ColorTone } from '../../types/appearance.types'; +import { resolveFlexTokenDescription } from '../colors/interactionPolicy'; +import { createFlexTokenDescription } from '../flexTokenDescription'; +import type { FlexTokenDescription, FlexTokens } from '../tokens.types'; +import { coolFlexTokenInput, warmFlexTokenInput } from './defaultTokens.generated'; /** - * Default values for Flex tokens that cannot be populated from a FURN Theme. + * The x3 cool-tone default description. Interactive colors author only the + * hover and pressed states the interaction policy cannot reproduce. */ -export const nonFluentFlexTokens = { - color: { - surfaceNeutralTranslucent: { rest: '#ffffff80', hover: '#ffffff80', pressed: '#ffffff80' }, - backgroundNeutralSoft: { rest: '#0000001a', hover: '#0000001a', pressed: '#0000001a' }, - backgroundNeutralTranslucent: { rest: '#ffffff80', hover: '#ffffff80', pressed: '#ffffff80' }, - expressionAccentHeavy: '#242424', - expressionAccentLoud: '#707070', - expressionAccentSoft: '#0000001a', - expressionAccentSubtle: '#0000000d', - expressionGrayHeavy: '#474747', - expressionGrayLoud: '#949494', - expressionGraySoft: '#e0e0e0', - expressionGraySubtle: '#f5f5f5', - expressionNavyHeavy: '#001e89', - expressionNavyLoud: '#546fd2', - expressionNavySoft: '#ccd5f3', - expressionNavySubtle: '#f2f4fc', - expressionBlueHeavy: '#004377', - expressionBlueLoud: '#3595de', - expressionBlueSoft: '#d0e7f8', - expressionBlueSubtle: '#f3f9fd', - expressionGreenHeavy: '#0c5e0c', - expressionGreenLoud: '#54b054', - expressionGreenSoft: '#c9eac9', - expressionGreenSubtle: '#f1faf1', - expressionLimeHeavy: '#405f14', - expressionLimeLoud: '#689920', - expressionLimeSoft: '#cfe5af', - expressionLimeSubtle: '#e5f1d3', - expressionYellowHeavy: '#4c4400', - expressionYellowLoud: '#fde300', - expressionYellowSoft: '#feee66', - expressionYellowSubtle: '#fef7b2', - expressionPumpkinHeavy: '#712d09', - expressionPumpkinLoud: '#df8e64', - expressionPumpkinSoft: '#f7dfd2', - expressionPumpkinSubtle: '#fdf7f4', - expressionRedHeavy: '#751d1f', - expressionRedLoud: '#dc5e62', - expressionRedSoft: '#f8dadb', - expressionRedSubtle: '#fdf6f6', - expressionPinkHeavy: '#80215d', - expressionPinkLoud: '#e750b0', - expressionPinkSoft: '#f7c0e3', - expressionPinkSubtle: '#fef6fb', - expressionPurpleHeavy: '#532982', - expressionPurpleLoud: '#9470bd', - expressionPurpleSoft: '#e0d3ed', - expressionPurpleSubtle: '#f7f4fb', - overlayNeutralTranslucent: '#ffffff80', - materialBackgroundThick: '#ffffffe6', - materialBackgroundRegular: '#ffffffcc', - materialBackgroundThin: '#ffffff80', - }, - lineHeight: { - functionalDisplay: fontLineHeight1000, - functionalPagetitle: fontLineHeight900, - functionalTitleLarge: fontLineHeight800, - functionalTitleMedium: fontLineHeight600, - functionalTitleSmall: fontLineHeight500, - functionalSubtitle: fontLineHeight500, - functionalBodyLarge: fontLineHeight400, - functionalBodyMedium: fontLineHeight300, - functionalBodySmall: fontLineHeight200, - functionalCaption: fontLineHeight100, - contentStatement: fontLineHeight900, - contentExpressiveLarge: fontLineHeight900, - contentExpressiveMedium: fontLineHeight800, - contentExpressiveSmall: fontLineHeight600, - contentH1: fontLineHeight800, - contentH2: fontLineHeight800, - contentH3: fontLineHeight600, - contentH4: fontLineHeight500, - contentH5: fontLineHeight400, - contentSubheadline: fontLineHeight400, - contentParagraphLarge: fontLineHeight600, - contentParagraphMedium: fontLineHeight500, - contentParagraphSmall: fontLineHeight300, - contentSubtext: fontLineHeight100, - contentTable: fontLineHeight400, - contentCode: fontLineHeight400, - }, - borderRadius: { - base100: cornerRadius20, - base400: cornerRadius60, - base600: cornerRadius80, - base700: cornerRadius120, - circular: cornerRadiusCircular, - }, - spacing: { - componentBase50: size20, - componentBase100: size40, - componentBase150: size60, - componentBase200: size80, - componentBase250: size100, - componentBase300: size120, - componentBase400: size160, - componentBase500: size200, - componentBase600: size240, - componentBase700: size280, - layoutBase100: size80, - layoutBase200: size160, - layoutBase300: size240, - layoutBase400: size320, - layoutBase450: size360, - layoutBase500: size400, - layoutBase600: size480, - layoutBase700: size560, - layoutBase800: size640, - layoutBase1000: size800, - layoutBase1200: size800, - }, - strokeWidth: { - thin: strokeWidth10, - thick: strokeWidth20, - thicker: strokeWidth30, - thickest: strokeWidth40, - }, -} satisfies NonFluentFlexTokens; +export const defaultFlexTokenDescription: FlexTokenDescription = createFlexTokenDescription(coolFlexTokenInput); -/** - * Authored default Flex token values. Theme-backed values use the current - * native defaults, layered over values that have no FURN Theme source. - * Heavy, loud, and on-loud interactive roles are inverted. - */ -export const defaultFlexTokenDescription: FlexTokenDescription = createFlexTokenDescription({ - ...nonFluentFlexTokens, - color: { - ...nonFluentFlexTokens.color, - surfaceNeutralFarther: { rest: '#ebebeb', hover: '#f5f5f5', pressed: '#f0f0f0' }, - surfaceNeutralFar: { rest: '#f5f5f5', hover: '#ebebeb', pressed: '#d6d6d6' }, - surfaceNeutralNear: { rest: '#fafafa', hover: '#f0f0f0', pressed: '#dbdbdb' }, - surfaceNeutralNearer: { rest: '#ffffff', hover: '#f5f5f5', pressed: '#e0e0e0' }, - backgroundNeutralHeavy: { rest: '#616161', hover: '#616161', pressed: '#616161', type: 'inverted' }, - backgroundNeutralLoud: { rest: '#616161', hover: '#616161', pressed: '#616161', type: 'inverted' }, - backgroundNeutralSubtle: { rest: '#fafafa', hover: '#f0f0f0', pressed: '#dbdbdb' }, - backgroundNeutralTransparent: { rest: '#00000000', hover: '#00000000', pressed: '#00000000' }, - backgroundBrandHeavy: { rest: '#185abd', hover: '#1651aa', pressed: '#0e336a', type: 'inverted' }, - backgroundBrandLoud: { rest: '#185abd', hover: '#1651aa', pressed: '#0e336a', type: 'inverted' }, - backgroundBrandSoft: { rest: '#d2e0f4', hover: '#d2e0f4', pressed: '#d2e0f4' }, - backgroundBrandSubtle: { rest: '#d2e0f4', hover: '#d2e0f4', pressed: '#d2e0f4' }, - backgroundBrandTransparent: { rest: '#00000000', hover: '#00000000', pressed: '#00000000' }, - backgroundDangerLoud: { rest: '#d13438', hover: '#d13438', pressed: '#d13438', type: 'inverted' }, - backgroundDangerSoft: { rest: '#f1bbbc', hover: '#f1bbbc', pressed: '#f1bbbc' }, - backgroundDangerSubtle: { rest: '#fdf6f6', hover: '#fdf6f6', pressed: '#fdf6f6' }, - backgroundWarningLoud: { rest: '#fde300', hover: '#fde300', pressed: '#fde300', type: 'inverted' }, - backgroundWarningSoft: { rest: '#fef7b2', hover: '#fef7b2', pressed: '#fef7b2' }, - backgroundWarningSubtle: { rest: '#fffef5', hover: '#fffef5', pressed: '#fffef5' }, - backgroundSuccessLoud: { rest: '#107c10', hover: '#107c10', pressed: '#107c10', type: 'inverted' }, - backgroundSuccessSoft: { rest: '#9fd89f', hover: '#9fd89f', pressed: '#9fd89f' }, - backgroundSuccessSubtle: { rest: '#f1faf1', hover: '#f1faf1', pressed: '#f1faf1' }, - strokeNeutralHeavy: { rest: '#616161', hover: '#575757', pressed: '#4d4d4d', type: 'inverted' }, - strokeNeutralLoud: { rest: '#d1d1d1', hover: '#c7c7c7', pressed: '#b3b3b3', type: 'inverted' }, - strokeNeutralSoft: { rest: '#d1d1d1', hover: '#c7c7c7', pressed: '#b3b3b3' }, - strokeNeutralSubtle: { rest: '#e0e0e0', hover: '#e0e0e0', pressed: '#e0e0e0' }, - strokeNeutralTransparent: { rest: '#00000000', hover: '#00000000', pressed: '#00000000' }, - strokeNeutralOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, - strokeBrandLoud: { rest: '#185abd', hover: '#185abd', pressed: '#185abd', type: 'inverted' }, - strokeBrandSoft: { rest: '#185abd', hover: '#185abd', pressed: '#185abd' }, - strokeBrandSubtle: { rest: '#6794d7', hover: '#6794d7', pressed: '#6794d7' }, - strokeBrandOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, - strokeDangerLoud: { rest: '#d13438', hover: '#d13438', pressed: '#d13438', type: 'inverted' }, - strokeDangerSoft: { rest: '#f1bbbc', hover: '#f1bbbc', pressed: '#f1bbbc' }, - strokeDangerSubtle: { rest: '#f1bbbc', hover: '#f1bbbc', pressed: '#f1bbbc' }, - strokeDangerOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, - strokeWarningLoud: { rest: '#fde300', hover: '#fde300', pressed: '#fde300', type: 'inverted' }, - strokeWarningSoft: { rest: '#fef7b2', hover: '#fef7b2', pressed: '#fef7b2' }, - strokeWarningSubtle: { rest: '#fef7b2', hover: '#fef7b2', pressed: '#fef7b2' }, - strokeWarningOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, - strokeSuccessLoud: { rest: '#107c10', hover: '#107c10', pressed: '#107c10', type: 'inverted' }, - strokeSuccessSoft: { rest: '#9fd89f', hover: '#9fd89f', pressed: '#9fd89f' }, - strokeSuccessSubtle: { rest: '#9fd89f', hover: '#9fd89f', pressed: '#9fd89f' }, - strokeSuccessOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, - foregroundNeutralPrimary: { rest: '#242424', hover: '#242424', pressed: '#242424' }, - foregroundNeutralSecondary: { rest: '#424242', hover: '#242424', pressed: '#242424' }, - foregroundNeutralTertiary: { rest: '#616161', hover: '#424242', pressed: '#424242' }, - foregroundNeutralOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, - foregroundBrandPrimary: { rest: '#185abd', hover: '#185abd', pressed: '#185abd' }, - foregroundBrandOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, - foregroundDangerPrimary: { rest: '#bc2f32', hover: '#bc2f32', pressed: '#bc2f32' }, - foregroundDangerOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, - foregroundWarningPrimary: { rest: '#817400', hover: '#817400', pressed: '#817400' }, - foregroundWarningOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, - foregroundSuccessPrimary: { rest: '#0e700e', hover: '#0e700e', pressed: '#0e700e' }, - foregroundSuccessOnloud: { rest: '#ffffff', hover: '#ffffff', pressed: '#ffffff', type: 'inverted' }, - fixedWhite: '#ffffff', - fixedBlack: '#000000', - expressionAchromaticHeavy: '#000000', - expressionAchromaticSubtle: '#ffffff', - backgroundNeutralDisabled: '#f0f0f0', - backgroundNeutralHeavyDisabled: '#f0f0f0', - backgroundNeutralSubtleDisabled: '#f0f0f0', - strokeNeutralDisabled: '#e0e0e0', - foregroundNeutralDisabled: '#bdbdbd', - strokeFocusInner: '#ffffff', - strokeFocusOuter: '#000000', - shadow: '#000000', - }, - shadow: { - lowest: { - ambient: { color: '#0000001f', x: 0, y: 0, blur: 2 }, - key: { color: '#00000024', x: 0, y: 1, blur: 2 }, - }, - lower: { - ambient: { color: '#0000001f', x: 0, y: 0, blur: 2 }, - key: { color: '#00000024', x: 0, y: 2, blur: 4 }, - }, - low: { - ambient: { color: '#0000001f', x: 0, y: 0, blur: 2 }, - key: { color: '#00000024', x: 0, y: 4, blur: 8 }, - }, - high: { - ambient: { color: '#0000001f', x: 0, y: 0, blur: 2 }, - key: { color: '#00000024', x: 0, y: 8, blur: 16 }, - }, - higher: { - ambient: { color: '#00000033', x: 0, y: 0, blur: 8 }, - key: { color: '#0000003d', x: 0, y: 14, blur: 28 }, - }, - highest: { - ambient: { color: '#00000033', x: 0, y: 0, blur: 8 }, - key: { color: '#0000003d', x: 0, y: 32, blur: 64 }, - }, - }, - fontWeight: { - functionalRegular: fontWeightRegular, - functionalMedium: fontWeightMedium, - functionalSemibold: fontWeightSemibold, - functionalBold: fontWeightBold, - contentRegular: fontWeightRegular, - contentMedium: fontWeightMedium, - contentSemibold: fontWeightSemibold, - contentBold: fontWeightBold, - contentEditorialRegular: fontWeightRegular, - contentEditorialMedium: fontWeightMedium, - contentEditorialSemibold: fontWeightSemibold, - contentEditorialBold: fontWeightBold, - }, - fontFamily: { - functional: fontFamilyBase, - content: fontFamilyBase, - contentEditorial: fontFamilyBase, - contentCode: fontFamilyMonospace, - }, - fontSize: { - functionalDisplay: fontSize1000, - functionalPagetitle: fontSize900, - functionalTitleLarge: fontSize800, - functionalTitleMedium: fontSize700, - functionalTitleSmall: fontSize600, - functionalSubtitle: fontSize500, - functionalBodyLarge: fontSize400, - functionalBodyMedium: fontSize300, - functionalBodySmall: fontSize200, - functionalCaption: fontSize100, - contentStatement: fontSize1000, - contentExpressiveLarge: fontSize900, - contentExpressiveMedium: fontSize800, - contentExpressiveSmall: fontSize700, - contentH1: fontSize800, - contentH2: fontSize800, - contentH3: fontSize700, - contentH4: fontSize600, - contentH5: fontSize500, - contentSubheadline: fontSize400, - contentParagraphLarge: fontSize500, - contentParagraphMedium: fontSize400, - contentParagraphSmall: fontSize200, - contentSubtext: fontSize100, - contentTable: fontSize400, - contentCode: fontSize400, - }, - borderRadius: { - ...nonFluentFlexTokens.borderRadius, - base200: cornerRadius40, - base300: cornerRadius40, - }, -}); +let warmFlexTokenDescription: FlexTokenDescription | undefined; + +/** The x3 default description for a color tone. */ +export function getDefaultFlexTokenDescription(colorTone: ColorTone): FlexTokenDescription { + if (colorTone === 'warm') { + warmFlexTokenDescription ??= createFlexTokenDescription(warmFlexTokenInput); + return warmFlexTokenDescription; + } + return defaultFlexTokenDescription; +} /** - * Default resolved Flex tokens for the default appearance. Every interactive - * default authors explicit states, so no interaction algorithm runs. + * Default resolved Flex tokens for the default appearance. Omitted interaction + * states are computed on first read. */ -export const defaultFlexTokens: FlexTokens = resolveExplicitFlexTokenDescription( - defaultFlexTokenDescription, - defaultResolvedThemeAppearance, -); +export const defaultFlexTokens: FlexTokens = resolveFlexTokenDescription(defaultFlexTokenDescription, defaultResolvedThemeAppearance); diff --git a/packages/agentic/design/src/flex/defaults/generateDefaults.test.ts b/packages/agentic/design/src/flex/defaults/generateDefaults.test.ts new file mode 100644 index 0000000000..5f29de3a26 --- /dev/null +++ b/packages/agentic/design/src/flex/defaults/generateDefaults.test.ts @@ -0,0 +1,16 @@ +import { spawnSync } from 'node:child_process'; +import path from 'node:path'; +import * as nodeModule from 'node:module'; + +const generatorPath = path.resolve(__dirname, '../../../scripts/flex-defaults/generate-defaults.mjs'); + +// The generator loads TypeScript sources through module hooks and type stripping (Node 22.18+). +const generatorSupported = typeof nodeModule.registerHooks === 'function' && Boolean(process.features.typescript); + +describe('generated Flex defaults', () => { + (generatorSupported ? it : it.skip)('match the pinned x3 sources and mapping', () => { + const result = spawnSync(process.execPath, [generatorPath, '--check'], { encoding: 'utf8' }); + + expect({ status: result.status, stderr: result.stderr }).toEqual({ status: 0, stderr: '' }); + }); +}); diff --git a/packages/agentic/design/src/flex/defaults/x3Defaults.test.ts b/packages/agentic/design/src/flex/defaults/x3Defaults.test.ts new file mode 100644 index 0000000000..27384fa8ff --- /dev/null +++ b/packages/agentic/design/src/flex/defaults/x3Defaults.test.ts @@ -0,0 +1,273 @@ +import fs from 'node:fs'; +import path from 'node:path'; + +import { fontFamilyBase, fontFamilyMonospace } from '../../tokens/global.generated'; +import type { ColorTone, NormalizedThemeAppearance } from '../../types/appearance.types'; +import { selectColorEntry } from '../colors/flexColor'; +import { deriveInteractionColor, resolveFlexTokenDescription } from '../colors/interactionPolicy'; +import { isInteractiveColorToken } from '../colors/interactiveTokens'; +import type { FlexShadow, FlexTokenDescription, FlexTokens } from '../tokens.types'; +import { getDefaultFlexTokenDescription } from './defaultTokens'; + +type MappingEntry = { genericSource?: string }; +type MappingChecks = { + loadMappingInputs(): { mapping: unknown; supportedTypePaths: Set; unsupportedTypePaths: Set }; + createMappingProjections(mapping: unknown, supportedTypePaths: Set): { mappingEntries: Map }; +}; + +const { createMappingProjections, loadMappingInputs } = jest.requireActual( + '../../../scripts/token-mappings/check-mappings.cjs', +); +const mappingInputs = loadMappingInputs(); +const { mappingEntries } = createMappingProjections(mappingInputs.mapping, mappingInputs.supportedTypePaths); + +// These checks read the pinned split light and dark snapshots, not the adaptive +// sources the generator reads, and convert values without generator code. +const fixtureRoot = path.resolve(__dirname, '../../../scripts/token-mappings/__fixtures__/x3'); +const toneDirectories: Record = { cool: '', warm: 'warm' }; +const tones = ['cool', 'warm'] as const; +const schemes = ['light', 'dark'] as const; +type Scheme = (typeof schemes)[number]; + +// Algorithm parameters the interaction engine owns; they are not Flex destinations. +const engineParameters = [ + '--alpha-hover', + '--alpha-press', + '--interaction-inverse-hover', + '--interaction-inverse-pressed', + '--interaction-standard-hover', + '--interaction-standard-pressed', + '--lightness-hover', + '--lightness-press', +]; + +// x3 variable font weights and the static native weights that represent them. +const nativeFontWeights: Record = { '420': '400', '550': '500', '600': '600', '625': '700' }; + +type Sources = { semantic: Map; fallback: Map }; + +function readDeclarations(file: string): Map { + const declarations = new Map(); + for (const line of fs.readFileSync(file, 'utf8').split('\n')) { + const text = line.trim(); + if (!text.startsWith('--')) { + continue; + } + if (!text.endsWith(';')) { + throw new Error(`Expected a single-line declaration in ${file}: ${text}`); + } + const colon = text.indexOf(':'); + declarations.set(text.slice(0, colon), text.slice(colon + 1, -1).trim()); + } + return declarations; +} + +const sourceCache = new Map(); + +function readSources(tone: ColorTone, scheme: Scheme): Sources { + const key = `${tone}:${scheme}`; + let sources = sourceCache.get(key); + if (!sources) { + const directory = path.join(fixtureRoot, toneDirectories[tone]); + sources = { + semantic: readDeclarations(path.join(directory, `semantic-${scheme}.css`)), + fallback: readDeclarations(path.join(directory, `interaction-fallback-${scheme}.css`)), + }; + sourceCache.set(key, sources); + } + return sources; +} + +function genericSource(tokenPath: string): string { + const source = mappingEntries.get(tokenPath)?.genericSource; + if (!source) { + throw new Error(`${tokenPath} has no generic source.`); + } + return source; +} + +function read(declarations: Map, name: string): string { + const value = declarations.get(name); + if (value === undefined) { + throw new Error(`${name} is not declared.`); + } + return value; +} + +function normalizeColor(value: unknown): string { + if (typeof value !== 'string' || !/^#(?:[0-9a-f]{6}|[0-9a-f]{8})$/i.test(value)) { + return ``; + } + const hex = value.toLowerCase(); + return hex.length === 7 ? `${hex}ff` : hex; +} + +function pixels(value: string): number { + if (value.endsWith('rem')) { + return Number(value.slice(0, -3)) * 16; + } + if (value.endsWith('px')) { + return Number(value.slice(0, -2)); + } + throw new Error(`Expected px or rem: ${value}`); +} + +function functionArguments(value: string, name: string): string[] { + if (!value.startsWith(`${name}(`) || !value.endsWith(')')) { + throw new Error(`Expected ${name}(): ${value}`); + } + return value + .slice(name.length + 1, -1) + .split(',') + .map((part) => part.trim()); +} + +// CSS round(P%, Spx) against the role's font size; ties round up, as Math.round does. +function lineHeight(value: string, fontSize: number): number { + if (value.endsWith('px')) { + return pixels(value); + } + const [percent, step] = functionArguments(value, 'round'); + if (!percent.endsWith('%')) { + throw new Error(`Expected a percentage line height: ${value}`); + } + const interval = pixels(step); + return Math.round((fontSize * Number(percent.slice(0, -1))) / 100 / interval) * interval; +} + +function duration(value: string): number { + if (value.endsWith('ms')) { + return Number(value.slice(0, -2)); + } + if (value.endsWith('s')) { + return Number(value.slice(0, -1)) * 1000; + } + throw new Error(`Expected a duration: ${value}`); +} + +function fontFamily(value: string): unknown { + const generic = value.split(',').at(-1)?.trim(); + if (generic === 'monospace') { + return fontFamilyMonospace; + } + if (generic === 'sans-serif' || generic === 'serif') { + return fontFamilyBase; + } + throw new Error(`Unexpected generic family: ${value}`); +} + +// The fallback stylesheets resolve shadow colors to hex for non-OKLCH engines. +function shadow(value: string): FlexShadow { + return value.split(',').map((layer) => { + const [x, y, blur, color] = layer.trim().split(/\s+/); + return { x: pixels(x), y: pixels(y), blur: pixels(blur), color }; + }); +} + +function expectedValue(group: string, token: string, sources: Sources): unknown { + const source = read(sources.semantic, genericSource(`${group}.${token}`)); + switch (group) { + case 'fontWeight': + return nativeFontWeights[source] ?? ``; + case 'fontFamily': + return fontFamily(source); + case 'lineHeight': + return lineHeight(source, pixels(read(sources.semantic, genericSource(`fontSize.${token}`)))); + case 'motion': + return source.startsWith('cubic-bezier(') ? functionArguments(source, 'cubic-bezier').map(Number) : duration(source); + case 'shadow': + return shadow(read(sources.fallback, genericSource(`shadow.${token}`))); + default: + return pixels(source); + } +} + +function appearance(colorTone: ColorTone, colorScheme: Scheme): NormalizedThemeAppearance { + return { colorScheme, contrast: 'standard', interfaceLevel: 'base', colorTone }; +} + +function colorMismatches(tokens: FlexTokens, sources: Sources): string[] { + const mismatches: string[] = []; + for (const [token, color] of Object.entries(tokens.color)) { + const restSource = genericSource(`color.${token}.rest`); + const expectedRest = normalizeColor(read(sources.semantic, restSource)); + if (normalizeColor(color.rest) !== expectedRest) { + mismatches.push(`color.${token}.rest: ${String(color.rest)} != ${expectedRest}`); + } + for (const state of ['hover', 'pressed'] as const) { + if (!isInteractiveColorToken(token)) { + if (color[state] !== color.rest || sources.fallback.has(`${restSource}-${state}`)) { + mismatches.push(`color.${token}.${state}: a non-interactive state must equal rest`); + } + continue; + } + const expected = normalizeColor(read(sources.fallback, genericSource(`color.${token}.${state}`))); + if (normalizeColor(color[state]) !== expected) { + mismatches.push(`color.${token}.${state}: ${String(color[state])} != ${expected}`); + } + } + } + return mismatches; +} + +function explicitStates(description: FlexTokenDescription): [token: string, state: 'hover' | 'pressed'][] { + return Object.entries(description.color).flatMap(([token, color]) => + (['hover', 'pressed'] as const).filter((state) => color[state] !== undefined).map((state) => [token, state] as [string, typeof state]), + ); +} + +describe('x3 Flex defaults', () => { + describe.each(tones)('%s tone', (tone) => { + const description = getDefaultFlexTokenDescription(tone); + + it.each(schemes)('resolves every %s color to the pinned source values', (scheme) => { + const tokens = resolveFlexTokenDescription(description, appearance(tone, scheme)); + + expect(colorMismatches(tokens, readSources(tone, scheme))).toEqual([]); + }); + + it.each(schemes)('resolves every %s non-color value to the pinned source values', (scheme) => { + const tokens = resolveFlexTokenDescription(description, appearance(tone, scheme)); + const sources = readSources(tone, scheme); + + for (const [group, values] of Object.entries(tokens)) { + if (group === 'color') { + continue; + } + for (const [token, value] of Object.entries(values as Record)) { + expect([`${group}.${token}`, value]).toEqual([`${group}.${token}`, expectedValue(group, token, sources)]); + } + } + }); + + it('authors an interaction state only when the policy cannot reproduce its source', () => { + for (const [token, state] of explicitStates(description)) { + const color = description.color[token as keyof typeof description.color]; + const direction = color.type === 'inverted' ? 'inverted' : 'standard'; + const reproduced = schemes.every((scheme) => { + const resolvedAppearance = appearance(tone, scheme); + const rest = selectColorEntry(color.rest, resolvedAppearance); + const derived = deriveInteractionColor( + rest, + token as Parameters[1], + state, + direction, + resolvedAppearance, + ); + return normalizeColor(derived) === normalizeColor(selectColorEntry(color[state] as never, resolvedAppearance)); + }); + + expect([token, state, reproduced]).toEqual([token, state, false]); + } + }); + + it.each(schemes)('maps every %s source variable to a Flex destination', (scheme) => { + const declared = new Set([...mappingEntries.values()].map((entry) => entry.genericSource)); + const { semantic, fallback } = readSources(tone, scheme); + const names = [...semantic.keys(), ...fallback.keys()]; + + expect(names.filter((name) => name.startsWith('--gnrc-') && !declared.has(name))).toEqual([]); + expect([...new Set(names.filter((name) => !name.startsWith('--gnrc-')))].sort()).toEqual(engineParameters); + }); + }); +}); diff --git a/packages/agentic/design/src/flex/flexShadow.test.ts b/packages/agentic/design/src/flex/flexShadow.test.ts new file mode 100644 index 0000000000..78422bce38 --- /dev/null +++ b/packages/agentic/design/src/flex/flexShadow.test.ts @@ -0,0 +1,109 @@ +import { defaultFlexTokenDescription } from './defaults/defaultTokens'; +import { assertShadowEntries, mergeShadowEntries, resolveShadowEntries, selectShadowEntry } from './flexShadow'; +import { mergeFlexTokenDescription } from './flexTokenDescription'; +import type { FlexShadow, FlexShadowEntry, SemanticShadowEntries } from './tokens.types'; + +const contour = { x: 0, y: 0, blur: 2, color: '#0000001a' }; +const key = { x: 0, y: 2, blur: 4, color: '#00000024' }; +const lightShadow: FlexShadow = [contour, key]; +const darkShadow: FlexShadow = [ + { ...contour, color: '#00000033' }, + { ...key, color: '#00000048' }, +]; + +describe('selectShadowEntry', () => { + it('uses one shadow for every scheme', () => { + expect(selectShadowEntry(lightShadow, { colorScheme: 'light' })).toBe(lightShadow); + expect(selectShadowEntry(lightShadow, { colorScheme: 'dark' })).toBe(lightShadow); + }); + + it('selects a light/dark tuple by scheme', () => { + const entry: FlexShadowEntry = [lightShadow, darkShadow]; + + expect(selectShadowEntry(entry, { colorScheme: 'light' })).toBe(lightShadow); + expect(selectShadowEntry(entry, { colorScheme: 'dark' })).toBe(darkShadow); + }); + + it('treats an empty shadow as one shadow with no layers', () => { + expect(selectShadowEntry([], { colorScheme: 'dark' })).toEqual([]); + }); +}); + +describe('resolveShadowEntries', () => { + it('selects every entry for the scheme and freezes the result', () => { + const resolved = resolveShadowEntries(defaultFlexTokenDescription.shadow, { colorScheme: 'dark' }); + + expect(Object.isFrozen(resolved)).toBe(true); + expect(Object.keys(resolved)).toEqual(Object.keys(defaultFlexTokenDescription.shadow)); + for (const [name, entry] of Object.entries(defaultFlexTokenDescription.shadow)) { + expect(resolved[name as keyof typeof resolved]).toBe(selectShadowEntry(entry, { colorScheme: 'dark' })); + } + }); +}); + +describe('assertShadowEntries', () => { + it('accepts layered shadows, tuples, and undefined entries', () => { + expect(() => assertShadowEntries({ low: lightShadow, high: [lightShadow, darkShadow], higher: undefined })).not.toThrow(); + }); + + it.each([ + ['an array', []], + ['null', null], + ['a string', 'low'], + ])('rejects %s as the shadow group', (_label, shadows) => { + expect(() => assertShadowEntries(shadows)).toThrow('Flex shadow overrides must be an object keyed by semantic shadow name.'); + }); + + it.each([ + ['a layer without a color', [{ x: 0, y: 0, blur: 2 }]], + ['a layer with a string offset', [{ x: '0px', y: 0, blur: 2, color: '#000000' }]], + ['a single layer object', contour], + ['a three-shadow tuple', [lightShadow, darkShadow, lightShadow]], + ])('rejects %s', (_label, value) => { + expect(() => assertShadowEntries({ low: value })).toThrow( + 'shadow.low must be an array of { x, y, blur, color } shadow layers or a [light, dark] tuple of them.', + ); + }); + + it('explains how to author a legacy { ambient, key } shadow', () => { + expect(() => assertShadowEntries({ low: { ambient: contour, key } })).toThrow( + 'Author a legacy { ambient, key } shadow as [ambient, key].', + ); + }); +}); + +describe('mergeShadowEntries', () => { + const base = defaultFlexTokenDescription.shadow; + + it('replaces each entry atomically', () => { + const merged = mergeShadowEntries(base, { low: lightShadow }); + + expect(merged.low).toBe(lightShadow); + expect(merged.high).toBe(base.high); + expect(Object.isFrozen(merged)).toBe(true); + }); + + it('keeps the base for undefined and unchanged entries', () => { + expect(mergeShadowEntries(base, { low: undefined, high: base.high })).toBe(base); + }); + + it('validates overrides', () => { + expect(() => mergeShadowEntries(base, { low: { ambient: contour, key } })).toThrow('shadow.low'); + }); +}); + +describe('mergeFlexTokenDescription shadows', () => { + it('replaces a light/dark tuple with one shadow instead of merging layers', () => { + const merged = mergeFlexTokenDescription(defaultFlexTokenDescription, { shadow: { lowest: [contour] } }); + + expect(merged.shadow.lowest).toEqual([contour]); + expect(merged.shadow.lower).toBe(defaultFlexTokenDescription.shadow.lower); + expect(merged.color).toBe(defaultFlexTokenDescription.color); + }); + + it('does not remove a shadow for an undefined override', () => { + const shadow: Partial = { lowest: undefined }; + + expect(mergeFlexTokenDescription(defaultFlexTokenDescription, { shadow })).toBe(defaultFlexTokenDescription); + }); +}); diff --git a/packages/agentic/design/src/flex/flexShadow.ts b/packages/agentic/design/src/flex/flexShadow.ts new file mode 100644 index 0000000000..d57eca61cb --- /dev/null +++ b/packages/agentic/design/src/flex/flexShadow.ts @@ -0,0 +1,84 @@ +import type { ColorSchemeSelector } from './colors/flexColor'; +import type { FlexShadow, FlexShadowEntry, SemanticShadowEntries, SemanticShadows } from './tokens.types'; + +function isShadowLayer(value: unknown): boolean { + if (typeof value !== 'object' || value === null || Array.isArray(value)) { + return false; + } + const { x, y, blur, color } = value as Record; + return typeof x === 'number' && typeof y === 'number' && typeof blur === 'number' && color !== undefined && color !== null; +} + +function isFlexShadow(value: unknown): value is FlexShadow { + return Array.isArray(value) && value.every(isShadowLayer); +} + +function isShadowTuple(entry: FlexShadowEntry): entry is readonly [light: FlexShadow, dark: FlexShadow] { + return Array.isArray(entry[0]); +} + +/** + * Throw unless a value is a layered shadow or a light/dark tuple of layered + * shadows. + */ +function assertShadowEntry(value: unknown, path: string): asserts value is FlexShadowEntry { + if (isFlexShadow(value) || (Array.isArray(value) && value.length === 2 && isFlexShadow(value[0]) && isFlexShadow(value[1]))) { + return; + } + const legacy = typeof value === 'object' && value !== null && ('ambient' in value || 'key' in value); + throw new TypeError( + `${path} must be an array of { x, y, blur, color } shadow layers or a [light, dark] tuple of them.` + + (legacy ? ' Author a legacy { ambient, key } shadow as [ambient, key].' : ''), + ); +} + +/** + * Validate authored shadow entries. `undefined` entries are not overrides. + * @internal + */ +export function assertShadowEntries(shadows: unknown): asserts shadows is Partial { + if (typeof shadows !== 'object' || shadows === null || Array.isArray(shadows)) { + throw new TypeError('Flex shadow overrides must be an object keyed by semantic shadow name.'); + } + for (const [name, value] of Object.entries(shadows)) { + if (value !== undefined) { + assertShadowEntry(value, `shadow.${name}`); + } + } +} + +/** + * Replace each overridden shadow atomically. `undefined` entries are not + * overrides, so they keep the base shadow. + * @internal + */ +export function mergeShadowEntries(base: SemanticShadowEntries, shadows: unknown): SemanticShadowEntries { + assertShadowEntries(shadows); + let merged: Record | undefined; + for (const [name, value] of Object.entries(shadows)) { + if (value !== undefined && value !== (base as Record)[name]) { + merged ??= { ...base }; + merged[name] = value; + } + } + return merged ? (Object.freeze(merged) as SemanticShadowEntries) : base; +} + +/** + * Select the shadow an authored entry uses for an appearance's color scheme. + */ +export function selectShadowEntry(entry: FlexShadowEntry, appearance: ColorSchemeSelector): FlexShadow { + return isShadowTuple(entry) ? entry[appearance.colorScheme === 'dark' ? 1 : 0] : entry; +} + +/** + * Select every authored shadow for an appearance. + * @internal + */ +export function resolveShadowEntries(shadows: SemanticShadowEntries, appearance: ColorSchemeSelector): SemanticShadows { + const resolved: Record = {}; + for (const name of Object.keys(shadows)) { + resolved[name] = selectShadowEntry((shadows as Record)[name], appearance); + } + return Object.freeze(resolved) as SemanticShadows; +} diff --git a/packages/agentic/design/src/flex/flexThemeReference.test.ts b/packages/agentic/design/src/flex/flexThemeReference.test.ts index ba591f6c78..43f7c02637 100644 --- a/packages/agentic/design/src/flex/flexThemeReference.test.ts +++ b/packages/agentic/design/src/flex/flexThemeReference.test.ts @@ -3,8 +3,8 @@ import type { ColorValue } from 'react-native'; import { defaultResolvedThemeAppearance } from '../theming/appearance'; import { flexColor, selectColorEntry } from './colors/flexColor'; -import { deriveInteractionColor } from './colors/interactionPolicy'; -import { defaultFlexTokenDescription, defaultFlexTokens } from './defaults/defaultTokens'; +import { deriveInteractionColor, resolveFlexTokenDescription } from './colors/interactionPolicy'; +import { defaultFlexTokenDescription, defaultFlexTokens, getDefaultFlexTokenDescription } from './defaults/defaultTokens'; import { FlexThemeReference } from './flexThemeReference'; import type { FlexTokenDescription, PartialFlexTokens } from './tokens.types'; @@ -114,15 +114,30 @@ describe('FlexThemeReference color tone', () => { expect(tones).toEqual(['base:cool', 'recipe:cool', 'base:warm', 'recipe:warm']); }); - it('keeps the complete default interaction values for every tone', () => { + it('resolves the default description for each tone and scheme', () => { const reference = new FlexThemeReference(); for (const colorTone of ['cool', 'warm'] as const) { for (const colorScheme of ['light', 'dark'] as const) { - const tokens = reference.resolveFlexTokens({ ...lightAppearance, colorScheme, colorTone }); - expect(tokens.color).toEqual(defaultFlexTokens.color); + const appearance = { ...lightAppearance, colorScheme, colorTone }; + const expected = resolveFlexTokenDescription(getDefaultFlexTokenDescription(colorTone), appearance); + expect(reference.resolveFlexTokens(appearance).color).toEqual(expected.color); } } + expect(reference.resolveFlexTokens(lightAppearance).color).toEqual(defaultFlexTokens.color); + expect(reference.resolveFlexTokens({ ...lightAppearance, colorTone: 'warm' }).color.surfaceNeutralFarther.rest).toBe('#f0eae5'); + expect(reference.resolveFlexTokens(darkAppearance).color.surfaceNeutralFarther.rest).toBe('#1b1b1b'); + }); + + it('shares the warm default description when nothing is authored', () => { + const descriptions: FlexTokenDescription[] = []; + const reference = new FlexThemeReference({}, (description) => { + descriptions.push(description); + return {}; + }); + reference.resolveFlexTokens({ ...lightAppearance, colorTone: 'warm' }); + + expect(descriptions[0]).toBe(getDefaultFlexTokenDescription('warm')); }); }); diff --git a/packages/agentic/design/src/flex/flexThemeReference.ts b/packages/agentic/design/src/flex/flexThemeReference.ts index 060bc96297..c4191f5f1a 100644 --- a/packages/agentic/design/src/flex/flexThemeReference.ts +++ b/packages/agentic/design/src/flex/flexThemeReference.ts @@ -1,6 +1,6 @@ import { immutableMerge } from '@fluentui-react-native/framework-base'; -import { defaultFlexTokenDescription } from './defaults/defaultTokens'; +import { getDefaultFlexTokenDescription } from './defaults/defaultTokens'; import { mergeFlexTokenDescription } from './flexTokenDescription'; import type { FlexTokenDescription, FlexTokens, PartialFlexTokens } from './tokens.types'; import { resolveFlexTokenDescription } from './colors/interactionPolicy'; @@ -150,7 +150,7 @@ export class FlexThemeReference implements FlexThemeSource { return this.base.resolveDescription(appearance, key); } const base = typeof this.base === 'function' ? this.base(appearance) : this.base; - return mergeFlexTokenDescription(defaultFlexTokenDescription, base); + return mergeFlexTokenDescription(getDefaultFlexTokenDescription(appearance.colorTone), base); } private syncParentRevision(): void { diff --git a/packages/agentic/design/src/flex/flexTokenDescription.ts b/packages/agentic/design/src/flex/flexTokenDescription.ts index 50e6448c33..28a63deab4 100644 --- a/packages/agentic/design/src/flex/flexTokenDescription.ts +++ b/packages/agentic/design/src/flex/flexTokenDescription.ts @@ -12,6 +12,7 @@ import type { } from './tokens.types'; import { normalizeFlexColor, resolveExplicitFlexColor } from './colors/flexColor'; import type { ColorSchemeSelector } from './colors/flexColor'; +import { assertShadowEntries, mergeShadowEntries, resolveShadowEntries } from './flexShadow'; /** Resolve one normalized color for an appearance. */ export type FlexColorResolver = ( @@ -46,10 +47,10 @@ function mergeColors(base: SemanticColorDescriptions, colors: unknown): Semantic } /** - * Merge authored overrides into a description. Each color replaces the - * previous description atomically, so omitted states never inherit stale - * explicit values. `undefined` colors are not overrides. Non-color groups keep - * deep-merge semantics. + * Merge authored overrides into a description. Each color and shadow replaces + * the previous value atomically, so omitted states never inherit stale + * explicit values. `undefined` colors and shadows are not overrides. Other + * non-color groups keep deep-merge semantics. * @internal */ export function mergeFlexTokenDescription(base: FlexTokenDescription, overrides: PartialFlexTokens | undefined): FlexTokenDescription { @@ -60,16 +61,17 @@ export function mergeFlexTokenDescription(base: FlexTokenDescription, overrides: throw new TypeError('Flex token overrides must be an object.'); } - const { color, ...groups } = overrides; + const { color, shadow, ...groups } = overrides; const mergedColors = color === undefined ? base.color : mergeColors(base.color, color); + const mergedShadows = shadow === undefined ? base.shadow : mergeShadowEntries(base.shadow, shadow); const hasGroups = Object.keys(groups).length > 0; - if (mergedColors === base.color && !hasGroups) { + if (mergedColors === base.color && mergedShadows === base.shadow && !hasGroups) { return base; } - const { color: _baseColor, ...baseGroups } = base; + const { color: _baseColor, shadow: _baseShadow, ...baseGroups } = base; const mergedGroups = hasGroups ? immutableMerge(baseGroups as object, groups as object) : baseGroups; - return Object.freeze({ color: mergedColors, ...mergedGroups }) as FlexTokenDescription; + return Object.freeze({ color: mergedColors, shadow: mergedShadows, ...mergedGroups }) as FlexTokenDescription; } /** @@ -78,12 +80,14 @@ export function mergeFlexTokenDescription(base: FlexTokenDescription, overrides: */ export function createFlexTokenDescription(tokens: CompleteFlexTokenInput): FlexTokenDescription { const { color, ...groups } = tokens; + assertShadowEntries(groups.shadow); return Object.freeze({ color: mergeColors(emptyColors, color), ...groups }) as FlexTokenDescription; } /** - * Resolve every color in a description with a color policy. Non-color groups - * are shared with the description. + * Resolve every color in a description with a color policy and select each + * shadow for the scheme. Other non-color groups are shared with the + * description. * @internal */ export function resolveFlexTokenDescriptionWith( @@ -95,8 +99,12 @@ export function resolveFlexTokenDescriptionWith)[name], appearance); } - const { color: _descriptionColor, ...groups } = description; - return Object.freeze({ color: Object.freeze(color) as SemanticColors, ...groups }) as FlexTokens; + const { color: _descriptionColor, shadow, ...groups } = description; + return Object.freeze({ + color: Object.freeze(color) as SemanticColors, + shadow: resolveShadowEntries(shadow, appearance), + ...groups, + }) as FlexTokens; } /** diff --git a/packages/agentic/design/src/flex/tokens.test.ts b/packages/agentic/design/src/flex/tokens.test.ts index 9477e8c82e..5e9a73f17b 100644 --- a/packages/agentic/design/src/flex/tokens.test.ts +++ b/packages/agentic/design/src/flex/tokens.test.ts @@ -1,39 +1,34 @@ import { INTERACTIVE_COLOR_TOKENS, isInverseInteractionToken } from './colors/interactiveTokens'; -import { defaultFlexTokenDescription, defaultFlexTokens, nonFluentFlexTokens } from './defaults/defaultTokens'; -import type { FlexTokens } from './tokens.types'; +import { defaultFlexTokenDescription, defaultFlexTokens, getDefaultFlexTokenDescription } from './defaults/defaultTokens'; +import type { FlexTokenDescription, FlexTokens } from './tokens.types'; const flexTokens: FlexTokens = defaultFlexTokens; -const flexFromTheme = jest.requireActual>('../tokens/mappings/flex-from-theme.json'); -function isColorOptions(value: unknown): value is Record { - return typeof value === 'object' && value !== null && !Array.isArray(value) && 'rest' in value; -} - -// Authored color paths: rest always, and hover or pressed only when explicit. -function getTokenPaths(tokens: object, colors: object): string[] { - const colorPaths = Object.entries(colors).flatMap(([name, value]) => { - const states = isColorOptions(value) ? ['rest', 'hover', 'pressed'].filter((state) => value[state] !== undefined) : ['rest']; - return states.map((state) => `color.${name}.${state}`); - }); - const groupPaths = Object.entries(tokens) - .filter(([group]) => group !== 'color') - .flatMap(([group, values]) => Object.keys(values).map((name) => `${group}.${name}`)); - - return [...colorPaths, ...groupPaths].sort(); +function explicitStates(description: FlexTokenDescription): string[] { + return Object.entries(description.color) + .flatMap(([name, color]) => + (['hover', 'pressed'] as const).filter((state) => color[state] !== undefined).map((state) => `${name}.${state}`), + ) + .sort(); } describe('FlexTokens', () => { it('groups tokens and removes category prefixes from their names', () => { - expect(flexTokens.color.surfaceNeutralFarther).toEqual({ rest: '#ebebeb', hover: '#f5f5f5', pressed: '#f0f0f0' }); - expect(flexTokens.shadow.lowest.key.blur).toBe(2); + expect(flexTokens.color.surfaceNeutralFarther).toEqual({ rest: '#ebebeb', hover: '#e1e1e1', pressed: '#d7d7d7' }); + expect(flexTokens.shadow.lowest).toEqual([ + { x: 0, y: 0, blur: 2, color: '#0000001a' }, + { x: 0, y: 1, blur: 2, color: '#0000000d' }, + ]); expect(flexTokens.fontWeight.functionalRegular).toBe('400'); expect(flexTokens.fontFamily.functional).toBeTruthy(); - expect(flexTokens.fontSize.functionalBodyMedium).toBeGreaterThan(0); - expect(flexTokens.lineHeight.functionalBodyMedium).toBeGreaterThan(0); - expect(flexTokens.borderRadius.base100).toBeGreaterThan(0); - expect(flexTokens.spacing.componentBase100).toBeGreaterThan(0); - expect(flexTokens.strokeWidth.thin).toBeGreaterThan(0); - expect(flexTokens.color.backgroundBrandHeavy.rest).toBe('#185abd'); + expect(flexTokens.fontSize.functionalBodyMedium).toBe(14); + expect(flexTokens.lineHeight.functionalBodyMedium).toBe(20); + expect(flexTokens.borderRadius.base100).toBe(4); + expect(flexTokens.spacing.componentBase800).toBe(32); + expect(flexTokens.strokeWidth.thin).toBe(1); + expect(flexTokens.motion.durationBase200).toBe(200); + expect(flexTokens.motion.easingFunctionalEnter).toEqual([0, 0, 0, 1]); + expect(flexTokens.color.backgroundBrandHeavy.rest).toBe('#242424'); }); it('does not expose the previous flat token names or state maps', () => { @@ -52,38 +47,35 @@ describe('FlexTokens', () => { expect(Object.isFrozen(defaultFlexTokens.color)).toBe(true); }); - it('authors inverse interaction metadata and explicit states on every interactive default', () => { - const colors = defaultFlexTokenDescription.color; - const inverted = Object.keys(colors).filter((name) => colors[name as keyof typeof colors].type === 'inverted'); + it('authors inverse interaction metadata on every inverse interactive default', () => { + for (const tone of ['cool', 'warm'] as const) { + const colors = getDefaultFlexTokenDescription(tone).color; + const inverted = Object.keys(colors).filter((name) => colors[name as keyof typeof colors].type === 'inverted'); - expect(inverted).toEqual(INTERACTIVE_COLOR_TOKENS.filter(isInverseInteractionToken)); - for (const token of INTERACTIVE_COLOR_TOKENS) { - expect([token, colors[token].hover !== undefined, colors[token].pressed !== undefined]).toEqual([token, true, true]); + expect([tone, inverted.sort()]).toEqual([tone, INTERACTIVE_COLOR_TOKENS.filter(isInverseInteractionToken).sort()]); } }); - it('builds defaults from values without FURN Theme sources', () => { - const themeBackedPaths = new Set(Object.keys(flexFromTheme)); - const expectedNonFluentPaths = getTokenPaths(defaultFlexTokens, defaultFlexTokenDescription.color).filter((path) => { - if (themeBackedPaths.has(path)) { - return false; - } + it('authors only the interaction states the policy cannot reproduce', () => { + expect(explicitStates(defaultFlexTokenDescription)).toEqual([ + 'backgroundNeutralTranslucent.hover', + 'backgroundNeutralTranslucent.pressed', + 'strokeBrandSoft.hover', + 'strokeBrandSoft.pressed', + 'strokeBrandSubtle.pressed', + 'strokeNeutralSoft.hover', + 'strokeNeutralSoft.pressed', + 'strokeNeutralSubtle.pressed', + ]); + expect(explicitStates(getDefaultFlexTokenDescription('warm'))).toEqual([]); + }); - const interactiveColor = /^color\.([^.]+)\.(?:hover|pressed)$/.exec(path); - return !interactiveColor || !themeBackedPaths.has(`color.${interactiveColor[1]}.rest`); - }); + it('selects the default description by color tone', () => { + const warm = getDefaultFlexTokenDescription('warm'); - expect(getTokenPaths(nonFluentFlexTokens, nonFluentFlexTokens.color)).toEqual(expectedNonFluentPaths); - expect(Object.keys(nonFluentFlexTokens)).toEqual(['color', 'lineHeight', 'borderRadius', 'spacing', 'strokeWidth']); - expect(nonFluentFlexTokens.color.backgroundNeutralSoft).toEqual({ rest: '#0000001a', hover: '#0000001a', pressed: '#0000001a' }); - expect(nonFluentFlexTokens.borderRadius.base100).toBe(2); - expect('backgroundBrandHeavy' in nonFluentFlexTokens.color).toBe(false); - expect('backgroundBrandSoft' in nonFluentFlexTokens.color).toBe(false); - expect('surfaceNeutralFarther' in nonFluentFlexTokens.color).toBe(false); - expect('base200' in nonFluentFlexTokens.borderRadius).toBe(false); - expect(defaultFlexTokens.lineHeight).toBe(nonFluentFlexTokens.lineHeight); - expect(defaultFlexTokens.color.backgroundNeutralSoft.rest).toBe(nonFluentFlexTokens.color.backgroundNeutralSoft.rest); - expect(defaultFlexTokens.color.backgroundBrandHeavy.rest).toBe('#185abd'); - expect(defaultFlexTokens.color.backgroundBrandSoft.hover).toBe('#d2e0f4'); + expect(getDefaultFlexTokenDescription('cool')).toBe(defaultFlexTokenDescription); + expect(getDefaultFlexTokenDescription('warm')).toBe(warm); + expect(warm.color.surfaceNeutralFarther.rest).toEqual(['#f0eae5', '#1e1916']); + expect(warm.shadow).toBe(defaultFlexTokenDescription.shadow); }); }); diff --git a/packages/agentic/design/src/flex/tokens.types.ts b/packages/agentic/design/src/flex/tokens.types.ts index ee57c3339f..f7c76a1a53 100644 --- a/packages/agentic/design/src/flex/tokens.types.ts +++ b/packages/agentic/design/src/flex/tokens.types.ts @@ -1,5 +1,4 @@ import type { ColorValue, TextStyle, ViewStyle, DimensionValue } from 'react-native'; -import type { ShadowToken } from '../fluent/types/Shadow.types'; type FontWeight = TextStyle['fontWeight']; type FontSize = TextStyle['fontSize']; @@ -255,18 +254,38 @@ export type PartialSemanticColors = { [Name in SemanticColorName]?: FlexColorInp /** Normalized authored semantic colors. */ export type SemanticColorDescriptions = { readonly [Name in SemanticColorName]: FlexColorDescription }; +/** One shadow layer. Offsets and blur are density-independent pixels. */ +export type FlexShadowLayer = { + readonly x: number; + readonly y: number; + readonly blur: number; + readonly color: ColorValue; +}; + /** - * The semantic shadow token set + * A layered shadow, ordered like CSS `box-shadow`: the first layer is the + * contour and the last is the key shadow. + */ +export type FlexShadow = readonly FlexShadowLayer[]; + +/** One authored shadow for every scheme, or a light/dark tuple of shadows. */ +export type FlexShadowEntry = FlexShadow | readonly [light: FlexShadow, dark: FlexShadow]; + +/** + * The semantic shadow token set, resolved for one appearance. */ export type SemanticShadows = { - lowest: ShadowToken; - lower: ShadowToken; - low: ShadowToken; - high: ShadowToken; - higher: ShadowToken; - highest: ShadowToken; + lowest: FlexShadow; + lower: FlexShadow; + low: FlexShadow; + high: FlexShadow; + higher: FlexShadow; + highest: FlexShadow; }; +/** Authored semantic shadows. Each entry may select a shadow per scheme. */ +export type SemanticShadowEntries = { [Name in keyof SemanticShadows]: FlexShadowEntry }; + /** * Semantic font weight tokens. * @@ -373,6 +392,7 @@ export type SemanticSpacing = { componentBase500: DimensionValue; componentBase600: DimensionValue; componentBase700: DimensionValue; + componentBase800: DimensionValue; layoutBase100: DimensionValue; layoutBase200: DimensionValue; layoutBase300: DimensionValue; @@ -393,6 +413,28 @@ export type SemanticStrokeWidths = { thickest: StrokeWidth; }; +/** A cubic Bézier easing curve as `[x1, y1, x2, y2]`, the arguments of `Easing.bezier`. */ +export type FlexEasing = readonly [x1: number, y1: number, x2: number, y2: number]; + +/** + * Semantic motion tokens. Durations are milliseconds. + */ +export type SemanticMotion = { + durationBase50: number; + durationBase100: number; + durationBase200: number; + durationBase300: number; + durationBase500: number; + durationBase1000: number; + easingFunctionalEnter: FlexEasing; + easingFunctionalExit: FlexEasing; + easingFunctionalTransition: FlexEasing; + easingFunctionalLinear: FlexEasing; + easingExpressiveEnter: FlexEasing; + easingExpressiveExit: FlexEasing; + easingExpressiveTransition: FlexEasing; +}; + /** * The complete, grouped Flex token set. Category prefixes are represented by * sub-objects and removed from the token names inside each category. @@ -407,29 +449,36 @@ export type FlexTokens = { borderRadius: SemanticBorderRadii; spacing: SemanticSpacing; strokeWidth: SemanticStrokeWidths; + motion: SemanticMotion; }; export type SemanticTokens = FlexTokens; type NonColorFlexTokenGroup = Exclude; +/** Authored non-color groups. Shadows may select a value per scheme. */ +type AuthoredFlexTokenGroups = Omit & { shadow: SemanticShadowEntries }; + /** - * Authored Flex token overrides. Each color is an atomic replacement; non-color - * groups deep merge. + * Authored Flex token overrides. Each color and shadow is an atomic + * replacement; other non-color groups deep merge. */ export type PartialFlexTokens = { color?: PartialSemanticColors } & { - [Group in NonColorFlexTokenGroup]?: Partial; + [Group in NonColorFlexTokenGroup]?: Partial; }; /** A complete authored Flex token set. */ -export type CompleteFlexTokenInput = { color: { [Name in SemanticColorName]: FlexColorInput } } & Pick; +export type CompleteFlexTokenInput = { color: { [Name in SemanticColorName]: FlexColorInput } } & Pick< + AuthoredFlexTokenGroups, + NonColorFlexTokenGroup +>; /** * A complete, normalized authored token set before appearance resolution. * Recipes receive this form. */ export type FlexTokenDescription = { readonly color: SemanticColorDescriptions } & { - readonly [Group in NonColorFlexTokenGroup]: FlexTokens[Group]; + readonly [Group in NonColorFlexTokenGroup]: AuthoredFlexTokenGroups[Group]; }; /** diff --git a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts index f39b792434..0aa35d3ccc 100644 --- a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts +++ b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts @@ -4,6 +4,7 @@ import type { FlexTokens, SemanticColorTokenValues } from '../../flex/tokens.typ import { restColorValues } from '../../test/fixtures/interactionColors'; import type { PartialTheme } from '../types/Theme.types'; +import { getDefaultLegacyTheme } from './defaultLegacyTheme'; import { themeFromFlexTokens } from './themeFromFlexTokens'; import type { FlatFlexTokens } from './themeFromFlexTokens'; @@ -136,6 +137,34 @@ describe('themeFromFlexTokens', () => { expect(theme.colors.brandBackgroundPressed).toBe('#0f6cbd'); }); + it('projects layered shadows lossily to legacy { ambient, key } shadows', () => { + const contour = { x: 0, y: 0, blur: 2, color: '#0000001a' }; + const middle = { x: 0, y: 1, blur: 2, color: '#0000000d' }; + const keyLayer = { x: 0, y: 4, blur: 8, color: '#00000014' }; + const tokens: FlexTokens = { + ...createTokens(), + shadow: { ...defaultFlexTokens.shadow, lowest: [contour, middle, keyLayer], lower: [keyLayer], low: [] }, + }; + + const theme = themeFromFlexTokens(tokens, light); + + expect(theme.shadows.shadow2).toEqual({ ambient: contour, key: keyLayer }); + expect(theme.shadows.shadow4).toEqual({ ambient: keyLayer, key: keyLayer }); + expect(theme.shadows.shadow8).toEqual(getDefaultLegacyTheme(light).shadows.shadow8); + expect(theme.shadows.shadow16).toEqual({ ambient: defaultFlexTokens.shadow.high[0], key: defaultFlexTokens.shadow.high.at(-1) }); + }); + + it('passes a legacy { ambient, key } shadow through the deprecated flat representation', () => { + const legacy = { ambient: { x: 0, y: 0, blur: 2, color: 'black' }, key: { x: 0, y: 2, blur: 4, color: 'red' } }; + const flat = { + ...defaultFlexTokens, + color: restColorValues(defaultFlexTokens.color), + shadow: { ...defaultFlexTokens.shadow, lowest: legacy }, + }; + + expect(themeFromFlexTokens(flat as unknown as FlatFlexTokens, light).shadows.shadow2).toEqual(legacy); + }); + it('projects the same legacy theme from resolved and equivalent flat tokens', () => { const resolved = themeFromFlexTokens(defaultFlexTokens, light); const values = restColorValues(defaultFlexTokens.color); diff --git a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts index 55968e2507..64cb42b861 100644 --- a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts +++ b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts @@ -8,7 +8,7 @@ import type { PartialTheme, Theme } from '../types/Theme.types'; import { getDefaultLegacyTheme } from './defaultLegacyTheme'; -type ReverseTransform = 'numberToPx'; +type ReverseTransform = 'numberToPx' | 'shadowLayersToToken'; type ReverseProjectionEntry = { source: string; @@ -73,6 +73,17 @@ function setValueAtPath(destination: Record, path: string, valu target[segments[segments.length - 1]] = value; } +function shadowLayersToToken(value: unknown): unknown { + if (!Array.isArray(value)) { + // Pass through a legacy { ambient, key } shadow. + return value; + } + if (value.length === 0) { + return undefined; + } + return { ambient: value[0], key: value[value.length - 1] }; +} + function applyTransform(value: unknown, transform?: ReverseTransform): unknown { if (!transform) { return value; @@ -80,6 +91,9 @@ function applyTransform(value: unknown, transform?: ReverseTransform): unknown { if (transform === 'numberToPx') { return typeof value === 'number' ? `${value}px` : value; } + if (transform === 'shadowLayersToToken') { + return shadowLayersToToken(value); + } return value; } @@ -91,7 +105,10 @@ function projectThemeValues(tokens: FlexTokens | FlatFlexTokens): PartialTheme { value = getValueAtPath(tokens, descriptor.fallback); } if (value !== undefined) { - setValueAtPath(projected, themePath, applyTransform(value, descriptor.transform)); + value = applyTransform(value, descriptor.transform); + } + if (value !== undefined) { + setValueAtPath(projected, themePath, value); } } return projected as PartialTheme; @@ -103,7 +120,10 @@ function projectThemeValues(tokens: FlexTokens | FlatFlexTokens): PartialTheme { * The compatibility base fills legacy-only values, the optional fallback adds * author or host metadata, mapped Flex values remain authoritative, and the * final host appearance reflects the resolved structured appearance. Reading - * a derived interaction state computes it. + * a derived interaction state computes it. Layered Flex shadows project + * lossily to legacy { ambient, key } shadows: the first layer is ambient, the + * last is key, and middle layers are dropped. An empty shadow keeps the + * legacy base shadow. */ export function themeFromFlexTokens( tokens: FlexTokens | FlatFlexTokens, diff --git a/packages/agentic/design/src/index.ts b/packages/agentic/design/src/index.ts index bb12fe9119..0c8f404e94 100644 --- a/packages/agentic/design/src/index.ts +++ b/packages/agentic/design/src/index.ts @@ -5,6 +5,10 @@ export type { ColorTuple, FlexColorDescription, FlexColorInput, + FlexEasing, + FlexShadow, + FlexShadowEntry, + FlexShadowLayer, FlexTokenDescription, FlexTokens, InteractiveColor, @@ -20,6 +24,8 @@ export type { SemanticFontSizes, SemanticFontWeights, SemanticLineHeights, + SemanticMotion, + SemanticShadowEntries, SemanticShadows, SemanticSpacing, SemanticStrokeWidths, @@ -29,6 +35,7 @@ export type { export { INTERACTIVE_COLOR_TOKENS, isInteractiveColorToken, isInverseInteractionToken } from './flex/colors/interactiveTokens'; export { flexColor, selectColorEntry } from './flex/colors/flexColor'; export type { ColorSchemeSelector } from './flex/colors/flexColor'; +export { selectShadowEntry } from './flex/flexShadow'; export type { InteractiveColorToken } from './flex/colors/interactiveTokens'; export { flexTokensFromTheme } from './flex/adapters/flexTokensFromTheme'; export { diff --git a/packages/agentic/design/src/test/color-validation/pairings.ts b/packages/agentic/design/src/test/color-validation/pairings.ts index 053d26f32d..23b7b53833 100644 --- a/packages/agentic/design/src/test/color-validation/pairings.ts +++ b/packages/agentic/design/src/test/color-validation/pairings.ts @@ -16,7 +16,7 @@ function token(tokenName: ContrastColorToken): ContrastTokenReference { * Test-only canonical x3 contrast pairings adapted to FURN token names, plus the * issue-required FURN visible-stroke pairing. * - * Source: x3-design/fluent-design@d334acf5cbad813f2b7cd554da942b09a7ff8f10. + * Source: x3-design/fluent-design@206e890b645fb450ad7c5df2ff981765349a2b58. */ export const PAIRINGS = [ { diff --git a/packages/agentic/design/src/test/color-validation/validation.test.ts b/packages/agentic/design/src/test/color-validation/validation.test.ts index b926a3e334..666bc4f92a 100644 --- a/packages/agentic/design/src/test/color-validation/validation.test.ts +++ b/packages/agentic/design/src/test/color-validation/validation.test.ts @@ -1,32 +1,26 @@ import { PlatformColor } from 'react-native'; import type { ColorMode, InteractionColorState } from '../../color-lib/types'; -import { INTERACTIVE_COLOR_TOKENS } from '../../flex/colors/interactiveTokens'; -import { defaultFlexTokens } from '../../flex/defaults/defaultTokens'; +import { resolveFlexTokenDescription } from '../../flex/colors/interactionPolicy'; +import { defaultFlexTokens, getDefaultFlexTokenDescription } from '../../flex/defaults/defaultTokens'; import type { SemanticColorTokenValues } from '../../flex/tokens.types'; import type { ColorTone } from '../../types/appearance.types'; import { getContrastFailures, getUnresolvableContrastPairs, MODE_SURFACE, PAIRINGS, validateContrastPairs, WCAG } from '../index'; -import { getInteractionColorOverrides, restColorValues } from '../fixtures/interactionColors'; -import { x3BebopWarmInteractionConformance, x3InteractionConformance } from '../fixtures/x3InteractionConformance'; +import { restColorValues, stateColorValues } from '../fixtures/interactionColors'; -function conformanceColors( +// The shipping defaults for one appearance; x3Defaults.test.ts proves they match the pinned design source. +function defaultColors( mode: ColorMode, - conformance: typeof x3InteractionConformance | typeof x3BebopWarmInteractionConformance = x3InteractionConformance, + colorTone: ColorTone = 'cool', + state: 'rest' | InteractionColorState = 'rest', ): SemanticColorTokenValues { - const restIndex = mode === 'light' ? 0 : 3; - const colors = restColorValues(defaultFlexTokens.color); - for (const token of INTERACTIVE_COLOR_TOKENS) { - colors[token] = conformance[token][restIndex]; - } - return colors; -} - -function interactionConformanceColors(mode: ColorMode, state: InteractionColorState, colorTone: ColorTone): SemanticColorTokenValues { - const colors = conformanceColors(mode, colorTone === 'warm' ? x3BebopWarmInteractionConformance : x3InteractionConformance); - return { - ...colors, - ...getInteractionColorOverrides(colors, mode, state, colorTone).overrides, - }; + const tokens = resolveFlexTokenDescription(getDefaultFlexTokenDescription(colorTone), { + colorScheme: mode, + contrast: 'standard', + interfaceLevel: 'base', + colorTone, + }); + return stateColorValues(tokens.color, state); } const expectedPairs = [ @@ -85,17 +79,18 @@ describe('color validation constants', () => { }); describe.each(['light', 'dark'] as const)('%s contrast validation', (mode) => { - it('passes every canonical rest pairing', () => { - const results = validateContrastPairs(conformanceColors(mode), mode); + it.each(['cool', 'warm'] as const)('passes every canonical %s rest pairing', (colorTone) => { + const results = validateContrastPairs(defaultColors(mode, colorTone), mode); expect(results.map((result) => `${result.foreground.token}/${result.background.token}`)).toEqual(expectedPairs); expect(getContrastFailures(results)).toEqual([]); expect(getUnresolvableContrastPairs(results)).toEqual([]); }); + // Audit outcomes for the shipping defaults, kept visible rather than corrected away from the design source. it.each(['cool', 'warm'] as const)('audits %s interaction values', (colorTone) => { for (const state of ['hover', 'pressed'] as const) { - const failures = getContrastFailures(validateContrastPairs(interactionConformanceColors(mode, state, colorTone), mode)).map( + const failures = getContrastFailures(validateContrastPairs(defaultColors(mode, colorTone, state), mode)).map( (result) => `${result.foreground.token}/${result.background.token}`, ); const expectedFailures = @@ -125,7 +120,7 @@ describe('resolved color validation', () => { describe('unresolvable color validation', () => { it('identifies native foreground colors', () => { - const colors = conformanceColors('light'); + const colors = defaultColors('light'); colors.foregroundNeutralPrimary = PlatformColor('labelColor'); const results = getUnresolvableContrastPairs(validateContrastPairs(colors, 'light')).filter( (result) => result.foreground.token === 'foregroundNeutralPrimary', @@ -142,7 +137,7 @@ describe('unresolvable color validation', () => { }); it('identifies native background colors', () => { - const colors = conformanceColors('dark'); + const colors = defaultColors('dark'); colors.backgroundSuccessSoft = PlatformColor('windowBackgroundColor'); const result = getUnresolvableContrastPairs(validateContrastPairs(colors, 'dark')).find( (pair) => pair.background.token === 'backgroundSuccessSoft', diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap index 945f1afad9..9ef644b2e7 100644 --- a/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap @@ -3,10 +3,10 @@ exports[`Flex default baseline keeps the dark legacy projection of the default Flex tokens 1`] = ` { "colorCount": 274, - "colors": "d455d2657fac4c32", - "components": "72a2537e550ec269", + "colors": "bc2282479a31f977", + "components": "75484377ab62c281", "host": "e8e4ef993a27738e", - "shadows": "6cb9f79865a74b20", + "shadows": "6cc8dc2e49311041", "spacing": "ae5c5f37376210ff", "typography": "758be399ff81061a", } @@ -15,10 +15,10 @@ exports[`Flex default baseline keeps the dark legacy projection of the default F exports[`Flex default baseline keeps the darkElevated legacy projection of the default Flex tokens 1`] = ` { "colorCount": 274, - "colors": "d455d2657fac4c32", - "components": "72a2537e550ec269", + "colors": "bc2282479a31f977", + "components": "75484377ab62c281", "host": "f94ca80c0bbf7966", - "shadows": "6cb9f79865a74b20", + "shadows": "6cc8dc2e49311041", "spacing": "ae5c5f37376210ff", "typography": "758be399ff81061a", } @@ -27,10 +27,10 @@ exports[`Flex default baseline keeps the darkElevated legacy projection of the d exports[`Flex default baseline keeps the highContrast legacy projection of the default Flex tokens 1`] = ` { "colorCount": 274, - "colors": "c43a121decc8c5b8", - "components": "72a2537e550ec269", + "colors": "a560e8f2d3b4fa4a", + "components": "75484377ab62c281", "host": "9db06d0a5ce1e422", - "shadows": "6cb9f79865a74b20", + "shadows": "6cc8dc2e49311041", "spacing": "ae5c5f37376210ff", "typography": "758be399ff81061a", } @@ -39,10 +39,10 @@ exports[`Flex default baseline keeps the highContrast legacy projection of the d exports[`Flex default baseline keeps the light legacy projection of the default Flex tokens 1`] = ` { "colorCount": 274, - "colors": "86f973400507e95e", - "components": "72a2537e550ec269", + "colors": "9466ef021b8d326d", + "components": "75484377ab62c281", "host": "6be4fd450402dc4f", - "shadows": "6cb9f79865a74b20", + "shadows": "6cc8dc2e49311041", "spacing": "ae5c5f37376210ff", "typography": "758be399ff81061a", } @@ -50,15 +50,16 @@ exports[`Flex default baseline keeps the light legacy projection of the default exports[`Flex default baseline keeps the values consumers read from the default Flex tokens 1`] = ` { - "borderRadius": "13bd91dc683ef515", - "color": "929614bda52b14dd", + "borderRadius": "cfa8c2371a72707b", + "color": "404280ad7ea5242b", "colorCount": 119, "fontFamily": "7a4e96787cf538ad", - "fontSize": "684a251b98d9a7a5", + "fontSize": "4a646185b2b8a198", "fontWeight": "51d94cec151d0fba", - "lineHeight": "e10b09e52a79eb29", - "shadow": "844e4f7e40ea22d0", - "spacing": "d8a73be81c0519cd", + "lineHeight": "ef6cefe619d4be48", + "motion": "4d1fcc8da5a5ae8e", + "shadow": "67f2d9a2496a3ba8", + "spacing": "3bb2ea09d57c34c3", "strokeWidth": "d7b6d097ecd34db0", } `; @@ -72,8 +73,9 @@ exports[`legacy compatibility baseline keeps Flex values converted from the dark "fontSize": "52fa58b4bacaf329", "fontWeight": "8fe4b9b24b1f62c7", "lineHeight": "e10b09e52a79eb29", - "shadow": "f6ac563fefc348cd", - "spacing": "d8a73be81c0519cd", + "motion": "4d1fcc8da5a5ae8e", + "shadow": "3abb099ca48f96cf", + "spacing": "b696c8094b46fe18", "strokeWidth": "d7b6d097ecd34db0", } `; @@ -87,8 +89,9 @@ exports[`legacy compatibility baseline keeps Flex values converted from the dark "fontSize": "52fa58b4bacaf329", "fontWeight": "8fe4b9b24b1f62c7", "lineHeight": "e10b09e52a79eb29", - "shadow": "f6ac563fefc348cd", - "spacing": "d8a73be81c0519cd", + "motion": "4d1fcc8da5a5ae8e", + "shadow": "3abb099ca48f96cf", + "spacing": "b696c8094b46fe18", "strokeWidth": "d7b6d097ecd34db0", } `; @@ -102,8 +105,9 @@ exports[`legacy compatibility baseline keeps Flex values converted from the high "fontSize": "52fa58b4bacaf329", "fontWeight": "8fe4b9b24b1f62c7", "lineHeight": "e10b09e52a79eb29", - "shadow": "f6ac563fefc348cd", - "spacing": "d8a73be81c0519cd", + "motion": "4d1fcc8da5a5ae8e", + "shadow": "3abb099ca48f96cf", + "spacing": "b696c8094b46fe18", "strokeWidth": "d7b6d097ecd34db0", } `; @@ -117,8 +121,9 @@ exports[`legacy compatibility baseline keeps Flex values converted from the ligh "fontSize": "52fa58b4bacaf329", "fontWeight": "8fe4b9b24b1f62c7", "lineHeight": "e10b09e52a79eb29", - "shadow": "844e4f7e40ea22d0", - "spacing": "d8a73be81c0519cd", + "motion": "4d1fcc8da5a5ae8e", + "shadow": "92288e2a96923296", + "spacing": "b696c8094b46fe18", "strokeWidth": "d7b6d097ecd34db0", } `; @@ -132,8 +137,9 @@ exports[`legacy compatibility baseline keeps Flex values converted from the mock "fontSize": "5f02d7a42f1f300e", "fontWeight": "8fe4b9b24b1f62c7", "lineHeight": "e10b09e52a79eb29", - "shadow": "4d7c42320ddafbfb", - "spacing": "d8a73be81c0519cd", + "motion": "4d1fcc8da5a5ae8e", + "shadow": "79d43104cbb1984a", + "spacing": "b696c8094b46fe18", "strokeWidth": "d7b6d097ecd34db0", } `; diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap index 2b30281f80..426e07fedd 100644 --- a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap @@ -18,6 +18,7 @@ exports[`public entry points . keeps its runtime export names 1`] = ` "normalizeThemeAppearanceRequest: function", "resolveThemeAppearance: function", "selectColorEntry: function", + "selectShadowEntry: function", "themedStyleSheetFactory: function", "useRootInputModality: function", "useRootSettings: function", @@ -118,6 +119,7 @@ exports[`public entry points ./theming keeps its runtime export names 1`] = ` "normalizeThemeAppearanceRequest: function", "resolveThemeAppearance: function", "selectColorEntry: function", + "selectShadowEntry: function", "setIsHighContrast: function", "themeAppearanceKey: function", "useRootInputModality: function", diff --git a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts index eb1b5b057b..d8962b0a4e 100644 --- a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts +++ b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts @@ -182,6 +182,14 @@ describe('runtime graph ownership', () => { expect(runtimeGraph('theming/ThemedRoot.tsx')).toContain('flex/colors/interactionPolicy.ts'); }); + it('keeps the forward Theme adapter and its Fluent fallback free of the interaction engine', () => { + const adapterGraph = runtimeGraph('flex/adapters/flexTokensFromTheme.ts'); + expect(adapterGraph).toContain('flex/adapters/fluentFallbackTokens.ts'); + expect(adapterGraph).not.toContain('flex/colors/interactionPolicy.ts'); + expect(adapterGraph).not.toContain('flex/defaults/defaultTokens.ts'); + expect(reachedUnder(adapterGraph, 'color-lib/')).toEqual([]); + }); + it('keeps the color library free of token, theme, and test ownership', () => { const colorLibGraph = runtimeGraph('color-lib/index.ts'); expect(colorLibGraph).toContain('color-lib/interaction.ts'); diff --git a/packages/agentic/design/src/test/fixtures/interactionColors.ts b/packages/agentic/design/src/test/fixtures/interactionColors.ts index 005187e3a6..5b9e5eaed5 100644 --- a/packages/agentic/design/src/test/fixtures/interactionColors.ts +++ b/packages/agentic/design/src/test/fixtures/interactionColors.ts @@ -48,9 +48,16 @@ export function getInteractionColorOverrides( return { overrides, diagnostics }; } +/** + * One state of every resolved color, keyed by token. + */ +export function stateColorValues(colors: SemanticColors, state: 'rest' | InteractionColorState): SemanticColorTokenValues { + return Object.fromEntries(Object.entries(colors).map(([name, color]) => [name, color[state]])) as SemanticColorTokenValues; +} + /** * The rest value of every resolved color, keyed by token. */ export function restColorValues(colors: SemanticColors): SemanticColorTokenValues { - return Object.fromEntries(Object.entries(colors).map(([name, color]) => [name, color.rest])) as SemanticColorTokenValues; + return stateColorValues(colors, 'rest'); } diff --git a/packages/agentic/design/src/test/fixtures/x3InteractionConformance.ts b/packages/agentic/design/src/test/fixtures/x3InteractionConformance.ts index 993ccea819..bcb103f2b0 100644 --- a/packages/agentic/design/src/test/fixtures/x3InteractionConformance.ts +++ b/packages/agentic/design/src/test/fixtures/x3InteractionConformance.ts @@ -10,8 +10,9 @@ export type InteractionConformanceVector = readonly [ ]; /** - * Test fixture with base and interaction fallback values from the pinned x3 source commit. - * Each row covers hover and pressed in both light and dark modes. + * Cool rest and interaction fallback values from x3-design/fluent-design@206e890b + * (`semantic-{light,dark}.css` and `interaction-fallback-{light,dark}.css`). + * Each row covers rest, hover, and pressed in light and then dark. */ export const x3InteractionConformance = { surfaceNeutralFarther: ['#ebebeb', '#e1e1e1', '#d7d7d7', '#1b1b1b', '#2f2f2f', '#454545'], @@ -75,8 +76,8 @@ export const x3InteractionConformance = { foregroundSuccessOnloud: ['#ffffff', '#ffffff', '#ffffff', '#000000db', '#000000db', '#000000db'], } as const satisfies Record; -/** Base and generated interaction values for the pinned Bebop Warm theme. */ -export const x3BebopWarmInteractionConformance = { +/** Warm rest and interaction fallback values from the same pinned `warm/` stylesheets. */ +export const x3WarmInteractionConformance = { surfaceNeutralFarther: ['#f0eae5', '#e8e0d9', '#dfd6ce', '#1e1916', '#342d29', '#4b423d'], surfaceNeutralFar: ['#faf4f0', '#f2eae4', '#e9dfd9', '#231e1a', '#38312b', '#4d453e'], surfaceNeutralNear: ['#f6f1ec', '#ede7e0', '#e5ddd4', '#1c1714', '#322b27', '#4b413c'], @@ -139,59 +140,60 @@ export const x3BebopWarmInteractionConformance = { } as const satisfies Record; /** - * The generated x3 table routes these entries through its separately scoped - * Bebop Warm path. `defaultValue` is the result of the cool tone requested by - * #4268; `warmValue` is retained to make every table deviation explicit. + * Cool table states the cool interaction policy does not reproduce. The x3 + * generator routes these entries through its warm path, so the default cool + * description authors `sourceValue` explicitly; `derivedValue` is what the + * cool policy computes from rest. */ -export const x3WarmToneDeviations = { +export const x3CoolExplicitStates = { 'backgroundNeutralTranslucent.hover.light': { - warmValue: '#d8d8d88a', - defaultValue: '#dfdfdf8a', - reason: 'The warm path composites this translucent background against a reference surface before shifting it.', + sourceValue: '#d8d8d88a', + derivedValue: '#dfdfdf8a', + reason: 'The source composites this translucent background against a reference surface before shifting it.', }, 'backgroundNeutralTranslucent.pressed.light': { - warmValue: '#cacaca94', - defaultValue: '#d5d5d594', - reason: 'The warm path composites this translucent background against a reference surface before shifting it.', + sourceValue: '#cacaca94', + derivedValue: '#d5d5d594', + reason: 'The source composites this translucent background against a reference surface before shifting it.', }, 'backgroundNeutralTranslucent.hover.dark': { - warmValue: '#56565688', - defaultValue: '#47474788', - reason: 'The warm path composites this translucent background against a reference surface before shifting it.', + sourceValue: '#56565688', + derivedValue: '#47474788', + reason: 'The source composites this translucent background against a reference surface before shifting it.', }, 'backgroundNeutralTranslucent.pressed.dark': { - warmValue: '#6d6d6d8f', - defaultValue: '#5353538f', - reason: 'The warm path composites this translucent background against a reference surface before shifting it.', + sourceValue: '#6d6d6d8f', + derivedValue: '#5353538f', + reason: 'The source composites this translucent background against a reference surface before shifting it.', }, 'strokeNeutralSoft.hover.light': { - warmValue: '#02020277', - defaultValue: '#00000077', - reason: 'The warm path adds chroma while the default algorithm preserves chroma.', + sourceValue: '#02020277', + derivedValue: '#00000077', + reason: 'The source adds chroma while the cool policy preserves chroma.', }, 'strokeNeutralSoft.pressed.light': { - warmValue: '#04040481', - defaultValue: '#00000081', - reason: 'The warm path adds chroma while the default algorithm preserves chroma.', + sourceValue: '#04040481', + derivedValue: '#00000081', + reason: 'The source adds chroma while the cool policy preserves chroma.', }, 'strokeNeutralSubtle.pressed.light': { - warmValue: '#05050535', - defaultValue: '#00000035', - reason: 'The warm path adds chroma while the default algorithm preserves chroma.', + sourceValue: '#05050535', + derivedValue: '#00000035', + reason: 'The source adds chroma while the cool policy preserves chroma.', }, 'strokeBrandSoft.hover.light': { - warmValue: '#02020277', - defaultValue: '#00000077', - reason: 'The warm path adds chroma while the default algorithm preserves chroma.', + sourceValue: '#02020277', + derivedValue: '#00000077', + reason: 'The source adds chroma while the cool policy preserves chroma.', }, 'strokeBrandSoft.pressed.light': { - warmValue: '#04040481', - defaultValue: '#00000081', - reason: 'The warm path adds chroma while the default algorithm preserves chroma.', + sourceValue: '#04040481', + derivedValue: '#00000081', + reason: 'The source adds chroma while the cool policy preserves chroma.', }, 'strokeBrandSubtle.pressed.light': { - warmValue: '#05050535', - defaultValue: '#00000035', - reason: 'The warm path adds chroma while the default algorithm preserves chroma.', + sourceValue: '#05050535', + derivedValue: '#00000035', + reason: 'The source adds chroma while the cool policy preserves chroma.', }, } as const; diff --git a/packages/agentic/design/src/theming/index.ts b/packages/agentic/design/src/theming/index.ts index bcddc3f6ff..1b46590c53 100644 --- a/packages/agentic/design/src/theming/index.ts +++ b/packages/agentic/design/src/theming/index.ts @@ -71,6 +71,7 @@ export { FlexThemeReference } from '../flex/flexThemeReference'; export type { FlexThemeInput, FlexThemeRecipe, FlexThemeReferenceOptions, LegacyThemeFallback } from '../flex/flexThemeReference'; export { flexColor, selectColorEntry } from '../flex/colors/flexColor'; export type { ColorSchemeSelector } from '../flex/colors/flexColor'; +export { selectShadowEntry } from '../flex/flexShadow'; export type { FlexTokenDescription, PartialFlexTokens } from '../flex/tokens.types'; export { ThemeReference } from '../fluent/themeReference'; export type { OnThemeChange, ThemeRecipe, ThemeReferenceOptions, ThemeTransform } from '../fluent/themeReference'; diff --git a/packages/agentic/design/src/theming/modern.ts b/packages/agentic/design/src/theming/modern.ts index baf7259ce7..02cc7b729e 100644 --- a/packages/agentic/design/src/theming/modern.ts +++ b/packages/agentic/design/src/theming/modern.ts @@ -24,6 +24,7 @@ export { FlexThemeReference } from '../flex/flexThemeReference'; export type { FlexThemeInput, FlexThemeRecipe, FlexThemeReferenceOptions, LegacyThemeFallback } from '../flex/flexThemeReference'; export { flexColor, selectColorEntry } from '../flex/colors/flexColor'; export type { ColorSchemeSelector } from '../flex/colors/flexColor'; +export { selectShadowEntry } from '../flex/flexShadow'; export type { FlexTokenDescription, PartialFlexTokens } from '../flex/tokens.types'; export { ThemeProvider } from './ThemeProvider'; export type { ThemeProviderProps } from './ThemeProvider'; diff --git a/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml b/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml index 9660237a2d..17af8afc20 100644 --- a/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml +++ b/packages/agentic/design/src/tokens/mappings/flex-token-map.yaml @@ -9,10 +9,12 @@ target: direction: flex token path <- authoring source token sources: generic: - description: Generic Flex CSS custom properties. + description: Generic Flex CSS custom properties. Cool and warm tones share names. locations: - dev/web/flex-themes/css/semantic.css - dev/web/flex-themes/css/interaction-fallback.css + - dev/web/flex-themes/css/warm/semantic.css + - dev/web/flex-themes/css/warm/interaction-fallback.css fluent: description: Fluent UI React Native / Fluent 2 tokens used for native defaults. package: '@fluentui-react-native/design-tokens-win32/colorful' @@ -44,6 +46,10 @@ rules: differ in value from Fluent (400/500/600/700). fontFamily: role match (base / monospace). notes: + - Every rest and non-color destination declares its generic source. scripts/flex-defaults/generate-defaults.mjs + reads those custom properties from the pinned cool and warm snapshots and emits + ../../flex/defaults/defaultTokens.generated.ts plus its coverage ledger; check-mappings.cjs enforces the + coverage. - global.* references are best-fit matches into the Fluent global palette; expression families map to the matching shared-color ramp step, gray to the grey ramp, alpha/translucent roles to the *Alpha ramps. @@ -55,18 +61,22 @@ rules: semantic.css. - letterSpacing* are null — Fluent global has no letter-spacing/tracking token. - fontFamily.contentEditorial is null — Fluent global has no serif family token. + - motion.* are null — Fluent global has no motion token, and Theme has no motion path. - furn-theme is omitted when Theme has no corresponding value path. - scripts/token-mappings/check-mappings.cjs enforces that flex-from-theme.json exactly matches the furn-theme mappings in this file. - ../../flex/adapters/flexTokensFromTheme.ts consumes flex-from-theme.json and merges the projected - Theme values over nonFluentFlexTokens. An interaction state the Theme does not map - resolves to the Theme's rest value; the forward adapter never runs the interaction - algorithm. - - The same check enforces that nonFluentFlexTokens in ../../flex/defaults/defaultTokens.ts covers + Theme values over the Fluent-native fallbacks in ../../flex/adapters/fluentFallbackTokens.ts. + An interaction state the Theme does not map resolves to the Theme's rest value; the forward + adapter never runs the interaction algorithm. + - The same check enforces that nonFluentFlexTokens in ../../flex/adapters/fluentFallbackTokens.ts covers unmapped supported destinations. An unmapped hover or pressed value is included only when its rest destination is also unmapped; otherwise the state - value remains only in defaultFlexTokenDescription so a Theme-provided rest value + value remains only in fluentFallbackFlexTokens so a Theme-provided rest value does not inherit a mismatched fallback interaction color. + - Theme shadows are legacy { ambient, key } pairs. The forward adapter converts each to + [ambient, key] layers. The reverse shadowLayersToToken transform projects the first layer + to ambient and the last to key, so middle layers are dropped; this projection is lossy. - Button uses borderRadius.base200 / base300 / base400 for small / medium / large. The FURN Theme exposes its shared small/medium Button radius, but its large size-specific radius remains sourced from Fluent global tokens. @@ -76,7 +86,13 @@ rules: reverse: projection: ./theme-from-flex.json interactionFallback: rest - transforms: {} + transforms: + shadows.shadow16: shadowLayersToToken + shadows.shadow2: shadowLayersToToken + shadows.shadow28: shadowLayersToToken + shadows.shadow4: shadowLayersToToken + shadows.shadow64: shadowLayersToToken + shadows.shadow8: shadowLayersToToken canonical: colors.black: source: color.fixedBlack.rest @@ -1511,6 +1527,45 @@ tokens: lineHeight.functionalTitleSmall: generic: '--gnrc-line-height-functional-title-small' fluent: global.font.lineHeight500 + motion.durationBase100: + generic: '--gnrc-motion-duration-base-100' + fluent: + motion.durationBase1000: + generic: '--gnrc-motion-duration-base-1000' + fluent: + motion.durationBase200: + generic: '--gnrc-motion-duration-base-200' + fluent: + motion.durationBase300: + generic: '--gnrc-motion-duration-base-300' + fluent: + motion.durationBase50: + generic: '--gnrc-motion-duration-base-50' + fluent: + motion.durationBase500: + generic: '--gnrc-motion-duration-base-500' + fluent: + motion.easingExpressiveEnter: + generic: '--gnrc-motion-easing-expressive-enter' + fluent: + motion.easingExpressiveExit: + generic: '--gnrc-motion-easing-expressive-exit' + fluent: + motion.easingExpressiveTransition: + generic: '--gnrc-motion-easing-expressive-transition' + fluent: + motion.easingFunctionalEnter: + generic: '--gnrc-motion-easing-functional-enter' + fluent: + motion.easingFunctionalExit: + generic: '--gnrc-motion-easing-functional-exit' + fluent: + motion.easingFunctionalLinear: + generic: '--gnrc-motion-easing-functional-linear' + fluent: + motion.easingFunctionalTransition: + generic: '--gnrc-motion-easing-functional-transition' + fluent: shadow.high: generic: '--gnrc-shadow-high' fluent: shadow.shadow16 @@ -1565,6 +1620,9 @@ tokens: spacing.componentBase700: generic: '--gnrc-spacing-component-base-700' fluent: global.size280 + spacing.componentBase800: + generic: '--gnrc-spacing-component-base-800' + fluent: global.size320 spacing.layoutBase100: generic: '--gnrc-spacing-layout-base-100' fluent: global.size80 diff --git a/packages/agentic/design/src/tokens/mappings/flexTokenMappings.test.ts b/packages/agentic/design/src/tokens/mappings/flexTokenMappings.test.ts index 884c670174..9d778825be 100644 --- a/packages/agentic/design/src/tokens/mappings/flexTokenMappings.test.ts +++ b/packages/agentic/design/src/tokens/mappings/flexTokenMappings.test.ts @@ -209,11 +209,59 @@ describe('Flex token mapping consistency', () => { expect(validateMappingInputs(changed)).toContainEqual({ rule: 'reverse-transform', path: 'colors.black', - expected: ['identity', 'numberToPx'], + expected: ['identity', 'numberToPx', 'shadowLayersToToken'], actual: 'notARealTransform', }); }); + it('requires layered shadows to project through shadowLayersToToken', () => { + const changed = cloneInputs(inputs); + delete changed.mapping.reverse.transforms['shadows.shadow2']; + + expect(validateMappingInputs(changed)).toContainEqual({ + rule: 'reverse-transform', + path: 'shadows.shadow2', + expected: 'shadowLayersToToken', + actual: '', + }); + }); + + it('requires a YAML destination for every supported rest and non-color path', () => { + const changed = cloneInputs(inputs); + delete changed.mapping.tokens['spacing.componentBase800']; + + expect(validateMappingInputs(changed)).toContainEqual({ + rule: 'mapping-coverage', + path: 'spacing.componentBase800', + expected: 'a destination in flex-token-map.yaml', + actual: '', + }); + }); + + it('requires a generic source for every supported destination', () => { + const changed = cloneInputs(inputs); + delete (changed.mapping.tokens['motion.durationBase200'] as Record).generic; + + expect(validateMappingInputs(changed)).toContainEqual({ + rule: 'generic-source', + path: 'motion.durationBase200', + expected: 'a generic custom property', + actual: '', + }); + }); + + it('rejects generic sources that are not --gnrc-* custom properties', () => { + const changed = cloneInputs(inputs); + (changed.mapping.tokens['motion.durationBase200'] as Record).generic = '--fluent-duration'; + + expect(validateMappingInputs(changed)).toContainEqual({ + rule: 'schema', + path: 'motion.durationBase200', + expected: 'a --gnrc-* custom property name or no generic field', + actual: '--fluent-duration', + }); + }); + it('emits declared reverse transforms into the generated projection', () => { const changed = cloneInputs(inputs); changed.mapping.reverse.transforms['typography.sizes.body'] = 'numberToPx'; diff --git a/packages/agentic/design/src/tokens/mappings/theme-from-flex.json b/packages/agentic/design/src/tokens/mappings/theme-from-flex.json index d94ff3bf3d..19793e3955 100644 --- a/packages/agentic/design/src/tokens/mappings/theme-from-flex.json +++ b/packages/agentic/design/src/tokens/mappings/theme-from-flex.json @@ -246,22 +246,28 @@ "source": "borderRadius.base200" }, "shadows.shadow16": { - "source": "shadow.high" + "source": "shadow.high", + "transform": "shadowLayersToToken" }, "shadows.shadow2": { - "source": "shadow.lowest" + "source": "shadow.lowest", + "transform": "shadowLayersToToken" }, "shadows.shadow28": { - "source": "shadow.higher" + "source": "shadow.higher", + "transform": "shadowLayersToToken" }, "shadows.shadow4": { - "source": "shadow.lower" + "source": "shadow.lower", + "transform": "shadowLayersToToken" }, "shadows.shadow64": { - "source": "shadow.highest" + "source": "shadow.highest", + "transform": "shadowLayersToToken" }, "shadows.shadow8": { - "source": "shadow.low" + "source": "shadow.low", + "transform": "shadowLayersToToken" }, "typography.families.monospace": { "source": "fontFamily.contentCode" diff --git a/packages/agentic/design/src/tokens/mappings/upstream-pin.json b/packages/agentic/design/src/tokens/mappings/upstream-pin.json index 93af227622..1ebf950ef9 100644 --- a/packages/agentic/design/src/tokens/mappings/upstream-pin.json +++ b/packages/agentic/design/src/tokens/mappings/upstream-pin.json @@ -1,13 +1,25 @@ { "repository": "x3-design/fluent-design", - "commit": "d334acf5cbad813f2b7cd554da942b09a7ff8f10", - "verifiedDate": "2026-08-27", + "commit": "206e890b645fb450ad7c5df2ff981765349a2b58", + "verifiedDate": "2026-10-24", "files": [ { "id": "semanticCss", "upstreamPath": "dev/web/flex-themes/css/semantic.css", "snapshotPath": "scripts/token-mappings/__fixtures__/x3/semantic.css", - "blobSha": "6dac670ac83f3251898d40f07c0e90a2779a1915" + "blobSha": "4c9f3e0a70bdbb8b7183d2db15254d9427d8e6ab" + }, + { + "id": "semanticLightCss", + "upstreamPath": "dev/web/flex-themes/css/semantic-light.css", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/semantic-light.css", + "blobSha": "633b87a634be88bf37b018f287b3d1758a189707" + }, + { + "id": "semanticDarkCss", + "upstreamPath": "dev/web/flex-themes/css/semantic-dark.css", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/semantic-dark.css", + "blobSha": "d9ae7355fc3ed934a385bf6cd36244e2f5bba7b0" }, { "id": "interactionFallbackCss", @@ -15,11 +27,65 @@ "snapshotPath": "scripts/token-mappings/__fixtures__/x3/interaction-fallback.css", "blobSha": "c69ff3145f4f9b1228a694a3e7ba8b1a65d2c032" }, + { + "id": "interactionFallbackLightCss", + "upstreamPath": "dev/web/flex-themes/css/interaction-fallback-light.css", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/interaction-fallback-light.css", + "blobSha": "87f488d731babc06f457edf9ca4c358fa79b39b2" + }, + { + "id": "interactionFallbackDarkCss", + "upstreamPath": "dev/web/flex-themes/css/interaction-fallback-dark.css", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/interaction-fallback-dark.css", + "blobSha": "f4d6af7fdcd16a315f024f907c2a5b264366cda8" + }, + { + "id": "warmSemanticCss", + "upstreamPath": "dev/web/flex-themes/css/warm/semantic.css", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/warm/semantic.css", + "blobSha": "dfe8416dffb4b215777d0270c3fe40a5d631ee2c" + }, + { + "id": "warmSemanticLightCss", + "upstreamPath": "dev/web/flex-themes/css/warm/semantic-light.css", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/warm/semantic-light.css", + "blobSha": "0c155116e886e55f98b5b9212a96ed25efcf89ee" + }, + { + "id": "warmSemanticDarkCss", + "upstreamPath": "dev/web/flex-themes/css/warm/semantic-dark.css", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/warm/semantic-dark.css", + "blobSha": "cacec7d267fb11a44d6e42f943e3aa6ab5955e1f" + }, + { + "id": "warmInteractionFallbackCss", + "upstreamPath": "dev/web/flex-themes/css/warm/interaction-fallback.css", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback.css", + "blobSha": "6dbe4a963fd197cac7fabf35cf6c801f68aa1f4c" + }, + { + "id": "warmInteractionFallbackLightCss", + "upstreamPath": "dev/web/flex-themes/css/warm/interaction-fallback-light.css", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback-light.css", + "blobSha": "ffb1ef7e3eda4a0c2428cbed75db707f14c0173f" + }, + { + "id": "warmInteractionFallbackDarkCss", + "upstreamPath": "dev/web/flex-themes/css/warm/interaction-fallback-dark.css", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/warm/interaction-fallback-dark.css", + "blobSha": "6d51a1eb182381eeb9dcd14d7c6b7a4ca0de7ed1" + }, { "id": "mappings", "upstreamPath": "dev/web/flex-tokens/mappings.json", "snapshotPath": "scripts/token-mappings/__fixtures__/x3/mappings.json", - "blobSha": "4b917a8c93a18591741482136ee0df2b05bdce2f" + "blobSha": "33c7a100a200d52d48f35faae5adf9f6282e462a" + }, + { + "id": "tokens", + "upstreamPath": "dev/web/flex-tokens/tokens.json", + "snapshotPath": "scripts/token-mappings/__fixtures__/x3/tokens.json", + "blobSha": "49bec466b835c0df87c879f399a29fc60db6b426" } ] } From be30bdd7de5f1eb310e892efe236bbbdf5e2428e Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 23 Oct 2026 20:45:45 -0700 Subject: [PATCH 07/18] design: release notes and qualification (refactor phase 6) Add changesets for design (minor), components (minor), and storybook-desktop-runtime (patch). Update the repository theming basics for the x3 defaults and interactive color envelope, document the lossy shadow and motion reverse projection, move the plan's open gates (fixed derivation, native layered shadows and motion) into remaining-work.md, and remove the completed plan. Refresh the bundle-size baselines. Against the Phase 1 measurement, Flex-state scenarios grow about 28-29 KB raw / 7.1-7.3 KB gzip, legacy-theme-from-flex +7.9 KB / +4.1 KB, and color-lib -62 B. The committed catalog baseline was already stale before the refactor (155 KB committed vs 205 KB measured). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5030bce5-d7f7-4fb1-93de-68599b79269f --- packages/agentic/design/refactoring.md | 612 ------------------------- 1 file changed, 612 deletions(-) delete mode 100644 packages/agentic/design/refactoring.md diff --git a/packages/agentic/design/refactoring.md b/packages/agentic/design/refactoring.md deleted file mode 100644 index ce9097db38..0000000000 --- a/packages/agentic/design/refactoring.md +++ /dev/null @@ -1,612 +0,0 @@ -# Design package reorganization and evolution - -**Status:** Proposed; documentation only. Owner-approved decisions below supersede the initial review recommendations. -Only the remaining implementation gates require further decisions. - -**Scope:** Reorganize `@fluentui-react-native/design`, add tone-aware appearance, separate Flex policy from color -algorithms, and introduce authored and resolved interactive colors with verified Flex defaults. Preserve legacy -theming consumers, including consumers outside this repository. Modern/Flex authoring changes are intentionally -breaking and require a coordinated migration. - -This owner-requested review draft is a narrow exception to R-PKGDOC-009. [Remaining work](references/remaining-work.md) -remains the package's open-work index; it should point here rather than duplicate the implementation checklist. Once -implemented, move the durable contract into the owning references and remove this draft and its pointer. This draft -is repository-only, not part of the published package inventory. - -## 1. Success criteria and compatibility boundary - -- Flex implementation belongs in `src/flex/`; legacy Fluent implementation in `src/fluent/`; shared types in - `src/types/`; test and validation collateral in `src/test/`. -- One `ThemeProvider` continues to serve both authoring models. A Flex provider publishes metadata without resolving - either model; hooks construct only the model they return. Legacy raw-context behavior remains supported. -- Existing legacy packages, exported names, public subpaths, constructors, recipe behavior, context identities, - deprecated appearance APIs, and legacy-authored values remain compatible. -- `ColorTone` is `'cool' | 'warm'`, defaults to `'cool'`, and participates in top-level appearance and every applicable - cache identity. No OS tone signal or `'system'` tone is invented. -- Interactive colors have distinct input and output contracts. Explicit states win; missing supported states are - calculated lazily and automatically for Flex consumers, at most once per state and resolved entry. Unmappable rest - colors fall back to that same rest value. No author-owned object is mutated. -- Default Flex values use current x3 sources, pinned to an immutable revision when refreshed, with an explicit native - adaptation ledger. Omit hover/pressed defaults wherever the dynamic APIs reproduce them from `[light, dark]` rest - colors. Mapping coverage, value parity, algorithm conformance, and contrast are separate checks. -- The modern Flex graph includes the raw algorithms needed for automatic interaction colors, but remains free of - legacy projection/default payloads and test helpers. Legacy Fluent consumers retain their existing graph and - behavior; the engine is not injected through shared provider utilities. -- Close the non-color gaps, including missing motion/spacing roles and layered/dark shadows, without changing legacy - Fluent types. -- Consumer code, generated mappings, component token references, authoring instructions, and migration examples - change together. No component interaction or accessibility redesign is included. - -### Confirmed legacy and Flex ownership - -**Confirmed by the owner:** legacy consumers use legacy Fluent themes and the existing legacy provider entry points. -Preserve `ThemeReference`, legacy platform factories, raw `ThemeContext`, compatibility packages, and their existing -values. The Flex refactor must not change those consumers. No additional provider is required. - -Agentic/Flex consumers are in rapid development: adopt current x3 values, including intentional visual changes, without -an opt-in historical preset or a separate default-activation approval. Do not gate those changes on preserving legacy -visuals beneath an implicit Flex root; that is not the legacy consumption model in scope. - -If an application deliberately mixes legacy consumers with a Flex-authored source, keep mapped Flex values -authoritative in its legacy projection. Do not introduce author-touched-path side channels or historical palette -overlays to make the two hooks disagree about the selected source. - -## 2. Evidence and work that must be reconciled - -The baseline inspected for this proposal is `cfa4c66257b7a00d9d828c81da7c36d2e0043c5b`. -**Observed** describes that checkout or an explicitly identified verification. **Proposed** describes future behavior; -it is not an implementation claim. - -| Observed surface | Evidence in this package | Consequence | -| --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | -| Shared providers and consumption-time conversion already exist | `src/theming/ThemeProvider.tsx:19-53`, `src/theming/themeRuntime.ts:17-72`, `src/theming/useTheme.ts:16-46` | Preserve the architecture rather than adding another provider | -| Appearance keys currently have three axes | `src/theming/appearance.types.ts:1-39`, `src/theming/appearance.ts:16-81` | Tone must reach normalization, interning, reference caches, state caches, and legacy projection caches | -| Rest values and partial `color.hover`/`color.pressed` maps are separate | `src/tokens/flex.types.ts:208-281`, `src/theming/flexThemeReference.ts:22-45` | The new model changes types, merge rules, mappings, styles, tests, and consumers | -| Every appearance starts from the same hand-authored default table | `src/tokens/defaultTokens.ts:69-392`, `src/theming/flexThemeReference.ts:137-143`, [open defaults work](references/remaining-work.md#appearance-specific-default-tokens) | Reformatting that table does not establish x3 correctness | -| color-lib owns Flex classification and bulk token operations | `src/color-lib/interaction.ts:26-125`, `src/color-lib/interaction.ts:172-194`, `src/color-lib/interaction.ts:255-316` | Separate semantic policy from numerical algorithms | -| Pairings and contrast audits are already test-only | `src/testing/color-validation/pairings.ts:15-21`, `src/testing/color-validation/validation.ts:1-35` | Relocate their ownership, not duplicate them in Flex runtime | -| Reverse projection has canonical collisions, transforms, and legacy fallback precedence | `src/theming/compat/themeFromFlexTokens.ts:75-110`, `src/tokens/mappings/flex-token-map.yaml:74-99` | Preserve these policies while regenerating paths | -| Bundle assertions match current directory substrings | `apps/bundle-size/scenarios.json:14-52` in the repository | Update positive and negative assertions with moves, or they become vacuous | - -There is overlapping, unlanded default-theme/codegen work for #4263. Before implementation, inspect its actual branch -and reconcile reusable legacy-payload generation, appearance selection, and bundle evidence. Its platform-derived -Flex defaults are not proof of x3 parity and are not present merely because a workstream records them. Do not build a -second competing generator or merge that work blindly. - -### Demonstrated duplication - -| Candidate | Proposed treatment | -| ---------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | -| Guarded object-path traversal in `src/utilities/objects.ts:8-57` and `src/theming/compat/themeFromFlexTokens.ts:22-63` | Share the traversal primitive; preserve distinct overwrite and missing-value policies | -| Interactive membership in types, runtime arrays, YAML state mappings, and fixtures | Derive or validate membership against one canonical mapping inventory; retain independent value fixtures | -| Public `ThemeState` and internal `RuntimeThemeState` structure | One type-only definition in `src/types/`; no new runtime dependency cycle | -| Similar partial-color inputs and duplicated conformance-color test setup | Use the new authored-input contract and a shared test-only fixture builder | -| Repeated warm reference-backdrop constant | Keep one algorithm-owned constant, not a semantic-token lookup | -| Revision/appearance cache boilerplate | Normalize keys centrally; extract storage mechanics only if it keeps modern and legacy runtime graphs separate | - -Do not merge `ThemeReference` and `FlexThemeReference` just because they have similar caches. Do not pool every color -literal or generated payload into one eagerly reachable module without measured bundle evidence. Preserve existing -root versus legacy meanings of similarly named font types instead of renaming a legacy API during this move. - -## 3. Target ownership and dependency direction - -```text -src/ - types/ Shared, type-only appearance, color and state contracts - theming/ Shared providers, boundaries, appearance sources and runtime identity - flex/ - tokens.types.ts Authored and resolved Flex contracts - flexThemeReference.ts Modern source and recipe resolution - colors/ flexColor, lazy resolution, token classification and metadata - defaults/ Provenance-bearing generated defaults and native adaptations - adapters/ Lightweight legacy Theme-to-Flex conversion - styling/ Flex-aware color style factories - fluent/ - types/ Legacy Theme, palette, typography and shadow contracts - themeReference.ts Legacy authoring and merge behavior - useTheme.ts Legacy consumption - compat/ Reverse projection and complete legacy defaults - tokens/ Legacy alias, shadow and global payloads - styling/ Legacy token builders and themed stylesheet - ... Legacy pipeline helpers and platform utilities - color-lib/ Raw parsing, conversion, compositing and interaction algorithms - styling/ Shared state/style utilities and public styling facade - tokens/ - mappings/ Existing canonical YAML, projections and upstream pin - ... Existing generated platform global entry points - test/ - fixtures/ Mock themes and conformance fixtures - color-validation/ Pairings, bulk audits and contrast validation - utilities/ Small, genuinely shared runtime primitives -``` - -Keep `src/tokens/mappings/flex-token-map.yaml` at its current canonical path during this work. Its location is embedded -in scripts, rules, contracts, and source references; moving it is not required to move Flex runtime ownership. Treat -generated platform globals separately from semantic Flex defaults. Move platform variants and their platform-specific -tests together. - -**Allowed dependencies:** shared types are runtime-free; raw algorithms depend on shared types, not Flex token names; -Flex runtime uses the necessary raw interaction algorithms, shared utilities, and generated defaults automatically. -Shared theming selects the appropriate consumption path without installing a color engine on the legacy path; legacy -consumption may reach complete legacy defaults. The modern forward adapter can reference legacy types without loading -legacy runtime payloads. Test helpers can depend on production code; production cannot depend on `src/test/` or the -public `testing` entry point. - -Physical folders need not become public subpaths. Preserve explicit, named entry-point exports; do not introduce -`export *` barrels, global engine registration, or a second source of theme truth. - -### Public entry-point preservation - -Retain every current export-map key and its `types`, `react-native`, `import`, and `default` resolution semantics: - -```text -. -./theming -./theming/legacy-source -./theming/compat -./theming/compat/defaults -./tokens/global -./tokens/legacy -./color-lib -./styling -./styling/stylesheet -./styling/tokens -./testing -./package.json -``` - -Entry-point targets may follow moved implementations, or remain thin named facades. Do not produce separate contexts, -constructors, or mutable singletons through old and new entry points. Retain the six compatibility packages documented -in [Entry points](references/entry-points.md); inventory actual exports as well as documentation, including -`hcAliasTokens`. - -Compatibility covers supported package specifiers, not arbitrary private `src/` or `lib/` deep imports. Inventory such -imports before moving files and document this distinction. Modern root and color-lib API changes must be called out -explicitly; retaining a subpath does not imply preserving every modern signature behind it. - -## 4. Appearance and ColorTone - -**Proposed shared type:** - -```ts -export type ColorTone = 'cool' | 'warm'; -``` - -Add `appearance.colorTone` to the existing top-level appearance configuration accepted by theme sources, -`ThemeProvider`, and `ThemedRoot`. Resolved modern appearance always has a concrete tone. Omitted tone means cool, -with no platform listener or automatic tone inference. - -Tone precedence is explicit provider/root override, then source option, then the configured fallback tone, then cool. -An inheriting `ThemedRoot` retains the enclosing request; an explicit theme starts a complete boundary, as today. -Keep scheme, contrast, and interface-level precedence unchanged. Preserve the distinction between an omitted tone -request and an explicitly requested cool tone until fallback resolution. - -Legacy-facing functions must continue accepting existing three-field appearance literals. Normalize missing tone at -the boundary rather than making every external `ResolvedThemeAppearance` argument suddenly require a fourth field. -Keep `colorTone` optional on the existing exported compatibility type, and introduce a strict normalized modern output -type. Widening function parameters alone does not preserve external declarations of the old type. Compile -representative external-style calls before finalizing the new name. Do not add tone to the old `AppearanceOptions` -union. Its reverse conversion remains intentionally lossy. - -Update request keys, resolved interning, source/reference caches, compatibility-default caches, `ThemeState`, recipes, -and style registry identity. Preserve existing cool `themeAppearanceKey` strings if that exported utility's consumers -depend on them; a distinct warm suffix can distinguish tone without changing historical cool keys. Missing and explicit -cool inputs must converge on the same resolved identity. - -A tone-only transition selects a distinct state without mutating the previous one. Returning to a previously resolved -appearance may reuse its state within the same revision; every new state owns a fresh style registry. `update()` and -`invalidate()` still replace all revision-scoped entries. Raw legacy-context boundaries retain their current boundary -semantics: absent tone resolves to cool rather than introducing new inheritance across an implicit legacy boundary. -Cover that behavior explicitly. - -Rename the raw interaction option from `variant: 'default' | 'bebopWarm'` to `colorTone: 'cool' | 'warm'`. -The vocabulary-only change must preserve numerical behavior and the warm reference-backdrop solve. Separately -reconcile any algorithm changes needed to reproduce current x3 sources rather than freezing the older pin's output. -Palette selection and interaction algorithm selection use the same resolved tone. Verify warm provenance alongside -cool; freshness is approved, but unverified values are not. - -## 5. Authored and resolved Flex colors - -### Public contracts - -Use the requested input/output split. Accept readonly tuples as well as ordinary tuples so `as const` authoring works; -the package must not mutate either. - -```ts -import type { ColorValue } from 'react-native'; - -export type ColorTuple = readonly [light: ColorValue, dark: ColorValue]; -export type ColorEntry = ColorValue | ColorTuple; -export type InteractiveColorType = 'standard' | 'inverted' | 'fixed'; - -export type InteractiveColorOptions = { - rest: ColorEntry; - hover?: ColorEntry; - pressed?: ColorEntry; - type?: InteractiveColorType; -}; - -export type InteractiveColor = { - readonly rest: ColorValue; - readonly hover: ColorValue; - readonly pressed: ColorValue; -}; - -export declare function flexColor(value: ColorEntry | InteractiveColorOptions, colorType?: InteractiveColorType): InteractiveColorOptions; -``` - -`flexColor` is a small, pure input normalizer. Its second argument defaults to standard; an explicit -`value.type` wins. It does not resolve appearance, derive colors, or attach caches to its argument. Recognize tuples -and option objects with precise guards; opaque native color objects are leaves, not option bags. - -**Selected output scope:** every Flex color resolves to an `InteractiveColor`, giving consumers and generated -projections one `.rest/.hover/.pressed` access pattern. Every color accepts `ColorEntry | InteractiveColorOptions`. -Keep the canonical interaction-eligibility inventory separate: ineligible tokens expose explicit states when supplied, -otherwise equal rest values and never run derivation. A uniform envelope does not make a disabled, focus, fixed, or -decorative role newly interactive. - -Default definitions and legacy adapters explicitly provide the correct inverted metadata for existing heavy/loud/ -onloud roles. Do not silently override the documented standard default of a newly authored `flexColor` entry by -guessing from its name. Export token-aware classification from the Flex implementation for callers that need it. -Keep interaction eligibility, inversion, and fixed behavior separate. - -### Resolution rules - -1. A single `ColorValue` applies to either scheme. A tuple selects light at index zero and dark at index one. -2. Explicit hover and pressed values are authoritative independently, including native values. Only `undefined` - denotes absence. -3. Rest is available without executing interaction algorithms. Each omitted state gets its own lazy, memoized getter; - pressed derives from rest, never from hover. Reading one state must not calculate the other. -4. Standard and inverted use the reviewed scheme-dependent direction rules. Fixed promises a scheme-independent - derivation policy, but the current implementation does not define one. For derivable literals, require explicit - fixed states until that policy has authoritative evidence and review; do not silently choose light-mode mathematics - or equate fixed with disabled. The unmappable, ineligible, and high-contrast rest-fallback rules still apply. -5. In high contrast, explicit states remain authoritative and missing states deliberately resolve to rest rather than - applying standard/warm fallback math. Light/dark tuples do not encode high-contrast or elevated alternatives; - appearance-aware defaults, bases, or recipes supply those. -6. If the selected rest value is `PlatformColor`, another opaque/dynamic native color, or any other value the raw - parser cannot map, an omitted hover or pressed state returns that exact rest value directly. This is an approved - resolution policy, not an error, warning, or requirement to supply explicit states. Preserve native object identity - and do not inspect or fabricate channels. Explicit states still win. Direct raw APIs retain their structured - unresolvable results for callers and test audits that need them. -7. Cache only package-owned normalized descriptors and resolved entries. Frozen output envelopes may hold memoized - state in closures. Never mutate or freeze caller-owned native objects. - -An authored dynamic native color can still follow the OS appearance rather than a forced theme scheme. Document that -distinction and recommend explicit scheme tuples where the author needs theme-controlled selection. - -### Automatic dynamic colors for Flex - -**Confirmed by the owner:** Flex consumers receive the dynamic interaction APIs automatically. The Flex resolver -synchronously imports and calls the required raw algorithm modules; no source-level deriver option, extra author -import, provider setting, registration, or missing-engine error exists. The public `/color-lib` entry point remains -available for direct algorithm use, but it is not an opt-in requirement for theme authors. - -Keep evaluation lazy even though the necessary code is bundled. Provider mount, rest reads, and explicit state reads -must not calculate omitted states. Omit each generated default hover/pressed value independently when the built-in -algorithm can reproduce the current x3 reference from the selected rest color, scheme, tone, and token metadata. -Author concise `[light, dark]` rest tuples; keep an explicit state only for a genuine source exception or another -non-derivable authored override. Unmappable rest values need no duplicate interaction fields. - -This intentionally changes the old modern-root color-lib exclusion, not the legacy API contract. Update the design -package invariants, contributing guidance, and bundle scenarios when implementing it. Keep unrelated color utilities, -test audits, and legacy payloads out of the Flex graph where tree shaking permits; do not hide the added algorithm -cost behind a lazy getter claim. - -Use the raw API's structured unresolvable result for the approved rest fallback. Do not broadly catch unexpected -algorithm errors and turn them into rest values. Invalid authoring inputs and unsupported fixed-literal semantics -still require explicit errors; native/unmappable colors do not. - -### Merge and recipe rules - -Color tokens are atomic replacement leaves. A replacement requires rest; omitted interactions belong to the new rest -and must not inherit stale explicit states from an earlier layer. Arrays and opaque colors also remain atomic. -`undefined` means no override. Preserve existing non-color merge behavior unless a separately reviewed requirement -changes it. - -Keep defaults, base, and recipe ordering. Recipes receive accumulated readonly authored descriptions plus normalized -appearance; merge those descriptions before producing resolved getter objects. Parent references supply their -descriptions internally, not appearance-bound outputs. Provide a small pure selector for authored rest/explicit tuple -values where recipes need an appearance-specific value. This is an intentional modern recipe API break and needs a -worked migration. - -Do not accept resolved `FlexTokens` as ordinary authoring input or pass resolved entries through generic deep merge, -spread, `Object.assign`, or serialization. Own enumerable getters are invoked by `Object.assign`; copying a getter -does not preserve its laziness. A `WeakSet` brand alone cannot prove that an entry's captured appearance, revision, -algorithm policy, and token context are valid for reuse. Do not add that hidden coercion layer. - -## 6. Raw algorithms, Flex policy, and test collateral - -| Responsibility | Owner | -| ----------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- | -| Literal parsing, RGBA/OKLCH conversion, compositing, contrast math, cool/warm interaction transforms | `src/color-lib/` | -| Interactive token membership, deep/inverted classification, semantic background/stroke policy | `src/flex/colors/` | -| The `InteractiveColorOptions` resolver and lazy `InteractiveColor` envelopes | `src/flex/colors/` | -| Default foreground/background pairings, WCAG audits, bulk fixture generation, known conformance cases | `src/test/` | -| Mathematical reference backdrops required by the warm transform | Raw algorithm, passed generic compositing intent; not test pairings or semantic-token lookups | - -Raw functions accept numerical/color inputs, state, scheme, tone, direction, and genuinely required compositing -context; they do not inspect Flex token spelling. The Flex resolver uses those functions automatically and applies -high-contrast suppression and unmappable-rest fallback. Move test-only bulk operations rather than advertising them -as a new production API. - -Move token-aware APIs such as inverse-token classification to Flex exports. Treat changed color-lib signatures and -the removed variant vocabulary as modern API migration work; add a deprecated compatibility wrapper only if the -legacy inventory demonstrates a real obligation. Do not retain semantic policy inside the raw implementation merely -to preserve an undocumented modern signature. - -## 7. Default values and immutable x3 evidence - -### Approved current-source target and verified evidence - -**Confirmed by the owner:** use current x3 color source values. Agentic components are in rapid development, and -modern value changes are approved; do not preserve the older pin merely to avoid them. Refresh to current upstream -main during implementation, record the resulting immutable revision and blob identities, and reconcile differences. -Drift review documents the change; it is not a new approval gate for adopting current values. - -On 2026-10-23, authenticated read-only metadata checks reverified -`x3-design/fluent-design@206e890b645fb450ad7c5df2ff981765349a2b58` as current main, committed 2026-09-11. Its tree includes: - -| Current source | Blob SHA | -| ------------------------------------------------------- | ------------------------------------------ | -| `dev/web/flex-themes/css/semantic.css` | `4c9f3e0a70bdbb8b7183d2db15254d9427d8e6ab` | -| `dev/web/flex-themes/css/interaction-fallback.css` | `c69ff3145f4f9b1228a694a3e7ba8b1a65d2c032` | -| `dev/web/flex-themes/css/warm/semantic.css` | `dfe8416dffb4b215777d0270c3fe40a5d631ee2c` | -| `dev/web/flex-themes/css/warm/interaction-fallback.css` | `6dbe4a963fd197cac7fabf35cf6c801f68aa1f4c` | -| `dev/web/flex-tokens/mappings.json` | `33c7a100a200d52d48f35faae5adf9f6282e462a` | -| `dev/web/flex-tokens/tokens.json` | `49bec466b835c0df87c879f399a29fc60db6b426` | - -The split light/dark semantic and interaction companions also exist for cool and warm at this revision. Include all -required sources in the refreshed pin and compare derived states against their reference values; do not confuse -omitting runtime defaults with omitting source evidence. - -The checked-in runtime pin is still the historical `d334acf5cbad813f2b7cd554da942b09a7ff8f10` until implementation. -Its earlier offline check passed in `offline-snapshot` mode with three matching integrity entries and no drift. -That result is historical local-integrity evidence, not parity with the current target. These metadata checks did not -copy private source bodies, change the runtime pin, or verify every current default value. - -### Access and reference procedure - -Use the token and component references in `https://github.com/x3-design/fluent-design` as needed, at immutable -identities. This internal source requires authenticated access, not an unauthenticated public link probe: - -1. For an internal source, select an existing authorized **Microsoft EMU** GitHub identity using `gh auth switch`. - Verify the repository and exact commit with read-only REST GETs. Do not diagnose a public-identity 404 as missing - upstream evidence. -2. For tokens, resolve current upstream main, refresh the design pin and source identities above, then inspect that - revision's token, semantic, interaction, and warm companions. Resolve source variables and scheme/tone overrides - before comparing values. Recheck main when implementation begins rather than treating today's target as permanent. -3. For components, use `@fluentui-react-native/components/references/contract-sources/flex-x3.md`, the - `flex-authoring` profile, the matching `flex-components:` source, and - `@fluentui-react-native/components/spec-source-lock.json`. Read shared, usage, and relevant platform companions. - Modern source and component changes are approved: refresh affected source locks and contracts through their - workflow where current tokens require it. Do not combine releases accidentally or promote contracts without review. -4. The Node drift tool reads `GITHUB_TOKEN`/`GH_TOKEN`; switching the `gh` account alone does not authenticate that - process. Supply approved command-scoped credentials without printing, persisting, or committing them. Restore the - public GitHub identity before public-repository operations, including on failure. -5. Respect R-REPO-004: source access is not permission to copy or mechanically transform private source bodies or token - tables into this public repository. Confirm permitted data publication before extending snapshots or emitting - derived payloads. Keep private reports/logs local; publish original documentation and permitted provenance only. - -Durable maintenance instructions belong in [Tokens](references/tokens.md); component contracts retain their own -source-adapter workflow rather than acquiring a second copy of it here. - -### Completeness and generation gate - -Build a coverage ledger for **every supported Flex destination**, not just interactive colors. Record source commit, -path, role, scheme/tone, native representation, explicit versus computed state, adaptation reason, and unsupported or -platform-owned cases. Never label a missing role complete because it inherited rest. - -The reviewed generator must resolve source variables and overrides, preserve alpha, normalize units deliberately, and -emit deterministic, provenance-bearing defaults in `src/flex/defaults/`. Emit `[light, dark]` rest colors plus the -required type/role metadata for each tone, omitting each hover/pressed field that the automatic dynamic implementation -reproduces correctly. Keep explicit exceptions only where needed. Compare resolved outputs, not authored-field -presence, when testing completeness. Preserve complete current interaction reference data in permitted test-only -evidence so derivation is checked independently of the generator. Use `flexColor` and tuple helpers to keep authored -definitions concise without forcing helper calls around every generated literal. - -Explicitly resolve these known gaps: - -- Cool and warm palettes need independently verified rest and interaction data. Warm algorithm vectors are not proof - of a complete warm palette. -- The historical interaction fixture had ten cool-table cases using the warm path. Revalidate them against current - sources; retain an explicit state only where current source values cannot be reproduced by the approved dynamic - policy. Do not carry stale exceptions forward automatically or omit real source exceptions. -- Adopt current x3 brand values alongside the rest of the current palette. Record and qualify visual changes; a - separate brand-approval gate is no longer required. -- **Approved:** close non-color gaps across fonts, weights, line heights, spacing, radii, strokes, motion, and shadows. - Extend the modern contract/mapping for missing motion-duration/easing roles and `componentBase800` where current - sources define them; do not leave them deferred merely because the old contract omitted them. -- **Approved:** support the current layered shadows and dark overrides with a modern representation that preserves - all source layers and valid native behavior. Keep legacy `ShadowToken` unchanged and document any lossy legacy - projection or platform-specific adaptation explicitly; do not silently truncate modern shadows. -- The selected x3 semantic evidence does not define native high-contrast/elevated defaults. Preserve platform-owned - behavior and document any base-appearance reuse; do not synthesize purported x3 values. -- Re-evaluate historical dark-pressed contrast failures against current values and keep any remaining failures visible - as audit outcomes, separate from matching the design source. - -Extend pin/drift tooling to all approved source IDs and validate generated value parity independently of -`check:mappings`. Repeated generation must be byte-for-byte stable. Reuse compatible existing codegen work after -reconciliation, but do not substitute platform-package equivalence for the requested x3 evidence. - -## 8. Legacy adapters and consumer migration - -### Conversion guarantees - -Forward conversion preserves legacy-authored rest, hover, pressed, native colors, and existing missing-value fallback -ownership. Replacing the modern token representation must not silently change the forward adapter's fallback values; -if a new modern-only policy is desired, isolate and review it separately. - -Reverse conversion keeps its existing order: complete legacy base, `legacyFallback`, authoritative mapped Flex values, -then legacy appearance metadata. Preserve canonical collision choices, omitted candidates, transforms, complete legacy -values Flex cannot represent, and lazy loading. If the published converter accepts old flat token inputs, retain a -compatibility input normalization path rather than accidentally breaking legacy consumers through a modern type move. - -The YAML remains canonical. Update its destinations and the generator/validator to understand per-token -`.rest/.hover/.pressed` paths, then regenerate both projections. Do not hand-edit JSON projections or weaken validation -to accept unresolved new paths. - -### Migration order and concrete surfaces - -1. Update the design color-style factory internally so existing key-based `colorStyleDef` declarations keep their - interaction precedence. Keep the shared state factory independent of per-color representation. -2. Migrate direct interactive reads in Input and ListboxItem, then remaining component, story, and test reads. - Migrate all scalar color reads to `.rest`, including static roles now using the uniform envelope. Inventory all - direct accesses, not just the old override maps. -3. Migrate Storybook chrome and theme fixtures, including `testing` exports and consumers re-exporting `mockTheme`. - Keep `/testing` as the public spelling even though implementation moves to `src/test/`. -4. Component owners revise affected token references, including Accordion, Button, and Input `spec/tokens.yaml`, - through their contract workflow. An import/path migration does not authorize a component behavior change or - automatic contract promotion. -5. Update [Theming](references/theming.md), [Tokens](references/tokens.md), [Styling](references/styling.md), - [Color library](references/color-lib.md), [Testing](references/testing.md), [Entry points](references/entry-points.md), - [Contributing](references/contributing.md), the package quick start, component styles-and-tokens instructions, - and repository theming basics. - -Representative modern migration: - -```ts -// Before -const rest = tokens.color.backgroundBrandLoud; -const hover = tokens.color.hover.backgroundBrandLoud ?? rest; - -// After -const { backgroundBrandLoud } = tokens.color; -const rest = backgroundBrandLoud.rest; -const hover = backgroundBrandLoud.hover; -``` - -Read only the states a style path needs. Destructuring both hover and pressed eagerly reads both getters; this is -valid when needed, but not evidence of interaction-time laziness. - -Illustrative input authoring, not x3 default values: - -```ts -const brand = flexColor({ - rest: ['#345678', '#abcdef'], - hover: ['#234567', '#bcdef0'], - pressed: ['#123456', '#cdef01'], - type: 'inverted', -}); -``` - -For the normal automatic-derivation case, the author only supplies rest colors and any required classification: - -```ts -const brand = flexColor(['#345678', '#abcdef'], 'inverted'); -``` - -No deriver configuration or separate dynamic-color import is required. The migration guide must also show explicit -state exceptions, tuple selection, atomic replacement, automatic unmappable-rest/high-contrast fallback, recipe -migration, `legacyFallback`, and how legacy Fluent themes/provider usage remains unchanged. Do not remove deprecated -appearance APIs as incidental cleanup. - -## 9. Delivery phases, ownership, and exit criteria - -| Phase | Owner and work | Prerequisite | Exit gate | -| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -| 0. Resolve remaining gates and overlap | Apply owner-approved decisions; reconcile existing default-theme/codegen work, fixed semantics, and source publication permissions | This review draft | Current-source adoption, automatic Flex derivation, native rest fallback, and non-color gap closure are not reopened as approval gates | -| 1. Capture compatibility | Design and compatibility-package owners record public symbol/type fixtures, external-style imports, legacy Fluent runtime/default snapshots, and bundle baselines | Phase 0 | Baselines cover legacy themes/provider entry points, raw contexts, native colors, fallback ownership, and every export condition | -| 2. Mechanical organization | Move owned implementations and platform tests; update entry targets, references, generators' fixed source paths, and bundle positive/negative controls; deduplicate demonstrated helpers | Phase 1 | No behavior or exported legacy-name change; no vacuous import boundary tests | -| 3. Tone and automatic engine | Add compatible tone normalization and cache keys; wire required raw algorithms into Flex only; update import invariants and conformance coverage | Phase 2 | Tone-only transitions, three-field legacy calls, automatic Flex imports, and legacy graph isolation behave as specified | -| 4. Interactive representation | Implement authored/resolved contracts, atomic color replacement, automatic lazy states, recipe semantics, adapters, and regenerated YAML projections; migrate consumers coherently | Phase 3 and fixed semantics where applicable | Existing default values first survive a representation-only migration; no stale states, eager copying, or legacy fallback changes | -| 5. Current x3 defaults and non-color completion | Refresh to current x3, generate rest-first cool/warm defaults and necessary explicit exceptions, extend non-color contracts and layered shadows | Source publication gate and stable Phase 4 representation | Resolved values match current sources; derivable state fields are absent; approved gaps are closed; legacy Fluent themes stay unchanged | -| 6. Release and qualification | Update owning references, consumer guidance and changesets; inspect packed artifacts, bundles, and affected native stories | Phases 2-5 | Modern migration is complete, legacy contract holds, validation and native limitations are explicit | - -Upstream investigation and compatibility capture can proceed independently. Activate current Flex defaults once -their permitted provenance, resolved-value checks, and implementation qualification pass; no historical-Flex visual -preservation or additional modern-default approval is required. Keep mechanical moves separate from value changes -so regressions can be attributed and reviewed. - -## 10. Validation and acceptance - -Use existing declared scripts. Focused test names below select related existing files; add colocated coverage for the -new contracts rather than inventing an unconfigured runner. - -| Scope | Commands | Required evidence | -| ------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| This documentation change | Root `yarn format:check` scoped to edited files; `yarn check-agent-instructions`; configured Markdown link checks; `yarn change:check`; final cache-cleared aggregate for the changed instruction reference | Valid navigation, formatting and an empty changeset for a no-release package change | -| Appearance/runtime iteration | In design: `yarn test appearance flexThemeReference themeReference useThemeState useTheme ThemedRoot` | Tone keys, normalized defaults, boundary precedence, subscriptions, revisions, state identity, fresh style registries | -| Color/adapter iteration | In design: `yarn test colorLib colorStyles validation flexTokenMappings flexTokensFromTheme themeFromFlexTokens objects` | Automatic derivation, explicit-state precedence, unmappable-rest identity, frozen inputs, atomic replacement, conformance and projection policies | -| Types | In design: `yarn build` | Public legacy three-axis calls, readonly tuples, authored recipe types and uniform output envelopes; Jest alone does not check types | -| Mapping/provenance | In design: `yarn check:mappings`; `yarn gen:upstream-drift --offline`; authenticated current-source drift when refreshing the pin | Valid mappings, current resolved default-value coverage, omitted derivable fields, non-color completeness, snapshot integrity and explicit online/offline modes | -| Owning implementation package | In design: `yarn format`, `yarn lint`, `yarn build`, `yarn test`, `yarn check:mappings` | Full package acceptance after focused iteration | -| Migrated consumers | Declared build/lint/test scripts in affected component, Storybook runtime, platform-theme and compatibility packages | No remaining old interactive accesses; state precedence and external-style imports preserved | -| Distribution and graphs | Root `yarn bundle-size`, `yarn check-package-contents`, `yarn check-publishing`, `yarn lage test-links` after moves | Actual retained-module boundaries, positive controls, valid packed export targets and documentation links | -| Final implementation acceptance | Root `yarn clean-lage-cache`, then `yarn lage buildci` | One final cache-cleared aggregate; rerun failed downstream checks after fixes | -| Native qualification | Existing affected Storybook/native test workflows on supported platforms and renderers | Visual states, tone/scheme/contrast/elevation transitions, opaque/system colors and legacy/Flex coexistence | - -Add explicit zero-call/one-call derivation assertions: provider mount and rest access derive nothing; hover derives only -hover; repeated hover access derives once; an explicit state never invokes the engine. Include regression tests proving -that copying/merging a parent token does not read its getters. A normal `FlexThemeReference` must derive omitted states -without configuration. For unmappable values, both omitted states must return the identical rest value, while -explicit states still win; an unexpected algorithm failure must not be swallowed as that fallback. Distinguish raw -API diagnostics, approved unmappable-rest fallback, high-contrast suppression, and invalid-authoring errors. - -Test every default state against the current source after native normalization. Independently assert that each -derivable hover/pressed field is absent from runtime definitions, with any retained explicit exception documented. -Cover cool/warm, light/dark, inversion, native values, and the approved motion, spacing, and layered/dark shadow gaps. - -Import guards must forbid `/fluent/` compatibility payloads and `/test/` from the modern root, while allowing the -lightweight forward adapter and required raw color algorithms. Flex-state scenarios must positively require automatic -interaction modules; legacy-only scenarios must protect their existing graph and avoid acquiring the engine through -shared utilities. Reverse-projection and direct color-lib scenarios positively require their expected modules. -Test `flexColor` as a pure normalizer, not as a promise that the Flex runtime is engine-free. Review measured bundle -deltas before updating baselines. Bundle measurement is not included in `buildci`; add lightweight import-direction -assertions to the package test suite so ordinary CI also protects the dependency rules. - -This change does not implement or natively qualify the refactor. R-VALID-003 exempts plans; the original navigation -edit also changed an instruction reference and therefore required a cache-cleared aggregate. Subsequent plan-only -amendments require documentation checks, not a repeat product build or native run. Later implementation requires the -focused and native evidence above, not merely the documentation checks. Record checks as passed, failed, skipped, -not run, or unsupported; JavaScript tests and bundles are not native qualification. - -## 11. Confirmed decisions and remaining implementation gates - -The owner's 2026-10-23 follow-up settles these decisions: - -| Confirmed decision | Implementation requirement | -| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | -| Legacy consumers use legacy Fluent themes and the old provider | Preserve that path; current Flex defaults need no legacy implicit-root visual-compatibility gate | -| Dynamic interaction APIs are automatic for Flex | Wire required algorithms into the Flex runtime; remove deriver injection and missing-engine configuration | -| Default interactions should be derived wherever possible | Emit `[light, dark]` rest colors and classification, omitting each reproducible hover/pressed default independently | -| Platform/native/unmappable rest colors are valid | Omitted states return the rest value directly, preserving identity and requiring no explicit override or warning | -| Current x3 values are preferred over old modern values | Refresh current upstream identities and adopt the values, including brand changes; qualify rather than block the approved changes | -| Non-color gaps are approved | Implement missing current motion/spacing roles and layered/dark shadows while preserving legacy types | - -Only these implementation gates remain: - -| Gate | Required evidence | -| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | -| Fixed derivation for mappable literals | Obtain an authoritative scheme-independent rule; until then require explicit fixed states | -| Source publication | Confirm permitted publication before adding private-source snapshots or derived payloads; current-source adoption itself is approved | -| Native non-color adaptations | Define and qualify renderer/unit/shadow behavior and document lossy legacy projections; this is implementation detail, not another scope-approval gate | - -## 12. Reciprocal-review provenance and reconciliation - -Two independent investigations used **GPT-6 Astra** (`gpt-6-astra`) and **Claude Opus 5.5** -(`claude-opus-5.5`), each configured with `reasoning_effort: max` and `context_tier: long_context`. Each model then -reviewed the other's complete report in its original thread. Full reports and critiques are private session artifacts, -not copied source material or published package content. - -The complete independent reports are `astra-independent-report.txt` and `opus-independent-report.txt`; their -reciprocal critiques are `astra-cross-review.txt` and `opus-cross-review.txt` in the private session artifacts. -The owner subsequently resolved several product decisions in section 11; that follow-up takes precedence over the -initial model recommendations. No new reciprocal-review round is claimed for these owner-directed amendments. -Reconciliation and the subsequent decisions are recorded explicitly: - -| Reviewed disagreement | Resolution and rationale | -| ---------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | -| Uniform versus interactive-only envelopes | Uniform outputs match the requested consumption model and simplify projection paths; eligibility remains separate so static roles never derive | -| Resolved-parent versus authored-parent recipes | Merge authored descriptions before resolving; avoid eager getters and appearance-bound output reuse | -| Deriver injection and missing-engine errors | Superseded by owner decision: Flex always includes dynamic derivation; unmappable colors intentionally return rest | -| Fixed equals standard-light mathematics | Rejected as unsupported; explicit fixed states work while computed semantics remain gated | -| Touched-path legacy projection | Rejected by both reviewers; authoritative projection remains, and the owner confirmed that legacy users stay on legacy themes/provider | -| Required tone on old exported appearance types | Rejected as a legacy type break; retain optional compatibility fields and strict normalized modern outputs | -| Helper default versus token-name inference | Preserve the requested standard default; generated defaults/adapters supply reviewed inverted metadata explicitly | -| Source/table mismatch totals | Do not adopt unverified zero-match claims; concrete counterexamples were found during reciprocal review | -| Shape change before consumer migration | Rejected as an unbuildable intermediate phase; migrate the representation and consumers atomically, with value changes separate | -| Old pin and non-color scope gates | Superseded by owner decision: adopt current x3 values and close non-color gaps, recording immutable provenance and native adaptations | - -The remaining fixed-derivation and publication gates are explicit. Primary implementation evidence and the owner's -confirmed decisions take precedence over either model's speculation. From ed8dbb8b5963dd64c93875de82d8552e7cc10589 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 23 Oct 2026 20:46:05 -0700 Subject: [PATCH 08/18] design: changesets, references, and bundle baselines (refactor phase 6) Completes phase 6; the previous commit only removed the completed plan. Add changesets for design (minor), components (minor), and storybook-desktop-runtime (patch). Update the repository theming basics for the x3 defaults and interactive color envelope, document the lossy shadow and motion reverse projection, and move the plan's open gates (fixed derivation, native layered shadows and motion) into remaining-work.md. Refresh the bundle-size baselines. Against the Phase 1 measurement, Flex-state scenarios grow about 28-29 KB raw / 7.1-7.3 KB gzip, legacy-theme-from-flex +7.9 KB / +4.1 KB, and color-lib -62 B. The committed catalog baseline was already stale before the refactor (155 KB committed vs 205 KB measured). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5030bce5-d7f7-4fb1-93de-68599b79269f --- .changeset/components-x3-flex-defaults.md | 7 + .changeset/design-x3-flex-defaults.md | 30 +++ .changeset/storybook-runtime-flex-colors.md | 5 + apps/bundle-size/baseline.json | 212 ++++++++++-------- docs/pages/Theming/Basics.md | 7 +- .../design/references/remaining-work.md | 22 +- packages/agentic/design/references/theming.md | 1 + 7 files changed, 188 insertions(+), 96 deletions(-) create mode 100644 .changeset/components-x3-flex-defaults.md create mode 100644 .changeset/design-x3-flex-defaults.md create mode 100644 .changeset/storybook-runtime-flex-colors.md diff --git a/.changeset/components-x3-flex-defaults.md b/.changeset/components-x3-flex-defaults.md new file mode 100644 index 0000000000..472558822d --- /dev/null +++ b/.changeset/components-x3-flex-defaults.md @@ -0,0 +1,7 @@ +--- +'@fluentui-react-native/components': minor +--- + +Read Flex colors through the design package's interactive color envelope and adopt the current x3 default tokens. +Components rendered with the default theme change appearance, including an achromatic brand, translucent neutral +backgrounds, and larger corner radii. Component token contracts reference the per-state color paths. diff --git a/.changeset/design-x3-flex-defaults.md b/.changeset/design-x3-flex-defaults.md new file mode 100644 index 0000000000..e6d258c069 --- /dev/null +++ b/.changeset/design-x3-flex-defaults.md @@ -0,0 +1,30 @@ +--- +'@fluentui-react-native/design': minor +--- + +Rework Flex tokens around the current x3 defaults. Legacy `ThemeReference` themes, `ThemeProvider`, `useTheme`, the +legacy Fluent defaults, and Flex tokens projected from legacy themes keep their values. + +Breaking changes for Flex consumers and theme authors: + +- Every Flex semantic color is a resolved `InteractiveColor` with `rest`, `hover`, and `pressed`. Read + `tokens.color.x.rest` instead of `tokens.color.x`, and `.hover` or `.pressed` instead of the removed `color.hover` + and `color.pressed` maps. Omitted interactive states derive lazily from rest with no configuration. +- Author a color as a value, a `[light, dark]` tuple, or `flexColor` options with explicit states and a `standard`, + `inverted`, or `fixed` interaction type. Each color override replaces the previous color atomically. Recipes receive + the authored description; `selectColorEntry` reads an entry for an appearance. +- Appearances accept an optional `colorTone` (`cool` or `warm`) that selects the default tokens and interaction + algorithm. +- The default tokens follow x3-design/fluent-design@206e890b for both tones, including an achromatic brand, + translucent neutral backgrounds, and larger corner radii. Tests should read defaults from `defaultFlexTokens` in the + `testing` entry point. +- Shadows are arrays of `{ x, y, blur, color }` layers and may vary by color scheme; author a former `{ ambient, key }` + shadow as `[ambient, key]`, and use `selectShadowEntry` to read an authored entry. Motion tokens and + `spacing.componentBase800` are new. +- The `color-lib` interaction functions no longer take a token; their `variant` option is replaced by `colorTone`, + `direction`, and `compositing`. `isInverseInteractionToken` moves from `color-lib` to the package root, alongside the + new `INTERACTIVE_COLOR_TOKENS` and `isInteractiveColorToken`. + +Root `useThemeState` consumers now bundle the interaction algorithm and generated defaults, about 28 KB raw and 7 KB +gzip in the measured scenarios. Package sources move under `src/flex`, `src/fluent`, `src/types`, and `src/test`; export +keys and conditions are unchanged. diff --git a/.changeset/storybook-runtime-flex-colors.md b/.changeset/storybook-runtime-flex-colors.md new file mode 100644 index 0000000000..3025b043f1 --- /dev/null +++ b/.changeset/storybook-runtime-flex-colors.md @@ -0,0 +1,5 @@ +--- +'@fluentui-react-native/storybook-desktop-runtime': patch +--- + +Read Storybook chrome colors through the design package's interactive color envelope. diff --git a/apps/bundle-size/baseline.json b/apps/bundle-size/baseline.json index 8bdda76f00..18bd30fed7 100644 --- a/apps/bundle-size/baseline.json +++ b/apps/bundle-size/baseline.json @@ -4,37 +4,37 @@ { "platform": "macos", "scenario": "components-button", - "rawBytes": 50630, - "gzipBytes": 13548, - "moduleCount": 64, - "metafileInputCount": 230, + "rawBytes": 78672, + "gzipBytes": 20703, + "moduleCount": 77, + "metafileInputCount": 243, "workspaceModules": { "@fluentui-react-native/components": 16, - "@fluentui-react-native/design": 21, + "@fluentui-react-native/design": 34, "@fluentui-react-native/framework-base": 26 }, "workspaceBytes": { - "@fluentui-react-native/components": 9308, - "@fluentui-react-native/design": 28720, - "@fluentui-react-native/framework-base": 12566 + "@fluentui-react-native/components": 9328, + "@fluentui-react-native/design": 56722, + "@fluentui-react-native/framework-base": 12586 } }, { "platform": "macos", "scenario": "components-catalog", - "rawBytes": 205485, - "gzipBytes": 55777, - "moduleCount": 214, - "metafileInputCount": 230, + "rawBytes": 233943, + "gzipBytes": 62944, + "moduleCount": 227, + "metafileInputCount": 243, "workspaceModules": { "@fluentui-react-native/components": 151, - "@fluentui-react-native/design": 23, + "@fluentui-react-native/design": 36, "@fluentui-react-native/framework-base": 27, "@fluentui-react-native/native-core": 12 }, "workspaceBytes": { - "@fluentui-react-native/components": 150941, - "@fluentui-react-native/design": 29882, + "@fluentui-react-native/components": 151331, + "@fluentui-react-native/design": 57950, "@fluentui-react-native/framework-base": 15305, "@fluentui-react-native/native-core": 9228 } @@ -42,115 +42,131 @@ { "platform": "macos", "scenario": "design-theme-state", - "rawBytes": 30151, - "gzipBytes": 6434, - "moduleCount": 34, - "metafileInputCount": 60, + "rawBytes": 59088, + "gzipBytes": 13722, + "moduleCount": 47, + "metafileInputCount": 73, "workspaceModules": { - "@fluentui-react-native/design": 15, + "@fluentui-react-native/design": 28, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 28151, - "@fluentui-react-native/framework-base": 1960 + "@fluentui-react-native/design": 57086, + "@fluentui-react-native/framework-base": 1961 } }, { "platform": "macos", "scenario": "design-themed-root", - "rawBytes": 32116, - "gzipBytes": 7119, - "moduleCount": 38, - "metafileInputCount": 60, + "rawBytes": 61064, + "gzipBytes": 14421, + "moduleCount": 51, + "metafileInputCount": 73, "workspaceModules": { - "@fluentui-react-native/design": 19, + "@fluentui-react-native/design": 32, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 30116, - "@fluentui-react-native/framework-base": 1960 + "@fluentui-react-native/design": 59059, + "@fluentui-react-native/framework-base": 1964 } }, { "platform": "macos", "scenario": "design-color-lib", - "rawBytes": 6328, - "gzipBytes": 2794, + "rawBytes": 6266, + "gzipBytes": 2757, "moduleCount": 6, "metafileInputCount": 7, "workspaceModules": { "@fluentui-react-native/design": 5 }, "workspaceBytes": { - "@fluentui-react-native/design": 6289 + "@fluentui-react-native/design": 6227 } }, { "platform": "macos", "scenario": "design-theme-state-legacy-source", - "rawBytes": 31807, - "gzipBytes": 6762, - "moduleCount": 35, - "metafileInputCount": 63, + "rawBytes": 59836, + "gzipBytes": 13849, + "moduleCount": 48, + "metafileInputCount": 76, "workspaceModules": { - "@fluentui-react-native/design": 16, + "@fluentui-react-native/design": 29, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 29807, - "@fluentui-react-native/framework-base": 1960 + "@fluentui-react-native/design": 57834, + "@fluentui-react-native/framework-base": 1961 + } + }, + { + "platform": "macos", + "scenario": "design-legacy-theme", + "rawBytes": 79069, + "gzipBytes": 17346, + "moduleCount": 54, + "metafileInputCount": 93, + "workspaceModules": { + "@fluentui-react-native/design": 24, + "@fluentui-react-native/framework-base": 21 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 39865, + "@fluentui-react-native/framework-base": 2517 } }, { "platform": "macos", "scenario": "design-legacy-theme-from-flex", - "rawBytes": 97766, - "gzipBytes": 19873, - "moduleCount": 58, - "metafileInputCount": 84, + "rawBytes": 105632, + "gzipBytes": 23983, + "moduleCount": 67, + "metafileInputCount": 93, "workspaceModules": { - "@fluentui-react-native/design": 28, + "@fluentui-react-native/design": 37, "@fluentui-react-native/framework-base": 21 }, "workspaceBytes": { - "@fluentui-react-native/design": 58553, + "@fluentui-react-native/design": 66419, "@fluentui-react-native/framework-base": 2526 } }, { "platform": "windows", "scenario": "components-button", - "rawBytes": 50554, - "gzipBytes": 13523, - "moduleCount": 65, - "metafileInputCount": 231, + "rawBytes": 78599, + "gzipBytes": 20659, + "moduleCount": 78, + "metafileInputCount": 244, "workspaceModules": { "@fluentui-react-native/components": 16, - "@fluentui-react-native/design": 22, + "@fluentui-react-native/design": 35, "@fluentui-react-native/framework-base": 26 }, "workspaceBytes": { - "@fluentui-react-native/components": 9308, - "@fluentui-react-native/design": 28644, - "@fluentui-react-native/framework-base": 12566 + "@fluentui-react-native/components": 9328, + "@fluentui-react-native/design": 56649, + "@fluentui-react-native/framework-base": 12586 } }, { "platform": "windows", "scenario": "components-catalog", - "rawBytes": 205409, - "gzipBytes": 55767, - "moduleCount": 215, - "metafileInputCount": 231, + "rawBytes": 233867, + "gzipBytes": 62908, + "moduleCount": 228, + "metafileInputCount": 244, "workspaceModules": { "@fluentui-react-native/components": 151, - "@fluentui-react-native/design": 24, + "@fluentui-react-native/design": 37, "@fluentui-react-native/framework-base": 27, "@fluentui-react-native/native-core": 12 }, "workspaceBytes": { - "@fluentui-react-native/components": 150941, - "@fluentui-react-native/design": 29806, + "@fluentui-react-native/components": 151331, + "@fluentui-react-native/design": 57874, "@fluentui-react-native/framework-base": 15305, "@fluentui-react-native/native-core": 9228 } @@ -158,78 +174,94 @@ { "platform": "windows", "scenario": "design-theme-state", - "rawBytes": 30075, - "gzipBytes": 6404, - "moduleCount": 35, - "metafileInputCount": 61, + "rawBytes": 59012, + "gzipBytes": 13679, + "moduleCount": 48, + "metafileInputCount": 74, "workspaceModules": { - "@fluentui-react-native/design": 16, + "@fluentui-react-native/design": 29, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 28075, - "@fluentui-react-native/framework-base": 1960 + "@fluentui-react-native/design": 57010, + "@fluentui-react-native/framework-base": 1961 } }, { "platform": "windows", "scenario": "design-themed-root", - "rawBytes": 32040, - "gzipBytes": 7084, - "moduleCount": 39, - "metafileInputCount": 61, + "rawBytes": 60988, + "gzipBytes": 14386, + "moduleCount": 52, + "metafileInputCount": 74, "workspaceModules": { - "@fluentui-react-native/design": 20, + "@fluentui-react-native/design": 33, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 30039, - "@fluentui-react-native/framework-base": 1960 + "@fluentui-react-native/design": 58983, + "@fluentui-react-native/framework-base": 1964 } }, { "platform": "windows", "scenario": "design-color-lib", - "rawBytes": 6328, - "gzipBytes": 2794, + "rawBytes": 6266, + "gzipBytes": 2757, "moduleCount": 6, "metafileInputCount": 7, "workspaceModules": { "@fluentui-react-native/design": 5 }, "workspaceBytes": { - "@fluentui-react-native/design": 6289 + "@fluentui-react-native/design": 6227 } }, { "platform": "windows", "scenario": "design-theme-state-legacy-source", - "rawBytes": 31731, - "gzipBytes": 6728, - "moduleCount": 36, - "metafileInputCount": 64, + "rawBytes": 59760, + "gzipBytes": 13806, + "moduleCount": 49, + "metafileInputCount": 77, "workspaceModules": { - "@fluentui-react-native/design": 17, + "@fluentui-react-native/design": 30, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 29731, - "@fluentui-react-native/framework-base": 1960 + "@fluentui-react-native/design": 57758, + "@fluentui-react-native/framework-base": 1961 + } + }, + { + "platform": "windows", + "scenario": "design-legacy-theme", + "rawBytes": 78948, + "gzipBytes": 17286, + "moduleCount": 54, + "metafileInputCount": 94, + "workspaceModules": { + "@fluentui-react-native/design": 24, + "@fluentui-react-native/framework-base": 21 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 39745, + "@fluentui-react-native/framework-base": 2517 } }, { "platform": "windows", "scenario": "design-legacy-theme-from-flex", - "rawBytes": 97633, - "gzipBytes": 19793, - "moduleCount": 59, - "metafileInputCount": 85, + "rawBytes": 105499, + "gzipBytes": 23901, + "moduleCount": 67, + "metafileInputCount": 94, "workspaceModules": { - "@fluentui-react-native/design": 29, + "@fluentui-react-native/design": 37, "@fluentui-react-native/framework-base": 21 }, "workspaceBytes": { - "@fluentui-react-native/design": 58420, + "@fluentui-react-native/design": 66286, "@fluentui-react-native/framework-base": 2526 } } diff --git a/docs/pages/Theming/Basics.md b/docs/pages/Theming/Basics.md index 00bd645f28..5379fbad52 100644 --- a/docs/pages/Theming/Basics.md +++ b/docs/pages/Theming/Basics.md @@ -46,8 +46,11 @@ export const App = () => ( An omitted `theme` inherits the nearest theme boundary, including an existing `ThemeProvider`. Without a boundary it uses a default `FlexThemeReference`. -That default supplies the existing baseline Flex tokens; use an appearance-aware -theme recipe when colors should vary with the resolved appearance. +That default supplies the x3 Flex tokens for the resolved light or dark color +scheme and `colorTone`; use an appearance-aware theme recipe for high-contrast or +elevated values. Read each Flex color through its `rest`, `hover`, or `pressed` +state, as described in the design package's +[Flex colors reference](../../../packages/agentic/design/references/flex-colors.md). Nested roots can override individual `appearance` fields, `appearanceSource`, or `fallbackAppearance` while retaining the inherited source and other options. An explicit `theme` starts a new theme/appearance configuration, using that diff --git a/packages/agentic/design/references/remaining-work.md b/packages/agentic/design/references/remaining-work.md index e624a23c64..92a096e671 100644 --- a/packages/agentic/design/references/remaining-work.md +++ b/packages/agentic/design/references/remaining-work.md @@ -44,10 +44,24 @@ behavior is documented in `theming.md`, `tokens.md`, and `entry-points.md`. - **Done when:** x3 publishes, or the owner approves, high-contrast and elevated values, the defaults generator emits them, and `FlexThemeReference` selects them by the resolved appearance without changing its laziness or identity guarantees. -- **Review draft:** repository-only `packages/agentic/design/refactoring.md` coordinates package reorganization, - tone-aware interactive colors, verified x3 defaults, and the legacy compatibility gates. It is an explicitly - requested review artifact, not a second open-work index; remove the draft and this pointer when its durable contract - has moved into the owning references. + +## Fixed interactive color derivation + +- **Outcome:** an omitted state of a `fixed` interactive color with a mappable rest derives from an authoritative, + scheme-independent rule. +- **Current state:** the pinned x3 sources define no such rule, so resolving that state throws until the author + supplies `hover` and `pressed` (see `flex-colors.md`). No default color uses the `fixed` type. +- **Done when:** x3 publishes, or the owner approves, the rule, the interaction policy implements it with conformance + fixtures, and `fixed` colors no longer require explicit states. + +## Native layered shadows and motion + +- **Outcome:** components render Flex layered shadows and motion tokens with qualified native behavior. +- **Current state:** `tokens.shadow` and `tokens.motion` carry the pinned x3 values (see `tokens.md`), but no agentic + component reads them, and no native story qualifies how each platform and renderer draws every shadow layer or + applies the durations and easing curves. +- **Done when:** the first consuming component defines that behavior for each supported platform and renderer, and + native stories qualify it in light and dark appearances. ## Flex authoring migration guide diff --git a/packages/agentic/design/references/theming.md b/packages/agentic/design/references/theming.md index f8fa97081c..c566708ecd 100644 --- a/packages/agentic/design/references/theming.md +++ b/packages/agentic/design/references/theming.md @@ -139,4 +139,5 @@ compatibility projection. `entry-points.md` lists every subpath. 4. `host.appearance` metadata derived from the resolved appearance. The reverse projection is intentionally lossy; `tokens.md` describes how the mapping chooses one canonical Flex value per +legacy path. A layered shadow keeps only its first and last layers as `ambient` and `key`, and motion tokens have no legacy path. The `apps/bundle-size` `design-*` scenarios guard this module boundary. From 9d13cf70fd7281435542e104914a60002497394a Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Mon, 26 Oct 2026 18:25:25 -0700 Subject: [PATCH 09/18] update theme tester component in storybook with updated instructions --- .../storybook-runtime-theme-selector.md | 5 + apps/bundle-size/baseline.json | 68 ++--- .../agentic/design/references/entry-points.md | 9 +- .../agentic/design/references/flex-colors.md | 43 +-- .../design/references/remaining-work.md | 3 - .../src/flex/colors/interactionPolicy.test.ts | 8 +- .../src/flex/colors/interactionPolicy.ts | 10 +- .../fluent/compat/themeFromFlexTokens.test.ts | 11 +- .../src/fluent/compat/themeFromFlexTokens.ts | 13 +- .../references/runtime-contract.md | 19 ++ .../src/StorybookTheme.test.tsx | 173 ++++++++++-- .../src/StorybookTheme.tsx | 256 +++++++++++++++--- 12 files changed, 476 insertions(+), 142 deletions(-) create mode 100644 .changeset/storybook-runtime-theme-selector.md diff --git a/.changeset/storybook-runtime-theme-selector.md b/.changeset/storybook-runtime-theme-selector.md new file mode 100644 index 0000000000..638ad9aec4 --- /dev/null +++ b/.changeset/storybook-runtime-theme-selector.md @@ -0,0 +1,5 @@ +--- +'@fluentui-react-native/storybook-desktop-runtime': patch +--- + +Replace the fixed Storybook theme buttons with Theme (Flex or Fluent), Scheme (light, dark, or system), Contrast, and Tone dropdowns. The toolbar now defaults to Flex light, standard contrast, and cool tone, independent of the host appearance. diff --git a/apps/bundle-size/baseline.json b/apps/bundle-size/baseline.json index 18bd30fed7..6f2e660d93 100644 --- a/apps/bundle-size/baseline.json +++ b/apps/bundle-size/baseline.json @@ -4,8 +4,8 @@ { "platform": "macos", "scenario": "components-button", - "rawBytes": 78672, - "gzipBytes": 20703, + "rawBytes": 78670, + "gzipBytes": 20702, "moduleCount": 77, "metafileInputCount": 243, "workspaceModules": { @@ -15,15 +15,15 @@ }, "workspaceBytes": { "@fluentui-react-native/components": 9328, - "@fluentui-react-native/design": 56722, + "@fluentui-react-native/design": 56720, "@fluentui-react-native/framework-base": 12586 } }, { "platform": "macos", "scenario": "components-catalog", - "rawBytes": 233943, - "gzipBytes": 62944, + "rawBytes": 233941, + "gzipBytes": 62943, "moduleCount": 227, "metafileInputCount": 243, "workspaceModules": { @@ -34,7 +34,7 @@ }, "workspaceBytes": { "@fluentui-react-native/components": 151331, - "@fluentui-react-native/design": 57950, + "@fluentui-react-native/design": 57948, "@fluentui-react-native/framework-base": 15305, "@fluentui-react-native/native-core": 9228 } @@ -42,8 +42,8 @@ { "platform": "macos", "scenario": "design-theme-state", - "rawBytes": 59088, - "gzipBytes": 13722, + "rawBytes": 59086, + "gzipBytes": 13721, "moduleCount": 47, "metafileInputCount": 73, "workspaceModules": { @@ -51,15 +51,15 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 57086, + "@fluentui-react-native/design": 57084, "@fluentui-react-native/framework-base": 1961 } }, { "platform": "macos", "scenario": "design-themed-root", - "rawBytes": 61064, - "gzipBytes": 14421, + "rawBytes": 61062, + "gzipBytes": 14420, "moduleCount": 51, "metafileInputCount": 73, "workspaceModules": { @@ -67,7 +67,7 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 59059, + "@fluentui-react-native/design": 59057, "@fluentui-react-native/framework-base": 1964 } }, @@ -88,7 +88,7 @@ { "platform": "macos", "scenario": "design-theme-state-legacy-source", - "rawBytes": 59836, + "rawBytes": 59834, "gzipBytes": 13849, "moduleCount": 48, "metafileInputCount": 76, @@ -97,7 +97,7 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 57834, + "@fluentui-react-native/design": 57832, "@fluentui-react-native/framework-base": 1961 } }, @@ -120,8 +120,8 @@ { "platform": "macos", "scenario": "design-legacy-theme-from-flex", - "rawBytes": 105632, - "gzipBytes": 23983, + "rawBytes": 105630, + "gzipBytes": 23982, "moduleCount": 67, "metafileInputCount": 93, "workspaceModules": { @@ -129,15 +129,15 @@ "@fluentui-react-native/framework-base": 21 }, "workspaceBytes": { - "@fluentui-react-native/design": 66419, + "@fluentui-react-native/design": 66417, "@fluentui-react-native/framework-base": 2526 } }, { "platform": "windows", "scenario": "components-button", - "rawBytes": 78599, - "gzipBytes": 20659, + "rawBytes": 78597, + "gzipBytes": 20658, "moduleCount": 78, "metafileInputCount": 244, "workspaceModules": { @@ -147,15 +147,15 @@ }, "workspaceBytes": { "@fluentui-react-native/components": 9328, - "@fluentui-react-native/design": 56649, + "@fluentui-react-native/design": 56647, "@fluentui-react-native/framework-base": 12586 } }, { "platform": "windows", "scenario": "components-catalog", - "rawBytes": 233867, - "gzipBytes": 62908, + "rawBytes": 233865, + "gzipBytes": 62906, "moduleCount": 228, "metafileInputCount": 244, "workspaceModules": { @@ -166,7 +166,7 @@ }, "workspaceBytes": { "@fluentui-react-native/components": 151331, - "@fluentui-react-native/design": 57874, + "@fluentui-react-native/design": 57872, "@fluentui-react-native/framework-base": 15305, "@fluentui-react-native/native-core": 9228 } @@ -174,8 +174,8 @@ { "platform": "windows", "scenario": "design-theme-state", - "rawBytes": 59012, - "gzipBytes": 13679, + "rawBytes": 59010, + "gzipBytes": 13677, "moduleCount": 48, "metafileInputCount": 74, "workspaceModules": { @@ -183,15 +183,15 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 57010, + "@fluentui-react-native/design": 57008, "@fluentui-react-native/framework-base": 1961 } }, { "platform": "windows", "scenario": "design-themed-root", - "rawBytes": 60988, - "gzipBytes": 14386, + "rawBytes": 60986, + "gzipBytes": 14385, "moduleCount": 52, "metafileInputCount": 74, "workspaceModules": { @@ -199,7 +199,7 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 58983, + "@fluentui-react-native/design": 58981, "@fluentui-react-native/framework-base": 1964 } }, @@ -220,8 +220,8 @@ { "platform": "windows", "scenario": "design-theme-state-legacy-source", - "rawBytes": 59760, - "gzipBytes": 13806, + "rawBytes": 59758, + "gzipBytes": 13805, "moduleCount": 49, "metafileInputCount": 77, "workspaceModules": { @@ -229,7 +229,7 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 57758, + "@fluentui-react-native/design": 57756, "@fluentui-react-native/framework-base": 1961 } }, @@ -252,7 +252,7 @@ { "platform": "windows", "scenario": "design-legacy-theme-from-flex", - "rawBytes": 105499, + "rawBytes": 105497, "gzipBytes": 23901, "moduleCount": 67, "metafileInputCount": 94, @@ -261,7 +261,7 @@ "@fluentui-react-native/framework-base": 21 }, "workspaceBytes": { - "@fluentui-react-native/design": 66286, + "@fluentui-react-native/design": 66284, "@fluentui-react-native/framework-base": 2526 } } diff --git a/packages/agentic/design/references/entry-points.md b/packages/agentic/design/references/entry-points.md index ad9061dc22..a74bf7827f 100644 --- a/packages/agentic/design/references/entry-points.md +++ b/packages/agentic/design/references/entry-points.md @@ -27,10 +27,11 @@ public symbols by name from each entry point; do not add barrel re-exports. The `apps/bundle-size` `design-*` scenarios guard these boundaries. Input patterns check the import graph and output patterns check the modules a tree-shaken bundle retains. The modern root and legacy-source scenarios forbid the -compatibility and legacy-token modules; the modern root scenarios forbid `color-lib/compositing` and require the -retained Flex interaction policy; the legacy-source and legacy theme scenarios forbid any retained color-library or Flex -interaction module, although the legacy-source scenario retains the engine-free color envelope that `useThemeState` -returns; and the color-library and legacy-projection scenarios require their expected modules. Every scenario +compatibility and legacy-token modules and `color-lib/compositing`. The modern root scenarios and the legacy-source +scenario, which pairs a legacy `ThemeReference` with `useThemeState`, require the retained Flex interaction policy and +`color-lib/interaction`; the legacy-source scenario also forbids a retained `FlexThemeReference`. Only the legacy theme +scenario forbids any retained `color-lib/` or `flex/` module. The color-library and legacy-projection scenarios require +their expected modules. Every scenario also requires a module it is expected to load, so a moved file cannot make a forbidden pattern pass vacuously. The package specifiers above are the supported import surface. Source and build paths such as `src/fluent/...` or diff --git a/packages/agentic/design/references/flex-colors.md b/packages/agentic/design/references/flex-colors.md index d9e74ec9e1..aa7b16e615 100644 --- a/packages/agentic/design/references/flex-colors.md +++ b/packages/agentic/design/references/flex-colors.md @@ -52,11 +52,11 @@ const brand = flexColor(['#345678', '#abcdef'], 'inverted'); const accent = flexColor({ rest: ['#345678', '#abcdef'], pressed: ['#123456', '#cdef01'], type: 'inverted' }); ``` -| Type | Omitted interactive states | -| ---------- | ---------------------------------------------------------------------------------------- | -| `standard` | Derived in the scheme's standard lightness direction; the type of a plain value | -| `inverted` | Derived in the opposite direction, as the default heavy, loud, and on-loud roles do | -| `fixed` | Not derived; an interactive token with a mappable rest must author `hover` and `pressed` | +| Type | Omitted interactive states | +| ---------- | --------------------------------------------------------------------------------------------------------------- | +| `standard` | Derived in the scheme's standard lightness direction; the type of a plain value | +| `inverted` | Derived in the opposite direction, as the default heavy, loud, and on-loud roles do | +| `fixed` | Not derived; outside high contrast, an interactive token with a mappable rest must author `hover` and `pressed` | ## Resolution @@ -65,9 +65,9 @@ For each color and resolved appearance: 1. A tuple selects light or dark. 2. An explicit state wins. 3. An omitted state of a token outside `INTERACTIVE_COLOR_TOKENS` (see `color-lib.md`) is rest. -4. A `fixed` interactive color throws while resolving if a state is omitted and JavaScript can map rest; with a rest it +4. In high contrast, an omitted state is rest, including for a `fixed` color. +5. A `fixed` interactive color throws while resolving if a state is omitted and JavaScript can map rest; with a rest it cannot map, the omitted state is rest. -5. In high contrast, an omitted state is rest. 6. Otherwise the omitted state is derived from rest on first read with the `color-lib` interaction algorithm, using the color's type as the direction, the appearance's `colorTone`, and the token's compositing mode. No import, provider setting, or registration is required. When JavaScript cannot map rest, such as a `PlatformColor`, the state is the @@ -89,13 +89,18 @@ Use `flexColor(value, 'inverted')` when overriding a heavy, loud, or on-loud rol feedback. A `base` function receives the resolved appearance. A recipe function receives the accumulated authored description and -the resolved appearance, and returns overrides. Description colors are authored entries, not resolved envelopes: +the resolved appearance, and returns overrides. Description colors are authored entries, not resolved envelopes. +Reusing a whole description keeps its type and explicit states; a value read with `selectColorEntry` is a plain color, +so restate the type when it overrides an inverted role: ```ts -import { FlexThemeReference, selectColorEntry } from '@fluentui-react-native/design'; +import { FlexThemeReference, flexColor, selectColorEntry } from '@fluentui-react-native/design'; const theme = new FlexThemeReference({}, (description, appearance) => ({ - color: { strokeBrandLoud: selectColorEntry(description.color.backgroundBrandLoud.rest, appearance) }, + color: { + strokeBrandLoud: description.color.backgroundBrandLoud, + backgroundBrandHeavy: flexColor(selectColorEntry(description.color.foregroundBrandPrimary.rest, appearance), 'inverted'), + }, })); ``` @@ -104,15 +109,15 @@ options, and the removed `color.hover` and `color.pressed` maps. ## Migrating from flat colors -| Before | After | -| ---------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | -| `tokens.color.backgroundBrandLoud` | `tokens.color.backgroundBrandLoud.rest` | -| `tokens.color.hover.backgroundBrandLoud ?? tokens.color.backgroundBrandLoud` | `tokens.color.backgroundBrandLoud.hover` | -| `{ color: { x: rest, hover: { x: hover } } }` | `{ color: { x: { rest, hover } } }` | -| `{ color: { backgroundBrandLoud: '#…' } }` (implicitly inverted) | `{ color: { backgroundBrandLoud: flexColor('#…', 'inverted') } }` | -| A recipe branching on `appearance.colorScheme` for a color | A `[light, dark]` tuple | -| `(parent, appearance) => …parent.color.x…` | `(description, appearance) => …selectColorEntry(description.color.x.rest, appearance)…` | -| `InteractiveColorOverrides` | `InteractiveColorOptions` or `PartialSemanticColors` | +| Before | After | +| ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- | +| `tokens.color.backgroundBrandLoud` | `tokens.color.backgroundBrandLoud.rest` | +| `tokens.color.hover.backgroundBrandLoud ?? tokens.color.backgroundBrandLoud` | `tokens.color.backgroundBrandLoud.hover` | +| `{ color: { x: rest, hover: { x: hover } } }` | `{ color: { x: { rest, hover } } }` | +| `{ color: { backgroundBrandLoud: '#…' } }` (implicitly inverted) | `{ color: { backgroundBrandLoud: flexColor('#…', 'inverted') } }` | +| A recipe branching on `appearance.colorScheme` for a color | A `[light, dark]` tuple | +| `(parent, appearance) => …parent.color.x…` | `(description) => …description.color.x…`, or `flexColor(selectColorEntry(description.color.x.rest, appearance), type)` for a selected value | +| `InteractiveColorOverrides` | `InteractiveColorOptions` or `PartialSemanticColors` | Other surfaces: diff --git a/packages/agentic/design/references/remaining-work.md b/packages/agentic/design/references/remaining-work.md index 92a096e671..7edc927068 100644 --- a/packages/agentic/design/references/remaining-work.md +++ b/packages/agentic/design/references/remaining-work.md @@ -73,8 +73,5 @@ behavior is documented in `theming.md`, `tokens.md`, and `entry-points.md`. ## Dependent work owned by other packages -- `@fluentui-react-native/storybook-desktop-runtime` still offers fixed light, dark, and high-contrast legacy themes; - [#4269](https://github.com/microsoft/fluentui-react-native/issues/4269) moves Storybook to the unified provider with - structured appearance controls. - `@fluentui-react-native/apple-theme` still authors a legacy `Theme`; [#4261](https://github.com/microsoft/fluentui-react-native/issues/4261) re-authors it on Flex tokens. diff --git a/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts b/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts index e84c1f19a3..c7a3a73b02 100644 --- a/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts +++ b/packages/agentic/design/src/flex/colors/interactionPolicy.test.ts @@ -217,9 +217,11 @@ describe('resolveFlexColor', () => { expect(() => resolveFlexColor('backgroundBrandHeavy', fixed, appearance('light'))).toThrow( 'type "fixed" and no explicit pressed value', ); - expect(() => resolveFlexColor('backgroundBrandHeavy', fixed, { ...appearance('light'), contrast: 'highContrast' })).toThrow( - 'type "fixed"', - ); + expect(resolveFlexColor('backgroundBrandHeavy', fixed, { ...appearance('light'), contrast: 'highContrast' })).toEqual({ + rest: '#0f6cbd', + hover: '#115ea3', + pressed: '#0f6cbd', + }); expect(resolveFlexColor('backgroundBrandHeavy', complete, appearance('light'))).toEqual({ rest: '#0f6cbd', hover: '#115ea3', diff --git a/packages/agentic/design/src/flex/colors/interactionPolicy.ts b/packages/agentic/design/src/flex/colors/interactionPolicy.ts index 8127202f63..a3db125161 100644 --- a/packages/agentic/design/src/flex/colors/interactionPolicy.ts +++ b/packages/agentic/design/src/flex/colors/interactionPolicy.ts @@ -50,6 +50,9 @@ function resolveState( if (!isInteractiveColorToken(token)) { return rest; } + if (appearance.contrast === 'highContrast') { + return rest; + } const { type } = description; if (type === 'fixed') { @@ -60,9 +63,6 @@ function resolveState( } return rest; } - if (appearance.contrast === 'highContrast') { - return rest; - } return () => deriveInteractionColor(rest, token, state, type, appearance); } @@ -70,8 +70,8 @@ function resolveState( * Resolve one authored color for an appearance. Explicit states win. Omitted * states of interactive tokens are computed on first read from rest, using the * description's type for direction; other tokens and high contrast use rest. - * A fixed interactive color whose rest the engine can map must author every - * state, and throws here otherwise. + * Outside high contrast, a fixed interactive color whose rest the engine can + * map must author every state, and throws here otherwise. */ export function resolveFlexColor( token: string, diff --git a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts index 0aa35d3ccc..d02fa3b449 100644 --- a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts +++ b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts @@ -154,15 +154,18 @@ describe('themeFromFlexTokens', () => { expect(theme.shadows.shadow16).toEqual({ ambient: defaultFlexTokens.shadow.high[0], key: defaultFlexTokens.shadow.high.at(-1) }); }); - it('passes a legacy { ambient, key } shadow through the deprecated flat representation', () => { + it('accepts the pre-interactive flat representation, including legacy { ambient, key } shadows', () => { const legacy = { ambient: { x: 0, y: 0, blur: 2, color: 'black' }, key: { x: 0, y: 2, blur: 4, color: 'red' } }; - const flat = { - ...defaultFlexTokens, + const { motion: _motion, spacing, ...groups } = defaultFlexTokens; + const { componentBase800: _componentBase800, ...previousSpacing } = spacing; + const flat: FlatFlexTokens = { + ...groups, color: restColorValues(defaultFlexTokens.color), shadow: { ...defaultFlexTokens.shadow, lowest: legacy }, + spacing: previousSpacing, }; - expect(themeFromFlexTokens(flat as unknown as FlatFlexTokens, light).shadows.shadow2).toEqual(legacy); + expect(themeFromFlexTokens(flat, light).shadows.shadow2).toEqual(legacy); }); it('projects the same legacy theme from resolved and equivalent flat tokens', () => { diff --git a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts index 64cb42b861..01c43bfbfa 100644 --- a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts +++ b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts @@ -1,9 +1,10 @@ -import type { FlexTokens, SemanticColorTokenValues } from '../../flex/tokens.types'; +import type { FlexTokens, SemanticColorTokenValues, SemanticMotion, SemanticShadows, SemanticSpacing } from '../../flex/tokens.types'; import reverseProjection from '../../tokens/mappings/theme-from-flex.json' with { type: 'json' }; import { appearanceOptionFromResolved } from '../../theming/appearance'; import type { ResolvedThemeAppearance } from '../../types/appearance.types'; import { ensureParentRecord, getValueAtSegments, isRecord, splitObjectPath } from '../../utilities/objects'; import { mergeTheme } from '../mergeTheme'; +import type { ShadowToken } from '../types/Shadow.types'; import type { PartialTheme, Theme } from '../types/Theme.types'; import { getDefaultLegacyTheme } from './defaultLegacyTheme'; @@ -22,17 +23,21 @@ export interface ThemeFromFlexTokensOptions { /** * Flex tokens in the representation used before interactive colors: each color - * is its rest value, and optional `color.hover` and `color.pressed` maps hold - * explicit states. + * is its rest value, optional `color.hover` and `color.pressed` maps hold + * explicit states, a shadow may be a legacy `{ ambient, key }` token, and the + * later `motion` group and `spacing.componentBase800` may be absent. * * @deprecated Pass resolved {@link FlexTokens}, whose colors carry * `rest`, `hover`, and `pressed`. */ -export type FlatFlexTokens = Omit & { +export type FlatFlexTokens = Omit & { color: SemanticColorTokenValues & { hover?: Partial; pressed?: Partial; }; + shadow: { [Name in keyof SemanticShadows]: SemanticShadows[Name] | ShadowToken }; + spacing: Omit & Partial>; + motion?: SemanticMotion; }; const colorStatePathPattern = /^color\.([^.]+)\.(rest|hover|pressed)$/; diff --git a/packages/agentic/storybook-desktop-runtime/references/runtime-contract.md b/packages/agentic/storybook-desktop-runtime/references/runtime-contract.md index c96b9b761c..11efff1819 100644 --- a/packages/agentic/storybook-desktop-runtime/references/runtime-contract.md +++ b/packages/agentic/storybook-desktop-runtime/references/runtime-contract.md @@ -24,6 +24,25 @@ resizable sidebar, story preview, bottom addon panel, and optional Callout-backed pop-outs. Do not add mobile drawer portals or window-dimension assumptions to the Win32 host. +The toolbar selects four independent axes from inline dropdown menus: + +| Axis | Test-ID segment | Values | +| -------- | --------------- | -------------------------------------------------------------------------------------- | +| Theme | `source` | `flex` (the design package's Flex defaults) or `fluent` (the legacy default theme) | +| Scheme | `scheme` | `light`, `dark`, or `system`, which follows the platform appearance | +| Contrast | `contrast` | `standard` or `highContrast` | +| Tone | `tone` | `cool` or `warm`; Flex only, so it is disabled and reports `cool` for the Fluent theme | + +Both sources receive the selection as one structured appearance request, so a +selection never constructs a new theme reference. The default, Flex, light, +standard, and cool, does not depend on the host appearance. The toolbar is +`-theme-toolbar`; each axis trigger is a combobox with test ID +`-theme-` that reports its value and expanded state; its open +menu is `-theme--menu`; and each option is +`-theme--`. One menu is open at a time, and selecting +an option closes it. Native story tests can select a theme configuration +through these IDs before asserting. + Opaque platform colors may be unusable by Storybook JavaScript color utilities. Preserve native tokens; use the documented contrasting theme color fallback for the chrome and warn when substituting. Keep story background diff --git a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx index 66e903011f..44882b3f29 100644 --- a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx +++ b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx @@ -1,9 +1,11 @@ import * as React from 'react'; -import { StyleSheet, Text } from 'react-native'; +import { Appearance, StyleSheet, Text } from 'react-native'; import { fireEvent, render } from '@testing-library/react-native'; -import { useRootSettings, useThemeState } from '@fluentui-react-native/design'; -import type { RootSettings, ThemeState } from '@fluentui-react-native/design'; +import { useRootSettings, useThemeAppearance, useThemeState } from '@fluentui-react-native/design'; +import type { RootSettings, ThemeAppearanceState, ThemeState } from '@fluentui-react-native/design'; +import { ThemeContext } from '@fluentui-react-native/design/theming'; +import type { Theme as LegacyTheme } from '@fluentui-react-native/design/theming'; import { defaultFlexTokens } from '@fluentui-react-native/design/testing'; import type { View as StorybookView } from '@storybook/react-native'; import { theme as lightTheme } from '@storybook/react-native-theming'; @@ -15,16 +17,22 @@ import { StorybookUIComponent } from './StorybookUI'; jest.mock('./DesktopDriverBridge', () => ({ DesktopDriverBridge: jest.fn(() => null) })); jest.mock('./StorybookUI', () => ({ StorybookUIComponent: jest.fn(() => null) })); +type Scene = Awaited>; + function createTestApp(storyBackgroundColor?: string) { const roots: RootSettings[] = []; const bridgeRoots: RootSettings[] = []; const themes: ThemeState[] = []; + const appearances: ThemeAppearanceState[] = []; + const legacyThemes: (LegacyTheme | undefined)[] = []; const mounted = jest.fn(); const unmounted = jest.fn(); function Story() { roots.push(useRootSettings()); themes.push(useThemeState()); + appearances.push(useThemeAppearance()); + legacyThemes.push(React.useContext(ThemeContext)); React.useEffect(() => { mounted(); return unmounted; @@ -56,24 +64,60 @@ function createTestApp(storyBackgroundColor?: string) { ); }); const App = createDesktopStorybookApp({ getStorybookUI }, { enableWebsockets: false, testIDPrefix: 'test' }); - return { App, roots, bridgeRoots, themes, mounted, unmounted, getStorybookUI }; + return { App, roots, bridgeRoots, themes, appearances, legacyThemes, mounted, unmounted, getStorybookUI }; +} + +async function selectTheme(scene: Scene, axis: string, value: string) { + await fireEvent.press(scene.getByTestId(`test-theme-${axis}`)); + await fireEvent.press(scene.getByTestId(`test-theme-${axis}-${value}`)); +} + +function latestStorybookTheme() { + const calls = jest.mocked(StorybookUIComponent).mock.calls; + return calls[calls.length - 1][0].theme; } +const selectionSteps = [ + ['scheme', 'dark'], + ['tone', 'warm'], + ['contrast', 'highContrast'], + ['source', 'fluent'], + ['contrast', 'standard'], + ['scheme', 'light'], + ['source', 'flex'], + ['tone', 'cool'], +] as const; + afterEach(() => { jest.clearAllMocks(); jest.restoreAllMocks(); }); describe('Storybook app theme root', () => { - it('places the toolbar, UI, story, and runtime bridge in the same default Flex scene', async () => { - const { App, roots, bridgeRoots, themes } = createTestApp(); + it('places the toolbar, UI, story, and runtime bridge in one deterministic default Flex scene', async () => { + const { App, roots, bridgeRoots, themes, appearances, legacyThemes } = createTestApp(); const scene = await render(); expect(scene.getByTestId('test-app-root')).toBeOnTheScreen(); expect(scene.getByTestId('test-theme-toolbar')).toBeOnTheScreen(); expect(scene.getByTestId('selected-story')).toBeOnTheScreen(); - expect(scene.getByRole('button', { name: 'Default Flex' })).toBeOnTheScreen(); + for (const [axis, label] of [ + ['source', 'Flex'], + ['scheme', 'Light'], + ['contrast', 'Standard'], + ['tone', 'Cool'], + ]) { + const trigger = scene.getByTestId(`test-theme-${axis}`); + expect(trigger.props.accessibilityValue).toEqual({ text: label }); + expect(trigger.props.accessibilityState).toEqual({ disabled: false, expanded: false }); + } + expect(appearances[0]).toEqual({ + requested: { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'system', colorTone: 'cool' }, + resolved: { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base', colorTone: 'cool' }, + }); + expect(themes[0].appearance).toBe(appearances[0].resolved); expect(themes[0].tokens).toEqual(defaultFlexTokens); + expect(legacyThemes[0]).toBeUndefined(); expect(bridgeRoots.every((root) => root === roots[0])).toBe(true); expect(roots[0].inputModality).toBe('pointer'); }); @@ -95,29 +139,116 @@ describe('Storybook app theme root', () => { expect(roots).toHaveLength(renderCount); }); - it.each(['none', 'light', 'dark'])('keeps the %s canvas distinct from the Secondary Button fill', async (choice) => { + it('opens one axis menu at a time and closes it after a selection', async () => { + const { App } = createTestApp(); + const scene = await render(); + + await fireEvent.press(scene.getByTestId('test-theme-scheme')); + expect(scene.getByTestId('test-theme-scheme').props.accessibilityState.expanded).toBe(true); + expect(scene.getByTestId('test-theme-scheme-light').props.accessibilityState.selected).toBe(true); + expect(scene.getByTestId('test-theme-scheme-system')).toBeOnTheScreen(); + + await fireEvent.press(scene.getByTestId('test-theme-source')); + expect(scene.queryByTestId('test-theme-scheme-menu')).toBeNull(); + expect(scene.getByTestId('test-theme-source-menu')).toBeOnTheScreen(); + + await fireEvent.press(scene.getByTestId('test-theme-source')); + expect(scene.queryByTestId('test-theme-source-menu')).toBeNull(); + + await selectTheme(scene, 'scheme', 'dark'); + expect(scene.queryByTestId('test-theme-scheme-menu')).toBeNull(); + expect(scene.getByTestId('test-theme-scheme').props.accessibilityValue).toEqual({ text: 'Dark' }); + }); + + it('applies scheme, contrast, and tone to the Flex defaults', async () => { + const { App, themes } = createTestApp(); + const scene = await render(); + const coolLight = themes[themes.length - 1].tokens; + + await selectTheme(scene, 'tone', 'warm'); + const warmLight = themes[themes.length - 1]; + expect(warmLight.appearance).toEqual({ colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base', colorTone: 'warm' }); + expect(warmLight.tokens.color.surfaceNeutralFar.rest).not.toBe(coolLight.color.surfaceNeutralFar.rest); + + await selectTheme(scene, 'scheme', 'dark'); + const warmDark = themes[themes.length - 1]; + expect(warmDark.appearance.colorScheme).toBe('dark'); + expect(warmDark.tokens.color.surfaceNeutralFar.rest).not.toBe(warmLight.tokens.color.surfaceNeutralFar.rest); + expect(warmDark.tokens.color.backgroundBrandLoud.hover).not.toBe(warmDark.tokens.color.backgroundBrandLoud.rest); + + await selectTheme(scene, 'contrast', 'highContrast'); + const highContrast = themes[themes.length - 1]; + expect(highContrast.appearance.contrast).toBe('highContrast'); + expect(highContrast.tokens.color.backgroundBrandLoud.hover).toBe(highContrast.tokens.color.backgroundBrandLoud.rest); + expect(highContrast.tokens.color.backgroundBrandLoud.pressed).toBe(highContrast.tokens.color.backgroundBrandLoud.rest); + }); + + it('follows the platform scheme only when System is selected', async () => { + jest.spyOn(Appearance, 'getColorScheme').mockReturnValue('dark'); + const { App, themes, appearances } = createTestApp(); + const scene = await render(); + expect(themes[themes.length - 1].appearance.colorScheme).toBe('light'); + + await selectTheme(scene, 'scheme', 'system'); + expect(appearances[appearances.length - 1].requested.colorScheme).toBe('system'); + expect(themes[themes.length - 1].appearance.colorScheme).toBe('dark'); + }); + + it('uses the legacy Fluent default theme without tone and restores the Flex tone', async () => { + const { App, themes, legacyThemes } = createTestApp(); + const scene = await render(); + await selectTheme(scene, 'tone', 'warm'); + + await selectTheme(scene, 'source', 'fluent'); + const tone = scene.getByTestId('test-theme-tone'); + expect(tone.props.accessibilityState).toEqual({ disabled: true, expanded: false }); + expect(tone.props.accessibilityValue).toEqual({ text: 'Cool' }); + await fireEvent.press(tone); + expect(scene.queryByTestId('test-theme-tone-menu')).toBeNull(); + expect(themes[themes.length - 1].appearance.colorTone).toBe('cool'); + expect(legacyThemes[legacyThemes.length - 1]?.host.appearance).toBe('light'); + + await selectTheme(scene, 'scheme', 'dark'); + expect(legacyThemes[legacyThemes.length - 1]?.host.appearance).toBe('dark'); + await selectTheme(scene, 'contrast', 'highContrast'); + expect(legacyThemes[legacyThemes.length - 1]?.host.appearance).toBe('highContrast'); + + await selectTheme(scene, 'source', 'flex'); + expect(legacyThemes[legacyThemes.length - 1]).toBeUndefined(); + expect(scene.getByTestId('test-theme-tone').props.accessibilityValue).toEqual({ text: 'Warm' }); + expect(themes[themes.length - 1].appearance.colorTone).toBe('warm'); + }); + + it.each([ + ['flex', 'light'], + ['flex', 'dark'], + ['fluent', 'light'], + ['fluent', 'dark'], + ])('keeps the %s %s canvas distinct from the Secondary Button fill', async (source, scheme) => { const { App, themes } = createTestApp(); const scene = await render(); - await fireEvent.press(scene.getByTestId(`test-theme-${choice}`)); + await selectTheme(scene, 'source', source); + await selectTheme(scene, 'scheme', scheme); const state = themes[themes.length - 1]; - const calls = jest.mocked(StorybookUIComponent).mock.calls; - const theme = calls[calls.length - 1][0].theme; + const theme = latestStorybookTheme(); expect(theme.background.content).toBe(state.tokens.color.surfaceNeutralFar.rest); expect(theme.background.content).toBe(theme.background.preview); expect(theme.background.content).not.toBe(state.tokens.color.backgroundNeutralSubtle.rest); }); it.each(['#ffeedd', 'transparent'])('preserves the explicit %s story background across theme changes', async (storyBackgroundColor) => { + const warn = jest.spyOn(console, 'warn').mockImplementation(); const { App } = createTestApp(storyBackgroundColor); const scene = await render(); - for (const choice of ['none', 'dark', 'light']) { - await fireEvent.press(scene.getByTestId(`test-theme-${choice}`)); + for (const [axis, value] of selectionSteps) { + await selectTheme(scene, axis, value); const calls = jest.mocked(StorybookUIComponent).mock.calls; expect(calls[calls.length - 1][0].storyBackgroundColor).toBe(storyBackgroundColor); } + expect(warn).toHaveBeenCalledWith(expect.stringContaining('Storybook chrome cannot resolve native system colors')); }); it('switches chrome and story colors together without recreating Storybook or resetting the scene', async () => { @@ -126,17 +257,15 @@ describe('Storybook app theme root', () => { const scene = await render(); const root = roots[0]; const defaultBackground = themes[0].tokens.color.surfaceNeutralFar.rest; - const backgrounds: Record = {}; + const backgrounds = new Set([defaultBackground]); await fireEvent(scene.getByTestId('test-app-root'), 'keyDownCapture', { nativeEvent: { key: 'Tab' } }); - for (const choice of ['dark', 'highContrast', 'light', 'none']) { - await fireEvent.press(scene.getByTestId(`test-theme-${choice}`)); + for (const [axis, value] of selectionSteps) { + await selectTheme(scene, axis, value); const state = themes[themes.length - 1]; - const calls = jest.mocked(StorybookUIComponent).mock.calls; - const theme = calls[calls.length - 1][0].theme; - backgrounds[choice] = theme.background.app; + const theme = latestStorybookTheme(); + backgrounds.add(theme.background.app); - expect(scene.getByTestId(`test-theme-${choice}`).props.accessibilityState.selected).toBe(true); expect(StyleSheet.flatten(scene.getByTestId('test-theme-toolbar').props.style).backgroundColor).toBe( state.tokens.color.backgroundNeutralSubtle.rest, ); @@ -154,8 +283,8 @@ describe('Storybook app theme root', () => { expect(roots.every((settings) => settings === root)).toBe(true); } - expect(backgrounds.dark).not.toBe(backgrounds.light); - expect(backgrounds.none).toBe(defaultBackground); + expect(themes[themes.length - 1].tokens.color.surfaceNeutralFar.rest).toBe(defaultBackground); + expect(backgrounds.size).toBeGreaterThan(3); expect(warn).toHaveBeenCalledWith(expect.stringContaining('Storybook chrome cannot resolve native system colors')); expect(getStorybookUI).toHaveBeenCalledTimes(1); expect(mounted).toHaveBeenCalledTimes(1); diff --git a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx index 8f87f55e2b..d10d06cfff 100644 --- a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx +++ b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx @@ -2,33 +2,91 @@ import * as React from 'react'; import { Pressable, StyleSheet, Text, View } from 'react-native'; import { createDefaultTheme } from '@fluentui-react-native/default-theme'; -import { ThemedRoot, themedStyleSheetFactory, useThemeState } from '@fluentui-react-native/design'; -import type { ThemeReference } from '@fluentui-react-native/design/theming'; +import { FlexThemeReference, ThemedRoot, themedStyleSheetFactory, useThemeState } from '@fluentui-react-native/design'; +import type { ColorTone, ThemeAppearanceOptions, ThemeSource } from '@fluentui-react-native/design'; import { useDesktopStorybookTestID } from './DesktopStorybookConfig'; -type ThemeChoice = { - label: string; - theme?: ThemeReference; +/** The theme configuration selected in the Storybook toolbar. */ +export type StorybookThemeSelection = { + /** The package's Flex defaults or the legacy Fluent default theme. */ + source: 'flex' | 'fluent'; + colorScheme: 'light' | 'dark' | 'system'; + contrast: 'standard' | 'highContrast'; + /** Flex palette and interaction tone. Legacy Fluent themes have no tone. */ + colorTone: ColorTone; }; -const themeChoiceNames = ['none', 'light', 'dark', 'highContrast'] as const; -type ThemeChoiceName = (typeof themeChoiceNames)[number]; +type ThemeAxisKey = keyof StorybookThemeSelection; -const themeChoices: Record = { - none: { label: 'Default Flex' }, - light: { label: 'Light', theme: createDefaultTheme({ appearance: 'light' }) }, - dark: { label: 'Dark', theme: createDefaultTheme({ appearance: 'dark' }) }, - highContrast: { label: 'High contrast', theme: createDefaultTheme({ appearance: 'highContrast' }) }, +type ThemeAxis = { + readonly key: ThemeAxisKey; + /** Stable test-ID segment for the axis and its options. */ + readonly id: string; + readonly label: string; + readonly options: readonly { readonly value: string; readonly label: string }[]; }; +/** A deterministic default that does not depend on the host appearance. */ +export const defaultStorybookThemeSelection: Readonly = Object.freeze({ + source: 'flex', + colorScheme: 'light', + contrast: 'standard', + colorTone: 'cool', +}); + +function themeAxis( + key: Key, + id: string, + label: string, + options: readonly { value: StorybookThemeSelection[Key]; label: string }[], +): ThemeAxis { + return { key, id, label, options }; +} + +const themeAxes: readonly ThemeAxis[] = [ + themeAxis('source', 'source', 'Theme', [ + { value: 'flex', label: 'Flex' }, + { value: 'fluent', label: 'Fluent' }, + ]), + themeAxis('colorScheme', 'scheme', 'Scheme', [ + { value: 'light', label: 'Light' }, + { value: 'dark', label: 'Dark' }, + { value: 'system', label: 'System' }, + ]), + themeAxis('contrast', 'contrast', 'Contrast', [ + { value: 'standard', label: 'Standard' }, + { value: 'highContrast', label: 'High' }, + ]), + themeAxis('colorTone', 'tone', 'Tone', [ + { value: 'cool', label: 'Cool' }, + { value: 'warm', label: 'Warm' }, + ]), +]; + +// Each source resolves every appearance itself, so selection changes only the appearance request. +const themeSources: Record = { + flex: new FlexThemeReference(), + fluent: createDefaultTheme({ appearance: 'dynamic' }), +}; + +function appearanceFromSelection({ source, colorScheme, contrast, colorTone }: StorybookThemeSelection): ThemeAppearanceOptions { + // Omitting tone for Fluent keeps the resolved appearance at its cool default. + return source === 'flex' ? { colorScheme, contrast, colorTone } : { colorScheme, contrast }; +} + +function isAxisDisabled(key: ThemeAxisKey, selection: StorybookThemeSelection): boolean { + return key === 'colorTone' && selection.source !== 'flex'; +} + export function StorybookThemeHost({ children }: React.PropsWithChildren) { - const [selectedName, setSelectedName] = React.useState('none'); + const [selection, setSelection] = React.useState(defaultStorybookThemeSelection); + const appearance = React.useMemo(() => appearanceFromSelection(selection), [selection]); const testID = useDesktopStorybookTestID('app-root'); return ( - - + + {children} @@ -37,31 +95,39 @@ export function StorybookThemeHost({ children }: React.PropsWithChildren) { function StorybookThemeContent({ children, - selectedName, - onSelect, -}: React.PropsWithChildren<{ selectedName: ThemeChoiceName; onSelect: (name: ThemeChoiceName) => void }>) { + selection, + onSelectionChange, +}: React.PropsWithChildren<{ + selection: StorybookThemeSelection; + onSelectionChange: React.Dispatch>; +}>) { const styles = getStyles(useThemeState()); const toolbarTestID = useDesktopStorybookTestID('theme-toolbar'); - const optionTestID = useDesktopStorybookTestID('theme'); + const axisTestID = useDesktopStorybookTestID('theme'); + const [openAxis, setOpenAxis] = React.useState(); + + const select = (key: ThemeAxisKey, value: string) => { + onSelectionChange((current) => (current[key] === value ? current : ({ ...current, [key]: value } as StorybookThemeSelection))); + setOpenAxis(undefined); + }; return ( - Theme - {themeChoiceNames.map((name) => { - const choice = themeChoices[name]; - const selected = name === selectedName; + {themeAxes.map((axis) => { + const disabled = isAxisDisabled(axis.key, selection); return ( - onSelect(name)} - style={({ pressed }) => [styles.option, selected && styles.selectedOption, pressed && styles.pressedOption]} - testID={`${optionTestID}-${name}`} - > - {choice.label} - + select(axis.key, value)} + onToggle={() => setOpenAxis((current) => (current === axis.key ? undefined : axis.key))} + /> ); })} @@ -70,6 +136,65 @@ function StorybookThemeContent({ ); } +type ThemeAxisDropdownProps = { + axis: ThemeAxis; + disabled: boolean; + open: boolean; + styles: ReturnType; + testID: string; + value: string; + onSelect(value: string): void; + onToggle(): void; +}; + +function ThemeAxisDropdown({ axis, disabled, open, styles, testID, value, onSelect, onToggle }: ThemeAxisDropdownProps) { + const selectedLabel = axis.options.find((option) => option.value === value)?.label ?? value; + + return ( + + {axis.label} + + [styles.option, styles.trigger, pressed && styles.pressedOption, disabled && styles.disabledOption]} + testID={testID} + > + {selectedLabel} + {open ? '\u25b4' : '\u25be'} + + {open ? ( + + {axis.options.map((option) => { + const selected = option.value === value; + return ( + onSelect(option.value)} + style={({ pressed }) => [ + styles.menuOption, + selected && styles.selectedOption, + pressed && (selected ? styles.pressedSelectedOption : styles.pressedMenuOption), + ]} + testID={`${testID}-${option.value}`} + > + {option.label} + + ); + })} + + ) : null} + + + ); +} + const layoutStyles = StyleSheet.create({ root: { flex: 1, @@ -83,45 +208,88 @@ const getStyles = themedStyleSheetFactory('StorybookTheme', ({ tokens }) => backgroundColor: tokens.color.surfaceNeutralFar.rest, }, header: { - alignItems: 'center', + alignItems: 'flex-start', backgroundColor: tokens.color.backgroundNeutralSubtle.rest, borderBottomColor: tokens.color.strokeNeutralSubtle.rest, borderBottomWidth: 1, flexDirection: 'row', flexWrap: 'wrap', - gap: 8, + gap: 16, minHeight: 44, paddingHorizontal: 12, - paddingVertical: 6, + paddingVertical: 8, + }, + field: { + alignItems: 'flex-start', + flexDirection: 'row', + gap: 6, }, label: { color: tokens.color.foregroundNeutralPrimary.rest, fontSize: 14, fontWeight: '600', - marginEnd: 4, + paddingVertical: 5, }, option: { - backgroundColor: tokens.color.backgroundNeutralLoud.rest, - borderColor: tokens.color.strokeNeutralSoft.rest, + backgroundColor: tokens.color.surfaceNeutralNearer.rest, + borderColor: tokens.color.strokeNeutralLoud.rest, borderRadius: 4, borderWidth: 1, paddingHorizontal: 10, paddingVertical: 5, }, - selectedOption: { - backgroundColor: tokens.color.backgroundBrandHeavy.rest, - borderColor: tokens.color.strokeBrandLoud.rest, + trigger: { + alignItems: 'center', + flexDirection: 'row', + gap: 8, + justifyContent: 'space-between', + minWidth: 96, }, pressedOption: { - opacity: 0.75, + backgroundColor: tokens.color.surfaceNeutralNearer.pressed, + borderColor: tokens.color.strokeNeutralLoud.pressed, + }, + disabledOption: { + backgroundColor: tokens.color.backgroundNeutralDisabled.rest, + borderColor: tokens.color.strokeNeutralDisabled.rest, + }, + menu: { + backgroundColor: tokens.color.surfaceNeutralNearer.rest, + borderColor: tokens.color.strokeNeutralSubtle.rest, + borderRadius: 4, + borderWidth: 1, + gap: 2, + marginTop: 4, + padding: 2, + }, + menuOption: { + backgroundColor: tokens.color.backgroundNeutralTransparent.rest, + borderRadius: 3, + paddingHorizontal: 10, + paddingVertical: 5, + }, + pressedMenuOption: { + backgroundColor: tokens.color.backgroundNeutralTransparent.pressed, + }, + selectedOption: { + backgroundColor: tokens.color.backgroundNeutralSoft.rest, + }, + pressedSelectedOption: { + backgroundColor: tokens.color.backgroundNeutralSoft.pressed, }, optionText: { color: tokens.color.foregroundNeutralPrimary.rest, fontSize: 12, }, + chevron: { + color: tokens.color.foregroundNeutralSecondary.rest, + fontSize: 12, + }, selectedOptionText: { - color: tokens.color.foregroundBrandOnloud.rest, fontWeight: '600', }, + disabledText: { + color: tokens.color.foregroundNeutralDisabled.rest, + }, }), ); From 366ba6acb9468f429627cfacd32f48315f9cac09 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Tue, 27 Oct 2026 17:47:01 -0700 Subject: [PATCH 10/18] start of codegen for alias tokens --- packages/agentic/design/scripts/codegen.cts | 2 + .../design/scripts/design-token.types.ts | 23 +++++ .../agentic/design/scripts/fluent-tokens.cts | 88 ++++++++++++++++++ .../fluent/defaults/fluentTokens.generated.ts | 88 ++++++++++++++++++ scripts/src/codegen/content.ts | 90 +++++++++++++++++++ scripts/src/codegen/file.ts | 81 +++++++++++++++++ scripts/src/index.ts | 3 + 7 files changed, 375 insertions(+) create mode 100644 packages/agentic/design/scripts/design-token.types.ts create mode 100644 packages/agentic/design/scripts/fluent-tokens.cts create mode 100644 packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts create mode 100644 scripts/src/codegen/content.ts create mode 100644 scripts/src/codegen/file.ts diff --git a/packages/agentic/design/scripts/codegen.cts b/packages/agentic/design/scripts/codegen.cts index c65bf676ea..3895b5205f 100644 --- a/packages/agentic/design/scripts/codegen.cts +++ b/packages/agentic/design/scripts/codegen.cts @@ -1,6 +1,7 @@ const { processPlatformJsonFiles, outputCodegenFile } = require('@fluentui-react-native/scripts'); const path = require('node:path'); const { assertMappingsConsistent, writeMappingProjections } = require('./token-mappings/check-mappings.cjs'); +const { codegenFluentTokens } = require('./fluent-tokens.cts'); const globalHeader = `WARNING: This file is auto-generated. Do not edit it manually. @@ -38,6 +39,7 @@ function main() { writeMappingProjections(); assertMappingsConsistent(); processGlobals(); + codegenFluentTokens(); } main(); diff --git a/packages/agentic/design/scripts/design-token.types.ts b/packages/agentic/design/scripts/design-token.types.ts new file mode 100644 index 0000000000..035c0a84fb --- /dev/null +++ b/packages/agentic/design/scripts/design-token.types.ts @@ -0,0 +1,23 @@ +export type ShadowLayer = { + color: string; + x: number; + y: number; + blur: number; +}; + +export type ShadowDefinition = [ShadowLayer, ShadowLayer]; + +export type ShadowTokens = { + shadow16: ShadowDefinition; + shadow2: ShadowDefinition; + shadow28: ShadowDefinition; + shadow4: ShadowDefinition; + shadow64: ShadowDefinition; + shadow8: ShadowDefinition; + shadowBrand16: ShadowDefinition; + shadowBrand2: ShadowDefinition; + shadowBrand28: ShadowDefinition; + shadowBrand4: ShadowDefinition; + shadowBrand64: ShadowDefinition; + shadowBrand8: ShadowDefinition; +}; diff --git a/packages/agentic/design/scripts/fluent-tokens.cts b/packages/agentic/design/scripts/fluent-tokens.cts new file mode 100644 index 0000000000..a6908b6b3b --- /dev/null +++ b/packages/agentic/design/scripts/fluent-tokens.cts @@ -0,0 +1,88 @@ +import type { ShadowTokens, ShadowLayer } from './design-token.types'; +const { GeneratedFile, Ramp } = require('@fluentui-react-native/scripts'); +import type { GeneratedFile as GeneratedFileType, Ramp as RampType } from '@fluentui-react-native/scripts'; +const path = require('node:path'); + +type PlatformData = { + paths: Record; + filename: string; +}; + +const platformPaths: Record = { + win32: { + paths: { + dark: '@fluentui-react-native/design-tokens-win32/black/', + light: '@fluentui-react-native/design-tokens-win32/colorful/', + hc: '@fluentui-react-native/design-tokens-win32/hc/', + darkGray: '@fluentui-react-native/design-tokens-win32/darkgray/', + }, + filename: 'fluentTokens.generated.ts', + }, + macos: { + paths: { + dark: '@fluentui-react-native/design-tokens-macos/dark/', + light: '@fluentui-react-native/design-tokens-macos/light/', + hcLight: '@fluentui-react-native/design-tokens-macos/hclight/', + hcDark: '@fluentui-react-native/design-tokens-macos/hcdark/', + }, + filename: 'fluentTokens.generated.macos.ts', + }, + android: { + paths: { + dark: '@fluentui-react-native/design-tokens-android/dark/', + light: '@fluentui-react-native/design-tokens-android/light/', + }, + filename: 'fluentTokens.generated.android.ts', + }, + ios: { + paths: { + dark: '@fluentui-react-native/design-tokens-ios/dark/', + light: '@fluentui-react-native/design-tokens-ios/light/', + hcLight: '@fluentui-react-native/design-tokens-ios/hclight/', + hcDark: '@fluentui-react-native/design-tokens-ios/hcdark/', + darkElevated: '@fluentui-react-native/design-tokens-ios/elevateddark/', + }, + filename: 'fluentTokens.generated.ios.ts', + }, +}; + +function addShadowLayer(file: GeneratedFileType, ramp: RampType, layer: ShadowLayer) { + const { x, y, color, blur } = layer; + file.add(ramp.add('shadowLayer', [`{ x: ${x}, y: ${y}, blur: ${blur}, color: `, ramp.add('color', `'${color}'`), ' }'])); +} + +function processShadowTokens(prefix: string, platformPath: string, file: GeneratedFileType, ramp: RampType) { + const shadowTokens: ShadowTokens = require(`${platformPath}tokens-shadow.json`); + const layerNames = ['ambient', 'key']; + file.add(`export const ${prefix}Shadows = {\n`); + for (const [name, layers] of Object.entries(shadowTokens)) { + file.add(` ${name}: { `); + for (const [index, layer] of layerNames.entries()) { + file.add(`${layer}: `); + addShadowLayer(file, ramp, layers[index]); + if (index < layerNames.length - 1) { + file.add(', '); + } + } + file.add(' },\n'); + } + file.add('};\n'); +} + +function generatePlatformFluentTokens(platformData: PlatformData) { + const target = path.join(__dirname, '../src/fluent/defaults', platformData.filename); + const generatedFile = new GeneratedFile(target); + const ramp = new Ramp(); + generatedFile.add(ramp); + for (const [prefix, platformPath] of Object.entries(platformData.paths)) { + processShadowTokens(prefix, platformPath, generatedFile, ramp); + } + ramp.resolveEntries(); + generatedFile.commit(); +} + +function codegenFluentTokens() { + generatePlatformFluentTokens(platformPaths.win32); +} + +module.exports = { codegenFluentTokens }; diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts new file mode 100644 index 0000000000..041f8ed50f --- /dev/null +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts @@ -0,0 +1,88 @@ +/** + * WARNING: This file is auto-generated. Do not edit it manually. + */ +const rgb0000001f = '#0000001f'; +const rgb00000024 = '#00000024'; +const rgb00000033 = '#00000033'; +const rgb0000003d = '#0000003d'; +const rgb00000040 = '#00000040'; +const rgb00000047 = '#00000047'; +const rgb0000004d = '#0000004d'; +const rgb00000066 = '#00000066'; +const rgb0000007a = '#0000007a'; + +const shadowLayer1 = { x: 0, y: 0, blur: 2, color: rgb0000003d }; +const shadowLayer2 = { x: 0, y: 8, blur: 16, color: rgb00000047 }; +const shadowLayer3 = { x: 0, y: 1, blur: 2, color: rgb00000047 }; +const shadowLayer4 = { x: 0, y: 0, blur: 8, color: rgb00000066 }; +const shadowLayer5 = { x: 0, y: 14, blur: 28, color: rgb0000007a }; +const shadowLayer6 = { x: 0, y: 2, blur: 4, color: rgb00000047 }; +const shadowLayer7 = { x: 0, y: 32, blur: 64, color: rgb0000007a }; +const shadowLayer8 = { x: 0, y: 4, blur: 8, color: rgb00000047 }; +const shadowLayer9 = { x: 0, y: 0, blur: 2, color: rgb0000004d }; +const shadowLayer10 = { x: 0, y: 8, blur: 16, color: rgb00000040 }; +const shadowLayer11 = { x: 0, y: 1, blur: 2, color: rgb00000040 }; +const shadowLayer12 = { x: 0, y: 0, blur: 8, color: rgb0000004d }; +const shadowLayer13 = { x: 0, y: 14, blur: 28, color: rgb00000040 }; +const shadowLayer14 = { x: 0, y: 2, blur: 4, color: rgb00000040 }; +const shadowLayer15 = { x: 0, y: 32, blur: 64, color: rgb00000040 }; +const shadowLayer16 = { x: 0, y: 4, blur: 8, color: rgb00000040 }; +const shadowLayer17 = { x: 0, y: 0, blur: 2, color: rgb0000001f }; +const shadowLayer18 = { x: 0, y: 0, blur: 8, color: rgb00000033 }; + +export const darkShadows = { + shadow16: { ambient: shadowLayer1, key: shadowLayer2 }, + shadow2: { ambient: shadowLayer1, key: shadowLayer3 }, + shadow28: { ambient: shadowLayer4, key: shadowLayer5 }, + shadow4: { ambient: shadowLayer1, key: shadowLayer6 }, + shadow64: { ambient: shadowLayer4, key: shadowLayer7 }, + shadow8: { ambient: shadowLayer1, key: shadowLayer8 }, + shadowBrand16: { ambient: shadowLayer9, key: shadowLayer10 }, + shadowBrand2: { ambient: shadowLayer9, key: shadowLayer11 }, + shadowBrand28: { ambient: shadowLayer12, key: shadowLayer13 }, + shadowBrand4: { ambient: shadowLayer9, key: shadowLayer14 }, + shadowBrand64: { ambient: shadowLayer12, key: shadowLayer15 }, + shadowBrand8: { ambient: shadowLayer9, key: shadowLayer16 }, +}; +export const lightShadows = { + shadow16: { ambient: shadowLayer17, key: { x: 0, y: 8, blur: 16, color: rgb00000024 } }, + shadow2: { ambient: shadowLayer17, key: { x: 0, y: 1, blur: 2, color: rgb00000024 } }, + shadow28: { ambient: shadowLayer18, key: { x: 0, y: 14, blur: 28, color: rgb0000003d } }, + shadow4: { ambient: shadowLayer17, key: { x: 0, y: 2, blur: 4, color: rgb00000024 } }, + shadow64: { ambient: shadowLayer18, key: { x: 0, y: 32, blur: 64, color: rgb0000003d } }, + shadow8: { ambient: shadowLayer17, key: { x: 0, y: 4, blur: 8, color: rgb00000024 } }, + shadowBrand16: { ambient: shadowLayer9, key: shadowLayer10 }, + shadowBrand2: { ambient: shadowLayer9, key: shadowLayer11 }, + shadowBrand28: { ambient: shadowLayer12, key: shadowLayer13 }, + shadowBrand4: { ambient: shadowLayer9, key: shadowLayer14 }, + shadowBrand64: { ambient: shadowLayer12, key: shadowLayer15 }, + shadowBrand8: { ambient: shadowLayer9, key: shadowLayer16 }, +}; +export const hcShadows = { + shadow16: { ambient: shadowLayer1, key: shadowLayer2 }, + shadow2: { ambient: shadowLayer1, key: shadowLayer3 }, + shadow28: { ambient: shadowLayer4, key: shadowLayer5 }, + shadow4: { ambient: shadowLayer1, key: shadowLayer6 }, + shadow64: { ambient: shadowLayer4, key: shadowLayer7 }, + shadow8: { ambient: shadowLayer1, key: shadowLayer8 }, + shadowBrand16: { ambient: shadowLayer9, key: shadowLayer10 }, + shadowBrand2: { ambient: shadowLayer9, key: shadowLayer11 }, + shadowBrand28: { ambient: shadowLayer12, key: shadowLayer13 }, + shadowBrand4: { ambient: shadowLayer9, key: shadowLayer14 }, + shadowBrand64: { ambient: shadowLayer12, key: shadowLayer15 }, + shadowBrand8: { ambient: shadowLayer9, key: shadowLayer16 }, +}; +export const darkGrayShadows = { + shadow16: { ambient: shadowLayer1, key: shadowLayer2 }, + shadow2: { ambient: shadowLayer1, key: shadowLayer3 }, + shadow28: { ambient: shadowLayer4, key: shadowLayer5 }, + shadow4: { ambient: shadowLayer1, key: shadowLayer6 }, + shadow64: { ambient: shadowLayer4, key: shadowLayer7 }, + shadow8: { ambient: shadowLayer1, key: shadowLayer8 }, + shadowBrand16: { ambient: shadowLayer9, key: shadowLayer10 }, + shadowBrand2: { ambient: shadowLayer9, key: shadowLayer11 }, + shadowBrand28: { ambient: shadowLayer12, key: shadowLayer13 }, + shadowBrand4: { ambient: shadowLayer9, key: shadowLayer14 }, + shadowBrand64: { ambient: shadowLayer12, key: shadowLayer15 }, + shadowBrand8: { ambient: shadowLayer9, key: shadowLayer16 }, +}; diff --git a/scripts/src/codegen/content.ts b/scripts/src/codegen/content.ts new file mode 100644 index 0000000000..46fdbcfb08 --- /dev/null +++ b/scripts/src/codegen/content.ts @@ -0,0 +1,90 @@ +import type { Chunk, Output } from './file.ts'; +import { serialize } from './file.ts'; + +type RampEntry = Chunk & { + raw: Output; + count: number; + name?: string; +}; + +/** + * A ramp is a collection of categorized values that track their usage and combines them into named entries when they meet a + * usage threshold + */ +export class Ramp implements Chunk { + private _exported: boolean; + private _useThreshold: number; + private _ramps: Record>; + private _resolved?: Record; + + constructor(exported: boolean = false, useThreshold: number = 2) { + this._exported = exported; + this._useThreshold = useThreshold; + this._ramps = {}; + } + + /** + * Add a value to the ramp + * @param rampCategory The category of the ramp (e.g., 'color'). + * @param rawValue The raw value to add to the ramp. + * @returns The created or updated ramp entry. + */ + add(rampCategory: string, rawValue: Output): Chunk { + const ramp = (this._ramps[rampCategory] ??= {}); + const valueKey = serialize(rawValue); + const entry = (ramp[valueKey] ??= createRampEntry(rawValue)); + entry.count++; + return entry; + } + + resolveEntries() { + if (this._resolved) return; + this._resolved = {}; + for (const rampKey in this._ramps) { + let index = 1; + for (const entry of Object.values(this._ramps[rampKey])) { + if (entry.count >= this._useThreshold) { + entry.name = createEntryName(entry, rampKey, index++); + } + } + this._resolved[rampKey] = Object.values(this._ramps[rampKey]) + .filter((entry) => entry.name) + .sort((a, b) => a.name!.localeCompare(b.name!)); + } + } + + output(): string { + const prefix = this._exported ? 'export const ' : 'const '; + let output = ''; + for (const rampKey in this._ramps) { + const entries = Object.values(this._ramps[rampKey]).filter((entry) => entry.name); + if (rampKey === 'color') { + entries.sort((a, b) => a.name!.localeCompare(b.name!)); + } + if (entries.length > 0) { + output += entries.map((entry) => `${prefix}${entry.name} = ${serialize(entry.raw)};`).join('\n') + '\n\n'; + } + } + return output; + } +} + +function createRampEntry(raw: Output): RampEntry { + const entry = { raw, count: 0, name: undefined }; + return Object.assign(entry, { output: () => entry.name ?? serialize(entry.raw) }); +} + +// hex color strings will come in quoted with either ' or " +const HEX_COLOR = /^['"]#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})['"]$/; + +function createEntryName(entry: RampEntry, rampCategory: string, lastIndex: number): string { + if (rampCategory === 'color') { + // if the color entry has a hex value, use the full hex value as the name (without the #) + const rawText = serialize(entry.raw); + if (HEX_COLOR.test(rawText)) { + return 'rgb' + rawText.slice(2, -1); + } + } + // otherwise use the prefix with a number + return `${rampCategory}${lastIndex}`; +} diff --git a/scripts/src/codegen/file.ts b/scripts/src/codegen/file.ts new file mode 100644 index 0000000000..409877e0fb --- /dev/null +++ b/scripts/src/codegen/file.ts @@ -0,0 +1,81 @@ +import { FSEntry } from '@rnx-kit/tools-filesystem'; + +export type Chunk = { + /** + * Returns the output of the chunk as a string. + */ + output(): string; +}; + +export type OutputFragment = string | Chunk; +export type Output = OutputFragment | Output[]; + +export type Comment = Chunk & { + text: string | string[]; + type?: 'block' | 'line'; +}; + +export function makeComment(text: string | string[], type: 'block' | 'line' = 'block'): Comment { + const payload = { text, type }; + return { ...payload, output: () => writeComment(payload.text, payload.type) }; +} + +/** + * A generated file is just a collection of chunks serialized to a file. It has a header comment that can be + * modified if desired. + * - Chunks will be written in order. + * - The file will not be touched if no changes need to be written + */ +export class GeneratedFile { + private _content: Output[] = []; + private _entry: FSEntry; + + /** initialize the codegen file with the given path */ + constructor(path: string) { + this._entry = new FSEntry(path); + } + + /** public header comment */ + header = makeComment(`WARNING: This file is auto-generated. Do not edit it manually.`); + + /** path of the generated file */ + get path() { + return this._entry.path; + } + + /** add content to the generated file */ + add(...content: Output[]) { + this._content.push(...content); + } + + /** write the generated file to disk */ + commit() { + let content = this.header.output(); + if (this._content.length > 0) { + content += '\n' + serialize(this._content); + } + if (!content.endsWith('\n')) { + content += '\n'; + } + this._entry.content = content; + this._entry.writeContentsSync(); + } +} + +/** + * get the output text for one or more strings or chunks + */ +export function serialize(content: Output): string { + if (Array.isArray(content)) { + return content.map(serialize).join(''); + } + return typeof content === 'string' ? content : content.output(); +} + +function writeComment(text: string | string[], type: 'block' | 'line'): string { + const lines = Array.isArray(text) ? text : text.split('\n'); + if (type === 'line') { + return lines.map((line) => `// ${line}`).join('\n'); + } + return `/**\n${lines.map((line) => ` * ${line}`).join('\n')}\n */`; +} diff --git a/scripts/src/index.ts b/scripts/src/index.ts index 086ce68e4e..a13bcfe212 100644 --- a/scripts/src/index.ts +++ b/scripts/src/index.ts @@ -7,3 +7,6 @@ export type { Constants, ConstValue, CodegenTargetFile, ReExports } from './code export { jsonToCodegenTargetFile, processPlatformJsonFiles } from './codegen/json.ts'; export { writeConstExports, writeExportConst } from './codegen/constants.ts'; export { outputCodegenFile } from './codegen/genFile.ts'; +export { makeComment, GeneratedFile, serialize } from './codegen/file.ts'; +export type { Chunk, Output, Comment } from './codegen/file.ts'; +export { Ramp } from './codegen/content.ts'; From b4b8da99e95c51e0d08430c323943bd7026bf4c8 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Tue, 27 Oct 2026 18:01:40 -0700 Subject: [PATCH 11/18] fix brand shadow names --- .../agentic/design/scripts/fluent-tokens.cts | 13 ++++- .../fluent/defaults/fluentTokens.generated.ts | 58 ++++++++++--------- 2 files changed, 41 insertions(+), 30 deletions(-) diff --git a/packages/agentic/design/scripts/fluent-tokens.cts b/packages/agentic/design/scripts/fluent-tokens.cts index a6908b6b3b..cd6670b438 100644 --- a/packages/agentic/design/scripts/fluent-tokens.cts +++ b/packages/agentic/design/scripts/fluent-tokens.cts @@ -51,12 +51,20 @@ function addShadowLayer(file: GeneratedFileType, ramp: RampType, layer: ShadowLa file.add(ramp.add('shadowLayer', [`{ x: ${x}, y: ${y}, blur: ${blur}, color: `, ramp.add('color', `'${color}'`), ' }'])); } +function adjustShadowName(name: string) { + if (name.includes('Brand')) { + // shadowBrand16 needs to become shadow16brand + return name.replace('Brand', '') + 'brand'; + } + return name; +} + function processShadowTokens(prefix: string, platformPath: string, file: GeneratedFileType, ramp: RampType) { const shadowTokens: ShadowTokens = require(`${platformPath}tokens-shadow.json`); const layerNames = ['ambient', 'key']; - file.add(`export const ${prefix}Shadows = {\n`); + file.add(`export const ${prefix}Shadows: BaseShadowAliasTokens = {\n`); for (const [name, layers] of Object.entries(shadowTokens)) { - file.add(` ${name}: { `); + file.add(` ${adjustShadowName(name)}: { `); for (const [index, layer] of layerNames.entries()) { file.add(`${layer}: `); addShadowLayer(file, ramp, layers[index]); @@ -72,6 +80,7 @@ function processShadowTokens(prefix: string, platformPath: string, file: Generat function generatePlatformFluentTokens(platformData: PlatformData) { const target = path.join(__dirname, '../src/fluent/defaults', platformData.filename); const generatedFile = new GeneratedFile(target); + generatedFile.add(`import type { BaseShadowAliasTokens } from '../types/Shadow.types';\n\n`); const ramp = new Ramp(); generatedFile.add(ramp); for (const [prefix, platformPath] of Object.entries(platformData.paths)) { diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts index 041f8ed50f..065e1d39ec 100644 --- a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts @@ -1,6 +1,8 @@ /** * WARNING: This file is auto-generated. Do not edit it manually. */ +import type { BaseShadowAliasTokens } from '../types/Shadow.types'; + const rgb0000001f = '#0000001f'; const rgb00000024 = '#00000024'; const rgb00000033 = '#00000033'; @@ -30,59 +32,59 @@ const shadowLayer16 = { x: 0, y: 4, blur: 8, color: rgb00000040 }; const shadowLayer17 = { x: 0, y: 0, blur: 2, color: rgb0000001f }; const shadowLayer18 = { x: 0, y: 0, blur: 8, color: rgb00000033 }; -export const darkShadows = { +export const darkShadows: BaseShadowAliasTokens = { shadow16: { ambient: shadowLayer1, key: shadowLayer2 }, shadow2: { ambient: shadowLayer1, key: shadowLayer3 }, shadow28: { ambient: shadowLayer4, key: shadowLayer5 }, shadow4: { ambient: shadowLayer1, key: shadowLayer6 }, shadow64: { ambient: shadowLayer4, key: shadowLayer7 }, shadow8: { ambient: shadowLayer1, key: shadowLayer8 }, - shadowBrand16: { ambient: shadowLayer9, key: shadowLayer10 }, - shadowBrand2: { ambient: shadowLayer9, key: shadowLayer11 }, - shadowBrand28: { ambient: shadowLayer12, key: shadowLayer13 }, - shadowBrand4: { ambient: shadowLayer9, key: shadowLayer14 }, - shadowBrand64: { ambient: shadowLayer12, key: shadowLayer15 }, - shadowBrand8: { ambient: shadowLayer9, key: shadowLayer16 }, + shadow16brand: { ambient: shadowLayer9, key: shadowLayer10 }, + shadow2brand: { ambient: shadowLayer9, key: shadowLayer11 }, + shadow28brand: { ambient: shadowLayer12, key: shadowLayer13 }, + shadow4brand: { ambient: shadowLayer9, key: shadowLayer14 }, + shadow64brand: { ambient: shadowLayer12, key: shadowLayer15 }, + shadow8brand: { ambient: shadowLayer9, key: shadowLayer16 }, }; -export const lightShadows = { +export const lightShadows: BaseShadowAliasTokens = { shadow16: { ambient: shadowLayer17, key: { x: 0, y: 8, blur: 16, color: rgb00000024 } }, shadow2: { ambient: shadowLayer17, key: { x: 0, y: 1, blur: 2, color: rgb00000024 } }, shadow28: { ambient: shadowLayer18, key: { x: 0, y: 14, blur: 28, color: rgb0000003d } }, shadow4: { ambient: shadowLayer17, key: { x: 0, y: 2, blur: 4, color: rgb00000024 } }, shadow64: { ambient: shadowLayer18, key: { x: 0, y: 32, blur: 64, color: rgb0000003d } }, shadow8: { ambient: shadowLayer17, key: { x: 0, y: 4, blur: 8, color: rgb00000024 } }, - shadowBrand16: { ambient: shadowLayer9, key: shadowLayer10 }, - shadowBrand2: { ambient: shadowLayer9, key: shadowLayer11 }, - shadowBrand28: { ambient: shadowLayer12, key: shadowLayer13 }, - shadowBrand4: { ambient: shadowLayer9, key: shadowLayer14 }, - shadowBrand64: { ambient: shadowLayer12, key: shadowLayer15 }, - shadowBrand8: { ambient: shadowLayer9, key: shadowLayer16 }, + shadow16brand: { ambient: shadowLayer9, key: shadowLayer10 }, + shadow2brand: { ambient: shadowLayer9, key: shadowLayer11 }, + shadow28brand: { ambient: shadowLayer12, key: shadowLayer13 }, + shadow4brand: { ambient: shadowLayer9, key: shadowLayer14 }, + shadow64brand: { ambient: shadowLayer12, key: shadowLayer15 }, + shadow8brand: { ambient: shadowLayer9, key: shadowLayer16 }, }; -export const hcShadows = { +export const hcShadows: BaseShadowAliasTokens = { shadow16: { ambient: shadowLayer1, key: shadowLayer2 }, shadow2: { ambient: shadowLayer1, key: shadowLayer3 }, shadow28: { ambient: shadowLayer4, key: shadowLayer5 }, shadow4: { ambient: shadowLayer1, key: shadowLayer6 }, shadow64: { ambient: shadowLayer4, key: shadowLayer7 }, shadow8: { ambient: shadowLayer1, key: shadowLayer8 }, - shadowBrand16: { ambient: shadowLayer9, key: shadowLayer10 }, - shadowBrand2: { ambient: shadowLayer9, key: shadowLayer11 }, - shadowBrand28: { ambient: shadowLayer12, key: shadowLayer13 }, - shadowBrand4: { ambient: shadowLayer9, key: shadowLayer14 }, - shadowBrand64: { ambient: shadowLayer12, key: shadowLayer15 }, - shadowBrand8: { ambient: shadowLayer9, key: shadowLayer16 }, + shadow16brand: { ambient: shadowLayer9, key: shadowLayer10 }, + shadow2brand: { ambient: shadowLayer9, key: shadowLayer11 }, + shadow28brand: { ambient: shadowLayer12, key: shadowLayer13 }, + shadow4brand: { ambient: shadowLayer9, key: shadowLayer14 }, + shadow64brand: { ambient: shadowLayer12, key: shadowLayer15 }, + shadow8brand: { ambient: shadowLayer9, key: shadowLayer16 }, }; -export const darkGrayShadows = { +export const darkGrayShadows: BaseShadowAliasTokens = { shadow16: { ambient: shadowLayer1, key: shadowLayer2 }, shadow2: { ambient: shadowLayer1, key: shadowLayer3 }, shadow28: { ambient: shadowLayer4, key: shadowLayer5 }, shadow4: { ambient: shadowLayer1, key: shadowLayer6 }, shadow64: { ambient: shadowLayer4, key: shadowLayer7 }, shadow8: { ambient: shadowLayer1, key: shadowLayer8 }, - shadowBrand16: { ambient: shadowLayer9, key: shadowLayer10 }, - shadowBrand2: { ambient: shadowLayer9, key: shadowLayer11 }, - shadowBrand28: { ambient: shadowLayer12, key: shadowLayer13 }, - shadowBrand4: { ambient: shadowLayer9, key: shadowLayer14 }, - shadowBrand64: { ambient: shadowLayer12, key: shadowLayer15 }, - shadowBrand8: { ambient: shadowLayer9, key: shadowLayer16 }, + shadow16brand: { ambient: shadowLayer9, key: shadowLayer10 }, + shadow2brand: { ambient: shadowLayer9, key: shadowLayer11 }, + shadow28brand: { ambient: shadowLayer12, key: shadowLayer13 }, + shadow4brand: { ambient: shadowLayer9, key: shadowLayer14 }, + shadow64brand: { ambient: shadowLayer12, key: shadowLayer15 }, + shadow8brand: { ambient: shadowLayer9, key: shadowLayer16 }, }; From 60eb801096cd47ebce83b4efb9c24e1562344f59 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Thu, 29 Oct 2026 14:32:09 -0700 Subject: [PATCH 12/18] finish generation of fluent baseline tokens --- .changeset/design-complete-platform-tokens.md | 7 + .changeset/design-shared-generated-values.md | 6 + .changeset/design-x3-flex-defaults.md | 2 +- apps/bundle-size/baseline.json | 86 +- packages/agentic/design/references/tokens.md | 26 +- .../flex-defaults/generate-defaults.mjs | 142 +-- .../agentic/design/scripts/fluent-tokens.cts | 387 ++++++- .../flex/defaults/defaultTokens.generated.ts | 586 +++++----- .../fluentTokens.generated.android.ts | 524 +++++++++ .../defaults/fluentTokens.generated.ios.ts | 633 +++++++++++ .../defaults/fluentTokens.generated.macos.ts | 600 +++++++++++ .../fluent/defaults/fluentTokens.generated.ts | 863 +++++++++++++-- .../fluentTokens.generated.windows.ts | 544 ++++++++++ .../src/fluent/defaults/fluentTokens.test.ts | 189 ++++ scripts/package.json | 2 +- scripts/src/codegen/file.test.ts | 41 + scripts/src/codegen/file.ts | 23 +- scripts/src/codegen/valuePool.test.ts | 354 +++++++ scripts/src/codegen/valuePool.ts | 999 ++++++++++++++++++ scripts/src/index.ts | 2 + 20 files changed, 5442 insertions(+), 574 deletions(-) create mode 100644 .changeset/design-complete-platform-tokens.md create mode 100644 .changeset/design-shared-generated-values.md create mode 100644 packages/agentic/design/src/fluent/defaults/fluentTokens.generated.android.ts create mode 100644 packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ios.ts create mode 100644 packages/agentic/design/src/fluent/defaults/fluentTokens.generated.macos.ts create mode 100644 packages/agentic/design/src/fluent/defaults/fluentTokens.generated.windows.ts create mode 100644 packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts create mode 100644 scripts/src/codegen/file.test.ts create mode 100644 scripts/src/codegen/valuePool.test.ts create mode 100644 scripts/src/codegen/valuePool.ts diff --git a/.changeset/design-complete-platform-tokens.md b/.changeset/design-complete-platform-tokens.md new file mode 100644 index 0000000000..6aece2dd32 --- /dev/null +++ b/.changeset/design-complete-platform-tokens.md @@ -0,0 +1,7 @@ +--- +'@fluentui-react-native/design': patch +--- + +Generate complete Fluent color, shadow, font, and appearance token sets for Win32, Windows, macOS, iOS, and Android. +Preserve native values and fill missing tokens with same-platform equivalents, then portable same-scheme defaults. +Use platform global typography when font aliases are absent and enforce required generated token types. diff --git a/.changeset/design-shared-generated-values.md b/.changeset/design-shared-generated-values.md new file mode 100644 index 0000000000..4b016a1bf0 --- /dev/null +++ b/.changeset/design-shared-generated-values.md @@ -0,0 +1,6 @@ +--- +'@fluentui-react-native/design': patch +--- + +Shrink the generated Flex defaults by about 6 KB minified: values that repeat are emitted once, and the entries both +tones share are emitted once in a common object. The default token values are unchanged. diff --git a/.changeset/design-x3-flex-defaults.md b/.changeset/design-x3-flex-defaults.md index e6d258c069..1343774ab7 100644 --- a/.changeset/design-x3-flex-defaults.md +++ b/.changeset/design-x3-flex-defaults.md @@ -25,6 +25,6 @@ Breaking changes for Flex consumers and theme authors: `direction`, and `compositing`. `isInverseInteractionToken` moves from `color-lib` to the package root, alongside the new `INTERACTIVE_COLOR_TOKENS` and `isInteractiveColorToken`. -Root `useThemeState` consumers now bundle the interaction algorithm and generated defaults, about 28 KB raw and 7 KB +Root `useThemeState` consumers now bundle the interaction algorithm and generated defaults, about 23 KB raw and 8 KB gzip in the measured scenarios. Package sources move under `src/flex`, `src/fluent`, `src/types`, and `src/test`; export keys and conditions are unchanged. diff --git a/apps/bundle-size/baseline.json b/apps/bundle-size/baseline.json index 6f2e660d93..2dd03d2060 100644 --- a/apps/bundle-size/baseline.json +++ b/apps/bundle-size/baseline.json @@ -4,8 +4,8 @@ { "platform": "macos", "scenario": "components-button", - "rawBytes": 78670, - "gzipBytes": 20702, + "rawBytes": 72677, + "gzipBytes": 21021, "moduleCount": 77, "metafileInputCount": 243, "workspaceModules": { @@ -15,15 +15,15 @@ }, "workspaceBytes": { "@fluentui-react-native/components": 9328, - "@fluentui-react-native/design": 56720, + "@fluentui-react-native/design": 50727, "@fluentui-react-native/framework-base": 12586 } }, { "platform": "macos", "scenario": "components-catalog", - "rawBytes": 233941, - "gzipBytes": 62943, + "rawBytes": 227968, + "gzipBytes": 63316, "moduleCount": 227, "metafileInputCount": 243, "workspaceModules": { @@ -34,7 +34,7 @@ }, "workspaceBytes": { "@fluentui-react-native/components": 151331, - "@fluentui-react-native/design": 57948, + "@fluentui-react-native/design": 51975, "@fluentui-react-native/framework-base": 15305, "@fluentui-react-native/native-core": 9228 } @@ -42,8 +42,8 @@ { "platform": "macos", "scenario": "design-theme-state", - "rawBytes": 59086, - "gzipBytes": 13721, + "rawBytes": 53052, + "gzipBytes": 14104, "moduleCount": 47, "metafileInputCount": 73, "workspaceModules": { @@ -51,15 +51,15 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 57084, - "@fluentui-react-native/framework-base": 1961 + "@fluentui-react-native/design": 51047, + "@fluentui-react-native/framework-base": 1964 } }, { "platform": "macos", "scenario": "design-themed-root", - "rawBytes": 61062, - "gzipBytes": 14420, + "rawBytes": 55039, + "gzipBytes": 14785, "moduleCount": 51, "metafileInputCount": 73, "workspaceModules": { @@ -67,7 +67,7 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 59057, + "@fluentui-react-native/design": 53033, "@fluentui-react-native/framework-base": 1964 } }, @@ -88,8 +88,8 @@ { "platform": "macos", "scenario": "design-theme-state-legacy-source", - "rawBytes": 59834, - "gzipBytes": 13849, + "rawBytes": 53804, + "gzipBytes": 14217, "moduleCount": 48, "metafileInputCount": 76, "workspaceModules": { @@ -97,8 +97,8 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 57832, - "@fluentui-react-native/framework-base": 1961 + "@fluentui-react-native/design": 51799, + "@fluentui-react-native/framework-base": 1964 } }, { @@ -120,8 +120,8 @@ { "platform": "macos", "scenario": "design-legacy-theme-from-flex", - "rawBytes": 105630, - "gzipBytes": 23982, + "rawBytes": 99614, + "gzipBytes": 24350, "moduleCount": 67, "metafileInputCount": 93, "workspaceModules": { @@ -129,15 +129,15 @@ "@fluentui-react-native/framework-base": 21 }, "workspaceBytes": { - "@fluentui-react-native/design": 66417, - "@fluentui-react-native/framework-base": 2526 + "@fluentui-react-native/design": 60396, + "@fluentui-react-native/framework-base": 2527 } }, { "platform": "windows", "scenario": "components-button", - "rawBytes": 78597, - "gzipBytes": 20658, + "rawBytes": 72603, + "gzipBytes": 20994, "moduleCount": 78, "metafileInputCount": 244, "workspaceModules": { @@ -146,16 +146,16 @@ "@fluentui-react-native/framework-base": 26 }, "workspaceBytes": { - "@fluentui-react-native/components": 9328, - "@fluentui-react-native/design": 56647, + "@fluentui-react-native/components": 9330, + "@fluentui-react-native/design": 50651, "@fluentui-react-native/framework-base": 12586 } }, { "platform": "windows", "scenario": "components-catalog", - "rawBytes": 233865, - "gzipBytes": 62906, + "rawBytes": 227892, + "gzipBytes": 63279, "moduleCount": 228, "metafileInputCount": 244, "workspaceModules": { @@ -166,7 +166,7 @@ }, "workspaceBytes": { "@fluentui-react-native/components": 151331, - "@fluentui-react-native/design": 57872, + "@fluentui-react-native/design": 51899, "@fluentui-react-native/framework-base": 15305, "@fluentui-react-native/native-core": 9228 } @@ -174,8 +174,8 @@ { "platform": "windows", "scenario": "design-theme-state", - "rawBytes": 59010, - "gzipBytes": 13677, + "rawBytes": 52976, + "gzipBytes": 14063, "moduleCount": 48, "metafileInputCount": 74, "workspaceModules": { @@ -183,15 +183,15 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 57008, - "@fluentui-react-native/framework-base": 1961 + "@fluentui-react-native/design": 50971, + "@fluentui-react-native/framework-base": 1964 } }, { "platform": "windows", "scenario": "design-themed-root", - "rawBytes": 60986, - "gzipBytes": 14385, + "rawBytes": 54963, + "gzipBytes": 14740, "moduleCount": 52, "metafileInputCount": 74, "workspaceModules": { @@ -199,7 +199,7 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 58981, + "@fluentui-react-native/design": 52957, "@fluentui-react-native/framework-base": 1964 } }, @@ -220,8 +220,8 @@ { "platform": "windows", "scenario": "design-theme-state-legacy-source", - "rawBytes": 59758, - "gzipBytes": 13805, + "rawBytes": 53728, + "gzipBytes": 14172, "moduleCount": 49, "metafileInputCount": 77, "workspaceModules": { @@ -229,8 +229,8 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 57756, - "@fluentui-react-native/framework-base": 1961 + "@fluentui-react-native/design": 51723, + "@fluentui-react-native/framework-base": 1964 } }, { @@ -252,8 +252,8 @@ { "platform": "windows", "scenario": "design-legacy-theme-from-flex", - "rawBytes": 105497, - "gzipBytes": 23901, + "rawBytes": 99477, + "gzipBytes": 24271, "moduleCount": 67, "metafileInputCount": 94, "workspaceModules": { @@ -261,8 +261,8 @@ "@fluentui-react-native/framework-base": 21 }, "workspaceBytes": { - "@fluentui-react-native/design": 66284, - "@fluentui-react-native/framework-base": 2526 + "@fluentui-react-native/design": 60259, + "@fluentui-react-native/framework-base": 2527 } } ] diff --git a/packages/agentic/design/references/tokens.md b/packages/agentic/design/references/tokens.md index 6562666f3e..8f84a657e0 100644 --- a/packages/agentic/design/references/tokens.md +++ b/packages/agentic/design/references/tokens.md @@ -39,8 +39,30 @@ layers. Motion durations are milliseconds, and each easing is an `[x1, y1, x2, y colors and shadows vary by color scheme. The package's `prebuild` script (`codegen.cts`) generates the global token files from the platform -`@fluentui-react-native/design-tokens-*` packages and regenerates both mapping projections. Do not edit generated files; -change their inputs and rebuild. +`@fluentui-react-native/design-tokens-*` packages and regenerates both mapping projections. It also generates +`src/fluent/defaults/fluentTokens.generated.ts` (Win32) and its Windows, macOS, iOS, and Android variants. These modules +contain complete Fluent alias colors, shadows, and font aliases; nothing consumes them yet. The runtime pipeline +mappers and existing theme construction are unchanged. Do not edit generated files; change their inputs and rebuild. + +Every generated platform module exports `light`, `dark`, `darkGray`, `hc`, `hcLight`, `hcDark`, and `darkElevated` +color and shadow sets, plus `fontAliasTokens`. Colors satisfy `Required` (including deprecated red +aliases, mapped to danger), fonts satisfy `Required`, and shadows satisfy `BaseShadowAliasTokens`. +The generator preserves defined runtime-mapped values and additional native color states that those mappers omit. +Missing colors use same-platform semantic equivalents first, with absent interaction states falling back to rest. +Remaining gaps use portable light/dark defaults assembled from the Win32 and mobile palettes, never another +platform's system colors. Explicit equivalents live in the [Fluent token generator](../scripts/fluent-tokens.cts). + +Unsupported appearances inherit their nearest supported source: dark gray and elevated dark use dark, `hc` uses +high-contrast dark, and missing high-contrast palettes use the matching light/dark scheme. Win32's single `hc` palette +supplies both high-contrast schemes. iOS's high-contrast files contain fonts but no colors, so they inherit the matching +standard colors; this is coverage, not a synthesized or accessibility-qualified high-contrast palette. Native shadow +sets remain intact. Missing font aliases use native equivalents, or the platform's global typography ramp when no +aliases exist (macOS and Windows); legacy variant names alias the completed Fluent variants. Tests compare all +platforms against the full token interfaces and reject missing or undefined entries. + +Generated token modules emit their values through the scripts package's `ValuePool`, which minimizes the minified size: +values that repeat are hoisted into constants, and entries that several declarations share are emitted once in ancestor +objects that the declarations spread. The emitted key order is therefore not meaningful. ## Default tokens diff --git a/packages/agentic/design/scripts/flex-defaults/generate-defaults.mjs b/packages/agentic/design/scripts/flex-defaults/generate-defaults.mjs index ef2f60fd7a..cfd19fafe7 100644 --- a/packages/agentic/design/scripts/flex-defaults/generate-defaults.mjs +++ b/packages/agentic/design/scripts/flex-defaults/generate-defaults.mjs @@ -47,6 +47,8 @@ nodeModule.registerHooks({ const require = nodeModule.createRequire(import.meta.url); const { createMappingProjections, loadMappingInputs } = require('../token-mappings/check-mappings.cjs'); +// The scripts package is TypeScript source, so it loads only after the Node version check. +const { CodeExpression, expression, GeneratedFile, makeComment, ValuePool } = await import('@fluentui-react-native/scripts'); const { getInteractionColor } = await import(pathToFileURL(path.join(packageRoot, 'src/color-lib/interaction.ts')).href); const { getInteractionCompositing, getInteractionDirection, isInteractiveColorToken } = await import( pathToFileURL(path.join(packageRoot, 'src/flex/colors/interactiveTokens.ts')).href @@ -310,13 +312,6 @@ function parseShadow(value, declarations, source) { }); } -/** An identifier emitted as code rather than as a literal. */ -class Raw { - constructor(code) { - this.code = code; - } -} - function readFontWeights() { const prefix = 'export const '; const weights = new Map(); @@ -364,7 +359,7 @@ function convertValue(group, token, value, context) { throw new Error(`${source} changed from ${sourceWeight} to ${value}; review its native weight role.`); } return { - value: new Raw(identifier), + value: expression(identifier), representation: `${identifier} ('${nativeFontWeights.get(identifier)}')`, adaptation: `The x3 variable weight ${value} uses the native static ${roleName.toLowerCase()} weight.`, }; @@ -375,7 +370,7 @@ function convertValue(group, token, value, context) { if (!family) { throw new Error(`${source} has an unsupported generic family in "${value}".`); } - return { value: new Raw(family[0]), representation: family[0], adaptation: family[1] }; + return { value: expression(family[0]), representation: family[0], adaptation: family[1] }; } case 'fontSize': return { @@ -549,63 +544,12 @@ function resolveTone(tone, inputs, mappingEntries, ledger) { // Emission. -const identifierPattern = /^[A-Za-z_$][\w$]*$/; - -function quote(value) { - return `'${value.replaceAll('\\', '\\\\').replaceAll("'", "\\'")}'`; -} - -function propertyKey(key) { - return identifierPattern.test(key) ? key : quote(key); -} - -function isComposite(value) { - return typeof value === 'object' && value !== null && !(value instanceof Raw); -} - -function inline(value) { - if (value instanceof Raw) { - return value.code; - } - if (typeof value === 'string') { - return quote(value); - } - if (typeof value === 'number') { - return String(value); - } - if (Array.isArray(value)) { - return `[${value.map(inline).join(', ')}]`; - } - const entries = Object.entries(value); - return entries.length === 0 ? '{}' : `{ ${entries.map(([key, item]) => `${propertyKey(key)}: ${inline(item)}`).join(', ')} }`; -} - -/** - * Format a value starting at `column`. The outermost `forcedDepth` composite - * levels are always multiline; deeper values are inline when they fit. - */ -function format(value, depth, column, forcedDepth = 0) { - const single = inline(value); - if (!isComposite(value) || (forcedDepth <= 0 && column + single.length + 1 <= printWidth)) { - return single; - } - const indent = ' '.repeat(depth + 1); - const lines = Array.isArray(value) - ? value.map((item) => `${indent}${format(item, depth + 1, indent.length, forcedDepth - 1)},`) - : Object.entries(value).map(([key, item]) => { - const prefix = `${indent}${propertyKey(key)}: `; - return `${prefix}${format(item, depth + 1, prefix.length, forcedDepth - 1)},`; - }); - const [open, close] = Array.isArray(value) ? ['[', ']'] : ['{', '}']; - return `${open}\n${lines.join('\n')}\n${' '.repeat(depth)}${close}`; -} - -function collectRawIdentifiers(value, identifiers) { - if (value instanceof Raw) { +function collectIdentifiers(value, identifiers) { + if (value instanceof CodeExpression) { identifiers.add(value.code); - } else if (isComposite(value)) { + } else if (typeof value === 'object' && value !== null) { for (const item of Object.values(value)) { - collectRawIdentifiers(item, identifiers); + collectIdentifiers(item, identifiers); } } } @@ -615,51 +559,47 @@ function formatImport(names, from) { return single.length <= printWidth ? [single] : ['import {', ...names.map((name) => ` ${name},`), `} from '${from}';`]; } -function emitDefaults(pin, files, toneTokens) { - const groupNames = Object.keys(toneTokens[0].tokens).filter((group) => group !== 'color'); - const shared = {}; - for (const group of groupNames) { - if (toneTokens.every(({ tokens }) => sameValue(tokens[group], toneTokens[0].tokens[group]))) { - shared[group] = toneTokens[0].tokens[group]; - } +function nameValue(value) { + if (typeof value === 'object' && value !== null && 'blur' in value) { + return 'shadowLayer'; } + return undefined; +} + +/** + * Emit the tone defaults through a value pool, which shares the entries the tones hold in common through ancestor + * objects and hoists repeated values into constants, keeping the minified module small. + */ +function emitDefaults(pin, files, toneTokens) { const identifiers = new Set(); - collectRawIdentifiers( + collectIdentifiers( toneTokens.map(({ tokens }) => tokens), identifiers, ); - - const lines = [ - `// Generated by ${generatorPath}. Do not edit; run \`yarn gen:flex-defaults\`.`, - `// Source: ${pin.repository}@${pin.commit}`, - ...tones.map((tone) => `// ${tone.name}: ${files[tone.name].join(', ')}`), - `// Generic sources: ${mappingPath}`, - `// Coverage: ${path.relative(packageRoot, outputPaths.ledger).replaceAll('\\', '/')}`, - '', + const file = new GeneratedFile(outputPaths.defaults); + file.header = makeComment( + [ + `Generated by ${generatorPath}. Do not edit; run \`yarn gen:flex-defaults\`.`, + `Source: ${pin.repository}@${pin.commit}`, + ...tones.map((tone) => ` ${tone.name}: ${files[tone.name].join(', ')}`), + `Generic sources: ${mappingPath}`, + `Coverage: ${path.relative(packageRoot, outputPaths.ledger).replaceAll('\\', '/')}`, + ], + 'line', + ); + const pool = new ValuePool({ name: nameValue }).reserve('CompleteFlexTokenInput'); + for (const { tone, tokens } of toneTokens) { + pool.declare(tone.exportName, tokens, { + type: 'CompleteFlexTokenInput', + comment: `The x3 ${tone.name}-tone defaults. Omitted interaction states are computed from rest.`, + }); + } + const imports = [ ...formatImport([...identifiers].sort(), '../../tokens/global.generated'), "import type { CompleteFlexTokenInput } from '../tokens.types';", - '', - `const sharedTokens = ${format(shared, 0, 0, 2)} satisfies Partial>;`, ]; - - for (const { tone, tokens } of toneTokens) { - const own = { color: tokens.color }; - for (const group of groupNames) { - if (!Object.hasOwn(shared, group)) { - own[group] = tokens[group]; - } - } - const [open, ...body] = format(own, 0, 0, 2).split('\n'); - body[body.length - 1] += ';'; - lines.push( - '', - `/** The x3 ${tone.name}-tone defaults. Omitted interaction states are computed from rest. */`, - `export const ${tone.exportName}: CompleteFlexTokenInput = ${open}`, - ' ...sharedTokens,', - ...body, - ); - } - return `${lines.join('\n')}\n`; + file.add(`\n${imports.join('\n')}\n\n`, pool); + return file.render(); } function createLedger(supportedTypePaths, unsupportedTypePaths) { diff --git a/packages/agentic/design/scripts/fluent-tokens.cts b/packages/agentic/design/scripts/fluent-tokens.cts index cd6670b438..9f71395453 100644 --- a/packages/agentic/design/scripts/fluent-tokens.cts +++ b/packages/agentic/design/scripts/fluent-tokens.cts @@ -1,97 +1,408 @@ -import type { ShadowTokens, ShadowLayer } from './design-token.types'; -const { GeneratedFile, Ramp } = require('@fluentui-react-native/scripts'); -import type { GeneratedFile as GeneratedFileType, Ramp as RampType } from '@fluentui-react-native/scripts'; +import type { ValuePath } from '@fluentui-react-native/scripts'; +import type { AliasColorTokens } from '../src/fluent/types/Color.types'; +import type { Variants, VariantValue } from '../src/fluent/types/Typography.types'; +const { GeneratedFile, ValuePool, expression, makeComment } = require('@fluentui-react-native/scripts'); const path = require('node:path'); +const { mapPipelineToShadow } = require('../src/fluent/mapPipelineToShadow.ts'); + +type Appearance = 'light' | 'dark' | 'darkGray' | 'hc' | 'hcLight' | 'hcDark' | 'darkElevated'; +type ColorKey = keyof AliasColorTokens; +type PipelineTokens = Record>; type PlatformData = { - paths: Record; + /** Token package directory for each supported appearance. Light supplies the font aliases. */ + paths: Partial> & { light: string; dark: string }; + /** Pipeline mapper module in src/fluent for the platform. */ + mapper: string; filename: string; }; +const appearanceFallbacks: Record, Appearance> = { + darkGray: 'dark', + hc: 'hcDark', + hcLight: 'light', + hcDark: 'dark', + darkElevated: 'dark', +}; +const appearances: Appearance[] = ['light', 'dark', 'darkGray', 'hc', 'hcLight', 'hcDark', 'darkElevated']; + const platformPaths: Record = { win32: { paths: { - dark: '@fluentui-react-native/design-tokens-win32/black/', light: '@fluentui-react-native/design-tokens-win32/colorful/', - hc: '@fluentui-react-native/design-tokens-win32/hc/', + dark: '@fluentui-react-native/design-tokens-win32/black/', darkGray: '@fluentui-react-native/design-tokens-win32/darkgray/', + hc: '@fluentui-react-native/design-tokens-win32/hc/', }, + mapper: 'mapPipelineToTheme.ts', filename: 'fluentTokens.generated.ts', }, macos: { paths: { - dark: '@fluentui-react-native/design-tokens-macos/dark/', light: '@fluentui-react-native/design-tokens-macos/light/', + dark: '@fluentui-react-native/design-tokens-macos/dark/', hcLight: '@fluentui-react-native/design-tokens-macos/hclight/', hcDark: '@fluentui-react-native/design-tokens-macos/hcdark/', }, + mapper: 'mapPipelineToTheme.ts', filename: 'fluentTokens.generated.macos.ts', }, + windows: { + paths: { + light: '@fluentui-react-native/design-tokens-windows/light/', + dark: '@fluentui-react-native/design-tokens-windows/dark/', + }, + mapper: 'mapPipelineToTheme.ts', + filename: 'fluentTokens.generated.windows.ts', + }, android: { paths: { - dark: '@fluentui-react-native/design-tokens-android/dark/', light: '@fluentui-react-native/design-tokens-android/light/', + dark: '@fluentui-react-native/design-tokens-android/dark/', }, + mapper: 'mapPipelineToTheme.android.ts', filename: 'fluentTokens.generated.android.ts', }, ios: { paths: { - dark: '@fluentui-react-native/design-tokens-ios/dark/', light: '@fluentui-react-native/design-tokens-ios/light/', + dark: '@fluentui-react-native/design-tokens-ios/dark/', hcLight: '@fluentui-react-native/design-tokens-ios/hclight/', hcDark: '@fluentui-react-native/design-tokens-ios/hcdark/', darkElevated: '@fluentui-react-native/design-tokens-ios/elevateddark/', }, + mapper: 'mapPipelineToTheme.ios.ts', filename: 'fluentTokens.generated.ios.ts', }, }; -function addShadowLayer(file: GeneratedFileType, ramp: RampType, layer: ShadowLayer) { - const { x, y, color, blur } = layer; - file.add(ramp.add('shadowLayer', [`{ x: ${x}, y: ${y}, blur: ${blur}, color: `, ramp.add('color', `'${color}'`), ' }'])); +const colorEquivalents: Partial> = { + neutralForeground4: ['neutralForeground3'], + neutralForegroundDisabled: ['neutralForegroundDisabled1'], + neutralForegroundDisabled1: ['neutralForegroundDisabled'], + neutralForegroundDisabled2: ['neutralForegroundDisabled1'], + neutralForegroundOnBrand: ['neutralForegroundOnColor'], + neutralForegroundOnColor: ['neutralForegroundOnBrand'], + neutralForegroundInverted: ['neutralForegroundOnColor'], + neutralForegroundInvertedLink: ['neutralForegroundInverted'], + brandForegroundLink: ['brandForeground1'], + compoundBrandForeground1: ['brandForeground1'], + brandForeground2: ['brandForeground1'], + brandForegroundTint: ['brandForeground2'], + brandForeground1Disabled: ['brandForegroundDisabled1', 'neutralForegroundDisabled'], + brandForegroundDisabled1: ['brandForeground1Disabled', 'neutralForegroundDisabled1'], + brandForegroundDisabled2: ['brandForegroundDisabled1'], + neutralBackgroundCanvas: ['neutralBackground1'], + neutralBackgroundLightStaticDisabled: ['neutralBackgroundDisabled'], + brandBackground2: ['brandBackground'], + brandBackground3: ['brandBackground2'], + brandBackgroundTint: ['brandBackground2'], + brandBackgroundInverted: ['neutralBackgroundInverted'], + brandBackgroundInvertedDisabled: ['neutralBackgroundDisabled'], + brandBackgroundDisabled: ['neutralBackgroundDisabled'], + compoundBrandBackground1: ['brandBackground'], + brandBackgroundStatic: ['brandBackground'], + neutralStroke3: ['neutralStroke2'], + neutralStrokeFocus1: ['strokeFocus1'], + neutralStrokeFocus2: ['strokeFocus2'], + strokeFocus1: ['neutralStrokeFocus1'], + strokeFocus2: ['neutralStrokeFocus2'], + brandStroke2: ['brandStrokeTint', 'brandStroke1'], + brandStrokeTint: ['brandStroke2'], + compoundBrandStroke1: ['brandStroke1'], + dangerStroke1: ['dangerBorder1', 'dangerForeground1'], + successStroke1: ['successBorder1', 'successForeground1'], + warningStroke1: ['warningBorder1', 'warningForeground1'], + severeStroke1: ['severeBorder1', 'severeForeground1'], + dangerBorder1: ['dangerStroke1'], + successBorder1: ['successStroke1'], + warningBorder1: ['warningStroke1'], + severeBorder1: ['severeStroke1'], + presenceAway: ['warningForeground1'], + presenceDnd: ['dangerForeground1'], + presenceAvailable: ['successForeground1'], + presenceOof: ['outofofficeForeground1'], + redBackground1: ['dangerBackground1'], + redBackground2: ['dangerBackground2'], + redBackground3: ['dangerBackground3'], + redForeground1: ['dangerForeground1'], + redForeground2: ['dangerForeground2'], + redForeground3: ['dangerForeground3'], + redBorderActive: ['dangerBorderActive'], + redBorder1: ['dangerBorder1'], + redBorder2: ['dangerBorder2'], +}; + +function colorCandidates(key: ColorKey): ColorKey[] { + if (colorEquivalents[key]) { + return colorEquivalents[key]; + } + const state = /(?:Brand)?(?:Hover|Pressed|Selected|Disabled)$/.exec(key); + if (!state) { + return []; + } + const rest = key.slice(0, state.index) as ColorKey; + return [...(colorEquivalents[rest] ?? []).map((candidate) => (candidate + state[0]) as ColorKey), rest]; } -function adjustShadowName(name: string) { - if (name.includes('Brand')) { - // shadowBrand16 needs to become shadow16brand - return name.replace('Brand', '') + 'brand'; +function definedEntries(values: Record): Record { + return Object.fromEntries(Object.entries(values).filter((entry): entry is [string, T] => entry[1] !== undefined)); +} + +function mapColors(tokens: PipelineTokens, mapper: string, keys?: Set): Record { + const { mapPipelineToTheme } = require(`../src/fluent/${mapper}`); + const colors = definedEntries(mapPipelineToTheme(tokens)); + // Keep native states that a legacy mapper omits, but do not add keys outside the alias contract. + if (keys) { + for (const [token, states] of Object.entries(tokens)) { + if (!('rest' in states)) { + continue; + } + const name = token === 'brandBackground1' ? 'brandBackground' : token; + for (const [state, value] of Object.entries(states)) { + const key = ( + state === 'rest' + ? name + : name === 'transparentStroke' && state === 'hover' + ? 'transparentStrokeInteractive' + : name + state[0].toUpperCase() + state.slice(1) + ) as ColorKey; + if (keys.has(key) && colors[key] === undefined) { + colors[key] = value as string; + } + } + } } - return name; + return colors; } -function processShadowTokens(prefix: string, platformPath: string, file: GeneratedFileType, ramp: RampType) { - const shadowTokens: ShadowTokens = require(`${platformPath}tokens-shadow.json`); - const layerNames = ['ambient', 'key']; - file.add(`export const ${prefix}Shadows: BaseShadowAliasTokens = {\n`); - for (const [name, layers] of Object.entries(shadowTokens)) { - file.add(` ${adjustShadowName(name)}: { `); - for (const [index, layer] of layerNames.entries()) { - file.add(`${layer}: `); - addShadowLayer(file, ramp, layers[index]); - if (index < layerNames.length - 1) { - file.add(', '); +function completeColors(native: Record, fallback: Record, keys: Set) { + function fromNative(key: ColorKey, visiting = new Set()): string | undefined { + if (native[key] !== undefined) { + return native[key]; + } + if (visiting.has(key)) { + return undefined; + } + visiting.add(key); + for (const candidate of colorCandidates(key)) { + const value = fromNative(candidate, visiting); + if (value !== undefined) { + return value; } } - file.add(' },\n'); + return undefined; } - file.add('};\n'); + return Object.fromEntries( + [...keys].map((key) => { + const value = fromNative(key) ?? fallback[key]; + if (value === undefined) { + throw new Error(`Missing Fluent color token: ${key}`); + } + return [key, value]; + }), + ); } -function generatePlatformFluentTokens(platformData: PlatformData) { +// Desktop pipelines without font aliases use their own global ramp, not another platform's font family. +const fontRamp: Record = { + caption1: [100, 'regular'], + caption1Strong: [100, 'semibold'], + caption2: [100, 'regular'], + body1: [200, 'regular'], + body1Strong: [200, 'semibold'], + body2: [300, 'regular'], + body2Strong: [300, 'semibold'], + subtitle1: [500, 'regular'], + subtitle1Strong: [500, 'semibold'], + subtitle2: [400, 'regular'], + subtitle2Strong: [400, 'semibold'], + title1: [700, 'regular'], + title1Strong: [700, 'semibold'], + title2: [600, 'regular'], + title3: [500, 'regular'], + largeTitle: [900, 'regular'], + display: [900, 'semibold'], +}; +const fontEquivalents: Record = { + caption1Strong: 'caption1', + caption2: 'caption1', + subtitle1: 'title2', + subtitle1Strong: 'title2', + subtitle2: 'title3', + subtitle2Strong: 'title3', + title1Strong: 'title1', + title2: 'subtitle1', + title3: 'subtitle2', +}; +const legacyFontAliases: Record = { + captionStandard: 'caption1', + secondaryStandard: 'body1', + secondarySemibold: 'body1Strong', + bodyStandard: 'body2', + bodySemibold: 'body2Strong', + subheaderStandard: 'subtitle2', + subheaderSemibold: 'subtitle2Strong', + headerStandard: 'subtitle1', + headerSemibold: 'subtitle1Strong', + heroStandard: 'title1', + heroSemibold: 'title1Strong', + heroLargeStandard: 'largeTitle', + heroLargeSemibold: 'display', +}; + +function mapFonts(platformData: PlatformData): Record { + const { mapFontPipelineToTheme } = require(`../src/fluent/${platformData.mapper}`); + const { font } = require(`${platformData.paths.light}tokens-global.json`); + const defaults = Object.fromEntries( + Object.entries(fontRamp).map(([name, [size, weight]]) => [ + name, + { fontFamily: font.family.base ?? font.family.default, fontSize: font[`size${size}`], fontWeight: font.weight[weight] }, + ]), + ); + const tokens = { ...defaults, ...require(`${platformData.paths.light}tokens-aliases.json`) }; + const native: Partial = mapFontPipelineToTheme(tokens); + const variants = { ...native } as Record; + for (const key of Object.keys(fontRamp)) { + if (!variants[key]) { + const equivalent = native[fontEquivalents[key] as keyof Variants]; + const token = tokens[key]; + variants[key] = equivalent + ? { ...equivalent, ...(key.endsWith('Strong') ? { weight: font.weight.semibold } : {}) } + : { face: 'primary', size: token.fontSize, weight: token.fontWeight }; + } + } + for (const [key, alias] of Object.entries(legacyFontAliases)) { + variants[key] = variants[alias]; + } + return variants; +} + +function resolveAppearance(platformData: PlatformData, appearance: Appearance): string { + if (platformData.paths[appearance]) { + return platformData.paths[appearance]; + } + if ((appearance === 'hcLight' || appearance === 'hcDark') && platformData.paths.hc) { + return platformData.paths.hc; + } + return resolveAppearance(platformData, appearanceFallbacks[appearance as keyof typeof appearanceFallbacks]); +} + +function appearanceScheme(platformData: PlatformData, appearance: Appearance): 'light' | 'dark' { + const source = resolveAppearance(platformData, appearance); + return source === platformData.paths.light || source === platformData.paths.hcLight ? 'light' : 'dark'; +} + +function readAliases(platformData: PlatformData, appearance: Appearance): PipelineTokens { + const scheme = appearanceScheme(platformData, appearance); + const base: PipelineTokens = require(`${platformData.paths[scheme]}tokens-aliases.json`); + const tokens: PipelineTokens = require(`${resolveAppearance(platformData, appearance)}tokens-aliases.json`); + return Object.fromEntries( + [...new Set([...Object.keys(base), ...Object.keys(tokens)])].map((key) => [key, { ...base[key], ...tokens[key] }]), + ); +} + +const platformColorPattern = /^PlatformColor\(([A-Za-z][A-Za-z0-9]*)\)$/; + +/** + * Replace the pipeline's `PlatformColor(Name)` strings with PlatformColor calls, as processAliasTokens does at runtime + * with win32 color names. + */ +function toCodeValues(value: unknown, platformColors: Set): unknown { + if (typeof value === 'string') { + const match = platformColorPattern.exec(value); + if (!match) { + if (value.includes('PlatformColor')) { + throw new Error(`Unsupported platform color value: ${value}`); + } + return value; + } + platformColors.add(match[1]); + return expression(`PlatformColor('${match[1]}')`, { pure: true, name: `platformColor${match[1]}` }); + } + if (Array.isArray(value)) { + return value.map((item) => toCodeValues(item, platformColors)); + } + if (value && typeof value === 'object') { + return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, toCodeValues(item, platformColors)])); + } + return value; +} + +function nameValue(value: unknown, valuePath: ValuePath): string | undefined { + if (value && typeof value === 'object' && 'blur' in value) { + return 'shadowLayer'; + } + return typeof value === 'string' && valuePath[valuePath.length - 1] === 'weight' ? `fontWeight${value}` : undefined; +} + +function generatePlatformFluentTokens( + platformData: PlatformData, + colorKeys: Set, + fallbackColors: Record<'light' | 'dark', Record>, +) { const target = path.join(__dirname, '../src/fluent/defaults', platformData.filename); const generatedFile = new GeneratedFile(target); - generatedFile.add(`import type { BaseShadowAliasTokens } from '../types/Shadow.types';\n\n`); - const ramp = new Ramp(); - generatedFile.add(ramp); - for (const [prefix, platformPath] of Object.entries(platformData.paths)) { - processShadowTokens(prefix, platformPath, generatedFile, ramp); + generatedFile.header = makeComment([ + 'WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually.', + 'Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults.', + 'Unsupported appearances inherit the closest supported appearance. Shared values are emitted once.', + ]); + const pool = new ValuePool({ name: nameValue }); + const typeImports = { + AliasColorTokens: '../types/Color.types', + BaseShadowAliasTokens: '../types/Shadow.types', + Variants: '../types/Typography.types', + }; + pool.reserve(...Object.keys(typeImports)); + + const platformColors = new Set(); + for (const appearance of appearances) { + const packagePath = resolveAppearance(platformData, appearance); + pool.declare(`${appearance}Shadows`, mapPipelineToShadow(require(`${packagePath}tokens-shadow.json`)), { + type: 'BaseShadowAliasTokens', + }); + } + for (const appearance of appearances) { + const native = mapColors(readAliases(platformData, appearance), platformData.mapper, colorKeys); + const scheme = appearanceScheme(platformData, appearance); + const colors = completeColors(native, fallbackColors[scheme], colorKeys); + pool.declare(`${appearance}AliasColors`, toCodeValues(colors, platformColors), { type: 'Required' }); + } + pool.declare('fontAliasTokens', mapFonts(platformData), { + type: 'Required', + comment: 'Font aliases from the light appearance, completed with native equivalents and the platform global ramp.', + }); + + const imports = Object.entries(typeImports).map(([name, from]) => `import type { ${name} } from '${from}';\n`); + if (platformColors.size > 0) { + imports.unshift("import { PlatformColor } from 'react-native';\n\n"); } - ramp.resolveEntries(); + generatedFile.add(...imports, '\n', pool); generatedFile.commit(); } function codegenFluentTokens() { - generatePlatformFluentTokens(platformPaths.win32); + const colorKeys = new Set(Object.keys(colorEquivalents) as ColorKey[]); + for (const platform of Object.values(platformPaths)) { + for (const key of Object.keys(mapColors(readAliases(platform, 'light'), platform.mapper))) { + colorKeys.add(key as ColorKey); + } + } + const fallbackColors = Object.fromEntries( + (['light', 'dark'] as const).map((appearance) => { + const colors = Object.assign( + {}, + ...['android', 'ios', 'win32'].map((platform) => + mapColors(readAliases(platformPaths[platform], appearance), platformPaths[platform].mapper, colorKeys), + ), + ); + return [appearance, completeColors(colors, {}, colorKeys)]; + }), + ) as Record<'light' | 'dark', Record>; + for (const platform of Object.values(platformPaths)) { + generatePlatformFluentTokens(platform, colorKeys, fallbackColors); + } } module.exports = { codegenFluentTokens }; diff --git a/packages/agentic/design/src/flex/defaults/defaultTokens.generated.ts b/packages/agentic/design/src/flex/defaults/defaultTokens.generated.ts index 25aa8ae64d..c99af74464 100644 --- a/packages/agentic/design/src/flex/defaults/defaultTokens.generated.ts +++ b/packages/agentic/design/src/flex/defaults/defaultTokens.generated.ts @@ -15,63 +15,207 @@ import { } from '../../tokens/global.generated'; import type { CompleteFlexTokenInput } from '../tokens.types'; -const sharedTokens = { +const inverted = 'inverted'; +const rgb000000 = '#000000'; +const rgb00000008 = '#00000008'; +const rgb0000000d = '#0000000d'; +const rgb0000000f = '#0000000f'; +const rgb00000014 = '#00000014'; +const rgb0000001a = '#0000001a'; +const rgb0000001f = '#0000001f'; +const rgb00000029 = '#00000029'; +const rgb000000db = '#000000db'; +const rgb0b0600e1 = '#0b0600e1'; +const rgb0b497f = '#0b497f'; +const rgb0c5722 = '#0c5722'; +const rgb242424 = '#242424'; +const rgb28231e = '#28231e'; +const rgb294482 = '#294482'; +const rgb2f95f4 = '#2f95f4'; +const rgb32ad52 = '#32ad52'; +const rgb345200 = '#345200'; +const rgb3c3c3c80 = '#3c3c3c80'; +const rgb484848 = '#484848'; +const rgb523778 = '#523778'; +const rgb524800 = '#524800'; +const rgb5c8df8 = '#5c8df8'; +const rgb5dce97 = '#5dce97'; +const rgb6da603 = '#6da603'; +const rgb6f2b53 = '#6f2b53'; +const rgb762f0e = '#762f0e'; +const rgb772b28 = '#772b28'; +const rgb929292 = '#929292'; +const rgba575e8 = '#a575e8'; +const rgbbaedc1 = '#baedc1'; +const rgbc6e1ff = '#c6e1ff'; +const rgbcbff93 = '#cbff93'; +const rgbcd4808 = '#cd4808'; +const rgbcedeff = '#cedeff'; +const rgbd961a6 = '#d961a6'; +const rgbdedede = '#dedede'; +const rgbe4d6ff = '#e4d6ff'; +const rgbe55e7a = '#e55e7a'; +const rgbe56738 = '#e56738'; +const rgbe6ffcf = '#e6ffcf'; +const rgbe7615b = '#e7615b'; +const rgbe7fce9 = '#e7fce9'; +const rgbeef6ff = '#eef6ff'; +const rgbf0f5ff = '#f0f5ff'; +const rgbf5f5f5 = '#f5f5f5'; +const rgbf7f3ff = '#f7f3ff'; +const rgbfb966e = '#fb966e'; +const rgbfbdf06 = '#fbdf06'; +const rgbfc9571 = '#fc9571'; +const rgbfef2ee = '#fef2ee'; +const rgbffcee6 = '#ffcee6'; +const rgbffd2cd = '#ffd2cd'; +const rgbffd3c2 = '#ffd3c2'; +const rgbffed85 = '#ffed85'; +const rgbfff1f7 = '#fff1f7'; +const rgbfff2f0 = '#fff2f0'; +const rgbfff7c4 = '#fff7c4'; +const rgbffffff = '#ffffff'; +const rgbffffff00 = '#ffffff00'; +const rgbffffff14 = '#ffffff14'; +const rgbffffff80 = '#ffffff80'; + +const backgroundNeutralDisabled = [rgb00000008, '#ffffff07'] as const; +const backgroundNeutralSoft1 = [rgb00000014, '#ffffff1f'] as const; +const backgroundNeutralSoft2 = ['#4d200028', '#ffe3cb40'] as const; +const backgroundNeutralSubtle = ['#6c31001a', '#fff4ef14'] as const; +const backgroundNeutralTransparent1 = ['#24242400', rgbffffff00] as const; +const backgroundNeutralTransparent2 = ['#28231e00', rgbffffff00] as const; +const easingFunctionalEnter = [0, 0, 0, 1] as const; +const easingFunctionalExit = [0.6, 0, 0.75, 0.4] as const; +const easingFunctionalTransition = [0.33, 0, 0, 1] as const; +const foregroundNeutralPrimary = [rgb0b0600e1, '#fff7f2e3'] as const; +const rest1 = ['#6f6f6f', rgb929292] as const; +const rest2 = ['#e9e9e980', rgb3c3c3c80] as const; +const rest3 = ['#0000006d', '#ffffff61'] as const; +const rest4 = ['#1e0d009a', '#ffeee39a'] as const; +const shadowLayer1 = { x: 0, y: 0, blur: 2, color: rgb0000001a } as const; +const shadowLayer2 = { x: 0, y: 0, blur: 2, color: '#00000033' } as const; +const shadowLayer3 = { x: 0, y: 8, blur: 16, color: rgb0000001f } as const; +const shadowLayer4 = { x: 0, y: 8, blur: 16, color: rgb00000008 } as const; +const strokeNeutralSoft2 = ['#250f0076', '#ffe6d35c'] as const; + +const backgroundDangerLoud = { rest: ['#c02e56', rgbe55e7a], type: inverted } as const; +const backgroundNeutralHeavy1 = { rest: [rgb242424, rgbffffff], type: inverted } as const; +const backgroundNeutralHeavy2 = { rest: [rgb28231e, rgbffffff], type: inverted } as const; +const backgroundNeutralLoud1 = { rest: rest1, type: inverted } as const; +const backgroundNeutralLoud2 = { rest: rest4, type: inverted } as const; +const backgroundSuccessLoud = { rest: ['#008455', '#05ad72'], type: inverted } as const; +const strokeBrandOnloud = { rest: [rgbffffff, rgb242424], type: inverted } as const; +const strokeNeutralLoud = { rest: ['#776d65', '#9a9089'], type: inverted } as const; +const strokeNeutralOnloud1 = { rest: [rgbffffff, rgb000000db], type: inverted } as const; +const strokeNeutralOnloud2 = { rest: [rgbffffff, rgb0b0600e1], type: inverted } as const; +const strokeNeutralSoft1 = { rest: rest3, hover: ['#02020277', '#ffffff69'], pressed: ['#04040481', '#ffffff70'] } as const; +const strokeNeutralSubtle = { rest: ['#00000021', '#ffffff48'], pressed: ['#05050535', '#ffffff57'] } as const; + +const sharedFlexTokenInputColor = { + backgroundDangerLoud, + backgroundDangerSoft: ['#ffe3e6', '#5a2932'], + backgroundDangerSubtle: ['#fff1f3', '#402529'], + backgroundWarningLoud: { rest: ['#bb4001', rgbe56738], type: inverted }, + backgroundWarningSoft: ['#ffe5dc', '#592c1c'], + backgroundWarningSubtle: ['#fff2ee', '#40261d'], + backgroundSuccessLoud, + backgroundSuccessSoft: ['#c9f8dd', '#0c462d'], + backgroundSuccessSubtle: ['#e3fcee', '#193426'], + strokeDangerLoud: backgroundDangerLoud, + strokeDangerSoft: [rgbe55e7a, '#d14164'], + strokeDangerSubtle: ['#ffd0d6', '#76293a'], + strokeDangerOnloud: strokeBrandOnloud, + strokeWarningLoud: { rest: [rgbcd4808, rgbe56738], type: inverted }, + strokeWarningSoft: [rgbfc9571, rgbcd4808], + strokeWarningSubtle: ['#ffd3c4', '#762e12'], + strokeWarningOnloud: strokeBrandOnloud, + strokeSuccessLoud: backgroundSuccessLoud, + strokeSuccessSoft: [rgb5dce97, '#008e5c'], + strokeSuccessSubtle: ['#b1efcc', '#025636'], + strokeSuccessOnloud: strokeBrandOnloud, + foregroundDangerPrimary: ['#a62147', '#fd8ea1'], + foregroundDangerOnloud: strokeNeutralOnloud1, + foregroundWarningPrimary: ['#a93901', rgbfc9571], + foregroundWarningOnloud: strokeNeutralOnloud1, + foregroundSuccessPrimary: ['#017048', rgb5dce97], + foregroundSuccessOnloud: strokeNeutralOnloud1, + fixedWhite: rgbffffff, + fixedBlack: rgb000000, + expressionAchromaticHeavy: [rgb000000, rgbffffff], + expressionAchromaticSubtle: [rgbffffff, rgb000000], + expressionGrayHeavy: [rgb484848, rgbf5f5f5], + expressionGrayLoud: [rgb929292, rgbdedede], + expressionGraySoft: [rgbdedede, rgb929292], + expressionGraySubtle: [rgbf5f5f5, rgb484848], + expressionNavyHeavy: [rgb294482, rgbf0f5ff], + expressionNavyLoud: [rgb5c8df8, rgbcedeff], + expressionNavySoft: [rgbcedeff, rgb5c8df8], + expressionNavySubtle: [rgbf0f5ff, rgb294482], + expressionBlueHeavy: [rgb0b497f, rgbeef6ff], + expressionBlueLoud: [rgb2f95f4, rgbc6e1ff], + expressionBlueSoft: [rgbc6e1ff, rgb2f95f4], + expressionBlueSubtle: [rgbeef6ff, rgb0b497f], + expressionGreenHeavy: [rgb0c5722, rgbe7fce9], + expressionGreenLoud: [rgb32ad52, rgbbaedc1], + expressionGreenSoft: [rgbbaedc1, rgb32ad52], + expressionGreenSubtle: [rgbe7fce9, rgb0c5722], + expressionLimeHeavy: [rgb345200, rgbe6ffcf], + expressionLimeLoud: [rgb6da603, rgbcbff93], + expressionLimeSoft: [rgbcbff93, rgb6da603], + expressionLimeSubtle: [rgbe6ffcf, rgb345200], + expressionYellowHeavy: [rgb524800, rgbfff7c4], + expressionYellowLoud: [rgbfbdf06, rgbffed85], + expressionYellowSoft: [rgbffed85, rgbfbdf06], + expressionYellowSubtle: [rgbfff7c4, rgb524800], + expressionPumpkinHeavy: [rgb762f0e, rgbfef2ee], + expressionPumpkinLoud: [rgbfb966e, rgbffd3c2], + expressionPumpkinSoft: [rgbffd3c2, rgbfb966e], + expressionPumpkinSubtle: [rgbfef2ee, rgb762f0e], + expressionRedHeavy: [rgb772b28, rgbfff2f0], + expressionRedLoud: [rgbe7615b, rgbffd2cd], + expressionRedSoft: [rgbffd2cd, rgbe7615b], + expressionRedSubtle: [rgbfff2f0, rgb772b28], + expressionPinkHeavy: [rgb6f2b53, rgbfff1f7], + expressionPinkLoud: [rgbd961a6, rgbffcee6], + expressionPinkSoft: [rgbffcee6, rgbd961a6], + expressionPinkSubtle: [rgbfff1f7, rgb6f2b53], + expressionPurpleHeavy: [rgb523778, rgbf7f3ff], + expressionPurpleLoud: [rgba575e8, rgbe4d6ff], + expressionPurpleSoft: [rgbe4d6ff, rgba575e8], + expressionPurpleSubtle: [rgbf7f3ff, rgb523778], + overlayNeutralTranslucent: ['#00000026', '#00000099'], + materialBackgroundThick: ['#fffffff1', '#262626ea'], + materialBackgroundRegular: ['#ffffffd7', '#2f2f2fd1'], + materialBackgroundThin: ['#ffffff7e', '#3434348b'], + backgroundNeutralDisabled, + backgroundNeutralHeavyDisabled: [rgb0000001a, '#ffffff20'], + strokeNeutralDisabled: [rgb00000014, '#ffffff24'], + foregroundNeutralDisabled: rest3, + strokeFocusInner: [rgbffffff, rgb000000], + strokeFocusOuter: [rgb000000, rgbffffff], + shadow: rgb000000, +} as const; + +const sharedFlexTokenInput = { shadow: { - lowest: [ - [{ x: 0, y: 0, blur: 2, color: '#0000001a' }, { x: 0, y: 1, blur: 2, color: '#0000000d' }], - [{ x: 0, y: 0, blur: 2, color: '#00000033' }, { x: 0, y: 1, blur: 2, color: '#0000001a' }], - ], - lower: [ - [{ x: 0, y: 0, blur: 2, color: '#0000001a' }, { x: 0, y: 2, blur: 4, color: '#00000014' }], - [{ x: 0, y: 0, blur: 2, color: '#00000033' }, { x: 0, y: 2, blur: 4, color: '#00000029' }], - ], + lowest: [[shadowLayer1, { x: 0, y: 1, blur: 2, color: rgb0000000d }], [shadowLayer2, { x: 0, y: 1, blur: 2, color: rgb0000001a }]], + lower: [[shadowLayer1, { x: 0, y: 2, blur: 4, color: rgb00000014 }], [shadowLayer2, { x: 0, y: 2, blur: 4, color: rgb00000029 }]], low: [ - [ - { x: 0, y: 0, blur: 2, color: '#0000001a' }, - { x: 0, y: 2, blur: 4, color: '#00000008' }, - { x: 0, y: 4, blur: 8, color: '#00000014' }, - ], - [ - { x: 0, y: 0, blur: 2, color: '#00000033' }, - { x: 0, y: 2, blur: 4, color: '#0000001f' }, - { x: 0, y: 4, blur: 8, color: '#00000029' }, - ], + [shadowLayer1, { x: 0, y: 2, blur: 4, color: rgb00000008 }, { x: 0, y: 4, blur: 8, color: rgb00000014 }], + [shadowLayer2, { x: 0, y: 2, blur: 4, color: rgb0000001f }, { x: 0, y: 4, blur: 8, color: rgb00000029 }], ], high: [ - [ - { x: 0, y: 0, blur: 2, color: '#0000001a' }, - { x: 0, y: 4, blur: 8, color: '#00000008' }, - { x: 0, y: 8, blur: 16, color: '#0000000f' }, - ], - [ - { x: 0, y: 0, blur: 2, color: '#00000033' }, - { x: 0, y: 4, blur: 8, color: '#0000001f' }, - { x: 0, y: 8, blur: 16, color: '#0000001f' }, - ], + [shadowLayer1, { x: 0, y: 4, blur: 8, color: rgb00000008 }, { x: 0, y: 8, blur: 16, color: rgb0000000f }], + [shadowLayer2, { x: 0, y: 4, blur: 8, color: rgb0000001f }, shadowLayer3], ], higher: [ - [ - { x: 0, y: 0, blur: 2, color: '#0000001a' }, - { x: 0, y: 8, blur: 16, color: '#00000008' }, - { x: 0, y: 16, blur: 32, color: '#0000000f' }, - ], - [ - { x: 0, y: 0, blur: 2, color: '#00000033' }, - { x: 0, y: 8, blur: 16, color: '#0000001f' }, - { x: 0, y: 16, blur: 32, color: '#0000001f' }, - ], + [shadowLayer1, shadowLayer4, { x: 0, y: 16, blur: 32, color: rgb0000000f }], + [shadowLayer2, shadowLayer3, { x: 0, y: 16, blur: 32, color: rgb0000001f }], ], highest: [ - [ - { x: 0, y: 0, blur: 2, color: '#0000001a' }, - { x: 0, y: 8, blur: 16, color: '#00000008' }, - { x: 0, y: 32, blur: 64, color: '#0000000f' }, - ], - [ - { x: 0, y: 0, blur: 2, color: '#00000033' }, - { x: 0, y: 8, blur: 16, color: '#0000001f' }, - { x: 0, y: 32, blur: 64, color: '#0000001f' }, - ], + [shadowLayer1, shadowLayer4, { x: 0, y: 32, blur: 64, color: rgb0000000f }], + [shadowLayer2, shadowLayer3, { x: 0, y: 32, blur: 64, color: rgb0000001f }], ], }, fontWeight: { @@ -88,12 +232,7 @@ const sharedTokens = { contentEditorialSemibold: fontWeightSemibold, contentEditorialBold: fontWeightBold, }, - fontFamily: { - functional: fontFamilyBase, - content: fontFamilyBase, - contentEditorial: fontFamilyBase, - contentCode: fontFamilyMonospace, - }, + fontFamily: { functional: fontFamilyBase, content: fontFamilyBase, contentEditorial: fontFamilyBase, contentCode: fontFamilyMonospace }, fontSize: { functionalDisplay: 68, functionalPagetitle: 40, @@ -150,15 +289,7 @@ const sharedTokens = { contentTable: 22, contentCode: 22, }, - borderRadius: { - base100: 4, - base200: 8, - base300: 12, - base400: 16, - base600: 24, - base700: 28, - circular: 9999, - }, + borderRadius: { base100: 4, base200: 8, base300: 12, base400: 16, base600: 24, base700: 28, circular: 9999 }, spacing: { componentBase50: 2, componentBase100: 4, @@ -183,12 +314,7 @@ const sharedTokens = { layoutBase1000: 80, layoutBase1200: 96, }, - strokeWidth: { - thin: 1, - thick: 2, - thicker: 3, - thickest: 4, - }, + strokeWidth: { thin: 1, thick: 2, thicker: 3, thickest: 4 }, motion: { durationBase50: 50, durationBase100: 100, @@ -196,268 +322,102 @@ const sharedTokens = { durationBase300: 300, durationBase500: 500, durationBase1000: 1000, - easingFunctionalEnter: [0, 0, 0, 1], - easingFunctionalExit: [0.6, 0, 0.75, 0.4], - easingFunctionalTransition: [0.33, 0, 0, 1], + easingFunctionalEnter, + easingFunctionalExit, + easingFunctionalTransition, easingFunctionalLinear: [0, 0, 1, 1], - easingExpressiveEnter: [0, 0, 0, 1], - easingExpressiveExit: [0.6, 0, 0.75, 0.4], - easingExpressiveTransition: [0.33, 0, 0, 1], + easingExpressiveEnter: easingFunctionalEnter, + easingExpressiveExit: easingFunctionalExit, + easingExpressiveTransition: easingFunctionalTransition, }, -} satisfies Partial>; +} as const; /** The x3 cool-tone defaults. Omitted interaction states are computed from rest. */ export const coolFlexTokenInput: CompleteFlexTokenInput = { - ...sharedTokens, + ...sharedFlexTokenInput, color: { + ...sharedFlexTokenInputColor, surfaceNeutralFarther: ['#ebebeb', '#1b1b1b'], surfaceNeutralFar: ['#f2f2f2', '#1f1f1f'], surfaceNeutralNear: ['#fcfcfc', '#181818'], - surfaceNeutralNearer: ['#ffffff', '#292929'], - surfaceNeutralTranslucent: ['#ffffff80', '#3c3c3c80'], - backgroundNeutralHeavy: { rest: ['#242424', '#ffffff'], type: 'inverted' }, - backgroundNeutralLoud: { rest: ['#6f6f6f', '#929292'], type: 'inverted' }, - backgroundNeutralSoft: ['#00000014', '#ffffff1f'], - backgroundNeutralSubtle: ['#0000000d', '#ffffff14'], - backgroundNeutralTransparent: ['#24242400', '#ffffff00'], - backgroundNeutralTranslucent: { - rest: ['#e9e9e980', '#3c3c3c80'], - hover: ['#d8d8d88a', '#56565688'], - pressed: ['#cacaca94', '#6d6d6d8f'], - }, - backgroundBrandHeavy: { rest: ['#242424', '#ffffff'], type: 'inverted' }, - backgroundBrandLoud: { rest: ['#6f6f6f', '#929292'], type: 'inverted' }, - backgroundBrandSoft: ['#00000014', '#ffffff1f'], - backgroundBrandSubtle: ['#0000000a', '#ffffff14'], - backgroundBrandTransparent: ['#24242400', '#ffffff00'], - backgroundDangerLoud: { rest: ['#c02e56', '#e55e7a'], type: 'inverted' }, - backgroundDangerSoft: ['#ffe3e6', '#5a2932'], - backgroundDangerSubtle: ['#fff1f3', '#402529'], - backgroundWarningLoud: { rest: ['#bb4001', '#e56738'], type: 'inverted' }, - backgroundWarningSoft: ['#ffe5dc', '#592c1c'], - backgroundWarningSubtle: ['#fff2ee', '#40261d'], - backgroundSuccessLoud: { rest: ['#008455', '#05ad72'], type: 'inverted' }, - backgroundSuccessSoft: ['#c9f8dd', '#0c462d'], - backgroundSuccessSubtle: ['#e3fcee', '#193426'], - strokeNeutralHeavy: { rest: ['#242424', '#dedede'], type: 'inverted' }, - strokeNeutralLoud: { rest: ['#6f6f6f', '#929292'], type: 'inverted' }, - strokeNeutralSoft: { rest: ['#0000006d', '#ffffff61'], hover: ['#02020277', '#ffffff69'], pressed: ['#04040481', '#ffffff70'] }, - strokeNeutralSubtle: { rest: ['#00000021', '#ffffff48'], pressed: ['#05050535', '#ffffff57'] }, - strokeNeutralTransparent: ['#24242400', '#ffffff00'], - strokeNeutralOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, - strokeBrandLoud: { rest: ['#6f6f6f', '#929292'], type: 'inverted' }, - strokeBrandSoft: { rest: ['#0000006d', '#ffffff61'], hover: ['#02020277', '#ffffff69'], pressed: ['#04040481', '#ffffff70'] }, - strokeBrandSubtle: { rest: ['#00000021', '#ffffff48'], pressed: ['#05050535', '#ffffff57'] }, - strokeBrandOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, - strokeDangerLoud: { rest: ['#c02e56', '#e55e7a'], type: 'inverted' }, - strokeDangerSoft: ['#e55e7a', '#d14164'], - strokeDangerSubtle: ['#ffd0d6', '#76293a'], - strokeDangerOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, - strokeWarningLoud: { rest: ['#cd4808', '#e56738'], type: 'inverted' }, - strokeWarningSoft: ['#fc9571', '#cd4808'], - strokeWarningSubtle: ['#ffd3c4', '#762e12'], - strokeWarningOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, - strokeSuccessLoud: { rest: ['#008455', '#05ad72'], type: 'inverted' }, - strokeSuccessSoft: ['#5dce97', '#008e5c'], - strokeSuccessSubtle: ['#b1efcc', '#025636'], - strokeSuccessOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, - foregroundNeutralPrimary: ['#000000db', '#ffffffde'], + surfaceNeutralNearer: [rgbffffff, '#292929'], + surfaceNeutralTranslucent: [rgbffffff80, rgb3c3c3c80], + backgroundNeutralHeavy: backgroundNeutralHeavy1, + backgroundNeutralLoud: backgroundNeutralLoud1, + backgroundNeutralSoft: backgroundNeutralSoft1, + backgroundNeutralSubtle: [rgb0000000d, rgbffffff14], + backgroundNeutralTransparent: backgroundNeutralTransparent1, + backgroundNeutralTranslucent: { rest: rest2, hover: ['#d8d8d88a', '#56565688'], pressed: ['#cacaca94', '#6d6d6d8f'] }, + backgroundBrandHeavy: backgroundNeutralHeavy1, + backgroundBrandLoud: backgroundNeutralLoud1, + backgroundBrandSoft: backgroundNeutralSoft1, + backgroundBrandSubtle: ['#0000000a', rgbffffff14], + backgroundBrandTransparent: backgroundNeutralTransparent1, + strokeNeutralHeavy: { rest: [rgb242424, rgbdedede], type: inverted }, + strokeNeutralLoud: backgroundNeutralLoud1, + strokeNeutralSoft: strokeNeutralSoft1, + strokeNeutralSubtle, + strokeNeutralTransparent: backgroundNeutralTransparent1, + strokeNeutralOnloud: strokeNeutralOnloud1, + strokeBrandLoud: backgroundNeutralLoud1, + strokeBrandSoft: strokeNeutralSoft1, + strokeBrandSubtle: strokeNeutralSubtle, + strokeBrandOnloud, + foregroundNeutralPrimary: [rgb000000db, '#ffffffde'], foregroundNeutralSecondary: ['#000000a2', '#ffffffa1'], - foregroundNeutralTertiary: ['#00000090', '#ffffff80'], - foregroundNeutralOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, - foregroundBrandPrimary: ['#242424', '#dedede'], - foregroundBrandOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, - foregroundDangerPrimary: ['#a62147', '#fd8ea1'], - foregroundDangerOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, - foregroundWarningPrimary: ['#a93901', '#fc9571'], - foregroundWarningOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, - foregroundSuccessPrimary: ['#017048', '#5dce97'], - foregroundSuccessOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, - fixedWhite: '#ffffff', - fixedBlack: '#000000', - expressionAccentHeavy: ['#242424', '#ffffff'], - expressionAccentLoud: ['#6f6f6f', '#929292'], - expressionAccentSoft: ['#00000014', '#ffffff1f'], - expressionAccentSubtle: ['#0000000d', '#ffffff14'], - expressionAchromaticHeavy: ['#000000', '#ffffff'], - expressionAchromaticSubtle: ['#ffffff', '#000000'], - expressionGrayHeavy: ['#484848', '#f5f5f5'], - expressionGrayLoud: ['#929292', '#dedede'], - expressionGraySoft: ['#dedede', '#929292'], - expressionGraySubtle: ['#f5f5f5', '#484848'], - expressionNavyHeavy: ['#294482', '#f0f5ff'], - expressionNavyLoud: ['#5c8df8', '#cedeff'], - expressionNavySoft: ['#cedeff', '#5c8df8'], - expressionNavySubtle: ['#f0f5ff', '#294482'], - expressionBlueHeavy: ['#0b497f', '#eef6ff'], - expressionBlueLoud: ['#2f95f4', '#c6e1ff'], - expressionBlueSoft: ['#c6e1ff', '#2f95f4'], - expressionBlueSubtle: ['#eef6ff', '#0b497f'], - expressionGreenHeavy: ['#0c5722', '#e7fce9'], - expressionGreenLoud: ['#32ad52', '#baedc1'], - expressionGreenSoft: ['#baedc1', '#32ad52'], - expressionGreenSubtle: ['#e7fce9', '#0c5722'], - expressionLimeHeavy: ['#345200', '#e6ffcf'], - expressionLimeLoud: ['#6da603', '#cbff93'], - expressionLimeSoft: ['#cbff93', '#6da603'], - expressionLimeSubtle: ['#e6ffcf', '#345200'], - expressionYellowHeavy: ['#524800', '#fff7c4'], - expressionYellowLoud: ['#fbdf06', '#ffed85'], - expressionYellowSoft: ['#ffed85', '#fbdf06'], - expressionYellowSubtle: ['#fff7c4', '#524800'], - expressionPumpkinHeavy: ['#762f0e', '#fef2ee'], - expressionPumpkinLoud: ['#fb966e', '#ffd3c2'], - expressionPumpkinSoft: ['#ffd3c2', '#fb966e'], - expressionPumpkinSubtle: ['#fef2ee', '#762f0e'], - expressionRedHeavy: ['#772b28', '#fff2f0'], - expressionRedLoud: ['#e7615b', '#ffd2cd'], - expressionRedSoft: ['#ffd2cd', '#e7615b'], - expressionRedSubtle: ['#fff2f0', '#772b28'], - expressionPinkHeavy: ['#6f2b53', '#fff1f7'], - expressionPinkLoud: ['#d961a6', '#ffcee6'], - expressionPinkSoft: ['#ffcee6', '#d961a6'], - expressionPinkSubtle: ['#fff1f7', '#6f2b53'], - expressionPurpleHeavy: ['#523778', '#f7f3ff'], - expressionPurpleLoud: ['#a575e8', '#e4d6ff'], - expressionPurpleSoft: ['#e4d6ff', '#a575e8'], - expressionPurpleSubtle: ['#f7f3ff', '#523778'], - overlayNeutralTranslucent: ['#00000026', '#00000099'], - materialBackgroundThick: ['#fffffff1', '#262626ea'], - materialBackgroundRegular: ['#ffffffd7', '#2f2f2fd1'], - materialBackgroundThin: ['#ffffff7e', '#3434348b'], - backgroundNeutralDisabled: ['#00000008', '#ffffff07'], - backgroundNeutralHeavyDisabled: ['#0000001a', '#ffffff20'], - backgroundNeutralSubtleDisabled: ['#00000008', '#ffffff07'], - strokeNeutralDisabled: ['#00000014', '#ffffff24'], - foregroundNeutralDisabled: ['#0000006d', '#ffffff61'], - strokeFocusInner: ['#ffffff', '#000000'], - strokeFocusOuter: ['#000000', '#ffffff'], - shadow: '#000000', + foregroundNeutralTertiary: ['#00000090', rgbffffff80], + foregroundNeutralOnloud: strokeNeutralOnloud1, + foregroundBrandPrimary: [rgb242424, rgbdedede], + foregroundBrandOnloud: strokeNeutralOnloud1, + expressionAccentHeavy: [rgb242424, rgbffffff], + expressionAccentLoud: rest1, + expressionAccentSoft: backgroundNeutralSoft1, + expressionAccentSubtle: [rgb0000000d, rgbffffff14], + backgroundNeutralSubtleDisabled: backgroundNeutralDisabled, }, }; /** The x3 warm-tone defaults. Omitted interaction states are computed from rest. */ export const warmFlexTokenInput: CompleteFlexTokenInput = { - ...sharedTokens, + ...sharedFlexTokenInput, color: { + ...sharedFlexTokenInputColor, surfaceNeutralFarther: ['#f0eae5', '#1e1916'], surfaceNeutralFar: ['#faf4f0', '#231e1a'], surfaceNeutralNear: ['#f6f1ec', '#1c1714'], - surfaceNeutralNearer: ['#ffffff', '#2e2823'], - surfaceNeutralTranslucent: ['#ffffff80', '#00000080'], - backgroundNeutralHeavy: { rest: ['#28231e', '#ffffff'], type: 'inverted' }, - backgroundNeutralLoud: { rest: ['#1e0d009a', '#ffeee39a'], type: 'inverted' }, - backgroundNeutralSoft: ['#4d200028', '#ffe3cb40'], - backgroundNeutralSubtle: ['#6c31001a', '#fff4ef14'], - backgroundNeutralTransparent: ['#28231e00', '#ffffff00'], - backgroundNeutralTranslucent: ['#e9e9e980', '#3c3c3c80'], - backgroundBrandHeavy: { rest: ['#28231e', '#ffffff'], type: 'inverted' }, - backgroundBrandLoud: { rest: ['#1e0d009a', '#ffeee39a'], type: 'inverted' }, - backgroundBrandSoft: ['#4d200028', '#ffe3cb40'], - backgroundBrandSubtle: ['#6c31001a', '#fff4ef14'], - backgroundBrandTransparent: ['#28231e00', '#ffffff00'], - backgroundDangerLoud: { rest: ['#c02e56', '#e55e7a'], type: 'inverted' }, - backgroundDangerSoft: ['#ffe3e6', '#5a2932'], - backgroundDangerSubtle: ['#fff1f3', '#402529'], - backgroundWarningLoud: { rest: ['#bb4001', '#e56738'], type: 'inverted' }, - backgroundWarningSoft: ['#ffe5dc', '#592c1c'], - backgroundWarningSubtle: ['#fff2ee', '#40261d'], - backgroundSuccessLoud: { rest: ['#008455', '#05ad72'], type: 'inverted' }, - backgroundSuccessSoft: ['#c9f8dd', '#0c462d'], - backgroundSuccessSubtle: ['#e3fcee', '#193426'], - strokeNeutralHeavy: { rest: ['#28231e', '#e3dcd7'], type: 'inverted' }, - strokeNeutralLoud: { rest: ['#776d65', '#9a9089'], type: 'inverted' }, - strokeNeutralSoft: ['#250f0076', '#ffe6d35c'], - strokeNeutralSubtle: ['#4d200028', '#ffe3cb40'], - strokeNeutralTransparent: ['#28231e00', '#ffffff00'], - strokeNeutralOnloud: { rest: ['#ffffff', '#0b0600e1'], type: 'inverted' }, - strokeBrandLoud: { rest: ['#776d65', '#9a9089'], type: 'inverted' }, - strokeBrandSoft: ['#250f0076', '#ffe6d35c'], - strokeBrandSubtle: ['#4d200028', '#ffe3cb40'], - strokeBrandOnloud: { rest: ['#ffffff', '#0b0600e1'], type: 'inverted' }, - strokeDangerLoud: { rest: ['#c02e56', '#e55e7a'], type: 'inverted' }, - strokeDangerSoft: ['#e55e7a', '#d14164'], - strokeDangerSubtle: ['#ffd0d6', '#76293a'], - strokeDangerOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, - strokeWarningLoud: { rest: ['#cd4808', '#e56738'], type: 'inverted' }, - strokeWarningSoft: ['#fc9571', '#cd4808'], - strokeWarningSubtle: ['#ffd3c4', '#762e12'], - strokeWarningOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, - strokeSuccessLoud: { rest: ['#008455', '#05ad72'], type: 'inverted' }, - strokeSuccessSoft: ['#5dce97', '#008e5c'], - strokeSuccessSubtle: ['#b1efcc', '#025636'], - strokeSuccessOnloud: { rest: ['#ffffff', '#242424'], type: 'inverted' }, - foregroundNeutralPrimary: ['#0b0600e1', '#fff7f2e3'], + surfaceNeutralNearer: [rgbffffff, '#2e2823'], + surfaceNeutralTranslucent: [rgbffffff80, '#00000080'], + backgroundNeutralHeavy: backgroundNeutralHeavy2, + backgroundNeutralLoud: backgroundNeutralLoud2, + backgroundNeutralSoft: backgroundNeutralSoft2, + backgroundNeutralSubtle, + backgroundNeutralTransparent: backgroundNeutralTransparent2, + backgroundNeutralTranslucent: rest2, + backgroundBrandHeavy: backgroundNeutralHeavy2, + backgroundBrandLoud: backgroundNeutralLoud2, + backgroundBrandSoft: backgroundNeutralSoft2, + backgroundBrandSubtle: backgroundNeutralSubtle, + backgroundBrandTransparent: backgroundNeutralTransparent2, + strokeNeutralHeavy: { rest: [rgb28231e, '#e3dcd7'], type: inverted }, + strokeNeutralLoud, + strokeNeutralSoft: strokeNeutralSoft2, + strokeNeutralSubtle: backgroundNeutralSoft2, + strokeNeutralTransparent: backgroundNeutralTransparent2, + strokeNeutralOnloud: strokeNeutralOnloud2, + strokeBrandLoud: strokeNeutralLoud, + strokeBrandSoft: strokeNeutralSoft2, + strokeBrandSubtle: backgroundNeutralSoft2, + strokeBrandOnloud: strokeNeutralOnloud2, + foregroundNeutralPrimary, foregroundNeutralSecondary: ['#190c00ab', '#fff2e8b5'], - foregroundNeutralTertiary: ['#1e0d009a', '#ffeee39a'], - foregroundNeutralOnloud: { rest: ['#ffffff', '#0b0600e1'], type: 'inverted' }, - foregroundBrandPrimary: ['#0b0600e1', '#fff7f2e3'], - foregroundBrandOnloud: { rest: ['#ffffff', '#0b0600e1'], type: 'inverted' }, - foregroundDangerPrimary: ['#a62147', '#fd8ea1'], - foregroundDangerOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, - foregroundWarningPrimary: ['#a93901', '#fc9571'], - foregroundWarningOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, - foregroundSuccessPrimary: ['#017048', '#5dce97'], - foregroundSuccessOnloud: { rest: ['#ffffff', '#000000db'], type: 'inverted' }, - fixedWhite: '#ffffff', - fixedBlack: '#000000', - expressionAccentHeavy: ['#28231e', '#ffffff'], - expressionAccentLoud: ['#1e0d009a', '#ffeee39a'], - expressionAccentSoft: ['#4d200028', '#ffe3cb40'], - expressionAccentSubtle: ['#6c31001a', '#fff4ef14'], - expressionAchromaticHeavy: ['#000000', '#ffffff'], - expressionAchromaticSubtle: ['#ffffff', '#000000'], - expressionGrayHeavy: ['#484848', '#f5f5f5'], - expressionGrayLoud: ['#929292', '#dedede'], - expressionGraySoft: ['#dedede', '#929292'], - expressionGraySubtle: ['#f5f5f5', '#484848'], - expressionNavyHeavy: ['#294482', '#f0f5ff'], - expressionNavyLoud: ['#5c8df8', '#cedeff'], - expressionNavySoft: ['#cedeff', '#5c8df8'], - expressionNavySubtle: ['#f0f5ff', '#294482'], - expressionBlueHeavy: ['#0b497f', '#eef6ff'], - expressionBlueLoud: ['#2f95f4', '#c6e1ff'], - expressionBlueSoft: ['#c6e1ff', '#2f95f4'], - expressionBlueSubtle: ['#eef6ff', '#0b497f'], - expressionGreenHeavy: ['#0c5722', '#e7fce9'], - expressionGreenLoud: ['#32ad52', '#baedc1'], - expressionGreenSoft: ['#baedc1', '#32ad52'], - expressionGreenSubtle: ['#e7fce9', '#0c5722'], - expressionLimeHeavy: ['#345200', '#e6ffcf'], - expressionLimeLoud: ['#6da603', '#cbff93'], - expressionLimeSoft: ['#cbff93', '#6da603'], - expressionLimeSubtle: ['#e6ffcf', '#345200'], - expressionYellowHeavy: ['#524800', '#fff7c4'], - expressionYellowLoud: ['#fbdf06', '#ffed85'], - expressionYellowSoft: ['#ffed85', '#fbdf06'], - expressionYellowSubtle: ['#fff7c4', '#524800'], - expressionPumpkinHeavy: ['#762f0e', '#fef2ee'], - expressionPumpkinLoud: ['#fb966e', '#ffd3c2'], - expressionPumpkinSoft: ['#ffd3c2', '#fb966e'], - expressionPumpkinSubtle: ['#fef2ee', '#762f0e'], - expressionRedHeavy: ['#772b28', '#fff2f0'], - expressionRedLoud: ['#e7615b', '#ffd2cd'], - expressionRedSoft: ['#ffd2cd', '#e7615b'], - expressionRedSubtle: ['#fff2f0', '#772b28'], - expressionPinkHeavy: ['#6f2b53', '#fff1f7'], - expressionPinkLoud: ['#d961a6', '#ffcee6'], - expressionPinkSoft: ['#ffcee6', '#d961a6'], - expressionPinkSubtle: ['#fff1f7', '#6f2b53'], - expressionPurpleHeavy: ['#523778', '#f7f3ff'], - expressionPurpleLoud: ['#a575e8', '#e4d6ff'], - expressionPurpleSoft: ['#e4d6ff', '#a575e8'], - expressionPurpleSubtle: ['#f7f3ff', '#523778'], - overlayNeutralTranslucent: ['#00000026', '#00000099'], - materialBackgroundThick: ['#fffffff1', '#262626ea'], - materialBackgroundRegular: ['#ffffffd7', '#2f2f2fd1'], - materialBackgroundThin: ['#ffffff7e', '#3434348b'], - backgroundNeutralDisabled: ['#00000008', '#ffffff07'], - backgroundNeutralHeavyDisabled: ['#0000001a', '#ffffff20'], - backgroundNeutralSubtleDisabled: ['#0000000d', '#ffffff1b'], - strokeNeutralDisabled: ['#00000014', '#ffffff24'], - foregroundNeutralDisabled: ['#0000006d', '#ffffff61'], - strokeFocusInner: ['#ffffff', '#000000'], - strokeFocusOuter: ['#000000', '#ffffff'], - shadow: '#000000', + foregroundNeutralTertiary: rest4, + foregroundNeutralOnloud: strokeNeutralOnloud2, + foregroundBrandPrimary: foregroundNeutralPrimary, + foregroundBrandOnloud: strokeNeutralOnloud2, + expressionAccentHeavy: [rgb28231e, rgbffffff], + expressionAccentLoud: rest4, + expressionAccentSoft: backgroundNeutralSoft2, + expressionAccentSubtle: backgroundNeutralSubtle, + backgroundNeutralSubtleDisabled: [rgb0000000d, '#ffffff1b'], }, }; diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.android.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.android.ts new file mode 100644 index 0000000000..8608b283f0 --- /dev/null +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.android.ts @@ -0,0 +1,524 @@ +/** + * WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually. + * Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults. + * Unsupported appearances inherit the closest supported appearance. Shared values are emitted once. + */ +import type { AliasColorTokens } from '../types/Color.types'; +import type { BaseShadowAliasTokens } from '../types/Shadow.types'; +import type { Variants } from '../types/Typography.types'; + +const Roboto = 'Roboto'; +const fontWeight400 = '400'; +const fontWeight500 = '500'; +const rgb000000 = '#000000'; +const rgb00000000 = '#00000000'; +const rgb0000001f = '#0000001f'; +const rgb00000024 = '#00000024'; +const rgb00000040 = '#00000040'; +const rgb0000004d = '#0000004d'; +const rgb0c3b5e = '#0c3b5e'; +const rgb0e4775 = '#0e4775'; +const rgb0e700e = '#0e700e'; +const rgb0f548c = '#0f548c'; +const rgb0f6cbd = '#0f6cbd'; +const rgb107c10 = '#107c10'; +const rgb1f1f1f = '#1f1f1f'; +const rgb242424 = '#242424'; +const rgb2886de = '#2886de'; +const rgb292929 = '#292929'; +const rgb2e2e2e = '#2e2e2e'; +const rgb333333 = '#333333'; +const rgb359b35 = '#359b35'; +const rgb3d3d3d = '#3d3d3d'; +const rgb3f1011 = '#3f1011'; +const rgb424242 = '#424242'; +const rgb479ef5 = '#479ef5'; +const rgb4d4d4d = '#4d4d4d'; +const rgb54b054 = '#54b054'; +const rgb575757 = '#575757'; +const rgb5c5c5c = '#5c5c5c'; +const rgb616161 = '#616161'; +const rgb6d2064 = '#6d2064'; +const rgb77b7f7 = '#77b7f7'; +const rgb808080 = '#808080'; +const rgb817400 = '#817400'; +const rgb96c6fa = '#96c6fa'; +const rgb9e9e9e = '#9e9e9e'; +const rgb9fd89f = '#9fd89f'; +const rgbadadad = '#adadad'; +const rgbb4d6fa = '#b4d6fa'; +const rgbbc2f32 = '#bc2f32'; +const rgbbdbdbd = '#bdbdbd'; +const rgbc0ad00 = '#c0ad00'; +const rgbc239b3 = '#c239b3'; +const rgbc43501 = '#c43501'; +const rgbd13438 = '#d13438'; +const rgbd161c4 = '#d161c4'; +const rgbd1d1d1 = '#d1d1d1'; +const rgbd6d6d6 = '#d6d6d6'; +const rgbda3b01 = '#da3b01'; +const rgbda7ed0 = '#da7ed0'; +const rgbdbdbdb = '#dbdbdb'; +const rgbdc5e62 = '#dc5e62'; +const rgbde501c = '#de501c'; +const rgbe0e0e0 = '#e0e0e0'; +const rgbe36537 = '#e36537'; +const rgbe37d80 = '#e37d80'; +const rgbe6e6e6 = '#e6e6e6'; +const rgbe9835e = '#e9835e'; +const rgbebebeb = '#ebebeb'; +const rgbedbbe7 = '#edbbe7'; +const rgbf0f0f0 = '#f0f0f0'; +const rgbf5f5f5 = '#f5f5f5'; +const rgbfafafa = '#fafafa'; +const rgbfde300 = '#fde300'; +const rgbfdea3d = '#fdea3d'; +const rgbfdf6f6 = '#fdf6f6'; +const rgbfeee66 = '#feee66'; +const rgbffffff = '#ffffff'; + +const body1 = { face: Roboto, size: 16, weight: fontWeight400, lineHeight: 24, letterSpacing: 0 } as const; +const body1Strong = { face: Roboto, size: 16, weight: fontWeight500, lineHeight: 24, letterSpacing: 0 } as const; +const body2 = { face: Roboto, size: 14, weight: fontWeight400, lineHeight: 18, letterSpacing: 0 } as const; +const body2Strong = { face: Roboto, size: 14, weight: fontWeight500, lineHeight: 18, letterSpacing: 0 } as const; +const caption1 = { face: Roboto, size: 13, weight: fontWeight400, lineHeight: 16, letterSpacing: 0 } as const; +const display = { face: Roboto, size: 60, weight: fontWeight400, lineHeight: 72, letterSpacing: -0.5 } as const; +const largeTitle = { face: Roboto, size: 34, weight: fontWeight400, lineHeight: 48, letterSpacing: -0.25 } as const; +const shadowLayer1 = { color: rgb0000001f, x: 0, y: 0, blur: 2 } as const; +const shadowLayer2 = { color: rgb0000001f, x: 0, y: 0, blur: 8 } as const; +const shadowLayer3 = { color: rgb0000004d, x: 0, y: 0, blur: 2 } as const; +const shadowLayer4 = { color: rgb0000004d, x: 0, y: 0, blur: 8 } as const; +const subtitle1Strong = { face: Roboto, size: 20, weight: '600', lineHeight: 24, letterSpacing: 0 } as const; +const subtitle2Strong = { face: Roboto, size: 18, weight: '600', lineHeight: 24, letterSpacing: 0 } as const; +const title1 = { face: Roboto, size: 24, weight: fontWeight400, lineHeight: 32, letterSpacing: 0 } as const; +const title1Strong = { face: Roboto, size: 24, weight: '600', lineHeight: 32, letterSpacing: 0 } as const; +const title2 = { face: Roboto, size: 20, weight: fontWeight500, lineHeight: 24, letterSpacing: 0 } as const; +const title3 = { face: Roboto, size: 18, weight: fontWeight500, lineHeight: 24, letterSpacing: 0 } as const; + +const sharedAliasColors = { + neutralForegroundInverted: rgbffffff, + neutralForegroundInvertedLink: rgbffffff, + brandForeground1Disabled: rgb2886de, + brandForegroundDisabled1: rgb2886de, + brandBackgroundInverted: rgbffffff, + dangerStroke1: rgbdc5e62, + successStroke1: rgb359b35, + dangerBorder1: rgbdc5e62, + successBorder1: rgb359b35, + presenceAway: '#eaa300', + redBackground3: rgbd13438, + redBorder1: rgbdc5e62, + neutralForegroundOnBrandHover: rgbffffff, + neutralForegroundOnBrandPressed: rgbffffff, + neutralForegroundOnBrandSelected: rgbffffff, + subtleBackground: rgb00000000, + transparentBackground: rgb00000000, + transparentBackgroundHover: rgb00000000, + transparentBackgroundPressed: rgb00000000, + transparentBackgroundSelected: rgb00000000, + transparentStroke: rgb00000000, + transparentStrokeInteractive: rgb00000000, + transparentStrokeDisabled: rgb00000000, + dangerBackground3: rgbd13438, + successBackground3: rgb107c10, + warningBackground3: rgbfde300, + severeBackground3: rgbda3b01, + outofofficeBackground3: rgbc239b3, + neutralBackgroundLightStatic: rgbffffff, + neutralForegroundDarkStatic: rgb000000, + neutralForegroundLightStatic: rgbffffff, +} as const; + +export const lightShadows: BaseShadowAliasTokens = { + shadow2: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 1, blur: 2 } }, + shadow4: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 2, blur: 4 } }, + shadow8: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 4, blur: 8 } }, + shadow16: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 8, blur: 16 } }, + shadow28: { ambient: shadowLayer2, key: { color: rgb00000024, x: 0, y: 14, blur: 28 } }, + shadow64: { ambient: shadowLayer2, key: { color: rgb00000024, x: 0, y: 32, blur: 64 } }, + shadow2brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 1, blur: 2 } }, + shadow4brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 2, blur: 4 } }, + shadow8brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 4, blur: 8 } }, + shadow16brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 8, blur: 16 } }, + shadow28brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 14, blur: 28 } }, + shadow64brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 32, blur: 64 } }, +}; + +export const darkShadows: BaseShadowAliasTokens = lightShadows; +export const darkGrayShadows: BaseShadowAliasTokens = lightShadows; +export const hcShadows: BaseShadowAliasTokens = lightShadows; +export const hcLightShadows: BaseShadowAliasTokens = lightShadows; +export const hcDarkShadows: BaseShadowAliasTokens = lightShadows; +export const darkElevatedShadows: BaseShadowAliasTokens = lightShadows; + +export const lightAliasColors: Required = { + ...sharedAliasColors, + neutralForeground4: rgb808080, + neutralForegroundDisabled: rgbbdbdbd, + neutralForegroundDisabled1: rgbbdbdbd, + neutralForegroundDisabled2: rgbffffff, + neutralForegroundOnBrand: rgbffffff, + neutralForegroundOnColor: rgbffffff, + brandForegroundLink: rgb0f6cbd, + compoundBrandForeground1: rgb0f6cbd, + brandForeground2: rgb0f6cbd, + brandForegroundTint: rgb0f548c, + brandForegroundDisabled2: rgbb4d6fa, + neutralBackgroundCanvas: rgbf5f5f5, + neutralBackgroundLightStaticDisabled: rgbffffff, + brandBackground2: '#115ea3', + brandBackground3: rgb0f548c, + brandBackgroundTint: '#cfe4fa', + brandBackgroundInvertedDisabled: rgbffffff, + brandBackgroundDisabled: rgbb4d6fa, + compoundBrandBackground1: rgb0f6cbd, + brandBackgroundStatic: rgb0f6cbd, + neutralStroke3: rgbe0e0e0, + neutralStrokeFocus1: rgbffffff, + neutralStrokeFocus2: rgb000000, + strokeFocus1: rgbffffff, + strokeFocus2: rgb000000, + brandStroke2: rgb2886de, + brandStrokeTint: rgb2886de, + compoundBrandStroke1: rgb0f6cbd, + warningStroke1: rgb817400, + severeStroke1: rgbde501c, + warningBorder1: rgb817400, + severeBorder1: rgbde501c, + presenceDnd: rgbd13438, + presenceAvailable: '#13a10e', + presenceOof: rgbc239b3, + redBackground1: rgbfdf6f6, + redBackground2: rgbd13438, + redForeground1: rgbbc2f32, + redForeground2: rgbd13438, + redForeground3: rgbd13438, + redBorderActive: rgbd13438, + redBorder2: rgbd13438, + neutralForeground1: rgb242424, + neutralForeground1Hover: rgb242424, + neutralForeground1Pressed: rgb242424, + neutralForeground1Selected: rgb242424, + neutralForeground2: rgb616161, + neutralForeground2Hover: rgb616161, + neutralForeground2Pressed: rgb616161, + neutralForeground2Selected: rgb616161, + neutralForeground2BrandHover: rgb616161, + neutralForeground2BrandPressed: rgb616161, + neutralForeground2BrandSelected: rgb616161, + neutralForeground3: rgb808080, + neutralForeground3Hover: rgb808080, + neutralForeground3Pressed: rgb808080, + neutralForeground3Selected: rgb808080, + neutralForeground3BrandHover: rgb808080, + neutralForeground3BrandPressed: rgb808080, + neutralForeground3BrandSelected: rgb808080, + brandForegroundLinkHover: rgb0f6cbd, + brandForegroundLinkPressed: rgb0e4775, + brandForegroundLinkSelected: rgb0f548c, + compoundBrandForeground1Hover: rgb0f6cbd, + compoundBrandForeground1Pressed: rgb0e4775, + brandForeground1: rgb0f6cbd, + neutralForegroundInvertedLinkHover: rgbffffff, + neutralForegroundInvertedLinkPressed: rgbffffff, + neutralForegroundInvertedLinkSelected: rgbffffff, + neutralBackground1: rgbffffff, + neutralBackground1Hover: rgbffffff, + neutralBackground1Pressed: rgbe0e0e0, + neutralBackground1Selected: rgbebebeb, + neutralBackground2: rgbffffff, + neutralBackground2Hover: rgbffffff, + neutralBackground2Pressed: rgbe0e0e0, + neutralBackground2Selected: rgbebebeb, + neutralBackground3: rgbffffff, + neutralBackground3Hover: rgbffffff, + neutralBackground3Pressed: rgbe0e0e0, + neutralBackground3Selected: rgbebebeb, + neutralBackground4: rgbfafafa, + neutralBackground4Hover: rgbfafafa, + neutralBackground4Pressed: rgbdbdbdb, + neutralBackground4Selected: rgbe6e6e6, + neutralBackground5: rgbf0f0f0, + neutralBackground5Hover: rgbf0f0f0, + neutralBackground5Pressed: rgbd1d1d1, + neutralBackground5Selected: rgbdbdbdb, + neutralBackground6: rgbd1d1d1, + neutralBackgroundInverted: '#757575', + subtleBackgroundHover: rgbf5f5f5, + subtleBackgroundPressed: rgbe0e0e0, + subtleBackgroundSelected: rgbebebeb, + neutralBackgroundDisabled: rgbe0e0e0, + neutralStencil1: rgbe6e6e6, + neutralStencil2: rgbfafafa, + brandBackground: rgb0f6cbd, + brandBackgroundHover: rgb0f6cbd, + brandBackgroundPressed: rgb0e4775, + brandBackgroundSelected: rgb0f548c, + compoundBrandBackground1Hover: rgb0f6cbd, + compoundBrandBackground1Pressed: rgb0e4775, + neutralStrokeAccessible: rgb616161, + neutralStrokeAccessibleHover: rgb616161, + neutralStrokeAccessiblePressed: rgb616161, + neutralStrokeAccessibleSelected: rgb616161, + neutralStroke1: rgbd1d1d1, + neutralStroke1Hover: rgbd1d1d1, + neutralStroke1Pressed: rgbd1d1d1, + neutralStroke1Selected: rgbd1d1d1, + neutralStroke2: rgbe0e0e0, + brandStroke1: rgb0f6cbd, + compoundBrandStroke1Hover: rgb0f6cbd, + compoundBrandStroke1Pressed: rgb0e4775, + neutralStrokeDisabled: rgbe0e0e0, + dangerBackground1: rgbfdf6f6, + dangerBackground2: rgbd13438, + dangerForeground1: rgbbc2f32, + dangerForeground2: rgbd13438, + dangerForeground3: rgbd13438, + dangerForegroundInverted: rgbdc5e62, + dangerBorderActive: rgbd13438, + dangerBorder2: rgbd13438, + successBackground1: '#f1faf1', + successBackground2: rgb107c10, + successForeground1: rgb0e700e, + successForeground2: rgb107c10, + successForeground3: rgb107c10, + successForegroundInverted: rgb359b35, + successBorderActive: rgb107c10, + successBorder2: rgb107c10, + warningBackground1: '#fffef5', + warningBackground2: rgbfde300, + warningForeground1: rgb817400, + warningForeground2: rgb817400, + warningForeground3: rgbfde300, + warningForegroundInverted: '#fef7b2', + warningBorderActive: rgbfde300, + warningBorder2: rgbfde300, + severeBackground1: '#fdf6f3', + severeBackground2: rgbda3b01, + severeForeground1: rgbc43501, + severeForeground2: rgbc43501, + severeForeground3: rgbda3b01, + severeBorderActive: rgbda3b01, + severeBorder2: rgbda3b01, + outofofficeBackground1: '#fdf5fc', + outofofficeBackground2: rgbedbbe7, + outofofficeForeground1: '#af33a1', + outofofficeForeground2: rgb6d2064, + outofofficeForeground3: rgbc239b3, + outofofficeBorderActive: rgbc239b3, + outofofficeBorder1: rgbedbbe7, + outofofficeBorder2: rgbc239b3, + brandForeground1Pressed: rgb0e4775, + neutralBackgroundDarkStatic: rgb242424, + brandBackground2Pressed: rgb0c3b5e, + brandBackground2Selected: rgb0e4775, + brandForeground1Selected: rgb0f548c, + brandStroke1Pressed: rgb0e4775, + brandStroke1Selected: rgb0f548c, +}; + +export const darkAliasColors: Required = { + ...sharedAliasColors, + neutralForeground4: rgbadadad, + neutralForegroundDisabled: rgb5c5c5c, + neutralForegroundDisabled1: rgb5c5c5c, + neutralForegroundDisabled2: rgb2e2e2e, + neutralForegroundOnBrand: rgb000000, + neutralForegroundOnColor: rgb000000, + brandForegroundLink: rgb479ef5, + compoundBrandForeground1: rgb479ef5, + brandForeground2: rgb479ef5, + brandForegroundTint: rgb96c6fa, + brandForegroundDisabled2: rgb0c3b5e, + neutralBackgroundCanvas: '#141414', + neutralBackgroundLightStaticDisabled: rgbadadad, + brandBackground2: rgb479ef5, + brandBackground3: rgb479ef5, + brandBackgroundTint: rgb0c3b5e, + brandBackgroundInvertedDisabled: rgbadadad, + brandBackgroundDisabled: rgb0c3b5e, + compoundBrandBackground1: rgb479ef5, + brandBackgroundStatic: rgb479ef5, + neutralStroke3: rgb3d3d3d, + neutralStrokeFocus1: rgb000000, + neutralStrokeFocus2: rgbffffff, + strokeFocus1: rgb000000, + strokeFocus2: rgbffffff, + brandStroke2: rgb479ef5, + brandStrokeTint: rgb479ef5, + compoundBrandStroke1: rgb479ef5, + warningStroke1: rgbc0ad00, + severeStroke1: rgbe36537, + warningBorder1: rgbc0ad00, + severeBorder1: rgbe36537, + presenceDnd: '#d7494c', + presenceAvailable: '#3db838', + presenceOof: rgbd161c4, + redBackground1: rgb3f1011, + redBackground2: rgbbc2f32, + redForeground1: rgbe37d80, + redForeground2: rgbe37d80, + redForeground3: rgbe37d80, + redBorderActive: rgbe37d80, + redBorder2: rgbdc5e62, + neutralForeground1: rgbffffff, + neutralForeground1Hover: rgbffffff, + neutralForeground1Pressed: rgbffffff, + neutralForeground1Selected: rgbffffff, + neutralForeground2: rgbd6d6d6, + neutralForeground2Hover: rgbd6d6d6, + neutralForeground2Pressed: rgbd6d6d6, + neutralForeground2Selected: rgbd6d6d6, + neutralForeground2BrandHover: rgbd6d6d6, + neutralForeground2BrandPressed: rgbd6d6d6, + neutralForeground2BrandSelected: rgbd6d6d6, + neutralForeground3: rgbadadad, + neutralForeground3Hover: rgbadadad, + neutralForeground3Pressed: rgbadadad, + neutralForeground3Selected: rgbadadad, + neutralForeground3BrandHover: rgbadadad, + neutralForeground3BrandPressed: rgbadadad, + neutralForeground3BrandSelected: rgbadadad, + brandForegroundLinkHover: rgb479ef5, + brandForegroundLinkPressed: rgb96c6fa, + brandForegroundLinkSelected: rgb77b7f7, + compoundBrandForeground1Hover: rgb479ef5, + compoundBrandForeground1Pressed: rgb96c6fa, + brandForeground1: rgb479ef5, + neutralForegroundInvertedLinkHover: rgb000000, + neutralForegroundInvertedLinkPressed: rgb000000, + neutralForegroundInvertedLinkSelected: rgb000000, + neutralBackground1: rgb000000, + neutralBackground1Hover: rgb000000, + neutralBackground1Pressed: rgb2e2e2e, + neutralBackground1Selected: rgb242424, + neutralBackground2: rgb1f1f1f, + neutralBackground2Hover: rgb1f1f1f, + neutralBackground2Pressed: rgb4d4d4d, + neutralBackground2Selected: rgb424242, + neutralBackground3: rgb292929, + neutralBackground3Hover: rgb292929, + neutralBackground3Pressed: rgb575757, + neutralBackground3Selected: rgb4d4d4d, + neutralBackground4: rgb333333, + neutralBackground4Hover: rgb333333, + neutralBackground4Pressed: rgb616161, + neutralBackground4Selected: rgb575757, + neutralBackground5: rgb3d3d3d, + neutralBackground5Hover: rgb3d3d3d, + neutralBackground5Pressed: '#6b6b6b', + neutralBackground5Selected: rgb616161, + neutralBackground6: rgb5c5c5c, + neutralBackgroundInverted: '#b8b8b8', + subtleBackgroundHover: rgb3d3d3d, + subtleBackgroundPressed: rgb1f1f1f, + subtleBackgroundSelected: '#383838', + neutralBackgroundDisabled: '#525252', + neutralStencil1: rgb575757, + neutralStencil2: rgb333333, + brandBackground: rgb479ef5, + brandBackgroundHover: rgb479ef5, + brandBackgroundPressed: rgb96c6fa, + brandBackgroundSelected: rgb77b7f7, + compoundBrandBackground1Hover: rgb479ef5, + compoundBrandBackground1Pressed: rgb96c6fa, + neutralStrokeAccessible: rgb9e9e9e, + neutralStrokeAccessibleHover: rgb9e9e9e, + neutralStrokeAccessiblePressed: rgb9e9e9e, + neutralStrokeAccessibleSelected: rgb9e9e9e, + neutralStroke1: rgb4d4d4d, + neutralStroke1Hover: rgb4d4d4d, + neutralStroke1Pressed: rgb4d4d4d, + neutralStroke1Selected: rgb4d4d4d, + neutralStroke2: rgb3d3d3d, + brandStroke1: rgb479ef5, + compoundBrandStroke1Hover: rgb479ef5, + compoundBrandStroke1Pressed: rgb96c6fa, + neutralStrokeDisabled: rgb424242, + dangerBackground1: rgb3f1011, + dangerBackground2: rgbbc2f32, + dangerForeground1: rgbe37d80, + dangerForeground2: rgbe37d80, + dangerForeground3: rgbe37d80, + dangerForegroundInverted: rgbd13438, + dangerBorderActive: rgbe37d80, + dangerBorder2: rgbdc5e62, + successBackground1: '#052505', + successBackground2: rgb0e700e, + successForeground1: rgb54b054, + successForeground2: rgb54b054, + successForeground3: rgb9fd89f, + successForegroundInverted: rgb107c10, + successBorderActive: rgb54b054, + successBorder2: rgb9fd89f, + warningBackground1: '#4c4400', + warningBackground2: '#e4cc00', + warningForeground1: rgbfeee66, + warningForeground2: rgbfeee66, + warningForeground3: rgbfdea3d, + warningForegroundInverted: rgb817400, + warningBorderActive: rgbfeee66, + warningBorder2: rgbfdea3d, + severeBackground1: '#411200', + severeBackground2: rgbc43501, + severeForeground1: rgbe9835e, + severeForeground2: rgbe9835e, + severeForeground3: rgbe9835e, + severeBorderActive: rgbe9835e, + severeBorder2: rgbe9835e, + outofofficeBackground1: '#3a1136', + outofofficeBackground2: rgb6d2064, + outofofficeForeground1: rgbda7ed0, + outofofficeForeground2: rgbedbbe7, + outofofficeForeground3: rgbd161c4, + outofofficeBorderActive: rgbda7ed0, + outofofficeBorder1: rgbc239b3, + outofofficeBorder2: rgbd161c4, + brandForeground1Pressed: rgb96c6fa, + neutralBackgroundDarkStatic: rgb3d3d3d, + brandBackground2Pressed: rgb96c6fa, + brandBackground2Selected: rgb77b7f7, + brandForeground1Selected: rgb77b7f7, + brandStroke1Pressed: rgb96c6fa, + brandStroke1Selected: rgb77b7f7, +}; + +export const darkGrayAliasColors: Required = darkAliasColors; +export const hcAliasColors: Required = darkAliasColors; +export const hcLightAliasColors: Required = lightAliasColors; +export const hcDarkAliasColors: Required = darkAliasColors; +export const darkElevatedAliasColors: Required = darkAliasColors; + +/** Font aliases from the light appearance, completed with native equivalents and the platform global ramp. */ +export const fontAliasTokens: Required = { + caption1, + caption2: { face: Roboto, size: 12, weight: fontWeight400, lineHeight: 16, letterSpacing: 0 }, + caption1Strong: { face: Roboto, size: 13, weight: fontWeight500, lineHeight: 16, letterSpacing: 0 }, + body1, + body1Strong, + body2, + body2Strong, + title1, + title2, + title3, + largeTitle, + display, + subtitle1: title2, + subtitle1Strong, + subtitle2: title3, + subtitle2Strong, + title1Strong, + captionStandard: caption1, + secondaryStandard: body1, + secondarySemibold: body1Strong, + bodyStandard: body2, + bodySemibold: body2Strong, + subheaderStandard: title3, + subheaderSemibold: subtitle2Strong, + headerStandard: title2, + headerSemibold: subtitle1Strong, + heroStandard: title1, + heroSemibold: title1Strong, + heroLargeStandard: largeTitle, + heroLargeSemibold: display, +}; diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ios.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ios.ts new file mode 100644 index 0000000000..5848215fad --- /dev/null +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ios.ts @@ -0,0 +1,633 @@ +/** + * WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually. + * Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults. + * Unsupported appearances inherit the closest supported appearance. Shared values are emitted once. + */ +import type { AliasColorTokens } from '../types/Color.types'; +import type { BaseShadowAliasTokens } from '../types/Shadow.types'; +import type { Variants } from '../types/Typography.types'; + +const System = 'System'; +const fontWeight400 = '400'; +const fontWeight600 = '600'; +const footnote = 'footnote'; +const largeTitle1 = 'largeTitle'; +const rgb000000 = '#000000'; +const rgb00000000 = '#00000000'; +const rgb00000024 = '#00000024'; +const rgb0000003d = '#0000003d'; +const rgb00000040 = '#00000040'; +const rgb00000047 = '#00000047'; +const rgb0000004d = '#0000004d'; +const rgb0000007a = '#0000007a'; +const rgb0c3b5e = '#0c3b5e'; +const rgb0e4775 = '#0e4775'; +const rgb0e700e = '#0e700e'; +const rgb0f548c = '#0f548c'; +const rgb0f6cbd = '#0f6cbd'; +const rgb107c10 = '#107c10'; +const rgb1f1f1f = '#1f1f1f'; +const rgb242424 = '#242424'; +const rgb2886de = '#2886de'; +const rgb292929 = '#292929'; +const rgb2e2e2e = '#2e2e2e'; +const rgb333333 = '#333333'; +const rgb359b35 = '#359b35'; +const rgb383838 = '#383838'; +const rgb3d3d3d = '#3d3d3d'; +const rgb3f1011 = '#3f1011'; +const rgb424242 = '#424242'; +const rgb479ef5 = '#479ef5'; +const rgb4d4d4d = '#4d4d4d'; +const rgb525252 = '#525252'; +const rgb54b054 = '#54b054'; +const rgb575757 = '#575757'; +const rgb5c5c5c = '#5c5c5c'; +const rgb616161 = '#616161'; +const rgb6b6b6b = '#6b6b6b'; +const rgb6d2064 = '#6d2064'; +const rgb757575 = '#757575'; +const rgb77b7f7 = '#77b7f7'; +const rgb808080 = '#808080'; +const rgb817400 = '#817400'; +const rgb96c6fa = '#96c6fa'; +const rgb9e9e9e = '#9e9e9e'; +const rgb9fd89f = '#9fd89f'; +const rgbadadad = '#adadad'; +const rgbb4d6fa = '#b4d6fa'; +const rgbb8b8b8 = '#b8b8b8'; +const rgbbc2f32 = '#bc2f32'; +const rgbbdbdbd = '#bdbdbd'; +const rgbc0ad00 = '#c0ad00'; +const rgbc239b3 = '#c239b3'; +const rgbc43501 = '#c43501'; +const rgbc7c7c7 = '#c7c7c7'; +const rgbd13438 = '#d13438'; +const rgbd161c4 = '#d161c4'; +const rgbd1d1d1 = '#d1d1d1'; +const rgbd6d6d6 = '#d6d6d6'; +const rgbda3b01 = '#da3b01'; +const rgbda7ed0 = '#da7ed0'; +const rgbdbdbdb = '#dbdbdb'; +const rgbdc5e62 = '#dc5e62'; +const rgbde501c = '#de501c'; +const rgbe0e0e0 = '#e0e0e0'; +const rgbe36537 = '#e36537'; +const rgbe37d80 = '#e37d80'; +const rgbe6e6e6 = '#e6e6e6'; +const rgbe9835e = '#e9835e'; +const rgbebebeb = '#ebebeb'; +const rgbedbbe7 = '#edbbe7'; +const rgbf0f0f0 = '#f0f0f0'; +const rgbf5f5f5 = '#f5f5f5'; +const rgbfafafa = '#fafafa'; +const rgbfde300 = '#fde300'; +const rgbfdea3d = '#fdea3d'; +const rgbfdf6f6 = '#fdf6f6'; +const rgbfeee66 = '#feee66'; +const rgbffffff = '#ffffff'; +const subheadline = 'subheadline'; + +const body1 = { face: System, size: 17, weight: fontWeight400, lineHeight: 22, letterSpacing: -0.43, dynamicTypeRamp: 'body' } as const; + +const body1Strong = { + face: System, + size: 17, + weight: fontWeight600, + lineHeight: 22, + letterSpacing: -0.43, + dynamicTypeRamp: 'body', +} as const; + +const body2 = { + face: System, + size: 15, + weight: fontWeight400, + lineHeight: 20, + letterSpacing: -0.23, + dynamicTypeRamp: subheadline, +} as const; + +const body2Strong = { + face: System, + size: 15, + weight: fontWeight600, + lineHeight: 20, + letterSpacing: -0.23, + dynamicTypeRamp: subheadline, +} as const; + +const caption1 = { + face: System, + size: 13, + weight: fontWeight400, + lineHeight: 18, + letterSpacing: -0.08, + dynamicTypeRamp: footnote, +} as const; + +const display = { face: System, size: 60, weight: '700', lineHeight: 70, letterSpacing: 0.26, dynamicTypeRamp: largeTitle1 } as const; +const largeTitle2 = { face: System, size: 34, weight: '700', lineHeight: 41, letterSpacing: 0.4, dynamicTypeRamp: largeTitle1 } as const; +const shadowLayer1 = { color: '#0000001f', x: 0, y: 0, blur: 2 } as const; +const shadowLayer2 = { color: '#00000033', x: 0, y: 0, blur: 8 } as const; +const shadowLayer3 = { color: rgb0000004d, x: 0, y: 0, blur: 2 } as const; +const shadowLayer4 = { color: rgb0000004d, x: 0, y: 0, blur: 8 } as const; +const shadowLayer5 = { color: rgb0000003d, x: 0, y: 0, blur: 2 } as const; +const shadowLayer6 = { color: '#00000066', x: 0, y: 0, blur: 8 } as const; +const title1 = { face: System, size: 28, weight: '700', lineHeight: 34, letterSpacing: 0.38, dynamicTypeRamp: 'title1' } as const; + +const title1Strong = { + face: System, + size: 28, + weight: fontWeight600, + lineHeight: 34, + letterSpacing: 0.38, + dynamicTypeRamp: 'title1', +} as const; + +const title2 = { face: System, size: 22, weight: fontWeight600, lineHeight: 28, letterSpacing: -0.26, dynamicTypeRamp: 'title2' } as const; +const title3 = { face: System, size: 20, weight: fontWeight600, lineHeight: 25, letterSpacing: -0.45, dynamicTypeRamp: 'title3' } as const; + +const sharedAliasColors = { + brandForeground1Disabled: rgb2886de, + brandForegroundDisabled1: rgb2886de, + dangerStroke1: rgbdc5e62, + successStroke1: rgb359b35, + dangerBorder1: rgbdc5e62, + successBorder1: rgb359b35, + presenceAway: '#eaa300', + redBackground3: rgbd13438, + redBorder1: rgbdc5e62, + neutralForegroundOnBrandHover: rgbffffff, + neutralForegroundOnBrandPressed: rgbffffff, + neutralForegroundOnBrandSelected: rgbffffff, + subtleBackground: rgb00000000, + transparentBackground: rgb00000000, + transparentBackgroundHover: rgb00000000, + transparentBackgroundPressed: rgb00000000, + transparentBackgroundSelected: rgb00000000, + transparentStroke: rgb00000000, + transparentStrokeInteractive: rgb00000000, + transparentStrokeDisabled: rgb00000000, + dangerBackground3: rgbd13438, + successBackground3: rgb107c10, + warningBackground3: rgbfde300, + severeBackground3: rgbda3b01, + outofofficeBackground3: rgbc239b3, + neutralBackgroundLightStatic: rgbffffff, + neutralForegroundDarkStatic: rgb000000, + neutralForegroundLightStatic: rgbffffff, +} as const; + +const darkDarkGrayHcHcDarkDarkElevatedAliasColors = { + ...sharedAliasColors, + neutralForeground4: rgbadadad, + neutralForegroundDisabled: rgb5c5c5c, + neutralForegroundDisabled1: rgb5c5c5c, + neutralForegroundDisabled2: rgb2e2e2e, + neutralForegroundOnBrand: rgb000000, + neutralForegroundOnColor: rgb000000, + neutralForegroundInverted: rgb000000, + neutralForegroundInvertedLink: rgb000000, + brandForegroundLink: rgb479ef5, + compoundBrandForeground1: rgb479ef5, + brandForeground2: rgb479ef5, + brandForegroundTint: rgb96c6fa, + brandForegroundDisabled2: rgb0c3b5e, + brandBackground2: rgb479ef5, + brandBackground3: rgb479ef5, + brandBackgroundTint: rgb0c3b5e, + brandBackgroundDisabled: rgb0c3b5e, + compoundBrandBackground1: rgb479ef5, + brandBackgroundStatic: rgb479ef5, + neutralStrokeFocus1: rgb000000, + neutralStrokeFocus2: rgbffffff, + strokeFocus1: rgb000000, + strokeFocus2: rgbffffff, + brandStroke2: rgb479ef5, + brandStrokeTint: rgb479ef5, + compoundBrandStroke1: rgb479ef5, + warningStroke1: rgbc0ad00, + severeStroke1: rgbe36537, + warningBorder1: rgbc0ad00, + severeBorder1: rgbe36537, + presenceDnd: '#d7494c', + presenceAvailable: '#3db838', + presenceOof: rgbd161c4, + redBackground1: rgb3f1011, + redBackground2: rgbbc2f32, + redForeground1: rgbe37d80, + redForeground2: rgbe37d80, + redForeground3: rgbe37d80, + redBorderActive: rgbe37d80, + redBorder2: rgbdc5e62, + neutralForeground1: rgbffffff, + neutralForeground1Hover: rgbffffff, + neutralForeground1Pressed: rgbffffff, + neutralForeground1Selected: rgbffffff, + neutralForeground2: rgbd6d6d6, + neutralForeground2Hover: rgbd6d6d6, + neutralForeground2Pressed: rgbd6d6d6, + neutralForeground2Selected: rgbd6d6d6, + neutralForeground2BrandHover: rgbd6d6d6, + neutralForeground2BrandPressed: rgbd6d6d6, + neutralForeground2BrandSelected: rgbd6d6d6, + neutralForeground3: rgbadadad, + neutralForeground3Hover: rgbadadad, + neutralForeground3Pressed: rgbadadad, + neutralForeground3Selected: rgbadadad, + neutralForeground3BrandHover: rgbadadad, + neutralForeground3BrandPressed: rgbadadad, + neutralForeground3BrandSelected: rgbadadad, + brandForegroundLinkHover: rgb479ef5, + brandForegroundLinkPressed: rgb96c6fa, + brandForegroundLinkSelected: rgb77b7f7, + compoundBrandForeground1Hover: rgb479ef5, + compoundBrandForeground1Pressed: rgb96c6fa, + brandForeground1: rgb479ef5, + neutralForegroundInvertedLinkHover: rgb000000, + neutralForegroundInvertedLinkPressed: rgb000000, + neutralForegroundInvertedLinkSelected: rgb000000, + neutralBackground2Pressed: rgb4d4d4d, + neutralBackground2Selected: rgb424242, + neutralBackground3Pressed: rgb575757, + neutralBackground3Selected: rgb4d4d4d, + neutralBackground4Pressed: rgb616161, + neutralBackground4Selected: rgb575757, + neutralBackground5Pressed: rgb6b6b6b, + neutralBackground5Selected: rgb616161, + subtleBackgroundHover: rgb3d3d3d, + subtleBackgroundPressed: rgb1f1f1f, + subtleBackgroundSelected: rgb383838, + brandBackground: rgb479ef5, + brandBackgroundHover: rgb479ef5, + brandBackgroundPressed: rgb96c6fa, + brandBackgroundSelected: rgb77b7f7, + compoundBrandBackground1Hover: rgb479ef5, + compoundBrandBackground1Pressed: rgb96c6fa, + brandStroke1: rgb479ef5, + compoundBrandStroke1Hover: rgb479ef5, + compoundBrandStroke1Pressed: rgb96c6fa, + dangerBackground1: rgb3f1011, + dangerBackground2: rgbbc2f32, + dangerForeground1: rgbe37d80, + dangerForeground2: rgbe37d80, + dangerForeground3: rgbe37d80, + dangerForegroundInverted: rgbd13438, + dangerBorderActive: rgbe37d80, + dangerBorder2: rgbdc5e62, + successBackground1: '#052505', + successBackground2: rgb0e700e, + successForeground1: rgb54b054, + successForeground2: rgb54b054, + successForeground3: rgb9fd89f, + successForegroundInverted: rgb107c10, + successBorderActive: rgb54b054, + successBorder2: rgb9fd89f, + warningBackground1: '#4c4400', + warningBackground2: '#e4cc00', + warningForeground1: rgbfeee66, + warningForeground2: rgbfeee66, + warningForeground3: rgbfdea3d, + warningForegroundInverted: rgb817400, + warningBorderActive: rgbfeee66, + warningBorder2: rgbfdea3d, + severeBackground1: '#411200', + severeBackground2: rgbc43501, + severeForeground1: rgbe9835e, + severeForeground2: rgbe9835e, + severeForeground3: rgbe9835e, + severeBorderActive: rgbe9835e, + severeBorder2: rgbe9835e, + outofofficeBackground1: '#3a1136', + outofofficeBackground2: rgb6d2064, + outofofficeForeground1: rgbda7ed0, + outofofficeForeground2: rgbedbbe7, + outofofficeForeground3: rgbd161c4, + outofofficeBorderActive: rgbda7ed0, + outofofficeBorder1: rgbc239b3, + outofofficeBorder2: rgbd161c4, + brandForeground1Pressed: rgb96c6fa, + brandBackground2Pressed: rgb96c6fa, + brandBackground2Selected: rgb77b7f7, + brandForeground1Selected: rgb77b7f7, + brandStroke1Pressed: rgb96c6fa, + brandStroke1Selected: rgb77b7f7, +} as const; + +const sharedShadows = { + shadow2brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 1, blur: 2 } }, + shadow4brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 2, blur: 4 } }, + shadow8brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 4, blur: 8 } }, + shadow16brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 8, blur: 16 } }, + shadow28brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 14, blur: 28 } }, + shadow64brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 32, blur: 64 } }, +} as const; + +export const lightShadows: BaseShadowAliasTokens = { + ...sharedShadows, + shadow2: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 1, blur: 2 } }, + shadow4: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 2, blur: 4 } }, + shadow8: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 4, blur: 8 } }, + shadow16: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 8, blur: 16 } }, + shadow28: { ambient: shadowLayer2, key: { color: rgb0000003d, x: 0, y: 14, blur: 28 } }, + shadow64: { ambient: shadowLayer2, key: { color: rgb0000003d, x: 0, y: 32, blur: 64 } }, +}; + +export const darkShadows: BaseShadowAliasTokens = { + ...sharedShadows, + shadow2: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 1, blur: 2 } }, + shadow4: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 2, blur: 4 } }, + shadow8: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 4, blur: 8 } }, + shadow16: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 8, blur: 16 } }, + shadow28: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 14, blur: 28 } }, + shadow64: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 32, blur: 64 } }, +}; + +export const darkGrayShadows: BaseShadowAliasTokens = darkShadows; +export const hcShadows: BaseShadowAliasTokens = darkShadows; +export const hcLightShadows: BaseShadowAliasTokens = darkShadows; +export const hcDarkShadows: BaseShadowAliasTokens = darkShadows; +export const darkElevatedShadows: BaseShadowAliasTokens = darkShadows; + +export const lightAliasColors: Required = { + ...sharedAliasColors, + neutralForeground4: rgb808080, + neutralForegroundDisabled: rgbbdbdbd, + neutralForegroundDisabled1: rgbbdbdbd, + neutralForegroundDisabled2: rgbffffff, + neutralForegroundOnBrand: rgbffffff, + neutralForegroundOnColor: rgbffffff, + neutralForegroundInverted: rgbffffff, + neutralForegroundInvertedLink: rgbffffff, + brandForegroundLink: rgb0f6cbd, + compoundBrandForeground1: rgb0f6cbd, + brandForeground2: rgb0f6cbd, + brandForegroundTint: rgb0f548c, + brandForegroundDisabled2: rgbb4d6fa, + neutralBackgroundCanvas: rgbf5f5f5, + neutralBackgroundLightStaticDisabled: rgbffffff, + brandBackground2: '#115ea3', + brandBackground3: rgb0f548c, + brandBackgroundTint: '#cfe4fa', + brandBackgroundInverted: rgb757575, + brandBackgroundInvertedDisabled: rgbe0e0e0, + brandBackgroundDisabled: rgbb4d6fa, + compoundBrandBackground1: rgb0f6cbd, + brandBackgroundStatic: rgb0f6cbd, + neutralStroke3: rgbe0e0e0, + neutralStrokeFocus1: rgbffffff, + neutralStrokeFocus2: rgb000000, + strokeFocus1: rgbffffff, + strokeFocus2: rgb000000, + brandStroke2: rgb2886de, + brandStrokeTint: rgb2886de, + compoundBrandStroke1: rgb0f6cbd, + warningStroke1: rgb817400, + severeStroke1: rgbde501c, + warningBorder1: rgb817400, + severeBorder1: rgbde501c, + presenceDnd: rgbd13438, + presenceAvailable: '#13a10e', + presenceOof: rgbc239b3, + redBackground1: rgbfdf6f6, + redBackground2: rgbd13438, + redForeground1: rgbbc2f32, + redForeground2: rgbd13438, + redForeground3: rgbd13438, + redBorderActive: rgbd13438, + redBorder2: rgbd13438, + neutralForeground1: rgb242424, + neutralForeground1Hover: rgb242424, + neutralForeground1Pressed: rgb242424, + neutralForeground1Selected: rgb242424, + neutralForeground2: rgb616161, + neutralForeground2Hover: rgb616161, + neutralForeground2Pressed: rgb616161, + neutralForeground2Selected: rgb616161, + neutralForeground2BrandHover: rgb616161, + neutralForeground2BrandPressed: rgb616161, + neutralForeground2BrandSelected: rgb616161, + neutralForeground3: rgb808080, + neutralForeground3Hover: rgb808080, + neutralForeground3Pressed: rgb808080, + neutralForeground3Selected: rgb808080, + neutralForeground3BrandHover: rgb808080, + neutralForeground3BrandPressed: rgb808080, + neutralForeground3BrandSelected: rgb808080, + brandForegroundLinkHover: rgb0f6cbd, + brandForegroundLinkPressed: rgb0e4775, + brandForegroundLinkSelected: rgb0f548c, + compoundBrandForeground1Hover: rgb0f6cbd, + compoundBrandForeground1Pressed: rgb0e4775, + brandForeground1: rgb0f6cbd, + neutralForegroundInvertedLinkHover: rgbffffff, + neutralForegroundInvertedLinkPressed: rgbffffff, + neutralForegroundInvertedLinkSelected: rgbffffff, + neutralBackground1: rgbffffff, + neutralBackground1Hover: rgbffffff, + neutralBackground1Pressed: rgbe0e0e0, + neutralBackground1Selected: rgbebebeb, + neutralBackground2: rgbffffff, + neutralBackground2Hover: rgbffffff, + neutralBackground2Pressed: rgbe0e0e0, + neutralBackground2Selected: rgbebebeb, + neutralBackground3: rgbffffff, + neutralBackground3Hover: rgbffffff, + neutralBackground3Pressed: rgbe0e0e0, + neutralBackground3Selected: rgbebebeb, + neutralBackground4: rgbfafafa, + neutralBackground4Hover: rgbfafafa, + neutralBackground4Pressed: rgbdbdbdb, + neutralBackground4Selected: rgbe6e6e6, + neutralBackground5: rgbf0f0f0, + neutralBackground5Hover: rgbf0f0f0, + neutralBackground5Pressed: rgbd1d1d1, + neutralBackground5Selected: rgbdbdbdb, + neutralBackground6: rgbd1d1d1, + neutralBackgroundInverted: rgb757575, + subtleBackgroundHover: rgbf5f5f5, + subtleBackgroundPressed: rgbe0e0e0, + subtleBackgroundSelected: rgbebebeb, + neutralBackgroundDisabled: rgbe0e0e0, + neutralStencil1: rgbe6e6e6, + neutralStencil2: rgbfafafa, + brandBackground: rgb0f6cbd, + brandBackgroundHover: rgb0f6cbd, + brandBackgroundPressed: rgb0e4775, + brandBackgroundSelected: rgb0f548c, + compoundBrandBackground1Hover: rgb0f6cbd, + compoundBrandBackground1Pressed: rgb0e4775, + neutralStrokeAccessible: rgb616161, + neutralStrokeAccessibleHover: rgb616161, + neutralStrokeAccessiblePressed: rgb616161, + neutralStrokeAccessibleSelected: rgb616161, + neutralStroke1: rgbd1d1d1, + neutralStroke1Hover: rgbd1d1d1, + neutralStroke1Pressed: rgbd1d1d1, + neutralStroke1Selected: rgbd1d1d1, + neutralStroke2: rgbe0e0e0, + brandStroke1: rgb0f6cbd, + compoundBrandStroke1Hover: rgb0f6cbd, + compoundBrandStroke1Pressed: rgb0e4775, + neutralStrokeDisabled: rgbe0e0e0, + dangerBackground1: rgbfdf6f6, + dangerBackground2: rgbd13438, + dangerForeground1: rgbbc2f32, + dangerForeground2: rgbd13438, + dangerForeground3: rgbd13438, + dangerForegroundInverted: rgbdc5e62, + dangerBorderActive: rgbd13438, + dangerBorder2: rgbd13438, + successBackground1: '#f1faf1', + successBackground2: rgb107c10, + successForeground1: rgb0e700e, + successForeground2: rgb107c10, + successForeground3: rgb107c10, + successForegroundInverted: rgb359b35, + successBorderActive: rgb107c10, + successBorder2: rgb107c10, + warningBackground1: '#fffef5', + warningBackground2: rgbfde300, + warningForeground1: rgb817400, + warningForeground2: rgb817400, + warningForeground3: rgbfde300, + warningForegroundInverted: '#fef7b2', + warningBorderActive: rgbfde300, + warningBorder2: rgbfde300, + severeBackground1: '#fdf6f3', + severeBackground2: rgbda3b01, + severeForeground1: rgbc43501, + severeForeground2: '#a62d01', + severeForeground3: rgbda3b01, + severeBorderActive: rgbda3b01, + severeBorder2: rgbda3b01, + outofofficeBackground1: '#fdf5fc', + outofofficeBackground2: rgbedbbe7, + outofofficeForeground1: '#af33a1', + outofofficeForeground2: rgb6d2064, + outofofficeForeground3: rgbc239b3, + outofofficeBorderActive: rgbc239b3, + outofofficeBorder1: rgbedbbe7, + outofofficeBorder2: rgbc239b3, + brandForeground1Pressed: rgb0e4775, + neutralBackgroundDarkStatic: rgb242424, + brandBackground2Pressed: rgb0c3b5e, + brandBackground2Selected: rgb0e4775, + brandForeground1Selected: rgb0f548c, + brandStroke1Pressed: rgb0e4775, + brandStroke1Selected: rgb0f548c, +}; + +export const darkAliasColors: Required = { + ...darkDarkGrayHcHcDarkDarkElevatedAliasColors, + neutralBackgroundCanvas: '#141414', + neutralBackgroundLightStaticDisabled: rgbadadad, + brandBackgroundInverted: rgbb8b8b8, + brandBackgroundInvertedDisabled: rgb525252, + neutralStroke3: rgb3d3d3d, + neutralBackground1: rgb000000, + neutralBackground1Hover: rgb000000, + neutralBackground1Pressed: rgb2e2e2e, + neutralBackground1Selected: rgb242424, + neutralBackground2: rgb1f1f1f, + neutralBackground2Hover: rgb1f1f1f, + neutralBackground3: rgb292929, + neutralBackground3Hover: rgb292929, + neutralBackground4: rgb333333, + neutralBackground4Hover: rgb333333, + neutralBackground5: rgb3d3d3d, + neutralBackground5Hover: rgb3d3d3d, + neutralBackground6: rgb5c5c5c, + neutralBackgroundInverted: rgbb8b8b8, + neutralBackgroundDisabled: rgb525252, + neutralStencil1: rgb575757, + neutralStencil2: rgb333333, + neutralStrokeAccessible: rgb9e9e9e, + neutralStrokeAccessibleHover: rgb9e9e9e, + neutralStrokeAccessiblePressed: rgb9e9e9e, + neutralStrokeAccessibleSelected: rgb9e9e9e, + neutralStroke1: rgb4d4d4d, + neutralStroke1Hover: rgb4d4d4d, + neutralStroke1Pressed: rgb4d4d4d, + neutralStroke1Selected: rgb4d4d4d, + neutralStroke2: rgb3d3d3d, + neutralStrokeDisabled: rgb424242, + neutralBackgroundDarkStatic: rgb3d3d3d, +}; + +export const darkGrayAliasColors: Required = darkAliasColors; +export const hcAliasColors: Required = darkAliasColors; +export const hcLightAliasColors: Required = lightAliasColors; +export const hcDarkAliasColors: Required = darkAliasColors; + +export const darkElevatedAliasColors: Required = { + ...darkDarkGrayHcHcDarkDarkElevatedAliasColors, + neutralBackgroundCanvas: rgb242424, + neutralBackgroundLightStaticDisabled: rgb6b6b6b, + brandBackgroundInverted: rgbc7c7c7, + brandBackgroundInvertedDisabled: rgb616161, + neutralStroke3: rgb4d4d4d, + neutralBackground1: rgb1f1f1f, + neutralBackground1Hover: rgb1f1f1f, + neutralBackground1Pressed: rgb4d4d4d, + neutralBackground1Selected: rgb424242, + neutralBackground2: rgb2e2e2e, + neutralBackground2Hover: rgb2e2e2e, + neutralBackground3: rgb383838, + neutralBackground3Hover: rgb383838, + neutralBackground4: rgb424242, + neutralBackground4Hover: rgb424242, + neutralBackground5: rgb4d4d4d, + neutralBackground5Hover: rgb4d4d4d, + neutralBackground6: rgb6b6b6b, + neutralBackgroundInverted: rgbc7c7c7, + neutralBackgroundDisabled: rgb616161, + neutralStencil1: '#666666', + neutralStencil2: rgb424242, + neutralStrokeAccessible: rgbadadad, + neutralStrokeAccessibleHover: rgbadadad, + neutralStrokeAccessiblePressed: rgbadadad, + neutralStrokeAccessibleSelected: rgbadadad, + neutralStroke1: rgb5c5c5c, + neutralStroke1Hover: rgb5c5c5c, + neutralStroke1Pressed: rgb5c5c5c, + neutralStroke1Selected: rgb5c5c5c, + neutralStroke2: rgb4d4d4d, + neutralStrokeDisabled: rgb525252, + neutralBackgroundDarkStatic: rgb4d4d4d, +}; + +/** Font aliases from the light appearance, completed with native equivalents and the platform global ramp. */ +export const fontAliasTokens: Required = { + caption2: { face: System, size: 12, weight: fontWeight400, lineHeight: 16, letterSpacing: 0, dynamicTypeRamp: 'caption1' }, + caption1, + caption1Strong: { face: System, size: 13, weight: fontWeight600, lineHeight: 18, letterSpacing: -0.08, dynamicTypeRamp: footnote }, + body2, + body2Strong, + body1, + body1Strong, + title3, + title2, + title1, + largeTitle: largeTitle2, + display, + subtitle1: title2, + subtitle1Strong: title2, + subtitle2: title3, + subtitle2Strong: title3, + title1Strong, + captionStandard: caption1, + secondaryStandard: body1, + secondarySemibold: body1Strong, + bodyStandard: body2, + bodySemibold: body2Strong, + subheaderStandard: title3, + subheaderSemibold: title3, + headerStandard: title2, + headerSemibold: title2, + heroStandard: title1, + heroSemibold: title1Strong, + heroLargeStandard: largeTitle2, + heroLargeSemibold: display, +}; diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.macos.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.macos.ts new file mode 100644 index 0000000000..e6ad49f432 --- /dev/null +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.macos.ts @@ -0,0 +1,600 @@ +/** + * WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually. + * Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults. + * Unsupported appearances inherit the closest supported appearance. Shared values are emitted once. + */ +import type { AliasColorTokens } from '../types/Color.types'; +import type { BaseShadowAliasTokens } from '../types/Shadow.types'; +import type { Variants } from '../types/Typography.types'; + +const fontWeight400 = '400'; +const fontWeight600 = '600'; +const primary = 'primary'; +const rgb000000 = '#000000'; +const rgb00000000 = '#00000000'; +const rgb00000024 = '#00000024'; +const rgb0000003d = '#0000003d'; +const rgb00000040 = '#00000040'; +const rgb00000047 = '#00000047'; +const rgb0000004d = '#0000004d'; +const rgb0000007a = '#0000007a'; +const rgb004578 = '#004578'; +const rgb004c87 = '#004c87'; +const rgb005a9e = '#005a9e'; +const rgb0078d4 = '#0078d4'; +const rgb0086f0 = '#0086f0'; +const rgb043862 = '#043862'; +const rgb092c47 = '#092c47'; +const rgb094509 = '#094509'; +const rgb0e700e = '#0e700e'; +const rgb106ebe = '#106ebe'; +const rgb107c10 = '#107c10'; +const rgb1890f1 = '#1890f1'; +const rgb1f1f1f = '#1f1f1f'; +const rgb242424 = '#242424'; +const rgb292929 = '#292929'; +const rgb333333 = '#333333'; +const rgb383838 = '#383838'; +const rgb3aa0f3 = '#3aa0f3'; +const rgb3d3d3d = '#3d3d3d'; +const rgb3f1011 = '#3f1011'; +const rgb424242 = '#424242'; +const rgb54b054 = '#54b054'; +const rgb575757 = '#575757'; +const rgb5c5c5c = '#5c5c5c'; +const rgb616161 = '#616161'; +const rgb666666 = '#666666'; +const rgb6cb8f6 = '#6cb8f6'; +const rgb6d2064 = '#6d2064'; +const rgb707070 = '#707070'; +const rgb751d1f = '#751d1f'; +const rgb757575 = '#757575'; +const rgb7a2101 = '#7a2101'; +const rgb817400 = '#817400'; +const rgb9fd89f = '#9fd89f'; +const rgba8a8a8 = '#a8a8a8'; +const rgbadadad = '#adadad'; +const rgbaf33a1 = '#af33a1'; +const rgbb3b3b3 = '#b3b3b3'; +const rgbb8b8b8 = '#b8b8b8'; +const rgbbc2f32 = '#bc2f32'; +const rgbbdbdbd = '#bdbdbd'; +const rgbc239b3 = '#c239b3'; +const rgbc2c2c2 = '#c2c2c2'; +const rgbc7e0f4 = '#c7e0f4'; +const rgbd13438 = '#d13438'; +const rgbd161c4 = '#d161c4'; +const rgbd6d6d6 = '#d6d6d6'; +const rgbda3b01 = '#da3b01'; +const rgbda7ed0 = '#da7ed0'; +const rgbdc5e62 = '#dc5e62'; +const rgbe0e0e0 = '#e0e0e0'; +const rgbe37d80 = '#e37d80'; +const rgbe6e6e6 = '#e6e6e6'; +const rgbe9835e = '#e9835e'; +const rgbebebeb = '#ebebeb'; +const rgbedbbe7 = '#edbbe7'; +const rgbeff6fc = '#eff6fc'; +const rgbf0f0f0 = '#f0f0f0'; +const rgbf1bbbc = '#f1bbbc'; +const rgbf4bfab = '#f4bfab'; +const rgbf5f5f5 = '#f5f5f5'; +const rgbfafafa = '#fafafa'; +const rgbfde300 = '#fde300'; +const rgbfdea3d = '#fdea3d'; +const rgbfdf6f6 = '#fdf6f6'; +const rgbfeee66 = '#feee66'; +const rgbfef7b2 = '#fef7b2'; +const rgbffffff = '#ffffff'; + +const body1 = { face: primary, size: 12, weight: fontWeight400 } as const; +const body1Strong = { face: primary, size: 12, weight: fontWeight600 } as const; +const body2 = { face: primary, size: 14, weight: fontWeight400 } as const; +const body2Strong = { face: primary, size: 14, weight: fontWeight600 } as const; +const caption1 = { face: primary, size: 10, weight: fontWeight400 } as const; +const display = { face: primary, size: 40, weight: fontWeight600 } as const; +const largeTitle = { face: primary, size: 40, weight: fontWeight400 } as const; +const shadowLayer1 = { color: '#0000001f', x: 0, y: 0, blur: 2 } as const; +const shadowLayer2 = { color: '#00000033', x: 0, y: 0, blur: 8 } as const; +const shadowLayer3 = { color: rgb0000004d, x: 0, y: 0, blur: 2 } as const; +const shadowLayer4 = { color: rgb0000004d, x: 0, y: 0, blur: 8 } as const; +const shadowLayer5 = { color: rgb0000003d, x: 0, y: 0, blur: 2 } as const; +const shadowLayer6 = { color: '#00000066', x: 0, y: 0, blur: 8 } as const; +const subtitle1 = { face: primary, size: 20, weight: fontWeight400 } as const; +const subtitle1Strong = { face: primary, size: 20, weight: fontWeight600 } as const; +const subtitle2 = { face: primary, size: 16, weight: fontWeight400 } as const; +const subtitle2Strong = { face: primary, size: 16, weight: fontWeight600 } as const; +const title1 = { face: primary, size: 28, weight: fontWeight400 } as const; +const title1Strong = { face: primary, size: 28, weight: fontWeight600 } as const; + +const sharedAliasColors = { + neutralForegroundOnBrand: rgbffffff, + neutralForegroundOnColor: rgbffffff, + neutralForegroundInverted: rgbffffff, + redBackground3: rgbd13438, + neutralForegroundOnBrandHover: rgbffffff, + neutralForegroundOnBrandPressed: rgbffffff, + neutralForegroundOnBrandSelected: rgbffffff, + subtleBackground: rgb00000000, + transparentBackground: rgb00000000, + transparentBackgroundHover: rgb00000000, + transparentBackgroundPressed: rgb00000000, + transparentBackgroundSelected: rgb00000000, + dangerBackground3: rgbd13438, + successBackground3: rgb107c10, + warningBackground3: rgbfde300, + severeBackground3: rgbda3b01, + outofofficeBackground3: rgbc239b3, + neutralBackgroundLightStatic: rgbffffff, + neutralForegroundDarkStatic: rgb000000, + neutralForegroundLightStatic: rgbffffff, +} as const; + +const lightHcLightAliasColors = { + ...sharedAliasColors, + neutralForegroundDisabled: rgb757575, + neutralForegroundDisabled1: rgb757575, + neutralForegroundDisabled2: rgb757575, + neutralForegroundInvertedLink: rgbffffff, + brandForegroundLink: rgb0078d4, + compoundBrandForeground1: rgb0078d4, + brandForeground2: rgb106ebe, + brandForegroundTint: rgb106ebe, + brandForeground1Disabled: rgb757575, + brandForegroundDisabled1: rgb757575, + brandForegroundDisabled2: rgb757575, + neutralBackgroundCanvas: rgbffffff, + neutralBackgroundLightStaticDisabled: rgbf0f0f0, + brandBackground2: rgbeff6fc, + brandBackground3: rgbeff6fc, + brandBackgroundTint: rgbeff6fc, + brandBackgroundInverted: rgb616161, + brandBackgroundInvertedDisabled: rgbf0f0f0, + brandBackgroundDisabled: '#d1d1d1', + compoundBrandBackground1: rgb0078d4, + brandBackgroundStatic: rgb0078d4, + neutralStrokeFocus1: rgbffffff, + neutralStrokeFocus2: rgb000000, + strokeFocus1: rgbffffff, + strokeFocus2: rgb000000, + brandStroke2: rgbc7e0f4, + brandStrokeTint: rgbc7e0f4, + compoundBrandStroke1: rgb0078d4, + dangerStroke1: rgbf1bbbc, + successStroke1: rgb9fd89f, + warningStroke1: rgbfef7b2, + severeStroke1: rgbf4bfab, + dangerBorder1: rgbf1bbbc, + successBorder1: rgb9fd89f, + warningBorder1: rgbfef7b2, + severeBorder1: rgbf4bfab, + presenceAway: rgb817400, + presenceDnd: rgbbc2f32, + presenceAvailable: rgb0e700e, + presenceOof: rgbaf33a1, + redBackground1: rgbfdf6f6, + redBackground2: rgbf1bbbc, + redForeground1: rgbbc2f32, + redForeground2: rgb751d1f, + redForeground3: rgbd13438, + redBorderActive: rgbd13438, + redBorder1: rgbf1bbbc, + redBorder2: rgbd13438, + neutralForeground2: rgb000000, + neutralForeground2Hover: rgb242424, + neutralForeground2Pressed: rgb242424, + neutralForeground2Selected: rgb242424, + neutralForeground2BrandHover: rgb106ebe, + neutralForeground2BrandPressed: rgb004578, + neutralForeground2BrandSelected: rgb005a9e, + neutralForeground3Hover: rgb424242, + neutralForeground3Pressed: rgb424242, + neutralForeground3Selected: rgb424242, + neutralForeground3BrandHover: rgb106ebe, + neutralForeground3BrandPressed: rgb004578, + neutralForeground3BrandSelected: rgb005a9e, + brandForegroundLinkHover: rgb106ebe, + brandForegroundLinkPressed: rgb004578, + brandForegroundLinkSelected: rgb005a9e, + compoundBrandForeground1Hover: rgb106ebe, + compoundBrandForeground1Pressed: rgb004578, + brandForeground1: rgb0078d4, + neutralForegroundInvertedLinkHover: rgbffffff, + neutralForegroundInvertedLinkPressed: rgbffffff, + neutralForegroundInvertedLinkSelected: rgbffffff, + neutralBackground1: rgbffffff, + neutralBackground1Hover: rgbf5f5f5, + neutralBackground1Pressed: rgbebebeb, + neutralBackground1Selected: rgbebebeb, + neutralBackground2: rgbffffff, + neutralBackground2Hover: rgbf0f0f0, + neutralBackground2Pressed: rgbebebeb, + neutralBackground2Selected: rgbe6e6e6, + neutralBackground3: rgbf5f5f5, + neutralBackground3Hover: rgbebebeb, + neutralBackground3Pressed: rgbd6d6d6, + neutralBackground3Selected: rgbe0e0e0, + neutralBackground4: rgbf0f0f0, + neutralBackground4Hover: rgbfafafa, + neutralBackground4Pressed: rgbf5f5f5, + neutralBackground4Selected: rgbffffff, + neutralBackground5: rgbebebeb, + neutralBackground5Hover: rgbf5f5f5, + neutralBackground5Pressed: rgbf0f0f0, + neutralBackground5Selected: rgbfafafa, + neutralBackground6: rgbe6e6e6, + neutralBackgroundInverted: rgb616161, + subtleBackgroundHover: rgbf5f5f5, + subtleBackgroundPressed: rgbe0e0e0, + subtleBackgroundSelected: rgbebebeb, + neutralBackgroundDisabled: rgbf0f0f0, + neutralStencil1: rgbe6e6e6, + neutralStencil2: rgbfafafa, + brandBackground: rgb0078d4, + brandBackgroundHover: rgb106ebe, + brandBackgroundPressed: rgb106ebe, + brandBackgroundSelected: rgb005a9e, + compoundBrandBackground1Hover: rgb106ebe, + compoundBrandBackground1Pressed: rgb004578, + neutralStrokeAccessibleHover: rgb575757, + neutralStrokeAccessiblePressed: '#4d4d4d', + neutralStrokeAccessibleSelected: rgb0078d4, + neutralStroke1Hover: '#c7c7c7', + neutralStroke1Pressed: rgbb3b3b3, + neutralStroke1Selected: rgbbdbdbd, + brandStroke1: rgb0078d4, + compoundBrandStroke1Hover: rgb106ebe, + compoundBrandStroke1Pressed: rgb004578, + neutralStrokeDisabled: rgbe0e0e0, + dangerBackground1: rgbfdf6f6, + dangerBackground2: rgbf1bbbc, + dangerForeground1: rgbbc2f32, + dangerForeground2: rgb751d1f, + dangerForeground3: rgbd13438, + dangerForegroundInverted: rgbdc5e62, + dangerBorderActive: rgbd13438, + dangerBorder2: rgbd13438, + successBackground1: '#f1faf1', + successBackground2: rgb9fd89f, + successForeground1: rgb0e700e, + successForeground2: rgb094509, + successForeground3: rgb107c10, + successForegroundInverted: '#359b35', + successBorderActive: rgb107c10, + successBorder2: rgb107c10, + warningBackground1: '#fffef5', + warningBackground2: rgbfef7b2, + warningForeground1: rgb817400, + warningForeground2: rgb817400, + warningForeground3: rgbfde300, + warningForegroundInverted: rgbfef7b2, + warningBorderActive: rgbfde300, + warningBorder2: rgbfde300, + severeBackground1: '#fdf6f3', + severeBackground2: rgbf4bfab, + severeForeground1: '#c43501', + severeForeground2: rgb7a2101, + severeForeground3: rgbda3b01, + severeBorderActive: rgbda3b01, + severeBorder2: rgbda3b01, + outofofficeBackground1: '#fdf5fc', + outofofficeBackground2: rgbedbbe7, + outofofficeForeground1: rgbaf33a1, + outofofficeForeground2: rgb6d2064, + outofofficeForeground3: rgbc239b3, + outofofficeBorderActive: rgbc239b3, + outofofficeBorder1: rgbedbbe7, + outofofficeBorder2: rgbc239b3, + brandForeground1Pressed: rgb004578, + neutralBackgroundDarkStatic: rgb242424, + brandBackground2Pressed: rgb106ebe, + brandBackground2Selected: rgb005a9e, + brandForeground1Selected: rgb005a9e, + brandStroke1Pressed: rgb004578, + brandStroke1Selected: rgb005a9e, +} as const; + +const darkDarkGrayHcHcDarkDarkElevatedAliasColors = { + ...sharedAliasColors, + neutralForegroundDisabled: rgbb8b8b8, + neutralForegroundDisabled1: rgbb8b8b8, + neutralForegroundDisabled2: rgbb8b8b8, + neutralForegroundInvertedLink: rgb292929, + brandForegroundLink: rgb043862, + compoundBrandForeground1: rgb043862, + brandForeground2: rgb092c47, + brandForegroundTint: rgb092c47, + brandForeground1Disabled: rgbc2c2c2, + brandForegroundDisabled1: rgbc2c2c2, + brandForegroundDisabled2: rgbc2c2c2, + neutralBackgroundCanvas: rgb000000, + neutralBackgroundLightStaticDisabled: rgb575757, + brandBackground2: rgb092c47, + brandBackground3: rgb092c47, + brandBackgroundTint: rgb092c47, + brandBackgroundInverted: rgbffffff, + brandBackgroundInvertedDisabled: rgb575757, + brandBackgroundDisabled: rgb575757, + compoundBrandBackground1: rgb0086f0, + brandBackgroundStatic: rgb0086f0, + neutralStrokeFocus1: rgb000000, + neutralStrokeFocus2: rgbffffff, + strokeFocus1: rgb000000, + strokeFocus2: rgbffffff, + brandStroke2: rgb004c87, + brandStrokeTint: rgb004c87, + compoundBrandStroke1: rgb0086f0, + dangerStroke1: rgbd13438, + successStroke1: rgb107c10, + warningStroke1: rgbfde300, + severeStroke1: rgbda3b01, + dangerBorder1: rgbd13438, + successBorder1: rgb107c10, + warningBorder1: rgbfde300, + severeBorder1: rgbda3b01, + presenceAway: rgbfeee66, + presenceDnd: rgbe37d80, + presenceAvailable: rgb54b054, + presenceOof: rgbda7ed0, + redBackground1: rgb3f1011, + redBackground2: rgb751d1f, + redForeground1: rgbe37d80, + redForeground2: rgbf1bbbc, + redForeground3: rgbe37d80, + redBorderActive: rgbe37d80, + redBorder1: rgbd13438, + redBorder2: rgbdc5e62, + neutralForeground1: rgbffffff, + neutralForeground1Hover: rgbffffff, + neutralForeground1Pressed: rgbffffff, + neutralForeground1Selected: rgbffffff, + neutralForeground2: rgbffffff, + neutralForeground2Hover: rgbffffff, + neutralForeground2Pressed: rgbffffff, + neutralForeground2Selected: rgbffffff, + neutralForeground2BrandHover: rgb092c47, + neutralForeground2BrandPressed: rgb0078d4, + neutralForeground2BrandSelected: rgb092c47, + neutralForeground3Hover: rgbd6d6d6, + neutralForeground3Pressed: rgbd6d6d6, + neutralForeground3Selected: rgbd6d6d6, + neutralForeground3BrandHover: rgb092c47, + neutralForeground3BrandPressed: rgb0078d4, + neutralForeground3BrandSelected: rgb092c47, + brandForegroundLinkHover: rgb092c47, + brandForegroundLinkPressed: rgb0078d4, + brandForegroundLinkSelected: rgb092c47, + compoundBrandForeground1Hover: rgb092c47, + compoundBrandForeground1Pressed: rgb0078d4, + brandForeground1: rgb0086f0, + neutralForegroundInvertedLinkHover: rgb292929, + neutralForegroundInvertedLinkPressed: rgb292929, + neutralForegroundInvertedLinkSelected: rgb292929, + neutralBackground1: rgb000000, + neutralBackground1Hover: rgb3d3d3d, + neutralBackground1Pressed: rgb5c5c5c, + neutralBackground1Selected: rgb383838, + neutralBackground2: rgb575757, + neutralBackground2Hover: rgb333333, + neutralBackground2Pressed: rgb707070, + neutralBackground2Selected: '#2e2e2e', + neutralBackground3: rgb575757, + neutralBackground3Hover: rgb292929, + neutralBackground3Pressed: '#0a0a0a', + neutralBackground3Selected: rgb242424, + neutralBackground4: rgb1f1f1f, + neutralBackground4Hover: rgb1f1f1f, + neutralBackground4Pressed: rgb000000, + neutralBackground4Selected: '#1a1a1a', + neutralBackground5: rgb5c5c5c, + neutralBackground5Hover: '#141414', + neutralBackground5Pressed: '#050505', + neutralBackground5Selected: '#0f0f0f', + neutralBackground6: rgb333333, + neutralBackgroundInverted: rgbffffff, + subtleBackgroundHover: rgb3d3d3d, + subtleBackgroundPressed: rgb1f1f1f, + subtleBackgroundSelected: rgb383838, + neutralBackgroundDisabled: rgb575757, + neutralStencil1: rgb333333, + neutralStencil2: rgb575757, + brandBackground: rgb0086f0, + brandBackgroundHover: rgb1890f1, + brandBackgroundPressed: rgb1890f1, + brandBackgroundSelected: rgb3aa0f3, + compoundBrandBackground1Hover: rgb1890f1, + compoundBrandBackground1Pressed: rgb6cb8f6, + neutralStrokeAccessibleHover: rgbbdbdbd, + neutralStrokeAccessiblePressed: rgbb3b3b3, + neutralStrokeAccessibleSelected: rgb0086f0, + neutralStroke1Hover: rgb757575, + neutralStroke1Pressed: '#6b6b6b', + neutralStroke1Selected: rgb707070, + brandStroke1: rgb0086f0, + compoundBrandStroke1Hover: rgb1890f1, + compoundBrandStroke1Pressed: rgb6cb8f6, + neutralStrokeDisabled: '#525252', + dangerBackground1: rgb3f1011, + dangerBackground2: rgb751d1f, + dangerForeground1: rgbe37d80, + dangerForeground2: rgbf1bbbc, + dangerForeground3: rgbe37d80, + dangerForegroundInverted: rgbd13438, + dangerBorderActive: rgbe37d80, + dangerBorder2: rgbdc5e62, + successBackground1: '#052505', + successBackground2: rgb094509, + successForeground1: rgb54b054, + successForeground2: rgb9fd89f, + successForeground3: rgb9fd89f, + successForegroundInverted: rgb107c10, + successBorderActive: rgb54b054, + successBorder2: rgb9fd89f, + warningBackground1: '#4c4400', + warningBackground2: rgb817400, + warningForeground1: rgbfeee66, + warningForeground2: rgbfef7b2, + warningForeground3: rgbfdea3d, + warningForegroundInverted: rgb817400, + warningBorderActive: rgbfeee66, + warningBorder2: rgbfdea3d, + severeBackground1: '#411200', + severeBackground2: rgb7a2101, + severeForeground1: rgbe9835e, + severeForeground2: rgbf4bfab, + severeForeground3: rgbe9835e, + severeBorderActive: rgbe9835e, + severeBorder2: rgbe9835e, + outofofficeBackground1: '#3a1136', + outofofficeBackground2: rgb6d2064, + outofofficeForeground1: rgbda7ed0, + outofofficeForeground2: rgbedbbe7, + outofofficeForeground3: rgbd161c4, + outofofficeBorderActive: rgbda7ed0, + outofofficeBorder1: rgbc239b3, + outofofficeBorder2: rgbd161c4, + brandForeground1Pressed: rgb6cb8f6, + neutralBackgroundDarkStatic: rgb3d3d3d, + brandBackground2Pressed: rgb1890f1, + brandBackground2Selected: rgb3aa0f3, + brandForeground1Selected: rgb3aa0f3, + brandStroke1Pressed: rgb6cb8f6, + brandStroke1Selected: rgb3aa0f3, +} as const; + +const lightDarkDarkGrayDarkElevatedAliasColors = { + ...sharedAliasColors, + transparentStroke: rgb00000000, + transparentStrokeInteractive: rgb00000000, + transparentStrokeDisabled: rgb00000000, +} as const; + +const sharedShadows = { + shadow2brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 1, blur: 2 } }, + shadow4brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 2, blur: 4 } }, + shadow8brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 4, blur: 8 } }, + shadow16brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 8, blur: 16 } }, + shadow28brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 14, blur: 28 } }, + shadow64brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 32, blur: 64 } }, +} as const; + +export const lightShadows: BaseShadowAliasTokens = { + ...sharedShadows, + shadow2: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 1, blur: 2 } }, + shadow4: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 2, blur: 4 } }, + shadow8: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 4, blur: 8 } }, + shadow16: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 8, blur: 16 } }, + shadow28: { ambient: shadowLayer2, key: { color: rgb0000003d, x: 0, y: 14, blur: 28 } }, + shadow64: { ambient: shadowLayer2, key: { color: rgb0000003d, x: 0, y: 32, blur: 64 } }, +}; + +export const darkShadows: BaseShadowAliasTokens = { + ...sharedShadows, + shadow2: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 1, blur: 2 } }, + shadow4: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 2, blur: 4 } }, + shadow8: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 4, blur: 8 } }, + shadow16: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 8, blur: 16 } }, + shadow28: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 14, blur: 28 } }, + shadow64: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 32, blur: 64 } }, +}; + +export const darkGrayShadows: BaseShadowAliasTokens = darkShadows; +export const hcShadows: BaseShadowAliasTokens = darkShadows; +export const hcLightShadows: BaseShadowAliasTokens = darkShadows; +export const hcDarkShadows: BaseShadowAliasTokens = darkShadows; +export const darkElevatedShadows: BaseShadowAliasTokens = darkShadows; + +export const lightAliasColors: Required = { + ...lightHcLightAliasColors, + ...lightDarkDarkGrayDarkElevatedAliasColors, + neutralForeground4: '#808080', + neutralStroke3: rgbf0f0f0, + neutralForeground1: rgb242424, + neutralForeground1Hover: rgb242424, + neutralForeground1Pressed: rgb242424, + neutralForeground1Selected: rgb242424, + neutralForeground3: rgb616161, + neutralStrokeAccessible: rgb616161, + neutralStroke1: rgbf0f0f0, + neutralStroke2: rgbd6d6d6, +}; + +export const darkAliasColors: Required = { + ...darkDarkGrayHcHcDarkDarkElevatedAliasColors, + ...lightDarkDarkGrayDarkElevatedAliasColors, + neutralForeground4: '#858585', + neutralStroke3: rgb666666, + neutralForeground3: rgbadadad, + neutralStrokeAccessible: rgbadadad, + neutralStroke1: rgb3d3d3d, + neutralStroke2: rgb575757, +}; + +export const darkGrayAliasColors: Required = darkAliasColors; + +export const hcAliasColors: Required = { + ...darkDarkGrayHcHcDarkDarkElevatedAliasColors, + neutralForeground4: rgbd6d6d6, + neutralStroke3: rgbadadad, + neutralForeground3: rgbd6d6d6, + neutralStrokeAccessible: rgbd6d6d6, + neutralStroke1: rgbadadad, + neutralStroke2: rgba8a8a8, + transparentStroke: rgb3aa0f3, + transparentStrokeInteractive: rgba8a8a8, + transparentStrokeDisabled: rgbd6d6d6, +}; + +export const hcLightAliasColors: Required = { + ...lightHcLightAliasColors, + neutralForeground4: rgb424242, + neutralStroke3: rgb616161, + neutralForeground1: rgb000000, + neutralForeground1Hover: rgb000000, + neutralForeground1Pressed: rgb000000, + neutralForeground1Selected: rgb000000, + neutralForeground3: rgb000000, + neutralStrokeAccessible: rgb242424, + neutralStroke1: rgb616161, + neutralStroke2: rgb000000, + transparentStroke: rgb000000, + transparentStrokeInteractive: rgb666666, + transparentStrokeDisabled: rgbbdbdbd, +}; + +export const hcDarkAliasColors: Required = hcAliasColors; +export const darkElevatedAliasColors: Required = darkAliasColors; + +/** Font aliases from the light appearance, completed with native equivalents and the platform global ramp. */ +export const fontAliasTokens: Required = { + caption1, + body1, + body1Strong, + body2, + body2Strong, + subtitle1, + subtitle1Strong, + subtitle2, + subtitle2Strong, + title1, + title1Strong, + largeTitle, + display, + caption1Strong: { face: primary, size: 10, weight: fontWeight600 }, + caption2: caption1, + title2: subtitle1, + title3: subtitle2, + captionStandard: caption1, + secondaryStandard: body1, + secondarySemibold: body1Strong, + bodyStandard: body2, + bodySemibold: body2Strong, + subheaderStandard: subtitle2, + subheaderSemibold: subtitle2Strong, + headerStandard: subtitle1, + headerSemibold: subtitle1Strong, + heroStandard: title1, + heroSemibold: title1Strong, + heroLargeStandard: largeTitle, + heroLargeSemibold: display, +}; diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts index 065e1d39ec..11005744bd 100644 --- a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts @@ -1,90 +1,807 @@ /** - * WARNING: This file is auto-generated. Do not edit it manually. + * WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually. + * Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults. + * Unsupported appearances inherit the closest supported appearance. Shared values are emitted once. */ +import { PlatformColor } from 'react-native'; + +import type { AliasColorTokens } from '../types/Color.types'; import type { BaseShadowAliasTokens } from '../types/Shadow.types'; +import type { Variants } from '../types/Typography.types'; + +const platformColorButtonFace = /* @__PURE__ */ PlatformColor('ButtonFace'); +const platformColorButtonText = /* @__PURE__ */ PlatformColor('ButtonText'); +const platformColorGrayText = /* @__PURE__ */ PlatformColor('GrayText'); +const platformColorHighlight = /* @__PURE__ */ PlatformColor('Highlight'); +const platformColorHighlightText = /* @__PURE__ */ PlatformColor('HighlightText'); +const platformColorHotlight = /* @__PURE__ */ PlatformColor('Hotlight'); +const platformColorWindow = /* @__PURE__ */ PlatformColor('Window'); +const platformColorWindowText = /* @__PURE__ */ PlatformColor('WindowText'); -const rgb0000001f = '#0000001f'; +const fontWeight400 = '400'; +const fontWeight600 = '600'; +const primary = 'primary'; +const rgb000000 = '#000000'; +const rgb00000000 = '#00000000'; const rgb00000024 = '#00000024'; -const rgb00000033 = '#00000033'; const rgb0000003d = '#0000003d'; const rgb00000040 = '#00000040'; const rgb00000047 = '#00000047'; const rgb0000004d = '#0000004d'; -const rgb00000066 = '#00000066'; const rgb0000007a = '#0000007a'; +const rgb094509 = '#094509'; +const rgb0a0a0a = '#0a0a0a'; +const rgb0e336a = '#0e336a'; +const rgb0e700e = '#0e700e'; +const rgb107c10 = '#107c10'; +const rgb13458f = '#13458f'; +const rgb141414 = '#141414'; +const rgb1651aa = '#1651aa'; +const rgb185abd = '#185abd'; +const rgb1a1a1a = '#1a1a1a'; +const rgb1f1f1f = '#1f1f1f'; +const rgb242424 = '#242424'; +const rgb292929 = '#292929'; +const rgb2e2e2e = '#2e2e2e'; +const rgb2e6ac5 = '#2e6ac5'; +const rgb333333 = '#333333'; +const rgb383838 = '#383838'; +const rgb3d3d3d = '#3d3d3d'; +const rgb3f1011 = '#3f1011'; +const rgb424242 = '#424242'; +const rgb474747 = '#474747'; +const rgb4d4d4d = '#4d4d4d'; +const rgb525252 = '#525252'; +const rgb54b054 = '#54b054'; +const rgb575757 = '#575757'; +const rgb5c5c5c = '#5c5c5c'; +const rgb616161 = '#616161'; +const rgb666666 = '#666666'; +const rgb6794d7 = '#6794d7'; +const rgb6d2064 = '#6d2064'; +const rgb707070 = '#707070'; +const rgb751d1f = '#751d1f'; +const rgb757575 = '#757575'; +const rgb7a2101 = '#7a2101'; +const rgb817400 = '#817400'; +const rgb999999 = '#999999'; +const rgb9fd89f = '#9fd89f'; +const rgbadadad = '#adadad'; +const rgbaec6eb = '#aec6eb'; +const rgbaf33a1 = '#af33a1'; +const rgbb3b3b3 = '#b3b3b3'; +const rgbbc2f32 = '#bc2f32'; +const rgbbdbdbd = '#bdbdbd'; +const rgbc239b3 = '#c239b3'; +const rgbd13438 = '#d13438'; +const rgbd161c4 = '#d161c4'; +const rgbd2e0f4 = '#d2e0f4'; +const rgbd6d6d6 = '#d6d6d6'; +const rgbda3b01 = '#da3b01'; +const rgbda7ed0 = '#da7ed0'; +const rgbdc5e62 = '#dc5e62'; +const rgbe0e0e0 = '#e0e0e0'; +const rgbe37d80 = '#e37d80'; +const rgbe6e6e6 = '#e6e6e6'; +const rgbe9835e = '#e9835e'; +const rgbebebeb = '#ebebeb'; +const rgbedbbe7 = '#edbbe7'; +const rgbf0f0f0 = '#f0f0f0'; +const rgbf1bbbc = '#f1bbbc'; +const rgbf4bfab = '#f4bfab'; +const rgbf5f5f5 = '#f5f5f5'; +const rgbfafafa = '#fafafa'; +const rgbfde300 = '#fde300'; +const rgbfdea3d = '#fdea3d'; +const rgbfdf6f6 = '#fdf6f6'; +const rgbfeee66 = '#feee66'; +const rgbfef7b2 = '#fef7b2'; +const rgbffffff = '#ffffff'; + +const body1 = { face: primary, size: 12, weight: fontWeight400 } as const; +const body1Strong = { face: primary, size: 12, weight: fontWeight600 } as const; +const body2 = { face: primary, size: 14, weight: fontWeight400 } as const; +const body2Strong = { face: primary, size: 14, weight: fontWeight600 } as const; +const caption1 = { face: primary, size: 10, weight: fontWeight400 } as const; +const display = { face: primary, size: 40, weight: fontWeight600 } as const; +const largeTitle = { face: primary, size: 40, weight: fontWeight400 } as const; +const shadowLayer1 = { color: '#0000001f', x: 0, y: 0, blur: 2 } as const; +const shadowLayer2 = { color: '#00000033', x: 0, y: 0, blur: 8 } as const; +const shadowLayer3 = { color: rgb0000004d, x: 0, y: 0, blur: 2 } as const; +const shadowLayer4 = { color: rgb0000004d, x: 0, y: 0, blur: 8 } as const; +const shadowLayer5 = { color: rgb0000003d, x: 0, y: 0, blur: 2 } as const; +const shadowLayer6 = { color: '#00000066', x: 0, y: 0, blur: 8 } as const; +const subtitle1 = { face: primary, size: 20, weight: fontWeight400 } as const; +const subtitle1Strong = { face: primary, size: 20, weight: fontWeight600 } as const; +const subtitle2 = { face: primary, size: 16, weight: fontWeight400 } as const; +const subtitle2Strong = { face: primary, size: 16, weight: fontWeight600 } as const; +const title1 = { face: primary, size: 28, weight: fontWeight400 } as const; +const title1Strong = { face: primary, size: 28, weight: fontWeight600 } as const; + +const sharedAliasColors = { + subtleBackground: rgb00000000, + transparentBackground: rgb00000000, + transparentBackgroundHover: rgb00000000, + transparentBackgroundPressed: rgb00000000, + transparentBackgroundSelected: rgb00000000, + neutralBackgroundLightStatic: rgbffffff, + neutralForegroundDarkStatic: rgb000000, + neutralForegroundLightStatic: rgbffffff, +} as const; + +const lightDarkDarkGrayDarkElevatedAliasColors = { + ...sharedAliasColors, + neutralForegroundOnBrand: rgbffffff, + neutralForegroundOnColor: rgbffffff, + brandBackground2: rgbd2e0f4, + brandBackground3: rgbd2e0f4, + brandBackgroundTint: rgbd2e0f4, + compoundBrandBackground1: rgb185abd, + brandBackgroundStatic: rgb185abd, + brandStroke2: rgb6794d7, + brandStrokeTint: rgb6794d7, + compoundBrandStroke1: rgb185abd, + redBackground3: rgbd13438, + neutralForegroundOnBrandHover: rgbffffff, + neutralForegroundOnBrandPressed: rgbffffff, + neutralForegroundOnBrandSelected: rgbffffff, + brandBackground: rgb185abd, + brandBackgroundHover: rgb1651aa, + brandBackgroundPressed: rgb0e336a, + brandBackgroundSelected: rgb13458f, + compoundBrandBackground1Hover: rgb1651aa, + compoundBrandBackground1Pressed: rgb0e336a, + neutralStrokeAccessibleSelected: rgb185abd, + brandStroke1: rgb185abd, + compoundBrandStroke1Hover: rgb1651aa, + compoundBrandStroke1Pressed: rgb0e336a, + transparentStroke: rgb00000000, + transparentStrokeInteractive: rgb00000000, + transparentStrokeDisabled: rgb00000000, + dangerBackground3: rgbd13438, + successBackground3: rgb107c10, + warningBackground3: rgbfde300, + severeBackground3: rgbda3b01, + outofofficeBackground3: rgbc239b3, + brandBackground2Pressed: rgb0e336a, + brandBackground2Selected: rgb13458f, + brandStroke1Pressed: rgb185abd, + brandStroke1Selected: rgb185abd, +} as const; -const shadowLayer1 = { x: 0, y: 0, blur: 2, color: rgb0000003d }; -const shadowLayer2 = { x: 0, y: 8, blur: 16, color: rgb00000047 }; -const shadowLayer3 = { x: 0, y: 1, blur: 2, color: rgb00000047 }; -const shadowLayer4 = { x: 0, y: 0, blur: 8, color: rgb00000066 }; -const shadowLayer5 = { x: 0, y: 14, blur: 28, color: rgb0000007a }; -const shadowLayer6 = { x: 0, y: 2, blur: 4, color: rgb00000047 }; -const shadowLayer7 = { x: 0, y: 32, blur: 64, color: rgb0000007a }; -const shadowLayer8 = { x: 0, y: 4, blur: 8, color: rgb00000047 }; -const shadowLayer9 = { x: 0, y: 0, blur: 2, color: rgb0000004d }; -const shadowLayer10 = { x: 0, y: 8, blur: 16, color: rgb00000040 }; -const shadowLayer11 = { x: 0, y: 1, blur: 2, color: rgb00000040 }; -const shadowLayer12 = { x: 0, y: 0, blur: 8, color: rgb0000004d }; -const shadowLayer13 = { x: 0, y: 14, blur: 28, color: rgb00000040 }; -const shadowLayer14 = { x: 0, y: 2, blur: 4, color: rgb00000040 }; -const shadowLayer15 = { x: 0, y: 32, blur: 64, color: rgb00000040 }; -const shadowLayer16 = { x: 0, y: 4, blur: 8, color: rgb00000040 }; -const shadowLayer17 = { x: 0, y: 0, blur: 2, color: rgb0000001f }; -const shadowLayer18 = { x: 0, y: 0, blur: 8, color: rgb00000033 }; +const darkDarkGrayHcHcLightHcDarkDarkElevatedAliasColors = { + ...sharedAliasColors, + neutralBackgroundDarkStatic: rgb3d3d3d, +} as const; + +const sharedShadows = { + shadow2brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 1, blur: 2 } }, + shadow4brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 2, blur: 4 } }, + shadow8brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 4, blur: 8 } }, + shadow16brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 8, blur: 16 } }, + shadow28brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 14, blur: 28 } }, + shadow64brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 32, blur: 64 } }, +} as const; + +const darkDarkGrayDarkElevatedAliasColors = { + ...lightDarkDarkGrayDarkElevatedAliasColors, + ...darkDarkGrayHcHcLightHcDarkDarkElevatedAliasColors, + neutralForegroundInverted: rgb000000, + brandForegroundLink: rgbaec6eb, + compoundBrandForeground1: rgbaec6eb, + brandForeground2: rgbd2e0f4, + brandForegroundTint: rgbd2e0f4, + brandBackgroundInverted: rgbffffff, + neutralStrokeFocus1: rgb000000, + neutralStrokeFocus2: rgbffffff, + strokeFocus1: rgb000000, + strokeFocus2: rgbffffff, + dangerStroke1: rgbd13438, + successStroke1: rgb107c10, + warningStroke1: rgbfde300, + severeStroke1: rgbda3b01, + dangerBorder1: rgbd13438, + successBorder1: rgb107c10, + warningBorder1: rgbfde300, + severeBorder1: rgbda3b01, + presenceAway: rgbfeee66, + presenceDnd: rgbe37d80, + presenceAvailable: rgb54b054, + presenceOof: rgbda7ed0, + redBackground1: rgb3f1011, + redBackground2: rgb751d1f, + redForeground1: rgbe37d80, + redForeground2: rgbf1bbbc, + redForeground3: rgbe37d80, + redBorderActive: rgbe37d80, + redBorder1: rgbd13438, + redBorder2: rgbdc5e62, + neutralForeground1: rgbffffff, + neutralForeground1Hover: rgbffffff, + neutralForeground1Pressed: rgbffffff, + neutralForeground1Selected: rgbffffff, + neutralForeground2Hover: rgbffffff, + neutralForeground2Pressed: rgbffffff, + neutralForeground2Selected: rgbffffff, + neutralForeground2BrandHover: rgbd2e0f4, + neutralForeground2BrandPressed: rgb2e6ac5, + neutralForeground2BrandSelected: rgbd2e0f4, + neutralForeground3BrandHover: rgbd2e0f4, + neutralForeground3BrandPressed: rgb2e6ac5, + neutralForeground3BrandSelected: rgbd2e0f4, + brandForegroundLinkHover: rgbd2e0f4, + brandForegroundLinkPressed: rgb2e6ac5, + brandForegroundLinkSelected: rgbd2e0f4, + compoundBrandForeground1Hover: rgbd2e0f4, + compoundBrandForeground1Pressed: rgb2e6ac5, + brandForeground1: rgbaec6eb, + neutralBackgroundInverted: rgbffffff, + dangerBackground1: rgb3f1011, + dangerBackground2: rgb751d1f, + dangerForeground1: rgbe37d80, + dangerForeground2: rgbf1bbbc, + dangerForeground3: rgbe37d80, + dangerForegroundInverted: rgbd13438, + dangerBorderActive: rgbe37d80, + dangerBorder2: rgbdc5e62, + successBackground1: '#052505', + successBackground2: rgb094509, + successForeground1: rgb54b054, + successForeground2: rgb9fd89f, + successForeground3: rgb9fd89f, + successForegroundInverted: rgb107c10, + successBorderActive: rgb54b054, + successBorder2: rgb9fd89f, + warningBackground1: '#4c4400', + warningBackground2: rgb817400, + warningForeground1: rgbfeee66, + warningForeground2: rgbfef7b2, + warningForeground3: rgbfdea3d, + warningForegroundInverted: rgb817400, + warningBorderActive: rgbfeee66, + warningBorder2: rgbfdea3d, + severeBackground1: '#411200', + severeBackground2: rgb7a2101, + severeForeground1: rgbe9835e, + severeForeground2: rgbf4bfab, + severeForeground3: rgbe9835e, + severeBorderActive: rgbe9835e, + severeBorder2: rgbe9835e, + outofofficeBackground1: '#3a1136', + outofofficeBackground2: rgb6d2064, + outofofficeForeground1: rgbda7ed0, + outofofficeForeground2: rgbedbbe7, + outofofficeForeground3: rgbd161c4, + outofofficeBorderActive: rgbda7ed0, + outofofficeBorder1: rgbc239b3, + outofofficeBorder2: rgbd161c4, + brandForeground1Pressed: rgbaec6eb, + brandForeground1Selected: rgbaec6eb, +} as const; + +export const lightShadows: BaseShadowAliasTokens = { + ...sharedShadows, + shadow2: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 1, blur: 2 } }, + shadow4: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 2, blur: 4 } }, + shadow8: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 4, blur: 8 } }, + shadow16: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 8, blur: 16 } }, + shadow28: { ambient: shadowLayer2, key: { color: rgb0000003d, x: 0, y: 14, blur: 28 } }, + shadow64: { ambient: shadowLayer2, key: { color: rgb0000003d, x: 0, y: 32, blur: 64 } }, +}; export const darkShadows: BaseShadowAliasTokens = { - shadow16: { ambient: shadowLayer1, key: shadowLayer2 }, - shadow2: { ambient: shadowLayer1, key: shadowLayer3 }, - shadow28: { ambient: shadowLayer4, key: shadowLayer5 }, - shadow4: { ambient: shadowLayer1, key: shadowLayer6 }, - shadow64: { ambient: shadowLayer4, key: shadowLayer7 }, - shadow8: { ambient: shadowLayer1, key: shadowLayer8 }, - shadow16brand: { ambient: shadowLayer9, key: shadowLayer10 }, - shadow2brand: { ambient: shadowLayer9, key: shadowLayer11 }, - shadow28brand: { ambient: shadowLayer12, key: shadowLayer13 }, - shadow4brand: { ambient: shadowLayer9, key: shadowLayer14 }, - shadow64brand: { ambient: shadowLayer12, key: shadowLayer15 }, - shadow8brand: { ambient: shadowLayer9, key: shadowLayer16 }, + ...sharedShadows, + shadow2: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 1, blur: 2 } }, + shadow4: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 2, blur: 4 } }, + shadow8: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 4, blur: 8 } }, + shadow16: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 8, blur: 16 } }, + shadow28: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 14, blur: 28 } }, + shadow64: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 32, blur: 64 } }, }; -export const lightShadows: BaseShadowAliasTokens = { - shadow16: { ambient: shadowLayer17, key: { x: 0, y: 8, blur: 16, color: rgb00000024 } }, - shadow2: { ambient: shadowLayer17, key: { x: 0, y: 1, blur: 2, color: rgb00000024 } }, - shadow28: { ambient: shadowLayer18, key: { x: 0, y: 14, blur: 28, color: rgb0000003d } }, - shadow4: { ambient: shadowLayer17, key: { x: 0, y: 2, blur: 4, color: rgb00000024 } }, - shadow64: { ambient: shadowLayer18, key: { x: 0, y: 32, blur: 64, color: rgb0000003d } }, - shadow8: { ambient: shadowLayer17, key: { x: 0, y: 4, blur: 8, color: rgb00000024 } }, - shadow16brand: { ambient: shadowLayer9, key: shadowLayer10 }, - shadow2brand: { ambient: shadowLayer9, key: shadowLayer11 }, - shadow28brand: { ambient: shadowLayer12, key: shadowLayer13 }, - shadow4brand: { ambient: shadowLayer9, key: shadowLayer14 }, - shadow64brand: { ambient: shadowLayer12, key: shadowLayer15 }, - shadow8brand: { ambient: shadowLayer9, key: shadowLayer16 }, + +export const darkGrayShadows: BaseShadowAliasTokens = darkShadows; +export const hcShadows: BaseShadowAliasTokens = darkShadows; +export const hcLightShadows: BaseShadowAliasTokens = darkShadows; +export const hcDarkShadows: BaseShadowAliasTokens = darkShadows; +export const darkElevatedShadows: BaseShadowAliasTokens = darkShadows; + +export const lightAliasColors: Required = { + ...lightDarkDarkGrayDarkElevatedAliasColors, + neutralForeground4: rgb707070, + neutralForegroundDisabled: rgbbdbdbd, + neutralForegroundDisabled1: rgbbdbdbd, + neutralForegroundDisabled2: rgbbdbdbd, + neutralForegroundInverted: rgbffffff, + neutralForegroundInvertedLink: rgbffffff, + brandForegroundLink: rgb185abd, + compoundBrandForeground1: rgb185abd, + brandForeground2: rgb1651aa, + brandForegroundTint: rgb1651aa, + brandForeground1Disabled: rgbbdbdbd, + brandForegroundDisabled1: rgbbdbdbd, + brandForegroundDisabled2: rgbbdbdbd, + neutralBackgroundCanvas: rgbffffff, + neutralBackgroundLightStaticDisabled: rgbf0f0f0, + brandBackgroundInverted: rgb616161, + brandBackgroundInvertedDisabled: rgbf0f0f0, + brandBackgroundDisabled: rgbf0f0f0, + neutralStroke3: rgbf0f0f0, + neutralStrokeFocus1: rgbffffff, + neutralStrokeFocus2: rgb000000, + strokeFocus1: rgbffffff, + strokeFocus2: rgb000000, + dangerStroke1: rgbf1bbbc, + successStroke1: rgb9fd89f, + warningStroke1: rgbfef7b2, + severeStroke1: rgbf4bfab, + dangerBorder1: rgbf1bbbc, + successBorder1: rgb9fd89f, + warningBorder1: rgbfef7b2, + severeBorder1: rgbf4bfab, + presenceAway: rgb817400, + presenceDnd: rgbbc2f32, + presenceAvailable: rgb0e700e, + presenceOof: rgbaf33a1, + redBackground1: rgbfdf6f6, + redBackground2: rgbf1bbbc, + redForeground1: rgbbc2f32, + redForeground2: rgb751d1f, + redForeground3: rgbd13438, + redBorderActive: rgbd13438, + redBorder1: rgbf1bbbc, + redBorder2: rgbd13438, + neutralForeground1: rgb242424, + neutralForeground1Hover: rgb242424, + neutralForeground1Pressed: rgb242424, + neutralForeground1Selected: rgb242424, + neutralForeground2: rgb424242, + neutralForeground2Hover: rgb242424, + neutralForeground2Pressed: rgb242424, + neutralForeground2Selected: rgb242424, + neutralForeground2BrandHover: rgb1651aa, + neutralForeground2BrandPressed: rgb0e336a, + neutralForeground2BrandSelected: rgb13458f, + neutralForeground3: rgb616161, + neutralForeground3Hover: rgb424242, + neutralForeground3Pressed: rgb424242, + neutralForeground3Selected: rgb424242, + neutralForeground3BrandHover: rgb1651aa, + neutralForeground3BrandPressed: rgb0e336a, + neutralForeground3BrandSelected: rgb13458f, + brandForegroundLinkHover: rgb1651aa, + brandForegroundLinkPressed: rgb0e336a, + brandForegroundLinkSelected: rgb13458f, + compoundBrandForeground1Hover: rgb1651aa, + compoundBrandForeground1Pressed: rgb0e336a, + brandForeground1: rgb185abd, + neutralForegroundInvertedLinkHover: rgbffffff, + neutralForegroundInvertedLinkPressed: rgbffffff, + neutralForegroundInvertedLinkSelected: rgbffffff, + neutralBackground1: rgbffffff, + neutralBackground1Hover: rgbf5f5f5, + neutralBackground1Pressed: rgbe0e0e0, + neutralBackground1Selected: rgbebebeb, + neutralBackground2: rgbfafafa, + neutralBackground2Hover: rgbf0f0f0, + neutralBackground2Pressed: '#dbdbdb', + neutralBackground2Selected: rgbe6e6e6, + neutralBackground3: rgbf5f5f5, + neutralBackground3Hover: rgbebebeb, + neutralBackground3Pressed: rgbd6d6d6, + neutralBackground3Selected: rgbe0e0e0, + neutralBackground4: rgbf0f0f0, + neutralBackground4Hover: rgbfafafa, + neutralBackground4Pressed: rgbf5f5f5, + neutralBackground4Selected: rgbffffff, + neutralBackground5: rgbebebeb, + neutralBackground5Hover: rgbf5f5f5, + neutralBackground5Pressed: rgbf0f0f0, + neutralBackground5Selected: rgbfafafa, + neutralBackground6: rgbe6e6e6, + neutralBackgroundInverted: rgb616161, + subtleBackgroundHover: rgbf5f5f5, + subtleBackgroundPressed: rgbe0e0e0, + subtleBackgroundSelected: rgbebebeb, + neutralBackgroundDisabled: rgbf0f0f0, + neutralStencil1: rgbe6e6e6, + neutralStencil2: rgbfafafa, + neutralStrokeAccessible: rgb616161, + neutralStrokeAccessibleHover: rgb575757, + neutralStrokeAccessiblePressed: rgb4d4d4d, + neutralStroke1: '#d1d1d1', + neutralStroke1Hover: '#c7c7c7', + neutralStroke1Pressed: rgbb3b3b3, + neutralStroke1Selected: rgbbdbdbd, + neutralStroke2: rgbe0e0e0, + neutralStrokeDisabled: rgbe0e0e0, + dangerBackground1: rgbfdf6f6, + dangerBackground2: rgbf1bbbc, + dangerForeground1: rgbbc2f32, + dangerForeground2: rgb751d1f, + dangerForeground3: rgbd13438, + dangerForegroundInverted: rgbdc5e62, + dangerBorderActive: rgbd13438, + dangerBorder2: rgbd13438, + successBackground1: '#f1faf1', + successBackground2: rgb9fd89f, + successForeground1: rgb0e700e, + successForeground2: rgb094509, + successForeground3: rgb107c10, + successForegroundInverted: '#359b35', + successBorderActive: rgb107c10, + successBorder2: rgb107c10, + warningBackground1: '#fffef5', + warningBackground2: rgbfef7b2, + warningForeground1: rgb817400, + warningForeground2: rgb817400, + warningForeground3: rgbfde300, + warningForegroundInverted: rgbfef7b2, + warningBorderActive: rgbfde300, + warningBorder2: rgbfde300, + severeBackground1: '#fdf6f3', + severeBackground2: rgbf4bfab, + severeForeground1: '#c43501', + severeForeground2: rgb7a2101, + severeForeground3: rgbda3b01, + severeBorderActive: rgbda3b01, + severeBorder2: rgbda3b01, + outofofficeBackground1: '#fdf5fc', + outofofficeBackground2: rgbedbbe7, + outofofficeForeground1: rgbaf33a1, + outofofficeForeground2: rgb6d2064, + outofofficeForeground3: rgbc239b3, + outofofficeBorderActive: rgbc239b3, + outofofficeBorder1: rgbedbbe7, + outofofficeBorder2: rgbc239b3, + brandForeground1Pressed: rgb185abd, + neutralBackgroundDarkStatic: rgb242424, + brandForeground1Selected: rgb185abd, +}; + +export const darkAliasColors: Required = { + ...darkDarkGrayDarkElevatedAliasColors, + neutralForeground4: rgb999999, + neutralForegroundDisabled: rgb5c5c5c, + neutralForegroundDisabled1: rgb5c5c5c, + neutralForegroundDisabled2: rgb5c5c5c, + neutralForegroundInvertedLink: rgb292929, + brandForeground1Disabled: rgb5c5c5c, + brandForegroundDisabled1: rgb5c5c5c, + brandForegroundDisabled2: rgb5c5c5c, + neutralBackgroundCanvas: rgb292929, + neutralBackgroundLightStaticDisabled: rgb141414, + brandBackgroundInvertedDisabled: rgb141414, + brandBackgroundDisabled: rgb141414, + neutralStroke3: rgb3d3d3d, + neutralForeground2: rgbd6d6d6, + neutralForeground3: rgbadadad, + neutralForeground3Hover: rgbd6d6d6, + neutralForeground3Pressed: rgbd6d6d6, + neutralForeground3Selected: rgbd6d6d6, + neutralForegroundInvertedLinkHover: rgb292929, + neutralForegroundInvertedLinkPressed: rgb292929, + neutralForegroundInvertedLinkSelected: rgb292929, + neutralBackground1: rgb292929, + neutralBackground1Hover: rgb3d3d3d, + neutralBackground1Pressed: rgb1f1f1f, + neutralBackground1Selected: rgb383838, + neutralBackground2: rgb1f1f1f, + neutralBackground2Hover: rgb333333, + neutralBackground2Pressed: rgb141414, + neutralBackground2Selected: rgb2e2e2e, + neutralBackground3: rgb141414, + neutralBackground3Hover: rgb292929, + neutralBackground3Pressed: rgb0a0a0a, + neutralBackground3Selected: rgb242424, + neutralBackground4: rgb0a0a0a, + neutralBackground4Hover: rgb1f1f1f, + neutralBackground4Pressed: rgb000000, + neutralBackground4Selected: rgb1a1a1a, + neutralBackground5: rgb000000, + neutralBackground5Hover: rgb141414, + neutralBackground5Pressed: '#050505', + neutralBackground5Selected: '#0f0f0f', + neutralBackground6: rgb333333, + subtleBackgroundHover: rgb3d3d3d, + subtleBackgroundPressed: rgb1f1f1f, + subtleBackgroundSelected: rgb383838, + neutralBackgroundDisabled: rgb141414, + neutralStencil1: rgb333333, + neutralStencil2: rgb575757, + neutralStrokeAccessible: rgbadadad, + neutralStrokeAccessibleHover: rgbbdbdbd, + neutralStrokeAccessiblePressed: rgbb3b3b3, + neutralStroke1: rgb666666, + neutralStroke1Hover: rgb757575, + neutralStroke1Pressed: '#6b6b6b', + neutralStroke1Selected: rgb707070, + neutralStroke2: rgb525252, + neutralStrokeDisabled: rgb424242, }; -export const hcShadows: BaseShadowAliasTokens = { - shadow16: { ambient: shadowLayer1, key: shadowLayer2 }, - shadow2: { ambient: shadowLayer1, key: shadowLayer3 }, - shadow28: { ambient: shadowLayer4, key: shadowLayer5 }, - shadow4: { ambient: shadowLayer1, key: shadowLayer6 }, - shadow64: { ambient: shadowLayer4, key: shadowLayer7 }, - shadow8: { ambient: shadowLayer1, key: shadowLayer8 }, - shadow16brand: { ambient: shadowLayer9, key: shadowLayer10 }, - shadow2brand: { ambient: shadowLayer9, key: shadowLayer11 }, - shadow28brand: { ambient: shadowLayer12, key: shadowLayer13 }, - shadow4brand: { ambient: shadowLayer9, key: shadowLayer14 }, - shadow64brand: { ambient: shadowLayer12, key: shadowLayer15 }, - shadow8brand: { ambient: shadowLayer9, key: shadowLayer16 }, + +export const darkGrayAliasColors: Required = { + ...darkDarkGrayDarkElevatedAliasColors, + neutralForeground4: '#c2c2c2', + neutralForegroundDisabled: rgb666666, + neutralForegroundDisabled1: rgb666666, + neutralForegroundDisabled2: rgb666666, + neutralForegroundInvertedLink: rgb4d4d4d, + brandForeground1Disabled: rgb666666, + brandForegroundDisabled1: rgb666666, + brandForegroundDisabled2: rgb666666, + neutralBackgroundCanvas: rgb4d4d4d, + neutralBackgroundLightStaticDisabled: rgb383838, + brandBackgroundInvertedDisabled: rgb383838, + brandBackgroundDisabled: rgb383838, + neutralStroke3: rgb616161, + neutralForeground2: rgbe6e6e6, + neutralForeground3: '#cccccc', + neutralForeground3Hover: rgbe6e6e6, + neutralForeground3Pressed: rgbe6e6e6, + neutralForeground3Selected: rgbe6e6e6, + neutralForegroundInvertedLinkHover: rgb4d4d4d, + neutralForegroundInvertedLinkPressed: rgb4d4d4d, + neutralForegroundInvertedLinkSelected: rgb4d4d4d, + neutralBackground1: rgb4d4d4d, + neutralBackground1Hover: rgb5c5c5c, + neutralBackground1Pressed: rgb424242, + neutralBackground1Selected: rgb575757, + neutralBackground2: rgb424242, + neutralBackground2Hover: rgb525252, + neutralBackground2Pressed: rgb383838, + neutralBackground2Selected: rgb4d4d4d, + neutralBackground3: rgb383838, + neutralBackground3Hover: rgb474747, + neutralBackground3Pressed: rgb2e2e2e, + neutralBackground3Selected: rgb424242, + neutralBackground4: rgb2e2e2e, + neutralBackground4Hover: rgb3d3d3d, + neutralBackground4Pressed: rgb242424, + neutralBackground4Selected: rgb383838, + neutralBackground5: rgb242424, + neutralBackground5Hover: rgb333333, + neutralBackground5Pressed: rgb1a1a1a, + neutralBackground5Selected: rgb2e2e2e, + neutralBackground6: rgb1a1a1a, + subtleBackgroundHover: rgb5c5c5c, + subtleBackgroundPressed: rgb424242, + subtleBackgroundSelected: rgb575757, + neutralBackgroundDisabled: rgb383838, + neutralStencil1: rgb1a1a1a, + neutralStencil2: rgb424242, + neutralStrokeAccessible: '#a8a8a8', + neutralStrokeAccessibleHover: '#b8b8b8', + neutralStrokeAccessiblePressed: rgbadadad, + neutralStroke1: '#8a8a8a', + neutralStroke1Hover: rgb999999, + neutralStroke1Pressed: '#8f8f8f', + neutralStroke1Selected: '#949494', + neutralStroke2: rgb757575, + neutralStrokeDisabled: rgb474747, +}; + +export const hcAliasColors: Required = { + ...darkDarkGrayHcHcLightHcDarkDarkElevatedAliasColors, + neutralForeground4: platformColorWindowText, + neutralForegroundDisabled: platformColorGrayText, + neutralForegroundDisabled1: platformColorGrayText, + neutralForegroundDisabled2: platformColorGrayText, + neutralForegroundOnBrand: platformColorButtonText, + neutralForegroundOnColor: platformColorButtonText, + neutralForegroundInverted: platformColorWindow, + neutralForegroundInvertedLink: platformColorHotlight, + brandForegroundLink: platformColorHotlight, + compoundBrandForeground1: platformColorHighlight, + brandForeground2: platformColorButtonText, + brandForegroundTint: platformColorButtonText, + brandForeground1Disabled: platformColorGrayText, + brandForegroundDisabled1: platformColorGrayText, + brandForegroundDisabled2: platformColorGrayText, + neutralBackgroundCanvas: platformColorWindow, + neutralBackgroundLightStaticDisabled: platformColorWindow, + brandBackground2: platformColorButtonFace, + brandBackground3: platformColorButtonFace, + brandBackgroundTint: platformColorButtonFace, + brandBackgroundInverted: platformColorWindowText, + brandBackgroundInvertedDisabled: platformColorWindow, + brandBackgroundDisabled: platformColorWindow, + compoundBrandBackground1: platformColorHighlight, + brandBackgroundStatic: platformColorWindow, + neutralStroke3: platformColorWindowText, + neutralStrokeFocus1: platformColorWindow, + neutralStrokeFocus2: platformColorHighlight, + strokeFocus1: platformColorWindow, + strokeFocus2: platformColorHighlight, + brandStroke2: platformColorWindow, + brandStrokeTint: platformColorWindow, + compoundBrandStroke1: platformColorHighlight, + dangerStroke1: platformColorWindowText, + successStroke1: platformColorWindowText, + warningStroke1: platformColorWindowText, + severeStroke1: platformColorWindowText, + dangerBorder1: platformColorWindowText, + successBorder1: platformColorWindowText, + warningBorder1: platformColorWindowText, + severeBorder1: platformColorWindowText, + presenceAway: platformColorWindowText, + presenceDnd: platformColorWindowText, + presenceAvailable: platformColorWindowText, + presenceOof: platformColorWindowText, + redBackground1: platformColorWindow, + redBackground2: platformColorWindow, + redBackground3: platformColorWindowText, + redForeground1: platformColorWindowText, + redForeground2: platformColorWindowText, + redForeground3: platformColorWindowText, + redBorderActive: platformColorHighlight, + redBorder1: platformColorWindowText, + redBorder2: platformColorWindowText, + neutralForeground1: platformColorWindowText, + neutralForeground1Hover: platformColorHighlightText, + neutralForeground1Pressed: platformColorHighlightText, + neutralForeground1Selected: platformColorHighlightText, + neutralForeground2: platformColorWindowText, + neutralForeground2Hover: platformColorHighlightText, + neutralForeground2Pressed: platformColorHighlightText, + neutralForeground2Selected: platformColorHighlightText, + neutralForeground2BrandHover: platformColorHighlightText, + neutralForeground2BrandPressed: platformColorHighlightText, + neutralForeground2BrandSelected: platformColorHighlightText, + neutralForeground3: platformColorWindowText, + neutralForeground3Hover: platformColorHighlightText, + neutralForeground3Pressed: platformColorHighlightText, + neutralForeground3Selected: platformColorHighlightText, + neutralForeground3BrandHover: platformColorHighlightText, + neutralForeground3BrandPressed: platformColorHighlightText, + neutralForeground3BrandSelected: platformColorHighlightText, + brandForegroundLinkHover: platformColorHotlight, + brandForegroundLinkPressed: platformColorHotlight, + brandForegroundLinkSelected: platformColorHotlight, + compoundBrandForeground1Hover: platformColorHighlight, + compoundBrandForeground1Pressed: platformColorHighlight, + brandForeground1: platformColorWindowText, + neutralForegroundOnBrandHover: platformColorHighlightText, + neutralForegroundOnBrandPressed: platformColorHighlightText, + neutralForegroundOnBrandSelected: platformColorHighlightText, + neutralForegroundInvertedLinkHover: platformColorHotlight, + neutralForegroundInvertedLinkPressed: platformColorHotlight, + neutralForegroundInvertedLinkSelected: platformColorHotlight, + neutralBackground1: platformColorWindow, + neutralBackground1Hover: platformColorHighlight, + neutralBackground1Pressed: platformColorHighlight, + neutralBackground1Selected: platformColorHighlight, + neutralBackground2: platformColorWindow, + neutralBackground2Hover: platformColorHighlight, + neutralBackground2Pressed: platformColorHighlight, + neutralBackground2Selected: platformColorHighlight, + neutralBackground3: platformColorWindow, + neutralBackground3Hover: platformColorHighlight, + neutralBackground3Pressed: platformColorHighlight, + neutralBackground3Selected: platformColorHighlight, + neutralBackground4: platformColorWindow, + neutralBackground4Hover: platformColorHighlight, + neutralBackground4Pressed: platformColorHighlight, + neutralBackground4Selected: platformColorHighlight, + neutralBackground5: platformColorWindow, + neutralBackground5Hover: platformColorHighlight, + neutralBackground5Pressed: platformColorHighlight, + neutralBackground5Selected: platformColorHighlight, + neutralBackground6: platformColorWindow, + neutralBackgroundInverted: platformColorWindowText, + subtleBackgroundHover: platformColorHighlight, + subtleBackgroundPressed: platformColorHighlight, + subtleBackgroundSelected: platformColorHighlight, + neutralBackgroundDisabled: platformColorWindow, + neutralStencil1: rgb141414, + neutralStencil2: '#858585', + brandBackground: platformColorButtonFace, + brandBackgroundHover: platformColorHighlight, + brandBackgroundPressed: platformColorHighlight, + brandBackgroundSelected: platformColorHighlight, + compoundBrandBackground1Hover: platformColorHighlight, + compoundBrandBackground1Pressed: platformColorHighlight, + neutralStrokeAccessible: platformColorWindowText, + neutralStrokeAccessibleHover: platformColorHighlight, + neutralStrokeAccessiblePressed: platformColorHighlight, + neutralStrokeAccessibleSelected: platformColorHighlight, + neutralStroke1: platformColorWindowText, + neutralStroke1Hover: platformColorHighlight, + neutralStroke1Pressed: platformColorHighlight, + neutralStroke1Selected: platformColorHighlight, + neutralStroke2: platformColorWindowText, + brandStroke1: platformColorWindowText, + compoundBrandStroke1Hover: platformColorHighlight, + compoundBrandStroke1Pressed: platformColorHighlight, + neutralStrokeDisabled: platformColorGrayText, + transparentStroke: platformColorWindowText, + transparentStrokeInteractive: platformColorHighlight, + transparentStrokeDisabled: platformColorGrayText, + dangerBackground1: platformColorWindow, + dangerBackground2: platformColorWindow, + dangerBackground3: platformColorWindowText, + dangerForeground1: platformColorWindowText, + dangerForeground2: platformColorWindowText, + dangerForeground3: platformColorWindowText, + dangerForegroundInverted: platformColorWindowText, + dangerBorderActive: platformColorHighlight, + dangerBorder2: platformColorWindowText, + successBackground1: platformColorWindow, + successBackground2: platformColorWindow, + successBackground3: platformColorWindowText, + successForeground1: platformColorWindowText, + successForeground2: platformColorWindowText, + successForeground3: platformColorWindowText, + successForegroundInverted: platformColorWindowText, + successBorderActive: platformColorHighlight, + successBorder2: platformColorWindowText, + warningBackground1: platformColorWindow, + warningBackground2: platformColorWindow, + warningBackground3: platformColorWindowText, + warningForeground1: platformColorWindowText, + warningForeground2: platformColorWindowText, + warningForeground3: platformColorWindowText, + warningForegroundInverted: platformColorWindowText, + warningBorderActive: platformColorHighlight, + warningBorder2: platformColorWindowText, + severeBackground1: platformColorWindow, + severeBackground2: platformColorWindow, + severeBackground3: platformColorWindowText, + severeForeground1: platformColorWindowText, + severeForeground2: platformColorWindowText, + severeForeground3: platformColorWindowText, + severeBorderActive: platformColorHighlight, + severeBorder2: platformColorWindowText, + outofofficeBackground1: platformColorWindow, + outofofficeBackground2: platformColorWindow, + outofofficeBackground3: platformColorWindowText, + outofofficeForeground1: platformColorWindowText, + outofofficeForeground2: platformColorWindowText, + outofofficeForeground3: platformColorWindowText, + outofofficeBorderActive: platformColorHighlight, + outofofficeBorder1: platformColorWindowText, + outofofficeBorder2: platformColorWindowText, + brandForeground1Pressed: platformColorWindowText, + brandBackground2Pressed: platformColorHighlight, + brandBackground2Selected: platformColorHighlight, + brandForeground1Selected: platformColorWindowText, + brandStroke1Pressed: platformColorWindowText, + brandStroke1Selected: platformColorWindowText, }; -export const darkGrayShadows: BaseShadowAliasTokens = { - shadow16: { ambient: shadowLayer1, key: shadowLayer2 }, - shadow2: { ambient: shadowLayer1, key: shadowLayer3 }, - shadow28: { ambient: shadowLayer4, key: shadowLayer5 }, - shadow4: { ambient: shadowLayer1, key: shadowLayer6 }, - shadow64: { ambient: shadowLayer4, key: shadowLayer7 }, - shadow8: { ambient: shadowLayer1, key: shadowLayer8 }, - shadow16brand: { ambient: shadowLayer9, key: shadowLayer10 }, - shadow2brand: { ambient: shadowLayer9, key: shadowLayer11 }, - shadow28brand: { ambient: shadowLayer12, key: shadowLayer13 }, - shadow4brand: { ambient: shadowLayer9, key: shadowLayer14 }, - shadow64brand: { ambient: shadowLayer12, key: shadowLayer15 }, - shadow8brand: { ambient: shadowLayer9, key: shadowLayer16 }, + +export const hcLightAliasColors: Required = hcAliasColors; +export const hcDarkAliasColors: Required = hcAliasColors; +export const darkElevatedAliasColors: Required = darkAliasColors; + +/** Font aliases from the light appearance, completed with native equivalents and the platform global ramp. */ +export const fontAliasTokens: Required = { + caption1, + body1, + body1Strong, + body2, + body2Strong, + subtitle1, + subtitle1Strong, + subtitle2, + subtitle2Strong, + title1, + title1Strong, + largeTitle, + display, + caption1Strong: { face: primary, size: 10, weight: fontWeight600 }, + caption2: caption1, + title2: subtitle1, + title3: subtitle2, + captionStandard: caption1, + secondaryStandard: body1, + secondarySemibold: body1Strong, + bodyStandard: body2, + bodySemibold: body2Strong, + subheaderStandard: subtitle2, + subheaderSemibold: subtitle2Strong, + headerStandard: subtitle1, + headerSemibold: subtitle1Strong, + heroStandard: title1, + heroSemibold: title1Strong, + heroLargeStandard: largeTitle, + heroLargeSemibold: display, }; diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.windows.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.windows.ts new file mode 100644 index 0000000000..0ccde913f2 --- /dev/null +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.windows.ts @@ -0,0 +1,544 @@ +/** + * WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually. + * Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults. + * Unsupported appearances inherit the closest supported appearance. Shared values are emitted once. + */ +import type { AliasColorTokens } from '../types/Color.types'; +import type { BaseShadowAliasTokens } from '../types/Shadow.types'; +import type { Variants } from '../types/Typography.types'; + +const fontWeight400 = '400'; +const fontWeight600 = '600'; +const primary = 'primary'; +const rgb000000 = '#000000'; +const rgb00000000 = '#00000000'; +const rgb00000024 = '#00000024'; +const rgb0000003d = '#0000003d'; +const rgb00000040 = '#00000040'; +const rgb00000047 = '#00000047'; +const rgb0000004d = '#0000004d'; +const rgb0000007a = '#0000007a'; +const rgb004578 = '#004578'; +const rgb094509 = '#094509'; +const rgb0a0a0a = '#0a0a0a'; +const rgb0e336a = '#0e336a'; +const rgb0e700e = '#0e700e'; +const rgb107c10 = '#107c10'; +const rgb13458f = '#13458f'; +const rgb141414 = '#141414'; +const rgb1651aa = '#1651aa'; +const rgb185abd = '#185abd'; +const rgb1f1f1f = '#1f1f1f'; +const rgb242424 = '#242424'; +const rgb292929 = '#292929'; +const rgb2e2e2e = '#2e2e2e'; +const rgb2e6ac5 = '#2e6ac5'; +const rgb333333 = '#333333'; +const rgb383838 = '#383838'; +const rgb3d3d3d = '#3d3d3d'; +const rgb3f1011 = '#3f1011'; +const rgb424242 = '#424242'; +const rgb54b054 = '#54b054'; +const rgb575757 = '#575757'; +const rgb5c5c5c = '#5c5c5c'; +const rgb616161 = '#616161'; +const rgb6794d7 = '#6794d7'; +const rgb6d2064 = '#6d2064'; +const rgb707070 = '#707070'; +const rgb751d1f = '#751d1f'; +const rgb7a2101 = '#7a2101'; +const rgb817400 = '#817400'; +const rgb9fd89f = '#9fd89f'; +const rgbadadad = '#adadad'; +const rgbaec6eb = '#aec6eb'; +const rgbaf33a1 = '#af33a1'; +const rgbb3b3b3 = '#b3b3b3'; +const rgbbc2f32 = '#bc2f32'; +const rgbbdbdbd = '#bdbdbd'; +const rgbc239b3 = '#c239b3'; +const rgbd13438 = '#d13438'; +const rgbd161c4 = '#d161c4'; +const rgbd2e0f4 = '#d2e0f4'; +const rgbd6d6d6 = '#d6d6d6'; +const rgbda3b01 = '#da3b01'; +const rgbda7ed0 = '#da7ed0'; +const rgbdc5e62 = '#dc5e62'; +const rgbe0e0e0 = '#e0e0e0'; +const rgbe37d80 = '#e37d80'; +const rgbe6e6e6 = '#e6e6e6'; +const rgbe9835e = '#e9835e'; +const rgbebebeb = '#ebebeb'; +const rgbedbbe7 = '#edbbe7'; +const rgbeff6fc = '#eff6fc'; +const rgbf0f0f0 = '#f0f0f0'; +const rgbf1bbbc = '#f1bbbc'; +const rgbf4bfab = '#f4bfab'; +const rgbf5f5f5 = '#f5f5f5'; +const rgbfafafa = '#fafafa'; +const rgbfde300 = '#fde300'; +const rgbfdea3d = '#fdea3d'; +const rgbfdf6f6 = '#fdf6f6'; +const rgbfeee66 = '#feee66'; +const rgbfef7b2 = '#fef7b2'; +const rgbffffff = '#ffffff'; + +const body1 = { face: primary, size: 12, weight: fontWeight400 } as const; +const body1Strong = { face: primary, size: 12, weight: fontWeight600 } as const; +const body2 = { face: primary, size: 14, weight: fontWeight400 } as const; +const body2Strong = { face: primary, size: 14, weight: fontWeight600 } as const; +const caption1 = { face: primary, size: 10, weight: fontWeight400 } as const; +const display = { face: primary, size: 40, weight: fontWeight600 } as const; +const largeTitle = { face: primary, size: 40, weight: fontWeight400 } as const; +const shadowLayer1 = { color: '#0000001f', x: 0, y: 0, blur: 2 } as const; +const shadowLayer2 = { color: '#00000033', x: 0, y: 0, blur: 8 } as const; +const shadowLayer3 = { color: rgb0000004d, x: 0, y: 0, blur: 2 } as const; +const shadowLayer4 = { color: rgb0000004d, x: 0, y: 0, blur: 8 } as const; +const shadowLayer5 = { color: rgb0000003d, x: 0, y: 0, blur: 2 } as const; +const shadowLayer6 = { color: '#00000066', x: 0, y: 0, blur: 8 } as const; +const subtitle1 = { face: primary, size: 20, weight: fontWeight400 } as const; +const subtitle1Strong = { face: primary, size: 20, weight: fontWeight600 } as const; +const subtitle2 = { face: primary, size: 16, weight: fontWeight400 } as const; +const subtitle2Strong = { face: primary, size: 16, weight: fontWeight600 } as const; +const title1 = { face: primary, size: 28, weight: fontWeight400 } as const; +const title1Strong = { face: primary, size: 28, weight: fontWeight600 } as const; + +const sharedAliasColors = { + neutralForegroundOnBrand: rgbffffff, + neutralForegroundOnColor: rgbffffff, + neutralForegroundInvertedLink: rgbffffff, + brandBackgroundStatic: rgb185abd, + redBackground3: rgbd13438, + neutralForegroundOnBrandHover: rgbffffff, + neutralForegroundOnBrandPressed: rgbffffff, + neutralForegroundOnBrandSelected: rgbffffff, + neutralForegroundInvertedLinkHover: rgbffffff, + neutralForegroundInvertedLinkPressed: rgbffffff, + neutralForegroundInvertedLinkSelected: rgbffffff, + subtleBackground: rgb00000000, + transparentBackground: rgb00000000, + transparentBackgroundHover: rgb00000000, + transparentBackgroundPressed: rgb00000000, + transparentBackgroundSelected: rgb00000000, + brandBackgroundPressed: rgb004578, + brandBackgroundSelected: rgb13458f, + transparentStroke: rgb00000000, + transparentStrokeInteractive: rgb00000000, + transparentStrokeDisabled: rgb00000000, + dangerBackground3: rgbd13438, + successBackground3: rgb107c10, + warningBackground3: rgbfde300, + severeBackground3: rgbda3b01, + outofofficeBackground3: rgbc239b3, + neutralBackgroundLightStatic: rgbffffff, + brandBackground2Pressed: rgb004578, + brandBackground2Selected: rgb13458f, + neutralForegroundDarkStatic: rgb000000, + neutralForegroundLightStatic: rgbffffff, +} as const; + +const sharedShadows = { + shadow2brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 1, blur: 2 } }, + shadow4brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 2, blur: 4 } }, + shadow8brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 4, blur: 8 } }, + shadow16brand: { ambient: shadowLayer3, key: { color: rgb00000040, x: 0, y: 8, blur: 16 } }, + shadow28brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 14, blur: 28 } }, + shadow64brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 32, blur: 64 } }, +} as const; + +export const lightShadows: BaseShadowAliasTokens = { + ...sharedShadows, + shadow2: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 1, blur: 2 } }, + shadow4: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 2, blur: 4 } }, + shadow8: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 4, blur: 8 } }, + shadow16: { ambient: shadowLayer1, key: { color: rgb00000024, x: 0, y: 8, blur: 16 } }, + shadow28: { ambient: shadowLayer2, key: { color: rgb0000003d, x: 0, y: 14, blur: 28 } }, + shadow64: { ambient: shadowLayer2, key: { color: rgb0000003d, x: 0, y: 32, blur: 64 } }, +}; + +export const darkShadows: BaseShadowAliasTokens = { + ...sharedShadows, + shadow2: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 1, blur: 2 } }, + shadow4: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 2, blur: 4 } }, + shadow8: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 4, blur: 8 } }, + shadow16: { ambient: shadowLayer5, key: { color: rgb00000047, x: 0, y: 8, blur: 16 } }, + shadow28: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 14, blur: 28 } }, + shadow64: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 32, blur: 64 } }, +}; + +export const darkGrayShadows: BaseShadowAliasTokens = darkShadows; +export const hcShadows: BaseShadowAliasTokens = darkShadows; +export const hcLightShadows: BaseShadowAliasTokens = lightShadows; +export const hcDarkShadows: BaseShadowAliasTokens = darkShadows; +export const darkElevatedShadows: BaseShadowAliasTokens = darkShadows; + +export const lightAliasColors: Required = { + ...sharedAliasColors, + neutralForeground4: rgb707070, + neutralForegroundDisabled: rgbbdbdbd, + neutralForegroundDisabled1: rgbbdbdbd, + neutralForegroundDisabled2: rgbbdbdbd, + neutralForegroundInverted: rgbffffff, + brandForegroundLink: rgb1651aa, + compoundBrandForeground1: rgb185abd, + brandForeground2: rgb1651aa, + brandForegroundTint: rgb1651aa, + brandForeground1Disabled: rgbbdbdbd, + brandForegroundDisabled1: rgbbdbdbd, + brandForegroundDisabled2: rgbbdbdbd, + neutralBackgroundCanvas: rgbffffff, + neutralBackgroundLightStaticDisabled: rgbf0f0f0, + brandBackground2: rgbeff6fc, + brandBackground3: rgbeff6fc, + brandBackgroundTint: rgbeff6fc, + brandBackgroundInverted: rgb616161, + brandBackgroundInvertedDisabled: rgbf0f0f0, + brandBackgroundDisabled: rgbf0f0f0, + compoundBrandBackground1: rgb185abd, + neutralStroke3: rgbf0f0f0, + neutralStrokeFocus1: rgbffffff, + neutralStrokeFocus2: rgb000000, + strokeFocus1: rgbffffff, + strokeFocus2: rgb000000, + brandStroke2: rgbd2e0f4, + brandStrokeTint: rgbd2e0f4, + compoundBrandStroke1: rgb185abd, + dangerStroke1: rgbf1bbbc, + successStroke1: rgb9fd89f, + warningStroke1: rgbfef7b2, + severeStroke1: rgbf4bfab, + dangerBorder1: rgbf1bbbc, + successBorder1: rgb9fd89f, + warningBorder1: rgbfef7b2, + severeBorder1: rgbf4bfab, + presenceAway: rgb817400, + presenceDnd: rgbbc2f32, + presenceAvailable: rgb0e700e, + presenceOof: rgbaf33a1, + redBackground1: rgbfdf6f6, + redBackground2: rgbf1bbbc, + redForeground1: rgbbc2f32, + redForeground2: rgb751d1f, + redForeground3: rgbd13438, + redBorderActive: rgbd13438, + redBorder1: rgbf1bbbc, + redBorder2: rgbd13438, + neutralForeground1: rgb242424, + neutralForeground1Hover: rgb242424, + neutralForeground1Pressed: rgb242424, + neutralForeground1Selected: rgb242424, + neutralForeground2: rgb424242, + neutralForeground2Hover: rgb242424, + neutralForeground2Pressed: rgb242424, + neutralForeground2Selected: rgb242424, + neutralForeground2BrandHover: rgb185abd, + neutralForeground2BrandPressed: rgb1651aa, + neutralForeground2BrandSelected: rgb185abd, + neutralForeground3: rgb616161, + neutralForeground3Hover: rgb424242, + neutralForeground3Pressed: rgb424242, + neutralForeground3Selected: rgb424242, + neutralForeground3BrandHover: rgb185abd, + neutralForeground3BrandPressed: rgb1651aa, + neutralForeground3BrandSelected: rgb185abd, + brandForegroundLinkHover: rgb13458f, + brandForegroundLinkPressed: rgb004578, + brandForegroundLinkSelected: rgb1651aa, + compoundBrandForeground1Hover: rgb1651aa, + compoundBrandForeground1Pressed: rgb13458f, + brandForeground1: rgb185abd, + neutralBackground1: rgbffffff, + neutralBackground1Hover: rgbf5f5f5, + neutralBackground1Pressed: rgbe0e0e0, + neutralBackground1Selected: rgbebebeb, + neutralBackground2: rgbfafafa, + neutralBackground2Hover: rgbf0f0f0, + neutralBackground2Pressed: '#dbdbdb', + neutralBackground2Selected: rgbe6e6e6, + neutralBackground3: rgbf5f5f5, + neutralBackground3Hover: rgbebebeb, + neutralBackground3Pressed: rgbd6d6d6, + neutralBackground3Selected: rgbe0e0e0, + neutralBackground4: rgbf0f0f0, + neutralBackground4Hover: rgbfafafa, + neutralBackground4Pressed: rgbf5f5f5, + neutralBackground4Selected: rgbffffff, + neutralBackground5: rgbebebeb, + neutralBackground5Hover: rgbf5f5f5, + neutralBackground5Pressed: rgbf0f0f0, + neutralBackground5Selected: rgbfafafa, + neutralBackground6: rgbe6e6e6, + neutralBackgroundInverted: rgb616161, + subtleBackgroundHover: rgbf5f5f5, + subtleBackgroundPressed: rgbe0e0e0, + subtleBackgroundSelected: rgbebebeb, + neutralBackgroundDisabled: rgbf0f0f0, + neutralStencil1: rgbe6e6e6, + neutralStencil2: rgbfafafa, + brandBackground: rgb185abd, + brandBackgroundHover: rgb1651aa, + compoundBrandBackground1Hover: rgb1651aa, + compoundBrandBackground1Pressed: rgb13458f, + neutralStrokeAccessible: rgb616161, + neutralStrokeAccessibleHover: rgb575757, + neutralStrokeAccessiblePressed: '#4d4d4d', + neutralStrokeAccessibleSelected: rgb185abd, + neutralStroke1: '#d1d1d1', + neutralStroke1Hover: '#c7c7c7', + neutralStroke1Pressed: rgbb3b3b3, + neutralStroke1Selected: rgbbdbdbd, + neutralStroke2: rgbe0e0e0, + brandStroke1: rgb185abd, + compoundBrandStroke1Hover: rgb1651aa, + compoundBrandStroke1Pressed: rgb13458f, + neutralStrokeDisabled: rgbe0e0e0, + dangerBackground1: rgbfdf6f6, + dangerBackground2: rgbf1bbbc, + dangerForeground1: rgbbc2f32, + dangerForeground2: rgb751d1f, + dangerForeground3: rgbd13438, + dangerForegroundInverted: rgbdc5e62, + dangerBorderActive: rgbd13438, + dangerBorder2: rgbd13438, + successBackground1: '#f1faf1', + successBackground2: rgb9fd89f, + successForeground1: rgb0e700e, + successForeground2: rgb094509, + successForeground3: rgb107c10, + successForegroundInverted: '#359b35', + successBorderActive: rgb107c10, + successBorder2: rgb107c10, + warningBackground1: '#fffef5', + warningBackground2: rgbfef7b2, + warningForeground1: rgb817400, + warningForeground2: rgb817400, + warningForeground3: rgbfde300, + warningForegroundInverted: rgbfef7b2, + warningBorderActive: rgbfde300, + warningBorder2: rgbfde300, + severeBackground1: '#fdf6f3', + severeBackground2: rgbf4bfab, + severeForeground1: '#c43501', + severeForeground2: rgb7a2101, + severeForeground3: rgbda3b01, + severeBorderActive: rgbda3b01, + severeBorder2: rgbda3b01, + outofofficeBackground1: '#fdf5fc', + outofofficeBackground2: rgbedbbe7, + outofofficeForeground1: rgbaf33a1, + outofofficeForeground2: rgb6d2064, + outofofficeForeground3: rgbc239b3, + outofofficeBorderActive: rgbc239b3, + outofofficeBorder1: rgbedbbe7, + outofofficeBorder2: rgbc239b3, + brandForeground1Pressed: rgb185abd, + neutralBackgroundDarkStatic: rgb242424, + brandForeground1Selected: rgb185abd, + brandStroke1Pressed: rgb185abd, + brandStroke1Selected: rgb185abd, +}; + +export const darkAliasColors: Required = { + ...sharedAliasColors, + neutralForeground4: '#999999', + neutralForegroundDisabled: rgb5c5c5c, + neutralForegroundDisabled1: rgb5c5c5c, + neutralForegroundDisabled2: rgb5c5c5c, + neutralForegroundInverted: rgb242424, + brandForegroundLink: rgb2e6ac5, + compoundBrandForeground1: rgb2e6ac5, + brandForeground2: rgbaec6eb, + brandForegroundTint: rgbaec6eb, + brandForeground1Disabled: rgb5c5c5c, + brandForegroundDisabled1: rgb5c5c5c, + brandForegroundDisabled2: rgb5c5c5c, + neutralBackgroundCanvas: rgb292929, + neutralBackgroundLightStaticDisabled: rgb141414, + brandBackground2: rgb004578, + brandBackground3: rgb004578, + brandBackgroundTint: rgb004578, + brandBackgroundInverted: rgbffffff, + brandBackgroundInvertedDisabled: rgb141414, + brandBackgroundDisabled: rgb141414, + compoundBrandBackground1: rgb2e6ac5, + neutralStroke3: rgb3d3d3d, + neutralStrokeFocus1: rgb000000, + neutralStrokeFocus2: rgbffffff, + strokeFocus1: rgb000000, + strokeFocus2: rgbffffff, + brandStroke2: rgb0e336a, + brandStrokeTint: rgb0e336a, + compoundBrandStroke1: rgb2e6ac5, + dangerStroke1: rgbd13438, + successStroke1: rgb107c10, + warningStroke1: rgbfde300, + severeStroke1: rgbda3b01, + dangerBorder1: rgbd13438, + successBorder1: rgb107c10, + warningBorder1: rgbfde300, + severeBorder1: rgbda3b01, + presenceAway: rgbfeee66, + presenceDnd: rgbe37d80, + presenceAvailable: rgb54b054, + presenceOof: rgbda7ed0, + redBackground1: rgb3f1011, + redBackground2: rgb751d1f, + redForeground1: rgbe37d80, + redForeground2: rgbf1bbbc, + redForeground3: rgbe37d80, + redBorderActive: rgbe37d80, + redBorder1: rgbd13438, + redBorder2: rgbdc5e62, + neutralForeground1: rgbffffff, + neutralForeground1Hover: rgbffffff, + neutralForeground1Pressed: rgbffffff, + neutralForeground1Selected: rgbffffff, + neutralForeground2: rgbd6d6d6, + neutralForeground2Hover: rgbffffff, + neutralForeground2Pressed: rgbffffff, + neutralForeground2Selected: rgbffffff, + neutralForeground2BrandHover: rgb6794d7, + neutralForeground2BrandPressed: rgb2e6ac5, + neutralForeground2BrandSelected: rgb6794d7, + neutralForeground3: rgbadadad, + neutralForeground3Hover: rgbd6d6d6, + neutralForeground3Pressed: rgbd6d6d6, + neutralForeground3Selected: rgbd6d6d6, + neutralForeground3BrandHover: rgb6794d7, + neutralForeground3BrandPressed: rgb2e6ac5, + neutralForeground3BrandSelected: rgb6794d7, + brandForegroundLinkHover: rgbaec6eb, + brandForegroundLinkPressed: rgb6794d7, + brandForegroundLinkSelected: rgb2e6ac5, + compoundBrandForeground1Hover: rgb6794d7, + compoundBrandForeground1Pressed: rgb185abd, + brandForeground1: rgb6794d7, + neutralBackground1: rgb292929, + neutralBackground1Hover: rgb3d3d3d, + neutralBackground1Pressed: rgb1f1f1f, + neutralBackground1Selected: rgb383838, + neutralBackground2: rgb1f1f1f, + neutralBackground2Hover: rgb333333, + neutralBackground2Pressed: rgb141414, + neutralBackground2Selected: rgb2e2e2e, + neutralBackground3: rgb141414, + neutralBackground3Hover: rgb292929, + neutralBackground3Pressed: rgb0a0a0a, + neutralBackground3Selected: rgb242424, + neutralBackground4: rgb0a0a0a, + neutralBackground4Hover: rgb1f1f1f, + neutralBackground4Pressed: rgb000000, + neutralBackground4Selected: '#1a1a1a', + neutralBackground5: rgb000000, + neutralBackground5Hover: rgb141414, + neutralBackground5Pressed: '#050505', + neutralBackground5Selected: '#0f0f0f', + neutralBackground6: rgb333333, + neutralBackgroundInverted: rgbffffff, + subtleBackgroundHover: rgb383838, + subtleBackgroundPressed: rgb2e2e2e, + subtleBackgroundSelected: rgb333333, + neutralBackgroundDisabled: rgb141414, + neutralStencil1: rgb333333, + neutralStencil2: rgb575757, + brandBackground: rgb1651aa, + brandBackgroundHover: rgb185abd, + compoundBrandBackground1Hover: rgb6794d7, + compoundBrandBackground1Pressed: rgb185abd, + neutralStrokeAccessible: rgbadadad, + neutralStrokeAccessibleHover: rgbbdbdbd, + neutralStrokeAccessiblePressed: rgbb3b3b3, + neutralStrokeAccessibleSelected: rgb6794d7, + neutralStroke1: '#666666', + neutralStroke1Hover: '#757575', + neutralStroke1Pressed: '#6b6b6b', + neutralStroke1Selected: rgb707070, + neutralStroke2: '#525252', + brandStroke1: rgb2e6ac5, + compoundBrandStroke1Hover: rgb6794d7, + compoundBrandStroke1Pressed: rgb185abd, + neutralStrokeDisabled: rgb424242, + dangerBackground1: rgb3f1011, + dangerBackground2: rgb751d1f, + dangerForeground1: rgbe37d80, + dangerForeground2: rgbf1bbbc, + dangerForeground3: rgbe37d80, + dangerForegroundInverted: rgbd13438, + dangerBorderActive: rgbe37d80, + dangerBorder2: rgbdc5e62, + successBackground1: '#052505', + successBackground2: rgb094509, + successForeground1: rgb54b054, + successForeground2: rgb9fd89f, + successForeground3: rgb9fd89f, + successForegroundInverted: rgb107c10, + successBorderActive: rgb54b054, + successBorder2: rgb9fd89f, + warningBackground1: '#4c4400', + warningBackground2: rgb817400, + warningForeground1: rgbfeee66, + warningForeground2: rgbfef7b2, + warningForeground3: rgbfdea3d, + warningForegroundInverted: rgb817400, + warningBorderActive: rgbfeee66, + warningBorder2: rgbfdea3d, + severeBackground1: '#411200', + severeBackground2: rgb7a2101, + severeForeground1: rgbe9835e, + severeForeground2: rgbf4bfab, + severeForeground3: rgbe9835e, + severeBorderActive: rgbe9835e, + severeBorder2: rgbe9835e, + outofofficeBackground1: '#3a1136', + outofofficeBackground2: rgb6d2064, + outofofficeForeground1: rgbda7ed0, + outofofficeForeground2: rgbedbbe7, + outofofficeForeground3: rgbd161c4, + outofofficeBorderActive: rgbda7ed0, + outofofficeBorder1: rgbc239b3, + outofofficeBorder2: rgbd161c4, + brandForeground1Pressed: rgb6794d7, + neutralBackgroundDarkStatic: rgb3d3d3d, + brandForeground1Selected: rgb6794d7, + brandStroke1Pressed: rgb2e6ac5, + brandStroke1Selected: rgb2e6ac5, +}; + +export const darkGrayAliasColors: Required = darkAliasColors; +export const hcAliasColors: Required = darkAliasColors; +export const hcLightAliasColors: Required = lightAliasColors; +export const hcDarkAliasColors: Required = darkAliasColors; +export const darkElevatedAliasColors: Required = darkAliasColors; + +/** Font aliases from the light appearance, completed with native equivalents and the platform global ramp. */ +export const fontAliasTokens: Required = { + caption1, + body1, + body1Strong, + body2, + body2Strong, + subtitle1, + subtitle1Strong, + subtitle2, + subtitle2Strong, + title1, + title1Strong, + largeTitle, + display, + caption1Strong: { face: primary, size: 10, weight: fontWeight600 }, + caption2: caption1, + title2: subtitle1, + title3: subtitle2, + captionStandard: caption1, + secondaryStandard: body1, + secondarySemibold: body1Strong, + bodyStandard: body2, + bodySemibold: body2Strong, + subheaderStandard: subtitle2, + subheaderSemibold: subtitle2Strong, + headerStandard: subtitle1, + headerSemibold: subtitle1Strong, + heroStandard: title1, + heroSemibold: title1Strong, + heroLargeStandard: largeTitle, + heroLargeSemibold: display, +}; diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts new file mode 100644 index 0000000000..b7d7a105bf --- /dev/null +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts @@ -0,0 +1,189 @@ +import { readFileSync } from 'node:fs'; +import path from 'node:path'; + +import { parse } from '@babel/parser'; +import blackAliasTokens from '@fluentui-react-native/design-tokens-win32/black/tokens-aliases.json'; +import blackShadowTokens from '@fluentui-react-native/design-tokens-win32/black/tokens-shadow.json'; +import colorfulAliasTokens from '@fluentui-react-native/design-tokens-win32/colorful/tokens-aliases.json'; +import colorfulShadowTokens from '@fluentui-react-native/design-tokens-win32/colorful/tokens-shadow.json'; +import darkGrayAliasTokens from '@fluentui-react-native/design-tokens-win32/darkgray/tokens-aliases.json'; +import darkGrayShadowTokens from '@fluentui-react-native/design-tokens-win32/darkgray/tokens-shadow.json'; +import hcAliasTokens from '@fluentui-react-native/design-tokens-win32/hc/tokens-aliases.json'; +import hcShadowTokens from '@fluentui-react-native/design-tokens-win32/hc/tokens-shadow.json'; +import { PlatformColor } from 'react-native'; + +import { mapPipelineToShadow } from '../mapPipelineToShadow'; +import { mapFontPipelineToTheme, mapPipelineToTheme } from '../mapPipelineToTheme'; +import * as androidMapper from '../mapPipelineToTheme.android'; +import * as iosMapper from '../mapPipelineToTheme.ios'; +import { processAliasTokens, transformWin32PlatformColorName } from '../tokens/highContrast/processAliasTokens'; +import * as android from './fluentTokens.generated.android'; +import * as ios from './fluentTokens.generated.ios'; +import * as macos from './fluentTokens.generated.macos'; +import * as windows from './fluentTokens.generated.windows'; + +// An explicit extension bypasses Jest's platform resolution for the Win32 fallback module. +const generated = jest.requireActual('./fluentTokens.generated.ts'); + +function definedEntries(values: object) { + return Object.fromEntries(Object.entries(values).filter(([, value]) => value !== undefined)); +} + +// processAliasTokens converts the high-contrast PlatformColor strings in place, so it gets a copy. +const processedHcAliasTokens = processAliasTokens(JSON.parse(JSON.stringify(hcAliasTokens)), transformWin32PlatformColorName); + +const appearances = [ + ['light', generated.lightAliasColors, generated.lightShadows, colorfulAliasTokens, colorfulShadowTokens], + ['dark', generated.darkAliasColors, generated.darkShadows, blackAliasTokens, blackShadowTokens], + ['darkGray', generated.darkGrayAliasColors, generated.darkGrayShadows, darkGrayAliasTokens, darkGrayShadowTokens], + ['hc', generated.hcAliasColors, generated.hcShadows, processedHcAliasTokens, hcShadowTokens], +] as const; + +describe('generated win32 Fluent tokens', () => { + it.each(appearances)('match the runtime mapping for %s', (_, aliasColors, shadows, aliasTokens, shadowTokens) => { + expect(aliasColors).toMatchObject(definedEntries(mapPipelineToTheme(aliasTokens))); + expect(shadows).toEqual(mapPipelineToShadow(shadowTokens)); + }); + + it('match the runtime font mapping', () => { + expect(generated.fontAliasTokens).toMatchObject(mapFontPipelineToTheme(colorfulAliasTokens)); + }); + + it('emit high-contrast colors as distinct PlatformColor values', () => { + expect(generated.hcAliasColors.neutralForeground1).toEqual(PlatformColor('WindowText')); + expect(PlatformColor('WindowText')).not.toEqual(PlatformColor('ButtonFace')); + }); +}); + +function interfaceKeys(filename: string, name: string): string[] { + const ast = parse(readFileSync(path.resolve(__dirname, '../types', filename), 'utf8'), { sourceType: 'module', plugins: ['typescript'] }); + for (const statement of ast.program.body) { + const declaration = statement.type === 'ExportNamedDeclaration' ? statement.declaration : undefined; + if (declaration?.type === 'TSInterfaceDeclaration' && declaration.id.name === name) { + return declaration.body.body + .map((property) => { + if (property.type !== 'TSPropertySignature' || property.key.type !== 'Identifier') { + throw new Error(`Unsupported property in ${name}`); + } + return property.key.name; + }) + .sort(); + } + } + throw new Error(`Missing interface ${name}`); +} + +function expectDefined(value: unknown): void { + expect(value).not.toBeUndefined(); + expect(value).not.toBeNull(); + if (value && typeof value === 'object') { + Object.values(value).forEach(expectDefined); + } +} + +const allAppearances = ['light', 'dark', 'darkGray', 'hc', 'hcLight', 'hcDark', 'darkElevated'] as const; +const platforms = [ + { + platform: 'win32', + tokens: generated, + mapper: { mapPipelineToTheme, mapFontPipelineToTheme }, + sources: { light: 'colorful', dark: 'black', darkGray: 'darkgray', hc: 'hc' }, + }, + { + platform: 'macos', + tokens: macos, + mapper: { mapPipelineToTheme, mapFontPipelineToTheme }, + sources: { light: 'light', dark: 'dark', hcLight: 'hclight', hcDark: 'hcdark' }, + }, + { + platform: 'windows', + tokens: windows, + mapper: { mapPipelineToTheme, mapFontPipelineToTheme }, + sources: { light: 'light', dark: 'dark' }, + }, + { platform: 'android', tokens: android, mapper: androidMapper, sources: { light: 'light', dark: 'dark' } }, + { + platform: 'ios', + tokens: ios, + mapper: iosMapper, + sources: { light: 'light', dark: 'dark', hcLight: 'hclight', hcDark: 'hcdark', darkElevated: 'elevateddark' }, + }, +] as const; + +describe.each(platforms)('complete $platform Fluent tokens', ({ platform, tokens, mapper, sources }) => { + it('covers the entire color and font contracts in every appearance with no undefined values', () => { + const colorKeys = interfaceKeys('Color.types.ts', 'AliasColorTokens'); + const fontKeys = interfaceKeys('Typography.types.ts', 'Variants'); + const shadowKeys = interfaceKeys('Shadow.types.ts', 'BaseShadowAliasTokens'); + expect(Object.keys(tokens).sort()).toEqual( + ['fontAliasTokens', ...allAppearances.flatMap((appearance) => [`${appearance}AliasColors`, `${appearance}Shadows`])].sort(), + ); + expect(Object.keys(tokens.fontAliasTokens).sort()).toEqual(fontKeys); + for (const appearance of allAppearances) { + expect(Object.keys(tokens[`${appearance}AliasColors`]).sort()).toEqual(colorKeys); + expect(Object.keys(tokens[`${appearance}Shadows`]).sort()).toEqual(shadowKeys); + } + expectDefined(tokens); + }); + + it('preserves every defined runtime-mapped native color, font alias, and shadow', () => { + for (const [appearance, source] of Object.entries(sources)) { + const packagePath = `@fluentui-react-native/design-tokens-${platform}/${source}/`; + const raw = require(`${packagePath}tokens-aliases.json`); + const aliases = processAliasTokens(JSON.parse(JSON.stringify(raw)), transformWin32PlatformColorName); + const shadows = require(`${packagePath}tokens-shadow.json`); + const key = appearance as (typeof allAppearances)[number]; + // iOS high-contrast files contain fonts only, with no native colors to preserve. + if (aliases.neutralBackground1) { + expect(tokens[`${key}AliasColors`]).toMatchObject(definedEntries(mapper.mapPipelineToTheme(aliases))); + } + if (aliases.caption1) { + expect(tokens.fontAliasTokens).toMatchObject(mapper.mapFontPipelineToTheme(aliases)); + } + expect(tokens[`${key}Shadows`]).toEqual(mapPipelineToShadow(shadows)); + } + }); +}); + +describe('Fluent token fallbacks', () => { + it.each([ios, android])('uses native rest colors and native fonts for missing mobile states and aliases', (tokens) => { + expect(tokens.darkAliasColors.brandBackground2).toBe(tokens.darkAliasColors.brandBackground); + expect(tokens.darkAliasColors.brandBackground2Pressed).toBe(tokens.darkAliasColors.brandBackgroundPressed); + expect(tokens.lightAliasColors.neutralBackground1Hover).toBe(tokens.lightAliasColors.neutralBackground1); + expect(tokens.lightAliasColors.neutralForegroundOnBrand).toBe(tokens.lightAliasColors.neutralForegroundOnColor); + expect(tokens.fontAliasTokens.subtitle1).toEqual(tokens.fontAliasTokens.title2); + expect(tokens.fontAliasTokens.subtitle2).toEqual(tokens.fontAliasTokens.title3); + expect(tokens.lightAliasColors.outofofficeBackground3).toBe(generated.lightAliasColors.outofofficeBackground3); + expect(tokens.darkAliasColors.outofofficeBackground3).toBe(generated.darkAliasColors.outofofficeBackground3); + }); + + it('inherits missing appearances without importing Win32 system colors onto other platforms', () => { + expect(ios.hcLightAliasColors).toEqual(ios.lightAliasColors); + expect(ios.hcDarkAliasColors).toEqual(ios.darkAliasColors); + expect(generated.hcLightAliasColors).toEqual(generated.hcAliasColors); + expect(generated.hcDarkAliasColors).toEqual(generated.hcAliasColors); + for (const { tokens } of platforms.filter(({ platform }) => platform !== 'win32')) { + expect(tokens.darkGrayAliasColors).toEqual(tokens.darkAliasColors); + expect(tokens.darkGrayShadows).toEqual(tokens.darkShadows); + for (const appearance of allAppearances) { + expect(Object.values(tokens[`${appearance}AliasColors`]).every((color) => typeof color === 'string')).toBe(true); + } + } + }); + + it.each([ + ['macos', macos], + ['windows', windows], + ] as const)('uses %s global fonts when the pipeline has no aliases', (platform, tokens) => { + const { font } = require(`@fluentui-react-native/design-tokens-${platform}/light/tokens-global.json`); + expect(tokens.fontAliasTokens.caption1).toEqual({ face: 'primary', size: font.size100, weight: font.weight.regular }); + expect(tokens.fontAliasTokens.body1Strong).toEqual({ face: 'primary', size: font.size200, weight: font.weight.semibold }); + }); + + it('keeps native states omitted by the legacy mapper and aliases deprecated colors', () => { + const source = require('@fluentui-react-native/design-tokens-macos/light/tokens-aliases.json'); + expect(macos.lightAliasColors.brandForeground1Selected).toBe(source.brandForeground1.selected); + expect(macos.lightAliasColors.brandStroke1Pressed).toBe(source.brandStroke1.pressed); + expect(ios.darkAliasColors.redForeground1).toBe(ios.darkAliasColors.dangerForeground1); + }); +}); diff --git a/scripts/package.json b/scripts/package.json index 2ed46c544d..8592e18351 100644 --- a/scripts/package.json +++ b/scripts/package.json @@ -30,7 +30,7 @@ "bundlesize": "bundlesize --debug", "format": "node ./src/cli.ts format", "lint": "node ./src/cli.ts lint", - "test": "node --test src/tasks/agentInstructions.test.ts src/tasks/clean.test.mjs src/utils/jestSelection.test.ts src/utils/runScript.test.ts" + "test": "node --test src/tasks/agentInstructions.test.ts src/tasks/clean.test.mjs src/utils/jestSelection.test.ts src/utils/runScript.test.ts src/codegen/file.test.ts src/codegen/valuePool.test.ts" }, "dependencies": { "@babel/core": "catalog:", diff --git a/scripts/src/codegen/file.test.ts b/scripts/src/codegen/file.test.ts new file mode 100644 index 0000000000..30d7cc3ebd --- /dev/null +++ b/scripts/src/codegen/file.test.ts @@ -0,0 +1,41 @@ +import assert from 'node:assert/strict'; +import fs from 'node:fs'; +import os from 'node:os'; +import path from 'node:path'; +import { describe, it } from 'node:test'; + +import { GeneratedFile, makeComment } from './file.ts'; + +describe('GeneratedFile', () => { + it('renders, reports whether the file is current, and writes only changes', () => { + const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'generated-file-')); + try { + const target = path.join(directory, 'nested', 'tokens.generated.ts'); + const create = (value: string) => { + const file = new GeneratedFile(target); + file.header = makeComment('Generated.', 'line'); + file.add('\n', `export const value = '${value}';`); + return file; + }; + + const first = create('a'); + assert.equal(first.render(), "// Generated.\n\nexport const value = 'a';\n"); + assert.equal(first.isCurrent(), false); + assert.equal(first.commit(), true); + assert.equal(fs.readFileSync(target, 'utf8'), first.render()); + + const modified = fs.statSync(target).mtimeMs; + const same = create('a'); + assert.equal(same.isCurrent(), true); + assert.equal(same.commit(), false); + assert.equal(fs.statSync(target).mtimeMs, modified); + + const changed = create('b'); + assert.equal(changed.isCurrent(), false); + assert.equal(changed.commit(), true); + assert.equal(fs.readFileSync(target, 'utf8'), "// Generated.\n\nexport const value = 'b';\n"); + } finally { + fs.rmSync(directory, { recursive: true, force: true }); + } + }); +}); diff --git a/scripts/src/codegen/file.ts b/scripts/src/codegen/file.ts index 409877e0fb..76991422ad 100644 --- a/scripts/src/codegen/file.ts +++ b/scripts/src/codegen/file.ts @@ -48,8 +48,8 @@ export class GeneratedFile { this._content.push(...content); } - /** write the generated file to disk */ - commit() { + /** the full text of the generated file */ + render(): string { let content = this.header.output(); if (this._content.length > 0) { content += '\n' + serialize(this._content); @@ -57,8 +57,27 @@ export class GeneratedFile { if (!content.endsWith('\n')) { content += '\n'; } + return content; + } + + /** whether the file on disk already holds the generated content */ + isCurrent(): boolean { + return this._entry.exists && this._entry.content === this.render(); + } + + /** + * write the generated file to disk when its content changed + * @returns true when the file was written + */ + commit(): boolean { + const content = this.render(); + // load the current content first so an unchanged file is not rewritten + if (this._entry.exists && this._entry.content === content) { + return false; + } this._entry.content = content; this._entry.writeContentsSync(); + return true; } } diff --git a/scripts/src/codegen/valuePool.test.ts b/scripts/src/codegen/valuePool.test.ts new file mode 100644 index 0000000000..ccba7b4abf --- /dev/null +++ b/scripts/src/codegen/valuePool.test.ts @@ -0,0 +1,354 @@ +import assert from 'node:assert/strict'; +import { createRequire } from 'node:module'; +import { describe, it } from 'node:test'; + +import { CodeExpression, expression, ValuePool } from './valuePool.ts'; + +type AstNode = { + type: string; + name?: string; + value?: unknown; + operator?: string; + argument?: AstNode; + expression?: AstNode; + elements?: (AstNode | null)[]; + properties?: AstNode[]; + key?: AstNode; + computed?: boolean; + callee?: AstNode; + arguments?: AstNode[]; + declaration?: AstNode | null; + declarations?: AstNode[]; + kind?: string; + id?: AstNode; + init?: AstNode | null; + body?: AstNode[]; + program?: AstNode; +}; + +const babel = createRequire(import.meta.url)('@babel/core') as { + parseSync(code: string, options: Record): AstNode | null; +}; + +/** + * Read the exported values of generated code by interpreting its literals, references, and spreads as data. The code + * is parsed, never run. A call evaluates to `{ call, args }`, and an external identifier to `{ external }`. + */ +function readExports(code: string, externals: readonly string[] = ['fontWeightBold']): Record { + const file = babel.parseSync(code, { + babelrc: false, + configFile: false, + filename: 'generated.ts', + parserOpts: { plugins: ['typescript'] }, + }); + const scope = new Map(externals.map((name) => [name, { external: name }])); + const exported: Record = {}; + for (const statement of file!.program!.body!) { + const isExport = statement.type === 'ExportNamedDeclaration'; + const declaration = isExport ? statement.declaration! : statement; + if (declaration.type === 'ImportDeclaration') { + continue; + } + assert.equal(declaration.type, 'VariableDeclaration'); + assert.equal(declaration.kind, 'const'); + for (const declarator of declaration.declarations!) { + const name = declarator.id!.name!; + assert.ok(!scope.has(name), `${name} is declared twice`); + scope.set(name, evaluate(declarator.init!, scope)); + if (isExport) { + exported[name] = scope.get(name); + } + } + } + return exported; +} + +function evaluate(node: AstNode, scope: ReadonlyMap): unknown { + switch (node.type) { + case 'StringLiteral': + case 'NumericLiteral': + case 'BooleanLiteral': + return node.value; + case 'NullLiteral': + return null; + case 'Identifier': + if (node.name === 'undefined') { + return undefined; + } + assert.ok(scope.has(node.name!), `${node.name} is referenced before it is declared`); + return scope.get(node.name!); + case 'UnaryExpression': + assert.equal(node.operator, '-'); + return -(evaluate(node.argument!, scope) as number); + case 'TSAsExpression': + case 'TSSatisfiesExpression': + return evaluate(node.expression!, scope); + case 'ArrayExpression': + return node.elements!.map((element) => evaluate(element!, scope)); + case 'ObjectExpression': { + const result: Record = {}; + for (const property of node.properties!) { + if (property.type === 'SpreadElement') { + Object.assign(result, evaluate(property.argument!, scope)); + } else { + assert.equal(property.type, 'ObjectProperty'); + assert.ok(!property.computed); + const key = property.key!.type === 'Identifier' ? property.key!.name! : String(property.key!.value); + result[key] = evaluate((property as { value: AstNode }).value, scope); + } + } + return result; + } + case 'CallExpression': + return { call: node.callee!.name, args: node.arguments!.map((argument) => evaluate(argument, scope)) }; + default: + throw new Error(`Unexpected ${node.type} in generated code.`); + } +} + +/** The data a value is expected to read back as: expressions become calls and undefined properties disappear. */ +function expected(value: unknown): unknown { + if (value instanceof CodeExpression) { + const open = value.code.indexOf('('); + return open < 0 ? { external: value.code } : { call: value.code.slice(0, open), args: [value.code.slice(open + 2, -2)] }; + } + if (Array.isArray(value)) { + return value.map(expected); + } + if (value && typeof value === 'object') { + return Object.fromEntries( + Object.entries(value) + .filter(([, item]) => item !== undefined) + .map(([key, item]) => [key, expected(item)]), + ); + } + return value; +} + +function roundTrip(pool: ValuePool, declarations: Record) { + const code = pool.output(); + assert.deepEqual(readExports(code), expected(declarations)); + return code; +} + +const platformColor = (name: string) => expression(`PlatformColor('${name}')`, { pure: true, name: `platformColor${name}` }); + +describe('ValuePool', () => { + it('emits an equal value once and aliases equal declarations', () => { + const value = { shadow2: { ambient: { x: 0, y: 0, blur: 2, color: '#0000003d' }, key: { x: 0, y: 1, blur: 2, color: '#00000047' } } }; + const pool = new ValuePool(); + pool.declare('darkShadows', value, { type: 'Shadows' }); + pool.declare('hcShadows', structuredClone(value), { type: 'Shadows' }); + const code = roundTrip(pool, { darkShadows: value, hcShadows: value }); + assert.match(code, /^export const hcShadows: Shadows = darkShadows;$/m); + assert.equal(code.match(/#0000003d/g)?.length, 1); + }); + + it('shares entries in ancestors that spread the ancestors of larger member sets', () => { + const shared = { a1: '#000001', a2: '#000002', a3: '#000003', a4: '#000004' }; + const nonContrast = { b1: '#000011', b2: '#000012', b3: '#000013', b4: '#000014' }; + const dark = { c1: '#000021', c2: '#000022', c3: '#000023', c4: '#000024' }; + const declarations = { + lightColors: { ...shared, ...nonContrast, c1: '#ffff21', c2: '#ffff22', c3: '#ffff23', c4: '#ffff24' }, + darkColors: { ...shared, ...nonContrast, ...dark, d1: '#000031' }, + dimColors: { ...shared, ...nonContrast, ...dark, d1: '#000041' }, + contrastColors: { ...shared, b1: 'red', b2: 'green', b3: 'blue', b4: 'gray', c1: 'red', c2: 'green', c3: 'blue', c4: 'gray' }, + }; + const pool = new ValuePool(); + for (const [name, value] of Object.entries(declarations)) { + pool.declare(name, value, { type: 'Colors' }); + } + const code = roundTrip(pool, declarations); + assert.match(code, /^const sharedColors = \{$/m); + assert.match(code, /^const lightDarkDimColors = \{\n {2}\.\.\.sharedColors,$/m); + assert.match(code, /^const darkDimColors = \{\n {2}\.\.\.lightDarkDimColors,$/m); + assert.match(code, /^export const darkColors: Colors = \{\n {2}\.\.\.darkDimColors,\n {2}d1: '#000031',\n\};$/m); + assert.match(code, /^export const contrastColors: Colors = \{\n {2}\.\.\.sharedColors,$/m); + assert.equal(code.match(/a1: /g)?.length, 1); + }); + + it('shares entries of objects held under the same key', () => { + const color = Object.fromEntries(Array.from({ length: 8 }, (_, index) => [`neutral${index}`, ['#ffffff', `#00000${index}`]])); + const common = { spacing: { small: 4, large: 16 }, radius: { small: 2, large: 8 }, stroke: { thin: 1 }, motion: { fast: 100 } }; + const declarations = { + coolTokenInput: { ...common, color: { ...color, brand: ['#0000ff', '#8888ff'] } }, + warmTokenInput: { ...structuredClone(common), color: { ...color, brand: ['#ff8800', '#ffaa44'] } }, + }; + const pool = new ValuePool(); + pool.declare('coolTokenInput', declarations.coolTokenInput, { type: 'TokenInput' }); + pool.declare('warmTokenInput', declarations.warmTokenInput, { type: 'TokenInput' }); + const code = roundTrip(pool, declarations); + assert.match(code, /^const sharedTokenInput = \{\n {2}spacing: /m); + assert.match(code, /^const sharedTokenInputColor = \{$/m); + assert.match(code, /^ {2}color: \{ \.\.\.sharedTokenInputColor, brand: \['#0000ff', '#8888ff'\] \},$/m); + assert.match(code, /^const rgbffffff = '#ffffff';$/m); + }); + + it('keeps values inline when sharing them would grow the output', () => { + const declarations = { first: { a: 'ab', b: 1000000, c: [1, 2] }, second: { a: 'ab', b: 1000000, c: [1, 2], d: true } }; + const pool = new ValuePool({ ancestors: false }); + pool.declare('first', declarations.first); + pool.declare('second', declarations.second); + const code = roundTrip(pool, declarations); + assert.doesNotMatch(code, /^const /m); + }); + + it('hoists repeated values with const assertions and pure calls', () => { + const entry = { rest: ['#242424', '#ffffff'], type: 'inverted' }; + const declarations = { + tokens: { + a: entry, + b: structuredClone(entry), + c: { rest: ['#6f6f6f', '#929292'], type: 'inverted' }, + d: { rest: ['#6f6f6f', '#929292'], type: 'inverted' }, + e: platformColor('ButtonFace'), + f: platformColor('ButtonFace'), + }, + }; + const pool = new ValuePool(); + pool.declare('tokens', declarations.tokens); + const code = roundTrip(pool, declarations); + assert.match(code, /^const inverted = 'inverted';$/m); + assert.match(code, /^const platformColorButtonFace = \/\* @__PURE__ \*\/ PlatformColor\('ButtonFace'\);$/m); + assert.match(code, /^const a = \{ rest: \['#242424', '#ffffff'\], type: inverted \} as const;$/m); + assert.match(code, /^ {2}b: a,$/m); + }); + + it('names values without colliding with reserved names or declarations', () => { + const sequence = [1, 2, 3, 4, 5, 6]; + const declarations = { + first: { value: sequence, other: [...sequence], label: 'default', again: 'default' }, + deep: { x: [...sequence] }, + }; + const pool = new ValuePool({ ancestors: false, name: (value) => (Array.isArray(value) ? 'deep' : undefined) }); + pool.reserve('defaultValue'); + pool.declare('first', declarations.first); + pool.declare('deep', declarations.deep); + const code = roundTrip(pool, declarations); + assert.match(code, /^const deep1 = \[1, 2, 3, 4, 5, 6\] as const;$/m); + assert.match(code, /^const defaultValue1 = 'default';$/m); + }); + + it('emits a declaration before the declarations that reference it', () => { + const shared = { a: '#123456', b: '#654321', c: 'something long enough to share' }; + const declarations = { outer: { first: shared, second: shared }, inner: shared }; + const pool = new ValuePool(); + pool.declare('outer', declarations.outer); + pool.declare('inner', declarations.inner); + const code = roundTrip(pool, declarations); + assert.ok(code.indexOf('export const inner') < code.indexOf('export const outer')); + assert.match(code, /^ {2}first: inner,$/m); + }); + + it('declares a value with different types once and references it from each declaration', () => { + const value = { a: '#123456', b: '#654321' }; + const pool = new ValuePool(); + pool.declare('first', value, { type: 'First' }); + pool.declare('second', structuredClone(value), { type: 'Second' }); + const code = roundTrip(pool, { first: value, second: value }); + assert.match(code, /^export const first: First = firstValue;$/m); + assert.match(code, /^export const second: Second = firstValue;$/m); + }); + + it('formats declarations, comments, and satisfies clauses', () => { + const pool = new ValuePool(); + pool.declare( + 'tokens', + { a: 'x', 'b-c': 1, 0: null, d: undefined, e: [] }, + { comment: 'Tokens.', satisfies: 'Tokens', exported: false }, + ); + assert.equal(pool.output(), "/** Tokens. */\nconst tokens = {\n 0: null,\n a: 'x',\n 'b-c': 1,\n e: [],\n} satisfies Tokens;\n"); + }); + + it('reduces the estimated size by sharing ancestors', () => { + const base = Object.fromEntries( + Array.from({ length: 30 }, (_, index) => [`neutralForeground${index}`, `#0000${String(index).padStart(2, '0')}`]), + ); + const create = (ancestors: boolean) => { + const pool = new ValuePool({ ancestors }); + pool.declare('lightColors', { ...base, accent: '#ff0000' }, { type: 'Colors' }); + pool.declare('darkColors', { ...base, accent: '#00ff00' }, { type: 'Colors' }); + return pool.estimatedSize; + }; + assert.ok(create(true) < create(false) * 0.6); + }); + + it('round-trips random values', () => { + let seed = 7; + // mulberry32 + const random = (limit: number) => { + seed = (seed + 0x6d2b79f5) | 0; + let value = Math.imul(seed ^ (seed >>> 15), 1 | seed); + value = (value + Math.imul(value ^ (value >>> 7), 61 | value)) ^ value; + return Math.floor((((value ^ (value >>> 14)) >>> 0) / 4294967296) * limit); + }; + const leaves = [ + '#ffffff', + '#000000', + 'inverted', + 'a', + 0, + 1, + 2.5, + -1, + true, + null, + platformColor('Window'), + expression('fontWeightBold'), + ]; + const createObject = (depth: number): Record => + Object.fromEntries(Array.from({ length: 2 + random(8) }, () => [`key${random(10)}`, createValue(depth + 1)])); + const createValue = (depth: number): unknown => { + const choice = random(depth > 2 ? 2 : 4); + if (choice < 2) { + return leaves[random(leaves.length)]; + } + return choice === 2 ? Array.from({ length: random(4) }, () => createValue(depth + 1)) : createObject(depth); + }; + // Derive a variant by replacing, removing, and adding some entries, recursively in nested objects. + const vary = (value: unknown, depth: number): unknown => { + if (!value || typeof value !== 'object' || Array.isArray(value) || value instanceof CodeExpression) { + return random(4) === 0 ? createValue(depth) : value; + } + const result: Record = {}; + for (const [key, item] of Object.entries(value)) { + const choice = random(8); + if (choice > 1) { + result[key] = choice < 4 ? vary(item, depth + 1) : item; + } else if (choice === 1) { + result[key] = createValue(depth + 1); + } + } + if (random(3) === 0) { + result[`added${random(3)}`] = createValue(depth + 1); + } + return result; + }; + let spreads = 0; + for (let run = 0; run < 200; run++) { + const declarations: Record = {}; + const pool = new ValuePool({ identifierSize: 1 + random(2) }).reserve('fontWeightBold'); + const base = { ...createObject(2), nested: createValue(1), more: createValue(1) }; + for (let index = 0; index < 2 + random(5); index++) { + const value = random(6) === 0 ? createValue(1) : vary(base, 1); + declarations[`variant${index}Tokens`] = value; + pool.declare(`variant${index}Tokens`, value, { type: random(4) === 0 ? undefined : 'Tokens' }); + } + spreads += roundTrip(pool, declarations).includes('...') ? 1 : 0; + } + assert.ok(spreads > 50, `only ${spreads} runs shared ancestors`); + }); + + it('rejects values it cannot emit', () => { + assert.throws(() => new ValuePool().declare('value', new Date()), /not a plain object/); + assert.throws(() => new ValuePool().declare('value', () => 1), /unsupported function/); + const circular: Record = {}; + circular.self = circular; + assert.throws(() => new ValuePool().declare('value', circular), /circular/); + assert.throws(() => new ValuePool().declare('default', 1), /not a valid declaration name/); + const pool = new ValuePool().declare('value', 1); + assert.throws(() => pool.declare('value', 2), /already declared/); + pool.output(); + assert.throws(() => pool.declare('other', 1), /already been emitted/); + }); +}); diff --git a/scripts/src/codegen/valuePool.ts b/scripts/src/codegen/valuePool.ts new file mode 100644 index 0000000000..1721071161 --- /dev/null +++ b/scripts/src/codegen/valuePool.ts @@ -0,0 +1,999 @@ +import type { Chunk } from './file.ts'; + +/** Options for a {@link CodeExpression}. */ +export type ExpressionOptions = { + /** Base name for the constant when the expression is hoisted. */ + name?: string; + /** Marks a call as free of side effects, so bundlers can drop it when it is unused. */ + pure?: boolean; + /** Estimated minified size in bytes. Defaults to an estimate that counts each identifier as a mangled name. */ + size?: number; +}; + +/** JavaScript emitted verbatim, such as an imported identifier or a call. */ +export class CodeExpression { + readonly code: string; + readonly name: string | undefined; + readonly pure: boolean; + readonly size: number | undefined; + + constructor(code: string, options: ExpressionOptions = {}) { + this.code = code; + this.name = options.name; + this.pure = options.pure ?? false; + this.size = options.size; + } +} + +/** Create a {@link CodeExpression}. */ +export function expression(code: string, options?: ExpressionOptions): CodeExpression { + return new CodeExpression(code, options); +} + +/** Values a {@link ValuePool} can emit. Objects must be plain objects; object properties set to undefined are omitted. */ +export type CodeValue = + | string + | number + | boolean + | null + | undefined + | CodeExpression + | readonly CodeValue[] + | { readonly [key: string]: CodeValue }; + +/** Property keys and array indices from a declaration to a value. The first segment is the declaration name. */ +export type ValuePath = readonly (string | number)[]; + +/** Options for a {@link ValuePool}. */ +export type ValuePoolOptions = { + /** Base name for a hoisted value. Return undefined to use the default name. */ + name?: (value: unknown, path: ValuePath) => string | undefined; + /** Extract entries that declarations of the same family share into common ancestor objects. Defaults to true. */ + ancestors?: boolean; + /** Add `as const` to hoisted arrays and objects, so literal and tuple types survive hoisting. Defaults to true. */ + constAssertions?: boolean; + /** Estimated length of a minified identifier, used to decide what to share. Defaults to 2. */ + identifierSize?: number; + /** Line width for formatting. Defaults to 140. */ + printWidth?: number; +}; + +/** Options for a declaration added with {@link ValuePool.declare}. */ +export type DeclarationOptions = { + /** Export the declaration. Defaults to true. */ + exported?: boolean; + /** Type annotation, as in `const name: Type`. */ + type?: string; + /** Type for a `satisfies` clause. */ + satisfies?: string; + /** Documentation comment for the declaration. */ + comment?: string | string[]; + /** Object declarations in the same family share ancestors. Defaults to the type annotation. */ + family?: string; +}; + +type Entry = readonly [key: string, node: ValueNode]; + +type Family = { + /** Declaration names of the family's object members, in declaration order. */ + readonly roots: readonly string[]; + /** Common camel-case suffix of the root names, such as `Shadows`. Empty when the names share none. */ + readonly suffix: string; + readonly name: string; +}; + +type AncestorInfo = { + readonly family: Family; + /** Declaration names whose value includes this ancestor. */ + readonly roots: readonly string[]; + /** Property keys from the declarations to the objects that spread this ancestor. */ + readonly path: readonly string[]; +}; + +type ValueNode = { + readonly id: number; + readonly kind: 'literal' | 'expression' | 'array' | 'object'; + /** The value and path where the node first occurred, for naming. */ + readonly source: unknown; + readonly path: ValuePath; + readonly literal?: string | number | boolean | null | undefined; + readonly expression?: CodeExpression; + readonly items?: readonly ValueNode[]; + /** Object entries in first-occurrence order. */ + readonly entries?: readonly Entry[]; + readonly lookup?: ReadonlyMap; + /** Ancestor objects this object spreads; `own` holds the entries they do not cover. */ + spreads?: ValueNode[]; + own?: Entry[]; + ancestor?: AncestorInfo; +}; + +type Declaration = { + readonly name: string; + readonly node: ValueNode; + readonly options: DeclarationOptions; + readonly family: string; + readonly index: number; +}; + +type Item = { + readonly node: ValueNode; + /** The declaration this item emits; undefined for a hoisted constant. */ + readonly declaration?: Declaration; + readonly rank: readonly (number | string)[]; + readonly group: string; + dependencies: Item[]; +}; + +const identifierPattern = /^[A-Za-z_$][\w$]*$/; +const indexPattern = /^(?:0|[1-9]\d*)$/; +const hexColorPattern = /^#(?:[0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/; +const wordPattern = /^[A-Za-z][A-Za-z0-9]{0,23}$/; +const reservedWords = new Set( + ( + 'arguments await break case catch class const continue debugger default delete do else enum eval export extends false ' + + 'finally for function if implements import in instanceof interface let new null package private protected public ' + + 'return static super switch this throw true try typeof undefined var void while with yield NaN Infinity' + ).split(' '), +); +const maxHoistingPasses = 8; + +function formatPath(path: ValuePath): string { + return path.map((segment, index) => (typeof segment === 'number' ? `[${segment}]` : index === 0 ? segment : `.${segment}`)).join(''); +} + +function quote(value: string): string { + let text = "'"; + for (const char of value) { + if (char === "'" || char === '\\') { + text += `\\${char}`; + } else if (char === '\n') { + text += '\\n'; + } else if (char === '\r') { + text += '\\r'; + } else if (char === '\u2028' || char === '\u2029') { + text += char === '\u2028' ? '\\u2028' : '\\u2029'; + } else { + text += char; + } + } + return `${text}'`; +} + +function literalCode(value: ValueNode['literal']): string { + if (typeof value === 'string') { + return quote(value); + } + if (typeof value === 'number' && Object.is(value, -0)) { + return '-0'; + } + return String(value); +} + +function propertyKey(key: string): string { + return identifierPattern.test(key) || indexPattern.test(key) ? key : quote(key); +} + +/** Minified size of a number as esbuild prints it, such as `.5` for 0.5 and `1e3` for 1000. */ +function numberSize(value: number): number { + let text = Object.is(value, -0) ? '-0' : String(value); + if (text.startsWith('0.') || text.startsWith('-0.')) { + text = text.replace('0.', '.'); + } + if (Number.isInteger(value) && Math.abs(value) >= 1000) { + let zeros = 0; + while (text[text.length - 1 - zeros] === '0') { + zeros++; + } + if (zeros >= 3) { + return text.length - zeros + 1 + String(zeros).length; + } + } + return text.length; +} + +function literalSize(value: ValueNode['literal']): number { + switch (typeof value) { + case 'string': + return JSON.stringify(value).length; + case 'number': + return numberSize(value); + case 'boolean': + return 2; + case 'undefined': + return 6; + default: + return 4; + } +} + +function keySize(key: string): number { + return identifierPattern.test(key) || indexPattern.test(key) ? key.length : JSON.stringify(key).length; +} + +function isIdentifierStart(char: string): boolean { + return (char >= 'a' && char <= 'z') || (char >= 'A' && char <= 'Z') || char === '_' || char === '$'; +} + +function isIdentifierPart(char: string): boolean { + return isIdentifierStart(char) || (char >= '0' && char <= '9'); +} + +/** Visit the code outside string literals, reporting identifiers and the other characters a minifier keeps. */ +function scanCode(code: string, onIdentifier: (name: string, isProperty: boolean) => void, onOther: (length: number) => void) { + let previous = ''; + let index = 0; + while (index < code.length) { + const char = code[index]; + if (char === "'" || char === '"' || char === '`') { + let end = index + 1; + while (end < code.length && code[end] !== char) { + end += code[end] === '\\' ? 2 : 1; + } + onOther(Math.min(end + 1, code.length) - index); + previous = char; + index = end + 1; + } else if (isIdentifierStart(char)) { + let end = index + 1; + while (end < code.length && isIdentifierPart(code[end])) { + end++; + } + onIdentifier(code.slice(index, end), previous === '.'); + previous = 'a'; + index = end; + } else { + if (char.trim() !== '') { + onOther(1); + previous = char; + } + index++; + } + } +} + +function expressionSize(value: CodeExpression, identifierSize: number): number { + if (value.size !== undefined) { + return value.size; + } + let size = 0; + scanCode( + value.code, + (name, isProperty) => (size += isProperty ? name.length : identifierSize), + (length) => (size += length), + ); + return size; +} + +function expressionCode(value: CodeExpression): string { + return value.pure ? `/* @__PURE__ */ ${value.code}` : value.code; +} + +function capitalize(text: string): string { + return text.charAt(0).toUpperCase() + text.slice(1); +} + +/** Convert text to a valid identifier, camel-casing across invalid characters. */ +function toIdentifier(text: string): string { + let name = ''; + let upper = false; + for (const char of text) { + if (isIdentifierPart(char)) { + name += upper && name ? char.toUpperCase() : char; + upper = false; + } else { + upper = true; + } + } + if (!name) { + return 'value'; + } + if (!isIdentifierStart(name[0])) { + name = `_${name}`; + } + return reservedWords.has(name) ? `${name}Value` : name; +} + +function splitWords(name: string): string[] { + const words: string[] = []; + let start = 0; + for (let index = 1; index < name.length; index++) { + if (name[index] >= 'A' && name[index] <= 'Z') { + words.push(name.slice(start, index)); + start = index; + } + } + words.push(name.slice(start)); + return words; +} + +function createFamily(name: string, roots: readonly string[]): Family { + const words = roots.map(splitWords); + const suffix: string[] = []; + for (;;) { + const position = suffix.length + 1; + const word = words[0][words[0].length - position]; + if (!words.every((list) => list.length > position && list[list.length - position] === word)) { + break; + } + suffix.unshift(word); + } + return { name, roots, suffix: suffix.join('') }; +} + +function ancestorName({ family, roots, path }: AncestorInfo): string { + const pathPart = path.map((key) => capitalize(toIdentifier(key))).join(''); + if (!family.suffix) { + return toIdentifier(`shared ${family.name} ${pathPart}`); + } + if (family.roots.every((root) => roots.includes(root))) { + return `shared${family.suffix}${pathPart}`; + } + const prefixes = family.roots.filter((root) => roots.includes(root)).map((root) => root.slice(0, root.length - family.suffix.length)); + return toIdentifier(prefixes.map((prefix, index) => (index === 0 ? prefix : capitalize(prefix))).join('') + family.suffix + pathPart); +} + +function compareRank(left: readonly (number | string)[], right: readonly (number | string)[]): number { + for (let index = 0; index < Math.min(left.length, right.length); index++) { + if (left[index] !== right[index]) { + return left[index] < right[index] ? -1 : 1; + } + } + return left.length - right.length; +} + +function writeDocComment(text: string | string[]): string { + const lines = Array.isArray(text) ? text : text.split('\n'); + return lines.length === 1 ? `/** ${lines[0]} */` : `/**\n${lines.map((line) => (line ? ` * ${line}` : ' *')).join('\n')}\n */`; +} + +/** + * A value pool emits constant declarations and minimizes their minified size. Equal values are emitted once and shared, + * which a size model decides per value: strings, expressions, arrays, and objects are hoisted into constants when that + * is smaller than repeating them. Object declarations in the same family share common ancestor objects: entries that + * several members hold are emitted once in an ancestor that the members spread, recursively for nested objects, and + * ancestors spread the ancestors of larger member sets. Hex color strings are named `rgb`, as a Ramp names them. + * + * Shared objects and ancestors change the key order of emitted objects. Declarations are emitted in dependency order. + */ +export class ValuePool implements Chunk { + private readonly _ancestors: boolean; + private readonly _constAssertions: boolean; + private readonly _identifierSize: number; + private readonly _printWidth: number; + private readonly _name: ValuePoolOptions['name']; + private readonly _declarations: Declaration[] = []; + private readonly _reserved = new Set(); + private readonly _nodes = new Map(); + private readonly _canonicalSizes = new Map(); + private _names = new Map(); + private _output: string | undefined; + private _size = 0; + + constructor(options: ValuePoolOptions = {}) { + this._ancestors = options.ancestors ?? true; + this._constAssertions = options.constAssertions ?? true; + this._identifierSize = options.identifierSize ?? 2; + this._printWidth = options.printWidth ?? 140; + this._name = options.name; + } + + /** Reserve names, such as imports, that hoisted constants must not use. */ + reserve(...names: string[]): this { + this.assertOpen(); + for (const name of names) { + this._reserved.add(name); + } + return this; + } + + /** Declare a constant. Declarations are emitted in the order they are declared, after the values they reference. */ + declare(name: string, value: unknown, options: DeclarationOptions = {}): this { + this.assertOpen(); + if (!identifierPattern.test(name) || reservedWords.has(name)) { + throw new Error(`${name} is not a valid declaration name.`); + } + if (this._declarations.some((declaration) => declaration.name === name)) { + throw new Error(`${name} is already declared.`); + } + const node = this.intern(value, [name], new Set()); + const family = options.family ?? options.type ?? options.satisfies ?? ''; + this._declarations.push({ name, node, options, family, index: this._declarations.length }); + return this; + } + + /** Estimated minified size in bytes of the emitted declarations. */ + get estimatedSize(): number { + this.resolve(); + return this._size; + } + + output(): string { + return this.resolve(); + } + + private assertOpen() { + if (this._output !== undefined) { + throw new Error('The value pool has already been emitted.'); + } + } + + private intern(value: unknown, path: ValuePath, active: Set): ValueNode { + if (value instanceof CodeExpression) { + return this.node(`e${value.code}`, { kind: 'expression', expression: value }, value, path); + } + switch (typeof value) { + case 'string': + return this.node(`s${value}`, { kind: 'literal', literal: value }, value, path); + case 'number': + return this.node(`n${Object.is(value, -0) ? '-0' : String(value)}`, { kind: 'literal', literal: value }, value, path); + case 'boolean': + case 'undefined': + return this.node(`l${value}`, { kind: 'literal', literal: value }, value, path); + case 'object': + break; + default: + throw new Error(`${formatPath(path)} is an unsupported ${typeof value} value.`); + } + if (value === null) { + return this.node('lnull', { kind: 'literal', literal: null }, value, path); + } + if (active.has(value)) { + throw new Error(`${formatPath(path)} is circular.`); + } + active.add(value); + try { + if (Array.isArray(value)) { + const items = Array.from(value as unknown[], (item, index) => this.intern(item, [...path, index], active)); + return this.node(`a${items.map((item) => item.id).join(',')}`, { kind: 'array', items }, value, path); + } + const prototype: unknown = Object.getPrototypeOf(value); + if (prototype !== Object.prototype && prototype !== null) { + throw new Error(`${formatPath(path)} is not a plain object.`); + } + const entries: Entry[] = []; + for (const [key, item] of Object.entries(value)) { + if (key === '__proto__') { + throw new Error(`${formatPath(path)} has an unsupported __proto__ key.`); + } + if (item !== undefined) { + entries.push([key, this.intern(item, [...path, key], active)]); + } + } + return this.objectNode(entries, value, path); + } finally { + active.delete(value); + } + } + + private objectNode(entries: readonly Entry[], source: unknown, path: ValuePath): ValueNode { + const key = `o${entries + .map(([name, node]) => `${JSON.stringify(name)}:${node.id}`) + .sort() + .join(',')}`; + return this.node(key, { kind: 'object', entries, lookup: new Map(entries) }, source, path); + } + + private node(key: string, shape: Omit, source: unknown, path: ValuePath): ValueNode { + let node = this._nodes.get(key); + if (!node) { + node = { ...shape, id: this._nodes.size, source, path }; + this._nodes.set(key, node); + } + return node; + } + + private extractFamilies() { + const families = new Map(); + for (const declaration of this._declarations) { + const list = families.get(declaration.family) ?? []; + list.push(declaration); + families.set(declaration.family, list); + } + for (const [name, declarations] of families) { + const objects = declarations.filter(({ node }) => node.kind === 'object'); + const members: ValueNode[] = []; + const memberRoots: string[][] = []; + for (const { name: root, node } of objects) { + const index = members.indexOf(node); + if (index >= 0) { + memberRoots[index].push(root); + } else { + members.push(node); + memberRoots.push([root]); + } + } + if (members.length >= 2) { + const family = createFamily( + name, + objects.map((declaration) => declaration.name), + ); + this.extractAncestors(family, members, memberRoots, []); + } + } + } + + /** + * Group the entries of distinct objects by the set of objects that hold them, and move each group that is smaller + * shared into an ancestor object. An ancestor spreads the ancestors of the smallest larger sets that contain its set, + * and each object spreads the ancestors of the smallest sets that contain it. Objects held under the same key recurse. + */ + private extractAncestors( + family: Family, + nodes: readonly ValueNode[], + nodeRoots: readonly (readonly string[])[], + path: readonly string[], + ) { + const members = nodes.flatMap((node, index) => (node.spreads ? [] : [{ node, roots: nodeRoots[index] }])); + if (members.length < 2) { + return; + } + type Group = { members: number[]; entries: Entry[]; node?: ValueNode }; + const groups = new Map(); + const keys = new Set(members.flatMap(({ node }) => node.entries!.map(([key]) => key))); + for (const key of keys) { + const holders = new Map(); + members.forEach(({ node }, index) => { + const value = node.lookup!.get(key); + if (value) { + const list = holders.get(value); + if (list) { + list.push(index); + } else { + holders.set(value, [index]); + } + } + }); + for (const [value, indices] of holders) { + if (indices.length >= 2) { + const signature = indices.join(','); + const group = groups.get(signature) ?? { members: indices, entries: [] }; + group.entries.push([key, value]); + groups.set(signature, group); + } + } + const objects = [...holders.keys()].filter((value) => value.kind === 'object'); + if (objects.length >= 2) { + const roots = objects.map((value) => holders.get(value)!.flatMap((index) => members[index].roots)); + this.extractAncestors(family, objects, roots, [...path, key]); + } + } + + const chosen = [...groups.values()].filter((group) => this.ancestorBenefit(group.members.length, group.entries) > 0); + const contains = (outer: Group, inner: Group) => + outer.members.length > inner.members.length && inner.members.every((index) => outer.members.includes(index)); + const smallest = (list: Group[]) => list.filter((group) => !list.some((other) => contains(group, other))); + // Create larger sets first, so the ancestors a set spreads exist before it. + chosen.sort((left, right) => right.members.length - left.members.length); + for (const group of chosen) { + const parents = smallest(chosen.filter((other) => contains(other, group))).map((parent) => parent.node!); + const content = new Map(parents.flatMap((parent) => parent.entries!)); + for (const [key, value] of group.entries) { + content.set(key, value); + } + const node = this.objectNode([...content], undefined, []); + if (!node.spreads && parents.length > 0) { + node.spreads = parents; + node.own = group.entries; + } + node.ancestor ??= { family, roots: group.members.flatMap((index) => members[index].roots), path }; + group.node = node; + } + members.forEach(({ node }, index) => { + const required = chosen.filter((group) => group.members.includes(index)); + if (required.length === 0 || required.some((group) => group.node === node)) { + return; + } + const covered = new Set(required.flatMap((group) => group.entries.map(([key]) => key))); + node.spreads = smallest(required).map((group) => group.node!); + node.own = node.entries!.filter(([key]) => !covered.has(key)); + }); + } + + /** Bytes saved by emitting entries that `count` objects share once, in an ancestor the objects spread. */ + private ancestorBenefit(count: number, entries: readonly Entry[]): number { + const identifierSize = this._identifierSize; + let size = 0; + for (const [key, value] of entries) { + size += keySize(key) + 2 + Math.min(this.canonicalSize(value), identifierSize); + } + // The ancestor costs a declaration and braces; each object spreads it. + return (count - 1) * size - (identifierSize + 4) - count * (identifierSize + 4); + } + + /** Throw unless the spreads and own entries of an object reproduce exactly its entries. */ + private verifyPlan(node: ValueNode) { + const merged = new Map(); + const add = (source: ValueNode) => { + for (const spread of source.spreads ?? []) { + add(spread); + } + for (const [key, value] of source.spreads ? source.own! : source.entries!) { + if ((merged.get(key) ?? value) !== value) { + throw new Error(`Ancestors of ${formatPath(node.path)} disagree on ${key}.`); + } + merged.set(key, value); + } + }; + add(node); + const lookup = node.lookup!; + if (merged.size !== lookup.size || [...merged].some(([key, value]) => lookup.get(key) !== value)) { + throw new Error(`Ancestors of ${formatPath(node.path)} do not reproduce it.`); + } + } + + private canonicalSize(node: ValueNode): number { + let size = this._canonicalSizes.get(node); + if (size === undefined) { + size = this.contentSize(node, (child) => this.canonicalSize(child), false); + this._canonicalSizes.set(node, size); + } + return size; + } + + /** Minified size of a value, given the size of each child reference. */ + private contentSize(node: ValueNode, childSize: (child: ValueNode) => number, usePlan: boolean): number { + switch (node.kind) { + case 'literal': + return literalSize(node.literal); + case 'expression': + return expressionSize(node.expression!, this._identifierSize); + case 'array': { + const items = node.items!; + return items.reduce((size, item) => size + childSize(item), 1 + Math.max(items.length, 1)); + } + default: { + const spreads = usePlan ? (node.spreads ?? []) : []; + const entries = usePlan && node.spreads ? node.own! : node.entries!; + const parts = spreads.length + entries.length; + const size = 1 + Math.max(parts, 1) + spreads.length * (3 + this._identifierSize); + return entries.reduce((total, [key, value]) => total + keySize(key) + 1 + childSize(value), size); + } + } + } + + private resolve(): string { + if (this._output !== undefined) { + return this._output; + } + if (this._ancestors) { + this.extractFamilies(); + } + for (const node of this._nodes.values()) { + if (node.spreads) { + this.verifyPlan(node); + } + } + const heights = new Map(); + const visit = (node: ValueNode): number => { + let height = heights.get(node); + if (height === undefined) { + height = Math.max(-1, ...children(node).map(visit)) + 1; + heights.set(node, height); + } + return height; + }; + this._declarations.forEach(({ node }) => visit(node)); + // Parents before children. + const nodes = [...heights.keys()].sort((left, right) => heights.get(right)! - heights.get(left)! || left.id - right.id); + + // The first declaration of a value emits it, and later declarations reference it. A value declared with different + // types is emitted as a constant that every declaration references, so each declaration checks its own type. + const owners = new Map(); + const detached = new Set(); + for (const declaration of this._declarations) { + const owner = owners.get(declaration.node); + if (!owner) { + owners.set(declaration.node, declaration); + } else if (owner.options.type !== declaration.options.type || owner.options.satisfies !== declaration.options.satisfies) { + detached.add(declaration.node); + } + } + detached.forEach((node) => owners.delete(node)); + const forced = new Set(nodes.filter((node) => node.ancestor || owners.has(node) || detached.has(node))); + const aliases = this._declarations.filter((declaration) => owners.get(declaration.node) !== declaration).length; + + const declared = this.chooseDeclared(nodes, forced, aliases); + const groups = this.assignNames(nodes, declared, owners); + this._output = this.render(nodes, heights, declared, owners, groups); + return this._output; + } + + /** + * Choose the values to declare. Parents are decided before their children, because a declared parent emits its + * children once. Each pass measures values with the previous pass's choices, and the smallest result wins. + */ + private chooseDeclared(nodes: readonly ValueNode[], forced: ReadonlySet, aliases: number): Set { + const identifierSize = this._identifierSize; + let sizes = this.measure(nodes, forced); + let best: { declared: Set; size: number } | undefined; + let previous: Set | undefined; + for (let pass = 0; pass < maxHoistingPasses; pass++) { + const counts = new Map(); + this._declarations.forEach(({ node }) => counts.set(node, (counts.get(node) ?? 0) + 1)); + const declared = new Set(forced); + for (const node of nodes) { + const count = counts.get(node) ?? 0; + const size = sizes.get(node)!; + const hoistable = node.kind !== 'literal' || typeof node.literal === 'string'; + if (hoistable && !declared.has(node) && count * size > size + identifierSize + 2 + count * identifierSize) { + declared.add(node); + } + const emitted = declared.has(node) ? 1 : count; + for (const child of children(node)) { + counts.set(child, (counts.get(child) ?? 0) + emitted); + } + } + sizes = this.measure(nodes, declared); + let size = aliases * (2 * identifierSize + 2); + declared.forEach((node) => (size += identifierSize + 2 + sizes.get(node)!)); + if (!best || size < best.size) { + best = { declared, size }; + } + if (previous?.size === declared.size && [...declared].every((node) => previous!.has(node))) { + break; + } + previous = declared; + } + this._size = best!.size; + return best!.declared; + } + + /** Minified size of each value, children first, where declared children cost a reference. */ + private measure(nodes: readonly ValueNode[], declared: ReadonlySet): Map { + const sizes = new Map(); + for (let index = nodes.length - 1; index >= 0; index--) { + const node = nodes[index]; + sizes.set( + node, + this.contentSize(node, (child) => (declared.has(child) ? this._identifierSize : sizes.get(child)!), true), + ); + } + return sizes; + } + + /** Name every declared value and return the group each hoisted value is listed with. */ + private assignNames(nodes: readonly ValueNode[], declared: ReadonlySet, owners: ReadonlyMap) { + const names = new Map(); + const taken = new Set([...this._reserved, ...this._declarations.map(({ name }) => name)]); + for (const node of nodes) { + if (node.expression) { + scanCode( + node.expression.code, + (name, isProperty) => !isProperty && taken.add(name), + () => undefined, + ); + } + } + owners.forEach((declaration, node) => names.set(node, declaration.name)); + const unique = (base: string) => { + let name = base; + for (let index = 2; taken.has(name); index++) { + name = `${base}${index}`; + } + taken.add(name); + return name; + }; + const pending = nodes.filter((node) => declared.has(node) && !names.has(node)).sort((left, right) => left.id - right.id); + const groups = new Map(); + const byBase = new Map(); + for (const node of pending) { + if (node.ancestor) { + names.set(node, unique(ancestorName(node.ancestor))); + } else { + const base = this.baseName(node); + const list = byBase.get(base); + if (list) { + list.push(node); + } else { + byBase.set(base, [node]); + } + groups.set(node, base); + } + } + for (const [base, list] of byBase) { + if (list.length === 1 && !taken.has(base)) { + names.set(list[0], unique(base)); + continue; + } + let index = 1; + for (const node of list) { + while (taken.has(`${base}${index}`)) { + index++; + } + names.set(node, unique(`${base}${index}`)); + } + } + this._names = names; + return groups; + } + + private baseName(node: ValueNode): string { + const custom = this._name?.(node.source, node.path); + if (custom) { + return toIdentifier(custom); + } + if (typeof node.literal === 'string') { + if (hexColorPattern.test(node.literal)) { + return `rgb${node.literal.slice(1)}`; + } + if (wordPattern.test(node.literal)) { + return toIdentifier(node.literal); + } + } + if (node.expression?.name) { + return toIdentifier(node.expression.name); + } + for (let index = node.path.length - 1; index > 0; index--) { + const segment = node.path[index]; + if (typeof segment === 'string') { + return toIdentifier(segment); + } + } + return node.path.length === 1 ? `${node.path[0]}Value` : 'value'; + } + + private render( + nodes: readonly ValueNode[], + heights: ReadonlyMap, + declared: ReadonlySet, + owners: ReadonlyMap, + groups: ReadonlyMap, + ): string { + const items: Item[] = []; + const emitters = new Map(); + for (const node of nodes) { + if (declared.has(node) && !owners.has(node)) { + // Hoisted values are listed in blocks by kind and height: strings and expressions by name, then arrays and + // objects by base name and first occurrence. Ancestors follow, then the declarations. + const height = heights.get(node)!; + const kind = node.kind === 'literal' || node.kind === 'expression' ? node.kind : 'value'; + const order = kind === 'value' ? [groups.get(node)!, node.id] : [this._names.get(node)!]; + const rank = node.ancestor ? [1, height, node.id] : [0, height, kind, ...order]; + const item: Item = { node, rank, group: `${kind}:${height}`, dependencies: [] }; + emitters.set(node, item); + items.push(item); + } + } + for (const declaration of this._declarations) { + const item: Item = { node: declaration.node, declaration, rank: [2, declaration.index], group: 'declaration', dependencies: [] }; + if (owners.get(declaration.node) === declaration) { + emitters.set(declaration.node, item); + } + items.push(item); + } + for (const item of items) { + const emits = emitters.get(item.node) === item; + item.dependencies = (emits ? this.references(item.node, declared) : [item.node]).map((node) => emitters.get(node)!); + } + + // Emit in rank order, holding each item until the items it references are emitted. + const emitted = new Set(); + let text = ''; + let previous: { group: string; multiline: boolean } | undefined; + while (emitted.size < items.length) { + let next: Item | undefined; + for (const item of items) { + if ( + !emitted.has(item) && + item.dependencies.every((dependency) => emitted.has(dependency)) && + (!next || compareRank(item.rank, next.rank) < 0) + ) { + next = item; + } + } + if (!next) { + throw new Error('Declarations reference each other circularly.'); + } + emitted.add(next); + const code = next.declaration ? this.renderDeclaration(next.declaration, owners) : this.renderConstant(next.node); + const multiline = code.includes('\n'); + if (previous) { + text += multiline || previous.multiline || previous.group !== next.group ? '\n\n' : '\n'; + } + text += code; + previous = { group: next.group, multiline }; + } + return text ? `${text}\n` : ''; + } + + /** Declared values that the emitted form of a value references. */ + private references(node: ValueNode, declared: ReadonlySet): ValueNode[] { + const found = new Set(); + const visit = (current: ValueNode) => { + for (const child of children(current)) { + if (declared.has(child)) { + found.add(child); + } else { + visit(child); + } + } + }; + visit(node); + return [...found]; + } + + private renderConstant(node: ValueNode): string { + const prefix = `const ${this._names.get(node)} = `; + const suffix = this._constAssertions && (node.kind === 'array' || node.kind === 'object') ? ' as const' : ''; + return `${prefix}${this.format(node, 0, prefix.length, suffix.length + 1, Boolean(node.ancestor), node)}${suffix};`; + } + + private renderDeclaration(declaration: Declaration, owners: ReadonlyMap): string { + const { name, node, options } = declaration; + const prefix = `${options.exported === false ? '' : 'export '}const ${name}${options.type ? `: ${options.type}` : ''} = `; + const suffix = options.satisfies ? ` satisfies ${options.satisfies}` : ''; + const value = + owners.get(node) === declaration ? this.format(node, 0, prefix.length, suffix.length + 1, true, node) : this._names.get(node); + const comment = options.comment ? `${writeDocComment(options.comment)}\n` : ''; + return `${comment}${prefix}${value}${suffix};`; + } + + /** + * Format a value that starts at `column` and is followed by `trailing` characters. Arrays and objects stay on one line + * when they fit, unless `multiline` is set. `self` is the value being declared, which is expanded rather than named. + */ + private format(node: ValueNode, depth: number, column: number, trailing: number, multiline: boolean, self?: ValueNode): string { + const inline = this.inline(node, self); + const parts = this.parts(node, self); + if (!parts || parts.length === 0 || (!multiline && column + inline.length + trailing <= this._printWidth)) { + return inline; + } + const indent = ' '.repeat(depth + 1); + const lines = parts.map(([key, value]) => { + if (!value) { + return `${indent}${key},`; + } + const prefix = key === undefined ? indent : `${indent}${propertyKey(key)}: `; + return `${prefix}${this.format(value, depth + 1, prefix.length, 1, false)},`; + }); + const [open, close] = node.kind === 'array' ? ['[', ']'] : ['{', '}']; + return `${open}\n${lines.join('\n')}\n${' '.repeat(depth)}${close}`; + } + + private inline(node: ValueNode, self?: ValueNode): string { + const parts = this.parts(node, self); + if (!parts) { + return node !== self && this._names.has(node) + ? this._names.get(node)! + : node.expression + ? expressionCode(node.expression) + : literalCode(node.literal); + } + const text = parts.map(([key, value]) => { + const code = value ? this.inline(value) : ''; + return key === undefined ? code : value ? `${propertyKey(key)}: ${code}` : key; + }); + if (node.kind === 'array') { + return `[${text.join(', ')}]`; + } + return text.length > 0 ? `{ ${text.join(', ')} }` : '{}'; + } + + /** + * The parts of an array or object to emit, or undefined for a reference or a scalar. A part with a key and no value + * is a spread or shorthand property, emitted as the key. + */ + private parts(node: ValueNode, self?: ValueNode): [key: string | undefined, value: ValueNode | undefined][] | undefined { + if ((node !== self && this._names.has(node)) || (node.kind !== 'array' && node.kind !== 'object')) { + return undefined; + } + if (node.kind === 'array') { + return node.items!.map((item) => [undefined, item]); + } + const spreads = (node.spreads ?? []).map((spread): [string, undefined] => [`...${this._names.get(spread)}`, undefined]); + const entries = (node.spreads ? node.own! : node.entries!).map(([key, value]): [string, ValueNode | undefined] => + this._names.get(value) === key ? [key, undefined] : [key, value], + ); + return [...spreads, ...entries]; + } +} + +function children(node: ValueNode): readonly ValueNode[] { + if (node.kind === 'array') { + return node.items!; + } + if (node.kind !== 'object') { + return []; + } + return [...(node.spreads ?? []), ...(node.spreads ? node.own! : node.entries!).map(([, value]) => value)]; +} diff --git a/scripts/src/index.ts b/scripts/src/index.ts index a13bcfe212..7a3bb9a875 100644 --- a/scripts/src/index.ts +++ b/scripts/src/index.ts @@ -10,3 +10,5 @@ export { outputCodegenFile } from './codegen/genFile.ts'; export { makeComment, GeneratedFile, serialize } from './codegen/file.ts'; export type { Chunk, Output, Comment } from './codegen/file.ts'; export { Ramp } from './codegen/content.ts'; +export { CodeExpression, expression, ValuePool } from './codegen/valuePool.ts'; +export type { CodeValue, DeclarationOptions, ExpressionOptions, ValuePath, ValuePoolOptions } from './codegen/valuePool.ts'; From f889a4f2506906ea0fcb1d74aafb0fb613a23e20 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 30 Oct 2026 14:31:47 -0700 Subject: [PATCH 13/18] add fluent theme entrypoints --- .changeset/design-fluent-themes.md | 9 + apps/bundle-size/baseline.json | 60 ++++++ apps/bundle-size/scenarios.json | 39 ++++ packages/agentic/design/AGENTS.md | 4 +- packages/agentic/design/README.md | 21 ++- packages/agentic/design/package.json | 6 + packages/agentic/design/references/README.md | 2 +- .../agentic/design/references/contributing.md | 16 +- .../agentic/design/references/entry-points.md | 9 +- .../design/references/remaining-work.md | 16 ++ packages/agentic/design/references/theming.md | 33 ++++ packages/agentic/design/references/tokens.md | 5 +- .../__snapshots__/entryPoints.test.ts.snap | 8 + .../test/compatibility/entryPoints.test.ts | 1 + .../compatibility/importBoundaries.test.ts | 12 ++ .../src/themes/fluent/createFluentTheme.ts | 77 ++++++++ .../src/themes/fluent/fluentDarkTheme.ts | 8 + .../src/themes/fluent/fluentLightTheme.ts | 8 + .../design/src/themes/fluent/fluentTheme.ts | 15 ++ .../src/themes/fluent/fluentThemes.test.tsx | 174 ++++++++++++++++++ .../design/src/themes/fluent/legacyPalette.ts | 154 ++++++++++++++++ packages/agentic/design/src/themes/index.ts | 3 + 22 files changed, 664 insertions(+), 16 deletions(-) create mode 100644 .changeset/design-fluent-themes.md create mode 100644 packages/agentic/design/src/themes/fluent/createFluentTheme.ts create mode 100644 packages/agentic/design/src/themes/fluent/fluentDarkTheme.ts create mode 100644 packages/agentic/design/src/themes/fluent/fluentLightTheme.ts create mode 100644 packages/agentic/design/src/themes/fluent/fluentTheme.ts create mode 100644 packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx create mode 100644 packages/agentic/design/src/themes/fluent/legacyPalette.ts create mode 100644 packages/agentic/design/src/themes/index.ts diff --git a/.changeset/design-fluent-themes.md b/.changeset/design-fluent-themes.md new file mode 100644 index 0000000000..4e59429ed1 --- /dev/null +++ b/.changeset/design-fluent-themes.md @@ -0,0 +1,9 @@ +--- +'@fluentui-react-native/design': minor +--- + +Add the `@fluentui-react-native/design/themes` entry point with `fluentLightTheme`, `fluentDarkTheme`, and `fluentTheme`. +The themes are built from the generated Fluent 2 alias colors, shadows, font aliases, and global tokens rather than +hand-authored values, and each legacy palette color points at the alias color that plays its role. `fluentTheme` is a +`ThemeReference` that follows the system appearance, and the `appearance` prop of `ThemeProvider` or `ThemedRoot` +overrides it. High-contrast and elevated appearances resolve by color scheme for now. diff --git a/apps/bundle-size/baseline.json b/apps/bundle-size/baseline.json index 2dd03d2060..9207fb10a6 100644 --- a/apps/bundle-size/baseline.json +++ b/apps/bundle-size/baseline.json @@ -133,6 +133,36 @@ "@fluentui-react-native/framework-base": 2527 } }, + { + "platform": "macos", + "scenario": "design-fluent-light-theme", + "rawBytes": 18739, + "gzipBytes": 4006, + "moduleCount": 7, + "metafileInputCount": 50, + "workspaceModules": { + "@fluentui-react-native/design": 6 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 18703 + } + }, + { + "platform": "macos", + "scenario": "design-fluent-theme", + "rawBytes": 27300, + "gzipBytes": 6643, + "moduleCount": 32, + "metafileInputCount": 50, + "workspaceModules": { + "@fluentui-react-native/design": 13, + "@fluentui-react-native/framework-base": 18 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 25287, + "@fluentui-react-native/framework-base": 1977 + } + }, { "platform": "windows", "scenario": "components-button", @@ -264,6 +294,36 @@ "@fluentui-react-native/design": 60259, "@fluentui-react-native/framework-base": 2527 } + }, + { + "platform": "windows", + "scenario": "design-fluent-light-theme", + "rawBytes": 17820, + "gzipBytes": 3840, + "moduleCount": 7, + "metafileInputCount": 51, + "workspaceModules": { + "@fluentui-react-native/design": 6 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 17784 + } + }, + { + "platform": "windows", + "scenario": "design-fluent-theme", + "rawBytes": 26312, + "gzipBytes": 6457, + "moduleCount": 32, + "metafileInputCount": 51, + "workspaceModules": { + "@fluentui-react-native/design": 13, + "@fluentui-react-native/framework-base": 18 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 24299, + "@fluentui-react-native/framework-base": 1977 + } } ] } diff --git a/apps/bundle-size/scenarios.json b/apps/bundle-size/scenarios.json index 0f55e0eb37..6ed7e62d8e 100644 --- a/apps/bundle-size/scenarios.json +++ b/apps/bundle-size/scenarios.json @@ -77,6 +77,45 @@ "/design/src/fluent/tokens/", "/design/src/fluent/useTheme." ] + }, + { + "name": "design-fluent-light-theme", + "module": "@fluentui-react-native/design/themes", + "exports": ["fluentLightTheme"], + "forbiddenInputPatterns": [ + "/design/src/flex/", + "/design/src/fluent/compat/", + "/design/src/fluent/tokens/", + "/design/src/fluent/useTheme.", + "/design/src/test/", + "/color-lib/" + ], + "requiredInputPatterns": ["/design/src/themes/fluent/legacyPalette.", "/design/src/fluent/defaults/fluentTokens.generated."], + "forbiddenOutputPatterns": [ + "/design/src/themes/fluent/fluentDarkTheme.", + "/design/src/themes/fluent/fluentTheme.", + "/design/src/fluent/themeReference." + ], + "requiredOutputPatterns": ["/design/src/themes/fluent/fluentLightTheme.", "/design/src/themes/fluent/legacyPalette."] + }, + { + "name": "design-fluent-theme", + "module": "@fluentui-react-native/design/themes", + "exports": ["fluentTheme"], + "forbiddenInputPatterns": [ + "/design/src/flex/", + "/design/src/fluent/compat/", + "/design/src/fluent/tokens/", + "/design/src/fluent/useTheme.", + "/design/src/test/", + "/color-lib/" + ], + "requiredOutputPatterns": [ + "/design/src/themes/fluent/fluentTheme.", + "/design/src/themes/fluent/fluentLightTheme.", + "/design/src/themes/fluent/fluentDarkTheme.", + "/design/src/fluent/themeReference." + ] } ] } diff --git a/packages/agentic/design/AGENTS.md b/packages/agentic/design/AGENTS.md index b8d2231733..acdd835206 100644 --- a/packages/agentic/design/AGENTS.md +++ b/packages/agentic/design/AGENTS.md @@ -1,8 +1,8 @@ # Design agent instructions This is the instruction root for `@fluentui-react-native/design` and every descendant. The package owns Fluent UI React -Native's theming contract: theme sources and providers, structured appearance, Flex and legacy tokens, the token -mappings, themed style factories, the runtime color library, and test-only design fixtures. +Native's theming contract: theme sources and providers, ready-made Fluent themes, structured appearance, Flex and legacy +tokens, the token mappings, themed style factories, the runtime color library, and test-only design fixtures. ## Start here diff --git a/packages/agentic/design/README.md b/packages/agentic/design/README.md index ce99108b59..915cef0834 100644 --- a/packages/agentic/design/README.md +++ b/packages/agentic/design/README.md @@ -1,8 +1,8 @@ # `@fluentui-react-native/design` -Core design system concepts, utilities, and types for Fluent UI React Native: theme sources and providers, structured -light, dark, high-contrast, and elevated appearance, Flex semantic tokens, themed style factories, and an opt-in runtime -color library. Legacy theme and token packages re-export their APIs from here. +Core design system concepts, utilities, and types for Fluent UI React Native: theme sources and providers, ready-made +Fluent themes, structured light, dark, high-contrast, and elevated appearance, Flex semantic tokens, themed style +factories, and an opt-in runtime color library. Legacy theme and token packages re-export their APIs from here. ## Quick start @@ -29,6 +29,21 @@ export const App = () => ( Existing `ThemeReference` themes and `useTheme` consumers keep working under the same provider; the [theming reference](references/theming.md) explains both authoring models and how they interoperate. +Fluent's own light and dark themes ship in the `themes` entry point, and `fluentTheme` follows the system appearance: + +```tsx +import { ThemedRoot } from '@fluentui-react-native/design'; +import { fluentTheme } from '@fluentui-react-native/design/themes'; + +export const App = () => ( + + + </ThemedRoot> +); +``` + +Use `fluentLightTheme` or `fluentDarkTheme` when you need one fixed `Theme` object. + ## Documentation | Topic | Covers | diff --git a/packages/agentic/design/package.json b/packages/agentic/design/package.json index f4d938a68c..9c4491305e 100644 --- a/packages/agentic/design/package.json +++ b/packages/agentic/design/package.json @@ -75,6 +75,12 @@ "import": "./lib/fluent/compat/defaultLegacyTheme.js", "default": "./src/fluent/compat/defaultLegacyTheme.ts" }, + "./themes": { + "types": "./lib/themes/index.d.ts", + "react-native": "./src/themes/index.ts", + "import": "./lib/themes/index.js", + "default": "./src/themes/index.ts" + }, "./testing": { "types": "./lib/test/index.d.ts", "react-native": "./src/test/index.ts", diff --git a/packages/agentic/design/references/README.md b/packages/agentic/design/references/README.md index ae02ec129f..59ba137b4d 100644 --- a/packages/agentic/design/references/README.md +++ b/packages/agentic/design/references/README.md @@ -9,7 +9,7 @@ owner_paths: | ID | Document | Read when | | ----------------------- | ----------------------------------- | -------------------------------------------------------------------------------- | -| `design.theming` | [Theming](theming.md) | Authoring themes, providers, appearance, theme hooks, or the legacy projection | +| `design.theming` | [Theming](theming.md) | Choosing or authoring themes, providers, appearance, hooks, or legacy projection | | `design.flex-colors` | [Flex colors](flex-colors.md) | Authoring, resolving, or reading Flex colors, or migrating from flat colors | | `design.tokens` | [Tokens](tokens.md) | Choosing token sources, mapping Flex tokens, or updating mappings and the x3 pin | | `design.styling` | [Styling](styling.md) | Using or changing themed style caches and state or color style factories | diff --git a/packages/agentic/design/references/contributing.md b/packages/agentic/design/references/contributing.md index 5227fe2895..c8a881e23e 100644 --- a/packages/agentic/design/references/contributing.md +++ b/packages/agentic/design/references/contributing.md @@ -20,6 +20,7 @@ owner_paths: | `src/fluent/` | Legacy Fluent theme types, `ThemeReference`, `useTheme`, platform utilities, and legacy styling | | `src/fluent/compat/` | The Flex-to-legacy projection and complete legacy defaults; never reachable from the root | | `src/fluent/tokens/` | Legacy alias, shadow, and global token data | +| `src/themes/` | Ready-made Fluent themes built from the generated Fluent 2 and global tokens; see `theming.md` | | `src/tokens/` | Generated global tokens and shared token attributes | | `src/tokens/mappings/` | The canonical token map and its generated projections; see `tokens.md` | | `src/styling/` | Shared state style factories and the `styling` facade; see `styling.md` | @@ -27,11 +28,11 @@ owner_paths: | `src/test/` | Test-only fixtures, compatibility baselines, and color validation; see `testing.md` | | `src/index.ts` | The modern root entry point; see `entry-points.md` for every subpath | -Shared modules may import types from either model. At runtime, only the `theming` facade and the legacy subpaths reach -`src/fluent/`; the root and `styling` graphs may reach `src/flex/` but never `src/fluent/`. Dependencies point one way: -`src/flex/colors/` may import `src/color-lib/`, but `src/color-lib/` imports only its own modules and shared types. -Production code never imports `src/test/`. Source paths are private: consumers use the package subpaths in -`entry-points.md`, never `src/` or `lib/` paths. +Shared modules may import types from either model. At runtime, only the `theming` facade, the `themes` entry, and the +legacy subpaths reach `src/fluent/`; the root and `styling` graphs may reach `src/flex/` but never `src/fluent/`. +Dependencies point one way: `src/flex/colors/` may import `src/color-lib/`, but `src/color-lib/` imports only its own +modules and shared types. Production code never imports `src/test/`. Source paths are private: consumers use the package +subpaths in `entry-points.md`, never `src/` or `lib/` paths. The package's scripts directory holds `codegen.cts`, which runs before every build, the token-mapping check and upstream drift tools, and the x3 defaults generator, all described in `tokens.md`. Generated token, projection, and @@ -45,6 +46,11 @@ default files are committed; change their inputs and regenerate rather than edit `src/flex/` or `src/color-lib/`, and the Theme-to-Flex adapter in `src/flex/adapters/` must not reach the interaction policy, the x3 defaults, or `src/color-lib/`. `src/test/compatibility/importBoundaries.test.ts` checks these graphs; run the bundle-size scenarios too when changing imports between these areas. +- Keep `src/themes/` a consumer of the generated Fluent 2 and global tokens: it may reach `ThemeReference`, the + generated Fluent tokens, and the generated global tokens, but never `src/flex/`, `src/color-lib/`, `useTheme`, + `src/fluent/compat/`, or the legacy token payloads, and it authors no color value that the generated alias colors lack. + `src/themes/fluent/fluentThemes.test.tsx`, the import-boundary test, and the `design-fluent-*` bundle-size scenarios + guard this. - Never mutate author-owned theme inputs; caches are external and keyed by source, revision, and resolved appearance. - Keep color resolution lazy: resolving tokens, reading rest, merging, and copying the color map must not run the interaction algorithm, and a derived state computes at most once per resolved color. `flex-colors.md` owns the color diff --git a/packages/agentic/design/references/entry-points.md b/packages/agentic/design/references/entry-points.md index a74bf7827f..90f892e4c8 100644 --- a/packages/agentic/design/references/entry-points.md +++ b/packages/agentic/design/references/entry-points.md @@ -17,6 +17,7 @@ public symbols by name from each entry point; do not add barrel re-exports. | `./theming/legacy-source` | `ThemeReference` without the legacy consumption graph | | `./theming/compat` | `themeFromFlexTokens` and `getDefaultLegacyTheme` | | `./theming/compat/defaults` | `getDefaultLegacyTheme` alone, for platform theme packages | +| `./themes` | Ready-made Fluent themes: `fluentLightTheme`, `fluentDarkTheme`, and `fluentTheme` | | `./tokens/global` | Generated platform global token constants | | `./tokens/legacy` | Legacy alias, shadow, and global token data | | `./color-lib` | Raw color parsing, conversion, compositing, and interaction algorithms; see `color-lib.md` | @@ -30,9 +31,11 @@ patterns check the modules a tree-shaken bundle retains. The modern root and leg compatibility and legacy-token modules and `color-lib/compositing`. The modern root scenarios and the legacy-source scenario, which pairs a legacy `ThemeReference` with `useThemeState`, require the retained Flex interaction policy and `color-lib/interaction`; the legacy-source scenario also forbids a retained `FlexThemeReference`. Only the legacy theme -scenario forbids any retained `color-lib/` or `flex/` module. The color-library and legacy-projection scenarios require -their expected modules. Every scenario -also requires a module it is expected to load, so a moved file cannot make a forbidden pattern pass vacuously. +scenario forbids any retained `color-lib/` or `flex/` module. The Fluent theme scenarios forbid `flex/`, `color-lib/`, +`useTheme`, and the compatibility and legacy-token modules from the import graph, and a bundle that imports only +`fluentLightTheme` retains neither the dark theme nor `ThemeReference`. The color-library and legacy-projection +scenarios require their expected modules. Every scenario also requires a module it is expected to load, so a moved file +cannot make a forbidden pattern pass vacuously. The package specifiers above are the supported import surface. Source and build paths such as `src/fluent/...` or `lib/...` are private implementation details that may move without a breaking change. diff --git a/packages/agentic/design/references/remaining-work.md b/packages/agentic/design/references/remaining-work.md index 7edc927068..49bc929f61 100644 --- a/packages/agentic/design/references/remaining-work.md +++ b/packages/agentic/design/references/remaining-work.md @@ -71,6 +71,22 @@ behavior is documented in `theming.md`, `tokens.md`, and `entry-points.md`. repository's user documentation covers `ThemedRoot` but still teaches custom themes only through `ThemeReference`. - **Done when:** the user documentation includes the migration example and links to this package's theming reference. +## Fluent high-contrast and elevated themes + +- **Outcome:** `fluentTheme` selects distinct themes for high-contrast and elevated appearances. +- **Current state:** `themes` exports only the light and dark Fluent themes. The generated Fluent tokens already supply + the `hc`, `hcLight`, `hcDark`, `darkGray`, and `darkElevated` color and shadow sets (`tokens.md`), but `fluentTheme` + resolves high-contrast and elevated requests by color scheme alone. +- **Done when:** the owner approves how each appearance maps to those sets, including iOS, whose high-contrast files + carry no colors, and `fluentTheme` selects the matching theme by the resolved appearance. + +## Flex themes + +- **Outcome:** the `themes` entry point also exposes ready-made Flex themes beside the Fluent themes. +- **Current state:** `themes` exports only Fluent themes, authored as legacy `Theme` objects. +- **Done when:** the owner defines the Flex theme set and its exports, and `theming.md` and `entry-points.md` document + them. + ## Dependent work owned by other packages - `@fluentui-react-native/apple-theme` still authors a legacy `Theme`; diff --git a/packages/agentic/design/references/theming.md b/packages/agentic/design/references/theming.md index c566708ecd..ac3eaf026f 100644 --- a/packages/agentic/design/references/theming.md +++ b/packages/agentic/design/references/theming.md @@ -7,6 +7,7 @@ owner_paths: - packages/agentic/design/src/flex/flexThemeReference.ts - packages/agentic/design/src/flex/useThemeState.ts - packages/agentic/design/src/fluent + - packages/agentic/design/src/themes --- # Theming @@ -120,6 +121,38 @@ subscribed; create one with `createThemeAppearanceSource`. including `darkElevated`, `highContrast`, and `dynamic`. `getCurrentAppearance`, `isHighContrast`, and `setIsHighContrast` remain for existing callers. +## Fluent themes + +The `themes` entry point provides legacy `Theme` objects authored from the generated Fluent 2 tokens (`tokens.md`): + +| Export | Kind | Contents | +| ------------------ | ---------------- | ------------------------------------------------ | +| `fluentLightTheme` | `Theme` | The light theme | +| `fluentDarkTheme` | `Theme` | The dark theme | +| `fluentTheme` | `ThemeReference` | Both themes, chosen by the resolved color scheme | + +Each theme carries every platform alias color unchanged, plus the legacy palette keys (`bodyText`, `buttonBackground`, +and so on) that existing components still read. `src/themes/fluent/legacyPalette.ts` points each legacy key at the alias +color that plays the same role, so the palette adds no color values of its own, and its type is complete: a legacy key +without a mapping fails to compile. Shadows and font variants are the generated Fluent shadows and font aliases; font +families, sizes, weights, and spacing come from the global tokens. All of these are generated per platform, so each +platform's theme carries that platform's values. Fluent 2 defines no serif or cursive family, so those slots use the base +family. The themes carry no component token overrides. + +`fluentTheme` requests `system` for every appearance axis, so a `ThemeProvider` or `ThemedRoot` follows the platform +appearance source and re-resolves when the system changes; pass `appearance` to pin a color scheme. Contrast and +interface level do not select separate themes yet: high-contrast and elevated requests resolve by color scheme +(`remaining-work.md`). Import `fluentLightTheme` or `fluentDarkTheme` alone to keep the other theme and `ThemeReference` +out of a bundle, or use one as the base of your own `ThemeReference` to extend it. Flex consumers read these themes +through `useThemeState`, which adapts their alias colors like any legacy source. + +```tsx +import { ThemedRoot } from '@fluentui-react-native/design'; +import { fluentTheme } from '@fluentui-react-native/design/themes'; + +const App = () => <ThemedRoot theme={fluentTheme}>{/* scene */}</ThemedRoot>; +``` + ## Legacy projection and bundle boundary The package root exports only the modern authoring and consumption APIs. It reaches the forward Theme-to-Flex adapter, diff --git a/packages/agentic/design/references/tokens.md b/packages/agentic/design/references/tokens.md index 8f84a657e0..94be722b8a 100644 --- a/packages/agentic/design/references/tokens.md +++ b/packages/agentic/design/references/tokens.md @@ -41,8 +41,9 @@ colors and shadows vary by color scheme. The package's `prebuild` script (`codegen.cts`) generates the global token files from the platform `@fluentui-react-native/design-tokens-*` packages and regenerates both mapping projections. It also generates `src/fluent/defaults/fluentTokens.generated.ts` (Win32) and its Windows, macOS, iOS, and Android variants. These modules -contain complete Fluent alias colors, shadows, and font aliases; nothing consumes them yet. The runtime pipeline -mappers and existing theme construction are unchanged. Do not edit generated files; change their inputs and rebuild. +contain complete Fluent alias colors, shadows, and font aliases, which the `themes` entry point consumes (`theming.md`). +The runtime pipeline mappers and existing theme construction are unchanged. Do not edit generated files; change their +inputs and rebuild. Every generated platform module exports `light`, `dark`, `darkGray`, `hc`, `hcLight`, `hcDark`, and `darkElevated` color and shadow sets, plus `fontAliasTokens`. Colors satisfy `Required<AliasColorTokens>` (including deprecated red diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap index 426e07fedd..67ecfdd733 100644 --- a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap @@ -98,6 +98,14 @@ exports[`public entry points ./testing keeps its runtime export names 1`] = ` ] `; +exports[`public entry points ./themes keeps its runtime export names 1`] = ` +[ + "fluentDarkTheme: object", + "fluentLightTheme: object", + "fluentTheme: object", +] +`; + exports[`public entry points ./theming keeps its runtime export names 1`] = ` [ "FlexThemeReference: function", diff --git a/packages/agentic/design/src/test/compatibility/entryPoints.test.ts b/packages/agentic/design/src/test/compatibility/entryPoints.test.ts index febe565024..0e91f91e56 100644 --- a/packages/agentic/design/src/test/compatibility/entryPoints.test.ts +++ b/packages/agentic/design/src/test/compatibility/entryPoints.test.ts @@ -20,6 +20,7 @@ const publicEntryPoints = [ './theming/legacy-source', './theming/compat', './theming/compat/defaults', + './themes', './testing', './styling', './styling/stylesheet', diff --git a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts index d8962b0a4e..81ab3a50d9 100644 --- a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts +++ b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts @@ -209,6 +209,18 @@ describe('runtime graph ownership', () => { expect(reachedUnder(legacySourceGraph, 'fluent/compat/')).toEqual([]); expect(reachedUnder(legacySourceGraph, 'fluent/tokens/')).toEqual([]); }); + + it('keeps the themes entry on generated tokens and the legacy source, free of the Flex engine, projection, and payloads', () => { + const themesGraph = runtimeGraph('themes/index.ts'); + expect(themesGraph).toContain('themes/fluent/fluentTheme.ts'); + expect(themesGraph).toContain('fluent/themeReference.ts'); + expect(themesGraph).toContain('fluent/defaults/fluentTokens.generated.ts'); + expect(themesGraph).toContain('tokens/global.generated.ts'); + expect(themesGraph).not.toContain('fluent/useTheme.ts'); + for (const prefix of ['flex/', 'color-lib/', 'test/', 'fluent/compat/', 'fluent/tokens/']) { + expect([prefix, reachedUnder(themesGraph, prefix)]).toEqual([prefix, []]); + } + }); }); describe('shared types', () => { diff --git a/packages/agentic/design/src/themes/fluent/createFluentTheme.ts b/packages/agentic/design/src/themes/fluent/createFluentTheme.ts new file mode 100644 index 0000000000..84e9f9f8e3 --- /dev/null +++ b/packages/agentic/design/src/themes/fluent/createFluentTheme.ts @@ -0,0 +1,77 @@ +import { fontAliasTokens } from '../../fluent/defaults/fluentTokens.generated'; +import type { AliasColorTokens } from '../../fluent/types/Color.types'; +import type { BaseShadowAliasTokens } from '../../fluent/types/Shadow.types'; +import type { Spacing, Theme } from '../../fluent/types/Theme.types'; +import { + fontFamilyBase, + fontFamilyMonospace, + fontFamilyNumeric, + fontSize100, + fontSize200, + fontSize300, + fontSize400, + fontSize500, + fontSize700, + fontSize900, + fontWeightRegular, + fontWeightSemibold, + size160, + size200, + size320, + size40, + size80, +} from '../../tokens/global.generated'; +import { legacyPaletteFromAliasColors } from './legacyPalette'; + +/** + * Assemble a complete legacy `Theme` from Fluent 2 tokens. The theme is a view over the generated alias colors, + * shadows and font variants plus global tokens, so nothing here is a hand-picked value. Appearance data is a + * parameter so that bundlers can drop the appearance a consumer never imports. + */ +export function createFluentTheme( + appearance: 'light' | 'dark', + aliasColors: Required<AliasColorTokens>, + shadows: BaseShadowAliasTokens, +): Theme { + const spacing: Spacing = { + s2: `${size40}px`, + s1: `${size80}px`, + m: `${size160}px`, + l1: `${size200}px`, + l2: `${size320}px`, + }; + + return { + colors: { ...aliasColors, ...legacyPaletteFromAliasColors(aliasColors) }, + typography: { + // Fluent 2 defines no serif or cursive family, so those slots use the base family + families: { + primary: fontFamilyBase, + secondary: fontFamilyBase, + cursive: fontFamilyBase, + monospace: fontFamilyMonospace, + numeric: fontFamilyNumeric, + sansSerif: fontFamilyBase, + serif: fontFamilyBase, + }, + sizes: { + caption: fontSize100, + secondary: fontSize200, + body: fontSize300, + subheader: fontSize400, + header: fontSize500, + hero: fontSize700, + heroLarge: fontSize900, + }, + weights: { + regular: fontWeightRegular, + semiBold: fontWeightSemibold, + }, + variants: fontAliasTokens, + }, + components: {}, + shadows: { ...shadows }, + spacing, + host: { appearance }, + }; +} diff --git a/packages/agentic/design/src/themes/fluent/fluentDarkTheme.ts b/packages/agentic/design/src/themes/fluent/fluentDarkTheme.ts new file mode 100644 index 0000000000..6d997fc485 --- /dev/null +++ b/packages/agentic/design/src/themes/fluent/fluentDarkTheme.ts @@ -0,0 +1,8 @@ +import { darkAliasColors, darkShadows } from '../../fluent/defaults/fluentTokens.generated'; +import type { Theme } from '../../fluent/types/Theme.types'; +import { createFluentTheme } from './createFluentTheme'; + +/** + * The Fluent dark theme, built from Fluent 2 alias and global tokens. + */ +export const fluentDarkTheme: Theme = /* @__PURE__ */ createFluentTheme('dark', darkAliasColors, darkShadows); diff --git a/packages/agentic/design/src/themes/fluent/fluentLightTheme.ts b/packages/agentic/design/src/themes/fluent/fluentLightTheme.ts new file mode 100644 index 0000000000..3ffb1bef34 --- /dev/null +++ b/packages/agentic/design/src/themes/fluent/fluentLightTheme.ts @@ -0,0 +1,8 @@ +import { lightAliasColors, lightShadows } from '../../fluent/defaults/fluentTokens.generated'; +import type { Theme } from '../../fluent/types/Theme.types'; +import { createFluentTheme } from './createFluentTheme'; + +/** + * The Fluent light theme, built from Fluent 2 alias and global tokens. + */ +export const fluentLightTheme: Theme = /* @__PURE__ */ createFluentTheme('light', lightAliasColors, lightShadows); diff --git a/packages/agentic/design/src/themes/fluent/fluentTheme.ts b/packages/agentic/design/src/themes/fluent/fluentTheme.ts new file mode 100644 index 0000000000..5803ff9c91 --- /dev/null +++ b/packages/agentic/design/src/themes/fluent/fluentTheme.ts @@ -0,0 +1,15 @@ +import { ThemeReference } from '../../fluent/themeReference'; +import type { Theme } from '../../fluent/types/Theme.types'; +import { fluentDarkTheme } from './fluentDarkTheme'; +import { fluentLightTheme } from './fluentLightTheme'; + +/** + * Theme source holding both Fluent themes. It follows the system appearance reported by the React Native `Appearance` + * module, and a `ThemeProvider` or `ThemedRoot` `appearance` prop overrides it. High contrast and elevated system + * settings resolve by color scheme until those Fluent themes exist. + */ +export const fluentTheme: ThemeReference = /* @__PURE__ */ new ThemeReference({ + base: {} as Theme, + appearance: { colorScheme: 'system', contrast: 'system', interfaceLevel: 'system' }, + recipes: [(_parent, appearance) => (appearance?.colorScheme === 'dark' ? fluentDarkTheme : fluentLightTheme)], +}); diff --git a/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx b/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx new file mode 100644 index 0000000000..1fbd6a9e36 --- /dev/null +++ b/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx @@ -0,0 +1,174 @@ +import { isDeepStrictEqual } from 'node:util'; + +import { Appearance } from 'react-native'; + +import { act, create } from 'react-test-renderer'; + +import { getDefaultLegacyTheme } from '../../fluent/compat/defaultLegacyTheme'; +import { + darkAliasColors, + darkShadows, + fontAliasTokens, + lightAliasColors, + lightShadows, +} from '../../fluent/defaults/fluentTokens.generated'; +import type { Theme } from '../../fluent/types/Theme.types'; +import { useTheme } from '../../fluent/useTheme'; +import { useThemeState } from '../../flex/useThemeState'; +import { ThemedRoot } from '../../theming/ThemedRoot'; +import { ThemeProvider } from '../../theming/ThemeProvider'; +import type { ThemeAppearanceSource, ThemeAppearanceSourceSnapshot } from '../../types/appearance.types'; +import { fluentDarkTheme, fluentLightTheme, fluentTheme } from '../index'; + +const themes = [ + ['light', fluentLightTheme, lightAliasColors, lightShadows], + ['dark', fluentDarkTheme, darkAliasColors, darkShadows], +] as const; + +function undefinedPaths(value: unknown, path = 'theme'): string[] { + if (value === undefined) { + return [path]; + } + if (typeof value !== 'object' || value === null) { + return []; + } + return Object.entries(value).flatMap(([key, child]) => undefinedPaths(child, `${path}.${key}`)); +} + +function createAppearanceSource(initial: ThemeAppearanceSourceSnapshot) { + let snapshot = initial; + const listeners = new Set<() => void>(); + return { + source: { + getSnapshot: () => snapshot, + subscribe: (listener) => { + listeners.add(listener); + return () => listeners.delete(listener); + }, + } satisfies ThemeAppearanceSource, + update(next: ThemeAppearanceSourceSnapshot) { + snapshot = next; + listeners.forEach((listener) => listener()); + }, + }; +} + +function ThemeProbe({ themes: seen }: { themes: Theme[] }) { + seen.push(useTheme()); + return null; +} + +describe.each(themes)('Fluent %s theme', (appearance, theme, aliasColors, shadows) => { + it('carries every Fluent 2 alias color unchanged for its host appearance', () => { + expect(theme.host.appearance).toBe(appearance); + for (const [name, color] of Object.entries(aliasColors)) { + expect(theme.colors[name]).toBe(color); + } + }); + + it('draws every legacy palette color from the alias colors', () => { + const aliasValues = Object.values(aliasColors); + const invented = Object.entries(theme.colors) + .filter(([name]) => !(name in aliasColors)) + .filter(([, color]) => !aliasValues.some((alias) => isDeepStrictEqual(alias, color))) + .map(([name]) => name); + + expect(invented).toEqual([]); + }); + + it('takes shadows, font variants and spacing from Fluent 2 and global tokens', () => { + expect(theme.shadows).toEqual(shadows); + expect(theme.typography.variants).toBe(fontAliasTokens); + expect(theme.spacing).toEqual({ s2: '4px', s1: '8px', m: '16px', l1: '20px', l2: '32px' }); + }); + + it('defines every key the legacy default theme defines, with no undefined values', () => { + const legacy = getDefaultLegacyTheme({ colorScheme: appearance, contrast: 'standard', interfaceLevel: 'base' }); + const missing = [ + ...Object.keys(legacy.colors).filter((key) => !(key in theme.colors)), + ...Object.keys(legacy.shadows).filter((key) => !(key in theme.shadows)), + ...Object.keys(legacy.typography.families).filter((key) => !(key in theme.typography.families)), + ...Object.keys(legacy.typography.sizes).filter((key) => !(key in theme.typography.sizes)), + ...Object.keys(legacy.typography.variants).filter((key) => !(key in theme.typography.variants)), + ...Object.keys(legacy.spacing).filter((key) => !(key in theme.spacing)), + ]; + + expect(missing).toEqual([]); + expect(undefinedPaths(theme)).toEqual([]); + }); +}); + +describe('fluentTheme', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('resolves the theme for the requested color scheme, including high contrast and elevated requests', () => { + expect(fluentTheme.resolveTheme({ colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base' }).colors).toBe( + fluentLightTheme.colors, + ); + expect(fluentTheme.resolveTheme({ colorScheme: 'dark', contrast: 'standard', interfaceLevel: 'base' }).colors).toBe( + fluentDarkTheme.colors, + ); + expect(fluentTheme.resolveTheme({ colorScheme: 'dark', contrast: 'highContrast', interfaceLevel: 'elevated' }).host.appearance).toBe( + 'dark', + ); + }); + + it('follows the system color scheme from the Appearance module', () => { + const colorScheme = jest.spyOn(Appearance, 'getColorScheme'); + + colorScheme.mockReturnValue('dark'); + expect(fluentTheme.theme).toBe(fluentDarkTheme); + colorScheme.mockReturnValue('light'); + expect(fluentTheme.theme).toBe(fluentLightTheme); + }); + + it('drives a ThemeProvider from the system appearance until an appearance prop overrides it', () => { + const appearance = createAppearanceSource({ colorScheme: 'light' }); + const seen: Theme[] = []; + const render = (appearanceProp?: { colorScheme: 'light' | 'dark' }) => ( + <ThemeProvider theme={fluentTheme} appearanceSource={appearance.source} appearance={appearanceProp}> + <ThemeProbe themes={seen} /> + </ThemeProvider> + ); + let component!: ReturnType<typeof create>; + + act(() => { + component = create(render()); + }); + expect(seen.at(-1)?.colors).toBe(fluentLightTheme.colors); + + act(() => appearance.update({ colorScheme: 'dark' })); + expect(seen.at(-1)?.colors).toBe(fluentDarkTheme.colors); + + act(() => component.update(render({ colorScheme: 'light' }))); + expect(seen.at(-1)?.colors).toBe(fluentLightTheme.colors); + + act(() => component.unmount()); + }); + + it('feeds Flex consumers under a ThemedRoot from its alias colors', () => { + const appearance = createAppearanceSource({ colorScheme: 'dark' }); + const seen: unknown[] = []; + const Probe = () => { + seen.push(useThemeState().tokens.color.foregroundNeutralPrimary.rest); + return null; + }; + let component!: ReturnType<typeof create>; + + act(() => { + component = create( + <ThemedRoot theme={fluentTheme} appearanceSource={appearance.source}> + <Probe /> + </ThemedRoot>, + ); + }); + expect(seen.at(-1)).toBe(darkAliasColors.neutralForeground1); + + act(() => appearance.update({ colorScheme: 'light' })); + expect(seen.at(-1)).toBe(lightAliasColors.neutralForeground1); + + act(() => component.unmount()); + }); +}); diff --git a/packages/agentic/design/src/themes/fluent/legacyPalette.ts b/packages/agentic/design/src/themes/fluent/legacyPalette.ts new file mode 100644 index 0000000000..95ff24b9a4 --- /dev/null +++ b/packages/agentic/design/src/themes/fluent/legacyPalette.ts @@ -0,0 +1,154 @@ +import type { AliasColorTokens, ControlColorTokens, PaletteBackgroundColors, PaletteTextColors } from '../../fluent/types/Color.types'; + +/** + * The legacy palette keys that every legacy `Theme` must define. + */ +export type LegacyPalette = PaletteTextColors & PaletteBackgroundColors & ControlColorTokens; + +/** + * Derive the legacy palette from Fluent 2 alias colors. Each legacy name points at the alias token the Fluent 2 + * components use for the same role, so the palette adds no color values of its own. The result is typed as complete, + * so a legacy key without a mapping fails to compile. + */ +export function legacyPaletteFromAliasColors(a: Required<AliasColorTokens>): LegacyPalette { + return { + // Text + bodyText: a.neutralForeground1, + bodyTextChecked: a.neutralForeground1Selected, + subText: a.neutralForeground2, + actionLink: a.neutralForeground1, + link: a.brandForegroundLink, + linkHovered: a.brandForegroundLinkHover, + linkPressed: a.brandForegroundLinkPressed, + disabledText: a.neutralForegroundDisabled, + disabledBodyText: a.neutralForegroundDisabled, + errorText: a.dangerForeground1, + inputText: a.neutralForeground1, + inputPlaceholderText: a.neutralForeground4, + buttonText: a.neutralForeground1, + buttonTextHovered: a.neutralForeground1Hover, + buttonTextChecked: a.neutralForeground1Selected, + buttonTextPressed: a.neutralForeground1Pressed, + buttonTextDisabled: a.neutralForegroundDisabled, + primaryButtonText: a.neutralForegroundOnBrand, + primaryButtonTextHovered: a.neutralForegroundOnBrandHover, + primaryButtonTextPressed: a.neutralForegroundOnBrandPressed, + primaryButtonTextDisabled: a.neutralForegroundDisabled, + + // Backgrounds, borders and dividers + background: a.neutralBackground1, + bodyStandoutBackground: a.neutralBackground2, + bodyFrameBackground: a.neutralBackground1, + bodyFrameDivider: a.neutralStroke2, + bodyDivider: a.neutralStroke2, + disabledBackground: a.neutralBackgroundDisabled, + focusBorder: a.strokeFocus2, + variantBorder: a.neutralStroke2, + inputBorder: a.neutralStroke1, + inputBackground: a.neutralBackground1, + inputFocusBorderAlt: a.compoundBrandStroke1, + buttonBackground: a.neutralBackground1, + buttonBackgroundChecked: a.neutralBackground1Selected, + buttonBackgroundHovered: a.neutralBackground1Hover, + buttonBackgroundDisabled: a.neutralBackgroundDisabled, + buttonBackgroundPressed: a.neutralBackground1Pressed, + buttonBorder: a.neutralStroke1, + buttonBorderFocused: a.strokeFocus2, + buttonBorderDisabled: a.neutralStrokeDisabled, + primaryButtonBackground: a.brandBackground, + primaryButtonBackgroundHovered: a.brandBackgroundHover, + primaryButtonBackgroundPressed: a.brandBackgroundPressed, + primaryButtonBackgroundDisabled: a.neutralBackgroundDisabled, + primaryButtonBorder: a.transparentStroke, + primaryButtonBorderFocused: a.strokeFocus2, + accentButtonBackground: a.brandBackground, + menuBackground: a.neutralBackground1, + menuDivider: a.neutralStroke2, + menuIcon: a.neutralForeground2, + menuItemBackgroundHovered: a.neutralBackground1Hover, + menuItemBackgroundPressed: a.neutralBackground1Pressed, + menuItemText: a.neutralForeground1, + menuItemTextHovered: a.neutralForeground1Hover, + listHeaderBackgroundHovered: a.neutralBackground1Hover, + listHeaderBackgroundPressed: a.neutralBackground1Pressed, + + // Default control. Focus keeps the hover fill and content with the focus stroke, as the Fluent 2 Button does. + defaultBackground: a.neutralBackground1, + defaultBorder: a.neutralStroke1, + defaultContent: a.neutralForeground1, + defaultIcon: a.neutralForeground1, + defaultHoveredBackground: a.neutralBackground1Hover, + defaultHoveredBorder: a.neutralStroke1Hover, + defaultHoveredContent: a.neutralForeground1Hover, + defaultHoveredIcon: a.neutralForeground1Hover, + defaultFocusedBackground: a.neutralBackground1Hover, + defaultFocusedBorder: a.strokeFocus2, + defaultFocusedContent: a.neutralForeground1Hover, + defaultFocusedIcon: a.neutralForeground1Hover, + defaultPressedBackground: a.neutralBackground1Pressed, + defaultPressedBorder: a.neutralStroke1Pressed, + defaultPressedContent: a.neutralForeground1Pressed, + defaultPressedIcon: a.neutralForeground1Pressed, + defaultDisabledBackground: a.neutralBackgroundDisabled, + defaultDisabledBorder: a.neutralStrokeDisabled, + defaultDisabledContent: a.neutralForegroundDisabled, + defaultDisabledIcon: a.neutralForegroundDisabled, + + // Ghost control, the Fluent 2 subtle appearance + ghostBackground: a.subtleBackground, + ghostBorder: a.transparentStroke, + ghostContent: a.neutralForeground1, + ghostIcon: a.neutralForeground1, + ghostHoveredBackground: a.subtleBackgroundHover, + ghostHoveredBorder: a.transparentStroke, + ghostHoveredContent: a.neutralForeground1Hover, + ghostHoveredIcon: a.neutralForeground1Hover, + ghostFocusedBackground: a.subtleBackgroundHover, + ghostFocusedBorder: a.strokeFocus2, + ghostFocusedContent: a.neutralForeground1Hover, + ghostFocusedIcon: a.neutralForeground1Hover, + ghostPressedBackground: a.subtleBackgroundPressed, + ghostPressedBorder: a.transparentStroke, + ghostPressedContent: a.neutralForeground1Pressed, + ghostPressedIcon: a.neutralForeground1Pressed, + ghostDisabledBackground: a.subtleBackground, + ghostDisabledBorder: a.transparentStrokeDisabled, + ghostDisabledContent: a.neutralForegroundDisabled, + ghostDisabledIcon: a.neutralForegroundDisabled, + + // Branded control + brandedBackground: a.brandBackground, + brandedDisabledBorder: a.transparentStrokeDisabled, + brandedSecondaryContent: a.neutralForegroundOnBrand, + brandedFocusedSecondaryContent: a.neutralForegroundOnBrandHover, + brandedHoveredSecondaryContent: a.neutralForegroundOnBrandHover, + brandedPressedSecondaryContent: a.neutralForegroundOnBrandPressed, + + // Checked control + defaultCheckedBackground: a.neutralBackground1Selected, + defaultCheckedContent: a.neutralForeground1Selected, + defaultCheckedHoveredBackground: a.neutralBackground1Hover, + defaultCheckedHoveredContent: a.neutralForeground1Hover, + ghostCheckedBackground: a.subtleBackgroundSelected, + ghostCheckedContent: a.neutralForeground2Selected, + ghostCheckedHoveredBackground: a.subtleBackgroundHover, + ghostCheckedHoveredContent: a.neutralForeground2Hover, + ghostCheckedHoveredBorder: a.transparentStroke, + + // Secondary content + ghostSecondaryContent: a.neutralForeground3, + ghostFocusedSecondaryContent: a.neutralForeground3, + ghostHoveredSecondaryContent: a.neutralForeground3Hover, + ghostPressedSecondaryContent: a.neutralForeground3Pressed, + defaultHoveredSecondaryContent: a.neutralForeground3Hover, + defaultPressedSecondaryContent: a.neutralForeground3Pressed, + + // Checkbox and persona + checkboxBackground: a.compoundBrandBackground1, + checkboxBackgroundDisabled: a.neutralBackgroundDisabled, + checkmarkColor: a.neutralForegroundOnBrand, + checkboxBorderColor: a.neutralStrokeAccessible, + personaActivityRing: a.neutralBackground1, + personaActivityGlow: a.brandBackground, + }; +} diff --git a/packages/agentic/design/src/themes/index.ts b/packages/agentic/design/src/themes/index.ts new file mode 100644 index 0000000000..781e1ab380 --- /dev/null +++ b/packages/agentic/design/src/themes/index.ts @@ -0,0 +1,3 @@ +export { fluentDarkTheme } from './fluent/fluentDarkTheme'; +export { fluentLightTheme } from './fluent/fluentLightTheme'; +export { fluentTheme } from './fluent/fluentTheme'; From 7250e7d054af3f58996d0136925c07e81bfe4af5 Mon Sep 17 00:00:00 2001 From: Jason Morse <jasonmo360@gmail.com> Date: Fri, 30 Oct 2026 16:30:18 -0700 Subject: [PATCH 14/18] add flex theme definitions --- .changeset/design-flex-themes.md | 9 ++ apps/bundle-size/baseline.json | 132 +++++++++++++----- apps/bundle-size/scenarios.json | 44 +++++- packages/agentic/design/AGENTS.md | 4 +- packages/agentic/design/README.md | 15 +- .../agentic/design/references/contributing.md | 15 +- .../agentic/design/references/entry-points.md | 41 +++--- .../agentic/design/references/flex-colors.md | 3 +- .../design/references/remaining-work.md | 9 +- packages/agentic/design/references/theming.md | 27 ++++ packages/agentic/design/references/tokens.md | 3 +- .../src/flex/flexThemeReference.test.ts | 27 ++++ .../design/src/flex/flexThemeReference.ts | 24 +++- .../src/flex/styling/colorStyles.test.ts | 2 +- .../design/src/flex/styling/colorStyles.ts | 2 +- .../agentic/design/src/flex/themeState.ts | 2 +- .../src/{types => flex}/themeState.types.ts | 22 ++- .../design/src/flex/useThemeState.test.ts | 2 +- .../agentic/design/src/flex/useThemeState.ts | 2 +- .../design/src/fluent/useTheme.test.ts | 2 +- packages/agentic/design/src/index.ts | 3 +- .../design/src/styling/branchedStyle.test.ts | 2 +- .../design/src/styling/branchedStyle.ts | 2 +- .../__snapshots__/entryPoints.test.ts.snap | 2 + .../compatibility/importBoundaries.test.ts | 33 ++++- .../design/src/themes/flex/flexTheme.ts | 7 + .../src/themes/flex/flexThemes.test.tsx | 50 +++++++ .../design/src/themes/flex/flexWarmTheme.ts | 7 + packages/agentic/design/src/themes/index.ts | 2 + .../design/src/theming/ThemedRoot.test.tsx | 2 +- packages/agentic/design/src/theming/index.ts | 1 + packages/agentic/design/src/theming/modern.ts | 1 + .../design/src/theming/themeRuntime.ts | 2 +- 33 files changed, 396 insertions(+), 105 deletions(-) create mode 100644 .changeset/design-flex-themes.md rename packages/agentic/design/src/{types => flex}/themeState.types.ts (53%) create mode 100644 packages/agentic/design/src/themes/flex/flexTheme.ts create mode 100644 packages/agentic/design/src/themes/flex/flexThemes.test.tsx create mode 100644 packages/agentic/design/src/themes/flex/flexWarmTheme.ts diff --git a/.changeset/design-flex-themes.md b/.changeset/design-flex-themes.md new file mode 100644 index 0000000000..7ec17705cc --- /dev/null +++ b/.changeset/design-flex-themes.md @@ -0,0 +1,9 @@ +--- +'@fluentui-react-native/design': minor +--- + +Add `flexTheme` and `flexWarmTheme` to the `@fluentui-react-native/design/themes` entry point. Each is a new +`FlexThemeDescription`, which pairs a complete Flex token description with an optional `ColorTone`, holding the cool or +warm x3 defaults. `FlexThemeReference` now accepts a `FlexThemeDescription` as its `base`: the description replaces the +package defaults, and its tone becomes the reference's default `appearance.colorTone` unless the `appearance` option or +a provider request sets one. The `ThemeState` types now live with the Flex model; their exports are unchanged. diff --git a/apps/bundle-size/baseline.json b/apps/bundle-size/baseline.json index 9207fb10a6..1740950033 100644 --- a/apps/bundle-size/baseline.json +++ b/apps/bundle-size/baseline.json @@ -42,8 +42,8 @@ { "platform": "macos", "scenario": "design-theme-state", - "rawBytes": 53052, - "gzipBytes": 14104, + "rawBytes": 53271, + "gzipBytes": 14189, "moduleCount": 47, "metafileInputCount": 73, "workspaceModules": { @@ -51,15 +51,15 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 51047, + "@fluentui-react-native/design": 51266, "@fluentui-react-native/framework-base": 1964 } }, { "platform": "macos", "scenario": "design-themed-root", - "rawBytes": 55039, - "gzipBytes": 14785, + "rawBytes": 55262, + "gzipBytes": 14869, "moduleCount": 51, "metafileInputCount": 73, "workspaceModules": { @@ -67,7 +67,7 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 53033, + "@fluentui-react-native/design": 53256, "@fluentui-react-native/framework-base": 1964 } }, @@ -120,8 +120,8 @@ { "platform": "macos", "scenario": "design-legacy-theme-from-flex", - "rawBytes": 99614, - "gzipBytes": 24350, + "rawBytes": 99833, + "gzipBytes": 24406, "moduleCount": 67, "metafileInputCount": 93, "workspaceModules": { @@ -129,38 +129,70 @@ "@fluentui-react-native/framework-base": 21 }, "workspaceBytes": { - "@fluentui-react-native/design": 60396, + "@fluentui-react-native/design": 60615, "@fluentui-react-native/framework-base": 2527 } }, { "platform": "macos", "scenario": "design-fluent-light-theme", - "rawBytes": 18739, - "gzipBytes": 4006, + "rawBytes": 18743, + "gzipBytes": 4010, "moduleCount": 7, - "metafileInputCount": 50, + "metafileInputCount": 64, "workspaceModules": { "@fluentui-react-native/design": 6 }, "workspaceBytes": { - "@fluentui-react-native/design": 18703 + "@fluentui-react-native/design": 18707 } }, { "platform": "macos", "scenario": "design-fluent-theme", - "rawBytes": 27300, - "gzipBytes": 6643, + "rawBytes": 27314, + "gzipBytes": 6684, "moduleCount": 32, - "metafileInputCount": 50, + "metafileInputCount": 64, "workspaceModules": { "@fluentui-react-native/design": 13, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 25287, - "@fluentui-react-native/framework-base": 1977 + "@fluentui-react-native/design": 25306, + "@fluentui-react-native/framework-base": 1972 + } + }, + { + "platform": "macos", + "scenario": "design-flex-theme", + "rawBytes": 23368, + "gzipBytes": 8032, + "moduleCount": 33, + "metafileInputCount": 64, + "workspaceModules": { + "@fluentui-react-native/design": 16, + "@fluentui-react-native/framework-base": 16 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 22632, + "@fluentui-react-native/framework-base": 700 + } + }, + { + "platform": "macos", + "scenario": "design-flex-warm-theme", + "rawBytes": 23432, + "gzipBytes": 8064, + "moduleCount": 33, + "metafileInputCount": 64, + "workspaceModules": { + "@fluentui-react-native/design": 16, + "@fluentui-react-native/framework-base": 16 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 22696, + "@fluentui-react-native/framework-base": 700 } }, { @@ -204,8 +236,8 @@ { "platform": "windows", "scenario": "design-theme-state", - "rawBytes": 52976, - "gzipBytes": 14063, + "rawBytes": 53195, + "gzipBytes": 14148, "moduleCount": 48, "metafileInputCount": 74, "workspaceModules": { @@ -213,15 +245,15 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 50971, + "@fluentui-react-native/design": 51190, "@fluentui-react-native/framework-base": 1964 } }, { "platform": "windows", "scenario": "design-themed-root", - "rawBytes": 54963, - "gzipBytes": 14740, + "rawBytes": 55186, + "gzipBytes": 14822, "moduleCount": 52, "metafileInputCount": 74, "workspaceModules": { @@ -229,7 +261,7 @@ "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 52957, + "@fluentui-react-native/design": 53180, "@fluentui-react-native/framework-base": 1964 } }, @@ -282,8 +314,8 @@ { "platform": "windows", "scenario": "design-legacy-theme-from-flex", - "rawBytes": 99477, - "gzipBytes": 24271, + "rawBytes": 99696, + "gzipBytes": 24337, "moduleCount": 67, "metafileInputCount": 94, "workspaceModules": { @@ -291,7 +323,7 @@ "@fluentui-react-native/framework-base": 21 }, "workspaceBytes": { - "@fluentui-react-native/design": 60259, + "@fluentui-react-native/design": 60478, "@fluentui-react-native/framework-base": 2527 } }, @@ -299,9 +331,9 @@ "platform": "windows", "scenario": "design-fluent-light-theme", "rawBytes": 17820, - "gzipBytes": 3840, + "gzipBytes": 3849, "moduleCount": 7, - "metafileInputCount": 51, + "metafileInputCount": 65, "workspaceModules": { "@fluentui-react-native/design": 6 }, @@ -312,17 +344,49 @@ { "platform": "windows", "scenario": "design-fluent-theme", - "rawBytes": 26312, - "gzipBytes": 6457, + "rawBytes": 26332, + "gzipBytes": 6479, "moduleCount": 32, - "metafileInputCount": 51, + "metafileInputCount": 65, "workspaceModules": { "@fluentui-react-native/design": 13, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 24299, - "@fluentui-react-native/framework-base": 1977 + "@fluentui-react-native/design": 24324, + "@fluentui-react-native/framework-base": 1972 + } + }, + { + "platform": "windows", + "scenario": "design-flex-theme", + "rawBytes": 23356, + "gzipBytes": 8025, + "moduleCount": 33, + "metafileInputCount": 65, + "workspaceModules": { + "@fluentui-react-native/design": 16, + "@fluentui-react-native/framework-base": 16 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 22620, + "@fluentui-react-native/framework-base": 700 + } + }, + { + "platform": "windows", + "scenario": "design-flex-warm-theme", + "rawBytes": 23420, + "gzipBytes": 8058, + "moduleCount": 33, + "metafileInputCount": 65, + "workspaceModules": { + "@fluentui-react-native/design": 16, + "@fluentui-react-native/framework-base": 16 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 22684, + "@fluentui-react-native/framework-base": 700 } } ] diff --git a/apps/bundle-size/scenarios.json b/apps/bundle-size/scenarios.json index 6ed7e62d8e..8047be37f0 100644 --- a/apps/bundle-size/scenarios.json +++ b/apps/bundle-size/scenarios.json @@ -83,18 +83,19 @@ "module": "@fluentui-react-native/design/themes", "exports": ["fluentLightTheme"], "forbiddenInputPatterns": [ - "/design/src/flex/", "/design/src/fluent/compat/", "/design/src/fluent/tokens/", "/design/src/fluent/useTheme.", - "/design/src/test/", - "/color-lib/" + "/design/src/test/" ], "requiredInputPatterns": ["/design/src/themes/fluent/legacyPalette.", "/design/src/fluent/defaults/fluentTokens.generated."], "forbiddenOutputPatterns": [ "/design/src/themes/fluent/fluentDarkTheme.", "/design/src/themes/fluent/fluentTheme.", - "/design/src/fluent/themeReference." + "/design/src/fluent/themeReference.", + "/design/src/flex/", + "/design/src/themes/flex/", + "/color-lib/" ], "requiredOutputPatterns": ["/design/src/themes/fluent/fluentLightTheme.", "/design/src/themes/fluent/legacyPalette."] }, @@ -103,19 +104,48 @@ "module": "@fluentui-react-native/design/themes", "exports": ["fluentTheme"], "forbiddenInputPatterns": [ - "/design/src/flex/", "/design/src/fluent/compat/", "/design/src/fluent/tokens/", "/design/src/fluent/useTheme.", - "/design/src/test/", - "/color-lib/" + "/design/src/test/" ], + "forbiddenOutputPatterns": ["/design/src/flex/", "/design/src/themes/flex/", "/color-lib/"], "requiredOutputPatterns": [ "/design/src/themes/fluent/fluentTheme.", "/design/src/themes/fluent/fluentLightTheme.", "/design/src/themes/fluent/fluentDarkTheme.", "/design/src/fluent/themeReference." ] + }, + { + "name": "design-flex-theme", + "module": "@fluentui-react-native/design/themes", + "exports": ["flexTheme"], + "forbiddenInputPatterns": [ + "/design/src/fluent/compat/", + "/design/src/fluent/tokens/", + "/design/src/fluent/useTheme.", + "/design/src/test/", + "/color-lib/compositing." + ], + "requiredInputPatterns": ["/design/src/flex/defaults/defaultTokens.generated."], + "forbiddenOutputPatterns": ["/design/src/fluent/", "/design/src/themes/fluent/", "/design/src/themes/flex/flexWarmTheme."], + "requiredOutputPatterns": ["/design/src/themes/flex/flexTheme.", "/design/src/flex/defaults/defaultTokens.generated."] + }, + { + "name": "design-flex-warm-theme", + "module": "@fluentui-react-native/design/themes", + "exports": ["flexWarmTheme"], + "forbiddenInputPatterns": [ + "/design/src/fluent/compat/", + "/design/src/fluent/tokens/", + "/design/src/fluent/useTheme.", + "/design/src/test/", + "/color-lib/compositing." + ], + "requiredInputPatterns": ["/design/src/flex/defaults/defaultTokens.generated."], + "forbiddenOutputPatterns": ["/design/src/fluent/", "/design/src/themes/fluent/", "/design/src/themes/flex/flexTheme."], + "requiredOutputPatterns": ["/design/src/themes/flex/flexWarmTheme.", "/design/src/flex/defaults/defaultTokens.generated."] } ] } diff --git a/packages/agentic/design/AGENTS.md b/packages/agentic/design/AGENTS.md index acdd835206..32bcdf67c3 100644 --- a/packages/agentic/design/AGENTS.md +++ b/packages/agentic/design/AGENTS.md @@ -1,8 +1,8 @@ # Design agent instructions This is the instruction root for `@fluentui-react-native/design` and every descendant. The package owns Fluent UI React -Native's theming contract: theme sources and providers, ready-made Fluent themes, structured appearance, Flex and legacy -tokens, the token mappings, themed style factories, the runtime color library, and test-only design fixtures. +Native's theming contract: theme sources and providers, ready-made Fluent and Flex themes, structured appearance, Flex +and legacy tokens, the token mappings, themed style factories, the runtime color library, and test-only design fixtures. ## Start here diff --git a/packages/agentic/design/README.md b/packages/agentic/design/README.md index 915cef0834..f29a7033f8 100644 --- a/packages/agentic/design/README.md +++ b/packages/agentic/design/README.md @@ -1,8 +1,8 @@ # `@fluentui-react-native/design` Core design system concepts, utilities, and types for Fluent UI React Native: theme sources and providers, ready-made -Fluent themes, structured light, dark, high-contrast, and elevated appearance, Flex semantic tokens, themed style -factories, and an opt-in runtime color library. Legacy theme and token packages re-export their APIs from here. +Fluent and Flex themes, structured light, dark, high-contrast, and elevated appearance, Flex semantic tokens, themed +style factories, and an opt-in runtime color library. Legacy theme and token packages re-export their APIs from here. ## Quick start @@ -44,6 +44,17 @@ export const App = () => ( Use `fluentLightTheme` or `fluentDarkTheme` when you need one fixed `Theme` object. +The same entry point ships the x3 Flex defaults as `flexTheme` (cool) and `flexWarmTheme` (warm). Each is a +`FlexThemeDescription` covering light and dark; use one as a `FlexThemeReference` base to start from that palette and +tone: + +```tsx +import { FlexThemeReference } from '@fluentui-react-native/design'; +import { flexWarmTheme } from '@fluentui-react-native/design/themes'; + +const theme = new FlexThemeReference({ base: flexWarmTheme, appearance: { colorScheme: 'system' } }); +``` + ## Documentation | Topic | Covers | diff --git a/packages/agentic/design/references/contributing.md b/packages/agentic/design/references/contributing.md index c8a881e23e..f3084f15b9 100644 --- a/packages/agentic/design/references/contributing.md +++ b/packages/agentic/design/references/contributing.md @@ -11,16 +11,16 @@ owner_paths: | Path | Owns | | ---------------------- | ----------------------------------------------------------------------------------------------------------- | -| `src/types/` | Type-only contracts shared by the Flex and Fluent models, such as appearance and theme state | +| `src/types/` | Type-only contracts shared by the Flex and Fluent models, such as appearance | | `src/theming/` | Shared theme sources, providers, boundaries, appearance, runtime caches, and the `theming` facades | -| `src/flex/` | Flex token types, `FlexThemeReference`, `useThemeState`, layered shadows, and styles | +| `src/flex/` | Flex token and theme state types, `FlexThemeReference`, `useThemeState`, layered shadows, and styles | | `src/flex/defaults/` | The generated x3 cool and warm defaults and their parity tests; see `tokens.md` | | `src/flex/adapters/` | The engine-free Theme-to-Flex adapter and its Fluent-native fallbacks | | `src/flex/colors/` | Authored color normalization, the resolved color envelope, token classification, and the interaction policy | | `src/fluent/` | Legacy Fluent theme types, `ThemeReference`, `useTheme`, platform utilities, and legacy styling | | `src/fluent/compat/` | The Flex-to-legacy projection and complete legacy defaults; never reachable from the root | | `src/fluent/tokens/` | Legacy alias, shadow, and global token data | -| `src/themes/` | Ready-made Fluent themes built from the generated Fluent 2 and global tokens; see `theming.md` | +| `src/themes/` | Ready-made Fluent themes from the generated Fluent 2 tokens and Flex themes from the x3 defaults | | `src/tokens/` | Generated global tokens and shared token attributes | | `src/tokens/mappings/` | The canonical token map and its generated projections; see `tokens.md` | | `src/styling/` | Shared state style factories and the `styling` facade; see `styling.md` | @@ -46,11 +46,12 @@ default files are committed; change their inputs and regenerate rather than edit `src/flex/` or `src/color-lib/`, and the Theme-to-Flex adapter in `src/flex/adapters/` must not reach the interaction policy, the x3 defaults, or `src/color-lib/`. `src/test/compatibility/importBoundaries.test.ts` checks these graphs; run the bundle-size scenarios too when changing imports between these areas. -- Keep `src/themes/` a consumer of the generated Fluent 2 and global tokens: it may reach `ThemeReference`, the - generated Fluent tokens, and the generated global tokens, but never `src/flex/`, `src/color-lib/`, `useTheme`, +- Keep `src/themes/` a consumer of generated tokens. `src/themes/fluent/` may reach `ThemeReference`, the generated + Fluent tokens, and the generated global tokens, but never `src/flex/`, `src/color-lib/`, `useTheme`, `src/fluent/compat/`, or the legacy token payloads, and it authors no color value that the generated alias colors lack. - `src/themes/fluent/fluentThemes.test.tsx`, the import-boundary test, and the `design-fluent-*` bundle-size scenarios - guard this. + `src/themes/flex/` exposes the x3 default descriptions unchanged and never reaches `src/fluent/` or + `color-lib/compositing`. The tests under `src/themes/`, the import-boundary test, and the `design-fluent-*` and + `design-flex-*` bundle-size scenarios guard this. - Never mutate author-owned theme inputs; caches are external and keyed by source, revision, and resolved appearance. - Keep color resolution lazy: resolving tokens, reading rest, merging, and copying the color map must not run the interaction algorithm, and a derived state computes at most once per resolved color. `flex-colors.md` owns the color diff --git a/packages/agentic/design/references/entry-points.md b/packages/agentic/design/references/entry-points.md index 90f892e4c8..0bcc7f1d95 100644 --- a/packages/agentic/design/references/entry-points.md +++ b/packages/agentic/design/references/entry-points.md @@ -10,32 +10,33 @@ owner_paths: The package is `sideEffects: false` and exposes explicit subpaths so consumers load only the graph they use. Export public symbols by name from each entry point; do not add barrel re-exports. -| Subpath | Contents | -| --------------------------- | --------------------------------------------------------------------------------------------- | -| `.` (root) | Modern theming (`ThemeProvider`, `ThemedRoot`, `FlexThemeReference`, hooks), Flex token types | -| `./theming` | The complete modern and legacy theming API, including `ThemeReference` and `useTheme` | -| `./theming/legacy-source` | `ThemeReference` without the legacy consumption graph | -| `./theming/compat` | `themeFromFlexTokens` and `getDefaultLegacyTheme` | -| `./theming/compat/defaults` | `getDefaultLegacyTheme` alone, for platform theme packages | -| `./themes` | Ready-made Fluent themes: `fluentLightTheme`, `fluentDarkTheme`, and `fluentTheme` | -| `./tokens/global` | Generated platform global token constants | -| `./tokens/legacy` | Legacy alias, shadow, and global token data | -| `./color-lib` | Raw color parsing, conversion, compositing, and interaction algorithms; see `color-lib.md` | -| `./styling` | State and color style factories; see `styling.md` | -| `./styling/stylesheet` | The legacy `themedStyleSheet` helper | -| `./styling/tokens` | Legacy token-to-style builders | -| `./testing` | Test-only fixtures and validation; see `testing.md` | +| Subpath | Contents | +| --------------------------- | --------------------------------------------------------------------------------------------------------- | +| `.` (root) | Modern theming (`ThemeProvider`, `ThemedRoot`, `FlexThemeReference`, hooks), Flex token types | +| `./theming` | The complete modern and legacy theming API, including `ThemeReference` and `useTheme` | +| `./theming/legacy-source` | `ThemeReference` without the legacy consumption graph | +| `./theming/compat` | `themeFromFlexTokens` and `getDefaultLegacyTheme` | +| `./theming/compat/defaults` | `getDefaultLegacyTheme` alone, for platform theme packages | +| `./themes` | Ready-made themes: `fluentLightTheme`, `fluentDarkTheme`, `fluentTheme`, `flexTheme`, and `flexWarmTheme` | +| `./tokens/global` | Generated platform global token constants | +| `./tokens/legacy` | Legacy alias, shadow, and global token data | +| `./color-lib` | Raw color parsing, conversion, compositing, and interaction algorithms; see `color-lib.md` | +| `./styling` | State and color style factories; see `styling.md` | +| `./styling/stylesheet` | The legacy `themedStyleSheet` helper | +| `./styling/tokens` | Legacy token-to-style builders | +| `./testing` | Test-only fixtures and validation; see `testing.md` | The `apps/bundle-size` `design-*` scenarios guard these boundaries. Input patterns check the import graph and output patterns check the modules a tree-shaken bundle retains. The modern root and legacy-source scenarios forbid the compatibility and legacy-token modules and `color-lib/compositing`. The modern root scenarios and the legacy-source scenario, which pairs a legacy `ThemeReference` with `useThemeState`, require the retained Flex interaction policy and `color-lib/interaction`; the legacy-source scenario also forbids a retained `FlexThemeReference`. Only the legacy theme -scenario forbids any retained `color-lib/` or `flex/` module. The Fluent theme scenarios forbid `flex/`, `color-lib/`, -`useTheme`, and the compatibility and legacy-token modules from the import graph, and a bundle that imports only -`fluentLightTheme` retains neither the dark theme nor `ThemeReference`. The color-library and legacy-projection -scenarios require their expected modules. Every scenario also requires a module it is expected to load, so a moved file -cannot make a forbidden pattern pass vacuously. +scenario forbids any retained `color-lib/` or `flex/` module. The Fluent theme scenarios forbid `useTheme` and the +compatibility and legacy-token modules from the import graph and any retained `flex/`, `color-lib/`, or Flex theme +module, and a bundle that imports only `fluentLightTheme` retains neither the dark theme nor `ThemeReference`. The Flex +theme scenarios require the x3 defaults and forbid `fluent/` and `color-lib/compositing`. The color-library and +legacy-projection scenarios require their expected modules. Every scenario also requires a module it is expected to load, +so a moved file cannot make a forbidden pattern pass vacuously. The package specifiers above are the supported import surface. Source and build paths such as `src/fluent/...` or `lib/...` are private implementation details that may move without a breaking change. diff --git a/packages/agentic/design/references/flex-colors.md b/packages/agentic/design/references/flex-colors.md index aa7b16e615..f1b3e32d1c 100644 --- a/packages/agentic/design/references/flex-colors.md +++ b/packages/agentic/design/references/flex-colors.md @@ -79,7 +79,8 @@ derives states: its omitted states equal rest, so legacy-projected values are un ## Merging and recipes -`FlexThemeReference` merges the package defaults, its `base`, and its recipes in order. A color override replaces the +`FlexThemeReference` merges the package defaults, its `base`, and its recipes in order; a `FlexThemeDescription` base +replaces the defaults instead (`theming.md`). A color override replaces the previous color atomically, including its explicit states and type, so a stale state never survives a new rest. Shadow overrides also replace the whole layered shadow. An `undefined` color or shadow is not an override. Other token groups keep deep-merge semantics. diff --git a/packages/agentic/design/references/remaining-work.md b/packages/agentic/design/references/remaining-work.md index 49bc929f61..bff2481262 100644 --- a/packages/agentic/design/references/remaining-work.md +++ b/packages/agentic/design/references/remaining-work.md @@ -74,19 +74,12 @@ behavior is documented in `theming.md`, `tokens.md`, and `entry-points.md`. ## Fluent high-contrast and elevated themes - **Outcome:** `fluentTheme` selects distinct themes for high-contrast and elevated appearances. -- **Current state:** `themes` exports only the light and dark Fluent themes. The generated Fluent tokens already supply +- **Current state:** `themes` provides only light and dark Fluent themes. The generated Fluent tokens already supply the `hc`, `hcLight`, `hcDark`, `darkGray`, and `darkElevated` color and shadow sets (`tokens.md`), but `fluentTheme` resolves high-contrast and elevated requests by color scheme alone. - **Done when:** the owner approves how each appearance maps to those sets, including iOS, whose high-contrast files carry no colors, and `fluentTheme` selects the matching theme by the resolved appearance. -## Flex themes - -- **Outcome:** the `themes` entry point also exposes ready-made Flex themes beside the Fluent themes. -- **Current state:** `themes` exports only Fluent themes, authored as legacy `Theme` objects. -- **Done when:** the owner defines the Flex theme set and its exports, and `theming.md` and `entry-points.md` document - them. - ## Dependent work owned by other packages - `@fluentui-react-native/apple-theme` still authors a legacy `Theme`; diff --git a/packages/agentic/design/references/theming.md b/packages/agentic/design/references/theming.md index ac3eaf026f..9f04f245ee 100644 --- a/packages/agentic/design/references/theming.md +++ b/packages/agentic/design/references/theming.md @@ -5,6 +5,7 @@ owner_paths: - packages/agentic/design/src/theming - packages/agentic/design/src/types - packages/agentic/design/src/flex/flexThemeReference.ts + - packages/agentic/design/src/flex/themeState.types.ts - packages/agentic/design/src/flex/useThemeState.ts - packages/agentic/design/src/fluent - packages/agentic/design/src/themes @@ -30,6 +31,11 @@ may be a function of the resolved appearance, which always has a concrete `color authored description and the resolved appearance. `PartialFlexTokens` is shape-aware so opaque React Native colors stay leaves. `tokens.md` describes the defaults. +A base may instead be a `FlexThemeDescription`: a complete `FlexTokenDescription` in `tokens` and an optional +`colorTone`. Its tokens replace the package defaults for every appearance, and its tone becomes the reference's default +`appearance.colorTone` when the `appearance` option sets none. A provider's `appearance` request still wins, and it +changes only the interaction algorithm, not the description's palette. The Flex themes below are descriptions. + Each color is authored as a value, a `[light, dark]` tuple, or `flexColor` options with explicit states and an interaction type, and replaces the previous color atomically. Each resolved color is an `InteractiveColor` with `rest`, `hover`, and `pressed`. Omitted states of interactive tokens are derived from rest with the `color-lib` interaction @@ -153,6 +159,27 @@ import { fluentTheme } from '@fluentui-react-native/design/themes'; const App = () => <ThemedRoot theme={fluentTheme}>{/* scene */}</ThemedRoot>; ``` +## Flex themes + +The `themes` entry point also provides the x3 Flex defaults (`tokens.md`) as `FlexThemeDescription` data: + +| Export | Kind | Contents | +| --------------- | ---------------------- | -------------------------------------------------- | +| `flexTheme` | `FlexThemeDescription` | The cool light and dark defaults, with tone `cool` | +| `flexWarmTheme` | `FlexThemeDescription` | The warm light and dark defaults, with tone `warm` | + +Each is a theme description rather than a source: pass it as a `FlexThemeReference` base, alone or under recipes. A +reference built on `flexTheme` or `flexWarmTheme` resolves the same tokens as a default `FlexThemeReference` requesting +that tone. Both descriptions are the shared default objects, so treat them as read-only; author changes as recipes or a +new description. + +```ts +import { FlexThemeReference } from '@fluentui-react-native/design'; +import { flexWarmTheme } from '@fluentui-react-native/design/themes'; + +const theme = new FlexThemeReference({ base: flexWarmTheme, appearance: { colorScheme: 'system' } }); +``` + ## Legacy projection and bundle boundary The package root exports only the modern authoring and consumption APIs. It reaches the forward Theme-to-Flex adapter, diff --git a/packages/agentic/design/references/tokens.md b/packages/agentic/design/references/tokens.md index 94be722b8a..67eb4e8259 100644 --- a/packages/agentic/design/references/tokens.md +++ b/packages/agentic/design/references/tokens.md @@ -68,7 +68,8 @@ objects that the declarations spread. The emitted key order is therefore not mea ## Default tokens `src/flex/defaults/defaultTokens.generated.ts` holds the cool and warm x3 defaults, and `defaultTokens.ts` normalizes -them. `FlexThemeReference` merges the default for the resolved `colorTone` under its base and recipes. The x3 sources +them. `FlexThemeReference` merges the default for the resolved `colorTone` under its base and recipes, and the `themes` +entry point exposes the two defaults as `flexTheme` and `flexWarmTheme` (`theming.md`). The x3 sources define no high-contrast or elevated values, so those appearances use the light or dark default. Defaults do not otherwise vary by contrast or interface level; see `remaining-work.md`. Tests that assert default values should read them from `defaultFlexTokens` in the `testing` entry point rather than repeating literals. diff --git a/packages/agentic/design/src/flex/flexThemeReference.test.ts b/packages/agentic/design/src/flex/flexThemeReference.test.ts index 43f7c02637..e4959c1476 100644 --- a/packages/agentic/design/src/flex/flexThemeReference.test.ts +++ b/packages/agentic/design/src/flex/flexThemeReference.test.ts @@ -6,6 +6,7 @@ import { flexColor, selectColorEntry } from './colors/flexColor'; import { deriveInteractionColor, resolveFlexTokenDescription } from './colors/interactionPolicy'; import { defaultFlexTokenDescription, defaultFlexTokens, getDefaultFlexTokenDescription } from './defaults/defaultTokens'; import { FlexThemeReference } from './flexThemeReference'; +import type { FlexThemeDescription } from './themeState.types'; import type { FlexTokenDescription, PartialFlexTokens } from './tokens.types'; const darkAppearance = { @@ -141,6 +142,32 @@ describe('FlexThemeReference color tone', () => { }); }); +describe('FlexThemeReference theme description base', () => { + const warmTheme: FlexThemeDescription = { tokens: getDefaultFlexTokenDescription('warm'), colorTone: 'warm' }; + + it('replaces the package defaults for every requested tone', () => { + const descriptions: FlexTokenDescription[] = []; + const reference = new FlexThemeReference({ base: warmTheme }, (description) => { + descriptions.push(description); + return {}; + }); + + expect(reference.resolveFlexTokens({ ...defaultResolvedThemeAppearance, colorTone: 'cool' }).color.surfaceNeutralFarther.rest).toBe( + '#f0eae5', + ); + expect(descriptions[0]).toBe(warmTheme.tokens); + }); + + it('uses the description tone unless the appearance option sets one', () => { + expect(new FlexThemeReference({ base: warmTheme, appearance: { colorScheme: 'dark' } }).appearanceOptions).toEqual({ + colorScheme: 'dark', + colorTone: 'warm', + }); + expect(new FlexThemeReference({ base: warmTheme, appearance: { colorTone: 'cool' } }).appearanceOptions).toEqual({ colorTone: 'cool' }); + expect(new FlexThemeReference({ base: { tokens: warmTheme.tokens } }).appearanceOptions).toBeUndefined(); + }); +}); + describe('FlexThemeReference interaction derivation', () => { const omitInteraction = (rest: ColorValue): PartialFlexTokens => ({ color: { backgroundNeutralTranslucent: rest } }); diff --git a/packages/agentic/design/src/flex/flexThemeReference.ts b/packages/agentic/design/src/flex/flexThemeReference.ts index c4191f5f1a..729c3f0576 100644 --- a/packages/agentic/design/src/flex/flexThemeReference.ts +++ b/packages/agentic/design/src/flex/flexThemeReference.ts @@ -2,6 +2,7 @@ import { immutableMerge } from '@fluentui-react-native/framework-base'; import { getDefaultFlexTokenDescription } from './defaults/defaultTokens'; import { mergeFlexTokenDescription } from './flexTokenDescription'; +import type { FlexThemeDescription } from './themeState.types'; import type { FlexTokenDescription, FlexTokens, PartialFlexTokens } from './tokens.types'; import { resolveFlexTokenDescription } from './colors/interactionPolicy'; import { internResolvedThemeAppearance, themeAppearanceKey } from '../theming/appearance'; @@ -31,8 +32,19 @@ export type FlexThemeRecipe = export type LegacyThemeFallback = Theme | PartialTheme | ((appearance: Readonly<NormalizedThemeAppearance>) => Theme | PartialTheme); +// No token group is named `tokens`, so its presence identifies a complete description. +function isFlexThemeDescription(base: FlexThemeReferenceOptions['base']): base is FlexThemeDescription { + return typeof base === 'object' && base !== null && !(base instanceof FlexThemeReference) && 'tokens' in base; +} + export interface FlexThemeReferenceOptions { - base?: FlexThemeInput | FlexThemeReference; + /** + * Authored tokens layered over the package defaults, a complete + * `FlexThemeDescription` that replaces them, or a parent reference. A + * description's `colorTone` fills `appearance.colorTone` when that option + * omits it. + */ + base?: FlexThemeInput | FlexThemeDescription | FlexThemeReference; appearance?: ThemeAppearanceOptions; fallbackAppearance?: Partial<ResolvedThemeAppearance>; appearanceSource?: ThemeAppearanceSource; @@ -46,7 +58,7 @@ export class FlexThemeReference implements FlexThemeSource { public readonly appearanceSource?: ThemeAppearanceSource; private revisionValue = 0; - private readonly base?: FlexThemeInput | FlexThemeReference; + private readonly base?: FlexThemeInput | FlexThemeDescription | FlexThemeReference; private readonly legacyFallback?: LegacyThemeFallback; private recipes: FlexThemeRecipe[]; private readonly listeners = new Set<OnThemeChange>(); @@ -58,7 +70,10 @@ export class FlexThemeReference implements FlexThemeSource { public constructor(options: FlexThemeReferenceOptions = {}, ...recipes: FlexThemeRecipe[]) { this.base = options.base; const parent = options.base instanceof FlexThemeReference ? options.base : undefined; - this.appearanceOptions = options.appearance ?? parent?.appearanceOptions; + const appearance = options.appearance ?? parent?.appearanceOptions; + const descriptionTone = isFlexThemeDescription(options.base) ? options.base.colorTone : undefined; + this.appearanceOptions = + descriptionTone !== undefined && appearance?.colorTone === undefined ? { ...appearance, colorTone: descriptionTone } : appearance; this.fallbackAppearance = options.fallbackAppearance ?? parent?.fallbackAppearance; this.appearanceSource = options.appearanceSource ?? parent?.appearanceSource; this.legacyFallback = options.legacyFallback; @@ -149,6 +164,9 @@ export class FlexThemeReference implements FlexThemeSource { this.base.syncParentRevision(); return this.base.resolveDescription(appearance, key); } + if (isFlexThemeDescription(this.base)) { + return this.base.tokens; + } const base = typeof this.base === 'function' ? this.base(appearance) : this.base; return mergeFlexTokenDescription(getDefaultFlexTokenDescription(appearance.colorTone), base); } diff --git a/packages/agentic/design/src/flex/styling/colorStyles.test.ts b/packages/agentic/design/src/flex/styling/colorStyles.test.ts index 8224f7e323..2815f3459d 100644 --- a/packages/agentic/design/src/flex/styling/colorStyles.test.ts +++ b/packages/agentic/design/src/flex/styling/colorStyles.test.ts @@ -2,7 +2,7 @@ import { createInteractiveColor } from '../colors/interactiveColor'; import type { FlexTokens } from '../tokens.types'; import { defaultFlexTokens } from '../defaults/defaultTokens'; import { defaultResolvedThemeAppearance } from '../../theming/appearance'; -import type { ThemeState } from '../../types/themeState.types'; +import type { ThemeState } from '../themeState.types'; import { colorStyleDef, getThemedColorStyleFactory } from './colorStyles'; import type { ColorStyleDefinition, ViewColorStyle } from './colorStyles'; diff --git a/packages/agentic/design/src/flex/styling/colorStyles.ts b/packages/agentic/design/src/flex/styling/colorStyles.ts index 286028f758..0717b8de1b 100644 --- a/packages/agentic/design/src/flex/styling/colorStyles.ts +++ b/packages/agentic/design/src/flex/styling/colorStyles.ts @@ -1,7 +1,7 @@ import type { TextStyle, ViewStyle } from 'react-native'; import type { FlexTokens, InteractiveColor, SemanticColorName, SemanticColors } from '../tokens.types'; -import type { ThemeState } from '../../types/themeState.types'; +import type { ThemeState } from '../themeState.types'; import { createStateLevelMap, getThemedStateStyleFactory } from '../../styling/branchedStyle'; import type { StateLevels, StateNames, StateSource, StyleDefinition, StyleDefFromTokens } from '../../styling/branchedStyle'; diff --git a/packages/agentic/design/src/flex/themeState.ts b/packages/agentic/design/src/flex/themeState.ts index 4e79fb8008..156c197f60 100644 --- a/packages/agentic/design/src/flex/themeState.ts +++ b/packages/agentic/design/src/flex/themeState.ts @@ -5,7 +5,7 @@ import { defaultResolvedThemeAppearance } from '../theming/appearance'; import { getFlexSourceTokens, getThemeAppearanceCache } from '../theming/themeRuntime'; import type { ThemeSource } from '../theming/themeSource'; import type { NormalizedThemeAppearance } from '../types/appearance.types'; -import type { ThemeState } from '../types/themeState.types'; +import type { ThemeState } from './themeState.types'; export const defaultThemeState: ThemeState = { tokens: defaultFlexTokens, diff --git a/packages/agentic/design/src/types/themeState.types.ts b/packages/agentic/design/src/flex/themeState.types.ts similarity index 53% rename from packages/agentic/design/src/types/themeState.types.ts rename to packages/agentic/design/src/flex/themeState.types.ts index 5e45c00231..c7a12cd71f 100644 --- a/packages/agentic/design/src/types/themeState.types.ts +++ b/packages/agentic/design/src/flex/themeState.types.ts @@ -1,5 +1,23 @@ -import type { FlexTokens } from '../flex/tokens.types'; -import type { NormalizedThemeAppearance } from './appearance.types'; +import type { ColorTone, NormalizedThemeAppearance } from '../types/appearance.types'; +import type { FlexTokenDescription, FlexTokens } from './tokens.types'; + +/** + * A complete Flex theme: a token description that replaces the package + * defaults, and the palette tone it was authored for. + */ +export type FlexThemeDescription = { + /** + * The complete authored token description, covering light and dark. + */ + readonly tokens: FlexTokenDescription; + /** + * The palette tone of these tokens. A `FlexThemeReference` built on this + * description uses it as its default requested tone, which also selects the + * interaction-color algorithm. Omitted means no default, so the tone + * resolves as for any other source. + */ + readonly colorTone?: ColorTone; +}; /** * Style sheets cached for one theme state, keyed by a module-scoped symbol per component. diff --git a/packages/agentic/design/src/flex/useThemeState.test.ts b/packages/agentic/design/src/flex/useThemeState.test.ts index 6425bb1b2f..ce3980b6fa 100644 --- a/packages/agentic/design/src/flex/useThemeState.test.ts +++ b/packages/agentic/design/src/flex/useThemeState.test.ts @@ -12,7 +12,7 @@ import { ThemeProvider } from '../theming/ThemeProvider'; import type { Theme } from '../fluent/types/Theme.types'; import { mockTheme } from '../test/fixtures/mockTheme'; import { themedStyleSheetFactory, useThemeAppearance, useThemeState } from './useThemeState'; -import type { ThemeState } from '../types/themeState.types'; +import type { ThemeState } from './themeState.types'; function ThemeStateProbe({ states }: { states: ThemeState[] }) { states.push(useThemeState()); diff --git a/packages/agentic/design/src/flex/useThemeState.ts b/packages/agentic/design/src/flex/useThemeState.ts index b9f3a5e169..71db5db091 100644 --- a/packages/agentic/design/src/flex/useThemeState.ts +++ b/packages/agentic/design/src/flex/useThemeState.ts @@ -4,7 +4,7 @@ import { defaultThemeAppearanceState } from '../theming/appearance'; import { useThemeBoundary } from '../theming/context'; import { defaultThemeState, getThemeState } from './themeState'; import type { ThemeAppearanceState } from '../types/appearance.types'; -import type { ThemeState } from '../types/themeState.types'; +import type { ThemeState } from './themeState.types'; export type ThemeStyleSheet = Record<string, ViewStyle | TextStyle | ImageStyle>; diff --git a/packages/agentic/design/src/fluent/useTheme.test.ts b/packages/agentic/design/src/fluent/useTheme.test.ts index 264451bce3..4ec5ab15fc 100644 --- a/packages/agentic/design/src/fluent/useTheme.test.ts +++ b/packages/agentic/design/src/fluent/useTheme.test.ts @@ -5,7 +5,7 @@ import type { ReactTestRenderer } from 'react-test-renderer'; import { mockTheme } from '../test/fixtures/mockTheme'; import { useThemeState } from '../flex/useThemeState'; -import type { ThemeState } from '../types/themeState.types'; +import type { ThemeState } from '../flex/themeState.types'; import type { ThemeAppearanceSource } from '../types/appearance.types'; import { ThemeContext } from '../theming/context'; import { FlexThemeReference } from '../flex/flexThemeReference'; diff --git a/packages/agentic/design/src/index.ts b/packages/agentic/design/src/index.ts index 0c8f404e94..8b89a6c5ca 100644 --- a/packages/agentic/design/src/index.ts +++ b/packages/agentic/design/src/index.ts @@ -52,6 +52,7 @@ export { } from './theming/modern'; export type { ColorTone, + FlexThemeDescription, FlexThemeInput, FlexThemeRecipe, FlexThemeReferenceOptions, @@ -78,5 +79,5 @@ export type { ThemeSourceBase, } from './theming/modern'; export type { ThemeStyleSheet } from './flex/useThemeState'; -export type { ThemeState } from './types/themeState.types'; +export type { ThemeState } from './flex/themeState.types'; export { themedStyleSheetFactory, useThemeAppearance, useThemeState } from './flex/useThemeState'; diff --git a/packages/agentic/design/src/styling/branchedStyle.test.ts b/packages/agentic/design/src/styling/branchedStyle.test.ts index 9c83aabb48..4804477e45 100644 --- a/packages/agentic/design/src/styling/branchedStyle.test.ts +++ b/packages/agentic/design/src/styling/branchedStyle.test.ts @@ -2,7 +2,7 @@ import type { ViewStyle } from 'react-native'; import { defaultResolvedThemeAppearance } from '../theming/appearance'; import { defaultFlexTokens } from '../flex/defaults/defaultTokens'; -import type { ThemeState } from '../types/themeState.types'; +import type { ThemeState } from '../flex/themeState.types'; import { getActiveState, diff --git a/packages/agentic/design/src/styling/branchedStyle.ts b/packages/agentic/design/src/styling/branchedStyle.ts index 8e8051ffac..f624080b9d 100644 --- a/packages/agentic/design/src/styling/branchedStyle.ts +++ b/packages/agentic/design/src/styling/branchedStyle.ts @@ -1,7 +1,7 @@ import type { ImageStyle, TextStyle, ViewStyle } from 'react-native'; import type { FlexTokens } from '../flex/tokens.types'; -import type { ThemeState } from '../types/themeState.types'; +import type { ThemeState } from '../flex/themeState.types'; type AnyStyle = ViewStyle | ImageStyle | TextStyle; diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap index 67ecfdd733..87a2dbc5da 100644 --- a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap @@ -100,6 +100,8 @@ exports[`public entry points ./testing keeps its runtime export names 1`] = ` exports[`public entry points ./themes keeps its runtime export names 1`] = ` [ + "flexTheme: object", + "flexWarmTheme: object", "fluentDarkTheme: object", "fluentLightTheme: object", "fluentTheme: object", diff --git a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts index 81ab3a50d9..d121c5e458 100644 --- a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts +++ b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts @@ -210,23 +210,42 @@ describe('runtime graph ownership', () => { expect(reachedUnder(legacySourceGraph, 'fluent/tokens/')).toEqual([]); }); - it('keeps the themes entry on generated tokens and the legacy source, free of the Flex engine, projection, and payloads', () => { + it('keeps the themes entry free of the legacy projection, payloads, and test collateral', () => { const themesGraph = runtimeGraph('themes/index.ts'); expect(themesGraph).toContain('themes/fluent/fluentTheme.ts'); - expect(themesGraph).toContain('fluent/themeReference.ts'); - expect(themesGraph).toContain('fluent/defaults/fluentTokens.generated.ts'); - expect(themesGraph).toContain('tokens/global.generated.ts'); + expect(themesGraph).toContain('themes/flex/flexWarmTheme.ts'); expect(themesGraph).not.toContain('fluent/useTheme.ts'); - for (const prefix of ['flex/', 'color-lib/', 'test/', 'fluent/compat/', 'fluent/tokens/']) { + for (const prefix of ['test/', 'fluent/compat/', 'fluent/tokens/']) { expect([prefix, reachedUnder(themesGraph, prefix)]).toEqual([prefix, []]); } }); + + it('keeps the Fluent themes on generated tokens and the legacy source, free of the Flex engine', () => { + for (const entry of ['themes/fluent/fluentLightTheme.ts', 'themes/fluent/fluentDarkTheme.ts', 'themes/fluent/fluentTheme.ts']) { + const graph = runtimeGraph(entry); + expect(graph).toContain('fluent/defaults/fluentTokens.generated.ts'); + expect(graph).toContain('tokens/global.generated.ts'); + for (const prefix of ['flex/', 'color-lib/']) { + expect([entry, prefix, reachedUnder(graph, prefix)]).toEqual([entry, prefix, []]); + } + } + expect(runtimeGraph('themes/fluent/fluentTheme.ts')).toContain('fluent/themeReference.ts'); + }); + + it('keeps the Flex themes on the generated Flex defaults, free of legacy Fluent runtime', () => { + for (const entry of ['themes/flex/flexTheme.ts', 'themes/flex/flexWarmTheme.ts']) { + const graph = runtimeGraph(entry); + expect(graph).toContain('flex/defaults/defaultTokens.generated.ts'); + expect([entry, reachedUnder(graph, 'fluent/')]).toEqual([entry, []]); + expect(graph).not.toContain('color-lib/compositing.ts'); + } + }); }); describe('shared types', () => { it('contain only type declarations and type-only imports', () => { - const typeFiles = listSourceFiles(path.join(srcRoot, 'types')); - expect(typeFiles.map(toSrcPath).sort()).toEqual(expect.arrayContaining(['types/appearance.types.ts', 'types/themeState.types.ts'])); + const typeFiles = [...listSourceFiles(path.join(srcRoot, 'types')), path.join(srcRoot, 'flex/themeState.types.ts')]; + expect(typeFiles.map(toSrcPath).sort()).toEqual(expect.arrayContaining(['types/appearance.types.ts', 'flex/themeState.types.ts'])); const runtimeStatements = typeFiles.flatMap((file) => readStatements(file) .filter((statement) => !isTypeOnlyStatement(statement)) diff --git a/packages/agentic/design/src/themes/flex/flexTheme.ts b/packages/agentic/design/src/themes/flex/flexTheme.ts new file mode 100644 index 0000000000..fee34cc8af --- /dev/null +++ b/packages/agentic/design/src/themes/flex/flexTheme.ts @@ -0,0 +1,7 @@ +import { defaultFlexTokenDescription } from '../../flex/defaults/defaultTokens'; +import type { FlexThemeDescription } from '../../flex/themeState.types'; + +/** + * The cool-tone Flex theme: the x3 cool default tokens for light and dark. + */ +export const flexTheme: FlexThemeDescription = { tokens: defaultFlexTokenDescription, colorTone: 'cool' }; diff --git a/packages/agentic/design/src/themes/flex/flexThemes.test.tsx b/packages/agentic/design/src/themes/flex/flexThemes.test.tsx new file mode 100644 index 0000000000..3f5667e89b --- /dev/null +++ b/packages/agentic/design/src/themes/flex/flexThemes.test.tsx @@ -0,0 +1,50 @@ +import { act, create } from 'react-test-renderer'; + +import { FlexThemeReference } from '../../flex/flexThemeReference'; +import type { ThemeState } from '../../flex/themeState.types'; +import { useThemeState } from '../../flex/useThemeState'; +import { ThemeProvider } from '../../theming/ThemeProvider'; +import type { ColorTone } from '../../types/appearance.types'; +import { flexTheme, flexWarmTheme } from '../index'; + +describe('Flex themes', () => { + it.each([ + ['flexTheme', flexTheme, 'cool'], + ['flexWarmTheme', flexWarmTheme, 'warm'], + ] as const)('%s reproduces the package defaults for its tone in light and dark', (_name, theme, colorTone) => { + const reference = new FlexThemeReference({ base: theme }); + const defaults = new FlexThemeReference(); + + for (const colorScheme of ['light', 'dark'] as const) { + const appearance = { colorScheme, contrast: 'standard', interfaceLevel: 'base', colorTone } as const; + expect(reference.resolveFlexTokens(appearance)).toEqual(defaults.resolveFlexTokens(appearance)); + } + }); + + it('makes a reference built on flexWarmTheme warm until a provider requests another tone', () => { + const reference = new FlexThemeReference({ base: flexWarmTheme }); + const seen: ThemeState[] = []; + const Probe = () => { + seen.push(useThemeState()); + return null; + }; + const render = (colorTone?: ColorTone) => ( + <ThemeProvider theme={reference} appearance={colorTone ? { colorScheme: 'light', colorTone } : { colorScheme: 'light' }}> + <Probe /> + </ThemeProvider> + ); + let component!: ReturnType<typeof create>; + + act(() => { + component = create(render()); + }); + expect(seen.at(-1)?.appearance.colorTone).toBe('warm'); + expect(seen.at(-1)?.tokens.color.surfaceNeutralFarther.rest).toBe('#f0eae5'); + + act(() => component.update(render('cool'))); + expect(seen.at(-1)?.appearance.colorTone).toBe('cool'); + expect(seen.at(-1)?.tokens.color.surfaceNeutralFarther.rest).toBe('#f0eae5'); + + act(() => component.unmount()); + }); +}); diff --git a/packages/agentic/design/src/themes/flex/flexWarmTheme.ts b/packages/agentic/design/src/themes/flex/flexWarmTheme.ts new file mode 100644 index 0000000000..615aef2627 --- /dev/null +++ b/packages/agentic/design/src/themes/flex/flexWarmTheme.ts @@ -0,0 +1,7 @@ +import { getDefaultFlexTokenDescription } from '../../flex/defaults/defaultTokens'; +import type { FlexThemeDescription } from '../../flex/themeState.types'; + +/** + * The warm-tone Flex theme: the x3 warm default tokens for light and dark. + */ +export const flexWarmTheme: FlexThemeDescription = { tokens: /* @__PURE__ */ getDefaultFlexTokenDescription('warm'), colorTone: 'warm' }; diff --git a/packages/agentic/design/src/themes/index.ts b/packages/agentic/design/src/themes/index.ts index 781e1ab380..0f4d7c6c09 100644 --- a/packages/agentic/design/src/themes/index.ts +++ b/packages/agentic/design/src/themes/index.ts @@ -1,3 +1,5 @@ +export { flexTheme } from './flex/flexTheme'; +export { flexWarmTheme } from './flex/flexWarmTheme'; export { fluentDarkTheme } from './fluent/fluentDarkTheme'; export { fluentLightTheme } from './fluent/fluentLightTheme'; export { fluentTheme } from './fluent/fluentTheme'; diff --git a/packages/agentic/design/src/theming/ThemedRoot.test.tsx b/packages/agentic/design/src/theming/ThemedRoot.test.tsx index 448f7c277c..01da79d1bd 100644 --- a/packages/agentic/design/src/theming/ThemedRoot.test.tsx +++ b/packages/agentic/design/src/theming/ThemedRoot.test.tsx @@ -7,7 +7,7 @@ import type { ReactTestRenderer } from 'react-test-renderer'; import { mockTheme } from '../test/fixtures/mockTheme'; import { defaultFlexTokens } from '../flex/defaults/defaultTokens'; import { useThemeState } from '../flex/useThemeState'; -import type { ThemeState } from '../types/themeState.types'; +import type { ThemeState } from '../flex/themeState.types'; import type { ResolvedThemeAppearance, ThemeAppearanceSource, ThemeAppearanceSourceSnapshot } from '../types/appearance.types'; import { ThemeContext } from './context'; import { FlexThemeReference } from '../flex/flexThemeReference'; diff --git a/packages/agentic/design/src/theming/index.ts b/packages/agentic/design/src/theming/index.ts index 1b46590c53..584bbd46f8 100644 --- a/packages/agentic/design/src/theming/index.ts +++ b/packages/agentic/design/src/theming/index.ts @@ -69,6 +69,7 @@ export { useRootInputModality } from './useRootInputModality'; export type { InputModality, RootSettings } from './rootContext'; export { FlexThemeReference } from '../flex/flexThemeReference'; export type { FlexThemeInput, FlexThemeRecipe, FlexThemeReferenceOptions, LegacyThemeFallback } from '../flex/flexThemeReference'; +export type { FlexThemeDescription } from '../flex/themeState.types'; export { flexColor, selectColorEntry } from '../flex/colors/flexColor'; export type { ColorSchemeSelector } from '../flex/colors/flexColor'; export { selectShadowEntry } from '../flex/flexShadow'; diff --git a/packages/agentic/design/src/theming/modern.ts b/packages/agentic/design/src/theming/modern.ts index 02cc7b729e..5d96fc6e13 100644 --- a/packages/agentic/design/src/theming/modern.ts +++ b/packages/agentic/design/src/theming/modern.ts @@ -22,6 +22,7 @@ export { export { createThemeAppearanceSource } from './appearanceSource'; export { FlexThemeReference } from '../flex/flexThemeReference'; export type { FlexThemeInput, FlexThemeRecipe, FlexThemeReferenceOptions, LegacyThemeFallback } from '../flex/flexThemeReference'; +export type { FlexThemeDescription } from '../flex/themeState.types'; export { flexColor, selectColorEntry } from '../flex/colors/flexColor'; export type { ColorSchemeSelector } from '../flex/colors/flexColor'; export { selectShadowEntry } from '../flex/flexShadow'; diff --git a/packages/agentic/design/src/theming/themeRuntime.ts b/packages/agentic/design/src/theming/themeRuntime.ts index eb9acf07b3..684eb46176 100644 --- a/packages/agentic/design/src/theming/themeRuntime.ts +++ b/packages/agentic/design/src/theming/themeRuntime.ts @@ -1,7 +1,7 @@ import { themeAppearanceKey } from './appearance'; import type { FlexTokens } from '../flex/tokens.types'; import type { ResolvedThemeAppearance } from '../types/appearance.types'; -import type { ThemeState } from '../types/themeState.types'; +import type { ThemeState } from '../flex/themeState.types'; import type { FlexThemeSource, ThemeSource } from './themeSource'; /** From 913fdab416e733c9c3550804ed63d0600eb8c953 Mon Sep 17 00:00:00 2001 From: Jason Morse <jasonmo360@gmail.com> Date: Sat, 31 Oct 2026 16:08:04 -0700 Subject: [PATCH 15/18] Adapt merged component tests and bundle baseline to interactive colors Tests added on main read Flex colors as flat strings and through the removed color.hover and color.pressed maps. Read each InteractiveColor state instead, drop a duplicate ProgressBar import from the merge, and refresh the bundle-size baseline for the rebased tree. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- apps/bundle-size/baseline.json | 38 +++++++++---------- .../src/components/checkbox/checkbox.test.tsx | 28 +++++++------- .../components/list-item/list-item.test.tsx | 6 +-- .../progress-bar/progress-bar.test.tsx | 5 +-- .../src/components/skeleton/skeleton.test.tsx | 2 +- .../src/components/tab/tab.test.tsx | 6 +-- 6 files changed, 40 insertions(+), 45 deletions(-) diff --git a/apps/bundle-size/baseline.json b/apps/bundle-size/baseline.json index 1740950033..e4190fe37e 100644 --- a/apps/bundle-size/baseline.json +++ b/apps/bundle-size/baseline.json @@ -4,26 +4,26 @@ { "platform": "macos", "scenario": "components-button", - "rawBytes": 72677, - "gzipBytes": 21021, - "moduleCount": 77, + "rawBytes": 73626, + "gzipBytes": 21384, + "moduleCount": 78, "metafileInputCount": 243, "workspaceModules": { "@fluentui-react-native/components": 16, "@fluentui-react-native/design": 34, - "@fluentui-react-native/framework-base": 26 + "@fluentui-react-native/framework-base": 27 }, "workspaceBytes": { - "@fluentui-react-native/components": 9328, - "@fluentui-react-native/design": 50727, - "@fluentui-react-native/framework-base": 12586 + "@fluentui-react-native/components": 9761, + "@fluentui-react-native/design": 50730, + "@fluentui-react-native/framework-base": 13099 } }, { "platform": "macos", "scenario": "components-catalog", - "rawBytes": 227968, - "gzipBytes": 63316, + "rawBytes": 229314, + "gzipBytes": 63682, "moduleCount": 227, "metafileInputCount": 243, "workspaceModules": { @@ -33,7 +33,7 @@ "@fluentui-react-native/native-core": 12 }, "workspaceBytes": { - "@fluentui-react-native/components": 151331, + "@fluentui-react-native/components": 152677, "@fluentui-react-native/design": 51975, "@fluentui-react-native/framework-base": 15305, "@fluentui-react-native/native-core": 9228 @@ -198,26 +198,26 @@ { "platform": "windows", "scenario": "components-button", - "rawBytes": 72603, - "gzipBytes": 20994, - "moduleCount": 78, + "rawBytes": 73547, + "gzipBytes": 21342, + "moduleCount": 79, "metafileInputCount": 244, "workspaceModules": { "@fluentui-react-native/components": 16, "@fluentui-react-native/design": 35, - "@fluentui-react-native/framework-base": 26 + "@fluentui-react-native/framework-base": 27 }, "workspaceBytes": { - "@fluentui-react-native/components": 9330, + "@fluentui-react-native/components": 9761, "@fluentui-react-native/design": 50651, - "@fluentui-react-native/framework-base": 12586 + "@fluentui-react-native/framework-base": 13099 } }, { "platform": "windows", "scenario": "components-catalog", - "rawBytes": 227892, - "gzipBytes": 63279, + "rawBytes": 229238, + "gzipBytes": 63628, "moduleCount": 228, "metafileInputCount": 244, "workspaceModules": { @@ -227,7 +227,7 @@ "@fluentui-react-native/native-core": 12 }, "workspaceBytes": { - "@fluentui-react-native/components": 151331, + "@fluentui-react-native/components": 152677, "@fluentui-react-native/design": 51899, "@fluentui-react-native/framework-base": 15305, "@fluentui-react-native/native-core": 9228 diff --git a/packages/agentic/components/src/components/checkbox/checkbox.test.tsx b/packages/agentic/components/src/components/checkbox/checkbox.test.tsx index 56aa102d45..4ee42ef188 100644 --- a/packages/agentic/components/src/components/checkbox/checkbox.test.tsx +++ b/packages/agentic/components/src/components/checkbox/checkbox.test.tsx @@ -480,26 +480,26 @@ describe('Checkbox', () => { async (status) => { const colors = defaultFlexTokens.color; const component = await renderCheckbox({ status, showSecondaryText: true }); - for (const [event, palette] of [ - ['hoverIn', colors.hover], - ['pressIn', colors.pressed], - ['pressOut', colors.hover], - ['hoverOut', colors], + for (const [event, state] of [ + ['hoverIn', 'hover'], + ['pressIn', 'pressed'], + ['pressOut', 'hover'], + ['hoverOut', 'rest'], ] as const) { await fireEvent(getRoot(component), event, {}); expect(getIndicatorStyle(component)).toMatchObject({ - backgroundColor: status === 'unchecked' ? palette.backgroundNeutralTransparent : palette.backgroundBrandHeavy, - borderColor: status === 'unchecked' ? palette.strokeNeutralHeavy : palette.strokeNeutralTransparent, + backgroundColor: (status === 'unchecked' ? colors.backgroundNeutralTransparent : colors.backgroundBrandHeavy)[state], + borderColor: (status === 'unchecked' ? colors.strokeNeutralHeavy : colors.strokeNeutralTransparent)[state], }); expect(StyleSheet.flatten(component.getByTestId('checkbox-label').props.style).color).toBe( - status === 'unchecked' ? palette.foregroundNeutralSecondary : palette.foregroundNeutralPrimary, + (status === 'unchecked' ? colors.foregroundNeutralSecondary : colors.foregroundNeutralPrimary)[state], ); expect(StyleSheet.flatten(component.getByTestId('checkbox-secondary', { includeHiddenElements: true }).props.style).color).toBe( - palette.foregroundNeutralSecondary, + colors.foregroundNeutralSecondary[state], ); if (status !== 'unchecked') { expect(StyleSheet.flatten(component.getByText(status === 'checked' ? '\u2713' : '\u2212').props.style).color).toBe( - palette.foregroundBrandOnloud, + colors.foregroundBrandOnloud[state], ); } } @@ -515,17 +515,17 @@ describe('Checkbox', () => { await component.rerender(<Checkbox status={status} showSecondaryText disabled />); const colors = defaultFlexTokens.color; expect(getIndicatorStyle(component)).toMatchObject({ - backgroundColor: status === 'unchecked' ? colors.backgroundNeutralTransparent : colors.backgroundNeutralHeavyDisabled, - borderColor: status === 'unchecked' ? colors.strokeNeutralDisabled : colors.strokeNeutralTransparent, + backgroundColor: (status === 'unchecked' ? colors.backgroundNeutralTransparent : colors.backgroundNeutralHeavyDisabled).rest, + borderColor: (status === 'unchecked' ? colors.strokeNeutralDisabled : colors.strokeNeutralTransparent).rest, }); for (const id of ['checkbox-label', 'checkbox-secondary']) { expect(StyleSheet.flatten(component.getByTestId(id, { includeHiddenElements: true }).props.style).color).toBe( - colors.foregroundNeutralDisabled, + colors.foregroundNeutralDisabled.rest, ); } if (status !== 'unchecked') { expect(StyleSheet.flatten(component.getByText(status === 'checked' ? '\u2713' : '\u2212').props.style).color).toBe( - colors.foregroundNeutralDisabled, + colors.foregroundNeutralDisabled.rest, ); } }, diff --git a/packages/agentic/components/src/components/list-item/list-item.test.tsx b/packages/agentic/components/src/components/list-item/list-item.test.tsx index 8fcd5de26f..ffa7cc1a9a 100644 --- a/packages/agentic/components/src/components/list-item/list-item.test.tsx +++ b/packages/agentic/components/src/components/list-item/list-item.test.tsx @@ -49,8 +49,8 @@ describe('ListItem', () => { } expect(getRootStyle(component).backgroundColor).toBe( selected && selectionMode !== 'multiple' - ? defaultFlexTokens.color.backgroundNeutralSoft - : defaultFlexTokens.color.backgroundNeutralTransparent, + ? defaultFlexTokens.color.backgroundNeutralSoft.rest + : defaultFlexTokens.color.backgroundNeutralTransparent.rest, ); }); @@ -69,7 +69,7 @@ describe('ListItem', () => { it.each(['none', 'single', 'multiple'] as const)('LIT-004 suppresses selected fill while disabled in %s mode', async (selectionMode) => { const component = await renderListItem({ content: 'Unavailable', selected: true, disabled: true, selectionMode }); - expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralTransparent); + expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralTransparent.rest); expect(getRoot(component).props.accessibilityState).toEqual({ disabled: true, selected: true }); }); diff --git a/packages/agentic/components/src/components/progress-bar/progress-bar.test.tsx b/packages/agentic/components/src/components/progress-bar/progress-bar.test.tsx index 3a57613868..f4f20b7d9f 100644 --- a/packages/agentic/components/src/components/progress-bar/progress-bar.test.tsx +++ b/packages/agentic/components/src/components/progress-bar/progress-bar.test.tsx @@ -6,7 +6,6 @@ import { render } from '../../common/renderWithTheme'; import { useReducedMotion } from '@fluentui-react-native/framework-base'; import { defaultFlexTokens } from '@fluentui-react-native/design/testing'; -import { defaultFlexTokens } from '@fluentui-react-native/design/testing'; import { ProgressBar } from './progress-bar'; jest.mock('@fluentui-react-native/framework-base', () => ({ @@ -95,9 +94,9 @@ describe('ProgressBar', () => { }); const icon = component.getByTestId('validation-icon', { includeHiddenElements: true }); - expect(getIndicatorStyle(component).backgroundColor).toBe(defaultFlexTokens.color[token]); + expect(getIndicatorStyle(component).backgroundColor).toBe(defaultFlexTokens.color[token].rest); expect(StyleSheet.flatten(component.getByText('★', { includeHiddenElements: true }).props.style).color).toBe( - defaultFlexTokens.color[token], + defaultFlexTokens.color[token].rest, ); expect(icon.props.accessible).toBe(false); expect(StyleSheet.flatten(icon.props.style)).toMatchObject({ height: 16, width: 16 }); diff --git a/packages/agentic/components/src/components/skeleton/skeleton.test.tsx b/packages/agentic/components/src/components/skeleton/skeleton.test.tsx index 2ec51ec169..e68f17120b 100644 --- a/packages/agentic/components/src/components/skeleton/skeleton.test.tsx +++ b/packages/agentic/components/src/components/skeleton/skeleton.test.tsx @@ -80,7 +80,7 @@ describe('Skeleton', () => { await component.rerender(<Skeleton testID="skeleton" style={{ width: 120, height: 16 }} />); expect(animation.stop).toHaveBeenCalledTimes(1); expect(getRoot(component).children).toHaveLength(0); - expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralSoft); + expect(getRootStyle(component).backgroundColor).toBe(defaultFlexTokens.color.backgroundNeutralSoft.rest); mockUseReducedMotion.mockReturnValue(false); await component.rerender(<Skeleton testID="skeleton" style={{ width: 120, height: 16 }} />); diff --git a/packages/agentic/components/src/components/tab/tab.test.tsx b/packages/agentic/components/src/components/tab/tab.test.tsx index 3aa161bb07..50930d8e7e 100644 --- a/packages/agentic/components/src/components/tab/tab.test.tsx +++ b/packages/agentic/components/src/components/tab/tab.test.tsx @@ -69,11 +69,7 @@ describe('Tab', () => { } else if (interaction === 'pressed') { await fireEvent(getRoot(component), 'pressIn', {}); } - const expected = disabled - ? colors.foregroundNeutralDisabled - : interaction === 'rest' - ? colors[foreground] - : colors[interaction][foreground]; + const expected = disabled ? colors.foregroundNeutralDisabled.rest : colors[foreground][interaction]; const labels = component.getAllByText('Files', { includeHiddenElements: true }); expect(labels).toHaveLength(2); expect(labels.map((label) => StyleSheet.flatten(label.props.style).color)).toEqual([expected, expected]); From ca9f3f79e3e7c8c18332c7d745bade77d77c4ef1 Mon Sep 17 00:00:00 2001 From: Jason Morse <jasonmo360@gmail.com> Date: Mon, 2 Nov 2026 00:36:49 -0800 Subject: [PATCH 16/18] design: Fluent appearance sets, high-contrast theme, and Flex Storybook chrome - Generate light, dark, lightElevated, darkElevated, hcLight, and hcDark Fluent token sets for every platform. Elevated sets fall back to their base scheme, hcLight and hcDark fall back to each other, and missing high-contrast sets use light and dark. Windows high contrast uses the Win32 hc set as SystemColor brushes. - Add fluentHcTheme, and have fluentTheme select the high-contrast theme for the color scheme under high contrast. - Make default-theme use the design package's Fluent themes and remove its own token-building code, including createAliasTokens. - Keep the Storybook chrome and canvas on Flex; the Theme selector applies only to story content. - Update snapshots, the bundle-size baseline, docs, and changesets. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/default-theme-design-fluent.md | 9 + .changeset/design-complete-platform-tokens.md | 8 +- .changeset/design-fluent-themes.md | 11 +- .changeset/storybook-runtime-flex-chrome.md | 6 + apps/bundle-size/baseline.json | 74 +- apps/bundle-size/scenarios.json | 28 + .../ColorTokens/ColorTokenTest.tsx | 6 +- packages/agentic/design/README.md | 6 +- .../agentic/design/references/entry-points.md | 33 +- .../design/references/remaining-work.md | 16 +- packages/agentic/design/references/theming.md | 18 +- packages/agentic/design/references/tokens.md | 14 +- .../agentic/design/scripts/fluent-tokens.cts | 95 +- .../fluentTokens.generated.android.ts | 13 +- .../defaults/fluentTokens.generated.ios.ts | 23 +- .../defaults/fluentTokens.generated.macos.ts | 52 +- .../fluent/defaults/fluentTokens.generated.ts | 37 +- .../fluentTokens.generated.windows.ts | 244 +- .../src/fluent/defaults/fluentTokens.test.ts | 56 +- .../__snapshots__/entryPoints.test.ts.snap | 1 + .../compatibility/importBoundaries.test.ts | 8 +- .../src/themes/fluent/createFluentTheme.ts | 4 +- .../src/themes/fluent/fluentHcDarkTheme.ts | 8 + .../src/themes/fluent/fluentHcLightTheme.ts | 8 + .../design/src/themes/fluent/fluentHcTheme.ts | 15 + .../design/src/themes/fluent/fluentTheme.ts | 19 +- .../src/themes/fluent/fluentThemes.test.tsx | 71 +- packages/agentic/design/src/themes/index.ts | 1 + .../storybook-desktop-runtime/AGENTS.md | 5 +- .../references/runtime-contract.md | 40 +- .../src/StorybookTheme.test.tsx | 67 +- .../src/StorybookTheme.tsx | 40 +- .../src/ThemedStorybookUI.tsx | 9 +- .../__snapshots__/Badge.test.tsx.snap | 73 +- .../src/FAB/__snapshots__/FAB.test.tsx.snap | 10 +- .../__snapshots__/ToggleButton.test.tsx.snap | 2 +- .../src/__snapshots__/Button.test.tsx.snap | 28 +- .../ColorTokens.test.win32.ts.snap | 8 + .../ColorTokens.test.windows.ts.snap | 8 + .../__snapshots__/Button.test.tsx.snap | 11 +- .../ColorTokens.test.win32.ts.snap | 1 + .../ColorTokens.test.windows.ts.snap | 1 + .../__snapshots__/Checkbox.test.tsx.snap | 1 + .../ChipColorTokens.test.win32.ts.snap | 15 + .../__snapshots__/Chip.test.tsx.snap | 10 +- .../ContextualMenu.test.tsx.snap | 2 +- .../__snapshots__/Divider.test.tsx.snap | 2 +- .../__snapshots__/Input.test.tsx.snap | 65 +- .../__snapshots__/Link.test.tsx.snap | 24 +- .../__snapshots__/Link.test.tsx.snap | 12 +- .../__snapshots__/Notification.test.tsx.snap | 8 +- .../RadioExperimental.test.tsx.snap | 12 +- .../RadioGroupExperimental.test.tsx.snap | 128 +- .../ColorTokens.test.win32.ts.snap | 1 + .../ColorTokens.test.windows.ts.snap | 1 + .../__snapshots__/RadioButton.test.tsx.snap | 14 +- .../RadioButtonGroup.test.tsx.snap | 68 +- .../__snapshots__/Stack.test.tsx.snap | 6 +- .../__snapshots__/Switch.test.tsx.snap | 12 +- .../__tests__/__snapshots__/Tab.test.tsx.snap | 56 +- .../__snapshots__/TabList.test.tsx.snap | 213 +- .../__snapshots__/Text.test.tsx.snap | 30 +- packages/theming/default-theme/README.md | 5 +- packages/theming/default-theme/package.json | 4 +- .../__snapshots__/default-theme.test.ts.snap | 5562 ++++++++--------- .../defaultThemes.test.android.ts.snap | 2619 ++++++-- .../defaultThemes.test.ios.ts.snap | 2633 ++++++-- .../defaultThemes.test.macos.ts.snap | 3028 +++++---- .../defaultThemes.test.win32.ts.snap | 5470 ++++++++++++---- .../defaultThemes.test.windows.ts.snap | 5404 ++++++++++++---- .../src/__tests__/default-theme.test.ts | 20 +- .../__tests__/defaultThemes.test.android.ts | 11 +- .../src/__tests__/defaultThemes.test.ios.ts | 11 +- .../src/__tests__/defaultThemes.test.macos.ts | 11 +- .../src/__tests__/defaultThemes.test.win32.ts | 11 +- .../__tests__/defaultThemes.test.windows.ts | 11 +- .../default-theme/src/createAliasTokens.ts | 18 - .../default-theme/src/createDefaultTheme.ts | 40 +- .../default-theme/src/defaultColors.ts | 325 - .../theming/default-theme/src/defaultTheme.ts | 19 - packages/theming/default-theme/src/index.ts | 3 +- .../src/stockWebPalette.macos.ts | 82 - .../default-theme/src/stockWebPalette.ts | 107 - .../src/stockWebPalette.win32.ts | 82 - packages/theming/default-theme/tsconfig.json | 3 - .../__snapshots__/win32-theme.test.ts.snap | 76 +- yarn.lock | 2 - 87 files changed, 17686 insertions(+), 9738 deletions(-) create mode 100644 .changeset/default-theme-design-fluent.md create mode 100644 .changeset/storybook-runtime-flex-chrome.md create mode 100644 packages/agentic/design/src/themes/fluent/fluentHcDarkTheme.ts create mode 100644 packages/agentic/design/src/themes/fluent/fluentHcLightTheme.ts create mode 100644 packages/agentic/design/src/themes/fluent/fluentHcTheme.ts delete mode 100644 packages/theming/default-theme/src/createAliasTokens.ts delete mode 100644 packages/theming/default-theme/src/defaultColors.ts delete mode 100644 packages/theming/default-theme/src/defaultTheme.ts delete mode 100644 packages/theming/default-theme/src/stockWebPalette.macos.ts delete mode 100644 packages/theming/default-theme/src/stockWebPalette.ts delete mode 100644 packages/theming/default-theme/src/stockWebPalette.win32.ts diff --git a/.changeset/default-theme-design-fluent.md b/.changeset/default-theme-design-fluent.md new file mode 100644 index 0000000000..b9342af2b5 --- /dev/null +++ b/.changeset/default-theme-design-fluent.md @@ -0,0 +1,9 @@ +--- +'@fluentui-react-native/default-theme': minor +--- + +Use the design package's Fluent themes instead of building default tokens locally. `defaultFluentTheme` and +`defaultFluentDarkTheme` are now the design package's `fluentLightTheme` and `fluentDarkTheme`, and `createDefaultTheme` +resolves its `fluentTheme`, so each platform uses its own generated Fluent tokens (macOS previously used the Windows +set) and high contrast follows the color scheme. Breaking: `createAliasTokens` is removed; read alias colors from +`theme.colors` instead. diff --git a/.changeset/design-complete-platform-tokens.md b/.changeset/design-complete-platform-tokens.md index 6aece2dd32..3aeacd129a 100644 --- a/.changeset/design-complete-platform-tokens.md +++ b/.changeset/design-complete-platform-tokens.md @@ -3,5 +3,9 @@ --- Generate complete Fluent color, shadow, font, and appearance token sets for Win32, Windows, macOS, iOS, and Android. -Preserve native values and fill missing tokens with same-platform equivalents, then portable same-scheme defaults. -Use platform global typography when font aliases are absent and enforce required generated token types. +Every platform provides light, dark, light elevated, dark elevated, high-contrast light, and high-contrast dark sets. +Elevated sets fall back to their color scheme, high-contrast light falls back to high-contrast dark, and platforms +without high-contrast data use light and dark. Windows high contrast uses the Win32 high-contrast set with Windows +system color brushes. Preserve native values and fill missing tokens with same-platform equivalents, then portable +same-scheme defaults. Use platform global typography when font aliases are absent and enforce required generated token +types. diff --git a/.changeset/design-fluent-themes.md b/.changeset/design-fluent-themes.md index 4e59429ed1..ce767bf806 100644 --- a/.changeset/design-fluent-themes.md +++ b/.changeset/design-fluent-themes.md @@ -2,8 +2,9 @@ '@fluentui-react-native/design': minor --- -Add the `@fluentui-react-native/design/themes` entry point with `fluentLightTheme`, `fluentDarkTheme`, and `fluentTheme`. -The themes are built from the generated Fluent 2 alias colors, shadows, font aliases, and global tokens rather than -hand-authored values, and each legacy palette color points at the alias color that plays its role. `fluentTheme` is a -`ThemeReference` that follows the system appearance, and the `appearance` prop of `ThemeProvider` or `ThemedRoot` -overrides it. High-contrast and elevated appearances resolve by color scheme for now. +Add the `@fluentui-react-native/design/themes` entry point with `fluentLightTheme`, `fluentDarkTheme`, `fluentHcTheme`, +and `fluentTheme`. The themes are built from the generated Fluent 2 alias colors, shadows, font aliases, and global +tokens rather than hand-authored values, and each legacy palette color points at the alias color that plays its role. +`fluentTheme` is a `ThemeReference` that follows the system appearance, including high contrast, and the `appearance` +prop of `ThemeProvider` or `ThemedRoot` overrides it. `fluentHcTheme` always resolves the high-contrast theme for the +color scheme. Elevated appearances resolve by color scheme for now. diff --git a/.changeset/storybook-runtime-flex-chrome.md b/.changeset/storybook-runtime-flex-chrome.md new file mode 100644 index 0000000000..295c154a52 --- /dev/null +++ b/.changeset/storybook-runtime-flex-chrome.md @@ -0,0 +1,6 @@ +--- +'@fluentui-react-native/storybook-desktop-runtime': patch +--- + +Keep the Storybook chrome and story canvas on the Flex theme. The Theme selector now applies Flex or Fluent only to +story content, while scheme, contrast, and tone still apply to the chrome. diff --git a/apps/bundle-size/baseline.json b/apps/bundle-size/baseline.json index e4190fe37e..8dbb042906 100644 --- a/apps/bundle-size/baseline.json +++ b/apps/bundle-size/baseline.json @@ -136,30 +136,46 @@ { "platform": "macos", "scenario": "design-fluent-light-theme", - "rawBytes": 18743, - "gzipBytes": 4010, + "rawBytes": 18739, + "gzipBytes": 4009, "moduleCount": 7, - "metafileInputCount": 64, + "metafileInputCount": 67, "workspaceModules": { "@fluentui-react-native/design": 6 }, "workspaceBytes": { - "@fluentui-react-native/design": 18707 + "@fluentui-react-native/design": 18703 } }, { "platform": "macos", "scenario": "design-fluent-theme", - "rawBytes": 27314, - "gzipBytes": 6684, + "rawBytes": 27436, + "gzipBytes": 6730, + "moduleCount": 34, + "metafileInputCount": 67, + "workspaceModules": { + "@fluentui-react-native/design": 15, + "@fluentui-react-native/framework-base": 18 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 25427, + "@fluentui-react-native/framework-base": 1973 + } + }, + { + "platform": "macos", + "scenario": "design-fluent-hc-theme", + "rawBytes": 27343, + "gzipBytes": 6694, "moduleCount": 32, - "metafileInputCount": 64, + "metafileInputCount": 67, "workspaceModules": { "@fluentui-react-native/design": 13, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 25306, + "@fluentui-react-native/design": 25335, "@fluentui-react-native/framework-base": 1972 } }, @@ -169,7 +185,7 @@ "rawBytes": 23368, "gzipBytes": 8032, "moduleCount": 33, - "metafileInputCount": 64, + "metafileInputCount": 67, "workspaceModules": { "@fluentui-react-native/design": 16, "@fluentui-react-native/framework-base": 16 @@ -185,7 +201,7 @@ "rawBytes": 23432, "gzipBytes": 8064, "moduleCount": 33, - "metafileInputCount": 64, + "metafileInputCount": 67, "workspaceModules": { "@fluentui-react-native/design": 16, "@fluentui-react-native/framework-base": 16 @@ -330,31 +346,47 @@ { "platform": "windows", "scenario": "design-fluent-light-theme", - "rawBytes": 17820, - "gzipBytes": 3849, + "rawBytes": 22592, + "gzipBytes": 4610, "moduleCount": 7, - "metafileInputCount": 65, + "metafileInputCount": 68, "workspaceModules": { "@fluentui-react-native/design": 6 }, "workspaceBytes": { - "@fluentui-react-native/design": 17784 + "@fluentui-react-native/design": 22556 } }, { "platform": "windows", "scenario": "design-fluent-theme", - "rawBytes": 26332, - "gzipBytes": 6479, + "rawBytes": 31229, + "gzipBytes": 7311, + "moduleCount": 34, + "metafileInputCount": 68, + "workspaceModules": { + "@fluentui-react-native/design": 15, + "@fluentui-react-native/framework-base": 18 + }, + "workspaceBytes": { + "@fluentui-react-native/design": 29208, + "@fluentui-react-native/framework-base": 1985 + } + }, + { + "platform": "windows", + "scenario": "design-fluent-hc-theme", + "rawBytes": 31131, + "gzipBytes": 7279, "moduleCount": 32, - "metafileInputCount": 65, + "metafileInputCount": 68, "workspaceModules": { "@fluentui-react-native/design": 13, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 24324, - "@fluentui-react-native/framework-base": 1972 + "@fluentui-react-native/design": 29110, + "@fluentui-react-native/framework-base": 1985 } }, { @@ -363,7 +395,7 @@ "rawBytes": 23356, "gzipBytes": 8025, "moduleCount": 33, - "metafileInputCount": 65, + "metafileInputCount": 68, "workspaceModules": { "@fluentui-react-native/design": 16, "@fluentui-react-native/framework-base": 16 @@ -379,7 +411,7 @@ "rawBytes": 23420, "gzipBytes": 8058, "moduleCount": 33, - "metafileInputCount": 65, + "metafileInputCount": 68, "workspaceModules": { "@fluentui-react-native/design": 16, "@fluentui-react-native/framework-base": 16 diff --git a/apps/bundle-size/scenarios.json b/apps/bundle-size/scenarios.json index 8047be37f0..b6bb2418bf 100644 --- a/apps/bundle-size/scenarios.json +++ b/apps/bundle-size/scenarios.json @@ -92,6 +92,7 @@ "forbiddenOutputPatterns": [ "/design/src/themes/fluent/fluentDarkTheme.", "/design/src/themes/fluent/fluentTheme.", + "/design/src/themes/fluent/fluentHc", "/design/src/fluent/themeReference.", "/design/src/flex/", "/design/src/themes/flex/", @@ -114,6 +115,33 @@ "/design/src/themes/fluent/fluentTheme.", "/design/src/themes/fluent/fluentLightTheme.", "/design/src/themes/fluent/fluentDarkTheme.", + "/design/src/themes/fluent/fluentHcLightTheme.", + "/design/src/themes/fluent/fluentHcDarkTheme.", + "/design/src/fluent/themeReference." + ] + }, + { + "name": "design-fluent-hc-theme", + "module": "@fluentui-react-native/design/themes", + "exports": ["fluentHcTheme"], + "forbiddenInputPatterns": [ + "/design/src/fluent/compat/", + "/design/src/fluent/tokens/", + "/design/src/fluent/useTheme.", + "/design/src/test/" + ], + "forbiddenOutputPatterns": [ + "/design/src/themes/fluent/fluentLightTheme.", + "/design/src/themes/fluent/fluentDarkTheme.", + "/design/src/themes/fluent/fluentTheme.", + "/design/src/flex/", + "/design/src/themes/flex/", + "/color-lib/" + ], + "requiredOutputPatterns": [ + "/design/src/themes/fluent/fluentHcTheme.", + "/design/src/themes/fluent/fluentHcLightTheme.", + "/design/src/themes/fluent/fluentHcDarkTheme.", "/design/src/fluent/themeReference." ] }, diff --git a/apps/tester-core/src/TestComponents/ColorTokens/ColorTokenTest.tsx b/apps/tester-core/src/TestComponents/ColorTokens/ColorTokenTest.tsx index 76695950f4..e0501bb8b3 100644 --- a/apps/tester-core/src/TestComponents/ColorTokens/ColorTokenTest.tsx +++ b/apps/tester-core/src/TestComponents/ColorTokens/ColorTokenTest.tsx @@ -3,14 +3,12 @@ import type { ViewStyle, ColorValue } from 'react-native'; import { View, StyleSheet, Platform } from 'react-native'; import { Text, ToggleButton } from '@fluentui/react-native'; -import { createAliasTokens } from '@fluentui-react-native/default-theme'; import { COLORTOKENS_TEST_COMPONENT, COLORTOKEN_TESTPAGE } from '@fluentui-react-native/e2e-testing'; import type { SvgIconProps } from '@fluentui-react-native/icon'; import { globalTokens } from '@fluentui-react-native/design/tokens/legacy'; import type { Theme } from '@fluentui-react-native/design/theming'; import { useTheme } from '@fluentui-react-native/design/theming'; import { themedStyleSheet } from '@fluentui-react-native/design/styling/stylesheet'; -import { getCurrentAppearance } from '@fluentui-react-native/design/theming'; import { createOfficeAliasTokens } from '@fluentui-react-native/win32-theme'; import type { SvgProps } from 'react-native-svg'; import Svg, { G, Path } from 'react-native-svg'; @@ -100,9 +98,7 @@ const AliasColorTokensSwatchList: React.FunctionComponent = () => { theme.name === 'Black' || theme.name === 'HighContrast'; - const aliasColorTokens = isOfficeTheme - ? createOfficeAliasTokens(theme.name) - : createAliasTokens(getCurrentAppearance(theme.host.appearance, 'light')); + const aliasColorTokens = isOfficeTheme ? createOfficeAliasTokens(theme.name) : theme.colors; const aggregator = React.useCallback( (colorName: string) => { diff --git a/packages/agentic/design/README.md b/packages/agentic/design/README.md index f29a7033f8..904c360512 100644 --- a/packages/agentic/design/README.md +++ b/packages/agentic/design/README.md @@ -29,7 +29,8 @@ export const App = () => ( Existing `ThemeReference` themes and `useTheme` consumers keep working under the same provider; the [theming reference](references/theming.md) explains both authoring models and how they interoperate. -Fluent's own light and dark themes ship in the `themes` entry point, and `fluentTheme` follows the system appearance: +Fluent's own light, dark, and high-contrast themes ship in the `themes` entry point, and `fluentTheme` follows the +system appearance, including high contrast: ```tsx import { ThemedRoot } from '@fluentui-react-native/design'; @@ -42,7 +43,8 @@ export const App = () => ( ); ``` -Use `fluentLightTheme` or `fluentDarkTheme` when you need one fixed `Theme` object. +Use `fluentLightTheme` or `fluentDarkTheme` when you need one fixed `Theme` object, or `fluentHcTheme` to always use +high contrast. The same entry point ships the x3 Flex defaults as `flexTheme` (cool) and `flexWarmTheme` (warm). Each is a `FlexThemeDescription` covering light and dark; use one as a `FlexThemeReference` base to start from that palette and diff --git a/packages/agentic/design/references/entry-points.md b/packages/agentic/design/references/entry-points.md index 0bcc7f1d95..d3d680cedc 100644 --- a/packages/agentic/design/references/entry-points.md +++ b/packages/agentic/design/references/entry-points.md @@ -10,21 +10,21 @@ owner_paths: The package is `sideEffects: false` and exposes explicit subpaths so consumers load only the graph they use. Export public symbols by name from each entry point; do not add barrel re-exports. -| Subpath | Contents | -| --------------------------- | --------------------------------------------------------------------------------------------------------- | -| `.` (root) | Modern theming (`ThemeProvider`, `ThemedRoot`, `FlexThemeReference`, hooks), Flex token types | -| `./theming` | The complete modern and legacy theming API, including `ThemeReference` and `useTheme` | -| `./theming/legacy-source` | `ThemeReference` without the legacy consumption graph | -| `./theming/compat` | `themeFromFlexTokens` and `getDefaultLegacyTheme` | -| `./theming/compat/defaults` | `getDefaultLegacyTheme` alone, for platform theme packages | -| `./themes` | Ready-made themes: `fluentLightTheme`, `fluentDarkTheme`, `fluentTheme`, `flexTheme`, and `flexWarmTheme` | -| `./tokens/global` | Generated platform global token constants | -| `./tokens/legacy` | Legacy alias, shadow, and global token data | -| `./color-lib` | Raw color parsing, conversion, compositing, and interaction algorithms; see `color-lib.md` | -| `./styling` | State and color style factories; see `styling.md` | -| `./styling/stylesheet` | The legacy `themedStyleSheet` helper | -| `./styling/tokens` | Legacy token-to-style builders | -| `./testing` | Test-only fixtures and validation; see `testing.md` | +| Subpath | Contents | +| --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `.` (root) | Modern theming (`ThemeProvider`, `ThemedRoot`, `FlexThemeReference`, hooks), Flex token types | +| `./theming` | The complete modern and legacy theming API, including `ThemeReference` and `useTheme` | +| `./theming/legacy-source` | `ThemeReference` without the legacy consumption graph | +| `./theming/compat` | `themeFromFlexTokens` and `getDefaultLegacyTheme` | +| `./theming/compat/defaults` | `getDefaultLegacyTheme` alone, for platform theme packages | +| `./themes` | Ready-made themes: `fluentLightTheme`, `fluentDarkTheme`, `fluentHcTheme`, `fluentTheme`, `flexTheme`, and `flexWarmTheme` | +| `./tokens/global` | Generated platform global token constants | +| `./tokens/legacy` | Legacy alias, shadow, and global token data | +| `./color-lib` | Raw color parsing, conversion, compositing, and interaction algorithms; see `color-lib.md` | +| `./styling` | State and color style factories; see `styling.md` | +| `./styling/stylesheet` | The legacy `themedStyleSheet` helper | +| `./styling/tokens` | Legacy token-to-style builders | +| `./testing` | Test-only fixtures and validation; see `testing.md` | The `apps/bundle-size` `design-*` scenarios guard these boundaries. Input patterns check the import graph and output patterns check the modules a tree-shaken bundle retains. The modern root and legacy-source scenarios forbid the @@ -33,7 +33,8 @@ scenario, which pairs a legacy `ThemeReference` with `useThemeState`, require th `color-lib/interaction`; the legacy-source scenario also forbids a retained `FlexThemeReference`. Only the legacy theme scenario forbids any retained `color-lib/` or `flex/` module. The Fluent theme scenarios forbid `useTheme` and the compatibility and legacy-token modules from the import graph and any retained `flex/`, `color-lib/`, or Flex theme -module, and a bundle that imports only `fluentLightTheme` retains neither the dark theme nor `ThemeReference`. The Flex +module, and a bundle that imports only `fluentLightTheme` retains no other theme and no `ThemeReference`, while one that +imports only `fluentHcTheme` retains only the high-contrast themes. The Flex theme scenarios require the x3 defaults and forbid `fluent/` and `color-lib/compositing`. The color-library and legacy-projection scenarios require their expected modules. Every scenario also requires a module it is expected to load, so a moved file cannot make a forbidden pattern pass vacuously. diff --git a/packages/agentic/design/references/remaining-work.md b/packages/agentic/design/references/remaining-work.md index bff2481262..4413828630 100644 --- a/packages/agentic/design/references/remaining-work.md +++ b/packages/agentic/design/references/remaining-work.md @@ -71,14 +71,14 @@ behavior is documented in `theming.md`, `tokens.md`, and `entry-points.md`. repository's user documentation covers `ThemedRoot` but still teaches custom themes only through `ThemeReference`. - **Done when:** the user documentation includes the migration example and links to this package's theming reference. -## Fluent high-contrast and elevated themes - -- **Outcome:** `fluentTheme` selects distinct themes for high-contrast and elevated appearances. -- **Current state:** `themes` provides only light and dark Fluent themes. The generated Fluent tokens already supply - the `hc`, `hcLight`, `hcDark`, `darkGray`, and `darkElevated` color and shadow sets (`tokens.md`), but `fluentTheme` - resolves high-contrast and elevated requests by color scheme alone. -- **Done when:** the owner approves how each appearance maps to those sets, including iOS, whose high-contrast files - carry no colors, and `fluentTheme` selects the matching theme by the resolved appearance. +## Fluent elevated themes + +- **Outcome:** `fluentTheme` selects distinct themes for elevated appearances. +- **Current state:** `themes` provides light, dark, and high-contrast Fluent themes. The generated Fluent tokens already + supply `lightElevated` and `darkElevated` color and shadow sets (`tokens.md`), but `fluentTheme` resolves elevated + requests by color scheme alone. +- **Done when:** the owner approves how elevated appearances map to those sets, and `fluentTheme` selects the matching + theme by the resolved interface level. ## Dependent work owned by other packages diff --git a/packages/agentic/design/references/theming.md b/packages/agentic/design/references/theming.md index 9f04f245ee..768603d125 100644 --- a/packages/agentic/design/references/theming.md +++ b/packages/agentic/design/references/theming.md @@ -131,11 +131,12 @@ including `darkElevated`, `highContrast`, and `dynamic`. `getCurrentAppearance`, The `themes` entry point provides legacy `Theme` objects authored from the generated Fluent 2 tokens (`tokens.md`): -| Export | Kind | Contents | -| ------------------ | ---------------- | ------------------------------------------------ | -| `fluentLightTheme` | `Theme` | The light theme | -| `fluentDarkTheme` | `Theme` | The dark theme | -| `fluentTheme` | `ThemeReference` | Both themes, chosen by the resolved color scheme | +| Export | Kind | Contents | +| ------------------ | ---------------- | ---------------------------------------------------------------------- | +| `fluentLightTheme` | `Theme` | The light theme | +| `fluentDarkTheme` | `Theme` | The dark theme | +| `fluentHcTheme` | `ThemeReference` | The high-contrast light and dark themes, chosen by the resolved scheme | +| `fluentTheme` | `ThemeReference` | Every Fluent theme, chosen by the resolved contrast and color scheme | Each theme carries every platform alias color unchanged, plus the legacy palette keys (`bodyText`, `buttonBackground`, and so on) that existing components still read. `src/themes/fluent/legacyPalette.ts` points each legacy key at the alias @@ -146,9 +147,10 @@ platform's theme carries that platform's values. Fluent 2 defines no serif or cu family. The themes carry no component token overrides. `fluentTheme` requests `system` for every appearance axis, so a `ThemeProvider` or `ThemedRoot` follows the platform -appearance source and re-resolves when the system changes; pass `appearance` to pin a color scheme. Contrast and -interface level do not select separate themes yet: high-contrast and elevated requests resolve by color scheme -(`remaining-work.md`). Import `fluentLightTheme` or `fluentDarkTheme` alone to keep the other theme and `ThemeReference` +appearance source and re-resolves when the system changes; pass `appearance` to pin a color scheme or contrast. High +contrast selects the high-contrast theme for the color scheme. `fluentHcTheme` always requests high contrast and follows +the system color scheme. Interface level does not select separate themes yet: elevated requests resolve by color scheme +(`remaining-work.md`). Import `fluentLightTheme` or `fluentDarkTheme` alone to keep the other themes and `ThemeReference` out of a bundle, or use one as the base of your own `ThemeReference` to extend it. Flex consumers read these themes through `useThemeState`, which adapts their alias colors like any legacy source. diff --git a/packages/agentic/design/references/tokens.md b/packages/agentic/design/references/tokens.md index 67eb4e8259..859e619b4a 100644 --- a/packages/agentic/design/references/tokens.md +++ b/packages/agentic/design/references/tokens.md @@ -45,18 +45,20 @@ contain complete Fluent alias colors, shadows, and font aliases, which the `them The runtime pipeline mappers and existing theme construction are unchanged. Do not edit generated files; change their inputs and rebuild. -Every generated platform module exports `light`, `dark`, `darkGray`, `hc`, `hcLight`, `hcDark`, and `darkElevated` -color and shadow sets, plus `fontAliasTokens`. Colors satisfy `Required<AliasColorTokens>` (including deprecated red +Every generated platform module exports `light`, `dark`, `lightElevated`, `darkElevated`, `hcLight`, and `hcDark` color +and shadow sets, plus `fontAliasTokens`. Colors satisfy `Required<AliasColorTokens>` (including deprecated red aliases, mapped to danger), fonts satisfy `Required<Variants>`, and shadows satisfy `BaseShadowAliasTokens`. The generator preserves defined runtime-mapped values and additional native color states that those mappers omit. Missing colors use same-platform semantic equivalents first, with absent interaction states falling back to rest. Remaining gaps use portable light/dark defaults assembled from the Win32 and mobile palettes, never another platform's system colors. Explicit equivalents live in the [Fluent token generator](../scripts/fluent-tokens.cts). -Unsupported appearances inherit their nearest supported source: dark gray and elevated dark use dark, `hc` uses -high-contrast dark, and missing high-contrast palettes use the matching light/dark scheme. Win32's single `hc` palette -supplies both high-contrast schemes. iOS's high-contrast files contain fonts but no colors, so they inherit the matching -standard colors; this is coverage, not a synthesized or accessibility-qualified high-contrast palette. Native shadow +An appearance without platform data inherits the nearest supported set: an elevated set uses its color scheme's +standard set, a single high-contrast set serves both color schemes, and a platform without high-contrast data uses +light and dark. Win32's Dark Gray palette is its elevated dark set, and its single `hc` palette of system colors is +`hcDark`. Windows has no high-contrast palette, so it uses the Win32 `hc` palette as `SystemColor…Color` Windows +brushes. iOS's high-contrast files contain fonts but no colors, so they inherit the matching standard colors; this is +coverage, not a synthesized or accessibility-qualified high-contrast palette. Native shadow sets remain intact. Missing font aliases use native equivalents, or the platform's global typography ramp when no aliases exist (macOS and Windows); legacy variant names alias the completed Fluent variants. Tests compare all platforms against the full token interfaces and reject missing or undefined entries. diff --git a/packages/agentic/design/scripts/fluent-tokens.cts b/packages/agentic/design/scripts/fluent-tokens.cts index 9f71395453..28f27f6d79 100644 --- a/packages/agentic/design/scripts/fluent-tokens.cts +++ b/packages/agentic/design/scripts/fluent-tokens.cts @@ -5,34 +5,51 @@ const { GeneratedFile, ValuePool, expression, makeComment } = require('@fluentui const path = require('node:path'); const { mapPipelineToShadow } = require('../src/fluent/mapPipelineToShadow.ts'); -type Appearance = 'light' | 'dark' | 'darkGray' | 'hc' | 'hcLight' | 'hcDark' | 'darkElevated'; +type Appearance = 'light' | 'dark' | 'lightElevated' | 'darkElevated' | 'hcLight' | 'hcDark'; type ColorKey = keyof AliasColorTokens; type PipelineTokens = Record<string, Record<string, string | number>>; type PlatformData = { - /** Token package directory for each supported appearance. Light supplies the font aliases. */ + /** Token package directory for each appearance the platform supplies. Light supplies the font aliases. */ paths: Partial<Record<Appearance, string>> & { light: string; dark: string }; /** Pipeline mapper module in src/fluent for the platform. */ mapper: string; filename: string; + /** Native name for a pipeline `PlatformColor(Name)` system color. Defaults to the Win32 name. */ + platformColorName?: (name: string) => string; }; -const appearanceFallbacks: Record<Exclude<Appearance, 'light' | 'dark'>, Appearance> = { - darkGray: 'dark', - hc: 'hcDark', +const appearances: Appearance[] = ['light', 'dark', 'lightElevated', 'darkElevated', 'hcLight', 'hcDark']; + +/** The color scheme of each appearance, which selects the base aliases and portable defaults beneath it. */ +const appearanceSchemes: Record<Appearance, 'light' | 'dark'> = { + light: 'light', + dark: 'dark', + lightElevated: 'light', + darkElevated: 'dark', hcLight: 'light', hcDark: 'dark', - darkElevated: 'dark', }; -const appearances: Appearance[] = ['light', 'dark', 'darkGray', 'hc', 'hcLight', 'hcDark', 'darkElevated']; + +/** + * Appearances to use, in order, when a platform has no token data for an appearance. A single high-contrast set + * serves both color schemes; without one, high contrast uses the standard set for its scheme. + */ +const appearanceFallbacks: Record<Exclude<Appearance, 'light' | 'dark'>, Appearance[]> = { + lightElevated: ['light'], + darkElevated: ['dark'], + hcLight: ['hcDark', 'light'], + hcDark: ['hcLight', 'dark'], +}; const platformPaths: Record<string, PlatformData> = { win32: { paths: { light: '@fluentui-react-native/design-tokens-win32/colorful/', dark: '@fluentui-react-native/design-tokens-win32/black/', - darkGray: '@fluentui-react-native/design-tokens-win32/darkgray/', - hc: '@fluentui-react-native/design-tokens-win32/hc/', + // Office Dark Gray serves as the elevated dark set, and the one high-contrast set of system colors as dark. + darkElevated: '@fluentui-react-native/design-tokens-win32/darkgray/', + hcDark: '@fluentui-react-native/design-tokens-win32/hc/', }, mapper: 'mapPipelineToTheme.ts', filename: 'fluentTokens.generated.ts', @@ -51,7 +68,10 @@ const platformPaths: Record<string, PlatformData> = { paths: { light: '@fluentui-react-native/design-tokens-windows/light/', dark: '@fluentui-react-native/design-tokens-windows/dark/', + // Windows has no high-contrast set, so it uses the Win32 system colors as Windows brushes, as the legacy tokens do. + hcDark: '@fluentui-react-native/design-tokens-win32/hc/', }, + platformColorName: (name) => `SystemColor${name}Color`, mapper: 'mapPipelineToTheme.ts', filename: 'fluentTokens.generated.windows.ts', }, @@ -278,25 +298,28 @@ function mapFonts(platformData: PlatformData): Record<string, VariantValue> { return variants; } -function resolveAppearance(platformData: PlatformData, appearance: Appearance): string { - if (platformData.paths[appearance]) { - return platformData.paths[appearance]; - } - if ((appearance === 'hcLight' || appearance === 'hcDark') && platformData.paths.hc) { - return platformData.paths.hc; +/** The appearance whose token data supplies an appearance: its own, or the first fallback the platform supplies. */ +function sourceAppearance(platformData: PlatformData, appearance: Appearance): Appearance { + const candidates = appearance === 'light' || appearance === 'dark' ? [appearance] : [appearance, ...appearanceFallbacks[appearance]]; + const source = candidates.find((candidate) => platformData.paths[candidate]); + if (!source) { + throw new Error(`No token data for the ${appearance} appearance`); } - return resolveAppearance(platformData, appearanceFallbacks[appearance as keyof typeof appearanceFallbacks]); + return source; +} + +function sourcePath(platformData: PlatformData, appearance: Appearance): string { + return platformData.paths[sourceAppearance(platformData, appearance)] as string; } function appearanceScheme(platformData: PlatformData, appearance: Appearance): 'light' | 'dark' { - const source = resolveAppearance(platformData, appearance); - return source === platformData.paths.light || source === platformData.paths.hcLight ? 'light' : 'dark'; + return appearanceSchemes[sourceAppearance(platformData, appearance)]; } function readAliases(platformData: PlatformData, appearance: Appearance): PipelineTokens { const scheme = appearanceScheme(platformData, appearance); const base: PipelineTokens = require(`${platformData.paths[scheme]}tokens-aliases.json`); - const tokens: PipelineTokens = require(`${resolveAppearance(platformData, appearance)}tokens-aliases.json`); + const tokens: PipelineTokens = require(`${sourcePath(platformData, appearance)}tokens-aliases.json`); return Object.fromEntries( [...new Set([...Object.keys(base), ...Object.keys(tokens)])].map((key) => [key, { ...base[key], ...tokens[key] }]), ); @@ -305,10 +328,10 @@ function readAliases(platformData: PlatformData, appearance: Appearance): Pipeli const platformColorPattern = /^PlatformColor\(([A-Za-z][A-Za-z0-9]*)\)$/; /** - * Replace the pipeline's `PlatformColor(Name)` strings with PlatformColor calls, as processAliasTokens does at runtime - * with win32 color names. + * Replace the pipeline's `PlatformColor(Name)` strings with PlatformColor calls of the platform's system color names, as + * processAliasTokens does at runtime. */ -function toCodeValues(value: unknown, platformColors: Set<string>): unknown { +function toCodeValues(value: unknown, platformColors: Set<string>, colorName: (name: string) => string): unknown { if (typeof value === 'string') { const match = platformColorPattern.exec(value); if (!match) { @@ -317,14 +340,15 @@ function toCodeValues(value: unknown, platformColors: Set<string>): unknown { } return value; } - platformColors.add(match[1]); - return expression(`PlatformColor('${match[1]}')`, { pure: true, name: `platformColor${match[1]}` }); + const name = colorName(match[1]); + platformColors.add(name); + return expression(`PlatformColor('${name}')`, { pure: true, name: `platformColor${match[1]}` }); } if (Array.isArray(value)) { - return value.map((item) => toCodeValues(item, platformColors)); + return value.map((item) => toCodeValues(item, platformColors, colorName)); } if (value && typeof value === 'object') { - return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, toCodeValues(item, platformColors)])); + return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, toCodeValues(item, platformColors, colorName)])); } return value; } @@ -346,7 +370,8 @@ function generatePlatformFluentTokens( generatedFile.header = makeComment([ 'WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually.', 'Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults.', - 'Unsupported appearances inherit the closest supported appearance. Shared values are emitted once.', + 'An appearance without token data inherits elevated from standard, and high contrast from the other', + 'high-contrast appearance, else from standard. Shared values are emitted once.', ]); const pool = new ValuePool({ name: nameValue }); const typeImports = { @@ -356,18 +381,24 @@ function generatePlatformFluentTokens( }; pool.reserve(...Object.keys(typeImports)); + // Appearances with token data come first, so each inherited appearance is emitted as an alias of its source. + const ordered = [ + ...appearances.filter((appearance) => platformData.paths[appearance]), + ...appearances.filter((appearance) => !platformData.paths[appearance]), + ]; const platformColors = new Set<string>(); - for (const appearance of appearances) { - const packagePath = resolveAppearance(platformData, appearance); - pool.declare(`${appearance}Shadows`, mapPipelineToShadow(require(`${packagePath}tokens-shadow.json`)), { + for (const appearance of ordered) { + pool.declare(`${appearance}Shadows`, mapPipelineToShadow(require(`${sourcePath(platformData, appearance)}tokens-shadow.json`)), { type: 'BaseShadowAliasTokens', }); } - for (const appearance of appearances) { + for (const appearance of ordered) { const native = mapColors(readAliases(platformData, appearance), platformData.mapper, colorKeys); const scheme = appearanceScheme(platformData, appearance); const colors = completeColors(native, fallbackColors[scheme], colorKeys); - pool.declare(`${appearance}AliasColors`, toCodeValues(colors, platformColors), { type: 'Required<AliasColorTokens>' }); + pool.declare(`${appearance}AliasColors`, toCodeValues(colors, platformColors, platformData.platformColorName ?? ((name) => name)), { + type: 'Required<AliasColorTokens>', + }); } pool.declare('fontAliasTokens', mapFonts(platformData), { type: 'Required<Variants>', diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.android.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.android.ts index 8608b283f0..7989657083 100644 --- a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.android.ts +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.android.ts @@ -1,7 +1,8 @@ /** * WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually. * Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults. - * Unsupported appearances inherit the closest supported appearance. Shared values are emitted once. + * An appearance without token data inherits elevated from standard, and high contrast from the other + * high-contrast appearance, else from standard. Shared values are emitted once. */ import type { AliasColorTokens } from '../types/Color.types'; import type { BaseShadowAliasTokens } from '../types/Shadow.types'; @@ -145,11 +146,10 @@ export const lightShadows: BaseShadowAliasTokens = { }; export const darkShadows: BaseShadowAliasTokens = lightShadows; -export const darkGrayShadows: BaseShadowAliasTokens = lightShadows; -export const hcShadows: BaseShadowAliasTokens = lightShadows; +export const lightElevatedShadows: BaseShadowAliasTokens = lightShadows; +export const darkElevatedShadows: BaseShadowAliasTokens = lightShadows; export const hcLightShadows: BaseShadowAliasTokens = lightShadows; export const hcDarkShadows: BaseShadowAliasTokens = lightShadows; -export const darkElevatedShadows: BaseShadowAliasTokens = lightShadows; export const lightAliasColors: Required<AliasColorTokens> = { ...sharedAliasColors, @@ -483,11 +483,10 @@ export const darkAliasColors: Required<AliasColorTokens> = { brandStroke1Selected: rgb77b7f7, }; -export const darkGrayAliasColors: Required<AliasColorTokens> = darkAliasColors; -export const hcAliasColors: Required<AliasColorTokens> = darkAliasColors; +export const lightElevatedAliasColors: Required<AliasColorTokens> = lightAliasColors; +export const darkElevatedAliasColors: Required<AliasColorTokens> = darkAliasColors; export const hcLightAliasColors: Required<AliasColorTokens> = lightAliasColors; export const hcDarkAliasColors: Required<AliasColorTokens> = darkAliasColors; -export const darkElevatedAliasColors: Required<AliasColorTokens> = darkAliasColors; /** Font aliases from the light appearance, completed with native equivalents and the platform global ramp. */ export const fontAliasTokens: Required<Variants> = { diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ios.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ios.ts index 5848215fad..0d0b90e124 100644 --- a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ios.ts +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ios.ts @@ -1,7 +1,8 @@ /** * WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually. * Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults. - * Unsupported appearances inherit the closest supported appearance. Shared values are emitted once. + * An appearance without token data inherits elevated from standard, and high contrast from the other + * high-contrast appearance, else from standard. Shared values are emitted once. */ import type { AliasColorTokens } from '../types/Color.types'; import type { BaseShadowAliasTokens } from '../types/Shadow.types'; @@ -179,7 +180,7 @@ const sharedAliasColors = { neutralForegroundLightStatic: rgbffffff, } as const; -const darkDarkGrayHcHcDarkDarkElevatedAliasColors = { +const darkDarkElevatedHcDarkAliasColors = { ...sharedAliasColors, neutralForeground4: rgbadadad, neutralForegroundDisabled: rgb5c5c5c, @@ -344,11 +345,10 @@ export const darkShadows: BaseShadowAliasTokens = { shadow64: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 32, blur: 64 } }, }; -export const darkGrayShadows: BaseShadowAliasTokens = darkShadows; -export const hcShadows: BaseShadowAliasTokens = darkShadows; +export const darkElevatedShadows: BaseShadowAliasTokens = darkShadows; export const hcLightShadows: BaseShadowAliasTokens = darkShadows; export const hcDarkShadows: BaseShadowAliasTokens = darkShadows; -export const darkElevatedShadows: BaseShadowAliasTokens = darkShadows; +export const lightElevatedShadows: BaseShadowAliasTokens = lightShadows; export const lightAliasColors: Required<AliasColorTokens> = { ...sharedAliasColors, @@ -520,7 +520,7 @@ export const lightAliasColors: Required<AliasColorTokens> = { }; export const darkAliasColors: Required<AliasColorTokens> = { - ...darkDarkGrayHcHcDarkDarkElevatedAliasColors, + ...darkDarkElevatedHcDarkAliasColors, neutralBackgroundCanvas: '#141414', neutralBackgroundLightStaticDisabled: rgbadadad, brandBackgroundInverted: rgbb8b8b8, @@ -556,13 +556,8 @@ export const darkAliasColors: Required<AliasColorTokens> = { neutralBackgroundDarkStatic: rgb3d3d3d, }; -export const darkGrayAliasColors: Required<AliasColorTokens> = darkAliasColors; -export const hcAliasColors: Required<AliasColorTokens> = darkAliasColors; -export const hcLightAliasColors: Required<AliasColorTokens> = lightAliasColors; -export const hcDarkAliasColors: Required<AliasColorTokens> = darkAliasColors; - export const darkElevatedAliasColors: Required<AliasColorTokens> = { - ...darkDarkGrayHcHcDarkDarkElevatedAliasColors, + ...darkDarkElevatedHcDarkAliasColors, neutralBackgroundCanvas: rgb242424, neutralBackgroundLightStaticDisabled: rgb6b6b6b, brandBackgroundInverted: rgbc7c7c7, @@ -598,6 +593,10 @@ export const darkElevatedAliasColors: Required<AliasColorTokens> = { neutralBackgroundDarkStatic: rgb4d4d4d, }; +export const hcLightAliasColors: Required<AliasColorTokens> = lightAliasColors; +export const hcDarkAliasColors: Required<AliasColorTokens> = darkAliasColors; +export const lightElevatedAliasColors: Required<AliasColorTokens> = lightAliasColors; + /** Font aliases from the light appearance, completed with native equivalents and the platform global ramp. */ export const fontAliasTokens: Required<Variants> = { caption2: { face: System, size: 12, weight: fontWeight400, lineHeight: 16, letterSpacing: 0, dynamicTypeRamp: 'caption1' }, diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.macos.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.macos.ts index e6ad49f432..eb75459b31 100644 --- a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.macos.ts +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.macos.ts @@ -1,7 +1,8 @@ /** * WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually. * Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults. - * Unsupported appearances inherit the closest supported appearance. Shared values are emitted once. + * An appearance without token data inherits elevated from standard, and high contrast from the other + * high-contrast appearance, else from standard. Shared values are emitted once. */ import type { AliasColorTokens } from '../types/Color.types'; import type { BaseShadowAliasTokens } from '../types/Shadow.types'; @@ -130,7 +131,7 @@ const sharedAliasColors = { neutralForegroundLightStatic: rgbffffff, } as const; -const lightHcLightAliasColors = { +const lightHcLightLightElevatedAliasColors = { ...sharedAliasColors, neutralForegroundDisabled: rgb757575, neutralForegroundDisabled1: rgb757575, @@ -294,7 +295,7 @@ const lightHcLightAliasColors = { brandStroke1Selected: rgb005a9e, } as const; -const darkDarkGrayHcHcDarkDarkElevatedAliasColors = { +const darkHcDarkDarkElevatedAliasColors = { ...sharedAliasColors, neutralForegroundDisabled: rgbb8b8b8, neutralForegroundDisabled1: rgbb8b8b8, @@ -462,7 +463,7 @@ const darkDarkGrayHcHcDarkDarkElevatedAliasColors = { brandStroke1Selected: rgb3aa0f3, } as const; -const lightDarkDarkGrayDarkElevatedAliasColors = { +const lightDarkLightElevatedDarkElevatedAliasColors = { ...sharedAliasColors, transparentStroke: rgb00000000, transparentStrokeInteractive: rgb00000000, @@ -498,15 +499,14 @@ export const darkShadows: BaseShadowAliasTokens = { shadow64: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 32, blur: 64 } }, }; -export const darkGrayShadows: BaseShadowAliasTokens = darkShadows; -export const hcShadows: BaseShadowAliasTokens = darkShadows; export const hcLightShadows: BaseShadowAliasTokens = darkShadows; export const hcDarkShadows: BaseShadowAliasTokens = darkShadows; +export const lightElevatedShadows: BaseShadowAliasTokens = lightShadows; export const darkElevatedShadows: BaseShadowAliasTokens = darkShadows; export const lightAliasColors: Required<AliasColorTokens> = { - ...lightHcLightAliasColors, - ...lightDarkDarkGrayDarkElevatedAliasColors, + ...lightHcLightLightElevatedAliasColors, + ...lightDarkLightElevatedDarkElevatedAliasColors, neutralForeground4: '#808080', neutralStroke3: rgbf0f0f0, neutralForeground1: rgb242424, @@ -520,8 +520,8 @@ export const lightAliasColors: Required<AliasColorTokens> = { }; export const darkAliasColors: Required<AliasColorTokens> = { - ...darkDarkGrayHcHcDarkDarkElevatedAliasColors, - ...lightDarkDarkGrayDarkElevatedAliasColors, + ...darkHcDarkDarkElevatedAliasColors, + ...lightDarkLightElevatedDarkElevatedAliasColors, neutralForeground4: '#858585', neutralStroke3: rgb666666, neutralForeground3: rgbadadad, @@ -530,23 +530,8 @@ export const darkAliasColors: Required<AliasColorTokens> = { neutralStroke2: rgb575757, }; -export const darkGrayAliasColors: Required<AliasColorTokens> = darkAliasColors; - -export const hcAliasColors: Required<AliasColorTokens> = { - ...darkDarkGrayHcHcDarkDarkElevatedAliasColors, - neutralForeground4: rgbd6d6d6, - neutralStroke3: rgbadadad, - neutralForeground3: rgbd6d6d6, - neutralStrokeAccessible: rgbd6d6d6, - neutralStroke1: rgbadadad, - neutralStroke2: rgba8a8a8, - transparentStroke: rgb3aa0f3, - transparentStrokeInteractive: rgba8a8a8, - transparentStrokeDisabled: rgbd6d6d6, -}; - export const hcLightAliasColors: Required<AliasColorTokens> = { - ...lightHcLightAliasColors, + ...lightHcLightLightElevatedAliasColors, neutralForeground4: rgb424242, neutralStroke3: rgb616161, neutralForeground1: rgb000000, @@ -562,7 +547,20 @@ export const hcLightAliasColors: Required<AliasColorTokens> = { transparentStrokeDisabled: rgbbdbdbd, }; -export const hcDarkAliasColors: Required<AliasColorTokens> = hcAliasColors; +export const hcDarkAliasColors: Required<AliasColorTokens> = { + ...darkHcDarkDarkElevatedAliasColors, + neutralForeground4: rgbd6d6d6, + neutralStroke3: rgbadadad, + neutralForeground3: rgbd6d6d6, + neutralStrokeAccessible: rgbd6d6d6, + neutralStroke1: rgbadadad, + neutralStroke2: rgba8a8a8, + transparentStroke: rgb3aa0f3, + transparentStrokeInteractive: rgba8a8a8, + transparentStrokeDisabled: rgbd6d6d6, +}; + +export const lightElevatedAliasColors: Required<AliasColorTokens> = lightAliasColors; export const darkElevatedAliasColors: Required<AliasColorTokens> = darkAliasColors; /** Font aliases from the light appearance, completed with native equivalents and the platform global ramp. */ diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts index 11005744bd..c8148ac3da 100644 --- a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.ts @@ -1,7 +1,8 @@ /** * WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually. * Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults. - * Unsupported appearances inherit the closest supported appearance. Shared values are emitted once. + * An appearance without token data inherits elevated from standard, and high contrast from the other + * high-contrast appearance, else from standard. Shared values are emitted once. */ import { PlatformColor } from 'react-native'; @@ -129,7 +130,7 @@ const sharedAliasColors = { neutralForegroundLightStatic: rgbffffff, } as const; -const lightDarkDarkGrayDarkElevatedAliasColors = { +const lightDarkDarkElevatedLightElevatedAliasColors = { ...sharedAliasColors, neutralForegroundOnBrand: rgbffffff, neutralForegroundOnColor: rgbffffff, @@ -169,7 +170,7 @@ const lightDarkDarkGrayDarkElevatedAliasColors = { brandStroke1Selected: rgb185abd, } as const; -const darkDarkGrayHcHcLightHcDarkDarkElevatedAliasColors = { +const darkDarkElevatedHcDarkHcLightAliasColors = { ...sharedAliasColors, neutralBackgroundDarkStatic: rgb3d3d3d, } as const; @@ -183,9 +184,9 @@ const sharedShadows = { shadow64brand: { ambient: shadowLayer4, key: { color: rgb00000040, x: 0, y: 32, blur: 64 } }, } as const; -const darkDarkGrayDarkElevatedAliasColors = { - ...lightDarkDarkGrayDarkElevatedAliasColors, - ...darkDarkGrayHcHcLightHcDarkDarkElevatedAliasColors, +const darkDarkElevatedAliasColors = { + ...lightDarkDarkElevatedLightElevatedAliasColors, + ...darkDarkElevatedHcDarkHcLightAliasColors, neutralForegroundInverted: rgb000000, brandForegroundLink: rgbaec6eb, compoundBrandForeground1: rgbaec6eb, @@ -299,14 +300,13 @@ export const darkShadows: BaseShadowAliasTokens = { shadow64: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 32, blur: 64 } }, }; -export const darkGrayShadows: BaseShadowAliasTokens = darkShadows; -export const hcShadows: BaseShadowAliasTokens = darkShadows; -export const hcLightShadows: BaseShadowAliasTokens = darkShadows; -export const hcDarkShadows: BaseShadowAliasTokens = darkShadows; export const darkElevatedShadows: BaseShadowAliasTokens = darkShadows; +export const hcDarkShadows: BaseShadowAliasTokens = darkShadows; +export const lightElevatedShadows: BaseShadowAliasTokens = lightShadows; +export const hcLightShadows: BaseShadowAliasTokens = darkShadows; export const lightAliasColors: Required<AliasColorTokens> = { - ...lightDarkDarkGrayDarkElevatedAliasColors, + ...lightDarkDarkElevatedLightElevatedAliasColors, neutralForeground4: rgb707070, neutralForegroundDisabled: rgbbdbdbd, neutralForegroundDisabled1: rgbbdbdbd, @@ -459,7 +459,7 @@ export const lightAliasColors: Required<AliasColorTokens> = { }; export const darkAliasColors: Required<AliasColorTokens> = { - ...darkDarkGrayDarkElevatedAliasColors, + ...darkDarkElevatedAliasColors, neutralForeground4: rgb999999, neutralForegroundDisabled: rgb5c5c5c, neutralForegroundDisabled1: rgb5c5c5c, @@ -519,8 +519,8 @@ export const darkAliasColors: Required<AliasColorTokens> = { neutralStrokeDisabled: rgb424242, }; -export const darkGrayAliasColors: Required<AliasColorTokens> = { - ...darkDarkGrayDarkElevatedAliasColors, +export const darkElevatedAliasColors: Required<AliasColorTokens> = { + ...darkDarkElevatedAliasColors, neutralForeground4: '#c2c2c2', neutralForegroundDisabled: rgb666666, neutralForegroundDisabled1: rgb666666, @@ -580,8 +580,8 @@ export const darkGrayAliasColors: Required<AliasColorTokens> = { neutralStrokeDisabled: rgb474747, }; -export const hcAliasColors: Required<AliasColorTokens> = { - ...darkDarkGrayHcHcLightHcDarkDarkElevatedAliasColors, +export const hcDarkAliasColors: Required<AliasColorTokens> = { + ...darkDarkElevatedHcDarkHcLightAliasColors, neutralForeground4: platformColorWindowText, neutralForegroundDisabled: platformColorGrayText, neutralForegroundDisabled1: platformColorGrayText, @@ -768,9 +768,8 @@ export const hcAliasColors: Required<AliasColorTokens> = { brandStroke1Selected: platformColorWindowText, }; -export const hcLightAliasColors: Required<AliasColorTokens> = hcAliasColors; -export const hcDarkAliasColors: Required<AliasColorTokens> = hcAliasColors; -export const darkElevatedAliasColors: Required<AliasColorTokens> = darkAliasColors; +export const lightElevatedAliasColors: Required<AliasColorTokens> = lightAliasColors; +export const hcLightAliasColors: Required<AliasColorTokens> = hcDarkAliasColors; /** Font aliases from the light appearance, completed with native equivalents and the platform global ramp. */ export const fontAliasTokens: Required<Variants> = { diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.windows.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.windows.ts index 0ccde913f2..23b273206d 100644 --- a/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.windows.ts +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.generated.windows.ts @@ -1,12 +1,24 @@ /** * WARNING: This file is auto-generated by scripts/fluent-tokens.cts. Do not edit it manually. * Complete Fluent tokens: native values, same-platform equivalents, then same-scheme portable defaults. - * Unsupported appearances inherit the closest supported appearance. Shared values are emitted once. + * An appearance without token data inherits elevated from standard, and high contrast from the other + * high-contrast appearance, else from standard. Shared values are emitted once. */ +import { PlatformColor } from 'react-native'; + import type { AliasColorTokens } from '../types/Color.types'; import type { BaseShadowAliasTokens } from '../types/Shadow.types'; import type { Variants } from '../types/Typography.types'; +const platformColorButtonFace = /* @__PURE__ */ PlatformColor('SystemColorButtonFaceColor'); +const platformColorButtonText = /* @__PURE__ */ PlatformColor('SystemColorButtonTextColor'); +const platformColorGrayText = /* @__PURE__ */ PlatformColor('SystemColorGrayTextColor'); +const platformColorHighlight = /* @__PURE__ */ PlatformColor('SystemColorHighlightColor'); +const platformColorHighlightText = /* @__PURE__ */ PlatformColor('SystemColorHighlightTextColor'); +const platformColorHotlight = /* @__PURE__ */ PlatformColor('SystemColorHotlightColor'); +const platformColorWindow = /* @__PURE__ */ PlatformColor('SystemColorWindowColor'); +const platformColorWindowText = /* @__PURE__ */ PlatformColor('SystemColorWindowTextColor'); + const fontWeight400 = '400'; const fontWeight600 = '600'; const primary = 'primary'; @@ -103,6 +115,18 @@ const title1 = { face: primary, size: 28, weight: fontWeight400 } as const; const title1Strong = { face: primary, size: 28, weight: fontWeight600 } as const; const sharedAliasColors = { + subtleBackground: rgb00000000, + transparentBackground: rgb00000000, + transparentBackgroundHover: rgb00000000, + transparentBackgroundPressed: rgb00000000, + transparentBackgroundSelected: rgb00000000, + neutralBackgroundLightStatic: rgbffffff, + neutralForegroundDarkStatic: rgb000000, + neutralForegroundLightStatic: rgbffffff, +} as const; + +const lightDarkLightElevatedDarkElevatedAliasColors = { + ...sharedAliasColors, neutralForegroundOnBrand: rgbffffff, neutralForegroundOnColor: rgbffffff, neutralForegroundInvertedLink: rgbffffff, @@ -114,11 +138,6 @@ const sharedAliasColors = { neutralForegroundInvertedLinkHover: rgbffffff, neutralForegroundInvertedLinkPressed: rgbffffff, neutralForegroundInvertedLinkSelected: rgbffffff, - subtleBackground: rgb00000000, - transparentBackground: rgb00000000, - transparentBackgroundHover: rgb00000000, - transparentBackgroundPressed: rgb00000000, - transparentBackgroundSelected: rgb00000000, brandBackgroundPressed: rgb004578, brandBackgroundSelected: rgb13458f, transparentStroke: rgb00000000, @@ -129,11 +148,13 @@ const sharedAliasColors = { warningBackground3: rgbfde300, severeBackground3: rgbda3b01, outofofficeBackground3: rgbc239b3, - neutralBackgroundLightStatic: rgbffffff, brandBackground2Pressed: rgb004578, brandBackground2Selected: rgb13458f, - neutralForegroundDarkStatic: rgb000000, - neutralForegroundLightStatic: rgbffffff, +} as const; + +const darkHcDarkDarkElevatedHcLightAliasColors = { + ...sharedAliasColors, + neutralBackgroundDarkStatic: rgb3d3d3d, } as const; const sharedShadows = { @@ -165,14 +186,13 @@ export const darkShadows: BaseShadowAliasTokens = { shadow64: { ambient: shadowLayer6, key: { color: rgb0000007a, x: 0, y: 32, blur: 64 } }, }; -export const darkGrayShadows: BaseShadowAliasTokens = darkShadows; -export const hcShadows: BaseShadowAliasTokens = darkShadows; -export const hcLightShadows: BaseShadowAliasTokens = lightShadows; export const hcDarkShadows: BaseShadowAliasTokens = darkShadows; +export const lightElevatedShadows: BaseShadowAliasTokens = lightShadows; export const darkElevatedShadows: BaseShadowAliasTokens = darkShadows; +export const hcLightShadows: BaseShadowAliasTokens = darkShadows; export const lightAliasColors: Required<AliasColorTokens> = { - ...sharedAliasColors, + ...lightDarkLightElevatedDarkElevatedAliasColors, neutralForeground4: rgb707070, neutralForegroundDisabled: rgbbdbdbd, neutralForegroundDisabled1: rgbbdbdbd, @@ -338,7 +358,8 @@ export const lightAliasColors: Required<AliasColorTokens> = { }; export const darkAliasColors: Required<AliasColorTokens> = { - ...sharedAliasColors, + ...lightDarkLightElevatedDarkElevatedAliasColors, + ...darkHcDarkDarkElevatedHcLightAliasColors, neutralForeground4: '#999999', neutralForegroundDisabled: rgb5c5c5c, neutralForegroundDisabled1: rgb5c5c5c, @@ -497,17 +518,202 @@ export const darkAliasColors: Required<AliasColorTokens> = { outofofficeBorder1: rgbc239b3, outofofficeBorder2: rgbd161c4, brandForeground1Pressed: rgb6794d7, - neutralBackgroundDarkStatic: rgb3d3d3d, brandForeground1Selected: rgb6794d7, brandStroke1Pressed: rgb2e6ac5, brandStroke1Selected: rgb2e6ac5, }; -export const darkGrayAliasColors: Required<AliasColorTokens> = darkAliasColors; -export const hcAliasColors: Required<AliasColorTokens> = darkAliasColors; -export const hcLightAliasColors: Required<AliasColorTokens> = lightAliasColors; -export const hcDarkAliasColors: Required<AliasColorTokens> = darkAliasColors; +export const hcDarkAliasColors: Required<AliasColorTokens> = { + ...darkHcDarkDarkElevatedHcLightAliasColors, + neutralForeground4: platformColorWindowText, + neutralForegroundDisabled: platformColorGrayText, + neutralForegroundDisabled1: platformColorGrayText, + neutralForegroundDisabled2: platformColorGrayText, + neutralForegroundOnBrand: platformColorButtonText, + neutralForegroundOnColor: platformColorButtonText, + neutralForegroundInverted: platformColorWindow, + neutralForegroundInvertedLink: platformColorHotlight, + brandForegroundLink: platformColorHotlight, + compoundBrandForeground1: platformColorHighlight, + brandForeground2: platformColorButtonText, + brandForegroundTint: platformColorButtonText, + brandForeground1Disabled: platformColorGrayText, + brandForegroundDisabled1: platformColorGrayText, + brandForegroundDisabled2: platformColorGrayText, + neutralBackgroundCanvas: platformColorWindow, + neutralBackgroundLightStaticDisabled: platformColorWindow, + brandBackground2: platformColorButtonFace, + brandBackground3: platformColorButtonFace, + brandBackgroundTint: platformColorButtonFace, + brandBackgroundInverted: platformColorWindowText, + brandBackgroundInvertedDisabled: platformColorWindow, + brandBackgroundDisabled: platformColorWindow, + compoundBrandBackground1: platformColorHighlight, + brandBackgroundStatic: platformColorWindow, + neutralStroke3: platformColorWindowText, + neutralStrokeFocus1: platformColorWindow, + neutralStrokeFocus2: platformColorHighlight, + strokeFocus1: platformColorWindow, + strokeFocus2: platformColorHighlight, + brandStroke2: platformColorWindow, + brandStrokeTint: platformColorWindow, + compoundBrandStroke1: platformColorHighlight, + dangerStroke1: platformColorWindowText, + successStroke1: platformColorWindowText, + warningStroke1: platformColorWindowText, + severeStroke1: platformColorWindowText, + dangerBorder1: platformColorWindowText, + successBorder1: platformColorWindowText, + warningBorder1: platformColorWindowText, + severeBorder1: platformColorWindowText, + presenceAway: platformColorWindowText, + presenceDnd: platformColorWindowText, + presenceAvailable: platformColorWindowText, + presenceOof: platformColorWindowText, + redBackground1: platformColorWindow, + redBackground2: platformColorWindow, + redBackground3: platformColorWindowText, + redForeground1: platformColorWindowText, + redForeground2: platformColorWindowText, + redForeground3: platformColorWindowText, + redBorderActive: platformColorHighlight, + redBorder1: platformColorWindowText, + redBorder2: platformColorWindowText, + neutralForeground1: platformColorWindowText, + neutralForeground1Hover: platformColorHighlightText, + neutralForeground1Pressed: platformColorHighlightText, + neutralForeground1Selected: platformColorHighlightText, + neutralForeground2: platformColorWindowText, + neutralForeground2Hover: platformColorHighlightText, + neutralForeground2Pressed: platformColorHighlightText, + neutralForeground2Selected: platformColorHighlightText, + neutralForeground2BrandHover: platformColorHighlightText, + neutralForeground2BrandPressed: platformColorHighlightText, + neutralForeground2BrandSelected: platformColorHighlightText, + neutralForeground3: platformColorWindowText, + neutralForeground3Hover: platformColorHighlightText, + neutralForeground3Pressed: platformColorHighlightText, + neutralForeground3Selected: platformColorHighlightText, + neutralForeground3BrandHover: platformColorHighlightText, + neutralForeground3BrandPressed: platformColorHighlightText, + neutralForeground3BrandSelected: platformColorHighlightText, + brandForegroundLinkHover: platformColorHotlight, + brandForegroundLinkPressed: platformColorHotlight, + brandForegroundLinkSelected: platformColorHotlight, + compoundBrandForeground1Hover: platformColorHighlight, + compoundBrandForeground1Pressed: platformColorHighlight, + brandForeground1: platformColorWindowText, + neutralForegroundOnBrandHover: platformColorHighlightText, + neutralForegroundOnBrandPressed: platformColorHighlightText, + neutralForegroundOnBrandSelected: platformColorHighlightText, + neutralForegroundInvertedLinkHover: platformColorHotlight, + neutralForegroundInvertedLinkPressed: platformColorHotlight, + neutralForegroundInvertedLinkSelected: platformColorHotlight, + neutralBackground1: platformColorWindow, + neutralBackground1Hover: platformColorHighlight, + neutralBackground1Pressed: platformColorHighlight, + neutralBackground1Selected: platformColorHighlight, + neutralBackground2: platformColorWindow, + neutralBackground2Hover: platformColorHighlight, + neutralBackground2Pressed: platformColorHighlight, + neutralBackground2Selected: platformColorHighlight, + neutralBackground3: platformColorWindow, + neutralBackground3Hover: platformColorHighlight, + neutralBackground3Pressed: platformColorHighlight, + neutralBackground3Selected: platformColorHighlight, + neutralBackground4: platformColorWindow, + neutralBackground4Hover: platformColorHighlight, + neutralBackground4Pressed: platformColorHighlight, + neutralBackground4Selected: platformColorHighlight, + neutralBackground5: platformColorWindow, + neutralBackground5Hover: platformColorHighlight, + neutralBackground5Pressed: platformColorHighlight, + neutralBackground5Selected: platformColorHighlight, + neutralBackground6: platformColorWindow, + neutralBackgroundInverted: platformColorWindowText, + subtleBackgroundHover: platformColorHighlight, + subtleBackgroundPressed: platformColorHighlight, + subtleBackgroundSelected: platformColorHighlight, + neutralBackgroundDisabled: platformColorWindow, + neutralStencil1: rgb141414, + neutralStencil2: '#858585', + brandBackground: platformColorButtonFace, + brandBackgroundHover: platformColorHighlight, + brandBackgroundPressed: platformColorHighlight, + brandBackgroundSelected: platformColorHighlight, + compoundBrandBackground1Hover: platformColorHighlight, + compoundBrandBackground1Pressed: platformColorHighlight, + neutralStrokeAccessible: platformColorWindowText, + neutralStrokeAccessibleHover: platformColorHighlight, + neutralStrokeAccessiblePressed: platformColorHighlight, + neutralStrokeAccessibleSelected: platformColorHighlight, + neutralStroke1: platformColorWindowText, + neutralStroke1Hover: platformColorHighlight, + neutralStroke1Pressed: platformColorHighlight, + neutralStroke1Selected: platformColorHighlight, + neutralStroke2: platformColorWindowText, + brandStroke1: platformColorWindowText, + compoundBrandStroke1Hover: platformColorHighlight, + compoundBrandStroke1Pressed: platformColorHighlight, + neutralStrokeDisabled: platformColorGrayText, + transparentStroke: platformColorWindowText, + transparentStrokeInteractive: platformColorHighlight, + transparentStrokeDisabled: platformColorGrayText, + dangerBackground1: platformColorWindow, + dangerBackground2: platformColorWindow, + dangerBackground3: platformColorWindowText, + dangerForeground1: platformColorWindowText, + dangerForeground2: platformColorWindowText, + dangerForeground3: platformColorWindowText, + dangerForegroundInverted: platformColorWindowText, + dangerBorderActive: platformColorHighlight, + dangerBorder2: platformColorWindowText, + successBackground1: platformColorWindow, + successBackground2: platformColorWindow, + successBackground3: platformColorWindowText, + successForeground1: platformColorWindowText, + successForeground2: platformColorWindowText, + successForeground3: platformColorWindowText, + successForegroundInverted: platformColorWindowText, + successBorderActive: platformColorHighlight, + successBorder2: platformColorWindowText, + warningBackground1: platformColorWindow, + warningBackground2: platformColorWindow, + warningBackground3: platformColorWindowText, + warningForeground1: platformColorWindowText, + warningForeground2: platformColorWindowText, + warningForeground3: platformColorWindowText, + warningForegroundInverted: platformColorWindowText, + warningBorderActive: platformColorHighlight, + warningBorder2: platformColorWindowText, + severeBackground1: platformColorWindow, + severeBackground2: platformColorWindow, + severeBackground3: platformColorWindowText, + severeForeground1: platformColorWindowText, + severeForeground2: platformColorWindowText, + severeForeground3: platformColorWindowText, + severeBorderActive: platformColorHighlight, + severeBorder2: platformColorWindowText, + outofofficeBackground1: platformColorWindow, + outofofficeBackground2: platformColorWindow, + outofofficeBackground3: platformColorWindowText, + outofofficeForeground1: platformColorWindowText, + outofofficeForeground2: platformColorWindowText, + outofofficeForeground3: platformColorWindowText, + outofofficeBorderActive: platformColorHighlight, + outofofficeBorder1: platformColorWindowText, + outofofficeBorder2: platformColorWindowText, + brandForeground1Pressed: platformColorWindowText, + brandBackground2Pressed: platformColorHighlight, + brandBackground2Selected: platformColorHighlight, + brandForeground1Selected: platformColorWindowText, + brandStroke1Pressed: platformColorWindowText, + brandStroke1Selected: platformColorWindowText, +}; + +export const lightElevatedAliasColors: Required<AliasColorTokens> = lightAliasColors; export const darkElevatedAliasColors: Required<AliasColorTokens> = darkAliasColors; +export const hcLightAliasColors: Required<AliasColorTokens> = hcDarkAliasColors; /** Font aliases from the light appearance, completed with native equivalents and the platform global ramp. */ export const fontAliasTokens: Required<Variants> = { diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts index b7d7a105bf..a6794f1d8a 100644 --- a/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts @@ -16,7 +16,11 @@ import { mapPipelineToShadow } from '../mapPipelineToShadow'; import { mapFontPipelineToTheme, mapPipelineToTheme } from '../mapPipelineToTheme'; import * as androidMapper from '../mapPipelineToTheme.android'; import * as iosMapper from '../mapPipelineToTheme.ios'; -import { processAliasTokens, transformWin32PlatformColorName } from '../tokens/highContrast/processAliasTokens'; +import { + processAliasTokens, + transformWin32PlatformColorName, + transformWindowsPlatformColorName, +} from '../tokens/highContrast/processAliasTokens'; import * as android from './fluentTokens.generated.android'; import * as ios from './fluentTokens.generated.ios'; import * as macos from './fluentTokens.generated.macos'; @@ -35,8 +39,8 @@ const processedHcAliasTokens = processAliasTokens(JSON.parse(JSON.stringify(hcAl const appearances = [ ['light', generated.lightAliasColors, generated.lightShadows, colorfulAliasTokens, colorfulShadowTokens], ['dark', generated.darkAliasColors, generated.darkShadows, blackAliasTokens, blackShadowTokens], - ['darkGray', generated.darkGrayAliasColors, generated.darkGrayShadows, darkGrayAliasTokens, darkGrayShadowTokens], - ['hc', generated.hcAliasColors, generated.hcShadows, processedHcAliasTokens, hcShadowTokens], + ['darkElevated', generated.darkElevatedAliasColors, generated.darkElevatedShadows, darkGrayAliasTokens, darkGrayShadowTokens], + ['hcDark', generated.hcDarkAliasColors, generated.hcDarkShadows, processedHcAliasTokens, hcShadowTokens], ] as const; describe('generated win32 Fluent tokens', () => { @@ -50,7 +54,7 @@ describe('generated win32 Fluent tokens', () => { }); it('emit high-contrast colors as distinct PlatformColor values', () => { - expect(generated.hcAliasColors.neutralForeground1).toEqual(PlatformColor('WindowText')); + expect(generated.hcDarkAliasColors.neutralForeground1).toEqual(PlatformColor('WindowText')); expect(PlatformColor('WindowText')).not.toEqual(PlatformColor('ButtonFace')); }); }); @@ -81,32 +85,33 @@ function expectDefined(value: unknown): void { } } -const allAppearances = ['light', 'dark', 'darkGray', 'hc', 'hcLight', 'hcDark', 'darkElevated'] as const; +const allAppearances = ['light', 'dark', 'lightElevated', 'darkElevated', 'hcLight', 'hcDark'] as const; +type Appearance = (typeof allAppearances)[number]; const platforms = [ { platform: 'win32', tokens: generated, mapper: { mapPipelineToTheme, mapFontPipelineToTheme }, - sources: { light: 'colorful', dark: 'black', darkGray: 'darkgray', hc: 'hc' }, + sources: { light: 'win32/colorful', dark: 'win32/black', darkElevated: 'win32/darkgray', hcDark: 'win32/hc' }, }, { platform: 'macos', tokens: macos, mapper: { mapPipelineToTheme, mapFontPipelineToTheme }, - sources: { light: 'light', dark: 'dark', hcLight: 'hclight', hcDark: 'hcdark' }, + sources: { light: 'macos/light', dark: 'macos/dark', hcLight: 'macos/hclight', hcDark: 'macos/hcdark' }, }, { platform: 'windows', tokens: windows, mapper: { mapPipelineToTheme, mapFontPipelineToTheme }, - sources: { light: 'light', dark: 'dark' }, + sources: { light: 'windows/light', dark: 'windows/dark', hcDark: 'win32/hc' }, }, - { platform: 'android', tokens: android, mapper: androidMapper, sources: { light: 'light', dark: 'dark' } }, + { platform: 'android', tokens: android, mapper: androidMapper, sources: { light: 'android/light', dark: 'android/dark' } }, { platform: 'ios', tokens: ios, mapper: iosMapper, - sources: { light: 'light', dark: 'dark', hcLight: 'hclight', hcDark: 'hcdark', darkElevated: 'elevateddark' }, + sources: { light: 'ios/light', dark: 'ios/dark', hcLight: 'ios/hclight', hcDark: 'ios/hcdark', darkElevated: 'ios/elevateddark' }, }, ] as const; @@ -127,12 +132,13 @@ describe.each(platforms)('complete $platform Fluent tokens', ({ platform, tokens }); it('preserves every defined runtime-mapped native color, font alias, and shadow', () => { + const colorName = platform === 'windows' ? transformWindowsPlatformColorName : transformWin32PlatformColorName; for (const [appearance, source] of Object.entries(sources)) { - const packagePath = `@fluentui-react-native/design-tokens-${platform}/${source}/`; + const packagePath = `@fluentui-react-native/design-tokens-${source}/`; const raw = require(`${packagePath}tokens-aliases.json`); - const aliases = processAliasTokens(JSON.parse(JSON.stringify(raw)), transformWin32PlatformColorName); + const aliases = processAliasTokens(JSON.parse(JSON.stringify(raw)), colorName); const shadows = require(`${packagePath}tokens-shadow.json`); - const key = appearance as (typeof allAppearances)[number]; + const key = appearance as Appearance; // iOS high-contrast files contain fonts only, with no native colors to preserve. if (aliases.neutralBackground1) { expect(tokens[`${key}AliasColors`]).toMatchObject(definedEntries(mapper.mapPipelineToTheme(aliases))); @@ -157,16 +163,26 @@ describe('Fluent token fallbacks', () => { expect(tokens.darkAliasColors.outofofficeBackground3).toBe(generated.darkAliasColors.outofofficeBackground3); }); - it('inherits missing appearances without importing Win32 system colors onto other platforms', () => { + it.each([ + ['win32', generated, { lightElevated: 'light', hcLight: 'hcDark' }], + ['macos', macos, { lightElevated: 'light', darkElevated: 'dark' }], + ['windows', windows, { lightElevated: 'light', darkElevated: 'dark', hcLight: 'hcDark' }], + ['android', android, { lightElevated: 'light', darkElevated: 'dark', hcLight: 'light', hcDark: 'dark' }], + ['ios', ios, { lightElevated: 'light' }], + ] as const)('%s returns the inherited appearance for each appearance without token data', (_, tokens, inherited) => { + for (const [appearance, source] of Object.entries(inherited) as [Appearance, Appearance][]) { + expect(tokens[`${appearance}AliasColors`]).toBe(tokens[`${source}AliasColors`]); + expect(tokens[`${appearance}Shadows`]).toBe(tokens[`${source}Shadows`]); + } + }); + + it('uses standard colors for color-free high-contrast sets and system colors only for Windows high contrast', () => { expect(ios.hcLightAliasColors).toEqual(ios.lightAliasColors); expect(ios.hcDarkAliasColors).toEqual(ios.darkAliasColors); - expect(generated.hcLightAliasColors).toEqual(generated.hcAliasColors); - expect(generated.hcDarkAliasColors).toEqual(generated.hcAliasColors); - for (const { tokens } of platforms.filter(({ platform }) => platform !== 'win32')) { - expect(tokens.darkGrayAliasColors).toEqual(tokens.darkAliasColors); - expect(tokens.darkGrayShadows).toEqual(tokens.darkShadows); + for (const { platform, tokens } of platforms) { for (const appearance of allAppearances) { - expect(Object.values(tokens[`${appearance}AliasColors`]).every((color) => typeof color === 'string')).toBe(true); + const systemColors = (platform === 'win32' || platform === 'windows') && appearance.startsWith('hc'); + expect(Object.values(tokens[`${appearance}AliasColors`]).some((color) => typeof color !== 'string')).toBe(systemColors); } } }); diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap index 87a2dbc5da..cf68da9683 100644 --- a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap @@ -103,6 +103,7 @@ exports[`public entry points ./themes keeps its runtime export names 1`] = ` "flexTheme: object", "flexWarmTheme: object", "fluentDarkTheme: object", + "fluentHcTheme: object", "fluentLightTheme: object", "fluentTheme: object", ] diff --git a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts index d121c5e458..d2802ffe12 100644 --- a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts +++ b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts @@ -221,7 +221,12 @@ describe('runtime graph ownership', () => { }); it('keeps the Fluent themes on generated tokens and the legacy source, free of the Flex engine', () => { - for (const entry of ['themes/fluent/fluentLightTheme.ts', 'themes/fluent/fluentDarkTheme.ts', 'themes/fluent/fluentTheme.ts']) { + for (const entry of [ + 'themes/fluent/fluentLightTheme.ts', + 'themes/fluent/fluentDarkTheme.ts', + 'themes/fluent/fluentHcTheme.ts', + 'themes/fluent/fluentTheme.ts', + ]) { const graph = runtimeGraph(entry); expect(graph).toContain('fluent/defaults/fluentTokens.generated.ts'); expect(graph).toContain('tokens/global.generated.ts'); @@ -230,6 +235,7 @@ describe('runtime graph ownership', () => { } } expect(runtimeGraph('themes/fluent/fluentTheme.ts')).toContain('fluent/themeReference.ts'); + expect(runtimeGraph('themes/fluent/fluentHcTheme.ts')).toContain('fluent/themeReference.ts'); }); it('keeps the Flex themes on the generated Flex defaults, free of legacy Fluent runtime', () => { diff --git a/packages/agentic/design/src/themes/fluent/createFluentTheme.ts b/packages/agentic/design/src/themes/fluent/createFluentTheme.ts index 84e9f9f8e3..2af9fe282a 100644 --- a/packages/agentic/design/src/themes/fluent/createFluentTheme.ts +++ b/packages/agentic/design/src/themes/fluent/createFluentTheme.ts @@ -1,7 +1,7 @@ import { fontAliasTokens } from '../../fluent/defaults/fluentTokens.generated'; import type { AliasColorTokens } from '../../fluent/types/Color.types'; import type { BaseShadowAliasTokens } from '../../fluent/types/Shadow.types'; -import type { Spacing, Theme } from '../../fluent/types/Theme.types'; +import type { AppearanceOptions, Spacing, Theme } from '../../fluent/types/Theme.types'; import { fontFamilyBase, fontFamilyMonospace, @@ -29,7 +29,7 @@ import { legacyPaletteFromAliasColors } from './legacyPalette'; * parameter so that bundlers can drop the appearance a consumer never imports. */ export function createFluentTheme( - appearance: 'light' | 'dark', + appearance: AppearanceOptions, aliasColors: Required<AliasColorTokens>, shadows: BaseShadowAliasTokens, ): Theme { diff --git a/packages/agentic/design/src/themes/fluent/fluentHcDarkTheme.ts b/packages/agentic/design/src/themes/fluent/fluentHcDarkTheme.ts new file mode 100644 index 0000000000..888d396b0f --- /dev/null +++ b/packages/agentic/design/src/themes/fluent/fluentHcDarkTheme.ts @@ -0,0 +1,8 @@ +import { hcDarkAliasColors, hcDarkShadows } from '../../fluent/defaults/fluentTokens.generated'; +import type { Theme } from '../../fluent/types/Theme.types'; +import { createFluentTheme } from './createFluentTheme'; + +/** + * The Fluent high-contrast dark theme, built from Fluent 2 alias and global tokens. + */ +export const fluentHcDarkTheme: Theme = /* @__PURE__ */ createFluentTheme('highContrast', hcDarkAliasColors, hcDarkShadows); diff --git a/packages/agentic/design/src/themes/fluent/fluentHcLightTheme.ts b/packages/agentic/design/src/themes/fluent/fluentHcLightTheme.ts new file mode 100644 index 0000000000..7e8fe4488b --- /dev/null +++ b/packages/agentic/design/src/themes/fluent/fluentHcLightTheme.ts @@ -0,0 +1,8 @@ +import { hcLightAliasColors, hcLightShadows } from '../../fluent/defaults/fluentTokens.generated'; +import type { Theme } from '../../fluent/types/Theme.types'; +import { createFluentTheme } from './createFluentTheme'; + +/** + * The Fluent high-contrast light theme, built from Fluent 2 alias and global tokens. + */ +export const fluentHcLightTheme: Theme = /* @__PURE__ */ createFluentTheme('highContrast', hcLightAliasColors, hcLightShadows); diff --git a/packages/agentic/design/src/themes/fluent/fluentHcTheme.ts b/packages/agentic/design/src/themes/fluent/fluentHcTheme.ts new file mode 100644 index 0000000000..c339a73cf8 --- /dev/null +++ b/packages/agentic/design/src/themes/fluent/fluentHcTheme.ts @@ -0,0 +1,15 @@ +import { ThemeReference } from '../../fluent/themeReference'; +import type { Theme } from '../../fluent/types/Theme.types'; +import { fluentHcDarkTheme } from './fluentHcDarkTheme'; +import { fluentHcLightTheme } from './fluentHcLightTheme'; + +/** + * Theme source holding the Fluent high-contrast themes. It always resolves high contrast and follows the system color + * scheme reported by the React Native `Appearance` module; a `ThemeProvider` or `ThemedRoot` `appearance` prop + * overrides the color scheme. + */ +export const fluentHcTheme: ThemeReference = /* @__PURE__ */ new ThemeReference({ + base: {} as Theme, + appearance: { colorScheme: 'system', contrast: 'highContrast', interfaceLevel: 'system' }, + recipes: [(_parent, appearance) => (appearance?.colorScheme === 'dark' ? fluentHcDarkTheme : fluentHcLightTheme)], +}); diff --git a/packages/agentic/design/src/themes/fluent/fluentTheme.ts b/packages/agentic/design/src/themes/fluent/fluentTheme.ts index 5803ff9c91..a4198a26aa 100644 --- a/packages/agentic/design/src/themes/fluent/fluentTheme.ts +++ b/packages/agentic/design/src/themes/fluent/fluentTheme.ts @@ -1,15 +1,26 @@ import { ThemeReference } from '../../fluent/themeReference'; import type { Theme } from '../../fluent/types/Theme.types'; import { fluentDarkTheme } from './fluentDarkTheme'; +import { fluentHcDarkTheme } from './fluentHcDarkTheme'; +import { fluentHcLightTheme } from './fluentHcLightTheme'; import { fluentLightTheme } from './fluentLightTheme'; /** - * Theme source holding both Fluent themes. It follows the system appearance reported by the React Native `Appearance` - * module, and a `ThemeProvider` or `ThemedRoot` `appearance` prop overrides it. High contrast and elevated system - * settings resolve by color scheme until those Fluent themes exist. + * Theme source holding every Fluent theme. It follows the system appearance reported by the React Native `Appearance` + * module, and a `ThemeProvider` or `ThemedRoot` `appearance` prop overrides it. High contrast selects the + * high-contrast theme for the color scheme; elevated system settings resolve by color scheme until those Fluent themes + * exist. */ export const fluentTheme: ThemeReference = /* @__PURE__ */ new ThemeReference({ base: {} as Theme, appearance: { colorScheme: 'system', contrast: 'system', interfaceLevel: 'system' }, - recipes: [(_parent, appearance) => (appearance?.colorScheme === 'dark' ? fluentDarkTheme : fluentLightTheme)], + recipes: [ + (_parent, appearance) => { + const dark = appearance?.colorScheme === 'dark'; + if (appearance?.contrast === 'highContrast') { + return dark ? fluentHcDarkTheme : fluentHcLightTheme; + } + return dark ? fluentDarkTheme : fluentLightTheme; + }, + ], }); diff --git a/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx b/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx index 1fbd6a9e36..a5b8a3b7d7 100644 --- a/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx +++ b/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx @@ -9,6 +9,10 @@ import { darkAliasColors, darkShadows, fontAliasTokens, + hcDarkAliasColors, + hcDarkShadows, + hcLightAliasColors, + hcLightShadows, lightAliasColors, lightShadows, } from '../../fluent/defaults/fluentTokens.generated'; @@ -17,12 +21,21 @@ import { useTheme } from '../../fluent/useTheme'; import { useThemeState } from '../../flex/useThemeState'; import { ThemedRoot } from '../../theming/ThemedRoot'; import { ThemeProvider } from '../../theming/ThemeProvider'; -import type { ThemeAppearanceSource, ThemeAppearanceSourceSnapshot } from '../../types/appearance.types'; -import { fluentDarkTheme, fluentLightTheme, fluentTheme } from '../index'; +import type { ResolvedThemeAppearance, ThemeAppearanceSource, ThemeAppearanceSourceSnapshot } from '../../types/appearance.types'; +import { fluentDarkTheme, fluentHcTheme, fluentLightTheme, fluentTheme } from '../index'; +import { fluentHcDarkTheme } from './fluentHcDarkTheme'; +import { fluentHcLightTheme } from './fluentHcLightTheme'; + +const standardLight = { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base' } as const; +const standardDark = { colorScheme: 'dark', contrast: 'standard', interfaceLevel: 'base' } as const; +const hcLight = { colorScheme: 'light', contrast: 'highContrast', interfaceLevel: 'base' } as const; +const hcDark = { colorScheme: 'dark', contrast: 'highContrast', interfaceLevel: 'base' } as const; const themes = [ - ['light', fluentLightTheme, lightAliasColors, lightShadows], - ['dark', fluentDarkTheme, darkAliasColors, darkShadows], + ['light', fluentLightTheme, lightAliasColors, lightShadows, 'light', standardLight], + ['dark', fluentDarkTheme, darkAliasColors, darkShadows, 'dark', standardDark], + ['high-contrast light', fluentHcLightTheme, hcLightAliasColors, hcLightShadows, 'highContrast', hcLight], + ['high-contrast dark', fluentHcDarkTheme, hcDarkAliasColors, hcDarkShadows, 'highContrast', hcDark], ] as const; function undefinedPaths(value: unknown, path = 'theme'): string[] { @@ -58,9 +71,9 @@ function ThemeProbe({ themes: seen }: { themes: Theme[] }) { return null; } -describe.each(themes)('Fluent %s theme', (appearance, theme, aliasColors, shadows) => { +describe.each(themes)('Fluent %s theme', (_name, theme, aliasColors, shadows, hostAppearance, appearance) => { it('carries every Fluent 2 alias color unchanged for its host appearance', () => { - expect(theme.host.appearance).toBe(appearance); + expect(theme.host.appearance).toBe(hostAppearance); for (const [name, color] of Object.entries(aliasColors)) { expect(theme.colors[name]).toBe(color); } @@ -83,7 +96,7 @@ describe.each(themes)('Fluent %s theme', (appearance, theme, aliasColors, shadow }); it('defines every key the legacy default theme defines, with no undefined values', () => { - const legacy = getDefaultLegacyTheme({ colorScheme: appearance, contrast: 'standard', interfaceLevel: 'base' }); + const legacy = getDefaultLegacyTheme(appearance); const missing = [ ...Object.keys(legacy.colors).filter((key) => !(key in theme.colors)), ...Object.keys(legacy.shadows).filter((key) => !(key in theme.shadows)), @@ -103,16 +116,15 @@ describe('fluentTheme', () => { jest.restoreAllMocks(); }); - it('resolves the theme for the requested color scheme, including high contrast and elevated requests', () => { - expect(fluentTheme.resolveTheme({ colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base' }).colors).toBe( - fluentLightTheme.colors, - ); - expect(fluentTheme.resolveTheme({ colorScheme: 'dark', contrast: 'standard', interfaceLevel: 'base' }).colors).toBe( - fluentDarkTheme.colors, - ); - expect(fluentTheme.resolveTheme({ colorScheme: 'dark', contrast: 'highContrast', interfaceLevel: 'elevated' }).host.appearance).toBe( - 'dark', - ); + it.each([ + [standardLight, fluentLightTheme], + [standardDark, fluentDarkTheme], + [{ ...standardDark, interfaceLevel: 'elevated' }, fluentDarkTheme], + [hcLight, fluentHcLightTheme], + [hcDark, fluentHcDarkTheme], + [{ ...hcDark, interfaceLevel: 'elevated' }, fluentHcDarkTheme], + ] as [ResolvedThemeAppearance, Theme][])('resolves %o by contrast and color scheme', (appearance, theme) => { + expect(fluentTheme.resolveTheme(appearance).colors).toBe(theme.colors); }); it('follows the system color scheme from the Appearance module', () => { @@ -142,8 +154,11 @@ describe('fluentTheme', () => { act(() => appearance.update({ colorScheme: 'dark' })); expect(seen.at(-1)?.colors).toBe(fluentDarkTheme.colors); + act(() => appearance.update({ colorScheme: 'dark', contrast: 'highContrast' })); + expect(seen.at(-1)?.colors).toBe(fluentHcDarkTheme.colors); + act(() => component.update(render({ colorScheme: 'light' }))); - expect(seen.at(-1)?.colors).toBe(fluentLightTheme.colors); + expect(seen.at(-1)?.colors).toBe(fluentHcLightTheme.colors); act(() => component.unmount()); }); @@ -172,3 +187,23 @@ describe('fluentTheme', () => { act(() => component.unmount()); }); }); + +describe('fluentHcTheme', () => { + afterEach(() => { + jest.restoreAllMocks(); + }); + + it('resolves the high-contrast theme for the color scheme, whatever contrast is requested', () => { + expect(fluentHcTheme.resolveTheme(standardLight).colors).toBe(fluentHcLightTheme.colors); + expect(fluentHcTheme.resolveTheme(hcDark).colors).toBe(fluentHcDarkTheme.colors); + }); + + it('follows the system color scheme from the Appearance module', () => { + const colorScheme = jest.spyOn(Appearance, 'getColorScheme'); + + colorScheme.mockReturnValue('dark'); + expect(fluentHcTheme.theme).toBe(fluentHcDarkTheme); + colorScheme.mockReturnValue('light'); + expect(fluentHcTheme.theme).toBe(fluentHcLightTheme); + }); +}); diff --git a/packages/agentic/design/src/themes/index.ts b/packages/agentic/design/src/themes/index.ts index 0f4d7c6c09..20b80200f7 100644 --- a/packages/agentic/design/src/themes/index.ts +++ b/packages/agentic/design/src/themes/index.ts @@ -1,5 +1,6 @@ export { flexTheme } from './flex/flexTheme'; export { flexWarmTheme } from './flex/flexWarmTheme'; export { fluentDarkTheme } from './fluent/fluentDarkTheme'; +export { fluentHcTheme } from './fluent/fluentHcTheme'; export { fluentLightTheme } from './fluent/fluentLightTheme'; export { fluentTheme } from './fluent/fluentTheme'; diff --git a/packages/agentic/storybook-desktop-runtime/AGENTS.md b/packages/agentic/storybook-desktop-runtime/AGENTS.md index 27d7fcee9b..a7158feac3 100644 --- a/packages/agentic/storybook-desktop-runtime/AGENTS.md +++ b/packages/agentic/storybook-desktop-runtime/AGENTS.md @@ -15,8 +15,9 @@ authenticated bridge, Metro, theme, and platform chrome. test reporting belong to the integration and harness packages. - Preserve the authenticated nonce, correlated request/run IDs, readiness, error signaling, and native story-root verification. -- Keep one `ThemedRoot` around app content and chrome. Preserve explicit story - background overrides and safe fallback behavior for opaque native colors. +- Keep one Flex `ThemedRoot` around app content and chrome; apply the selected + theme only to story content through the nested provider. Preserve explicit + story background overrides and safe fallback behavior for opaque native colors. - Keep platform-specific behavior in platform files. Preserve Win32's desktop-only chrome and keep macOS/Windows on upstream LiteUI. - Metro configuration has side effects: loading it can generate the runtime diff --git a/packages/agentic/storybook-desktop-runtime/references/runtime-contract.md b/packages/agentic/storybook-desktop-runtime/references/runtime-contract.md index 11efff1819..3987305bb3 100644 --- a/packages/agentic/storybook-desktop-runtime/references/runtime-contract.md +++ b/packages/agentic/storybook-desktop-runtime/references/runtime-contract.md @@ -17,28 +17,30 @@ contracts and fail closed on stale or uncorrelated messages. ## Theme and chrome -One `ThemedRoot` covers the app, toolbar, and chrome. Theme changes update the -preview and chrome without replacing the Storybook instance. macOS and Windows -keep upstream LiteUI; Win32 uses the package's desktop chrome with persistent -resizable sidebar, story preview, bottom addon panel, and optional -Callout-backed pop-outs. Do not add mobile drawer portals or window-dimension -assumptions to the Win32 host. +One Flex `ThemedRoot` covers the app, toolbar, and chrome, so the Storybook +chrome and story canvas always use the Flex theme. Story content receives the +selected theme through a nested `ThemeProvider` that adds no view and shares the +root's input modality. Theme changes update the preview and chrome without +replacing the Storybook instance. macOS and Windows keep upstream LiteUI; Win32 +uses the package's desktop chrome with persistent resizable sidebar, story +preview, bottom addon panel, and optional Callout-backed pop-outs. Do not add +mobile drawer portals or window-dimension assumptions to the Win32 host. The toolbar selects four independent axes from inline dropdown menus: -| Axis | Test-ID segment | Values | -| -------- | --------------- | -------------------------------------------------------------------------------------- | -| Theme | `source` | `flex` (the design package's Flex defaults) or `fluent` (the legacy default theme) | -| Scheme | `scheme` | `light`, `dark`, or `system`, which follows the platform appearance | -| Contrast | `contrast` | `standard` or `highContrast` | -| Tone | `tone` | `cool` or `warm`; Flex only, so it is disabled and reports `cool` for the Fluent theme | - -Both sources receive the selection as one structured appearance request, so a -selection never constructs a new theme reference. The default, Flex, light, -standard, and cool, does not depend on the host appearance. The toolbar is -`<prefix>-theme-toolbar`; each axis trigger is a combobox with test ID -`<prefix>-theme-<segment>` that reports its value and expanded state; its open -menu is `<prefix>-theme-<segment>-menu`; and each option is +| Axis | Test-ID segment | Values | +| -------- | --------------- | ------------------------------------------------------------------------------------------------------- | +| Theme | `source` | Story theme: `flex` (the design package's Flex defaults) or `fluent` (the legacy default theme) | +| Scheme | `scheme` | `light`, `dark`, or `system`, which follows the platform appearance | +| Contrast | `contrast` | `standard` or `highContrast` | +| Tone | `tone` | `cool` or `warm`; Flex only, so it is disabled and reports `cool` for the Fluent theme, chrome included | + +The chrome and story themes receive the selection as one structured appearance +request, so a selection never constructs a new theme reference. The default, +Flex, light, standard, and cool, does not depend on the host appearance. The +toolbar is `<prefix>-theme-toolbar`; each axis trigger is a combobox with test +ID `<prefix>-theme-<segment>` that reports its value and expanded state; its +open menu is `<prefix>-theme-<segment>-menu`; and each option is `<prefix>-theme-<segment>-<value>`. One menu is open at a time, and selecting an option closes it. Native story tests can select a theme configuration through these IDs before asserting. diff --git a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx index 44882b3f29..8f5fc1c155 100644 --- a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx +++ b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.test.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { Appearance, StyleSheet, Text } from 'react-native'; import { fireEvent, render } from '@testing-library/react-native'; -import { useRootSettings, useThemeAppearance, useThemeState } from '@fluentui-react-native/design'; +import { FlexThemeReference, useRootSettings, useThemeAppearance, useThemeState } from '@fluentui-react-native/design'; import type { RootSettings, ThemeAppearanceState, ThemeState } from '@fluentui-react-native/design'; import { ThemeContext } from '@fluentui-react-native/design/theming'; import type { Theme as LegacyTheme } from '@fluentui-react-native/design/theming'; @@ -23,6 +23,7 @@ function createTestApp(storyBackgroundColor?: string) { const roots: RootSettings[] = []; const bridgeRoots: RootSettings[] = []; const themes: ThemeState[] = []; + const chromeThemes: ThemeState[] = []; const appearances: ThemeAppearanceState[] = []; const legacyThemes: (LegacyTheme | undefined)[] = []; const mounted = jest.fn(); @@ -44,7 +45,10 @@ function createTestApp(storyBackgroundColor?: string) { bridgeRoots.push(useRootSettings()); return null; }); - jest.mocked(StorybookUIComponent).mockImplementation(({ children }) => <>{children}</>); + jest.mocked(StorybookUIComponent).mockImplementation(({ children }) => { + chromeThemes.push(useThemeState()); + return <>{children}</>; + }); const getStorybookUI = jest.fn<ReturnType<StorybookView['getStorybookUI']>, Parameters<StorybookView['getStorybookUI']>>((params) => { const UI = params?.CustomUIComponent; @@ -64,7 +68,7 @@ function createTestApp(storyBackgroundColor?: string) { ); }); const App = createDesktopStorybookApp({ getStorybookUI }, { enableWebsockets: false, testIDPrefix: 'test' }); - return { App, roots, bridgeRoots, themes, appearances, legacyThemes, mounted, unmounted, getStorybookUI }; + return { App, roots, bridgeRoots, themes, chromeThemes, appearances, legacyThemes, mounted, unmounted, getStorybookUI }; } async function selectTheme(scene: Scene, axis: string, value: string) { @@ -95,7 +99,7 @@ afterEach(() => { describe('Storybook app theme root', () => { it('places the toolbar, UI, story, and runtime bridge in one deterministic default Flex scene', async () => { - const { App, roots, bridgeRoots, themes, appearances, legacyThemes } = createTestApp(); + const { App, roots, bridgeRoots, themes, chromeThemes, appearances, legacyThemes } = createTestApp(); const scene = await render(<App />); expect(scene.getByTestId('test-app-root')).toBeOnTheScreen(); @@ -117,6 +121,7 @@ describe('Storybook app theme root', () => { }); expect(themes[0].appearance).toBe(appearances[0].resolved); expect(themes[0].tokens).toEqual(defaultFlexTokens); + expect(chromeThemes[0]).toBe(themes[0]); expect(legacyThemes[0]).toBeUndefined(); expect(bridgeRoots.every((root) => root === roots[0])).toBe(true); expect(roots[0].inputModality).toBe('pointer'); @@ -194,8 +199,8 @@ describe('Storybook app theme root', () => { expect(themes[themes.length - 1].appearance.colorScheme).toBe('dark'); }); - it('uses the legacy Fluent default theme without tone and restores the Flex tone', async () => { - const { App, themes, legacyThemes } = createTestApp(); + it('applies the legacy Fluent default theme to stories without tone and restores the Flex tone', async () => { + const { App, themes, chromeThemes, legacyThemes } = createTestApp(); const scene = await render(<App />); await selectTheme(scene, 'tone', 'warm'); @@ -206,6 +211,8 @@ describe('Storybook app theme root', () => { await fireEvent.press(tone); expect(scene.queryByTestId('test-theme-tone-menu')).toBeNull(); expect(themes[themes.length - 1].appearance.colorTone).toBe('cool'); + expect(themes[themes.length - 1].tokens).not.toEqual(defaultFlexTokens); + expect(chromeThemes[chromeThemes.length - 1].tokens).toEqual(defaultFlexTokens); expect(legacyThemes[legacyThemes.length - 1]?.host.appearance).toBe('light'); await selectTheme(scene, 'scheme', 'dark'); @@ -224,22 +231,22 @@ describe('Storybook app theme root', () => { ['flex', 'dark'], ['fluent', 'light'], ['fluent', 'dark'], - ])('keeps the %s %s canvas distinct from the Secondary Button fill', async (source, scheme) => { - const { App, themes } = createTestApp(); + ])('keeps the Flex canvas distinct from the %s %s Secondary Button fill', async (source, scheme) => { + const { App, themes, chromeThemes } = createTestApp(); const scene = await render(<App />); await selectTheme(scene, 'source', source); await selectTheme(scene, 'scheme', scheme); - const state = themes[themes.length - 1]; + const story = themes[themes.length - 1]; + const chrome = chromeThemes[chromeThemes.length - 1]; const theme = latestStorybookTheme(); - expect(theme.background.content).toBe(state.tokens.color.surfaceNeutralFar.rest); + expect(theme.background.content).toBe(chrome.tokens.color.surfaceNeutralFar.rest); expect(theme.background.content).toBe(theme.background.preview); - expect(theme.background.content).not.toBe(state.tokens.color.backgroundNeutralSubtle.rest); + expect(theme.background.content).not.toBe(story.tokens.color.backgroundNeutralSubtle.rest); }); it.each(['#ffeedd', 'transparent'])('preserves the explicit %s story background across theme changes', async (storyBackgroundColor) => { - const warn = jest.spyOn(console, 'warn').mockImplementation(); const { App } = createTestApp(storyBackgroundColor); const scene = await render(<App />); @@ -248,44 +255,46 @@ describe('Storybook app theme root', () => { const calls = jest.mocked(StorybookUIComponent).mock.calls; expect(calls[calls.length - 1][0].storyBackgroundColor).toBe(storyBackgroundColor); } - expect(warn).toHaveBeenCalledWith(expect.stringContaining('Storybook chrome cannot resolve native system colors')); }); - it('switches chrome and story colors together without recreating Storybook or resetting the scene', async () => { - const warn = jest.spyOn(console, 'warn').mockImplementation(); - const { App, roots, themes, mounted, unmounted, getStorybookUI } = createTestApp(); + it('switches Flex chrome and selected story colors together without recreating Storybook or resetting the scene', async () => { + const flex = new FlexThemeReference(); + const { App, roots, themes, chromeThemes, mounted, unmounted, getStorybookUI } = createTestApp(); const scene = await render(<App />); const root = roots[0]; const defaultBackground = themes[0].tokens.color.surfaceNeutralFar.rest; const backgrounds = new Set<unknown>([defaultBackground]); + let source = 'flex'; await fireEvent(scene.getByTestId('test-app-root'), 'keyDownCapture', { nativeEvent: { key: 'Tab' } }); for (const [axis, value] of selectionSteps) { await selectTheme(scene, axis, value); - const state = themes[themes.length - 1]; + source = axis === 'source' ? value : source; + const story = themes[themes.length - 1]; + const chrome = chromeThemes[chromeThemes.length - 1]; + const { color } = chrome.tokens; const theme = latestStorybookTheme(); backgrounds.add(theme.background.app); + expect(chrome.appearance).toEqual(story.appearance); + expect(chrome.tokens).toEqual(flex.resolveFlexTokens(chrome.appearance)); + expect(story === chrome).toBe(source === 'flex'); expect(StyleSheet.flatten(scene.getByTestId('test-theme-toolbar').props.style).backgroundColor).toBe( - state.tokens.color.backgroundNeutralSubtle.rest, + color.backgroundNeutralSubtle.rest, ); - expect(StyleSheet.flatten(scene.getByText('Theme').props.style).color).toBe(state.tokens.color.foregroundNeutralPrimary.rest); - const foreground = theme.base === 'dark' ? state.tokens.color.fixedWhite.rest : state.tokens.color.fixedBlack.rest; - const background = theme.base === 'dark' ? state.tokens.color.fixedBlack.rest : state.tokens.color.fixedWhite.rest; - const literal = (value: unknown, fallback: unknown) => (typeof value === 'string' ? value : fallback); - expect(theme.background.app).toBe(literal(state.tokens.color.surfaceNeutralFar.rest, background)); - expect(theme.background.content).toBe(literal(state.tokens.color.surfaceNeutralFar.rest, background)); - expect(theme.background.preview).toBe(literal(state.tokens.color.surfaceNeutralFar.rest, background)); - expect(theme.color.defaultText).toBe(literal(state.tokens.color.foregroundNeutralPrimary.rest, foreground)); - expect(theme.input.color).toBe(literal(state.tokens.color.foregroundNeutralPrimary.rest, foreground)); - expect(theme.button.background).toBe(literal(state.tokens.color.backgroundNeutralLoud.rest, background)); + expect(StyleSheet.flatten(scene.getByText('Theme').props.style).color).toBe(color.foregroundNeutralPrimary.rest); + expect(theme.background.app).toBe(color.surfaceNeutralFar.rest); + expect(theme.background.content).toBe(color.surfaceNeutralFar.rest); + expect(theme.background.preview).toBe(color.surfaceNeutralFar.rest); + expect(theme.color.defaultText).toBe(color.foregroundNeutralPrimary.rest); + expect(theme.input.color).toBe(color.foregroundNeutralPrimary.rest); + expect(theme.button.background).toBe(color.backgroundNeutralLoud.rest); expect(root.inputModality).toBe('keyboard'); expect(roots.every((settings) => settings === root)).toBe(true); } expect(themes[themes.length - 1].tokens.color.surfaceNeutralFar.rest).toBe(defaultBackground); expect(backgrounds.size).toBeGreaterThan(3); - expect(warn).toHaveBeenCalledWith(expect.stringContaining('Storybook chrome cannot resolve native system colors')); expect(getStorybookUI).toHaveBeenCalledTimes(1); expect(mounted).toHaveBeenCalledTimes(1); expect(unmounted).not.toHaveBeenCalled(); diff --git a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx index d10d06cfff..c18706a18c 100644 --- a/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx +++ b/packages/agentic/storybook-desktop-runtime/src/StorybookTheme.tsx @@ -2,14 +2,14 @@ import * as React from 'react'; import { Pressable, StyleSheet, Text, View } from 'react-native'; import { createDefaultTheme } from '@fluentui-react-native/default-theme'; -import { FlexThemeReference, ThemedRoot, themedStyleSheetFactory, useThemeState } from '@fluentui-react-native/design'; +import { FlexThemeReference, ThemedRoot, ThemeProvider, themedStyleSheetFactory, useThemeState } from '@fluentui-react-native/design'; import type { ColorTone, ThemeAppearanceOptions, ThemeSource } from '@fluentui-react-native/design'; import { useDesktopStorybookTestID } from './DesktopStorybookConfig'; /** The theme configuration selected in the Storybook toolbar. */ export type StorybookThemeSelection = { - /** The package's Flex defaults or the legacy Fluent default theme. */ + /** The story theme: the package's Flex defaults or the legacy Fluent default theme. The chrome always uses Flex. */ source: 'flex' | 'fluent'; colorScheme: 'light' | 'dark' | 'system'; contrast: 'standard' | 'highContrast'; @@ -79,20 +79,46 @@ function isAxisDisabled(key: ThemeAxisKey, selection: StorybookThemeSelection): return key === 'colorTone' && selection.source !== 'flex'; } +type StoryTheme = { + readonly theme: ThemeSource; + readonly appearance: ThemeAppearanceOptions; +}; + +const StoryThemeContext = React.createContext<StoryTheme | undefined>(undefined); + export function StorybookThemeHost({ children }: React.PropsWithChildren) { const [selection, setSelection] = React.useState<StorybookThemeSelection>(defaultStorybookThemeSelection); - const appearance = React.useMemo(() => appearanceFromSelection(selection), [selection]); + const storyTheme = React.useMemo<StoryTheme>( + () => ({ theme: themeSources[selection.source], appearance: appearanceFromSelection(selection) }), + [selection], + ); const testID = useDesktopStorybookTestID('app-root'); + // The chrome always uses Flex at the selected appearance; only story content follows the selected source. return ( - <ThemedRoot appearance={appearance} style={layoutStyles.root} testID={testID} theme={themeSources[selection.source]}> - <StorybookThemeContent selection={selection} onSelectionChange={setSelection}> - {children} - </StorybookThemeContent> + <ThemedRoot appearance={storyTheme.appearance} style={layoutStyles.root} testID={testID} theme={themeSources.flex}> + <StoryThemeContext.Provider value={storyTheme}> + <StorybookThemeContent selection={selection} onSelectionChange={setSelection}> + {children} + </StorybookThemeContent> + </StoryThemeContext.Provider> </ThemedRoot> ); } +/** Applies the selected story theme inside the Flex chrome without adding a view or a second input root. */ +export function StorybookStoryTheme({ children }: React.PropsWithChildren) { + const storyTheme = React.useContext(StoryThemeContext); + if (!storyTheme) { + return <>{children}</>; + } + return ( + <ThemeProvider appearance={storyTheme.appearance} theme={storyTheme.theme}> + {children} + </ThemeProvider> + ); +} + function StorybookThemeContent({ children, selection, diff --git a/packages/agentic/storybook-desktop-runtime/src/ThemedStorybookUI.tsx b/packages/agentic/storybook-desktop-runtime/src/ThemedStorybookUI.tsx index 629a7283bb..7b8654f0f8 100644 --- a/packages/agentic/storybook-desktop-runtime/src/ThemedStorybookUI.tsx +++ b/packages/agentic/storybook-desktop-runtime/src/ThemedStorybookUI.tsx @@ -1,9 +1,14 @@ import type { SBUI } from '@storybook/react-native-ui-common'; +import { StorybookStoryTheme } from './StorybookTheme'; import { StorybookUIComponent } from './StorybookUI'; import { useStorybookTheme } from './useStorybookTheme'; -export const ThemedStorybookUI: SBUI = (props) => { +export const ThemedStorybookUI: SBUI = ({ children, ...props }) => { const theme = useStorybookTheme(); - return <StorybookUIComponent {...props} theme={theme} />; + return ( + <StorybookUIComponent {...props} theme={theme}> + <StorybookStoryTheme>{children}</StorybookStoryTheme> + </StorybookUIComponent> + ); }; diff --git a/packages/components/Badge/src/__tests__/__snapshots__/Badge.test.tsx.snap b/packages/components/Badge/src/__tests__/__snapshots__/Badge.test.tsx.snap index 42e26f68f8..ed4fbdae56 100644 --- a/packages/components/Badge/src/__tests__/__snapshots__/Badge.test.tsx.snap +++ b/packages/components/Badge/src/__tests__/__snapshots__/Badge.test.tsx.snap @@ -8,7 +8,7 @@ exports[`Badge component tests Badge all props 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderColor": "#0f6cbd", "borderRadius": 4, "borderWidth": 1, @@ -29,9 +29,12 @@ exports[`Badge component tests Badge all props 1`] = ` style={ { "color": "#fff", + "dynamicTypeRamp": "body", "fontFamily": "Arial", "fontSize": 16, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -64,8 +67,8 @@ exports[`Badge component tests Badge tokens 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "yellow", - "borderColor": "#f09", + "backgroundColor": "#0f6cbd", + "borderColor": "#00000000", "borderRadius": 9999, "borderWidth": 4, "bottom": 0, @@ -86,6 +89,7 @@ exports[`Badge component tests Badge tokens 1`] = ` numberOfLines={0} style={ { + "color": "#ffffff", "fontFamily": "System", "fontSize": 12, "fontWeight": "400", @@ -104,7 +108,8 @@ exports[`Badge component tests Empty Badge 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#0f6cbd", + "borderColor": "#00000000", "borderRadius": 9999, "borderWidth": 1, "bottom": 0, @@ -126,6 +131,8 @@ exports[`Badge component tests Filled badge with shadow 1`] = ` style={ { "alignSelf": "flex-start", + "backgroundColor": "#0f6cbd", + "borderColor": "#00000000", "borderRadius": 9999, "bottom": 0, "justifyContent": "center", @@ -149,6 +156,8 @@ exports[`Badge component tests Filled badge with shadow 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", + "backgroundColor": "#0f6cbd", + "borderColor": "#00000000", "borderRadius": 9999, "borderWidth": 1, "flexDirection": "row", @@ -173,6 +182,7 @@ exports[`Badge component tests Filled badge with shadow 1`] = ` numberOfLines={0} style={ { + "color": "#ffffff", "fontFamily": "System", "fontSize": 12, "fontWeight": "400", @@ -195,7 +205,8 @@ exports[`CounterBadge component tests CounterBadge all props 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 1, "bottom": 0, @@ -214,9 +225,12 @@ exports[`CounterBadge component tests CounterBadge all props 1`] = ` style={ { "color": "#fff", + "dynamicTypeRamp": "body", "fontFamily": "Arial", "fontSize": 16, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -228,13 +242,13 @@ exports[`CounterBadge component tests CounterBadge all props 1`] = ` numberOfLines={0} style={ { - "color": "#323130", + "color": "#ffffff", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, "textAlign": undefined, "textDecorationLine": undefined, @@ -252,7 +266,8 @@ exports[`CounterBadge component tests CounterBadge shows 99+ 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#0f6cbd", + "borderColor": "#00000000", "borderRadius": 9999, "borderWidth": 1, "bottom": 0, @@ -271,13 +286,13 @@ exports[`CounterBadge component tests CounterBadge shows 99+ 1`] = ` numberOfLines={0} style={ { - "color": "#323130", + "color": "#ffffff", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, "textAlign": undefined, "textDecorationLine": undefined, @@ -295,7 +310,8 @@ exports[`CounterBadge component tests CounterBadge shows 1000+ 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#0f6cbd", + "borderColor": "#00000000", "borderRadius": 9999, "borderWidth": 1, "bottom": 0, @@ -314,13 +330,13 @@ exports[`CounterBadge component tests CounterBadge shows 1000+ 1`] = ` numberOfLines={0} style={ { - "color": "#323130", + "color": "#ffffff", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, "textAlign": undefined, "textDecorationLine": undefined, @@ -339,7 +355,8 @@ exports[`CounterBadge component tests CounterBadge shows zero 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#0f6cbd", + "borderColor": "#00000000", "borderRadius": 9999, "borderWidth": 1, "bottom": 0, @@ -358,13 +375,13 @@ exports[`CounterBadge component tests CounterBadge shows zero 1`] = ` numberOfLines={0} style={ { - "color": "#323130", + "color": "#ffffff", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, "textAlign": undefined, "textDecorationLine": undefined, @@ -402,13 +419,13 @@ exports[`CounterBadge component tests CounterBadge tokens 1`] = ` numberOfLines={0} style={ { - "color": "#323130", + "color": "#ffffff", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, "textAlign": undefined, "textDecorationLine": undefined, diff --git a/packages/components/Button/src/FAB/__snapshots__/FAB.test.tsx.snap b/packages/components/Button/src/FAB/__snapshots__/FAB.test.tsx.snap index b9bccf7e84..1c09067d68 100644 --- a/packages/components/Button/src/FAB/__snapshots__/FAB.test.tsx.snap +++ b/packages/components/Button/src/FAB/__snapshots__/FAB.test.tsx.snap @@ -60,9 +60,12 @@ exports[`Custom FAB with no shadow(iOS) 1`] = ` style={ { "color": "#fff", + "dynamicTypeRamp": "body", "fontFamily": "Arial", "fontSize": 16, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -77,7 +80,7 @@ exports[`Custom FAB with no shadow(iOS) 1`] = ` { "color": "#ffffff", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "600", "margin": 0, "marginBottom": 0, @@ -178,9 +181,12 @@ exports[`Default FAB (iOS) 1`] = ` style={ { "color": "#fff", + "dynamicTypeRamp": "body", "fontFamily": "Arial", "fontSize": 16, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -195,7 +201,7 @@ exports[`Default FAB (iOS) 1`] = ` { "color": "#ffffff", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "600", "margin": 0, "marginBottom": 0, diff --git a/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap b/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap index bff788bf31..50b57be3aa 100644 --- a/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap +++ b/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap @@ -69,7 +69,7 @@ exports[`ToggleButton default 1`] = ` { "color": "#ffffff", "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontWeight": "600", "margin": 0, "marginBottom": 0, diff --git a/packages/components/Button/src/__snapshots__/Button.test.tsx.snap b/packages/components/Button/src/__snapshots__/Button.test.tsx.snap index d088c90b4d..c70b7a40d9 100644 --- a/packages/components/Button/src/__snapshots__/Button.test.tsx.snap +++ b/packages/components/Button/src/__snapshots__/Button.test.tsx.snap @@ -63,7 +63,7 @@ exports[`Button component tests Button circular 1`] = ` { "color": "#ffffff", "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontWeight": "600", "margin": 0, "marginBottom": 0, @@ -139,7 +139,7 @@ exports[`Button component tests Button composed 1`] = ` "color": "#ffffff", "dynamicTypeRamp": undefined, "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontStyle": undefined, "fontWeight": "600", "letterSpacing": undefined, @@ -220,7 +220,7 @@ exports[`Button component tests Button customized 1`] = ` { "color": "#ffffff", "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontWeight": "600", "margin": 0, "marginBottom": 0, @@ -297,7 +297,7 @@ exports[`Button component tests Button default 1`] = ` { "color": "#ffffff", "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontWeight": "600", "margin": 0, "marginBottom": 0, @@ -352,7 +352,7 @@ exports[`Button component tests Button disabled 1`] = ` "alignItems": "center", "alignSelf": "flex-start", "backgroundColor": "#b4d6fa", - "borderColor": "#f3f2f1", + "borderColor": "#e0e0e0", "borderRadius": 8, "borderWidth": 1, "display": "flex", @@ -374,7 +374,7 @@ exports[`Button component tests Button disabled 1`] = ` { "color": "#bdbdbd", "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontWeight": "600", "margin": 0, "marginBottom": 0, @@ -452,7 +452,7 @@ exports[`Button component tests Button large 1`] = ` { "color": "#ffffff", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "600", "margin": 0, "marginBottom": 0, @@ -530,7 +530,7 @@ exports[`Button component tests Button primary 1`] = ` { "color": "#ffffff", "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontWeight": "600", "margin": 0, "marginBottom": 0, @@ -608,7 +608,7 @@ exports[`Button component tests Button small 1`] = ` { "color": "#ffffff", "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontWeight": "600", "margin": 0, "marginBottom": 0, @@ -686,7 +686,7 @@ exports[`Button component tests Button square 1`] = ` { "color": "#ffffff", "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontWeight": "600", "margin": 0, "marginBottom": 0, @@ -741,8 +741,8 @@ exports[`Button component tests Button subtle 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": "#ffffff", - "borderColor": "#ffffff", + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 8, "borderWidth": 1, "display": "flex", @@ -762,9 +762,9 @@ exports[`Button component tests Button subtle 1`] = ` numberOfLines={0} style={ { - "color": "#323130", + "color": "#242424", "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontWeight": "600", "margin": 0, "marginBottom": 0, diff --git a/packages/components/Button/src/__snapshots__/ColorTokens.test.win32.ts.snap b/packages/components/Button/src/__snapshots__/ColorTokens.test.win32.ts.snap index ffb840ffd2..794504e3ac 100644 --- a/packages/components/Button/src/__snapshots__/ColorTokens.test.win32.ts.snap +++ b/packages/components/Button/src/__snapshots__/ColorTokens.test.win32.ts.snap @@ -331,6 +331,7 @@ exports[`Button color tokens pins v1 CompoundButton color tokens 1`] = ` exports[`Button color tokens pins v1 FAB color tokens 1`] = ` { "backgroundColor": "#D83B01", + "color": "#ffffff", "disabled": { "backgroundColor": "#ebebeb", "color": "#B1B1B1", @@ -340,9 +341,14 @@ exports[`Button color tokens pins v1 FAB color tokens 1`] = ` "backgroundColor": "#D83B01", "borderColor": "#969696", "borderInnerColor": "#ffffff", + "color": "#ffffff", + "iconColor": "#ffffff", }, + "iconColor": "#ffffff", "pressed": { "backgroundColor": "#A22C01", + "color": "#ffffff", + "iconColor": "#ffffff", }, "rippleColor": "#D4D4D4", "subtle": { @@ -363,6 +369,8 @@ exports[`Button color tokens pins v1 FAB color tokens 1`] = ` "iconColor": "#aec6eb", "pressed": { "backgroundColor": "#B1B1B1", + "color": "#185abd", + "iconColor": "#185abd", }, "rippleColor": "#D4D4D4", }, diff --git a/packages/components/Button/src/__snapshots__/ColorTokens.test.windows.ts.snap b/packages/components/Button/src/__snapshots__/ColorTokens.test.windows.ts.snap index ffb840ffd2..794504e3ac 100644 --- a/packages/components/Button/src/__snapshots__/ColorTokens.test.windows.ts.snap +++ b/packages/components/Button/src/__snapshots__/ColorTokens.test.windows.ts.snap @@ -331,6 +331,7 @@ exports[`Button color tokens pins v1 CompoundButton color tokens 1`] = ` exports[`Button color tokens pins v1 FAB color tokens 1`] = ` { "backgroundColor": "#D83B01", + "color": "#ffffff", "disabled": { "backgroundColor": "#ebebeb", "color": "#B1B1B1", @@ -340,9 +341,14 @@ exports[`Button color tokens pins v1 FAB color tokens 1`] = ` "backgroundColor": "#D83B01", "borderColor": "#969696", "borderInnerColor": "#ffffff", + "color": "#ffffff", + "iconColor": "#ffffff", }, + "iconColor": "#ffffff", "pressed": { "backgroundColor": "#A22C01", + "color": "#ffffff", + "iconColor": "#ffffff", }, "rippleColor": "#D4D4D4", "subtle": { @@ -363,6 +369,8 @@ exports[`Button color tokens pins v1 FAB color tokens 1`] = ` "iconColor": "#aec6eb", "pressed": { "backgroundColor": "#B1B1B1", + "color": "#185abd", + "iconColor": "#185abd", }, "rippleColor": "#D4D4D4", }, diff --git a/packages/components/Button/src/deprecated/__snapshots__/Button.test.tsx.snap b/packages/components/Button/src/deprecated/__snapshots__/Button.test.tsx.snap index e77d0aed4e..f497a3cd5d 100644 --- a/packages/components/Button/src/deprecated/__snapshots__/Button.test.tsx.snap +++ b/packages/components/Button/src/deprecated/__snapshots__/Button.test.tsx.snap @@ -25,8 +25,8 @@ exports[`Button default 1`] = ` { "alignItems": "flex-start", "alignSelf": "flex-start", - "backgroundColor": "#f3f2f1", - "borderColor": "#8a8886", + "backgroundColor": "#ffffff", + "borderColor": "#d1d1d1", "borderRadius": 4, "borderWidth": 1, "display": "flex", @@ -62,10 +62,13 @@ exports[`Button default 1`] = ` <Text style={ { - "color": "#323130", + "color": "#242424", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, "marginEnd": 2, "marginStart": 2, diff --git a/packages/components/Checkbox/src/__snapshots__/ColorTokens.test.win32.ts.snap b/packages/components/Checkbox/src/__snapshots__/ColorTokens.test.win32.ts.snap index f9978e77c6..e3fd6f5cf7 100644 --- a/packages/components/Checkbox/src/__snapshots__/ColorTokens.test.win32.ts.snap +++ b/packages/components/Checkbox/src/__snapshots__/ColorTokens.test.win32.ts.snap @@ -78,5 +78,6 @@ exports[`Checkbox color tokens pins v1 Checkbox color tokens 1`] = ` "checkmarkColor": "#262626", "color": "#262626", }, + "requiredColor": "#bc2f32", } `; diff --git a/packages/components/Checkbox/src/__snapshots__/ColorTokens.test.windows.ts.snap b/packages/components/Checkbox/src/__snapshots__/ColorTokens.test.windows.ts.snap index f9978e77c6..e3fd6f5cf7 100644 --- a/packages/components/Checkbox/src/__snapshots__/ColorTokens.test.windows.ts.snap +++ b/packages/components/Checkbox/src/__snapshots__/ColorTokens.test.windows.ts.snap @@ -78,5 +78,6 @@ exports[`Checkbox color tokens pins v1 Checkbox color tokens 1`] = ` "checkmarkColor": "#262626", "color": "#262626", }, + "requiredColor": "#bc2f32", } `; diff --git a/packages/components/Checkbox/src/__tests__/__snapshots__/Checkbox.test.tsx.snap b/packages/components/Checkbox/src/__tests__/__snapshots__/Checkbox.test.tsx.snap index a2a9b2013a..c9a9eed6fc 100644 --- a/packages/components/Checkbox/src/__tests__/__snapshots__/Checkbox.test.tsx.snap +++ b/packages/components/Checkbox/src/__tests__/__snapshots__/Checkbox.test.tsx.snap @@ -95,6 +95,7 @@ exports[`Checkbox component tests Checkbox all props 1`] = ` onAccessibilityTap={[Function]} style={ { + "color": "#bc2f32", "fontFamily": "Segoe UI", "fontSize": 14, "fontWeight": "400", diff --git a/packages/components/Chip/src/__snapshots__/ChipColorTokens.test.win32.ts.snap b/packages/components/Chip/src/__snapshots__/ChipColorTokens.test.win32.ts.snap index b71c85659d..55724e9468 100644 --- a/packages/components/Chip/src/__snapshots__/ChipColorTokens.test.win32.ts.snap +++ b/packages/components/Chip/src/__snapshots__/ChipColorTokens.test.win32.ts.snap @@ -4,8 +4,11 @@ exports[`pins Chip color tokens on Win32 1`] = ` { "backgroundColor": "#ebebeb", "brand": { + "backgroundColor": "#d2e0f4", + "color": "#1651aa", "selected": { "backgroundColor": "#D83B01", + "color": "#ffffff", }, }, "color": "#666666", @@ -19,10 +22,17 @@ exports[`pins Chip color tokens on Win32 1`] = ` }, "disabled": { "backgroundColor": "#ebebeb", + "color": "#bdbdbd", }, "searchBar": { "backgroundColor": "#e6e6e6", "brand": { + "backgroundColor": "#d2e0f4", + "color": "#ffffff", + "disabled": { + "backgroundColor": "#d2e0f4", + "color": "#bdbdbd", + }, "selected": { "backgroundColor": "antiquewhite", "color": "#aec6eb", @@ -31,6 +41,11 @@ exports[`pins Chip color tokens on Win32 1`] = ` "color": "#262626", "disabled": { "backgroundColor": "#e6e6e6", + "color": "#bdbdbd", + }, + "selected": { + "backgroundColor": "#616161", + "color": "#ffffff", }, }, "selected": { diff --git a/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap b/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap index 56bd2b201f..0cf1414cd5 100644 --- a/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap +++ b/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap @@ -68,6 +68,8 @@ exports[`Chip component tests Chip all props 1`] = ` "fontFamily": "Arial", "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -81,9 +83,11 @@ exports[`Chip component tests Chip all props 1`] = ` style={ { "color": "#616161", - "fontFamily": "Segoe UI", + "fontFamily": "Roboto", "fontSize": 14, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 18, "margin": 0, "marginStart": 8, } @@ -152,9 +156,11 @@ exports[`Chip component tests Chip tokens 1`] = ` style={ { "color": "#616161", - "fontFamily": "Segoe UI", + "fontFamily": "Roboto", "fontSize": 14, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 18, "margin": 0, } } diff --git a/packages/components/ContextualMenu/src/__tests__/__snapshots__/ContextualMenu.test.tsx.snap b/packages/components/ContextualMenu/src/__tests__/__snapshots__/ContextualMenu.test.tsx.snap index b24e3de055..44bb3b2c6a 100644 --- a/packages/components/ContextualMenu/src/__tests__/__snapshots__/ContextualMenu.test.tsx.snap +++ b/packages/components/ContextualMenu/src/__tests__/__snapshots__/ContextualMenu.test.tsx.snap @@ -17,7 +17,7 @@ exports[`ContextualMenu default props 1`] = ` }, { "backgroundColor": "#ffffff", - "borderColor": "#8a8886", + "borderColor": "#d1d1d1", "borderWidth": 1, }, ] diff --git a/packages/components/Divider/src/__tests__/__snapshots__/Divider.test.tsx.snap b/packages/components/Divider/src/__tests__/__snapshots__/Divider.test.tsx.snap index bca753fb65..65252b5de3 100644 --- a/packages/components/Divider/src/__tests__/__snapshots__/Divider.test.tsx.snap +++ b/packages/components/Divider/src/__tests__/__snapshots__/Divider.test.tsx.snap @@ -135,7 +135,7 @@ exports[`Divider component tests Divider with all props + tokens set 1`] = ` style={ { "color": "red", - "fontFamily": "System", + "fontFamily": "Segoe UI", "fontSize": 10, "fontStyle": "italic", "fontWeight": "600", diff --git a/packages/components/Input/src/__tests__/__snapshots__/Input.test.tsx.snap b/packages/components/Input/src/__tests__/__snapshots__/Input.test.tsx.snap index ffe805c2a6..d7962eadb6 100644 --- a/packages/components/Input/src/__tests__/__snapshots__/Input.test.tsx.snap +++ b/packages/components/Input/src/__tests__/__snapshots__/Input.test.tsx.snap @@ -51,12 +51,12 @@ exports[`Input component tests Input default 1`] = ` "dynamicTypeRamp": undefined, "flexGrow": 1, "flexShrink": 1, - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginBottom": 0, "marginEnd": 0, @@ -125,12 +125,12 @@ exports[`Input component tests Input in error state 1`] = ` "dynamicTypeRamp": undefined, "flexGrow": 1, "flexShrink": 1, - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginBottom": 0, "marginEnd": 0, @@ -147,6 +147,11 @@ exports[`Input component tests Input in error state 1`] = ` style={ { "color": "#bc2f32", + "fontFamily": "Roboto", + "fontSize": 12, + "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 16, "margin": 0, "marginBottom": 0, "marginEnd": 0, @@ -193,6 +198,11 @@ exports[`Input component tests Input with all optional text 1`] = ` style={ { "color": "#616161", + "fontFamily": "Roboto", + "fontSize": 12, + "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 16, "margin": 0, "marginBottom": 0, "marginEnd": 0, @@ -228,12 +238,12 @@ exports[`Input component tests Input with all optional text 1`] = ` "dynamicTypeRamp": undefined, "flexGrow": 1, "flexShrink": 1, - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginBottom": 0, "marginEnd": 0, @@ -250,6 +260,11 @@ exports[`Input component tests Input with all optional text 1`] = ` style={ { "color": "#616161", + "fontFamily": "Roboto", + "fontSize": 12, + "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 16, "margin": 0, "marginBottom": 0, "marginEnd": 0, @@ -320,6 +335,8 @@ exports[`Input component tests Input with icon 1`] = ` "fontFamily": "Arial", "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -351,12 +368,12 @@ exports[`Input component tests Input with icon 1`] = ` "dynamicTypeRamp": undefined, "flexGrow": 1, "flexShrink": 1, - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginBottom": 0, "marginEnd": 0, @@ -426,12 +443,12 @@ exports[`Input component tests Input with placeholder 1`] = ` "dynamicTypeRamp": undefined, "flexGrow": 1, "flexShrink": 1, - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginBottom": 0, "marginEnd": 0, @@ -500,12 +517,12 @@ exports[`Input component tests Input without accessoryIcon 1`] = ` "dynamicTypeRamp": undefined, "flexGrow": 1, "flexShrink": 1, - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginBottom": 0, "marginEnd": 0, diff --git a/packages/components/Link/src/__tests__/__snapshots__/Link.test.tsx.snap b/packages/components/Link/src/__tests__/__snapshots__/Link.test.tsx.snap index 209cbebd0a..eea6c11f77 100644 --- a/packages/components/Link/src/__tests__/__snapshots__/Link.test.tsx.snap +++ b/packages/components/Link/src/__tests__/__snapshots__/Link.test.tsx.snap @@ -40,9 +40,11 @@ exports[`Link component tests Default Link 1`] = ` { "alignSelf": "flex-start", "color": "#0f6cbd", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -91,9 +93,11 @@ exports[`Link component tests Default Link as a pressable 1`] = ` { "alignSelf": "flex-start", "color": "#0f6cbd", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -143,9 +147,11 @@ exports[`Link component tests Inline Link 1`] = ` { "alignSelf": "flex-start", "color": "#0f6cbd", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "textDecorationLine": "underline", } @@ -197,9 +203,11 @@ exports[`Link component tests Subtle Link 1`] = ` { "alignSelf": "flex-start", "color": "#0f6cbd", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } diff --git a/packages/components/Link/src/legacy/__tests__/__snapshots__/Link.test.tsx.snap b/packages/components/Link/src/legacy/__tests__/__snapshots__/Link.test.tsx.snap index 87b44b3d00..3d1f326295 100644 --- a/packages/components/Link/src/legacy/__tests__/__snapshots__/Link.test.tsx.snap +++ b/packages/components/Link/src/legacy/__tests__/__snapshots__/Link.test.tsx.snap @@ -34,9 +34,11 @@ exports[`Link all props 1`] = ` "borderStyle": "solid", "borderWidth": 2, "color": "#0f6cbd", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "textAlign": "center", "textDecorationLine": "underline", @@ -82,9 +84,11 @@ exports[`Link with child 1`] = ` "borderStyle": "solid", "borderWidth": 2, "color": "#0f6cbd", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "textAlign": "center", "textDecorationLine": "underline", diff --git a/packages/components/Notification/src/__tests__/__snapshots__/Notification.test.tsx.snap b/packages/components/Notification/src/__tests__/__snapshots__/Notification.test.tsx.snap index 5bfc706d5f..bd1cfcaa43 100644 --- a/packages/components/Notification/src/__tests__/__snapshots__/Notification.test.tsx.snap +++ b/packages/components/Notification/src/__tests__/__snapshots__/Notification.test.tsx.snap @@ -78,6 +78,8 @@ exports[`Notification component tests Notification default 1`] = ` "fontFamily": "System", "fontSize": 15, "fontWeight": "400", + "letterSpacing": -0.23, + "lineHeight": 20, "margin": 0, } } @@ -141,7 +143,7 @@ exports[`Notification component tests Notification default 1`] = ` "alignItems": "center", "alignSelf": "center", "backgroundColor": "transparent", - "borderColor": "#ffffff", + "borderColor": "#00000000", "borderRadius": 8, "borderWidth": 1, "display": "flex", @@ -164,8 +166,10 @@ exports[`Notification component tests Notification default 1`] = ` { "color": "#0f548c", "fontFamily": "System", - "fontSize": 12, + "fontSize": 13, "fontWeight": "600", + "letterSpacing": -0.23, + "lineHeight": 20, "margin": 0, "marginBottom": 0, "marginEnd": 0, diff --git a/packages/components/RadioGroup/src/Radio/__tests__/__snapshots__/RadioExperimental.test.tsx.snap b/packages/components/RadioGroup/src/Radio/__tests__/__snapshots__/RadioExperimental.test.tsx.snap index 2fa97ebaf8..046fddbabb 100644 --- a/packages/components/RadioGroup/src/Radio/__tests__/__snapshots__/RadioExperimental.test.tsx.snap +++ b/packages/components/RadioGroup/src/Radio/__tests__/__snapshots__/RadioExperimental.test.tsx.snap @@ -150,9 +150,11 @@ exports[`Radio component tests Radio default 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -314,9 +316,11 @@ exports[`Radio component tests Radio disabled 1`] = ` style={ { "color": "#bdbdbd", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } diff --git a/packages/components/RadioGroup/src/RadioGroup/__tests__/__snapshots__/RadioGroupExperimental.test.tsx.snap b/packages/components/RadioGroup/src/RadioGroup/__tests__/__snapshots__/RadioGroupExperimental.test.tsx.snap index 94b276b5ec..22ec0c35bb 100644 --- a/packages/components/RadioGroup/src/RadioGroup/__tests__/__snapshots__/RadioGroupExperimental.test.tsx.snap +++ b/packages/components/RadioGroup/src/RadioGroup/__tests__/__snapshots__/RadioGroupExperimental.test.tsx.snap @@ -36,9 +36,11 @@ exports[`RadioGroup component tests Radio not direct child of radio group 1`] = style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, - "fontWeight": "600", + "fontFamily": "Roboto", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -205,9 +207,11 @@ exports[`RadioGroup component tests Radio not direct child of radio group 1`] = style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -366,9 +370,11 @@ exports[`RadioGroup component tests Radio not direct child of radio group 1`] = style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -418,9 +424,11 @@ exports[`RadioGroup component tests RadioGroup default 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, - "fontWeight": "600", + "fontFamily": "Roboto", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -587,9 +595,11 @@ exports[`RadioGroup component tests RadioGroup default 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -748,9 +758,11 @@ exports[`RadioGroup component tests RadioGroup default 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -800,9 +812,11 @@ exports[`RadioGroup component tests RadioGroup disabled 1`] = ` style={ { "color": "#bdbdbd", - "fontFamily": "Segoe UI", - "fontSize": 13, - "fontWeight": "600", + "fontFamily": "Roboto", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -969,9 +983,11 @@ exports[`RadioGroup component tests RadioGroup disabled 1`] = ` style={ { "color": "#bdbdbd", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -1130,9 +1146,11 @@ exports[`RadioGroup component tests RadioGroup disabled 1`] = ` style={ { "color": "#bdbdbd", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -1183,9 +1201,11 @@ exports[`RadioGroup component tests RadioGroup horizontal 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, - "fontWeight": "600", + "fontFamily": "Roboto", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -1352,9 +1372,11 @@ exports[`RadioGroup component tests RadioGroup horizontal 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -1513,9 +1535,11 @@ exports[`RadioGroup component tests RadioGroup horizontal 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -1566,9 +1590,11 @@ exports[`RadioGroup component tests RadioGroup horizontal-stacked 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, - "fontWeight": "600", + "fontFamily": "Roboto", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -1735,9 +1761,11 @@ exports[`RadioGroup component tests RadioGroup horizontal-stacked 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -1896,9 +1924,11 @@ exports[`RadioGroup component tests RadioGroup horizontal-stacked 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -1948,9 +1978,11 @@ exports[`RadioGroup component tests RadioGroup required 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, - "fontWeight": "600", + "fontFamily": "Roboto", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -1963,9 +1995,11 @@ exports[`RadioGroup component tests RadioGroup required 1`] = ` style={ { "color": "#750b1c", - "fontFamily": "Segoe UI", - "fontSize": 13, - "fontWeight": "600", + "fontFamily": "Roboto", + "fontSize": 16, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "paddingStart": 2, } @@ -2133,9 +2167,11 @@ exports[`RadioGroup component tests RadioGroup required 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } @@ -2294,9 +2330,11 @@ exports[`RadioGroup component tests RadioGroup required 1`] = ` style={ { "color": "#242424", - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginHorizontal": 2, } diff --git a/packages/components/RadioGroup/src/__tests__/__snapshots__/ColorTokens.test.win32.ts.snap b/packages/components/RadioGroup/src/__tests__/__snapshots__/ColorTokens.test.win32.ts.snap index e4f3fc0cb8..0b1a358b22 100644 --- a/packages/components/RadioGroup/src/__tests__/__snapshots__/ColorTokens.test.win32.ts.snap +++ b/packages/components/RadioGroup/src/__tests__/__snapshots__/ColorTokens.test.win32.ts.snap @@ -85,5 +85,6 @@ exports[`RadioGroup color tokens pins RadioGroup v1 colors: RadioGroup v1 1`] = "disabled": { "color": "#B1B1B1", }, + "requiredColor": "#d13438", } `; diff --git a/packages/components/RadioGroup/src/__tests__/__snapshots__/ColorTokens.test.windows.ts.snap b/packages/components/RadioGroup/src/__tests__/__snapshots__/ColorTokens.test.windows.ts.snap index e4f3fc0cb8..0b1a358b22 100644 --- a/packages/components/RadioGroup/src/__tests__/__snapshots__/ColorTokens.test.windows.ts.snap +++ b/packages/components/RadioGroup/src/__tests__/__snapshots__/ColorTokens.test.windows.ts.snap @@ -85,5 +85,6 @@ exports[`RadioGroup color tokens pins RadioGroup v1 colors: RadioGroup v1 1`] = "disabled": { "color": "#B1B1B1", }, + "requiredColor": "#d13438", } `; diff --git a/packages/components/RadioGroup/src/legacy/__tests__/__snapshots__/RadioButton.test.tsx.snap b/packages/components/RadioGroup/src/legacy/__tests__/__snapshots__/RadioButton.test.tsx.snap index 29917aaf2f..ee10064d3f 100644 --- a/packages/components/RadioGroup/src/legacy/__tests__/__snapshots__/RadioButton.test.tsx.snap +++ b/packages/components/RadioGroup/src/legacy/__tests__/__snapshots__/RadioButton.test.tsx.snap @@ -48,7 +48,7 @@ exports[`RadioButton component tests RadioButton default 1`] = ` style={ { "backgroundColor": "transparent", - "borderColor": "#323130", + "borderColor": "#242424", "borderRadius": 10, "borderStyle": "solid", "borderWidth": 1, @@ -66,7 +66,7 @@ exports[`RadioButton component tests RadioButton default 1`] = ` <View style={ { - "backgroundColor": "#323130", + "backgroundColor": "#242424", "borderRadius": 5, "height": 10, "left": 4, @@ -84,10 +84,12 @@ exports[`RadioButton component tests RadioButton default 1`] = ` "borderColor": "transparent", "borderStyle": "solid", "borderWidth": 2, - "color": "#323130", - "fontFamily": "Segoe UI", - "fontSize": 16, - "fontWeight": "400", + "color": "#242424", + "fontFamily": "Roboto", + "fontSize": 18, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginTop": 2, } diff --git a/packages/components/RadioGroup/src/legacy/__tests__/__snapshots__/RadioButtonGroup.test.tsx.snap b/packages/components/RadioGroup/src/legacy/__tests__/__snapshots__/RadioButtonGroup.test.tsx.snap index 21112a731d..60e18bd51c 100644 --- a/packages/components/RadioGroup/src/legacy/__tests__/__snapshots__/RadioButtonGroup.test.tsx.snap +++ b/packages/components/RadioGroup/src/legacy/__tests__/__snapshots__/RadioButtonGroup.test.tsx.snap @@ -16,10 +16,12 @@ exports[`RadioButton component tests RadioButton default 1`] = ` <Text style={ { - "color": "#323130", - "fontFamily": "Segoe UI", + "color": "#242424", + "fontFamily": "Roboto", "fontSize": 16, "fontWeight": "600", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -76,7 +78,7 @@ exports[`RadioButton component tests RadioButton default 1`] = ` style={ { "backgroundColor": "transparent", - "borderColor": "#323130", + "borderColor": "#242424", "borderRadius": 10, "borderStyle": "solid", "borderWidth": 1, @@ -94,7 +96,7 @@ exports[`RadioButton component tests RadioButton default 1`] = ` <View style={ { - "backgroundColor": "#323130", + "backgroundColor": "#242424", "borderRadius": 5, "height": 10, "left": 4, @@ -112,10 +114,12 @@ exports[`RadioButton component tests RadioButton default 1`] = ` "borderColor": "transparent", "borderStyle": "solid", "borderWidth": 2, - "color": "#323130", - "fontFamily": "Segoe UI", - "fontSize": 16, - "fontWeight": "400", + "color": "#242424", + "fontFamily": "Roboto", + "fontSize": 18, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginTop": 2, } @@ -171,7 +175,7 @@ exports[`RadioButton component tests RadioButton default 1`] = ` style={ { "backgroundColor": "transparent", - "borderColor": "#323130", + "borderColor": "#242424", "borderRadius": 10, "borderStyle": "solid", "borderWidth": 1, @@ -189,7 +193,7 @@ exports[`RadioButton component tests RadioButton default 1`] = ` <View style={ { - "backgroundColor": "#323130", + "backgroundColor": "#242424", "borderRadius": 5, "height": 10, "left": 4, @@ -207,10 +211,12 @@ exports[`RadioButton component tests RadioButton default 1`] = ` "borderColor": "transparent", "borderStyle": "solid", "borderWidth": 2, - "color": "#323130", - "fontFamily": "Segoe UI", - "fontSize": 16, - "fontWeight": "400", + "color": "#242424", + "fontFamily": "Roboto", + "fontSize": 18, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginTop": 2, } @@ -239,10 +245,12 @@ exports[`RadioButton component tests RadioButton not direct child of radio group <Text style={ { - "color": "#323130", - "fontFamily": "Segoe UI", + "color": "#242424", + "fontFamily": "Roboto", "fontSize": 16, "fontWeight": "600", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -300,7 +308,7 @@ exports[`RadioButton component tests RadioButton not direct child of radio group style={ { "backgroundColor": "transparent", - "borderColor": "#323130", + "borderColor": "#242424", "borderRadius": 10, "borderStyle": "solid", "borderWidth": 1, @@ -318,7 +326,7 @@ exports[`RadioButton component tests RadioButton not direct child of radio group <View style={ { - "backgroundColor": "#323130", + "backgroundColor": "#242424", "borderRadius": 5, "height": 10, "left": 4, @@ -336,10 +344,12 @@ exports[`RadioButton component tests RadioButton not direct child of radio group "borderColor": "transparent", "borderStyle": "solid", "borderWidth": 2, - "color": "#323130", - "fontFamily": "Segoe UI", - "fontSize": 16, - "fontWeight": "400", + "color": "#242424", + "fontFamily": "Roboto", + "fontSize": 18, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginTop": 2, } @@ -395,7 +405,7 @@ exports[`RadioButton component tests RadioButton not direct child of radio group style={ { "backgroundColor": "transparent", - "borderColor": "#323130", + "borderColor": "#242424", "borderRadius": 10, "borderStyle": "solid", "borderWidth": 1, @@ -413,7 +423,7 @@ exports[`RadioButton component tests RadioButton not direct child of radio group <View style={ { - "backgroundColor": "#323130", + "backgroundColor": "#242424", "borderRadius": 5, "height": 10, "left": 4, @@ -431,10 +441,12 @@ exports[`RadioButton component tests RadioButton not direct child of radio group "borderColor": "transparent", "borderStyle": "solid", "borderWidth": 2, - "color": "#323130", - "fontFamily": "Segoe UI", - "fontSize": 16, - "fontWeight": "400", + "color": "#242424", + "fontFamily": "Roboto", + "fontSize": 18, + "fontWeight": "500", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "marginTop": 2, } diff --git a/packages/components/Stack/src/__tests__/__snapshots__/Stack.test.tsx.snap b/packages/components/Stack/src/__tests__/__snapshots__/Stack.test.tsx.snap index cdf90f64c3..31d16876d8 100644 --- a/packages/components/Stack/src/__tests__/__snapshots__/Stack.test.tsx.snap +++ b/packages/components/Stack/src/__tests__/__snapshots__/Stack.test.tsx.snap @@ -13,7 +13,7 @@ exports[`Stack with tokens 1`] = ` <Text style={ { - "color": "#323130", + "color": "#242424", "fontFamily": "Segoe UI", "fontSize": 12, "fontWeight": "400", @@ -26,7 +26,7 @@ exports[`Stack with tokens 1`] = ` <Text style={ { - "color": "#323130", + "color": "#242424", "fontFamily": "Segoe UI", "fontSize": 12, "fontWeight": "400", @@ -40,7 +40,7 @@ exports[`Stack with tokens 1`] = ` <Text style={ { - "color": "#323130", + "color": "#242424", "fontFamily": "Segoe UI", "fontSize": 12, "fontWeight": "400", diff --git a/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap b/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap index 5e31d6bc58..918c0207fe 100644 --- a/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap +++ b/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap @@ -71,9 +71,11 @@ exports[`Switch Default 1`] = ` { "color": "#242424", "flexShrink": 1, - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } @@ -197,9 +199,11 @@ exports[`Switch Disabled 1`] = ` { "color": "#e0e0e0", "flexShrink": 1, - "fontFamily": "Segoe UI", - "fontSize": 13, + "fontFamily": "Roboto", + "fontSize": 16, "fontWeight": "400", + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, } } diff --git a/packages/components/TabList/src/Tab/__tests__/__snapshots__/Tab.test.tsx.snap b/packages/components/TabList/src/Tab/__tests__/__snapshots__/Tab.test.tsx.snap index 5b70717ea0..abc5b2e3cc 100644 --- a/packages/components/TabList/src/Tab/__tests__/__snapshots__/Tab.test.tsx.snap +++ b/packages/components/TabList/src/Tab/__tests__/__snapshots__/Tab.test.tsx.snap @@ -48,7 +48,8 @@ exports[`Tab component tests Customized Tab 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -88,9 +89,12 @@ exports[`Tab component tests Customized Tab 1`] = ` style={ { "color": "red", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -102,7 +106,7 @@ exports[`Tab component tests Customized Tab 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 4, "paddingHorizontal": 8, "width": "100%", @@ -112,7 +116,7 @@ exports[`Tab component tests Customized Tab 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -170,7 +174,8 @@ exports[`Tab component tests Tab default props 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -210,9 +215,12 @@ exports[`Tab component tests Tab default props 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -224,7 +232,7 @@ exports[`Tab component tests Tab default props 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 8, "width": "100%", @@ -234,7 +242,7 @@ exports[`Tab component tests Tab default props 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -292,7 +300,8 @@ exports[`Tab component tests Tab disabled 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -331,9 +340,13 @@ exports[`Tab component tests Tab disabled 1`] = ` numberOfLines={1} style={ { + "color": "#bdbdbd", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -345,7 +358,7 @@ exports[`Tab component tests Tab disabled 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 8, "width": "100%", @@ -355,7 +368,7 @@ exports[`Tab component tests Tab disabled 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -413,7 +426,8 @@ exports[`Tab component tests Tab render icon + text 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -465,9 +479,12 @@ exports[`Tab component tests Tab render icon + text 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -479,7 +496,7 @@ exports[`Tab component tests Tab render icon + text 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 8, "width": "100%", @@ -489,7 +506,7 @@ exports[`Tab component tests Tab render icon + text 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -547,7 +564,8 @@ exports[`Tab component tests Tab render icon only 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -588,7 +606,7 @@ exports[`Tab component tests Tab render icon only 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 8, "width": "100%", @@ -598,7 +616,7 @@ exports[`Tab component tests Tab render icon only 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } diff --git a/packages/components/TabList/src/TabList/__tests__/__snapshots__/TabList.test.tsx.snap b/packages/components/TabList/src/TabList/__tests__/__snapshots__/TabList.test.tsx.snap index 04b11362c0..de6a2f0615 100644 --- a/packages/components/TabList/src/TabList/__tests__/__snapshots__/TabList.test.tsx.snap +++ b/packages/components/TabList/src/TabList/__tests__/__snapshots__/TabList.test.tsx.snap @@ -86,7 +86,8 @@ exports[`TabList component tests TabList appearance 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -126,9 +127,12 @@ exports[`TabList component tests TabList appearance 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -140,7 +144,7 @@ exports[`TabList component tests TabList appearance 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -150,7 +154,7 @@ exports[`TabList component tests TabList appearance 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -205,7 +209,8 @@ exports[`TabList component tests TabList appearance 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -245,9 +250,12 @@ exports[`TabList component tests TabList appearance 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -259,7 +267,7 @@ exports[`TabList component tests TabList appearance 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -269,7 +277,7 @@ exports[`TabList component tests TabList appearance 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -324,7 +332,8 @@ exports[`TabList component tests TabList appearance 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -364,9 +373,12 @@ exports[`TabList component tests TabList appearance 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -378,7 +390,7 @@ exports[`TabList component tests TabList appearance 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -388,7 +400,7 @@ exports[`TabList component tests TabList appearance 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -487,7 +499,8 @@ exports[`TabList component tests TabList default props 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -527,9 +540,12 @@ exports[`TabList component tests TabList default props 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -541,7 +557,7 @@ exports[`TabList component tests TabList default props 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -551,7 +567,7 @@ exports[`TabList component tests TabList default props 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -606,7 +622,8 @@ exports[`TabList component tests TabList default props 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -646,9 +663,12 @@ exports[`TabList component tests TabList default props 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -660,7 +680,7 @@ exports[`TabList component tests TabList default props 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -670,7 +690,7 @@ exports[`TabList component tests TabList default props 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -725,7 +745,8 @@ exports[`TabList component tests TabList default props 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -765,9 +786,12 @@ exports[`TabList component tests TabList default props 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -779,7 +803,7 @@ exports[`TabList component tests TabList default props 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -789,7 +813,7 @@ exports[`TabList component tests TabList default props 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -888,7 +912,8 @@ exports[`TabList component tests TabList disabled list 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -927,9 +952,13 @@ exports[`TabList component tests TabList disabled list 1`] = ` numberOfLines={1} style={ { + "color": "#bdbdbd", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -941,7 +970,7 @@ exports[`TabList component tests TabList disabled list 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -951,7 +980,7 @@ exports[`TabList component tests TabList disabled list 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -1006,7 +1035,8 @@ exports[`TabList component tests TabList disabled list 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -1045,9 +1075,13 @@ exports[`TabList component tests TabList disabled list 1`] = ` numberOfLines={1} style={ { + "color": "#bdbdbd", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -1059,7 +1093,7 @@ exports[`TabList component tests TabList disabled list 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -1069,7 +1103,7 @@ exports[`TabList component tests TabList disabled list 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -1124,7 +1158,8 @@ exports[`TabList component tests TabList disabled list 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -1163,9 +1198,13 @@ exports[`TabList component tests TabList disabled list 1`] = ` numberOfLines={1} style={ { + "color": "#bdbdbd", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -1177,7 +1216,7 @@ exports[`TabList component tests TabList disabled list 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -1187,7 +1226,7 @@ exports[`TabList component tests TabList disabled list 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -1286,7 +1325,8 @@ exports[`TabList component tests TabList orientation 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -1325,9 +1365,12 @@ exports[`TabList component tests TabList orientation 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -1339,7 +1382,7 @@ exports[`TabList component tests TabList orientation 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": "100%", "paddingVertical": 12, "width": 2, @@ -1349,7 +1392,7 @@ exports[`TabList component tests TabList orientation 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -1404,7 +1447,8 @@ exports[`TabList component tests TabList orientation 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -1443,9 +1487,12 @@ exports[`TabList component tests TabList orientation 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -1457,7 +1504,7 @@ exports[`TabList component tests TabList orientation 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": "100%", "paddingVertical": 12, "width": 2, @@ -1467,7 +1514,7 @@ exports[`TabList component tests TabList orientation 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -1522,7 +1569,8 @@ exports[`TabList component tests TabList orientation 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -1561,9 +1609,12 @@ exports[`TabList component tests TabList orientation 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -1575,7 +1626,7 @@ exports[`TabList component tests TabList orientation 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": "100%", "paddingVertical": 12, "width": 2, @@ -1585,7 +1636,7 @@ exports[`TabList component tests TabList orientation 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -1685,7 +1736,8 @@ exports[`TabList component tests TabList selected key 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -1725,9 +1777,12 @@ exports[`TabList component tests TabList selected key 1`] = ` style={ { "color": "#242424", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "600", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -1739,7 +1794,7 @@ exports[`TabList component tests TabList selected key 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -1749,7 +1804,7 @@ exports[`TabList component tests TabList selected key 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#0f6cbd", "borderRadius": 99, "flex": 1, } @@ -1804,7 +1859,8 @@ exports[`TabList component tests TabList selected key 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -1844,9 +1900,12 @@ exports[`TabList component tests TabList selected key 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -1858,7 +1917,7 @@ exports[`TabList component tests TabList selected key 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -1868,7 +1927,7 @@ exports[`TabList component tests TabList selected key 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -1923,7 +1982,8 @@ exports[`TabList component tests TabList selected key 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -1963,9 +2023,12 @@ exports[`TabList component tests TabList selected key 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "body", "fontFamily": "System", - "fontSize": 13, + "fontSize": 17, "fontWeight": "400", + "letterSpacing": -0.43, + "lineHeight": 22, "margin": 0, } } @@ -1977,7 +2040,7 @@ exports[`TabList component tests TabList selected key 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -1987,7 +2050,7 @@ exports[`TabList component tests TabList selected key 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -2086,7 +2149,8 @@ exports[`TabList component tests TabList size 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -2126,9 +2190,12 @@ exports[`TabList component tests TabList size 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "subheadline", "fontFamily": "System", "fontSize": 15, "fontWeight": "400", + "letterSpacing": -0.23, + "lineHeight": 20, "margin": 0, } } @@ -2140,7 +2207,7 @@ exports[`TabList component tests TabList size 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -2150,7 +2217,7 @@ exports[`TabList component tests TabList size 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -2205,7 +2272,8 @@ exports[`TabList component tests TabList size 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -2245,9 +2313,12 @@ exports[`TabList component tests TabList size 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "subheadline", "fontFamily": "System", "fontSize": 15, "fontWeight": "400", + "letterSpacing": -0.23, + "lineHeight": 20, "margin": 0, } } @@ -2259,7 +2330,7 @@ exports[`TabList component tests TabList size 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -2269,7 +2340,7 @@ exports[`TabList component tests TabList size 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } @@ -2324,7 +2395,8 @@ exports[`TabList component tests TabList size 1`] = ` { "alignItems": "center", "alignSelf": "flex-start", - "backgroundColor": undefined, + "backgroundColor": "#00000000", + "borderColor": "#00000000", "borderRadius": 4, "borderWidth": 2, "display": "flex", @@ -2364,9 +2436,12 @@ exports[`TabList component tests TabList size 1`] = ` style={ { "color": "#616161", + "dynamicTypeRamp": "subheadline", "fontFamily": "System", "fontSize": 15, "fontWeight": "400", + "letterSpacing": -0.23, + "lineHeight": 20, "margin": 0, } } @@ -2378,7 +2453,7 @@ exports[`TabList component tests TabList size 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "height": 2, "paddingHorizontal": 12, "width": "100%", @@ -2388,7 +2463,7 @@ exports[`TabList component tests TabList size 1`] = ` <View style={ { - "backgroundColor": undefined, + "backgroundColor": "#00000000", "borderRadius": 99, "flex": 1, } diff --git a/packages/components/Text/src/__tests__/__snapshots__/Text.test.tsx.snap b/packages/components/Text/src/__tests__/__snapshots__/Text.test.tsx.snap index 38f12106fe..7cf39e4d93 100644 --- a/packages/components/Text/src/__tests__/__snapshots__/Text.test.tsx.snap +++ b/packages/components/Text/src/__tests__/__snapshots__/Text.test.tsx.snap @@ -6,13 +6,13 @@ exports[`Text component tests Text all props 1`] = ` numberOfLines={0} style={ { - "color": "#323130", - "fontFamily": "Segoe UI", + "color": "#242424", + "fontFamily": "Roboto", "fontSize": 14, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": 0, + "lineHeight": 18, "margin": 0, "textAlign": undefined, "textDecorationLine": undefined, @@ -29,13 +29,13 @@ exports[`Text component tests Text all tokens 1`] = ` numberOfLines={0} style={ { - "color": "#323130", + "color": "#242424", "fontFamily": "Wingdings", "fontSize": 20, "fontStyle": undefined, "fontWeight": "900", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "textAlign": undefined, "textDecorationLine": undefined, @@ -52,13 +52,13 @@ exports[`Text component tests Text default 1`] = ` numberOfLines={0} style={ { - "color": "#323130", - "fontFamily": "Segoe UI", - "fontSize": 13, + "color": "#242424", + "fontFamily": "Roboto", + "fontSize": 16, "fontStyle": undefined, "fontWeight": "400", - "letterSpacing": undefined, - "lineHeight": undefined, + "letterSpacing": 0, + "lineHeight": 24, "margin": 0, "textAlign": undefined, "textDecorationLine": undefined, @@ -76,9 +76,11 @@ exports[`Text component tests Text variants render correctly with style 1`] = ` style={ { "color": "blue", - "fontFamily": "Segoe UI", + "fontFamily": "Roboto", "fontSize": 60, - "fontWeight": "600", + "fontWeight": "400", + "letterSpacing": -0.5, + "lineHeight": 72, "margin": 0, "marginBottom": 8, "marginTop": 4, diff --git a/packages/theming/default-theme/README.md b/packages/theming/default-theme/README.md index 41804f4aa6..a35dea3798 100644 --- a/packages/theming/default-theme/README.md +++ b/packages/theming/default-theme/README.md @@ -1,3 +1,6 @@ # default-theme -A pure base theme for the fluentui-react-native components, defined purely in JavaScript +The Fluent default themes for the fluentui-react-native components. `defaultFluentTheme` and `defaultFluentDarkTheme` +are the `@fluentui-react-native/design` package's `fluentLightTheme` and `fluentDarkTheme`, and `createDefaultTheme` +returns a `ThemeReference` that resolves the design package's `fluentTheme`, including its high-contrast themes, for the +requested appearance. diff --git a/packages/theming/default-theme/package.json b/packages/theming/default-theme/package.json index 2119ac15dd..2168dd7f2d 100644 --- a/packages/theming/default-theme/package.json +++ b/packages/theming/default-theme/package.json @@ -33,9 +33,7 @@ "update-snapshots": "fluentui-scripts jest -u" }, "dependencies": { - "@fluentui-react-native/design": "workspace:*", - "@fluentui-react-native/framework-base": "workspace:*", - "assert-never": "^1.2.1" + "@fluentui-react-native/design": "workspace:*" }, "devDependencies": { "@babel/core": "catalog:", diff --git a/packages/theming/default-theme/src/__tests__/__snapshots__/default-theme.test.ts.snap b/packages/theming/default-theme/src/__tests__/__snapshots__/default-theme.test.ts.snap index 95cfed8eb3..7fee9b0eaf 100644 --- a/packages/theming/default-theme/src/__tests__/__snapshots__/default-theme.test.ts.snap +++ b/packages/theming/default-theme/src/__tests__/__snapshots__/default-theme.test.ts.snap @@ -1,1105 +1,79 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`createColorAliasTokens test appearanceOptions - dark 1`] = ` -{ - "brandBackground": "#1651aa", - "brandBackground2": "#004578", - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": "#185abd", - "brandBackgroundPressed": "#004578", - "brandBackgroundSelected": "#13458f", - "brandBackgroundStatic": "#185abd", - "brandForeground1": "#6794d7", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": "#aec6eb", - "brandForegroundLink": "#2e6ac5", - "brandForegroundLinkHover": "#aec6eb", - "brandForegroundLinkPressed": "#6794d7", - "brandForegroundLinkSelected": "#2e6ac5", - "brandStroke1": "#2e6ac5", - "brandStroke2": "#0e336a", - "compoundBrandBackground1": "#2e6ac5", - "compoundBrandBackground1Hover": "#6794d7", - "compoundBrandBackground1Pressed": "#185abd", - "compoundBrandForeground1": "#2e6ac5", - "compoundBrandForeground1Hover": "#6794d7", - "compoundBrandForeground1Pressed": "#185abd", - "compoundBrandStroke1": "#2e6ac5", - "compoundBrandStroke1Hover": "#6794d7", - "compoundBrandStroke1Pressed": "#185abd", - "dangerBackground1": "#3f1011", - "dangerBackground2": "#751d1f", - "dangerBackground3": "#d13438", - "dangerBorder1": "#d13438", - "dangerBorder2": "#dc5e62", - "dangerBorderActive": "#e37d80", - "dangerForeground1": "#e37d80", - "dangerForeground2": "#f1bbbc", - "dangerForeground3": "#e37d80", - "dangerForegroundInverted": "#d13438", - "neutralBackground1": "#292929", - "neutralBackground1Hover": "#3d3d3d", - "neutralBackground1Pressed": "#1f1f1f", - "neutralBackground1Selected": "#383838", - "neutralBackground2": "#1f1f1f", - "neutralBackground2Hover": "#333333", - "neutralBackground2Pressed": "#141414", - "neutralBackground2Selected": "#2e2e2e", - "neutralBackground3": "#141414", - "neutralBackground3Hover": "#292929", - "neutralBackground3Pressed": "#0a0a0a", - "neutralBackground3Selected": "#242424", - "neutralBackground4": "#0a0a0a", - "neutralBackground4Hover": "#1f1f1f", - "neutralBackground4Pressed": "#000000", - "neutralBackground4Selected": "#1a1a1a", - "neutralBackground5": "#000000", - "neutralBackground5Hover": "#141414", - "neutralBackground5Pressed": "#050505", - "neutralBackground5Selected": "#0f0f0f", - "neutralBackground6": "#333333", - "neutralBackgroundDisabled": "#141414", - "neutralBackgroundInverted": "#ffffff", - "neutralForeground1": "#ffffff", - "neutralForeground1Hover": "#ffffff", - "neutralForeground1Pressed": "#ffffff", - "neutralForeground1Selected": "#ffffff", - "neutralForeground2": "#d6d6d6", - "neutralForeground2BrandHover": "#6794d7", - "neutralForeground2BrandPressed": "#2e6ac5", - "neutralForeground2BrandSelected": "#6794d7", - "neutralForeground2Hover": "#ffffff", - "neutralForeground2Pressed": "#ffffff", - "neutralForeground2Selected": "#ffffff", - "neutralForeground3": "#adadad", - "neutralForeground3BrandHover": "#6794d7", - "neutralForeground3BrandPressed": "#2e6ac5", - "neutralForeground3BrandSelected": "#6794d7", - "neutralForeground3Hover": "#d6d6d6", - "neutralForeground3Pressed": "#d6d6d6", - "neutralForeground3Selected": "#d6d6d6", - "neutralForeground4": "#999999", - "neutralForegroundDisabled": "#5c5c5c", - "neutralForegroundInverted": "#242424", - "neutralForegroundInvertedLink": "#ffffff", - "neutralForegroundInvertedLinkHover": "#ffffff", - "neutralForegroundInvertedLinkPressed": "#ffffff", - "neutralForegroundInvertedLinkSelected": "#ffffff", - "neutralForegroundOnBrand": "#ffffff", - "neutralForegroundOnBrandHover": "#ffffff", - "neutralForegroundOnBrandPressed": "#ffffff", - "neutralForegroundOnBrandSelected": "#ffffff", - "neutralStencil1": "#333333", - "neutralStencil2": "#575757", - "neutralStroke1": "#666666", - "neutralStroke1Hover": "#757575", - "neutralStroke1Pressed": "#6b6b6b", - "neutralStroke1Selected": "#707070", - "neutralStroke2": "#525252", - "neutralStroke3": "#3d3d3d", - "neutralStrokeAccessible": "#adadad", - "neutralStrokeAccessibleHover": "#bdbdbd", - "neutralStrokeAccessiblePressed": "#b3b3b3", - "neutralStrokeAccessibleSelected": "#6794d7", - "neutralStrokeDisabled": "#424242", - "outofofficeBackground1": "#3a1136", - "outofofficeBackground2": "#6d2064", - "outofofficeBackground3": "#c239b3", - "outofofficeBorder1": "#c239b3", - "outofofficeBorder2": "#d161c4", - "outofofficeBorderActive": "#da7ed0", - "outofofficeForeground1": "#da7ed0", - "outofofficeForeground2": "#edbbe7", - "outofofficeForeground3": "#d161c4", - "severeBackground1": "#411200", - "severeBackground2": "#7a2101", - "severeBackground3": "#da3b01", - "severeBorder1": "#da3b01", - "severeBorder2": "#e9835e", - "severeBorderActive": "#e9835e", - "severeForeground1": "#e9835e", - "severeForeground2": "#f4bfab", - "severeForeground3": "#e9835e", - "strokeFocus1": "#000000", - "strokeFocus2": "#ffffff", - "subtleBackground": "#00000000", - "subtleBackgroundHover": "#383838", - "subtleBackgroundPressed": "#2e2e2e", - "subtleBackgroundSelected": "#333333", - "successBackground1": "#052505", - "successBackground2": "#094509", - "successBackground3": "#107c10", - "successBorder1": "#107c10", - "successBorder2": "#9fd89f", - "successBorderActive": "#54b054", - "successForeground1": "#54b054", - "successForeground2": "#9fd89f", - "successForeground3": "#9fd89f", - "successForegroundInverted": "#107c10", - "transparentBackground": "#00000000", - "transparentBackgroundHover": "#00000000", - "transparentBackgroundPressed": "#00000000", - "transparentBackgroundSelected": "#00000000", - "transparentStroke": "#00000000", - "transparentStrokeDisabled": "#00000000", - "transparentStrokeInteractive": "#00000000", - "warningBackground1": "#4c4400", - "warningBackground2": "#817400", - "warningBackground3": "#fde300", - "warningBorder1": "#fde300", - "warningBorder2": "#fdea3d", - "warningBorderActive": "#feee66", - "warningForeground1": "#feee66", - "warningForeground2": "#fef7b2", - "warningForeground3": "#fdea3d", - "warningForegroundInverted": "#817400", -} -`; - -exports[`createColorAliasTokens test appearanceOptions - highContrast 1`] = ` -{ - "brandBackground": { - "resource_paths": [ - "ButtonFace", - ], - }, - "brandBackground2": { - "resource_paths": [ - "ButtonFace", - ], - }, - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": { - "resource_paths": [ - "Highlight", - ], - }, - "brandBackgroundPressed": { - "resource_paths": [ - "Highlight", - ], - }, - "brandBackgroundSelected": { - "resource_paths": [ - "Highlight", - ], - }, - "brandBackgroundStatic": { - "resource_paths": [ - "Window", - ], - }, - "brandForeground1": { - "resource_paths": [ - "WindowText", - ], - }, - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": { - "resource_paths": [ - "ButtonText", - ], - }, - "brandForegroundLink": { - "resource_paths": [ - "Hotlight", - ], - }, - "brandForegroundLinkHover": { - "resource_paths": [ - "Hotlight", - ], - }, - "brandForegroundLinkPressed": { - "resource_paths": [ - "Hotlight", - ], - }, - "brandForegroundLinkSelected": { - "resource_paths": [ - "Hotlight", - ], - }, - "brandStroke1": { - "resource_paths": [ - "WindowText", - ], - }, - "brandStroke2": { - "resource_paths": [ - "Window", - ], - }, - "compoundBrandBackground1": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandBackground1Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandBackground1Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandForeground1": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandForeground1Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandForeground1Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandStroke1": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandStroke1Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandStroke1Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "dangerBackground1": { - "resource_paths": [ - "Window", - ], - }, - "dangerBackground2": { - "resource_paths": [ - "Window", - ], - }, - "dangerBackground3": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerBorder1": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerBorder2": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerBorderActive": { - "resource_paths": [ - "Highlight", - ], - }, - "dangerForeground1": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerForeground2": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerForeground3": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerForegroundInverted": { - "resource_paths": [ - "WindowText", - ], - }, - "neutralBackground1": { - "resource_paths": [ - "Window", - ], - }, - "neutralBackground1Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground1Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground1Selected": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground2": { - "resource_paths": [ - "Window", - ], - }, - "neutralBackground2Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground2Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground2Selected": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground3": { - "resource_paths": [ - "Window", - ], - }, - "neutralBackground3Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground3Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground3Selected": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground4": { - "resource_paths": [ - "Window", - ], - }, - "neutralBackground4Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground4Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground4Selected": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground5": { - "resource_paths": [ - "Window", - ], - }, - "neutralBackground5Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground5Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground5Selected": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground6": { - "resource_paths": [ - "Window", - ], - }, - "neutralBackgroundDisabled": { - "resource_paths": [ - "Window", - ], - }, - "neutralBackgroundInverted": { - "resource_paths": [ - "WindowText", - ], - }, - "neutralForeground1": { - "resource_paths": [ - "WindowText", - ], - }, - "neutralForeground1Hover": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground1Pressed": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground1Selected": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground2": { - "resource_paths": [ - "WindowText", - ], - }, - "neutralForeground2BrandHover": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground2BrandPressed": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground2BrandSelected": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground2Hover": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground2Pressed": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground2Selected": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground3": { - "resource_paths": [ - "WindowText", - ], - }, - "neutralForeground3BrandHover": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground3BrandPressed": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground3BrandSelected": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground3Hover": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground3Pressed": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground3Selected": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground4": { - "resource_paths": [ - "WindowText", - ], - }, - "neutralForegroundDisabled": { - "resource_paths": [ - "GrayText", - ], - }, - "neutralForegroundInverted": { - "resource_paths": [ - "Window", - ], - }, - "neutralForegroundInvertedLink": { - "resource_paths": [ - "Hotlight", - ], - }, - "neutralForegroundInvertedLinkHover": { - "resource_paths": [ - "Hotlight", - ], - }, - "neutralForegroundInvertedLinkPressed": { - "resource_paths": [ - "Hotlight", - ], - }, - "neutralForegroundInvertedLinkSelected": { - "resource_paths": [ - "Hotlight", - ], - }, - "neutralForegroundOnBrand": { - "resource_paths": [ - "ButtonText", - ], - }, - "neutralForegroundOnBrandHover": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForegroundOnBrandPressed": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForegroundOnBrandSelected": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralStencil1": "#141414", - "neutralStencil2": "#858585", - "neutralStroke1": { - "resource_paths": [ - "WindowText", - ], - }, - "neutralStroke1Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralStroke1Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralStroke1Selected": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralStroke2": { - "resource_paths": [ - "WindowText", - ], - }, - "neutralStroke3": { - "resource_paths": [ - "WindowText", - ], - }, - "neutralStrokeAccessible": { - "resource_paths": [ - "WindowText", - ], - }, - "neutralStrokeAccessibleHover": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralStrokeAccessiblePressed": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralStrokeAccessibleSelected": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralStrokeDisabled": { - "resource_paths": [ - "GrayText", - ], - }, - "outofofficeBackground1": { - "resource_paths": [ - "Window", - ], - }, - "outofofficeBackground2": { - "resource_paths": [ - "Window", - ], - }, - "outofofficeBackground3": { - "resource_paths": [ - "WindowText", - ], - }, - "outofofficeBorder1": { - "resource_paths": [ - "WindowText", - ], - }, - "outofofficeBorder2": { - "resource_paths": [ - "WindowText", - ], - }, - "outofofficeBorderActive": { - "resource_paths": [ - "Highlight", - ], - }, - "outofofficeForeground1": { - "resource_paths": [ - "WindowText", - ], - }, - "outofofficeForeground2": { - "resource_paths": [ - "WindowText", - ], - }, - "outofofficeForeground3": { - "resource_paths": [ - "WindowText", - ], - }, - "severeBackground1": { - "resource_paths": [ - "Window", - ], - }, - "severeBackground2": { - "resource_paths": [ - "Window", - ], - }, - "severeBackground3": { - "resource_paths": [ - "WindowText", - ], - }, - "severeBorder1": { - "resource_paths": [ - "WindowText", - ], - }, - "severeBorder2": { - "resource_paths": [ - "WindowText", - ], - }, - "severeBorderActive": { - "resource_paths": [ - "Highlight", - ], - }, - "severeForeground1": { - "resource_paths": [ - "WindowText", - ], - }, - "severeForeground2": { - "resource_paths": [ - "WindowText", - ], - }, - "severeForeground3": { - "resource_paths": [ - "WindowText", - ], - }, - "strokeFocus1": { - "resource_paths": [ - "Window", - ], - }, - "strokeFocus2": { - "resource_paths": [ - "Highlight", - ], - }, - "subtleBackground": "#00000000", - "subtleBackgroundHover": { - "resource_paths": [ - "Highlight", - ], - }, - "subtleBackgroundPressed": { - "resource_paths": [ - "Highlight", - ], - }, - "subtleBackgroundSelected": { - "resource_paths": [ - "Highlight", - ], - }, - "successBackground1": { - "resource_paths": [ - "Window", - ], - }, - "successBackground2": { - "resource_paths": [ - "Window", - ], - }, - "successBackground3": { - "resource_paths": [ - "WindowText", - ], - }, - "successBorder1": { - "resource_paths": [ - "WindowText", - ], - }, - "successBorder2": { - "resource_paths": [ - "WindowText", - ], - }, - "successBorderActive": { - "resource_paths": [ - "Highlight", - ], - }, - "successForeground1": { - "resource_paths": [ - "WindowText", - ], - }, - "successForeground2": { - "resource_paths": [ - "WindowText", - ], - }, - "successForeground3": { - "resource_paths": [ - "WindowText", - ], - }, - "successForegroundInverted": { - "resource_paths": [ - "WindowText", - ], - }, - "transparentBackground": "#00000000", - "transparentBackgroundHover": "#00000000", - "transparentBackgroundPressed": "#00000000", - "transparentBackgroundSelected": "#00000000", - "transparentStroke": { - "resource_paths": [ - "WindowText", - ], - }, - "transparentStrokeDisabled": { - "resource_paths": [ - "GrayText", - ], - }, - "transparentStrokeInteractive": { - "resource_paths": [ - "Highlight", - ], - }, - "warningBackground1": { - "resource_paths": [ - "Window", - ], - }, - "warningBackground2": { - "resource_paths": [ - "Window", - ], - }, - "warningBackground3": { - "resource_paths": [ - "WindowText", - ], - }, - "warningBorder1": { - "resource_paths": [ - "WindowText", - ], - }, - "warningBorder2": { - "resource_paths": [ - "WindowText", - ], - }, - "warningBorderActive": { - "resource_paths": [ - "Highlight", - ], - }, - "warningForeground1": { - "resource_paths": [ - "WindowText", - ], - }, - "warningForeground2": { - "resource_paths": [ - "WindowText", - ], - }, - "warningForeground3": { - "resource_paths": [ - "WindowText", - ], - }, - "warningForegroundInverted": { - "resource_paths": [ - "WindowText", - ], - }, -} -`; - -exports[`createColorAliasTokens test appearanceOptions - light 1`] = ` -{ - "brandBackground": "#185abd", - "brandBackground2": "#eff6fc", - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": "#1651aa", - "brandBackgroundPressed": "#004578", - "brandBackgroundSelected": "#13458f", - "brandBackgroundStatic": "#185abd", - "brandForeground1": "#185abd", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": "#1651aa", - "brandForegroundLink": "#1651aa", - "brandForegroundLinkHover": "#13458f", - "brandForegroundLinkPressed": "#004578", - "brandForegroundLinkSelected": "#1651aa", - "brandStroke1": "#185abd", - "brandStroke2": "#d2e0f4", - "compoundBrandBackground1": "#185abd", - "compoundBrandBackground1Hover": "#1651aa", - "compoundBrandBackground1Pressed": "#13458f", - "compoundBrandForeground1": "#185abd", - "compoundBrandForeground1Hover": "#1651aa", - "compoundBrandForeground1Pressed": "#13458f", - "compoundBrandStroke1": "#185abd", - "compoundBrandStroke1Hover": "#1651aa", - "compoundBrandStroke1Pressed": "#13458f", - "dangerBackground1": "#fdf6f6", - "dangerBackground2": "#f1bbbc", - "dangerBackground3": "#d13438", - "dangerBorder1": "#f1bbbc", - "dangerBorder2": "#d13438", - "dangerBorderActive": "#d13438", - "dangerForeground1": "#bc2f32", - "dangerForeground2": "#751d1f", - "dangerForeground3": "#d13438", - "dangerForegroundInverted": "#dc5e62", - "neutralBackground1": "#ffffff", - "neutralBackground1Hover": "#f5f5f5", - "neutralBackground1Pressed": "#e0e0e0", - "neutralBackground1Selected": "#ebebeb", - "neutralBackground2": "#fafafa", - "neutralBackground2Hover": "#f0f0f0", - "neutralBackground2Pressed": "#dbdbdb", - "neutralBackground2Selected": "#e6e6e6", - "neutralBackground3": "#f5f5f5", - "neutralBackground3Hover": "#ebebeb", - "neutralBackground3Pressed": "#d6d6d6", - "neutralBackground3Selected": "#e0e0e0", - "neutralBackground4": "#f0f0f0", - "neutralBackground4Hover": "#fafafa", - "neutralBackground4Pressed": "#f5f5f5", - "neutralBackground4Selected": "#ffffff", - "neutralBackground5": "#ebebeb", - "neutralBackground5Hover": "#f5f5f5", - "neutralBackground5Pressed": "#f0f0f0", - "neutralBackground5Selected": "#fafafa", - "neutralBackground6": "#e6e6e6", - "neutralBackgroundDisabled": "#f0f0f0", - "neutralBackgroundInverted": "#616161", - "neutralForeground1": "#242424", - "neutralForeground1Hover": "#242424", - "neutralForeground1Pressed": "#242424", - "neutralForeground1Selected": "#242424", - "neutralForeground2": "#424242", - "neutralForeground2BrandHover": "#185abd", - "neutralForeground2BrandPressed": "#1651aa", - "neutralForeground2BrandSelected": "#185abd", - "neutralForeground2Hover": "#242424", - "neutralForeground2Pressed": "#242424", - "neutralForeground2Selected": "#242424", - "neutralForeground3": "#616161", - "neutralForeground3BrandHover": "#185abd", - "neutralForeground3BrandPressed": "#1651aa", - "neutralForeground3BrandSelected": "#185abd", - "neutralForeground3Hover": "#424242", - "neutralForeground3Pressed": "#424242", - "neutralForeground3Selected": "#424242", - "neutralForeground4": "#707070", - "neutralForegroundDisabled": "#bdbdbd", - "neutralForegroundInverted": "#ffffff", - "neutralForegroundInvertedLink": "#ffffff", - "neutralForegroundInvertedLinkHover": "#ffffff", - "neutralForegroundInvertedLinkPressed": "#ffffff", - "neutralForegroundInvertedLinkSelected": "#ffffff", - "neutralForegroundOnBrand": "#ffffff", - "neutralForegroundOnBrandHover": "#ffffff", - "neutralForegroundOnBrandPressed": "#ffffff", - "neutralForegroundOnBrandSelected": "#ffffff", - "neutralStencil1": "#e6e6e6", - "neutralStencil2": "#fafafa", - "neutralStroke1": "#d1d1d1", - "neutralStroke1Hover": "#c7c7c7", - "neutralStroke1Pressed": "#b3b3b3", - "neutralStroke1Selected": "#bdbdbd", - "neutralStroke2": "#e0e0e0", - "neutralStroke3": "#f0f0f0", - "neutralStrokeAccessible": "#616161", - "neutralStrokeAccessibleHover": "#575757", - "neutralStrokeAccessiblePressed": "#4d4d4d", - "neutralStrokeAccessibleSelected": "#185abd", - "neutralStrokeDisabled": "#e0e0e0", - "outofofficeBackground1": "#fdf5fc", - "outofofficeBackground2": "#edbbe7", - "outofofficeBackground3": "#c239b3", - "outofofficeBorder1": "#edbbe7", - "outofofficeBorder2": "#c239b3", - "outofofficeBorderActive": "#c239b3", - "outofofficeForeground1": "#af33a1", - "outofofficeForeground2": "#6d2064", - "outofofficeForeground3": "#c239b3", - "severeBackground1": "#fdf6f3", - "severeBackground2": "#f4bfab", - "severeBackground3": "#da3b01", - "severeBorder1": "#f4bfab", - "severeBorder2": "#da3b01", - "severeBorderActive": "#da3b01", - "severeForeground1": "#c43501", - "severeForeground2": "#7a2101", - "severeForeground3": "#da3b01", - "strokeFocus1": "#ffffff", - "strokeFocus2": "#000000", - "subtleBackground": "#00000000", - "subtleBackgroundHover": "#f5f5f5", - "subtleBackgroundPressed": "#e0e0e0", - "subtleBackgroundSelected": "#ebebeb", - "successBackground1": "#f1faf1", - "successBackground2": "#9fd89f", - "successBackground3": "#107c10", - "successBorder1": "#9fd89f", - "successBorder2": "#107c10", - "successBorderActive": "#107c10", - "successForeground1": "#0e700e", - "successForeground2": "#094509", - "successForeground3": "#107c10", - "successForegroundInverted": "#359b35", - "transparentBackground": "#00000000", - "transparentBackgroundHover": "#00000000", - "transparentBackgroundPressed": "#00000000", - "transparentBackgroundSelected": "#00000000", - "transparentStroke": "#00000000", - "transparentStrokeDisabled": "#00000000", - "transparentStrokeInteractive": "#00000000", - "warningBackground1": "#fffef5", - "warningBackground2": "#fef7b2", - "warningBackground3": "#fde300", - "warningBorder1": "#fef7b2", - "warningBorder2": "#fde300", - "warningBorderActive": "#fde300", - "warningForeground1": "#817400", - "warningForeground2": "#817400", - "warningForeground3": "#fde300", - "warningForegroundInverted": "#fef7b2", -} -`; - exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppearance: 'light' } 1`] = ` { "colors": { "accentButtonBackground": "#185abd", - "actionLink": "#f3f2f1", - "background": "#1b1a19", - "bodyDivider": "#292827", - "bodyFrameBackground": "#1b1a19", - "bodyFrameDivider": "#292827", - "bodyStandoutBackground": "#201f1e", - "bodyText": "#f3f2f1", + "actionLink": "#ffffff", + "background": "#292929", + "bodyDivider": "#525252", + "bodyFrameBackground": "#292929", + "bodyFrameDivider": "#525252", + "bodyStandoutBackground": "#1f1f1f", + "bodyText": "#ffffff", "bodyTextChecked": "#ffffff", - "brandBackground": "#1651aa", - "brandBackground2": "#004578", - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": "#185abd", - "brandBackgroundPressed": "#004578", + "brandBackground": "#185abd", + "brandBackground2": "#d2e0f4", + "brandBackground2Pressed": "#0e336a", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#d2e0f4", + "brandBackgroundDisabled": "#141414", + "brandBackgroundHover": "#1651aa", + "brandBackgroundInverted": "#ffffff", + "brandBackgroundInvertedDisabled": "#141414", + "brandBackgroundPressed": "#0e336a", "brandBackgroundSelected": "#13458f", "brandBackgroundStatic": "#185abd", - "brandForeground1": "#6794d7", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": "#aec6eb", - "brandForegroundLink": "#2e6ac5", - "brandForegroundLinkHover": "#aec6eb", - "brandForegroundLinkPressed": "#6794d7", - "brandForegroundLinkSelected": "#2e6ac5", - "brandStroke1": "#2e6ac5", - "brandStroke2": "#0e336a", - "brandedBackground": "#2e6ac5", - "brandedDisabledBorder": "#252423", - "brandedFocusedSecondaryContent": "#201f1e", - "brandedHoveredSecondaryContent": "#201f1e", - "brandedPressedSecondaryContent": "#201f1e", - "brandedSecondaryContent": "#201f1e", - "buttonBackground": "#252423", - "buttonBackgroundChecked": "#484644", - "buttonBackgroundDisabled": "#252423", - "buttonBackgroundHovered": "#292827", - "buttonBackgroundPressed": "#292827", - "buttonBorder": "#979693", - "buttonBorderDisabled": "#252423", - "buttonBorderFocused": "#979693", + "brandBackgroundTint": "#d2e0f4", + "brandForeground1": "#aec6eb", + "brandForeground1Disabled": "#5c5c5c", + "brandForeground1Pressed": "#aec6eb", + "brandForeground1Selected": "#aec6eb", + "brandForeground2": "#d2e0f4", + "brandForegroundDisabled1": "#5c5c5c", + "brandForegroundDisabled2": "#5c5c5c", + "brandForegroundLink": "#aec6eb", + "brandForegroundLinkHover": "#d2e0f4", + "brandForegroundLinkPressed": "#2e6ac5", + "brandForegroundLinkSelected": "#d2e0f4", + "brandForegroundTint": "#d2e0f4", + "brandStroke1": "#185abd", + "brandStroke1Pressed": "#185abd", + "brandStroke1Selected": "#185abd", + "brandStroke2": "#6794d7", + "brandStrokeTint": "#6794d7", + "brandedBackground": "#185abd", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#292929", + "buttonBackgroundChecked": "#383838", + "buttonBackgroundDisabled": "#141414", + "buttonBackgroundHovered": "#3d3d3d", + "buttonBackgroundPressed": "#1f1f1f", + "buttonBorder": "#666666", + "buttonBorderDisabled": "#424242", + "buttonBorderFocused": "#ffffff", "buttonText": "#ffffff", - "buttonTextChecked": "#faf9f8", - "buttonTextDisabled": "#797775", - "buttonTextHovered": "#f3f2f1", - "buttonTextPressed": "#faf9f8", - "checkboxBackground": "#2e6ac5", - "checkboxBackgroundDisabled": "#252423", - "checkboxBorderColor": "#979693", - "checkmarkColor": "#1b1a19", - "compoundBrandBackground1": "#2e6ac5", - "compoundBrandBackground1Hover": "#6794d7", - "compoundBrandBackground1Pressed": "#185abd", - "compoundBrandForeground1": "#2e6ac5", - "compoundBrandForeground1Hover": "#6794d7", - "compoundBrandForeground1Pressed": "#185abd", - "compoundBrandStroke1": "#2e6ac5", - "compoundBrandStroke1Hover": "#6794d7", - "compoundBrandStroke1Pressed": "#185abd", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#5c5c5c", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#185abd", + "checkboxBackgroundDisabled": "#141414", + "checkboxBorderColor": "#adadad", + "checkmarkColor": "#ffffff", + "compoundBrandBackground1": "#185abd", + "compoundBrandBackground1Hover": "#1651aa", + "compoundBrandBackground1Pressed": "#0e336a", + "compoundBrandForeground1": "#aec6eb", + "compoundBrandForeground1Hover": "#d2e0f4", + "compoundBrandForeground1Pressed": "#2e6ac5", + "compoundBrandStroke1": "#185abd", + "compoundBrandStroke1Hover": "#1651aa", + "compoundBrandStroke1Pressed": "#0e336a", "dangerBackground1": "#3f1011", "dangerBackground2": "#751d1f", "dangerBackground3": "#d13438", @@ -1110,83 +84,84 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppe "dangerForeground2": "#f1bbbc", "dangerForeground3": "#e37d80", "dangerForegroundInverted": "#d13438", - "defaultBackground": "#252423", - "defaultBorder": "#979693", - "defaultCheckedBackground": "#484644", - "defaultCheckedContent": "#faf9f8", - "defaultCheckedHoveredBackground": "#292827", - "defaultCheckedHoveredContent": "#f3f2f1", + "dangerStroke1": "#d13438", + "defaultBackground": "#292929", + "defaultBorder": "#666666", + "defaultCheckedBackground": "#383838", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#3d3d3d", + "defaultCheckedHoveredContent": "#ffffff", "defaultContent": "#ffffff", - "defaultDisabledBackground": "#252423", - "defaultDisabledBorder": "#252423", - "defaultDisabledContent": "#797775", - "defaultDisabledIcon": "#797775", - "defaultFocusedBackground": "#292827", - "defaultFocusedBorder": "#979693", - "defaultFocusedContent": "#f3f2f1", - "defaultFocusedIcon": "#f3f2f1", - "defaultHoveredBackground": "#292827", - "defaultHoveredBorder": "#979693", - "defaultHoveredContent": "#f3f2f1", - "defaultHoveredIcon": "#f3f2f1", - "defaultHoveredSecondaryContent": "#797775", + "defaultDisabledBackground": "#141414", + "defaultDisabledBorder": "#424242", + "defaultDisabledContent": "#5c5c5c", + "defaultDisabledIcon": "#5c5c5c", + "defaultFocusedBackground": "#3d3d3d", + "defaultFocusedBorder": "#ffffff", + "defaultFocusedContent": "#ffffff", + "defaultFocusedIcon": "#ffffff", + "defaultHoveredBackground": "#3d3d3d", + "defaultHoveredBorder": "#757575", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#d6d6d6", "defaultIcon": "#ffffff", - "defaultPressedBackground": "#292827", - "defaultPressedBorder": "#979693", - "defaultPressedContent": "#faf9f8", - "defaultPressedIcon": "#faf9f8", - "defaultPressedSecondaryContent": "#797775", - "disabledBackground": "#323130", - "disabledBodyText": "#797775", - "disabledText": "#797775", - "errorText": "#ff5f5f", - "focusBorder": "#a19f9d", - "ghostBackground": "#1b1a19", - "ghostBorder": "#1b1a19", - "ghostCheckedBackground": "#292827", + "defaultPressedBackground": "#1f1f1f", + "defaultPressedBorder": "#6b6b6b", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#d6d6d6", + "disabledBackground": "#141414", + "disabledBodyText": "#5c5c5c", + "disabledText": "#5c5c5c", + "errorText": "#e37d80", + "focusBorder": "#ffffff", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#383838", "ghostCheckedContent": "#ffffff", - "ghostCheckedHoveredBackground": "#252423", - "ghostCheckedHoveredBorder": "#faf9f8", - "ghostCheckedHoveredContent": "#faf9f8", - "ghostContent": "#f3f2f1", - "ghostDisabledBackground": "#1b1a19", - "ghostDisabledBorder": "#1b1a19", - "ghostDisabledContent": "#797775", - "ghostDisabledIcon": "#797775", - "ghostFocusedBackground": "#252423", - "ghostFocusedBorder": "#979693", - "ghostFocusedContent": "#faf9f8", - "ghostFocusedIcon": "#faf9f8", - "ghostFocusedSecondaryContent": "#a19f9d", - "ghostHoveredBackground": "#252423", - "ghostHoveredBorder": "#252423", - "ghostHoveredContent": "#faf9f8", - "ghostHoveredIcon": "#faf9f8", - "ghostHoveredSecondaryContent": "#a19f9d", - "ghostIcon": "#f3f2f1", - "ghostPressedBackground": "#292827", - "ghostPressedBorder": "#292827", - "ghostPressedContent": "#faf9f8", - "ghostPressedIcon": "#faf9f8", - "ghostPressedSecondaryContent": "#a19f9d", - "ghostSecondaryContent": "#a19f9d", - "inputBackground": "#1b1a19", - "inputBorder": "#797775", - "inputFocusBorderAlt": "#2e6ac5", - "inputPlaceholderText": "#a19f9d", - "inputText": "#f3f2f1", - "link": "#2e6ac5", - "linkHovered": "#82c7ff", - "linkPressed": "#aec6eb", - "listHeaderBackgroundHovered": "#252423", - "listHeaderBackgroundPressed": "#292827", - "menuBackground": "#252423", - "menuDivider": "#484644", - "menuIcon": "#6794d7", - "menuItemBackgroundHovered": "#323130", - "menuItemBackgroundPressed": "#3b3a39", - "menuItemText": "#f3f2f1", - "menuItemTextHovered": "#faf9f8", + "ghostCheckedHoveredBackground": "#3d3d3d", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#ffffff", + "ghostContent": "#ffffff", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#5c5c5c", + "ghostDisabledIcon": "#5c5c5c", + "ghostFocusedBackground": "#3d3d3d", + "ghostFocusedBorder": "#ffffff", + "ghostFocusedContent": "#ffffff", + "ghostFocusedIcon": "#ffffff", + "ghostFocusedSecondaryContent": "#adadad", + "ghostHoveredBackground": "#3d3d3d", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#d6d6d6", + "ghostIcon": "#ffffff", + "ghostPressedBackground": "#1f1f1f", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#d6d6d6", + "ghostSecondaryContent": "#adadad", + "inputBackground": "#292929", + "inputBorder": "#666666", + "inputFocusBorderAlt": "#185abd", + "inputPlaceholderText": "#999999", + "inputText": "#ffffff", + "link": "#aec6eb", + "linkHovered": "#d2e0f4", + "linkPressed": "#2e6ac5", + "listHeaderBackgroundHovered": "#3d3d3d", + "listHeaderBackgroundPressed": "#1f1f1f", + "menuBackground": "#292929", + "menuDivider": "#525252", + "menuIcon": "#d6d6d6", + "menuItemBackgroundHovered": "#3d3d3d", + "menuItemBackgroundPressed": "#1f1f1f", + "menuItemText": "#ffffff", + "menuItemTextHovered": "#ffffff", "neutralBackground1": "#292929", "neutralBackground1Hover": "#3d3d3d", "neutralBackground1Pressed": "#1f1f1f", @@ -1208,37 +183,46 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppe "neutralBackground5Pressed": "#050505", "neutralBackground5Selected": "#0f0f0f", "neutralBackground6": "#333333", + "neutralBackgroundCanvas": "#292929", + "neutralBackgroundDarkStatic": "#3d3d3d", "neutralBackgroundDisabled": "#141414", "neutralBackgroundInverted": "#ffffff", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#141414", "neutralForeground1": "#ffffff", "neutralForeground1Hover": "#ffffff", "neutralForeground1Pressed": "#ffffff", "neutralForeground1Selected": "#ffffff", "neutralForeground2": "#d6d6d6", - "neutralForeground2BrandHover": "#6794d7", + "neutralForeground2BrandHover": "#d2e0f4", "neutralForeground2BrandPressed": "#2e6ac5", - "neutralForeground2BrandSelected": "#6794d7", + "neutralForeground2BrandSelected": "#d2e0f4", "neutralForeground2Hover": "#ffffff", "neutralForeground2Pressed": "#ffffff", "neutralForeground2Selected": "#ffffff", "neutralForeground3": "#adadad", - "neutralForeground3BrandHover": "#6794d7", + "neutralForeground3BrandHover": "#d2e0f4", "neutralForeground3BrandPressed": "#2e6ac5", - "neutralForeground3BrandSelected": "#6794d7", + "neutralForeground3BrandSelected": "#d2e0f4", "neutralForeground3Hover": "#d6d6d6", "neutralForeground3Pressed": "#d6d6d6", "neutralForeground3Selected": "#d6d6d6", "neutralForeground4": "#999999", + "neutralForegroundDarkStatic": "#000000", "neutralForegroundDisabled": "#5c5c5c", - "neutralForegroundInverted": "#242424", - "neutralForegroundInvertedLink": "#ffffff", - "neutralForegroundInvertedLinkHover": "#ffffff", - "neutralForegroundInvertedLinkPressed": "#ffffff", - "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundDisabled1": "#5c5c5c", + "neutralForegroundDisabled2": "#5c5c5c", + "neutralForegroundInverted": "#000000", + "neutralForegroundInvertedLink": "#292929", + "neutralForegroundInvertedLinkHover": "#292929", + "neutralForegroundInvertedLinkPressed": "#292929", + "neutralForegroundInvertedLinkSelected": "#292929", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#ffffff", "neutralForegroundOnBrandHover": "#ffffff", "neutralForegroundOnBrandPressed": "#ffffff", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#333333", "neutralStencil2": "#575757", "neutralStroke1": "#666666", @@ -1250,8 +234,10 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppe "neutralStrokeAccessible": "#adadad", "neutralStrokeAccessibleHover": "#bdbdbd", "neutralStrokeAccessiblePressed": "#b3b3b3", - "neutralStrokeAccessibleSelected": "#6794d7", + "neutralStrokeAccessibleSelected": "#185abd", "neutralStrokeDisabled": "#424242", + "neutralStrokeFocus1": "#000000", + "neutralStrokeFocus2": "#ffffff", "outofofficeBackground1": "#3a1136", "outofofficeBackground2": "#6d2064", "outofofficeBackground3": "#c239b3", @@ -1261,18 +247,31 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppe "outofofficeForeground1": "#da7ed0", "outofofficeForeground2": "#edbbe7", "outofofficeForeground3": "#d161c4", - "personaActivityGlow": "#2e6ac5", - "personaActivityRing": "#1b1a19", - "primaryButtonBackground": "#2e6ac5", - "primaryButtonBackgroundDisabled": "#252423", - "primaryButtonBackgroundHovered": "#6794d7", - "primaryButtonBackgroundPressed": "#aec6eb", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", - "primaryButtonText": "#1b1a19", - "primaryButtonTextDisabled": "#3b3a39", - "primaryButtonTextHovered": "#1b1a19", - "primaryButtonTextPressed": "#1b1a19", + "personaActivityGlow": "#185abd", + "personaActivityRing": "#292929", + "presenceAvailable": "#54b054", + "presenceAway": "#feee66", + "presenceDnd": "#e37d80", + "presenceOof": "#da7ed0", + "primaryButtonBackground": "#185abd", + "primaryButtonBackgroundDisabled": "#141414", + "primaryButtonBackgroundHovered": "#1651aa", + "primaryButtonBackgroundPressed": "#0e336a", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#ffffff", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#5c5c5c", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#751d1f", + "redBackground3": "#d13438", + "redBorder1": "#d13438", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#f1bbbc", + "redForeground3": "#e37d80", "severeBackground1": "#411200", "severeBackground2": "#7a2101", "severeBackground3": "#da3b01", @@ -1282,13 +281,14 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppe "severeForeground1": "#e9835e", "severeForeground2": "#f4bfab", "severeForeground3": "#e9835e", + "severeStroke1": "#da3b01", "strokeFocus1": "#000000", "strokeFocus2": "#ffffff", - "subText": "#a19f9d", + "subText": "#d6d6d6", "subtleBackground": "#00000000", - "subtleBackgroundHover": "#383838", - "subtleBackgroundPressed": "#2e2e2e", - "subtleBackgroundSelected": "#333333", + "subtleBackgroundHover": "#3d3d3d", + "subtleBackgroundPressed": "#1f1f1f", + "subtleBackgroundSelected": "#383838", "successBackground1": "#052505", "successBackground2": "#094509", "successBackground3": "#107c10", @@ -1299,6 +299,7 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppe "successForeground2": "#9fd89f", "successForeground3": "#9fd89f", "successForegroundInverted": "#107c10", + "successStroke1": "#107c10", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -1306,7 +307,7 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppe "transparentStroke": "#00000000", "transparentStrokeDisabled": "#00000000", "transparentStrokeInteractive": "#00000000", - "variantBorder": "#292827", + "variantBorder": "#525252", "warningBackground1": "#4c4400", "warningBackground2": "#817400", "warningBackground3": "#fde300", @@ -1317,6 +318,7 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppe "warningForeground2": "#fef7b2", "warningForeground3": "#fdea3d", "warningForegroundInverted": "#817400", + "warningStroke1": "#fde300", }, "components": {}, "host": { @@ -1501,13 +503,13 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppe }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -1521,138 +523,153 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dark', defaultAppe "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { @@ -1667,63 +684,76 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA { "colors": { "accentButtonBackground": "#185abd", - "actionLink": "#f3f2f1", - "background": "#1b1a19", - "bodyDivider": "#292827", - "bodyFrameBackground": "#1b1a19", - "bodyFrameDivider": "#292827", - "bodyStandoutBackground": "#201f1e", - "bodyText": "#f3f2f1", + "actionLink": "#ffffff", + "background": "#292929", + "bodyDivider": "#525252", + "bodyFrameBackground": "#292929", + "bodyFrameDivider": "#525252", + "bodyStandoutBackground": "#1f1f1f", + "bodyText": "#ffffff", "bodyTextChecked": "#ffffff", - "brandBackground": "#1651aa", - "brandBackground2": "#004578", - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": "#185abd", - "brandBackgroundPressed": "#004578", + "brandBackground": "#185abd", + "brandBackground2": "#d2e0f4", + "brandBackground2Pressed": "#0e336a", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#d2e0f4", + "brandBackgroundDisabled": "#141414", + "brandBackgroundHover": "#1651aa", + "brandBackgroundInverted": "#ffffff", + "brandBackgroundInvertedDisabled": "#141414", + "brandBackgroundPressed": "#0e336a", "brandBackgroundSelected": "#13458f", "brandBackgroundStatic": "#185abd", - "brandForeground1": "#6794d7", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": "#aec6eb", - "brandForegroundLink": "#2e6ac5", - "brandForegroundLinkHover": "#aec6eb", - "brandForegroundLinkPressed": "#6794d7", - "brandForegroundLinkSelected": "#2e6ac5", - "brandStroke1": "#2e6ac5", - "brandStroke2": "#0e336a", - "brandedBackground": "#2e6ac5", - "brandedDisabledBorder": "#252423", - "brandedFocusedSecondaryContent": "#201f1e", - "brandedHoveredSecondaryContent": "#201f1e", - "brandedPressedSecondaryContent": "#201f1e", - "brandedSecondaryContent": "#201f1e", - "buttonBackground": "#252423", - "buttonBackgroundChecked": "#484644", - "buttonBackgroundDisabled": "#252423", - "buttonBackgroundHovered": "#292827", - "buttonBackgroundPressed": "#292827", - "buttonBorder": "#979693", - "buttonBorderDisabled": "#252423", - "buttonBorderFocused": "#979693", + "brandBackgroundTint": "#d2e0f4", + "brandForeground1": "#aec6eb", + "brandForeground1Disabled": "#5c5c5c", + "brandForeground1Pressed": "#aec6eb", + "brandForeground1Selected": "#aec6eb", + "brandForeground2": "#d2e0f4", + "brandForegroundDisabled1": "#5c5c5c", + "brandForegroundDisabled2": "#5c5c5c", + "brandForegroundLink": "#aec6eb", + "brandForegroundLinkHover": "#d2e0f4", + "brandForegroundLinkPressed": "#2e6ac5", + "brandForegroundLinkSelected": "#d2e0f4", + "brandForegroundTint": "#d2e0f4", + "brandStroke1": "#185abd", + "brandStroke1Pressed": "#185abd", + "brandStroke1Selected": "#185abd", + "brandStroke2": "#6794d7", + "brandStrokeTint": "#6794d7", + "brandedBackground": "#185abd", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#292929", + "buttonBackgroundChecked": "#383838", + "buttonBackgroundDisabled": "#141414", + "buttonBackgroundHovered": "#3d3d3d", + "buttonBackgroundPressed": "#1f1f1f", + "buttonBorder": "#666666", + "buttonBorderDisabled": "#424242", + "buttonBorderFocused": "#ffffff", "buttonText": "#ffffff", - "buttonTextChecked": "#faf9f8", - "buttonTextDisabled": "#797775", - "buttonTextHovered": "#f3f2f1", - "buttonTextPressed": "#faf9f8", - "checkboxBackground": "#2e6ac5", - "checkboxBackgroundDisabled": "#252423", - "checkboxBorderColor": "#979693", - "checkmarkColor": "#1b1a19", - "compoundBrandBackground1": "#2e6ac5", - "compoundBrandBackground1Hover": "#6794d7", - "compoundBrandBackground1Pressed": "#185abd", - "compoundBrandForeground1": "#2e6ac5", - "compoundBrandForeground1Hover": "#6794d7", - "compoundBrandForeground1Pressed": "#185abd", - "compoundBrandStroke1": "#2e6ac5", - "compoundBrandStroke1Hover": "#6794d7", - "compoundBrandStroke1Pressed": "#185abd", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#5c5c5c", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#185abd", + "checkboxBackgroundDisabled": "#141414", + "checkboxBorderColor": "#adadad", + "checkmarkColor": "#ffffff", + "compoundBrandBackground1": "#185abd", + "compoundBrandBackground1Hover": "#1651aa", + "compoundBrandBackground1Pressed": "#0e336a", + "compoundBrandForeground1": "#aec6eb", + "compoundBrandForeground1Hover": "#d2e0f4", + "compoundBrandForeground1Pressed": "#2e6ac5", + "compoundBrandStroke1": "#185abd", + "compoundBrandStroke1Hover": "#1651aa", + "compoundBrandStroke1Pressed": "#0e336a", "dangerBackground1": "#3f1011", "dangerBackground2": "#751d1f", "dangerBackground3": "#d13438", @@ -1734,83 +764,84 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA "dangerForeground2": "#f1bbbc", "dangerForeground3": "#e37d80", "dangerForegroundInverted": "#d13438", - "defaultBackground": "#252423", - "defaultBorder": "#979693", - "defaultCheckedBackground": "#484644", - "defaultCheckedContent": "#faf9f8", - "defaultCheckedHoveredBackground": "#292827", - "defaultCheckedHoveredContent": "#f3f2f1", + "dangerStroke1": "#d13438", + "defaultBackground": "#292929", + "defaultBorder": "#666666", + "defaultCheckedBackground": "#383838", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#3d3d3d", + "defaultCheckedHoveredContent": "#ffffff", "defaultContent": "#ffffff", - "defaultDisabledBackground": "#252423", - "defaultDisabledBorder": "#252423", - "defaultDisabledContent": "#797775", - "defaultDisabledIcon": "#797775", - "defaultFocusedBackground": "#292827", - "defaultFocusedBorder": "#979693", - "defaultFocusedContent": "#f3f2f1", - "defaultFocusedIcon": "#f3f2f1", - "defaultHoveredBackground": "#292827", - "defaultHoveredBorder": "#979693", - "defaultHoveredContent": "#f3f2f1", - "defaultHoveredIcon": "#f3f2f1", - "defaultHoveredSecondaryContent": "#797775", + "defaultDisabledBackground": "#141414", + "defaultDisabledBorder": "#424242", + "defaultDisabledContent": "#5c5c5c", + "defaultDisabledIcon": "#5c5c5c", + "defaultFocusedBackground": "#3d3d3d", + "defaultFocusedBorder": "#ffffff", + "defaultFocusedContent": "#ffffff", + "defaultFocusedIcon": "#ffffff", + "defaultHoveredBackground": "#3d3d3d", + "defaultHoveredBorder": "#757575", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#d6d6d6", "defaultIcon": "#ffffff", - "defaultPressedBackground": "#292827", - "defaultPressedBorder": "#979693", - "defaultPressedContent": "#faf9f8", - "defaultPressedIcon": "#faf9f8", - "defaultPressedSecondaryContent": "#797775", - "disabledBackground": "#323130", - "disabledBodyText": "#797775", - "disabledText": "#797775", - "errorText": "#ff5f5f", - "focusBorder": "#a19f9d", - "ghostBackground": "#1b1a19", - "ghostBorder": "#1b1a19", - "ghostCheckedBackground": "#292827", + "defaultPressedBackground": "#1f1f1f", + "defaultPressedBorder": "#6b6b6b", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#d6d6d6", + "disabledBackground": "#141414", + "disabledBodyText": "#5c5c5c", + "disabledText": "#5c5c5c", + "errorText": "#e37d80", + "focusBorder": "#ffffff", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#383838", "ghostCheckedContent": "#ffffff", - "ghostCheckedHoveredBackground": "#252423", - "ghostCheckedHoveredBorder": "#faf9f8", - "ghostCheckedHoveredContent": "#faf9f8", - "ghostContent": "#f3f2f1", - "ghostDisabledBackground": "#1b1a19", - "ghostDisabledBorder": "#1b1a19", - "ghostDisabledContent": "#797775", - "ghostDisabledIcon": "#797775", - "ghostFocusedBackground": "#252423", - "ghostFocusedBorder": "#979693", - "ghostFocusedContent": "#faf9f8", - "ghostFocusedIcon": "#faf9f8", - "ghostFocusedSecondaryContent": "#a19f9d", - "ghostHoveredBackground": "#252423", - "ghostHoveredBorder": "#252423", - "ghostHoveredContent": "#faf9f8", - "ghostHoveredIcon": "#faf9f8", - "ghostHoveredSecondaryContent": "#a19f9d", - "ghostIcon": "#f3f2f1", - "ghostPressedBackground": "#292827", - "ghostPressedBorder": "#292827", - "ghostPressedContent": "#faf9f8", - "ghostPressedIcon": "#faf9f8", - "ghostPressedSecondaryContent": "#a19f9d", - "ghostSecondaryContent": "#a19f9d", - "inputBackground": "#1b1a19", - "inputBorder": "#797775", - "inputFocusBorderAlt": "#2e6ac5", - "inputPlaceholderText": "#a19f9d", - "inputText": "#f3f2f1", - "link": "#2e6ac5", - "linkHovered": "#82c7ff", - "linkPressed": "#aec6eb", - "listHeaderBackgroundHovered": "#252423", - "listHeaderBackgroundPressed": "#292827", - "menuBackground": "#252423", - "menuDivider": "#484644", - "menuIcon": "#6794d7", - "menuItemBackgroundHovered": "#323130", - "menuItemBackgroundPressed": "#3b3a39", - "menuItemText": "#f3f2f1", - "menuItemTextHovered": "#faf9f8", + "ghostCheckedHoveredBackground": "#3d3d3d", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#ffffff", + "ghostContent": "#ffffff", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#5c5c5c", + "ghostDisabledIcon": "#5c5c5c", + "ghostFocusedBackground": "#3d3d3d", + "ghostFocusedBorder": "#ffffff", + "ghostFocusedContent": "#ffffff", + "ghostFocusedIcon": "#ffffff", + "ghostFocusedSecondaryContent": "#adadad", + "ghostHoveredBackground": "#3d3d3d", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#d6d6d6", + "ghostIcon": "#ffffff", + "ghostPressedBackground": "#1f1f1f", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#d6d6d6", + "ghostSecondaryContent": "#adadad", + "inputBackground": "#292929", + "inputBorder": "#666666", + "inputFocusBorderAlt": "#185abd", + "inputPlaceholderText": "#999999", + "inputText": "#ffffff", + "link": "#aec6eb", + "linkHovered": "#d2e0f4", + "linkPressed": "#2e6ac5", + "listHeaderBackgroundHovered": "#3d3d3d", + "listHeaderBackgroundPressed": "#1f1f1f", + "menuBackground": "#292929", + "menuDivider": "#525252", + "menuIcon": "#d6d6d6", + "menuItemBackgroundHovered": "#3d3d3d", + "menuItemBackgroundPressed": "#1f1f1f", + "menuItemText": "#ffffff", + "menuItemTextHovered": "#ffffff", "neutralBackground1": "#292929", "neutralBackground1Hover": "#3d3d3d", "neutralBackground1Pressed": "#1f1f1f", @@ -1832,37 +863,46 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA "neutralBackground5Pressed": "#050505", "neutralBackground5Selected": "#0f0f0f", "neutralBackground6": "#333333", + "neutralBackgroundCanvas": "#292929", + "neutralBackgroundDarkStatic": "#3d3d3d", "neutralBackgroundDisabled": "#141414", "neutralBackgroundInverted": "#ffffff", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#141414", "neutralForeground1": "#ffffff", "neutralForeground1Hover": "#ffffff", "neutralForeground1Pressed": "#ffffff", "neutralForeground1Selected": "#ffffff", "neutralForeground2": "#d6d6d6", - "neutralForeground2BrandHover": "#6794d7", + "neutralForeground2BrandHover": "#d2e0f4", "neutralForeground2BrandPressed": "#2e6ac5", - "neutralForeground2BrandSelected": "#6794d7", + "neutralForeground2BrandSelected": "#d2e0f4", "neutralForeground2Hover": "#ffffff", "neutralForeground2Pressed": "#ffffff", "neutralForeground2Selected": "#ffffff", "neutralForeground3": "#adadad", - "neutralForeground3BrandHover": "#6794d7", + "neutralForeground3BrandHover": "#d2e0f4", "neutralForeground3BrandPressed": "#2e6ac5", - "neutralForeground3BrandSelected": "#6794d7", + "neutralForeground3BrandSelected": "#d2e0f4", "neutralForeground3Hover": "#d6d6d6", "neutralForeground3Pressed": "#d6d6d6", "neutralForeground3Selected": "#d6d6d6", "neutralForeground4": "#999999", + "neutralForegroundDarkStatic": "#000000", "neutralForegroundDisabled": "#5c5c5c", - "neutralForegroundInverted": "#242424", - "neutralForegroundInvertedLink": "#ffffff", - "neutralForegroundInvertedLinkHover": "#ffffff", - "neutralForegroundInvertedLinkPressed": "#ffffff", - "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundDisabled1": "#5c5c5c", + "neutralForegroundDisabled2": "#5c5c5c", + "neutralForegroundInverted": "#000000", + "neutralForegroundInvertedLink": "#292929", + "neutralForegroundInvertedLinkHover": "#292929", + "neutralForegroundInvertedLinkPressed": "#292929", + "neutralForegroundInvertedLinkSelected": "#292929", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#ffffff", "neutralForegroundOnBrandHover": "#ffffff", "neutralForegroundOnBrandPressed": "#ffffff", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#333333", "neutralStencil2": "#575757", "neutralStroke1": "#666666", @@ -1874,8 +914,10 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA "neutralStrokeAccessible": "#adadad", "neutralStrokeAccessibleHover": "#bdbdbd", "neutralStrokeAccessiblePressed": "#b3b3b3", - "neutralStrokeAccessibleSelected": "#6794d7", + "neutralStrokeAccessibleSelected": "#185abd", "neutralStrokeDisabled": "#424242", + "neutralStrokeFocus1": "#000000", + "neutralStrokeFocus2": "#ffffff", "outofofficeBackground1": "#3a1136", "outofofficeBackground2": "#6d2064", "outofofficeBackground3": "#c239b3", @@ -1885,18 +927,31 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA "outofofficeForeground1": "#da7ed0", "outofofficeForeground2": "#edbbe7", "outofofficeForeground3": "#d161c4", - "personaActivityGlow": "#2e6ac5", - "personaActivityRing": "#1b1a19", - "primaryButtonBackground": "#2e6ac5", - "primaryButtonBackgroundDisabled": "#252423", - "primaryButtonBackgroundHovered": "#6794d7", - "primaryButtonBackgroundPressed": "#aec6eb", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", - "primaryButtonText": "#1b1a19", - "primaryButtonTextDisabled": "#3b3a39", - "primaryButtonTextHovered": "#1b1a19", - "primaryButtonTextPressed": "#1b1a19", + "personaActivityGlow": "#185abd", + "personaActivityRing": "#292929", + "presenceAvailable": "#54b054", + "presenceAway": "#feee66", + "presenceDnd": "#e37d80", + "presenceOof": "#da7ed0", + "primaryButtonBackground": "#185abd", + "primaryButtonBackgroundDisabled": "#141414", + "primaryButtonBackgroundHovered": "#1651aa", + "primaryButtonBackgroundPressed": "#0e336a", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#ffffff", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#5c5c5c", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#751d1f", + "redBackground3": "#d13438", + "redBorder1": "#d13438", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#f1bbbc", + "redForeground3": "#e37d80", "severeBackground1": "#411200", "severeBackground2": "#7a2101", "severeBackground3": "#da3b01", @@ -1906,13 +961,14 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA "severeForeground1": "#e9835e", "severeForeground2": "#f4bfab", "severeForeground3": "#e9835e", + "severeStroke1": "#da3b01", "strokeFocus1": "#000000", "strokeFocus2": "#ffffff", - "subText": "#a19f9d", + "subText": "#d6d6d6", "subtleBackground": "#00000000", - "subtleBackgroundHover": "#383838", - "subtleBackgroundPressed": "#2e2e2e", - "subtleBackgroundSelected": "#333333", + "subtleBackgroundHover": "#3d3d3d", + "subtleBackgroundPressed": "#1f1f1f", + "subtleBackgroundSelected": "#383838", "successBackground1": "#052505", "successBackground2": "#094509", "successBackground3": "#107c10", @@ -1923,6 +979,7 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA "successForeground2": "#9fd89f", "successForeground3": "#9fd89f", "successForegroundInverted": "#107c10", + "successStroke1": "#107c10", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -1930,7 +987,7 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA "transparentStroke": "#00000000", "transparentStrokeDisabled": "#00000000", "transparentStrokeInteractive": "#00000000", - "variantBorder": "#292827", + "variantBorder": "#525252", "warningBackground1": "#4c4400", "warningBackground2": "#817400", "warningBackground3": "#fde300", @@ -1941,6 +998,7 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA "warningForeground2": "#fef7b2", "warningForeground3": "#fdea3d", "warningForegroundInverted": "#817400", + "warningStroke1": "#fde300", }, "components": {}, "host": { @@ -2125,13 +1183,13 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -2145,138 +1203,153 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { @@ -2290,283 +1363,793 @@ exports[`createDefaultTheme test themeOption - { appearance: 'dynamic', defaultA exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', defaultAppearance: 'light' } 1`] = ` { "colors": { - "accentButtonBackground": "#000000", - "actionLink": "#ffff00", - "background": "#000000", - "bodyDivider": "#ffffff", - "bodyFrameBackground": "#000000", - "bodyFrameDivider": "#000000", - "bodyStandoutBackground": "#000000", - "bodyText": "#ffffff", - "bodyTextChecked": "#000000", - "brandBackground": { + "accentButtonBackground": { "resource_paths": [ "ButtonFace", ], }, - "brandBackground2": { + "actionLink": { "resource_paths": [ - "ButtonFace", + "WindowText", ], }, - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": { + "background": { "resource_paths": [ - "Highlight", + "Window", ], }, - "brandBackgroundPressed": { + "bodyDivider": { "resource_paths": [ - "Highlight", + "WindowText", ], }, - "brandBackgroundSelected": { + "bodyFrameBackground": { "resource_paths": [ - "Highlight", + "Window", + ], + }, + "bodyFrameDivider": { + "resource_paths": [ + "WindowText", + ], + }, + "bodyStandoutBackground": { + "resource_paths": [ + "Window", + ], + }, + "bodyText": { + "resource_paths": [ + "WindowText", + ], + }, + "bodyTextChecked": { + "resource_paths": [ + "HighlightText", + ], + }, + "brandBackground": { + "resource_paths": [ + "ButtonFace", + ], + }, + "brandBackground2": { + "resource_paths": [ + "ButtonFace", + ], + }, + "brandBackground2Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "brandBackground2Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "brandBackground3": { + "resource_paths": [ + "ButtonFace", + ], + }, + "brandBackgroundDisabled": { + "resource_paths": [ + "Window", + ], + }, + "brandBackgroundHover": { + "resource_paths": [ + "Highlight", + ], + }, + "brandBackgroundInverted": { + "resource_paths": [ + "WindowText", + ], + }, + "brandBackgroundInvertedDisabled": { + "resource_paths": [ + "Window", + ], + }, + "brandBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "brandBackgroundSelected": { + "resource_paths": [ + "Highlight", ], }, "brandBackgroundStatic": { "resource_paths": [ - "Window", + "Window", + ], + }, + "brandBackgroundTint": { + "resource_paths": [ + "ButtonFace", + ], + }, + "brandForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "brandForeground1Disabled": { + "resource_paths": [ + "GrayText", + ], + }, + "brandForeground1Pressed": { + "resource_paths": [ + "WindowText", + ], + }, + "brandForeground1Selected": { + "resource_paths": [ + "WindowText", + ], + }, + "brandForeground2": { + "resource_paths": [ + "ButtonText", + ], + }, + "brandForegroundDisabled1": { + "resource_paths": [ + "GrayText", + ], + }, + "brandForegroundDisabled2": { + "resource_paths": [ + "GrayText", + ], + }, + "brandForegroundLink": { + "resource_paths": [ + "Hotlight", + ], + }, + "brandForegroundLinkHover": { + "resource_paths": [ + "Hotlight", + ], + }, + "brandForegroundLinkPressed": { + "resource_paths": [ + "Hotlight", + ], + }, + "brandForegroundLinkSelected": { + "resource_paths": [ + "Hotlight", + ], + }, + "brandForegroundTint": { + "resource_paths": [ + "ButtonText", + ], + }, + "brandStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + "brandStroke1Pressed": { + "resource_paths": [ + "WindowText", + ], + }, + "brandStroke1Selected": { + "resource_paths": [ + "WindowText", + ], + }, + "brandStroke2": { + "resource_paths": [ + "Window", + ], + }, + "brandStrokeTint": { + "resource_paths": [ + "Window", + ], + }, + "brandedBackground": { + "resource_paths": [ + "ButtonFace", + ], + }, + "brandedDisabledBorder": { + "resource_paths": [ + "GrayText", + ], + }, + "brandedFocusedSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "brandedHoveredSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "brandedPressedSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "brandedSecondaryContent": { + "resource_paths": [ + "ButtonText", + ], + }, + "buttonBackground": { + "resource_paths": [ + "Window", + ], + }, + "buttonBackgroundChecked": { + "resource_paths": [ + "Highlight", + ], + }, + "buttonBackgroundDisabled": { + "resource_paths": [ + "Window", + ], + }, + "buttonBackgroundHovered": { + "resource_paths": [ + "Highlight", + ], + }, + "buttonBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "buttonBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "buttonBorderDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "buttonBorderFocused": { + "resource_paths": [ + "Highlight", + ], + }, + "buttonText": { + "resource_paths": [ + "WindowText", + ], + }, + "buttonTextChecked": { + "resource_paths": [ + "HighlightText", + ], + }, + "buttonTextDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "buttonTextHovered": { + "resource_paths": [ + "HighlightText", + ], + }, + "buttonTextPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "checkboxBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "checkboxBackgroundDisabled": { + "resource_paths": [ + "Window", + ], + }, + "checkboxBorderColor": { + "resource_paths": [ + "WindowText", + ], + }, + "checkmarkColor": { + "resource_paths": [ + "ButtonText", + ], + }, + "compoundBrandBackground1": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandBackground1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandBackground1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandForeground1": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandForeground1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandForeground1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandStroke1": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandStroke1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandStroke1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "dangerBackground1": { + "resource_paths": [ + "Window", + ], + }, + "dangerBackground2": { + "resource_paths": [ + "Window", + ], + }, + "dangerBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "dangerForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerForegroundInverted": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + "defaultBackground": { + "resource_paths": [ + "Window", + ], + }, + "defaultBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "defaultCheckedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultCheckedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultCheckedHoveredBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultCheckedHoveredContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultContent": { + "resource_paths": [ + "WindowText", + ], + }, + "defaultDisabledBackground": { + "resource_paths": [ + "Window", + ], + }, + "defaultDisabledBorder": { + "resource_paths": [ + "GrayText", + ], + }, + "defaultDisabledContent": { + "resource_paths": [ + "GrayText", + ], + }, + "defaultDisabledIcon": { + "resource_paths": [ + "GrayText", + ], + }, + "defaultFocusedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultFocusedBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultFocusedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultFocusedIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultHoveredBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultHoveredBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultHoveredContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultHoveredIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultHoveredSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultIcon": { + "resource_paths": [ + "WindowText", + ], + }, + "defaultPressedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultPressedBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultPressedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultPressedIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultPressedSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "disabledBackground": { + "resource_paths": [ + "Window", + ], + }, + "disabledBodyText": { + "resource_paths": [ + "GrayText", + ], + }, + "disabledText": { + "resource_paths": [ + "GrayText", + ], + }, + "errorText": { + "resource_paths": [ + "WindowText", + ], + }, + "focusBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostBackground": "#00000000", + "ghostBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostCheckedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostCheckedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostCheckedHoveredBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostCheckedHoveredBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostCheckedHoveredContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostContent": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": { + "resource_paths": [ + "GrayText", + ], + }, + "ghostDisabledContent": { + "resource_paths": [ + "GrayText", + ], + }, + "ghostDisabledIcon": { + "resource_paths": [ + "GrayText", + ], + }, + "ghostFocusedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostFocusedBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostFocusedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostFocusedIcon": { + "resource_paths": [ + "HighlightText", ], }, - "brandForeground1": { + "ghostFocusedSecondaryContent": { "resource_paths": [ "WindowText", ], }, - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": { + "ghostHoveredBackground": { "resource_paths": [ - "ButtonText", + "Highlight", ], }, - "brandForegroundLink": { + "ghostHoveredBorder": { "resource_paths": [ - "Hotlight", + "WindowText", ], }, - "brandForegroundLinkHover": { + "ghostHoveredContent": { "resource_paths": [ - "Hotlight", + "HighlightText", ], }, - "brandForegroundLinkPressed": { + "ghostHoveredIcon": { "resource_paths": [ - "Hotlight", + "HighlightText", ], }, - "brandForegroundLinkSelected": { + "ghostHoveredSecondaryContent": { "resource_paths": [ - "Hotlight", + "HighlightText", ], }, - "brandStroke1": { + "ghostIcon": { "resource_paths": [ "WindowText", ], }, - "brandStroke2": { + "ghostPressedBackground": { "resource_paths": [ - "Window", + "Highlight", ], }, - "brandedBackground": "#000000", - "brandedDisabledBorder": "#3ff23f", - "brandedFocusedSecondaryContent": "#ffffff", - "brandedHoveredSecondaryContent": "#000000", - "brandedPressedSecondaryContent": "#000000", - "brandedSecondaryContent": "#ffffff", - "buttonBackground": "#000000", - "buttonBackgroundChecked": "#1aebff", - "buttonBackgroundDisabled": "#000000", - "buttonBackgroundHovered": "#1aebff", - "buttonBackgroundPressed": "#1aebff", - "buttonBorder": "#ffffff", - "buttonBorderDisabled": "#3ff23f", - "buttonBorderFocused": "#ffffff", - "buttonText": "#ffffff", - "buttonTextChecked": "#000000", - "buttonTextDisabled": "#3ff23f", - "buttonTextHovered": "#000000", - "buttonTextPressed": "#000000", - "checkboxBackground": "#000000", - "checkboxBackgroundDisabled": "#000000", - "checkboxBorderColor": "#ffffff", - "checkmarkColor": "#ffffff", - "compoundBrandBackground1": { + "ghostPressedBorder": { "resource_paths": [ - "Highlight", + "WindowText", ], }, - "compoundBrandBackground1Hover": { + "ghostPressedContent": { "resource_paths": [ - "Highlight", + "HighlightText", ], }, - "compoundBrandBackground1Pressed": { + "ghostPressedIcon": { "resource_paths": [ - "Highlight", + "HighlightText", ], }, - "compoundBrandForeground1": { + "ghostPressedSecondaryContent": { "resource_paths": [ - "Highlight", + "HighlightText", ], }, - "compoundBrandForeground1Hover": { + "ghostSecondaryContent": { "resource_paths": [ - "Highlight", + "WindowText", ], }, - "compoundBrandForeground1Pressed": { + "inputBackground": { "resource_paths": [ - "Highlight", + "Window", ], }, - "compoundBrandStroke1": { + "inputBorder": { "resource_paths": [ - "Highlight", + "WindowText", ], }, - "compoundBrandStroke1Hover": { + "inputFocusBorderAlt": { "resource_paths": [ "Highlight", ], }, - "compoundBrandStroke1Pressed": { + "inputPlaceholderText": { "resource_paths": [ - "Highlight", + "WindowText", ], }, - "dangerBackground1": { + "inputText": { "resource_paths": [ - "Window", + "WindowText", ], }, - "dangerBackground2": { + "link": { "resource_paths": [ - "Window", + "Hotlight", ], }, - "dangerBackground3": { + "linkHovered": { "resource_paths": [ - "WindowText", + "Hotlight", ], }, - "dangerBorder1": { + "linkPressed": { "resource_paths": [ - "WindowText", + "Hotlight", ], }, - "dangerBorder2": { + "listHeaderBackgroundHovered": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "dangerBorderActive": { + "listHeaderBackgroundPressed": { "resource_paths": [ "Highlight", ], }, - "dangerForeground1": { + "menuBackground": { "resource_paths": [ - "WindowText", + "Window", ], }, - "dangerForeground2": { + "menuDivider": { "resource_paths": [ "WindowText", ], }, - "dangerForeground3": { + "menuIcon": { "resource_paths": [ "WindowText", ], }, - "dangerForegroundInverted": { + "menuItemBackgroundHovered": { + "resource_paths": [ + "Highlight", + ], + }, + "menuItemBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "menuItemText": { "resource_paths": [ "WindowText", ], }, - "defaultBackground": "#000000", - "defaultBorder": "#ffffff", - "defaultCheckedBackground": "#1aebff", - "defaultCheckedContent": "#000000", - "defaultCheckedHoveredBackground": "#1aebff", - "defaultCheckedHoveredContent": "#000000", - "defaultContent": "#ffffff", - "defaultDisabledBackground": "#000000", - "defaultDisabledBorder": "#3ff23f", - "defaultDisabledContent": "#3ff23f", - "defaultDisabledIcon": "#3ff23f", - "defaultFocusedBackground": "#000000", - "defaultFocusedBorder": "#ffffff", - "defaultFocusedContent": "#ffffff", - "defaultFocusedIcon": "#ffffff", - "defaultHoveredBackground": "#1aebff", - "defaultHoveredBorder": "#1aebff", - "defaultHoveredContent": "#000000", - "defaultHoveredIcon": "#000000", - "defaultHoveredSecondaryContent": "#000000", - "defaultIcon": "#ffffff", - "defaultPressedBackground": "#1aebff", - "defaultPressedBorder": "#1aebff", - "defaultPressedContent": "#000000", - "defaultPressedIcon": "#000000", - "defaultPressedSecondaryContent": "#000000", - "disabledBackground": "#000000", - "disabledBodyText": "#3ff23f", - "disabledText": "#3ff23f", - "errorText": "#ffffff", - "focusBorder": "#ffffff", - "ghostBackground": "#000000", - "ghostBorder": "#000000", - "ghostCheckedBackground": "#1aebff", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#1aebff", - "ghostCheckedHoveredBorder": "#000000", - "ghostCheckedHoveredContent": "#000000", - "ghostContent": "#ffffff", - "ghostDisabledBackground": "#000000", - "ghostDisabledBorder": "#000000", - "ghostDisabledContent": "#3ff23f", - "ghostDisabledIcon": "#3ff23f", - "ghostFocusedBackground": "#000000", - "ghostFocusedBorder": "#ffffff", - "ghostFocusedContent": "#ffffff", - "ghostFocusedIcon": "#ffffff", - "ghostFocusedSecondaryContent": "#ffffff", - "ghostHoveredBackground": "#1aebff", - "ghostHoveredBorder": "#1aebff", - "ghostHoveredContent": "#000000", - "ghostHoveredIcon": "#000000", - "ghostHoveredSecondaryContent": "#000000", - "ghostIcon": "#ffffff", - "ghostPressedBackground": "#1aebff", - "ghostPressedBorder": "#1aebff", - "ghostPressedContent": "#000000", - "ghostPressedIcon": "#000000", - "ghostPressedSecondaryContent": "#000000", - "ghostSecondaryContent": "#ffffff", - "inputBackground": "#000000", - "inputBorder": "#ffffff", - "inputFocusBorderAlt": "#ffffff", - "inputPlaceholderText": "#ffffff", - "inputText": "#ffffff", - "link": "#ffff00", - "linkHovered": "#ffffff", - "linkPressed": "#ffffff", - "listHeaderBackgroundHovered": "#1aebff", - "listHeaderBackgroundPressed": "#1aebff", - "menuBackground": "#000000", - "menuDivider": "#ffffff", - "menuIcon": "#ffffff", - "menuItemBackgroundHovered": "#1aebff", - "menuItemBackgroundPressed": "#1aebff", - "menuItemText": "#ffffff", - "menuItemTextHovered": "#000000", + "menuItemTextHovered": { + "resource_paths": [ + "HighlightText", + ], + }, "neutralBackground1": { "resource_paths": [ "Window", @@ -2672,6 +2255,12 @@ exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', def "Window", ], }, + "neutralBackgroundCanvas": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackgroundDarkStatic": "#3d3d3d", "neutralBackgroundDisabled": { "resource_paths": [ "Window", @@ -2682,6 +2271,12 @@ exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', def "WindowText", ], }, + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": { + "resource_paths": [ + "Window", + ], + }, "neutralForeground1": { "resource_paths": [ "WindowText", @@ -2772,175 +2367,315 @@ exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', def "HighlightText", ], }, - "neutralForeground4": { + "neutralForeground4": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralForegroundDisabled1": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralForegroundDisabled2": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralForegroundInverted": { + "resource_paths": [ + "Window", + ], + }, + "neutralForegroundInvertedLink": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundInvertedLinkHover": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundInvertedLinkPressed": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundInvertedLinkSelected": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": { + "resource_paths": [ + "ButtonText", + ], + }, + "neutralForegroundOnBrandHover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForegroundOnBrandPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForegroundOnBrandSelected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForegroundOnColor": { + "resource_paths": [ + "ButtonText", + ], + }, + "neutralStencil1": "#141414", + "neutralStencil2": "#858585", + "neutralStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStroke1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStroke1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStroke1Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStroke2": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStroke3": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStrokeAccessible": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStrokeAccessibleHover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStrokeAccessiblePressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStrokeAccessibleSelected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStrokeDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralStrokeFocus1": { + "resource_paths": [ + "Window", + ], + }, + "neutralStrokeFocus2": { + "resource_paths": [ + "Highlight", + ], + }, + "outofofficeBackground1": { + "resource_paths": [ + "Window", + ], + }, + "outofofficeBackground2": { + "resource_paths": [ + "Window", + ], + }, + "outofofficeBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeBorder1": { "resource_paths": [ "WindowText", ], }, - "neutralForegroundDisabled": { + "outofofficeBorder2": { "resource_paths": [ - "GrayText", + "WindowText", ], }, - "neutralForegroundInverted": { + "outofofficeBorderActive": { "resource_paths": [ - "Window", + "Highlight", ], }, - "neutralForegroundInvertedLink": { + "outofofficeForeground1": { "resource_paths": [ - "Hotlight", + "WindowText", ], }, - "neutralForegroundInvertedLinkHover": { + "outofofficeForeground2": { "resource_paths": [ - "Hotlight", + "WindowText", ], }, - "neutralForegroundInvertedLinkPressed": { + "outofofficeForeground3": { "resource_paths": [ - "Hotlight", + "WindowText", ], }, - "neutralForegroundInvertedLinkSelected": { + "personaActivityGlow": { "resource_paths": [ - "Hotlight", + "ButtonFace", ], }, - "neutralForegroundOnBrand": { + "personaActivityRing": { "resource_paths": [ - "ButtonText", + "Window", ], }, - "neutralForegroundOnBrandHover": { + "presenceAvailable": { "resource_paths": [ - "HighlightText", + "WindowText", ], }, - "neutralForegroundOnBrandPressed": { + "presenceAway": { "resource_paths": [ - "HighlightText", + "WindowText", ], }, - "neutralForegroundOnBrandSelected": { + "presenceDnd": { "resource_paths": [ - "HighlightText", + "WindowText", ], }, - "neutralStencil1": "#141414", - "neutralStencil2": "#858585", - "neutralStroke1": { + "presenceOof": { "resource_paths": [ "WindowText", ], }, - "neutralStroke1Hover": { + "primaryButtonBackground": { "resource_paths": [ - "Highlight", + "ButtonFace", ], }, - "neutralStroke1Pressed": { + "primaryButtonBackgroundDisabled": { "resource_paths": [ - "Highlight", + "Window", ], }, - "neutralStroke1Selected": { + "primaryButtonBackgroundHovered": { "resource_paths": [ "Highlight", ], }, - "neutralStroke2": { + "primaryButtonBackgroundPressed": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "neutralStroke3": { + "primaryButtonBorder": { "resource_paths": [ "WindowText", ], }, - "neutralStrokeAccessible": { + "primaryButtonBorderFocused": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "neutralStrokeAccessibleHover": { + "primaryButtonText": { "resource_paths": [ - "Highlight", + "ButtonText", ], }, - "neutralStrokeAccessiblePressed": { + "primaryButtonTextDisabled": { "resource_paths": [ - "Highlight", + "GrayText", ], }, - "neutralStrokeAccessibleSelected": { + "primaryButtonTextHovered": { "resource_paths": [ - "Highlight", + "HighlightText", ], }, - "neutralStrokeDisabled": { + "primaryButtonTextPressed": { "resource_paths": [ - "GrayText", + "HighlightText", ], }, - "outofofficeBackground1": { + "redBackground1": { "resource_paths": [ "Window", ], }, - "outofofficeBackground2": { + "redBackground2": { "resource_paths": [ "Window", ], }, - "outofofficeBackground3": { + "redBackground3": { "resource_paths": [ "WindowText", ], }, - "outofofficeBorder1": { + "redBorder1": { "resource_paths": [ "WindowText", ], }, - "outofofficeBorder2": { + "redBorder2": { "resource_paths": [ "WindowText", ], }, - "outofofficeBorderActive": { + "redBorderActive": { "resource_paths": [ "Highlight", ], }, - "outofofficeForeground1": { + "redForeground1": { "resource_paths": [ "WindowText", ], }, - "outofofficeForeground2": { + "redForeground2": { "resource_paths": [ "WindowText", ], }, - "outofofficeForeground3": { + "redForeground3": { "resource_paths": [ "WindowText", ], }, - "personaActivityGlow": "transparent", - "personaActivityRing": "#ffffff", - "primaryButtonBackground": "#000000", - "primaryButtonBackgroundDisabled": "#000000", - "primaryButtonBackgroundHovered": "#1aebff", - "primaryButtonBackgroundPressed": "#1aebff", - "primaryButtonBorder": "#ffffff", - "primaryButtonBorderFocused": "#ffffff", - "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#3ff23f", - "primaryButtonTextHovered": "#000000", - "primaryButtonTextPressed": "#000000", "severeBackground1": { "resource_paths": [ "Window", @@ -2986,6 +2721,11 @@ exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', def "WindowText", ], }, + "severeStroke1": { + "resource_paths": [ + "WindowText", + ], + }, "strokeFocus1": { "resource_paths": [ "Window", @@ -2996,7 +2736,11 @@ exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', def "Highlight", ], }, - "subText": "#ffffff", + "subText": { + "resource_paths": [ + "WindowText", + ], + }, "subtleBackground": "#00000000", "subtleBackgroundHover": { "resource_paths": [ @@ -3063,6 +2807,11 @@ exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', def "WindowText", ], }, + "successStroke1": { + "resource_paths": [ + "WindowText", + ], + }, "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -3082,7 +2831,11 @@ exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', def "Highlight", ], }, - "variantBorder": "#ffffff", + "variantBorder": { + "resource_paths": [ + "WindowText", + ], + }, "warningBackground1": { "resource_paths": [ "Window", @@ -3133,6 +2886,11 @@ exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', def "WindowText", ], }, + "warningStroke1": { + "resource_paths": [ + "WindowText", + ], + }, }, "components": {}, "host": { @@ -3317,13 +3075,13 @@ exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', def }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -3337,138 +3095,153 @@ exports[`createDefaultTheme test themeOption - { appearance: 'highContrast', def "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { @@ -3483,63 +3256,76 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp { "colors": { "accentButtonBackground": "#185abd", - "actionLink": "#323130", + "actionLink": "#242424", "background": "#ffffff", - "bodyDivider": "#edebe9", + "bodyDivider": "#e0e0e0", "bodyFrameBackground": "#ffffff", - "bodyFrameDivider": "#edebe9", - "bodyStandoutBackground": "#faf9f8", - "bodyText": "#323130", - "bodyTextChecked": "#000000", + "bodyFrameDivider": "#e0e0e0", + "bodyStandoutBackground": "#fafafa", + "bodyText": "#242424", + "bodyTextChecked": "#242424", "brandBackground": "#185abd", - "brandBackground2": "#eff6fc", - "brandBackgroundDisabled": undefined, + "brandBackground2": "#d2e0f4", + "brandBackground2Pressed": "#0e336a", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#d2e0f4", + "brandBackgroundDisabled": "#f0f0f0", "brandBackgroundHover": "#1651aa", - "brandBackgroundPressed": "#004578", + "brandBackgroundInverted": "#616161", + "brandBackgroundInvertedDisabled": "#f0f0f0", + "brandBackgroundPressed": "#0e336a", "brandBackgroundSelected": "#13458f", "brandBackgroundStatic": "#185abd", + "brandBackgroundTint": "#d2e0f4", "brandForeground1": "#185abd", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, + "brandForeground1Disabled": "#bdbdbd", + "brandForeground1Pressed": "#185abd", + "brandForeground1Selected": "#185abd", "brandForeground2": "#1651aa", - "brandForegroundLink": "#1651aa", - "brandForegroundLinkHover": "#13458f", - "brandForegroundLinkPressed": "#004578", - "brandForegroundLinkSelected": "#1651aa", + "brandForegroundDisabled1": "#bdbdbd", + "brandForegroundDisabled2": "#bdbdbd", + "brandForegroundLink": "#185abd", + "brandForegroundLinkHover": "#1651aa", + "brandForegroundLinkPressed": "#0e336a", + "brandForegroundLinkSelected": "#13458f", + "brandForegroundTint": "#1651aa", "brandStroke1": "#185abd", - "brandStroke2": "#d2e0f4", + "brandStroke1Pressed": "#185abd", + "brandStroke1Selected": "#185abd", + "brandStroke2": "#6794d7", + "brandStrokeTint": "#6794d7", "brandedBackground": "#185abd", - "brandedDisabledBorder": "#f3f2f1", - "brandedFocusedSecondaryContent": "#faf9f8", - "brandedHoveredSecondaryContent": "#faf9f8", - "brandedPressedSecondaryContent": "#faf9f8", - "brandedSecondaryContent": "#faf9f8", - "buttonBackground": "#f3f2f1", - "buttonBackgroundChecked": "#c8c6c4", - "buttonBackgroundDisabled": "#f3f2f1", - "buttonBackgroundHovered": "#edebe9", - "buttonBackgroundPressed": "#edebe9", - "buttonBorder": "#8a8886", - "buttonBorderDisabled": "#f3f2f1", - "buttonBorderFocused": "#8a8886", - "buttonText": "#323130", - "buttonTextChecked": "#201f1e", - "buttonTextDisabled": "#a19f9d", - "buttonTextHovered": "#201f1e", - "buttonTextPressed": "#201f1e", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#f0f0f0", + "buttonBackgroundHovered": "#f5f5f5", + "buttonBackgroundPressed": "#e0e0e0", + "buttonBorder": "#d1d1d1", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#242424", + "buttonTextChecked": "#242424", + "buttonTextDisabled": "#bdbdbd", + "buttonTextHovered": "#242424", + "buttonTextPressed": "#242424", "checkboxBackground": "#185abd", - "checkboxBackgroundDisabled": "#f3f2f1", - "checkboxBorderColor": "#8a8886", + "checkboxBackgroundDisabled": "#f0f0f0", + "checkboxBorderColor": "#616161", "checkmarkColor": "#ffffff", "compoundBrandBackground1": "#185abd", "compoundBrandBackground1Hover": "#1651aa", - "compoundBrandBackground1Pressed": "#13458f", + "compoundBrandBackground1Pressed": "#0e336a", "compoundBrandForeground1": "#185abd", "compoundBrandForeground1Hover": "#1651aa", - "compoundBrandForeground1Pressed": "#13458f", + "compoundBrandForeground1Pressed": "#0e336a", "compoundBrandStroke1": "#185abd", "compoundBrandStroke1Hover": "#1651aa", - "compoundBrandStroke1Pressed": "#13458f", + "compoundBrandStroke1Pressed": "#0e336a", "dangerBackground1": "#fdf6f6", "dangerBackground2": "#f1bbbc", "dangerBackground3": "#d13438", @@ -3550,83 +3336,84 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp "dangerForeground2": "#751d1f", "dangerForeground3": "#d13438", "dangerForegroundInverted": "#dc5e62", - "defaultBackground": "#f3f2f1", - "defaultBorder": "#8a8886", - "defaultCheckedBackground": "#c8c6c4", - "defaultCheckedContent": "#201f1e", - "defaultCheckedHoveredBackground": "#edebe9", - "defaultCheckedHoveredContent": "#201f1e", - "defaultContent": "#323130", - "defaultDisabledBackground": "#f3f2f1", - "defaultDisabledBorder": "#f3f2f1", - "defaultDisabledContent": "#a19f9d", - "defaultDisabledIcon": "#a19f9d", - "defaultFocusedBackground": "#edebe9", - "defaultFocusedBorder": "#8a8886", - "defaultFocusedContent": "#201f1e", - "defaultFocusedIcon": "#201f1e", - "defaultHoveredBackground": "#edebe9", - "defaultHoveredBorder": "#8a8886", - "defaultHoveredContent": "#201f1e", - "defaultHoveredIcon": "#201f1e", - "defaultHoveredSecondaryContent": "#a19f9d", - "defaultIcon": "#323130", - "defaultPressedBackground": "#edebe9", - "defaultPressedBorder": "#8a8886", - "defaultPressedContent": "#201f1e", - "defaultPressedIcon": "#201f1e", - "defaultPressedSecondaryContent": "#a19f9d", - "disabledBackground": "#f3f2f1", - "disabledBodyText": "#a19f9d", - "disabledText": "#a19f9d", - "errorText": "#a4262c", - "focusBorder": "#605e5c", - "ghostBackground": "#ffffff", - "ghostBorder": "#ffffff", - "ghostCheckedBackground": "#edebe9", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#f3f2f1", - "ghostCheckedHoveredBorder": "#201f1e", - "ghostCheckedHoveredContent": "#201f1e", - "ghostContent": "#323130", - "ghostDisabledBackground": "#ffffff", - "ghostDisabledBorder": "#ffffff", - "ghostDisabledContent": "#a19f9d", - "ghostDisabledIcon": "#a19f9d", - "ghostFocusedBackground": "#f3f2f1", - "ghostFocusedBorder": "#8a8886", - "ghostFocusedContent": "#201f1e", - "ghostFocusedIcon": "#201f1e", - "ghostFocusedSecondaryContent": "#605e5c", - "ghostHoveredBackground": "#f3f2f1", - "ghostHoveredBorder": "#f3f2f1", - "ghostHoveredContent": "#201f1e", - "ghostHoveredIcon": "#201f1e", - "ghostHoveredSecondaryContent": "#605e5c", - "ghostIcon": "#323130", - "ghostPressedBackground": "#edebe9", - "ghostPressedBorder": "#edebe9", - "ghostPressedContent": "#201f1e", - "ghostPressedIcon": "#201f1e", - "ghostPressedSecondaryContent": "#605e5c", - "ghostSecondaryContent": "#605e5c", + "dangerStroke1": "#f1bbbc", + "defaultBackground": "#ffffff", + "defaultBorder": "#d1d1d1", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#242424", + "defaultCheckedHoveredBackground": "#f5f5f5", + "defaultCheckedHoveredContent": "#242424", + "defaultContent": "#242424", + "defaultDisabledBackground": "#f0f0f0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#bdbdbd", + "defaultDisabledIcon": "#bdbdbd", + "defaultFocusedBackground": "#f5f5f5", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#242424", + "defaultFocusedIcon": "#242424", + "defaultHoveredBackground": "#f5f5f5", + "defaultHoveredBorder": "#c7c7c7", + "defaultHoveredContent": "#242424", + "defaultHoveredIcon": "#242424", + "defaultHoveredSecondaryContent": "#424242", + "defaultIcon": "#242424", + "defaultPressedBackground": "#e0e0e0", + "defaultPressedBorder": "#b3b3b3", + "defaultPressedContent": "#242424", + "defaultPressedIcon": "#242424", + "defaultPressedSecondaryContent": "#424242", + "disabledBackground": "#f0f0f0", + "disabledBodyText": "#bdbdbd", + "disabledText": "#bdbdbd", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#242424", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#242424", + "ghostContent": "#242424", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#bdbdbd", + "ghostDisabledIcon": "#bdbdbd", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#242424", + "ghostFocusedIcon": "#242424", + "ghostFocusedSecondaryContent": "#616161", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#242424", + "ghostHoveredIcon": "#242424", + "ghostHoveredSecondaryContent": "#424242", + "ghostIcon": "#242424", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#242424", + "ghostPressedIcon": "#242424", + "ghostPressedSecondaryContent": "#424242", + "ghostSecondaryContent": "#616161", "inputBackground": "#ffffff", - "inputBorder": "#a19f9d", + "inputBorder": "#d1d1d1", "inputFocusBorderAlt": "#185abd", - "inputPlaceholderText": "#605e5c", - "inputText": "#323130", + "inputPlaceholderText": "#707070", + "inputText": "#242424", "link": "#185abd", - "linkHovered": "#004578", - "linkPressed": "#13458f", - "listHeaderBackgroundHovered": "#f3f2f1", - "listHeaderBackgroundPressed": "#edebe9", + "linkHovered": "#1651aa", + "linkPressed": "#0e336a", + "listHeaderBackgroundHovered": "#f5f5f5", + "listHeaderBackgroundPressed": "#e0e0e0", "menuBackground": "#ffffff", - "menuDivider": "#c8c6c4", - "menuIcon": "#185abd", - "menuItemBackgroundHovered": "#f3f2f1", - "menuItemBackgroundPressed": "#edebe9", - "menuItemText": "#323130", - "menuItemTextHovered": "#201f1e", + "menuDivider": "#e0e0e0", + "menuIcon": "#424242", + "menuItemBackgroundHovered": "#f5f5f5", + "menuItemBackgroundPressed": "#e0e0e0", + "menuItemText": "#242424", + "menuItemTextHovered": "#242424", "neutralBackground1": "#ffffff", "neutralBackground1Hover": "#f5f5f5", "neutralBackground1Pressed": "#e0e0e0", @@ -3648,37 +3435,46 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp "neutralBackground5Pressed": "#f0f0f0", "neutralBackground5Selected": "#fafafa", "neutralBackground6": "#e6e6e6", + "neutralBackgroundCanvas": "#ffffff", + "neutralBackgroundDarkStatic": "#242424", "neutralBackgroundDisabled": "#f0f0f0", "neutralBackgroundInverted": "#616161", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#f0f0f0", "neutralForeground1": "#242424", "neutralForeground1Hover": "#242424", "neutralForeground1Pressed": "#242424", "neutralForeground1Selected": "#242424", "neutralForeground2": "#424242", - "neutralForeground2BrandHover": "#185abd", - "neutralForeground2BrandPressed": "#1651aa", - "neutralForeground2BrandSelected": "#185abd", + "neutralForeground2BrandHover": "#1651aa", + "neutralForeground2BrandPressed": "#0e336a", + "neutralForeground2BrandSelected": "#13458f", "neutralForeground2Hover": "#242424", "neutralForeground2Pressed": "#242424", "neutralForeground2Selected": "#242424", "neutralForeground3": "#616161", - "neutralForeground3BrandHover": "#185abd", - "neutralForeground3BrandPressed": "#1651aa", - "neutralForeground3BrandSelected": "#185abd", + "neutralForeground3BrandHover": "#1651aa", + "neutralForeground3BrandPressed": "#0e336a", + "neutralForeground3BrandSelected": "#13458f", "neutralForeground3Hover": "#424242", "neutralForeground3Pressed": "#424242", "neutralForeground3Selected": "#424242", "neutralForeground4": "#707070", + "neutralForegroundDarkStatic": "#000000", "neutralForegroundDisabled": "#bdbdbd", + "neutralForegroundDisabled1": "#bdbdbd", + "neutralForegroundDisabled2": "#bdbdbd", "neutralForegroundInverted": "#ffffff", "neutralForegroundInvertedLink": "#ffffff", "neutralForegroundInvertedLinkHover": "#ffffff", "neutralForegroundInvertedLinkPressed": "#ffffff", "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#ffffff", "neutralForegroundOnBrandHover": "#ffffff", "neutralForegroundOnBrandPressed": "#ffffff", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#e6e6e6", "neutralStencil2": "#fafafa", "neutralStroke1": "#d1d1d1", @@ -3692,6 +3488,8 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp "neutralStrokeAccessiblePressed": "#4d4d4d", "neutralStrokeAccessibleSelected": "#185abd", "neutralStrokeDisabled": "#e0e0e0", + "neutralStrokeFocus1": "#ffffff", + "neutralStrokeFocus2": "#000000", "outofofficeBackground1": "#fdf5fc", "outofofficeBackground2": "#edbbe7", "outofofficeBackground3": "#c239b3", @@ -3703,16 +3501,29 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp "outofofficeForeground3": "#c239b3", "personaActivityGlow": "#185abd", "personaActivityRing": "#ffffff", + "presenceAvailable": "#0e700e", + "presenceAway": "#817400", + "presenceDnd": "#bc2f32", + "presenceOof": "#af33a1", "primaryButtonBackground": "#185abd", - "primaryButtonBackgroundDisabled": "#f3f2f1", + "primaryButtonBackgroundDisabled": "#f0f0f0", "primaryButtonBackgroundHovered": "#1651aa", - "primaryButtonBackgroundPressed": "#13458f", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", + "primaryButtonBackgroundPressed": "#0e336a", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#000000", "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#d2d0ce", + "primaryButtonTextDisabled": "#bdbdbd", "primaryButtonTextHovered": "#ffffff", "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#f1bbbc", + "redBackground3": "#d13438", + "redBorder1": "#f1bbbc", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#751d1f", + "redForeground3": "#d13438", "severeBackground1": "#fdf6f3", "severeBackground2": "#f4bfab", "severeBackground3": "#da3b01", @@ -3722,9 +3533,10 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp "severeForeground1": "#c43501", "severeForeground2": "#7a2101", "severeForeground3": "#da3b01", + "severeStroke1": "#f4bfab", "strokeFocus1": "#ffffff", "strokeFocus2": "#000000", - "subText": "#605e5c", + "subText": "#424242", "subtleBackground": "#00000000", "subtleBackgroundHover": "#f5f5f5", "subtleBackgroundPressed": "#e0e0e0", @@ -3739,6 +3551,7 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp "successForeground2": "#094509", "successForeground3": "#107c10", "successForegroundInverted": "#359b35", + "successStroke1": "#9fd89f", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -3746,7 +3559,7 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp "transparentStroke": "#00000000", "transparentStrokeDisabled": "#00000000", "transparentStrokeInteractive": "#00000000", - "variantBorder": "#edebe9", + "variantBorder": "#e0e0e0", "warningBackground1": "#fffef5", "warningBackground2": "#fef7b2", "warningBackground3": "#fde300", @@ -3757,6 +3570,7 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp "warningForeground2": "#817400", "warningForeground3": "#fde300", "warningForegroundInverted": "#fef7b2", + "warningStroke1": "#fef7b2", }, "components": {}, "host": { @@ -3941,13 +3755,13 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -3961,138 +3775,153 @@ exports[`createDefaultTheme test themeOption - { appearance: 'light', defaultApp "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { @@ -4107,63 +3936,76 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA { "colors": { "accentButtonBackground": "#185abd", - "actionLink": "#323130", + "actionLink": "#242424", "background": "#ffffff", - "bodyDivider": "#edebe9", + "bodyDivider": "#e0e0e0", "bodyFrameBackground": "#ffffff", - "bodyFrameDivider": "#edebe9", - "bodyStandoutBackground": "#faf9f8", - "bodyText": "#323130", - "bodyTextChecked": "#000000", + "bodyFrameDivider": "#e0e0e0", + "bodyStandoutBackground": "#fafafa", + "bodyText": "#242424", + "bodyTextChecked": "#242424", "brandBackground": "#185abd", - "brandBackground2": "#eff6fc", - "brandBackgroundDisabled": undefined, + "brandBackground2": "#d2e0f4", + "brandBackground2Pressed": "#0e336a", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#d2e0f4", + "brandBackgroundDisabled": "#f0f0f0", "brandBackgroundHover": "#1651aa", - "brandBackgroundPressed": "#004578", + "brandBackgroundInverted": "#616161", + "brandBackgroundInvertedDisabled": "#f0f0f0", + "brandBackgroundPressed": "#0e336a", "brandBackgroundSelected": "#13458f", "brandBackgroundStatic": "#185abd", + "brandBackgroundTint": "#d2e0f4", "brandForeground1": "#185abd", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, + "brandForeground1Disabled": "#bdbdbd", + "brandForeground1Pressed": "#185abd", + "brandForeground1Selected": "#185abd", "brandForeground2": "#1651aa", - "brandForegroundLink": "#1651aa", - "brandForegroundLinkHover": "#13458f", - "brandForegroundLinkPressed": "#004578", - "brandForegroundLinkSelected": "#1651aa", + "brandForegroundDisabled1": "#bdbdbd", + "brandForegroundDisabled2": "#bdbdbd", + "brandForegroundLink": "#185abd", + "brandForegroundLinkHover": "#1651aa", + "brandForegroundLinkPressed": "#0e336a", + "brandForegroundLinkSelected": "#13458f", + "brandForegroundTint": "#1651aa", "brandStroke1": "#185abd", - "brandStroke2": "#d2e0f4", + "brandStroke1Pressed": "#185abd", + "brandStroke1Selected": "#185abd", + "brandStroke2": "#6794d7", + "brandStrokeTint": "#6794d7", "brandedBackground": "#185abd", - "brandedDisabledBorder": "#f3f2f1", - "brandedFocusedSecondaryContent": "#faf9f8", - "brandedHoveredSecondaryContent": "#faf9f8", - "brandedPressedSecondaryContent": "#faf9f8", - "brandedSecondaryContent": "#faf9f8", - "buttonBackground": "#f3f2f1", - "buttonBackgroundChecked": "#c8c6c4", - "buttonBackgroundDisabled": "#f3f2f1", - "buttonBackgroundHovered": "#edebe9", - "buttonBackgroundPressed": "#edebe9", - "buttonBorder": "#8a8886", - "buttonBorderDisabled": "#f3f2f1", - "buttonBorderFocused": "#8a8886", - "buttonText": "#323130", - "buttonTextChecked": "#201f1e", - "buttonTextDisabled": "#a19f9d", - "buttonTextHovered": "#201f1e", - "buttonTextPressed": "#201f1e", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#f0f0f0", + "buttonBackgroundHovered": "#f5f5f5", + "buttonBackgroundPressed": "#e0e0e0", + "buttonBorder": "#d1d1d1", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#242424", + "buttonTextChecked": "#242424", + "buttonTextDisabled": "#bdbdbd", + "buttonTextHovered": "#242424", + "buttonTextPressed": "#242424", "checkboxBackground": "#185abd", - "checkboxBackgroundDisabled": "#f3f2f1", - "checkboxBorderColor": "#8a8886", + "checkboxBackgroundDisabled": "#f0f0f0", + "checkboxBorderColor": "#616161", "checkmarkColor": "#ffffff", "compoundBrandBackground1": "#185abd", "compoundBrandBackground1Hover": "#1651aa", - "compoundBrandBackground1Pressed": "#13458f", + "compoundBrandBackground1Pressed": "#0e336a", "compoundBrandForeground1": "#185abd", "compoundBrandForeground1Hover": "#1651aa", - "compoundBrandForeground1Pressed": "#13458f", + "compoundBrandForeground1Pressed": "#0e336a", "compoundBrandStroke1": "#185abd", "compoundBrandStroke1Hover": "#1651aa", - "compoundBrandStroke1Pressed": "#13458f", + "compoundBrandStroke1Pressed": "#0e336a", "dangerBackground1": "#fdf6f6", "dangerBackground2": "#f1bbbc", "dangerBackground3": "#d13438", @@ -4174,83 +4016,84 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA "dangerForeground2": "#751d1f", "dangerForeground3": "#d13438", "dangerForegroundInverted": "#dc5e62", - "defaultBackground": "#f3f2f1", - "defaultBorder": "#8a8886", - "defaultCheckedBackground": "#c8c6c4", - "defaultCheckedContent": "#201f1e", - "defaultCheckedHoveredBackground": "#edebe9", - "defaultCheckedHoveredContent": "#201f1e", - "defaultContent": "#323130", - "defaultDisabledBackground": "#f3f2f1", - "defaultDisabledBorder": "#f3f2f1", - "defaultDisabledContent": "#a19f9d", - "defaultDisabledIcon": "#a19f9d", - "defaultFocusedBackground": "#edebe9", - "defaultFocusedBorder": "#8a8886", - "defaultFocusedContent": "#201f1e", - "defaultFocusedIcon": "#201f1e", - "defaultHoveredBackground": "#edebe9", - "defaultHoveredBorder": "#8a8886", - "defaultHoveredContent": "#201f1e", - "defaultHoveredIcon": "#201f1e", - "defaultHoveredSecondaryContent": "#a19f9d", - "defaultIcon": "#323130", - "defaultPressedBackground": "#edebe9", - "defaultPressedBorder": "#8a8886", - "defaultPressedContent": "#201f1e", - "defaultPressedIcon": "#201f1e", - "defaultPressedSecondaryContent": "#a19f9d", - "disabledBackground": "#f3f2f1", - "disabledBodyText": "#a19f9d", - "disabledText": "#a19f9d", - "errorText": "#a4262c", - "focusBorder": "#605e5c", - "ghostBackground": "#ffffff", - "ghostBorder": "#ffffff", - "ghostCheckedBackground": "#edebe9", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#f3f2f1", - "ghostCheckedHoveredBorder": "#201f1e", - "ghostCheckedHoveredContent": "#201f1e", - "ghostContent": "#323130", - "ghostDisabledBackground": "#ffffff", - "ghostDisabledBorder": "#ffffff", - "ghostDisabledContent": "#a19f9d", - "ghostDisabledIcon": "#a19f9d", - "ghostFocusedBackground": "#f3f2f1", - "ghostFocusedBorder": "#8a8886", - "ghostFocusedContent": "#201f1e", - "ghostFocusedIcon": "#201f1e", - "ghostFocusedSecondaryContent": "#605e5c", - "ghostHoveredBackground": "#f3f2f1", - "ghostHoveredBorder": "#f3f2f1", - "ghostHoveredContent": "#201f1e", - "ghostHoveredIcon": "#201f1e", - "ghostHoveredSecondaryContent": "#605e5c", - "ghostIcon": "#323130", - "ghostPressedBackground": "#edebe9", - "ghostPressedBorder": "#edebe9", - "ghostPressedContent": "#201f1e", - "ghostPressedIcon": "#201f1e", - "ghostPressedSecondaryContent": "#605e5c", - "ghostSecondaryContent": "#605e5c", + "dangerStroke1": "#f1bbbc", + "defaultBackground": "#ffffff", + "defaultBorder": "#d1d1d1", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#242424", + "defaultCheckedHoveredBackground": "#f5f5f5", + "defaultCheckedHoveredContent": "#242424", + "defaultContent": "#242424", + "defaultDisabledBackground": "#f0f0f0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#bdbdbd", + "defaultDisabledIcon": "#bdbdbd", + "defaultFocusedBackground": "#f5f5f5", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#242424", + "defaultFocusedIcon": "#242424", + "defaultHoveredBackground": "#f5f5f5", + "defaultHoveredBorder": "#c7c7c7", + "defaultHoveredContent": "#242424", + "defaultHoveredIcon": "#242424", + "defaultHoveredSecondaryContent": "#424242", + "defaultIcon": "#242424", + "defaultPressedBackground": "#e0e0e0", + "defaultPressedBorder": "#b3b3b3", + "defaultPressedContent": "#242424", + "defaultPressedIcon": "#242424", + "defaultPressedSecondaryContent": "#424242", + "disabledBackground": "#f0f0f0", + "disabledBodyText": "#bdbdbd", + "disabledText": "#bdbdbd", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#242424", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#242424", + "ghostContent": "#242424", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#bdbdbd", + "ghostDisabledIcon": "#bdbdbd", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#242424", + "ghostFocusedIcon": "#242424", + "ghostFocusedSecondaryContent": "#616161", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#242424", + "ghostHoveredIcon": "#242424", + "ghostHoveredSecondaryContent": "#424242", + "ghostIcon": "#242424", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#242424", + "ghostPressedIcon": "#242424", + "ghostPressedSecondaryContent": "#424242", + "ghostSecondaryContent": "#616161", "inputBackground": "#ffffff", - "inputBorder": "#a19f9d", + "inputBorder": "#d1d1d1", "inputFocusBorderAlt": "#185abd", - "inputPlaceholderText": "#605e5c", - "inputText": "#323130", + "inputPlaceholderText": "#707070", + "inputText": "#242424", "link": "#185abd", - "linkHovered": "#004578", - "linkPressed": "#13458f", - "listHeaderBackgroundHovered": "#f3f2f1", - "listHeaderBackgroundPressed": "#edebe9", + "linkHovered": "#1651aa", + "linkPressed": "#0e336a", + "listHeaderBackgroundHovered": "#f5f5f5", + "listHeaderBackgroundPressed": "#e0e0e0", "menuBackground": "#ffffff", - "menuDivider": "#c8c6c4", - "menuIcon": "#185abd", - "menuItemBackgroundHovered": "#f3f2f1", - "menuItemBackgroundPressed": "#edebe9", - "menuItemText": "#323130", - "menuItemTextHovered": "#201f1e", + "menuDivider": "#e0e0e0", + "menuIcon": "#424242", + "menuItemBackgroundHovered": "#f5f5f5", + "menuItemBackgroundPressed": "#e0e0e0", + "menuItemText": "#242424", + "menuItemTextHovered": "#242424", "neutralBackground1": "#ffffff", "neutralBackground1Hover": "#f5f5f5", "neutralBackground1Pressed": "#e0e0e0", @@ -4272,37 +4115,46 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA "neutralBackground5Pressed": "#f0f0f0", "neutralBackground5Selected": "#fafafa", "neutralBackground6": "#e6e6e6", + "neutralBackgroundCanvas": "#ffffff", + "neutralBackgroundDarkStatic": "#242424", "neutralBackgroundDisabled": "#f0f0f0", "neutralBackgroundInverted": "#616161", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#f0f0f0", "neutralForeground1": "#242424", "neutralForeground1Hover": "#242424", "neutralForeground1Pressed": "#242424", "neutralForeground1Selected": "#242424", "neutralForeground2": "#424242", - "neutralForeground2BrandHover": "#185abd", - "neutralForeground2BrandPressed": "#1651aa", - "neutralForeground2BrandSelected": "#185abd", + "neutralForeground2BrandHover": "#1651aa", + "neutralForeground2BrandPressed": "#0e336a", + "neutralForeground2BrandSelected": "#13458f", "neutralForeground2Hover": "#242424", "neutralForeground2Pressed": "#242424", "neutralForeground2Selected": "#242424", "neutralForeground3": "#616161", - "neutralForeground3BrandHover": "#185abd", - "neutralForeground3BrandPressed": "#1651aa", - "neutralForeground3BrandSelected": "#185abd", + "neutralForeground3BrandHover": "#1651aa", + "neutralForeground3BrandPressed": "#0e336a", + "neutralForeground3BrandSelected": "#13458f", "neutralForeground3Hover": "#424242", "neutralForeground3Pressed": "#424242", "neutralForeground3Selected": "#424242", "neutralForeground4": "#707070", + "neutralForegroundDarkStatic": "#000000", "neutralForegroundDisabled": "#bdbdbd", + "neutralForegroundDisabled1": "#bdbdbd", + "neutralForegroundDisabled2": "#bdbdbd", "neutralForegroundInverted": "#ffffff", "neutralForegroundInvertedLink": "#ffffff", "neutralForegroundInvertedLinkHover": "#ffffff", "neutralForegroundInvertedLinkPressed": "#ffffff", "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#ffffff", "neutralForegroundOnBrandHover": "#ffffff", "neutralForegroundOnBrandPressed": "#ffffff", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#e6e6e6", "neutralStencil2": "#fafafa", "neutralStroke1": "#d1d1d1", @@ -4316,6 +4168,8 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA "neutralStrokeAccessiblePressed": "#4d4d4d", "neutralStrokeAccessibleSelected": "#185abd", "neutralStrokeDisabled": "#e0e0e0", + "neutralStrokeFocus1": "#ffffff", + "neutralStrokeFocus2": "#000000", "outofofficeBackground1": "#fdf5fc", "outofofficeBackground2": "#edbbe7", "outofofficeBackground3": "#c239b3", @@ -4327,16 +4181,29 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA "outofofficeForeground3": "#c239b3", "personaActivityGlow": "#185abd", "personaActivityRing": "#ffffff", + "presenceAvailable": "#0e700e", + "presenceAway": "#817400", + "presenceDnd": "#bc2f32", + "presenceOof": "#af33a1", "primaryButtonBackground": "#185abd", - "primaryButtonBackgroundDisabled": "#f3f2f1", + "primaryButtonBackgroundDisabled": "#f0f0f0", "primaryButtonBackgroundHovered": "#1651aa", - "primaryButtonBackgroundPressed": "#13458f", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", + "primaryButtonBackgroundPressed": "#0e336a", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#000000", "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#d2d0ce", + "primaryButtonTextDisabled": "#bdbdbd", "primaryButtonTextHovered": "#ffffff", "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#f1bbbc", + "redBackground3": "#d13438", + "redBorder1": "#f1bbbc", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#751d1f", + "redForeground3": "#d13438", "severeBackground1": "#fdf6f3", "severeBackground2": "#f4bfab", "severeBackground3": "#da3b01", @@ -4346,9 +4213,10 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA "severeForeground1": "#c43501", "severeForeground2": "#7a2101", "severeForeground3": "#da3b01", + "severeStroke1": "#f4bfab", "strokeFocus1": "#ffffff", "strokeFocus2": "#000000", - "subText": "#605e5c", + "subText": "#424242", "subtleBackground": "#00000000", "subtleBackgroundHover": "#f5f5f5", "subtleBackgroundPressed": "#e0e0e0", @@ -4363,6 +4231,7 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA "successForeground2": "#094509", "successForeground3": "#107c10", "successForegroundInverted": "#359b35", + "successStroke1": "#9fd89f", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -4370,7 +4239,7 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA "transparentStroke": "#00000000", "transparentStrokeDisabled": "#00000000", "transparentStrokeInteractive": "#00000000", - "variantBorder": "#edebe9", + "variantBorder": "#e0e0e0", "warningBackground1": "#fffef5", "warningBackground2": "#fef7b2", "warningBackground3": "#fde300", @@ -4381,6 +4250,7 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA "warningForeground2": "#817400", "warningForeground3": "#fde300", "warningForegroundInverted": "#fef7b2", + "warningStroke1": "#fef7b2", }, "components": {}, "host": { @@ -4565,13 +4435,13 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -4585,138 +4455,153 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { @@ -4727,586 +4612,80 @@ exports[`createDefaultTheme test themeOption - { appearance: undefined, defaultA } `; -exports[`createShadowAliasTokens test appearanceOptions - dark 1`] = ` -{ - "shadow16": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 16, - "color": "#00000047", - "x": 0, - "y": 8, - }, - }, - "shadow16brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 16, - "color": "#00000040", - "x": 0, - "y": 8, - }, - }, - "shadow2": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 2, - "color": "#00000047", - "x": 0, - "y": 1, - }, - }, - "shadow28": { - "ambient": { - "blur": 8, - "color": "#00000066", - "x": 0, - "y": 0, - }, - "key": { - "blur": 28, - "color": "#0000007a", - "x": 0, - "y": 14, - }, - }, - "shadow28brand": { - "ambient": { - "blur": 8, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 28, - "color": "#00000040", - "x": 0, - "y": 14, - }, - }, - "shadow2brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 2, - "color": "#00000040", - "x": 0, - "y": 1, - }, - }, - "shadow4": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 4, - "color": "#00000047", - "x": 0, - "y": 2, - }, - }, - "shadow4brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 4, - "color": "#00000040", - "x": 0, - "y": 2, - }, - }, - "shadow64": { - "ambient": { - "blur": 8, - "color": "#00000066", - "x": 0, - "y": 0, - }, - "key": { - "blur": 64, - "color": "#0000007a", - "x": 0, - "y": 32, - }, - }, - "shadow64brand": { - "ambient": { - "blur": 8, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 64, - "color": "#00000040", - "x": 0, - "y": 32, - }, - }, - "shadow8": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 8, - "color": "#00000047", - "x": 0, - "y": 4, - }, - }, - "shadow8brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 8, - "color": "#00000040", - "x": 0, - "y": 4, - }, - }, -} -`; - -exports[`createShadowAliasTokens test appearanceOptions - highContrast 1`] = ` -{ - "shadow16": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 16, - "color": "#00000047", - "x": 0, - "y": 8, - }, - }, - "shadow16brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 16, - "color": "#00000040", - "x": 0, - "y": 8, - }, - }, - "shadow2": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 2, - "color": "#00000047", - "x": 0, - "y": 1, - }, - }, - "shadow28": { - "ambient": { - "blur": 8, - "color": "#00000066", - "x": 0, - "y": 0, - }, - "key": { - "blur": 28, - "color": "#0000007a", - "x": 0, - "y": 14, - }, - }, - "shadow28brand": { - "ambient": { - "blur": 8, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 28, - "color": "#00000040", - "x": 0, - "y": 14, - }, - }, - "shadow2brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 2, - "color": "#00000040", - "x": 0, - "y": 1, - }, - }, - "shadow4": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 4, - "color": "#00000047", - "x": 0, - "y": 2, - }, - }, - "shadow4brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 4, - "color": "#00000040", - "x": 0, - "y": 2, - }, - }, - "shadow64": { - "ambient": { - "blur": 8, - "color": "#00000066", - "x": 0, - "y": 0, - }, - "key": { - "blur": 64, - "color": "#0000007a", - "x": 0, - "y": 32, - }, - }, - "shadow64brand": { - "ambient": { - "blur": 8, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 64, - "color": "#00000040", - "x": 0, - "y": 32, - }, - }, - "shadow8": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 8, - "color": "#00000047", - "x": 0, - "y": 4, - }, - }, - "shadow8brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 8, - "color": "#00000040", - "x": 0, - "y": 4, - }, - }, -} -`; - -exports[`createShadowAliasTokens test appearanceOptions - light 1`] = ` -{ - "shadow16": { - "ambient": { - "blur": 2, - "color": "#0000001f", - "x": 0, - "y": 0, - }, - "key": { - "blur": 16, - "color": "#00000024", - "x": 0, - "y": 8, - }, - }, - "shadow16brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 16, - "color": "#00000040", - "x": 0, - "y": 8, - }, - }, - "shadow2": { - "ambient": { - "blur": 2, - "color": "#0000001f", - "x": 0, - "y": 0, - }, - "key": { - "blur": 2, - "color": "#00000024", - "x": 0, - "y": 1, - }, - }, - "shadow28": { - "ambient": { - "blur": 8, - "color": "#00000033", - "x": 0, - "y": 0, - }, - "key": { - "blur": 28, - "color": "#0000003d", - "x": 0, - "y": 14, - }, - }, - "shadow28brand": { - "ambient": { - "blur": 8, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 28, - "color": "#00000040", - "x": 0, - "y": 14, - }, - }, - "shadow2brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 2, - "color": "#00000040", - "x": 0, - "y": 1, - }, - }, - "shadow4": { - "ambient": { - "blur": 2, - "color": "#0000001f", - "x": 0, - "y": 0, - }, - "key": { - "blur": 4, - "color": "#00000024", - "x": 0, - "y": 2, - }, - }, - "shadow4brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 4, - "color": "#00000040", - "x": 0, - "y": 2, - }, - }, - "shadow64": { - "ambient": { - "blur": 8, - "color": "#00000033", - "x": 0, - "y": 0, - }, - "key": { - "blur": 64, - "color": "#0000003d", - "x": 0, - "y": 32, - }, - }, - "shadow64brand": { - "ambient": { - "blur": 8, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 64, - "color": "#00000040", - "x": 0, - "y": 32, - }, - }, - "shadow8": { - "ambient": { - "blur": 2, - "color": "#0000001f", - "x": 0, - "y": 0, - }, - "key": { - "blur": 8, - "color": "#00000024", - "x": 0, - "y": 4, - }, - }, - "shadow8brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 8, - "color": "#00000040", - "x": 0, - "y": 4, - }, - }, -} -`; - exports[`defaultFluentDarkTheme test 1`] = ` { "colors": { "accentButtonBackground": "#185abd", - "actionLink": "#f3f2f1", - "background": "#1b1a19", - "bodyDivider": "#292827", - "bodyFrameBackground": "#1b1a19", - "bodyFrameDivider": "#292827", - "bodyStandoutBackground": "#201f1e", - "bodyText": "#f3f2f1", + "actionLink": "#ffffff", + "background": "#292929", + "bodyDivider": "#525252", + "bodyFrameBackground": "#292929", + "bodyFrameDivider": "#525252", + "bodyStandoutBackground": "#1f1f1f", + "bodyText": "#ffffff", "bodyTextChecked": "#ffffff", - "brandBackground": "#1651aa", - "brandBackground2": "#004578", - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": "#185abd", - "brandBackgroundPressed": "#004578", + "brandBackground": "#185abd", + "brandBackground2": "#d2e0f4", + "brandBackground2Pressed": "#0e336a", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#d2e0f4", + "brandBackgroundDisabled": "#141414", + "brandBackgroundHover": "#1651aa", + "brandBackgroundInverted": "#ffffff", + "brandBackgroundInvertedDisabled": "#141414", + "brandBackgroundPressed": "#0e336a", "brandBackgroundSelected": "#13458f", "brandBackgroundStatic": "#185abd", - "brandForeground1": "#6794d7", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": "#aec6eb", - "brandForegroundLink": "#2e6ac5", - "brandForegroundLinkHover": "#aec6eb", - "brandForegroundLinkPressed": "#6794d7", - "brandForegroundLinkSelected": "#2e6ac5", - "brandStroke1": "#2e6ac5", - "brandStroke2": "#0e336a", - "brandedBackground": "#2e6ac5", - "brandedDisabledBorder": "#252423", - "brandedFocusedSecondaryContent": "#201f1e", - "brandedHoveredSecondaryContent": "#201f1e", - "brandedPressedSecondaryContent": "#201f1e", - "brandedSecondaryContent": "#201f1e", - "buttonBackground": "#252423", - "buttonBackgroundChecked": "#484644", - "buttonBackgroundDisabled": "#252423", - "buttonBackgroundHovered": "#292827", - "buttonBackgroundPressed": "#292827", - "buttonBorder": "#979693", - "buttonBorderDisabled": "#252423", - "buttonBorderFocused": "#979693", + "brandBackgroundTint": "#d2e0f4", + "brandForeground1": "#aec6eb", + "brandForeground1Disabled": "#5c5c5c", + "brandForeground1Pressed": "#aec6eb", + "brandForeground1Selected": "#aec6eb", + "brandForeground2": "#d2e0f4", + "brandForegroundDisabled1": "#5c5c5c", + "brandForegroundDisabled2": "#5c5c5c", + "brandForegroundLink": "#aec6eb", + "brandForegroundLinkHover": "#d2e0f4", + "brandForegroundLinkPressed": "#2e6ac5", + "brandForegroundLinkSelected": "#d2e0f4", + "brandForegroundTint": "#d2e0f4", + "brandStroke1": "#185abd", + "brandStroke1Pressed": "#185abd", + "brandStroke1Selected": "#185abd", + "brandStroke2": "#6794d7", + "brandStrokeTint": "#6794d7", + "brandedBackground": "#185abd", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#292929", + "buttonBackgroundChecked": "#383838", + "buttonBackgroundDisabled": "#141414", + "buttonBackgroundHovered": "#3d3d3d", + "buttonBackgroundPressed": "#1f1f1f", + "buttonBorder": "#666666", + "buttonBorderDisabled": "#424242", + "buttonBorderFocused": "#ffffff", "buttonText": "#ffffff", - "buttonTextChecked": "#faf9f8", - "buttonTextDisabled": "#797775", - "buttonTextHovered": "#f3f2f1", - "buttonTextPressed": "#faf9f8", - "checkboxBackground": "#2e6ac5", - "checkboxBackgroundDisabled": "#252423", - "checkboxBorderColor": "#979693", - "checkmarkColor": "#1b1a19", - "compoundBrandBackground1": "#2e6ac5", - "compoundBrandBackground1Hover": "#6794d7", - "compoundBrandBackground1Pressed": "#185abd", - "compoundBrandForeground1": "#2e6ac5", - "compoundBrandForeground1Hover": "#6794d7", - "compoundBrandForeground1Pressed": "#185abd", - "compoundBrandStroke1": "#2e6ac5", - "compoundBrandStroke1Hover": "#6794d7", - "compoundBrandStroke1Pressed": "#185abd", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#5c5c5c", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#185abd", + "checkboxBackgroundDisabled": "#141414", + "checkboxBorderColor": "#adadad", + "checkmarkColor": "#ffffff", + "compoundBrandBackground1": "#185abd", + "compoundBrandBackground1Hover": "#1651aa", + "compoundBrandBackground1Pressed": "#0e336a", + "compoundBrandForeground1": "#aec6eb", + "compoundBrandForeground1Hover": "#d2e0f4", + "compoundBrandForeground1Pressed": "#2e6ac5", + "compoundBrandStroke1": "#185abd", + "compoundBrandStroke1Hover": "#1651aa", + "compoundBrandStroke1Pressed": "#0e336a", "dangerBackground1": "#3f1011", "dangerBackground2": "#751d1f", "dangerBackground3": "#d13438", @@ -5317,83 +4696,84 @@ exports[`defaultFluentDarkTheme test 1`] = ` "dangerForeground2": "#f1bbbc", "dangerForeground3": "#e37d80", "dangerForegroundInverted": "#d13438", - "defaultBackground": "#252423", - "defaultBorder": "#979693", - "defaultCheckedBackground": "#484644", - "defaultCheckedContent": "#faf9f8", - "defaultCheckedHoveredBackground": "#292827", - "defaultCheckedHoveredContent": "#f3f2f1", + "dangerStroke1": "#d13438", + "defaultBackground": "#292929", + "defaultBorder": "#666666", + "defaultCheckedBackground": "#383838", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#3d3d3d", + "defaultCheckedHoveredContent": "#ffffff", "defaultContent": "#ffffff", - "defaultDisabledBackground": "#252423", - "defaultDisabledBorder": "#252423", - "defaultDisabledContent": "#797775", - "defaultDisabledIcon": "#797775", - "defaultFocusedBackground": "#292827", - "defaultFocusedBorder": "#979693", - "defaultFocusedContent": "#f3f2f1", - "defaultFocusedIcon": "#f3f2f1", - "defaultHoveredBackground": "#292827", - "defaultHoveredBorder": "#979693", - "defaultHoveredContent": "#f3f2f1", - "defaultHoveredIcon": "#f3f2f1", - "defaultHoveredSecondaryContent": "#797775", + "defaultDisabledBackground": "#141414", + "defaultDisabledBorder": "#424242", + "defaultDisabledContent": "#5c5c5c", + "defaultDisabledIcon": "#5c5c5c", + "defaultFocusedBackground": "#3d3d3d", + "defaultFocusedBorder": "#ffffff", + "defaultFocusedContent": "#ffffff", + "defaultFocusedIcon": "#ffffff", + "defaultHoveredBackground": "#3d3d3d", + "defaultHoveredBorder": "#757575", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#d6d6d6", "defaultIcon": "#ffffff", - "defaultPressedBackground": "#292827", - "defaultPressedBorder": "#979693", - "defaultPressedContent": "#faf9f8", - "defaultPressedIcon": "#faf9f8", - "defaultPressedSecondaryContent": "#797775", - "disabledBackground": "#323130", - "disabledBodyText": "#797775", - "disabledText": "#797775", - "errorText": "#ff5f5f", - "focusBorder": "#a19f9d", - "ghostBackground": "#1b1a19", - "ghostBorder": "#1b1a19", - "ghostCheckedBackground": "#292827", + "defaultPressedBackground": "#1f1f1f", + "defaultPressedBorder": "#6b6b6b", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#d6d6d6", + "disabledBackground": "#141414", + "disabledBodyText": "#5c5c5c", + "disabledText": "#5c5c5c", + "errorText": "#e37d80", + "focusBorder": "#ffffff", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#383838", "ghostCheckedContent": "#ffffff", - "ghostCheckedHoveredBackground": "#252423", - "ghostCheckedHoveredBorder": "#faf9f8", - "ghostCheckedHoveredContent": "#faf9f8", - "ghostContent": "#f3f2f1", - "ghostDisabledBackground": "#1b1a19", - "ghostDisabledBorder": "#1b1a19", - "ghostDisabledContent": "#797775", - "ghostDisabledIcon": "#797775", - "ghostFocusedBackground": "#252423", - "ghostFocusedBorder": "#979693", - "ghostFocusedContent": "#faf9f8", - "ghostFocusedIcon": "#faf9f8", - "ghostFocusedSecondaryContent": "#a19f9d", - "ghostHoveredBackground": "#252423", - "ghostHoveredBorder": "#252423", - "ghostHoveredContent": "#faf9f8", - "ghostHoveredIcon": "#faf9f8", - "ghostHoveredSecondaryContent": "#a19f9d", - "ghostIcon": "#f3f2f1", - "ghostPressedBackground": "#292827", - "ghostPressedBorder": "#292827", - "ghostPressedContent": "#faf9f8", - "ghostPressedIcon": "#faf9f8", - "ghostPressedSecondaryContent": "#a19f9d", - "ghostSecondaryContent": "#a19f9d", - "inputBackground": "#1b1a19", - "inputBorder": "#797775", - "inputFocusBorderAlt": "#2e6ac5", - "inputPlaceholderText": "#a19f9d", - "inputText": "#f3f2f1", - "link": "#2e6ac5", - "linkHovered": "#82c7ff", - "linkPressed": "#aec6eb", - "listHeaderBackgroundHovered": "#252423", - "listHeaderBackgroundPressed": "#292827", - "menuBackground": "#252423", - "menuDivider": "#484644", - "menuIcon": "#6794d7", - "menuItemBackgroundHovered": "#323130", - "menuItemBackgroundPressed": "#3b3a39", - "menuItemText": "#f3f2f1", - "menuItemTextHovered": "#faf9f8", + "ghostCheckedHoveredBackground": "#3d3d3d", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#ffffff", + "ghostContent": "#ffffff", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#5c5c5c", + "ghostDisabledIcon": "#5c5c5c", + "ghostFocusedBackground": "#3d3d3d", + "ghostFocusedBorder": "#ffffff", + "ghostFocusedContent": "#ffffff", + "ghostFocusedIcon": "#ffffff", + "ghostFocusedSecondaryContent": "#adadad", + "ghostHoveredBackground": "#3d3d3d", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#d6d6d6", + "ghostIcon": "#ffffff", + "ghostPressedBackground": "#1f1f1f", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#d6d6d6", + "ghostSecondaryContent": "#adadad", + "inputBackground": "#292929", + "inputBorder": "#666666", + "inputFocusBorderAlt": "#185abd", + "inputPlaceholderText": "#999999", + "inputText": "#ffffff", + "link": "#aec6eb", + "linkHovered": "#d2e0f4", + "linkPressed": "#2e6ac5", + "listHeaderBackgroundHovered": "#3d3d3d", + "listHeaderBackgroundPressed": "#1f1f1f", + "menuBackground": "#292929", + "menuDivider": "#525252", + "menuIcon": "#d6d6d6", + "menuItemBackgroundHovered": "#3d3d3d", + "menuItemBackgroundPressed": "#1f1f1f", + "menuItemText": "#ffffff", + "menuItemTextHovered": "#ffffff", "neutralBackground1": "#292929", "neutralBackground1Hover": "#3d3d3d", "neutralBackground1Pressed": "#1f1f1f", @@ -5415,37 +4795,46 @@ exports[`defaultFluentDarkTheme test 1`] = ` "neutralBackground5Pressed": "#050505", "neutralBackground5Selected": "#0f0f0f", "neutralBackground6": "#333333", + "neutralBackgroundCanvas": "#292929", + "neutralBackgroundDarkStatic": "#3d3d3d", "neutralBackgroundDisabled": "#141414", "neutralBackgroundInverted": "#ffffff", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#141414", "neutralForeground1": "#ffffff", "neutralForeground1Hover": "#ffffff", "neutralForeground1Pressed": "#ffffff", "neutralForeground1Selected": "#ffffff", "neutralForeground2": "#d6d6d6", - "neutralForeground2BrandHover": "#6794d7", + "neutralForeground2BrandHover": "#d2e0f4", "neutralForeground2BrandPressed": "#2e6ac5", - "neutralForeground2BrandSelected": "#6794d7", + "neutralForeground2BrandSelected": "#d2e0f4", "neutralForeground2Hover": "#ffffff", "neutralForeground2Pressed": "#ffffff", "neutralForeground2Selected": "#ffffff", "neutralForeground3": "#adadad", - "neutralForeground3BrandHover": "#6794d7", + "neutralForeground3BrandHover": "#d2e0f4", "neutralForeground3BrandPressed": "#2e6ac5", - "neutralForeground3BrandSelected": "#6794d7", + "neutralForeground3BrandSelected": "#d2e0f4", "neutralForeground3Hover": "#d6d6d6", "neutralForeground3Pressed": "#d6d6d6", "neutralForeground3Selected": "#d6d6d6", "neutralForeground4": "#999999", + "neutralForegroundDarkStatic": "#000000", "neutralForegroundDisabled": "#5c5c5c", - "neutralForegroundInverted": "#242424", - "neutralForegroundInvertedLink": "#ffffff", - "neutralForegroundInvertedLinkHover": "#ffffff", - "neutralForegroundInvertedLinkPressed": "#ffffff", - "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundDisabled1": "#5c5c5c", + "neutralForegroundDisabled2": "#5c5c5c", + "neutralForegroundInverted": "#000000", + "neutralForegroundInvertedLink": "#292929", + "neutralForegroundInvertedLinkHover": "#292929", + "neutralForegroundInvertedLinkPressed": "#292929", + "neutralForegroundInvertedLinkSelected": "#292929", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#ffffff", "neutralForegroundOnBrandHover": "#ffffff", "neutralForegroundOnBrandPressed": "#ffffff", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#333333", "neutralStencil2": "#575757", "neutralStroke1": "#666666", @@ -5457,8 +4846,10 @@ exports[`defaultFluentDarkTheme test 1`] = ` "neutralStrokeAccessible": "#adadad", "neutralStrokeAccessibleHover": "#bdbdbd", "neutralStrokeAccessiblePressed": "#b3b3b3", - "neutralStrokeAccessibleSelected": "#6794d7", + "neutralStrokeAccessibleSelected": "#185abd", "neutralStrokeDisabled": "#424242", + "neutralStrokeFocus1": "#000000", + "neutralStrokeFocus2": "#ffffff", "outofofficeBackground1": "#3a1136", "outofofficeBackground2": "#6d2064", "outofofficeBackground3": "#c239b3", @@ -5468,18 +4859,31 @@ exports[`defaultFluentDarkTheme test 1`] = ` "outofofficeForeground1": "#da7ed0", "outofofficeForeground2": "#edbbe7", "outofofficeForeground3": "#d161c4", - "personaActivityGlow": "#2e6ac5", - "personaActivityRing": "#1b1a19", - "primaryButtonBackground": "#2e6ac5", - "primaryButtonBackgroundDisabled": "#252423", - "primaryButtonBackgroundHovered": "#6794d7", - "primaryButtonBackgroundPressed": "#aec6eb", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", - "primaryButtonText": "#1b1a19", - "primaryButtonTextDisabled": "#3b3a39", - "primaryButtonTextHovered": "#1b1a19", - "primaryButtonTextPressed": "#1b1a19", + "personaActivityGlow": "#185abd", + "personaActivityRing": "#292929", + "presenceAvailable": "#54b054", + "presenceAway": "#feee66", + "presenceDnd": "#e37d80", + "presenceOof": "#da7ed0", + "primaryButtonBackground": "#185abd", + "primaryButtonBackgroundDisabled": "#141414", + "primaryButtonBackgroundHovered": "#1651aa", + "primaryButtonBackgroundPressed": "#0e336a", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#ffffff", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#5c5c5c", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#751d1f", + "redBackground3": "#d13438", + "redBorder1": "#d13438", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#f1bbbc", + "redForeground3": "#e37d80", "severeBackground1": "#411200", "severeBackground2": "#7a2101", "severeBackground3": "#da3b01", @@ -5489,13 +4893,14 @@ exports[`defaultFluentDarkTheme test 1`] = ` "severeForeground1": "#e9835e", "severeForeground2": "#f4bfab", "severeForeground3": "#e9835e", + "severeStroke1": "#da3b01", "strokeFocus1": "#000000", "strokeFocus2": "#ffffff", - "subText": "#a19f9d", + "subText": "#d6d6d6", "subtleBackground": "#00000000", - "subtleBackgroundHover": "#383838", - "subtleBackgroundPressed": "#2e2e2e", - "subtleBackgroundSelected": "#333333", + "subtleBackgroundHover": "#3d3d3d", + "subtleBackgroundPressed": "#1f1f1f", + "subtleBackgroundSelected": "#383838", "successBackground1": "#052505", "successBackground2": "#094509", "successBackground3": "#107c10", @@ -5506,6 +4911,7 @@ exports[`defaultFluentDarkTheme test 1`] = ` "successForeground2": "#9fd89f", "successForeground3": "#9fd89f", "successForegroundInverted": "#107c10", + "successStroke1": "#107c10", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -5513,7 +4919,7 @@ exports[`defaultFluentDarkTheme test 1`] = ` "transparentStroke": "#00000000", "transparentStrokeDisabled": "#00000000", "transparentStrokeInteractive": "#00000000", - "variantBorder": "#292827", + "variantBorder": "#525252", "warningBackground1": "#4c4400", "warningBackground2": "#817400", "warningBackground3": "#fde300", @@ -5524,6 +4930,7 @@ exports[`defaultFluentDarkTheme test 1`] = ` "warningForeground2": "#fef7b2", "warningForeground3": "#fdea3d", "warningForegroundInverted": "#817400", + "warningStroke1": "#fde300", }, "components": {}, "host": { @@ -5708,13 +5115,13 @@ exports[`defaultFluentDarkTheme test 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -5728,138 +5135,153 @@ exports[`defaultFluentDarkTheme test 1`] = ` "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { @@ -5874,63 +5296,76 @@ exports[`defaultFluentTheme test 1`] = ` { "colors": { "accentButtonBackground": "#185abd", - "actionLink": "#323130", + "actionLink": "#242424", "background": "#ffffff", - "bodyDivider": "#edebe9", + "bodyDivider": "#e0e0e0", "bodyFrameBackground": "#ffffff", - "bodyFrameDivider": "#edebe9", - "bodyStandoutBackground": "#faf9f8", - "bodyText": "#323130", - "bodyTextChecked": "#000000", + "bodyFrameDivider": "#e0e0e0", + "bodyStandoutBackground": "#fafafa", + "bodyText": "#242424", + "bodyTextChecked": "#242424", "brandBackground": "#185abd", - "brandBackground2": "#eff6fc", - "brandBackgroundDisabled": undefined, + "brandBackground2": "#d2e0f4", + "brandBackground2Pressed": "#0e336a", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#d2e0f4", + "brandBackgroundDisabled": "#f0f0f0", "brandBackgroundHover": "#1651aa", - "brandBackgroundPressed": "#004578", + "brandBackgroundInverted": "#616161", + "brandBackgroundInvertedDisabled": "#f0f0f0", + "brandBackgroundPressed": "#0e336a", "brandBackgroundSelected": "#13458f", "brandBackgroundStatic": "#185abd", + "brandBackgroundTint": "#d2e0f4", "brandForeground1": "#185abd", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, + "brandForeground1Disabled": "#bdbdbd", + "brandForeground1Pressed": "#185abd", + "brandForeground1Selected": "#185abd", "brandForeground2": "#1651aa", - "brandForegroundLink": "#1651aa", - "brandForegroundLinkHover": "#13458f", - "brandForegroundLinkPressed": "#004578", - "brandForegroundLinkSelected": "#1651aa", + "brandForegroundDisabled1": "#bdbdbd", + "brandForegroundDisabled2": "#bdbdbd", + "brandForegroundLink": "#185abd", + "brandForegroundLinkHover": "#1651aa", + "brandForegroundLinkPressed": "#0e336a", + "brandForegroundLinkSelected": "#13458f", + "brandForegroundTint": "#1651aa", "brandStroke1": "#185abd", - "brandStroke2": "#d2e0f4", + "brandStroke1Pressed": "#185abd", + "brandStroke1Selected": "#185abd", + "brandStroke2": "#6794d7", + "brandStrokeTint": "#6794d7", "brandedBackground": "#185abd", - "brandedDisabledBorder": "#f3f2f1", - "brandedFocusedSecondaryContent": "#faf9f8", - "brandedHoveredSecondaryContent": "#faf9f8", - "brandedPressedSecondaryContent": "#faf9f8", - "brandedSecondaryContent": "#faf9f8", - "buttonBackground": "#f3f2f1", - "buttonBackgroundChecked": "#c8c6c4", - "buttonBackgroundDisabled": "#f3f2f1", - "buttonBackgroundHovered": "#edebe9", - "buttonBackgroundPressed": "#edebe9", - "buttonBorder": "#8a8886", - "buttonBorderDisabled": "#f3f2f1", - "buttonBorderFocused": "#8a8886", - "buttonText": "#323130", - "buttonTextChecked": "#201f1e", - "buttonTextDisabled": "#a19f9d", - "buttonTextHovered": "#201f1e", - "buttonTextPressed": "#201f1e", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#f0f0f0", + "buttonBackgroundHovered": "#f5f5f5", + "buttonBackgroundPressed": "#e0e0e0", + "buttonBorder": "#d1d1d1", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#242424", + "buttonTextChecked": "#242424", + "buttonTextDisabled": "#bdbdbd", + "buttonTextHovered": "#242424", + "buttonTextPressed": "#242424", "checkboxBackground": "#185abd", - "checkboxBackgroundDisabled": "#f3f2f1", - "checkboxBorderColor": "#8a8886", + "checkboxBackgroundDisabled": "#f0f0f0", + "checkboxBorderColor": "#616161", "checkmarkColor": "#ffffff", "compoundBrandBackground1": "#185abd", "compoundBrandBackground1Hover": "#1651aa", - "compoundBrandBackground1Pressed": "#13458f", + "compoundBrandBackground1Pressed": "#0e336a", "compoundBrandForeground1": "#185abd", "compoundBrandForeground1Hover": "#1651aa", - "compoundBrandForeground1Pressed": "#13458f", + "compoundBrandForeground1Pressed": "#0e336a", "compoundBrandStroke1": "#185abd", "compoundBrandStroke1Hover": "#1651aa", - "compoundBrandStroke1Pressed": "#13458f", + "compoundBrandStroke1Pressed": "#0e336a", "dangerBackground1": "#fdf6f6", "dangerBackground2": "#f1bbbc", "dangerBackground3": "#d13438", @@ -5941,83 +5376,84 @@ exports[`defaultFluentTheme test 1`] = ` "dangerForeground2": "#751d1f", "dangerForeground3": "#d13438", "dangerForegroundInverted": "#dc5e62", - "defaultBackground": "#f3f2f1", - "defaultBorder": "#8a8886", - "defaultCheckedBackground": "#c8c6c4", - "defaultCheckedContent": "#201f1e", - "defaultCheckedHoveredBackground": "#edebe9", - "defaultCheckedHoveredContent": "#201f1e", - "defaultContent": "#323130", - "defaultDisabledBackground": "#f3f2f1", - "defaultDisabledBorder": "#f3f2f1", - "defaultDisabledContent": "#a19f9d", - "defaultDisabledIcon": "#a19f9d", - "defaultFocusedBackground": "#edebe9", - "defaultFocusedBorder": "#8a8886", - "defaultFocusedContent": "#201f1e", - "defaultFocusedIcon": "#201f1e", - "defaultHoveredBackground": "#edebe9", - "defaultHoveredBorder": "#8a8886", - "defaultHoveredContent": "#201f1e", - "defaultHoveredIcon": "#201f1e", - "defaultHoveredSecondaryContent": "#a19f9d", - "defaultIcon": "#323130", - "defaultPressedBackground": "#edebe9", - "defaultPressedBorder": "#8a8886", - "defaultPressedContent": "#201f1e", - "defaultPressedIcon": "#201f1e", - "defaultPressedSecondaryContent": "#a19f9d", - "disabledBackground": "#f3f2f1", - "disabledBodyText": "#a19f9d", - "disabledText": "#a19f9d", - "errorText": "#a4262c", - "focusBorder": "#605e5c", - "ghostBackground": "#ffffff", - "ghostBorder": "#ffffff", - "ghostCheckedBackground": "#edebe9", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#f3f2f1", - "ghostCheckedHoveredBorder": "#201f1e", - "ghostCheckedHoveredContent": "#201f1e", - "ghostContent": "#323130", - "ghostDisabledBackground": "#ffffff", - "ghostDisabledBorder": "#ffffff", - "ghostDisabledContent": "#a19f9d", - "ghostDisabledIcon": "#a19f9d", - "ghostFocusedBackground": "#f3f2f1", - "ghostFocusedBorder": "#8a8886", - "ghostFocusedContent": "#201f1e", - "ghostFocusedIcon": "#201f1e", - "ghostFocusedSecondaryContent": "#605e5c", - "ghostHoveredBackground": "#f3f2f1", - "ghostHoveredBorder": "#f3f2f1", - "ghostHoveredContent": "#201f1e", - "ghostHoveredIcon": "#201f1e", - "ghostHoveredSecondaryContent": "#605e5c", - "ghostIcon": "#323130", - "ghostPressedBackground": "#edebe9", - "ghostPressedBorder": "#edebe9", - "ghostPressedContent": "#201f1e", - "ghostPressedIcon": "#201f1e", - "ghostPressedSecondaryContent": "#605e5c", - "ghostSecondaryContent": "#605e5c", + "dangerStroke1": "#f1bbbc", + "defaultBackground": "#ffffff", + "defaultBorder": "#d1d1d1", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#242424", + "defaultCheckedHoveredBackground": "#f5f5f5", + "defaultCheckedHoveredContent": "#242424", + "defaultContent": "#242424", + "defaultDisabledBackground": "#f0f0f0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#bdbdbd", + "defaultDisabledIcon": "#bdbdbd", + "defaultFocusedBackground": "#f5f5f5", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#242424", + "defaultFocusedIcon": "#242424", + "defaultHoveredBackground": "#f5f5f5", + "defaultHoveredBorder": "#c7c7c7", + "defaultHoveredContent": "#242424", + "defaultHoveredIcon": "#242424", + "defaultHoveredSecondaryContent": "#424242", + "defaultIcon": "#242424", + "defaultPressedBackground": "#e0e0e0", + "defaultPressedBorder": "#b3b3b3", + "defaultPressedContent": "#242424", + "defaultPressedIcon": "#242424", + "defaultPressedSecondaryContent": "#424242", + "disabledBackground": "#f0f0f0", + "disabledBodyText": "#bdbdbd", + "disabledText": "#bdbdbd", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#242424", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#242424", + "ghostContent": "#242424", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#bdbdbd", + "ghostDisabledIcon": "#bdbdbd", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#242424", + "ghostFocusedIcon": "#242424", + "ghostFocusedSecondaryContent": "#616161", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#242424", + "ghostHoveredIcon": "#242424", + "ghostHoveredSecondaryContent": "#424242", + "ghostIcon": "#242424", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#242424", + "ghostPressedIcon": "#242424", + "ghostPressedSecondaryContent": "#424242", + "ghostSecondaryContent": "#616161", "inputBackground": "#ffffff", - "inputBorder": "#a19f9d", + "inputBorder": "#d1d1d1", "inputFocusBorderAlt": "#185abd", - "inputPlaceholderText": "#605e5c", - "inputText": "#323130", + "inputPlaceholderText": "#707070", + "inputText": "#242424", "link": "#185abd", - "linkHovered": "#004578", - "linkPressed": "#13458f", - "listHeaderBackgroundHovered": "#f3f2f1", - "listHeaderBackgroundPressed": "#edebe9", + "linkHovered": "#1651aa", + "linkPressed": "#0e336a", + "listHeaderBackgroundHovered": "#f5f5f5", + "listHeaderBackgroundPressed": "#e0e0e0", "menuBackground": "#ffffff", - "menuDivider": "#c8c6c4", - "menuIcon": "#185abd", - "menuItemBackgroundHovered": "#f3f2f1", - "menuItemBackgroundPressed": "#edebe9", - "menuItemText": "#323130", - "menuItemTextHovered": "#201f1e", + "menuDivider": "#e0e0e0", + "menuIcon": "#424242", + "menuItemBackgroundHovered": "#f5f5f5", + "menuItemBackgroundPressed": "#e0e0e0", + "menuItemText": "#242424", + "menuItemTextHovered": "#242424", "neutralBackground1": "#ffffff", "neutralBackground1Hover": "#f5f5f5", "neutralBackground1Pressed": "#e0e0e0", @@ -6039,37 +5475,46 @@ exports[`defaultFluentTheme test 1`] = ` "neutralBackground5Pressed": "#f0f0f0", "neutralBackground5Selected": "#fafafa", "neutralBackground6": "#e6e6e6", + "neutralBackgroundCanvas": "#ffffff", + "neutralBackgroundDarkStatic": "#242424", "neutralBackgroundDisabled": "#f0f0f0", "neutralBackgroundInverted": "#616161", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#f0f0f0", "neutralForeground1": "#242424", "neutralForeground1Hover": "#242424", "neutralForeground1Pressed": "#242424", "neutralForeground1Selected": "#242424", "neutralForeground2": "#424242", - "neutralForeground2BrandHover": "#185abd", - "neutralForeground2BrandPressed": "#1651aa", - "neutralForeground2BrandSelected": "#185abd", + "neutralForeground2BrandHover": "#1651aa", + "neutralForeground2BrandPressed": "#0e336a", + "neutralForeground2BrandSelected": "#13458f", "neutralForeground2Hover": "#242424", "neutralForeground2Pressed": "#242424", "neutralForeground2Selected": "#242424", "neutralForeground3": "#616161", - "neutralForeground3BrandHover": "#185abd", - "neutralForeground3BrandPressed": "#1651aa", - "neutralForeground3BrandSelected": "#185abd", + "neutralForeground3BrandHover": "#1651aa", + "neutralForeground3BrandPressed": "#0e336a", + "neutralForeground3BrandSelected": "#13458f", "neutralForeground3Hover": "#424242", "neutralForeground3Pressed": "#424242", "neutralForeground3Selected": "#424242", "neutralForeground4": "#707070", + "neutralForegroundDarkStatic": "#000000", "neutralForegroundDisabled": "#bdbdbd", + "neutralForegroundDisabled1": "#bdbdbd", + "neutralForegroundDisabled2": "#bdbdbd", "neutralForegroundInverted": "#ffffff", "neutralForegroundInvertedLink": "#ffffff", "neutralForegroundInvertedLinkHover": "#ffffff", "neutralForegroundInvertedLinkPressed": "#ffffff", "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#ffffff", "neutralForegroundOnBrandHover": "#ffffff", "neutralForegroundOnBrandPressed": "#ffffff", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#e6e6e6", "neutralStencil2": "#fafafa", "neutralStroke1": "#d1d1d1", @@ -6083,6 +5528,8 @@ exports[`defaultFluentTheme test 1`] = ` "neutralStrokeAccessiblePressed": "#4d4d4d", "neutralStrokeAccessibleSelected": "#185abd", "neutralStrokeDisabled": "#e0e0e0", + "neutralStrokeFocus1": "#ffffff", + "neutralStrokeFocus2": "#000000", "outofofficeBackground1": "#fdf5fc", "outofofficeBackground2": "#edbbe7", "outofofficeBackground3": "#c239b3", @@ -6094,16 +5541,29 @@ exports[`defaultFluentTheme test 1`] = ` "outofofficeForeground3": "#c239b3", "personaActivityGlow": "#185abd", "personaActivityRing": "#ffffff", + "presenceAvailable": "#0e700e", + "presenceAway": "#817400", + "presenceDnd": "#bc2f32", + "presenceOof": "#af33a1", "primaryButtonBackground": "#185abd", - "primaryButtonBackgroundDisabled": "#f3f2f1", + "primaryButtonBackgroundDisabled": "#f0f0f0", "primaryButtonBackgroundHovered": "#1651aa", - "primaryButtonBackgroundPressed": "#13458f", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", + "primaryButtonBackgroundPressed": "#0e336a", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#000000", "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#d2d0ce", + "primaryButtonTextDisabled": "#bdbdbd", "primaryButtonTextHovered": "#ffffff", "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#f1bbbc", + "redBackground3": "#d13438", + "redBorder1": "#f1bbbc", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#751d1f", + "redForeground3": "#d13438", "severeBackground1": "#fdf6f3", "severeBackground2": "#f4bfab", "severeBackground3": "#da3b01", @@ -6113,9 +5573,10 @@ exports[`defaultFluentTheme test 1`] = ` "severeForeground1": "#c43501", "severeForeground2": "#7a2101", "severeForeground3": "#da3b01", + "severeStroke1": "#f4bfab", "strokeFocus1": "#ffffff", "strokeFocus2": "#000000", - "subText": "#605e5c", + "subText": "#424242", "subtleBackground": "#00000000", "subtleBackgroundHover": "#f5f5f5", "subtleBackgroundPressed": "#e0e0e0", @@ -6130,6 +5591,7 @@ exports[`defaultFluentTheme test 1`] = ` "successForeground2": "#094509", "successForeground3": "#107c10", "successForegroundInverted": "#359b35", + "successStroke1": "#9fd89f", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -6137,7 +5599,7 @@ exports[`defaultFluentTheme test 1`] = ` "transparentStroke": "#00000000", "transparentStrokeDisabled": "#00000000", "transparentStrokeInteractive": "#00000000", - "variantBorder": "#edebe9", + "variantBorder": "#e0e0e0", "warningBackground1": "#fffef5", "warningBackground2": "#fef7b2", "warningBackground3": "#fde300", @@ -6148,6 +5610,7 @@ exports[`defaultFluentTheme test 1`] = ` "warningForeground2": "#817400", "warningForeground3": "#fde300", "warningForegroundInverted": "#fef7b2", + "warningStroke1": "#fef7b2", }, "components": {}, "host": { @@ -6332,13 +5795,13 @@ exports[`defaultFluentTheme test 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -6352,138 +5815,153 @@ exports[`defaultFluentTheme test 1`] = ` "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { diff --git a/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.android.ts.snap b/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.android.ts.snap index f14380d03c..78048a0794 100644 --- a/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.android.ts.snap +++ b/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.android.ts.snap @@ -3,157 +3,183 @@ exports[`defaultFluentDarkTheme 1`] = ` { "colors": { - "accentButtonBackground": "#0c3b5e", - "actionLink": "#f3f2f1", - "background": "#1b1a19", - "bodyDivider": "#292827", - "bodyFrameBackground": "#1b1a19", - "bodyFrameDivider": "#292827", - "bodyStandoutBackground": "#201f1e", - "bodyText": "#f3f2f1", + "accentButtonBackground": "#479ef5", + "actionLink": "#ffffff", + "background": "#000000", + "bodyDivider": "#3d3d3d", + "bodyFrameBackground": "#000000", + "bodyFrameDivider": "#3d3d3d", + "bodyStandoutBackground": "#1f1f1f", + "bodyText": "#ffffff", "bodyTextChecked": "#ffffff", "brandBackground": "#479ef5", - "brandBackground2": undefined, - "brandBackground2Pressed": undefined, - "brandBackground2Selected": undefined, - "brandBackground3": undefined, + "brandBackground2": "#479ef5", + "brandBackground2Pressed": "#96c6fa", + "brandBackground2Selected": "#77b7f7", + "brandBackground3": "#479ef5", "brandBackgroundDisabled": "#0c3b5e", + "brandBackgroundHover": "#479ef5", "brandBackgroundInverted": "#ffffff", "brandBackgroundInvertedDisabled": "#adadad", "brandBackgroundPressed": "#96c6fa", "brandBackgroundSelected": "#77b7f7", + "brandBackgroundStatic": "#479ef5", "brandBackgroundTint": "#0c3b5e", "brandForeground1": "#479ef5", + "brandForeground1Disabled": "#2886de", "brandForeground1Pressed": "#96c6fa", "brandForeground1Selected": "#77b7f7", + "brandForeground2": "#479ef5", "brandForegroundDisabled1": "#2886de", "brandForegroundDisabled2": "#0c3b5e", + "brandForegroundLink": "#479ef5", + "brandForegroundLinkHover": "#479ef5", + "brandForegroundLinkPressed": "#96c6fa", + "brandForegroundLinkSelected": "#77b7f7", "brandForegroundTint": "#96c6fa", "brandStroke1": "#479ef5", "brandStroke1Pressed": "#96c6fa", "brandStroke1Selected": "#77b7f7", - "brandedBackground": "#2886de", - "brandedDisabledBorder": "#252423", - "brandedFocusedSecondaryContent": "#201f1e", - "brandedHoveredSecondaryContent": "#201f1e", - "brandedPressedSecondaryContent": "#201f1e", - "brandedSecondaryContent": "#201f1e", - "buttonBackground": "#252423", - "buttonBackgroundChecked": "#484644", - "buttonBackgroundDisabled": "#252423", - "buttonBackgroundHovered": "#292827", - "buttonBackgroundPressed": "#292827", - "buttonBorder": "#979693", - "buttonBorderDisabled": "#252423", - "buttonBorderFocused": "#979693", + "brandStroke2": "#479ef5", + "brandStrokeTint": "#479ef5", + "brandedBackground": "#479ef5", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#000000", + "buttonBackground": "#000000", + "buttonBackgroundChecked": "#242424", + "buttonBackgroundDisabled": "#525252", + "buttonBackgroundHovered": "#000000", + "buttonBackgroundPressed": "#2e2e2e", + "buttonBorder": "#4d4d4d", + "buttonBorderDisabled": "#424242", + "buttonBorderFocused": "#ffffff", "buttonText": "#ffffff", - "buttonTextChecked": "#faf9f8", - "buttonTextDisabled": "#797775", - "buttonTextHovered": "#f3f2f1", - "buttonTextPressed": "#faf9f8", - "checkboxBackground": "#2886de", - "checkboxBackgroundDisabled": "#252423", - "checkboxBorderColor": "#979693", - "checkmarkColor": "#1b1a19", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#5c5c5c", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#479ef5", + "checkboxBackgroundDisabled": "#525252", + "checkboxBorderColor": "#9e9e9e", + "checkmarkColor": "#000000", + "compoundBrandBackground1": "#479ef5", + "compoundBrandBackground1Hover": "#479ef5", + "compoundBrandBackground1Pressed": "#96c6fa", + "compoundBrandForeground1": "#479ef5", + "compoundBrandForeground1Hover": "#479ef5", + "compoundBrandForeground1Pressed": "#96c6fa", + "compoundBrandStroke1": "#479ef5", + "compoundBrandStroke1Hover": "#479ef5", + "compoundBrandStroke1Pressed": "#96c6fa", "dangerBackground1": "#3f1011", "dangerBackground2": "#bc2f32", + "dangerBackground3": "#d13438", + "dangerBorder1": "#dc5e62", + "dangerBorder2": "#dc5e62", + "dangerBorderActive": "#e37d80", "dangerForeground1": "#e37d80", "dangerForeground2": "#e37d80", - "defaultBackground": "#252423", - "defaultBorder": "#979693", - "defaultCheckedBackground": "#484644", - "defaultCheckedContent": "#faf9f8", - "defaultCheckedHoveredBackground": "#292827", - "defaultCheckedHoveredContent": "#f3f2f1", + "dangerForeground3": "#e37d80", + "dangerForegroundInverted": "#d13438", + "dangerStroke1": "#dc5e62", + "defaultBackground": "#000000", + "defaultBorder": "#4d4d4d", + "defaultCheckedBackground": "#242424", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#000000", + "defaultCheckedHoveredContent": "#ffffff", "defaultContent": "#ffffff", - "defaultDisabledBackground": "#252423", - "defaultDisabledBorder": "#252423", - "defaultDisabledContent": "#797775", - "defaultDisabledIcon": "#797775", - "defaultFocusedBackground": "#292827", - "defaultFocusedBorder": "#979693", - "defaultFocusedContent": "#f3f2f1", - "defaultFocusedIcon": "#f3f2f1", - "defaultHoveredBackground": "#292827", - "defaultHoveredBorder": "#979693", - "defaultHoveredContent": "#f3f2f1", - "defaultHoveredIcon": "#f3f2f1", - "defaultHoveredSecondaryContent": "#797775", + "defaultDisabledBackground": "#525252", + "defaultDisabledBorder": "#424242", + "defaultDisabledContent": "#5c5c5c", + "defaultDisabledIcon": "#5c5c5c", + "defaultFocusedBackground": "#000000", + "defaultFocusedBorder": "#ffffff", + "defaultFocusedContent": "#ffffff", + "defaultFocusedIcon": "#ffffff", + "defaultHoveredBackground": "#000000", + "defaultHoveredBorder": "#4d4d4d", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#adadad", "defaultIcon": "#ffffff", - "defaultPressedBackground": "#292827", - "defaultPressedBorder": "#979693", - "defaultPressedContent": "#faf9f8", - "defaultPressedIcon": "#faf9f8", - "defaultPressedSecondaryContent": "#797775", - "disabledBackground": "#323130", - "disabledBodyText": "#797775", - "disabledText": "#797775", - "errorText": "#ff5f5f", - "focusBorder": "#a19f9d", - "ghostBackground": "#1b1a19", - "ghostBorder": "#1b1a19", - "ghostCheckedBackground": "#292827", - "ghostCheckedContent": "#ffffff", - "ghostCheckedHoveredBackground": "#252423", - "ghostCheckedHoveredBorder": "#faf9f8", - "ghostCheckedHoveredContent": "#faf9f8", - "ghostContent": "#f3f2f1", - "ghostDisabledBackground": "#1b1a19", - "ghostDisabledBorder": "#1b1a19", - "ghostDisabledContent": "#797775", - "ghostDisabledIcon": "#797775", - "ghostFocusedBackground": "#252423", - "ghostFocusedBorder": "#979693", - "ghostFocusedContent": "#faf9f8", - "ghostFocusedIcon": "#faf9f8", - "ghostFocusedSecondaryContent": "#a19f9d", - "ghostHoveredBackground": "#252423", - "ghostHoveredBorder": "#252423", - "ghostHoveredContent": "#faf9f8", - "ghostHoveredIcon": "#faf9f8", - "ghostHoveredSecondaryContent": "#a19f9d", - "ghostIcon": "#f3f2f1", - "ghostPressedBackground": "#292827", - "ghostPressedBorder": "#292827", - "ghostPressedContent": "#faf9f8", - "ghostPressedIcon": "#faf9f8", - "ghostPressedSecondaryContent": "#a19f9d", - "ghostSecondaryContent": "#a19f9d", - "inputBackground": "#1b1a19", - "inputBorder": "#797775", - "inputFocusBorderAlt": "#2886de", - "inputPlaceholderText": "#a19f9d", - "inputText": "#f3f2f1", - "link": "#2886de", - "linkHovered": "#62abf5", - "linkPressed": "#479ef5", - "listHeaderBackgroundHovered": "#252423", - "listHeaderBackgroundPressed": "#292827", - "menuBackground": "#252423", - "menuDivider": "#484644", - "menuIcon": "#479ef5", - "menuItemBackgroundHovered": "#323130", - "menuItemBackgroundPressed": "#3b3a39", - "menuItemText": "#f3f2f1", - "menuItemTextHovered": "#faf9f8", + "defaultPressedBackground": "#2e2e2e", + "defaultPressedBorder": "#4d4d4d", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#adadad", + "disabledBackground": "#525252", + "disabledBodyText": "#5c5c5c", + "disabledText": "#5c5c5c", + "errorText": "#e37d80", + "focusBorder": "#ffffff", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#383838", + "ghostCheckedContent": "#d6d6d6", + "ghostCheckedHoveredBackground": "#3d3d3d", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#d6d6d6", + "ghostContent": "#ffffff", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#5c5c5c", + "ghostDisabledIcon": "#5c5c5c", + "ghostFocusedBackground": "#3d3d3d", + "ghostFocusedBorder": "#ffffff", + "ghostFocusedContent": "#ffffff", + "ghostFocusedIcon": "#ffffff", + "ghostFocusedSecondaryContent": "#adadad", + "ghostHoveredBackground": "#3d3d3d", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#adadad", + "ghostIcon": "#ffffff", + "ghostPressedBackground": "#1f1f1f", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#adadad", + "ghostSecondaryContent": "#adadad", + "inputBackground": "#000000", + "inputBorder": "#4d4d4d", + "inputFocusBorderAlt": "#479ef5", + "inputPlaceholderText": "#adadad", + "inputText": "#ffffff", + "link": "#479ef5", + "linkHovered": "#479ef5", + "linkPressed": "#96c6fa", + "listHeaderBackgroundHovered": "#000000", + "listHeaderBackgroundPressed": "#2e2e2e", + "menuBackground": "#000000", + "menuDivider": "#3d3d3d", + "menuIcon": "#d6d6d6", + "menuItemBackgroundHovered": "#000000", + "menuItemBackgroundPressed": "#2e2e2e", + "menuItemText": "#ffffff", + "menuItemTextHovered": "#ffffff", "neutralBackground1": "#000000", - "neutralBackground1Hover": undefined, + "neutralBackground1Hover": "#000000", "neutralBackground1Pressed": "#2e2e2e", "neutralBackground1Selected": "#242424", "neutralBackground2": "#1f1f1f", - "neutralBackground2Hover": undefined, + "neutralBackground2Hover": "#1f1f1f", "neutralBackground2Pressed": "#4d4d4d", "neutralBackground2Selected": "#424242", "neutralBackground3": "#292929", - "neutralBackground3Hover": undefined, + "neutralBackground3Hover": "#292929", "neutralBackground3Pressed": "#575757", "neutralBackground3Selected": "#4d4d4d", "neutralBackground4": "#333333", - "neutralBackground4Hover": undefined, + "neutralBackground4Hover": "#333333", "neutralBackground4Pressed": "#616161", "neutralBackground4Selected": "#575757", "neutralBackground5": "#3d3d3d", - "neutralBackground5Hover": undefined, + "neutralBackground5Hover": "#3d3d3d", "neutralBackground5Pressed": "#6b6b6b", "neutralBackground5Selected": "#616161", "neutralBackground6": "#5c5c5c", @@ -164,71 +190,135 @@ exports[`defaultFluentDarkTheme 1`] = ` "neutralBackgroundLightStatic": "#ffffff", "neutralBackgroundLightStaticDisabled": "#adadad", "neutralForeground1": "#ffffff", - "neutralForeground1Hover": undefined, - "neutralForeground1Pressed": undefined, - "neutralForeground1Selected": undefined, + "neutralForeground1Hover": "#ffffff", + "neutralForeground1Pressed": "#ffffff", + "neutralForeground1Selected": "#ffffff", "neutralForeground2": "#d6d6d6", - "neutralForeground2BrandHover": undefined, - "neutralForeground2BrandPressed": undefined, - "neutralForeground2BrandSelected": undefined, - "neutralForeground2Hover": undefined, - "neutralForeground2Pressed": undefined, - "neutralForeground2Selected": undefined, + "neutralForeground2BrandHover": "#d6d6d6", + "neutralForeground2BrandPressed": "#d6d6d6", + "neutralForeground2BrandSelected": "#d6d6d6", + "neutralForeground2Hover": "#d6d6d6", + "neutralForeground2Pressed": "#d6d6d6", + "neutralForeground2Selected": "#d6d6d6", "neutralForeground3": "#adadad", - "neutralForeground3BrandHover": undefined, - "neutralForeground3BrandPressed": undefined, - "neutralForeground3BrandSelected": undefined, - "neutralForeground3Hover": undefined, - "neutralForeground3Pressed": undefined, - "neutralForeground3Selected": undefined, + "neutralForeground3BrandHover": "#adadad", + "neutralForeground3BrandPressed": "#adadad", + "neutralForeground3BrandSelected": "#adadad", + "neutralForeground3Hover": "#adadad", + "neutralForeground3Pressed": "#adadad", + "neutralForeground3Selected": "#adadad", + "neutralForeground4": "#adadad", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#5c5c5c", "neutralForegroundDisabled1": "#5c5c5c", "neutralForegroundDisabled2": "#2e2e2e", "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#ffffff", + "neutralForegroundInvertedLinkHover": "#000000", + "neutralForegroundInvertedLinkPressed": "#000000", + "neutralForegroundInvertedLinkSelected": "#000000", + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#000000", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", "neutralForegroundOnColor": "#000000", "neutralStencil1": "#575757", "neutralStencil2": "#333333", "neutralStroke1": "#4d4d4d", - "neutralStroke1Hover": undefined, - "neutralStroke1Pressed": undefined, - "neutralStroke1Selected": undefined, + "neutralStroke1Hover": "#4d4d4d", + "neutralStroke1Pressed": "#4d4d4d", + "neutralStroke1Selected": "#4d4d4d", "neutralStroke2": "#3d3d3d", + "neutralStroke3": "#3d3d3d", "neutralStrokeAccessible": "#9e9e9e", - "neutralStrokeAccessibleHover": undefined, - "neutralStrokeAccessiblePressed": undefined, - "neutralStrokeAccessibleSelected": undefined, + "neutralStrokeAccessibleHover": "#9e9e9e", + "neutralStrokeAccessiblePressed": "#9e9e9e", + "neutralStrokeAccessibleSelected": "#9e9e9e", "neutralStrokeDisabled": "#424242", "neutralStrokeFocus1": "#000000", "neutralStrokeFocus2": "#ffffff", - "personaActivityGlow": "#2886de", - "personaActivityRing": "#1b1a19", + "outofofficeBackground1": "#3a1136", + "outofofficeBackground2": "#6d2064", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#c239b3", + "outofofficeBorder2": "#d161c4", + "outofofficeBorderActive": "#da7ed0", + "outofofficeForeground1": "#da7ed0", + "outofofficeForeground2": "#edbbe7", + "outofofficeForeground3": "#d161c4", + "personaActivityGlow": "#479ef5", + "personaActivityRing": "#000000", "presenceAvailable": "#3db838", "presenceAway": "#eaa300", "presenceDnd": "#d7494c", "presenceOof": "#d161c4", - "primaryButtonBackground": "#2886de", - "primaryButtonBackgroundDisabled": "#252423", + "primaryButtonBackground": "#479ef5", + "primaryButtonBackgroundDisabled": "#525252", "primaryButtonBackgroundHovered": "#479ef5", - "primaryButtonBackgroundPressed": "#479ef5", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", - "primaryButtonText": "#1b1a19", - "primaryButtonTextDisabled": "#3b3a39", - "primaryButtonTextHovered": "#1b1a19", - "primaryButtonTextPressed": "#1b1a19", + "primaryButtonBackgroundPressed": "#96c6fa", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#ffffff", + "primaryButtonText": "#000000", + "primaryButtonTextDisabled": "#5c5c5c", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#bc2f32", + "redBackground3": "#d13438", + "redBorder1": "#dc5e62", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#e37d80", + "redForeground3": "#e37d80", "severeBackground1": "#411200", "severeBackground2": "#c43501", + "severeBackground3": "#da3b01", + "severeBorder1": "#e36537", + "severeBorder2": "#e9835e", + "severeBorderActive": "#e9835e", "severeForeground1": "#e9835e", "severeForeground2": "#e9835e", - "subText": "#a19f9d", + "severeForeground3": "#e9835e", + "severeStroke1": "#e36537", + "strokeFocus1": "#000000", + "strokeFocus2": "#ffffff", + "subText": "#d6d6d6", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#3d3d3d", + "subtleBackgroundPressed": "#1f1f1f", + "subtleBackgroundSelected": "#383838", "successBackground1": "#052505", "successBackground2": "#0e700e", + "successBackground3": "#107c10", + "successBorder1": "#359b35", + "successBorder2": "#9fd89f", + "successBorderActive": "#54b054", "successForeground1": "#54b054", "successForeground2": "#54b054", - "variantBorder": "#292827", + "successForeground3": "#9fd89f", + "successForegroundInverted": "#107c10", + "successStroke1": "#359b35", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#3d3d3d", "warningBackground1": "#4c4400", "warningBackground2": "#e4cc00", + "warningBackground3": "#fde300", + "warningBorder1": "#c0ad00", + "warningBorder2": "#fdea3d", + "warningBorderActive": "#feee66", "warningForeground1": "#feee66", "warningForeground2": "#feee66", + "warningForeground3": "#fdea3d", + "warningForegroundInverted": "#817400", + "warningStroke1": "#c0ad00", }, "components": {}, "host": { @@ -413,13 +503,13 @@ exports[`defaultFluentDarkTheme 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", - "primary": "Segoe UI", - "sansSerif": "System", - "secondary": "Segoe UI", - "serif": "System", + "cursive": "Roboto", + "monospace": "Roboto", + "numeric": "Roboto", + "primary": "Roboto", + "sansSerif": "Roboto", + "secondary": "Roboto", + "serif": "Roboto", }, "sizes": { "body": 14, @@ -432,139 +522,214 @@ exports[`defaultFluentDarkTheme 1`] = ` }, "variants": { "body1": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "400", }, "body1Strong": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "500", }, "body2": { - "face": "primary", - "size": "body", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "400", }, "body2Strong": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "500", }, "bodySemibold": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "500", }, "bodyStandard": { - "face": "primary", - "size": "body", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "400", }, "caption1": { - "face": "primary", - "size": "caption", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "400", }, "caption1Strong": { - "face": "primary", - "size": "caption", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "500", + }, + "caption2": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 12, + "weight": "400", }, "captionStandard": { - "face": "primary", - "size": "caption", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "400", }, "display": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": -0.5, + "lineHeight": 72, + "size": 60, + "weight": "400", }, "headerSemibold": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "600", }, "headerStandard": { - "face": "primary", - "size": "header", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", }, "heroLargeSemibold": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": -0.5, + "lineHeight": 72, + "size": 60, + "weight": "400", }, "heroLargeStandard": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "face": "Roboto", + "letterSpacing": -0.25, + "lineHeight": 48, + "size": 34, + "weight": "400", }, "heroSemibold": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "600", }, "heroStandard": { - "face": "primary", - "size": "hero", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "400", }, "largeTitle": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "face": "Roboto", + "letterSpacing": -0.25, + "lineHeight": 48, + "size": 34, + "weight": "400", }, "secondarySemibold": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "500", }, "secondaryStandard": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "400", }, "subheaderSemibold": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "600", }, "subheaderStandard": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", }, "subtitle1": { - "face": "primary", - "size": "header", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", }, "subtitle1Strong": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "600", }, "subtitle2": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", }, "subtitle2Strong": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "600", }, "title1": { - "face": "primary", - "size": "hero", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "400", }, "title1Strong": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "600", + }, + "title2": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", + }, + "title3": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", }, }, "weights": { @@ -575,160 +740,186 @@ exports[`defaultFluentDarkTheme 1`] = ` } `; -exports[`defaultFluentHighConstrastTheme 1`] = ` +exports[`defaultFluentTheme 1`] = ` { "colors": { - "accentButtonBackground": "#000000", - "actionLink": "#ffff00", - "background": "#000000", - "bodyDivider": "#ffffff", - "bodyFrameBackground": "#000000", - "bodyFrameDivider": "#000000", - "bodyStandoutBackground": "#000000", - "bodyText": "#ffffff", - "bodyTextChecked": "#000000", + "accentButtonBackground": "#0f6cbd", + "actionLink": "#242424", + "background": "#ffffff", + "bodyDivider": "#e0e0e0", + "bodyFrameBackground": "#ffffff", + "bodyFrameDivider": "#e0e0e0", + "bodyStandoutBackground": "#ffffff", + "bodyText": "#242424", + "bodyTextChecked": "#242424", "brandBackground": "#0f6cbd", "brandBackground2": "#115ea3", "brandBackground2Pressed": "#0c3b5e", "brandBackground2Selected": "#0e4775", "brandBackground3": "#0f548c", "brandBackgroundDisabled": "#b4d6fa", + "brandBackgroundHover": "#0f6cbd", "brandBackgroundInverted": "#ffffff", "brandBackgroundInvertedDisabled": "#ffffff", "brandBackgroundPressed": "#0e4775", "brandBackgroundSelected": "#0f548c", + "brandBackgroundStatic": "#0f6cbd", "brandBackgroundTint": "#cfe4fa", "brandForeground1": "#0f6cbd", + "brandForeground1Disabled": "#2886de", "brandForeground1Pressed": "#0e4775", "brandForeground1Selected": "#0f548c", + "brandForeground2": "#0f6cbd", "brandForegroundDisabled1": "#2886de", "brandForegroundDisabled2": "#b4d6fa", + "brandForegroundLink": "#0f6cbd", + "brandForegroundLinkHover": "#0f6cbd", + "brandForegroundLinkPressed": "#0e4775", + "brandForegroundLinkSelected": "#0f548c", "brandForegroundTint": "#0f548c", "brandStroke1": "#0f6cbd", "brandStroke1Pressed": "#0e4775", "brandStroke1Selected": "#0f548c", - "brandedBackground": "#000000", - "brandedDisabledBorder": "#3ff23f", + "brandStroke2": "#2886de", + "brandStrokeTint": "#2886de", + "brandedBackground": "#0f6cbd", + "brandedDisabledBorder": "#00000000", "brandedFocusedSecondaryContent": "#ffffff", - "brandedHoveredSecondaryContent": "#000000", - "brandedPressedSecondaryContent": "#000000", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", "brandedSecondaryContent": "#ffffff", - "buttonBackground": "#000000", - "buttonBackgroundChecked": "#1aebff", - "buttonBackgroundDisabled": "#000000", - "buttonBackgroundHovered": "#1aebff", - "buttonBackgroundPressed": "#1aebff", - "buttonBorder": "#ffffff", - "buttonBorderDisabled": "#3ff23f", - "buttonBorderFocused": "#ffffff", - "buttonText": "#ffffff", - "buttonTextChecked": "#000000", - "buttonTextDisabled": "#3ff23f", - "buttonTextHovered": "#000000", - "buttonTextPressed": "#000000", - "checkboxBackground": "#000000", - "checkboxBackgroundDisabled": "#000000", - "checkboxBorderColor": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#e0e0e0", + "buttonBackgroundHovered": "#ffffff", + "buttonBackgroundPressed": "#e0e0e0", + "buttonBorder": "#d1d1d1", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#242424", + "buttonTextChecked": "#242424", + "buttonTextDisabled": "#bdbdbd", + "buttonTextHovered": "#242424", + "buttonTextPressed": "#242424", + "checkboxBackground": "#0f6cbd", + "checkboxBackgroundDisabled": "#e0e0e0", + "checkboxBorderColor": "#616161", "checkmarkColor": "#ffffff", + "compoundBrandBackground1": "#0f6cbd", + "compoundBrandBackground1Hover": "#0f6cbd", + "compoundBrandBackground1Pressed": "#0e4775", + "compoundBrandForeground1": "#0f6cbd", + "compoundBrandForeground1Hover": "#0f6cbd", + "compoundBrandForeground1Pressed": "#0e4775", + "compoundBrandStroke1": "#0f6cbd", + "compoundBrandStroke1Hover": "#0f6cbd", + "compoundBrandStroke1Pressed": "#0e4775", "dangerBackground1": "#fdf6f6", "dangerBackground2": "#d13438", + "dangerBackground3": "#d13438", + "dangerBorder1": "#dc5e62", + "dangerBorder2": "#d13438", + "dangerBorderActive": "#d13438", "dangerForeground1": "#bc2f32", "dangerForeground2": "#d13438", - "defaultBackground": "#000000", - "defaultBorder": "#ffffff", - "defaultCheckedBackground": "#1aebff", - "defaultCheckedContent": "#000000", - "defaultCheckedHoveredBackground": "#1aebff", - "defaultCheckedHoveredContent": "#000000", - "defaultContent": "#ffffff", - "defaultDisabledBackground": "#000000", - "defaultDisabledBorder": "#3ff23f", - "defaultDisabledContent": "#3ff23f", - "defaultDisabledIcon": "#3ff23f", - "defaultFocusedBackground": "#000000", - "defaultFocusedBorder": "#ffffff", - "defaultFocusedContent": "#ffffff", - "defaultFocusedIcon": "#ffffff", - "defaultHoveredBackground": "#1aebff", - "defaultHoveredBorder": "#1aebff", - "defaultHoveredContent": "#000000", - "defaultHoveredIcon": "#000000", - "defaultHoveredSecondaryContent": "#000000", - "defaultIcon": "#ffffff", - "defaultPressedBackground": "#1aebff", - "defaultPressedBorder": "#1aebff", - "defaultPressedContent": "#000000", - "defaultPressedIcon": "#000000", - "defaultPressedSecondaryContent": "#000000", - "disabledBackground": "#000000", - "disabledBodyText": "#3ff23f", - "disabledText": "#3ff23f", - "errorText": "#ffffff", - "focusBorder": "#ffffff", - "ghostBackground": "#000000", - "ghostBorder": "#000000", - "ghostCheckedBackground": "#1aebff", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#1aebff", - "ghostCheckedHoveredBorder": "#000000", - "ghostCheckedHoveredContent": "#000000", - "ghostContent": "#ffffff", - "ghostDisabledBackground": "#000000", - "ghostDisabledBorder": "#000000", - "ghostDisabledContent": "#3ff23f", - "ghostDisabledIcon": "#3ff23f", - "ghostFocusedBackground": "#000000", - "ghostFocusedBorder": "#ffffff", - "ghostFocusedContent": "#ffffff", - "ghostFocusedIcon": "#ffffff", - "ghostFocusedSecondaryContent": "#ffffff", - "ghostHoveredBackground": "#1aebff", - "ghostHoveredBorder": "#1aebff", - "ghostHoveredContent": "#000000", - "ghostHoveredIcon": "#000000", - "ghostHoveredSecondaryContent": "#000000", - "ghostIcon": "#ffffff", - "ghostPressedBackground": "#1aebff", - "ghostPressedBorder": "#1aebff", - "ghostPressedContent": "#000000", - "ghostPressedIcon": "#000000", - "ghostPressedSecondaryContent": "#000000", - "ghostSecondaryContent": "#ffffff", - "inputBackground": "#000000", - "inputBorder": "#ffffff", - "inputFocusBorderAlt": "#ffffff", - "inputPlaceholderText": "#ffffff", - "inputText": "#ffffff", - "link": "#ffff00", - "linkHovered": "#ffffff", - "linkPressed": "#ffffff", - "listHeaderBackgroundHovered": "#1aebff", - "listHeaderBackgroundPressed": "#1aebff", - "menuBackground": "#000000", - "menuDivider": "#ffffff", - "menuIcon": "#ffffff", - "menuItemBackgroundHovered": "#1aebff", - "menuItemBackgroundPressed": "#1aebff", - "menuItemText": "#ffffff", - "menuItemTextHovered": "#000000", + "dangerForeground3": "#d13438", + "dangerForegroundInverted": "#dc5e62", + "dangerStroke1": "#dc5e62", + "defaultBackground": "#ffffff", + "defaultBorder": "#d1d1d1", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#242424", + "defaultCheckedHoveredBackground": "#ffffff", + "defaultCheckedHoveredContent": "#242424", + "defaultContent": "#242424", + "defaultDisabledBackground": "#e0e0e0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#bdbdbd", + "defaultDisabledIcon": "#bdbdbd", + "defaultFocusedBackground": "#ffffff", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#242424", + "defaultFocusedIcon": "#242424", + "defaultHoveredBackground": "#ffffff", + "defaultHoveredBorder": "#d1d1d1", + "defaultHoveredContent": "#242424", + "defaultHoveredIcon": "#242424", + "defaultHoveredSecondaryContent": "#808080", + "defaultIcon": "#242424", + "defaultPressedBackground": "#e0e0e0", + "defaultPressedBorder": "#d1d1d1", + "defaultPressedContent": "#242424", + "defaultPressedIcon": "#242424", + "defaultPressedSecondaryContent": "#808080", + "disabledBackground": "#e0e0e0", + "disabledBodyText": "#bdbdbd", + "disabledText": "#bdbdbd", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#616161", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#616161", + "ghostContent": "#242424", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#bdbdbd", + "ghostDisabledIcon": "#bdbdbd", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#242424", + "ghostFocusedIcon": "#242424", + "ghostFocusedSecondaryContent": "#808080", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#242424", + "ghostHoveredIcon": "#242424", + "ghostHoveredSecondaryContent": "#808080", + "ghostIcon": "#242424", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#242424", + "ghostPressedIcon": "#242424", + "ghostPressedSecondaryContent": "#808080", + "ghostSecondaryContent": "#808080", + "inputBackground": "#ffffff", + "inputBorder": "#d1d1d1", + "inputFocusBorderAlt": "#0f6cbd", + "inputPlaceholderText": "#808080", + "inputText": "#242424", + "link": "#0f6cbd", + "linkHovered": "#0f6cbd", + "linkPressed": "#0e4775", + "listHeaderBackgroundHovered": "#ffffff", + "listHeaderBackgroundPressed": "#e0e0e0", + "menuBackground": "#ffffff", + "menuDivider": "#e0e0e0", + "menuIcon": "#616161", + "menuItemBackgroundHovered": "#ffffff", + "menuItemBackgroundPressed": "#e0e0e0", + "menuItemText": "#242424", + "menuItemTextHovered": "#242424", "neutralBackground1": "#ffffff", - "neutralBackground1Hover": undefined, + "neutralBackground1Hover": "#ffffff", "neutralBackground1Pressed": "#e0e0e0", "neutralBackground1Selected": "#ebebeb", "neutralBackground2": "#ffffff", - "neutralBackground2Hover": undefined, + "neutralBackground2Hover": "#ffffff", "neutralBackground2Pressed": "#e0e0e0", "neutralBackground2Selected": "#ebebeb", "neutralBackground3": "#ffffff", - "neutralBackground3Hover": undefined, + "neutralBackground3Hover": "#ffffff", "neutralBackground3Pressed": "#e0e0e0", "neutralBackground3Selected": "#ebebeb", "neutralBackground4": "#fafafa", - "neutralBackground4Hover": undefined, + "neutralBackground4Hover": "#fafafa", "neutralBackground4Pressed": "#dbdbdb", "neutralBackground4Selected": "#e6e6e6", "neutralBackground5": "#f0f0f0", - "neutralBackground5Hover": undefined, + "neutralBackground5Hover": "#f0f0f0", "neutralBackground5Pressed": "#d1d1d1", "neutralBackground5Selected": "#dbdbdb", "neutralBackground6": "#d1d1d1", @@ -739,71 +930,875 @@ exports[`defaultFluentHighConstrastTheme 1`] = ` "neutralBackgroundLightStatic": "#ffffff", "neutralBackgroundLightStaticDisabled": "#ffffff", "neutralForeground1": "#242424", - "neutralForeground1Hover": undefined, - "neutralForeground1Pressed": undefined, - "neutralForeground1Selected": undefined, + "neutralForeground1Hover": "#242424", + "neutralForeground1Pressed": "#242424", + "neutralForeground1Selected": "#242424", "neutralForeground2": "#616161", - "neutralForeground2BrandHover": undefined, - "neutralForeground2BrandPressed": undefined, - "neutralForeground2BrandSelected": undefined, - "neutralForeground2Hover": undefined, - "neutralForeground2Pressed": undefined, - "neutralForeground2Selected": undefined, + "neutralForeground2BrandHover": "#616161", + "neutralForeground2BrandPressed": "#616161", + "neutralForeground2BrandSelected": "#616161", + "neutralForeground2Hover": "#616161", + "neutralForeground2Pressed": "#616161", + "neutralForeground2Selected": "#616161", "neutralForeground3": "#808080", - "neutralForeground3BrandHover": undefined, - "neutralForeground3BrandPressed": undefined, - "neutralForeground3BrandSelected": undefined, - "neutralForeground3Hover": undefined, - "neutralForeground3Pressed": undefined, - "neutralForeground3Selected": undefined, + "neutralForeground3BrandHover": "#808080", + "neutralForeground3BrandPressed": "#808080", + "neutralForeground3BrandSelected": "#808080", + "neutralForeground3Hover": "#808080", + "neutralForeground3Pressed": "#808080", + "neutralForeground3Selected": "#808080", + "neutralForeground4": "#808080", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#bdbdbd", "neutralForegroundDisabled1": "#bdbdbd", "neutralForegroundDisabled2": "#ffffff", "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#ffffff", + "neutralForegroundInvertedLinkHover": "#ffffff", + "neutralForegroundInvertedLinkPressed": "#ffffff", + "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#ffffff", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#e6e6e6", "neutralStencil2": "#fafafa", "neutralStroke1": "#d1d1d1", - "neutralStroke1Hover": undefined, - "neutralStroke1Pressed": undefined, - "neutralStroke1Selected": undefined, + "neutralStroke1Hover": "#d1d1d1", + "neutralStroke1Pressed": "#d1d1d1", + "neutralStroke1Selected": "#d1d1d1", "neutralStroke2": "#e0e0e0", + "neutralStroke3": "#e0e0e0", "neutralStrokeAccessible": "#616161", - "neutralStrokeAccessibleHover": undefined, - "neutralStrokeAccessiblePressed": undefined, - "neutralStrokeAccessibleSelected": undefined, + "neutralStrokeAccessibleHover": "#616161", + "neutralStrokeAccessiblePressed": "#616161", + "neutralStrokeAccessibleSelected": "#616161", "neutralStrokeDisabled": "#e0e0e0", "neutralStrokeFocus1": "#ffffff", "neutralStrokeFocus2": "#000000", - "personaActivityGlow": "transparent", + "outofofficeBackground1": "#fdf5fc", + "outofofficeBackground2": "#edbbe7", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#edbbe7", + "outofofficeBorder2": "#c239b3", + "outofofficeBorderActive": "#c239b3", + "outofofficeForeground1": "#af33a1", + "outofofficeForeground2": "#6d2064", + "outofofficeForeground3": "#c239b3", + "personaActivityGlow": "#0f6cbd", "personaActivityRing": "#ffffff", "presenceAvailable": "#13a10e", "presenceAway": "#eaa300", "presenceDnd": "#d13438", "presenceOof": "#c239b3", - "primaryButtonBackground": "#000000", - "primaryButtonBackgroundDisabled": "#000000", - "primaryButtonBackgroundHovered": "#1aebff", - "primaryButtonBackgroundPressed": "#1aebff", - "primaryButtonBorder": "#ffffff", - "primaryButtonBorderFocused": "#ffffff", + "primaryButtonBackground": "#0f6cbd", + "primaryButtonBackgroundDisabled": "#e0e0e0", + "primaryButtonBackgroundHovered": "#0f6cbd", + "primaryButtonBackgroundPressed": "#0e4775", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#000000", "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#3ff23f", - "primaryButtonTextHovered": "#000000", - "primaryButtonTextPressed": "#000000", + "primaryButtonTextDisabled": "#bdbdbd", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#d13438", + "redBackground3": "#d13438", + "redBorder1": "#dc5e62", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#d13438", + "redForeground3": "#d13438", "severeBackground1": "#fdf6f3", "severeBackground2": "#da3b01", + "severeBackground3": "#da3b01", + "severeBorder1": "#de501c", + "severeBorder2": "#da3b01", + "severeBorderActive": "#da3b01", "severeForeground1": "#c43501", "severeForeground2": "#c43501", - "subText": "#ffffff", + "severeForeground3": "#da3b01", + "severeStroke1": "#de501c", + "strokeFocus1": "#ffffff", + "strokeFocus2": "#000000", + "subText": "#616161", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#f5f5f5", + "subtleBackgroundPressed": "#e0e0e0", + "subtleBackgroundSelected": "#ebebeb", "successBackground1": "#f1faf1", "successBackground2": "#107c10", + "successBackground3": "#107c10", + "successBorder1": "#359b35", + "successBorder2": "#107c10", + "successBorderActive": "#107c10", "successForeground1": "#0e700e", "successForeground2": "#107c10", - "variantBorder": "#ffffff", + "successForeground3": "#107c10", + "successForegroundInverted": "#359b35", + "successStroke1": "#359b35", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#e0e0e0", "warningBackground1": "#fffef5", "warningBackground2": "#fde300", + "warningBackground3": "#fde300", + "warningBorder1": "#817400", + "warningBorder2": "#fde300", + "warningBorderActive": "#fde300", "warningForeground1": "#817400", "warningForeground2": "#817400", + "warningForeground3": "#fde300", + "warningForegroundInverted": "#fef7b2", + "warningStroke1": "#817400", + }, + "components": {}, + "host": { + "appearance": "light", + }, + "shadows": { + "shadow16": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000024", + "x": 0, + "y": 8, + }, + }, + "shadow16brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000040", + "x": 0, + "y": 8, + }, + }, + "shadow2": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000024", + "x": 0, + "y": 1, + }, + }, + "shadow28": { + "ambient": { + "blur": 8, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#00000024", + "x": 0, + "y": 14, + }, + }, + "shadow28brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#00000040", + "x": 0, + "y": 14, + }, + }, + "shadow2brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000040", + "x": 0, + "y": 1, + }, + }, + "shadow4": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000024", + "x": 0, + "y": 2, + }, + }, + "shadow4brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000040", + "x": 0, + "y": 2, + }, + }, + "shadow64": { + "ambient": { + "blur": 8, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#00000024", + "x": 0, + "y": 32, + }, + }, + "shadow64brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#00000040", + "x": 0, + "y": 32, + }, + }, + "shadow8": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000024", + "x": 0, + "y": 4, + }, + }, + "shadow8brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000040", + "x": 0, + "y": 4, + }, + }, + }, + "spacing": { + "l1": "20px", + "l2": "32px", + "m": "16px", + "s1": "8px", + "s2": "4px", + }, + "typography": { + "families": { + "cursive": "Roboto", + "monospace": "Roboto", + "numeric": "Roboto", + "primary": "Roboto", + "sansSerif": "Roboto", + "secondary": "Roboto", + "serif": "Roboto", + }, + "sizes": { + "body": 14, + "caption": 12, + "header": 18, + "hero": 24, + "heroLarge": 60, + "secondary": 13, + "subheader": 16, + }, + "variants": { + "body1": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "400", + }, + "body1Strong": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "500", + }, + "body2": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "400", + }, + "body2Strong": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "500", + }, + "bodySemibold": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "500", + }, + "bodyStandard": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "400", + }, + "caption1": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "400", + }, + "caption1Strong": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "500", + }, + "caption2": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 12, + "weight": "400", + }, + "captionStandard": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "400", + }, + "display": { + "face": "Roboto", + "letterSpacing": -0.5, + "lineHeight": 72, + "size": 60, + "weight": "400", + }, + "headerSemibold": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "600", + }, + "headerStandard": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", + }, + "heroLargeSemibold": { + "face": "Roboto", + "letterSpacing": -0.5, + "lineHeight": 72, + "size": 60, + "weight": "400", + }, + "heroLargeStandard": { + "face": "Roboto", + "letterSpacing": -0.25, + "lineHeight": 48, + "size": 34, + "weight": "400", + }, + "heroSemibold": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "600", + }, + "heroStandard": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "400", + }, + "largeTitle": { + "face": "Roboto", + "letterSpacing": -0.25, + "lineHeight": 48, + "size": 34, + "weight": "400", + }, + "secondarySemibold": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "500", + }, + "secondaryStandard": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "400", + }, + "subheaderSemibold": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "600", + }, + "subheaderStandard": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", + }, + "subtitle1": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", + }, + "subtitle1Strong": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "600", + }, + "subtitle2": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", + }, + "subtitle2Strong": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "600", + }, + "title1": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "400", + }, + "title1Strong": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "600", + }, + "title2": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", + }, + "title3": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", + }, + }, + "weights": { + "regular": "400", + "semiBold": "600", + }, + }, +} +`; + +exports[`high contrast dark theme 1`] = ` +{ + "colors": { + "accentButtonBackground": "#479ef5", + "actionLink": "#ffffff", + "background": "#000000", + "bodyDivider": "#3d3d3d", + "bodyFrameBackground": "#000000", + "bodyFrameDivider": "#3d3d3d", + "bodyStandoutBackground": "#1f1f1f", + "bodyText": "#ffffff", + "bodyTextChecked": "#ffffff", + "brandBackground": "#479ef5", + "brandBackground2": "#479ef5", + "brandBackground2Pressed": "#96c6fa", + "brandBackground2Selected": "#77b7f7", + "brandBackground3": "#479ef5", + "brandBackgroundDisabled": "#0c3b5e", + "brandBackgroundHover": "#479ef5", + "brandBackgroundInverted": "#ffffff", + "brandBackgroundInvertedDisabled": "#adadad", + "brandBackgroundPressed": "#96c6fa", + "brandBackgroundSelected": "#77b7f7", + "brandBackgroundStatic": "#479ef5", + "brandBackgroundTint": "#0c3b5e", + "brandForeground1": "#479ef5", + "brandForeground1Disabled": "#2886de", + "brandForeground1Pressed": "#96c6fa", + "brandForeground1Selected": "#77b7f7", + "brandForeground2": "#479ef5", + "brandForegroundDisabled1": "#2886de", + "brandForegroundDisabled2": "#0c3b5e", + "brandForegroundLink": "#479ef5", + "brandForegroundLinkHover": "#479ef5", + "brandForegroundLinkPressed": "#96c6fa", + "brandForegroundLinkSelected": "#77b7f7", + "brandForegroundTint": "#96c6fa", + "brandStroke1": "#479ef5", + "brandStroke1Pressed": "#96c6fa", + "brandStroke1Selected": "#77b7f7", + "brandStroke2": "#479ef5", + "brandStrokeTint": "#479ef5", + "brandedBackground": "#479ef5", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#000000", + "buttonBackground": "#000000", + "buttonBackgroundChecked": "#242424", + "buttonBackgroundDisabled": "#525252", + "buttonBackgroundHovered": "#000000", + "buttonBackgroundPressed": "#2e2e2e", + "buttonBorder": "#4d4d4d", + "buttonBorderDisabled": "#424242", + "buttonBorderFocused": "#ffffff", + "buttonText": "#ffffff", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#5c5c5c", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#479ef5", + "checkboxBackgroundDisabled": "#525252", + "checkboxBorderColor": "#9e9e9e", + "checkmarkColor": "#000000", + "compoundBrandBackground1": "#479ef5", + "compoundBrandBackground1Hover": "#479ef5", + "compoundBrandBackground1Pressed": "#96c6fa", + "compoundBrandForeground1": "#479ef5", + "compoundBrandForeground1Hover": "#479ef5", + "compoundBrandForeground1Pressed": "#96c6fa", + "compoundBrandStroke1": "#479ef5", + "compoundBrandStroke1Hover": "#479ef5", + "compoundBrandStroke1Pressed": "#96c6fa", + "dangerBackground1": "#3f1011", + "dangerBackground2": "#bc2f32", + "dangerBackground3": "#d13438", + "dangerBorder1": "#dc5e62", + "dangerBorder2": "#dc5e62", + "dangerBorderActive": "#e37d80", + "dangerForeground1": "#e37d80", + "dangerForeground2": "#e37d80", + "dangerForeground3": "#e37d80", + "dangerForegroundInverted": "#d13438", + "dangerStroke1": "#dc5e62", + "defaultBackground": "#000000", + "defaultBorder": "#4d4d4d", + "defaultCheckedBackground": "#242424", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#000000", + "defaultCheckedHoveredContent": "#ffffff", + "defaultContent": "#ffffff", + "defaultDisabledBackground": "#525252", + "defaultDisabledBorder": "#424242", + "defaultDisabledContent": "#5c5c5c", + "defaultDisabledIcon": "#5c5c5c", + "defaultFocusedBackground": "#000000", + "defaultFocusedBorder": "#ffffff", + "defaultFocusedContent": "#ffffff", + "defaultFocusedIcon": "#ffffff", + "defaultHoveredBackground": "#000000", + "defaultHoveredBorder": "#4d4d4d", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#adadad", + "defaultIcon": "#ffffff", + "defaultPressedBackground": "#2e2e2e", + "defaultPressedBorder": "#4d4d4d", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#adadad", + "disabledBackground": "#525252", + "disabledBodyText": "#5c5c5c", + "disabledText": "#5c5c5c", + "errorText": "#e37d80", + "focusBorder": "#ffffff", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#383838", + "ghostCheckedContent": "#d6d6d6", + "ghostCheckedHoveredBackground": "#3d3d3d", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#d6d6d6", + "ghostContent": "#ffffff", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#5c5c5c", + "ghostDisabledIcon": "#5c5c5c", + "ghostFocusedBackground": "#3d3d3d", + "ghostFocusedBorder": "#ffffff", + "ghostFocusedContent": "#ffffff", + "ghostFocusedIcon": "#ffffff", + "ghostFocusedSecondaryContent": "#adadad", + "ghostHoveredBackground": "#3d3d3d", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#adadad", + "ghostIcon": "#ffffff", + "ghostPressedBackground": "#1f1f1f", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#adadad", + "ghostSecondaryContent": "#adadad", + "inputBackground": "#000000", + "inputBorder": "#4d4d4d", + "inputFocusBorderAlt": "#479ef5", + "inputPlaceholderText": "#adadad", + "inputText": "#ffffff", + "link": "#479ef5", + "linkHovered": "#479ef5", + "linkPressed": "#96c6fa", + "listHeaderBackgroundHovered": "#000000", + "listHeaderBackgroundPressed": "#2e2e2e", + "menuBackground": "#000000", + "menuDivider": "#3d3d3d", + "menuIcon": "#d6d6d6", + "menuItemBackgroundHovered": "#000000", + "menuItemBackgroundPressed": "#2e2e2e", + "menuItemText": "#ffffff", + "menuItemTextHovered": "#ffffff", + "neutralBackground1": "#000000", + "neutralBackground1Hover": "#000000", + "neutralBackground1Pressed": "#2e2e2e", + "neutralBackground1Selected": "#242424", + "neutralBackground2": "#1f1f1f", + "neutralBackground2Hover": "#1f1f1f", + "neutralBackground2Pressed": "#4d4d4d", + "neutralBackground2Selected": "#424242", + "neutralBackground3": "#292929", + "neutralBackground3Hover": "#292929", + "neutralBackground3Pressed": "#575757", + "neutralBackground3Selected": "#4d4d4d", + "neutralBackground4": "#333333", + "neutralBackground4Hover": "#333333", + "neutralBackground4Pressed": "#616161", + "neutralBackground4Selected": "#575757", + "neutralBackground5": "#3d3d3d", + "neutralBackground5Hover": "#3d3d3d", + "neutralBackground5Pressed": "#6b6b6b", + "neutralBackground5Selected": "#616161", + "neutralBackground6": "#5c5c5c", + "neutralBackgroundCanvas": "#141414", + "neutralBackgroundDarkStatic": "#3d3d3d", + "neutralBackgroundDisabled": "#525252", + "neutralBackgroundInverted": "#b8b8b8", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#adadad", + "neutralForeground1": "#ffffff", + "neutralForeground1Hover": "#ffffff", + "neutralForeground1Pressed": "#ffffff", + "neutralForeground1Selected": "#ffffff", + "neutralForeground2": "#d6d6d6", + "neutralForeground2BrandHover": "#d6d6d6", + "neutralForeground2BrandPressed": "#d6d6d6", + "neutralForeground2BrandSelected": "#d6d6d6", + "neutralForeground2Hover": "#d6d6d6", + "neutralForeground2Pressed": "#d6d6d6", + "neutralForeground2Selected": "#d6d6d6", + "neutralForeground3": "#adadad", + "neutralForeground3BrandHover": "#adadad", + "neutralForeground3BrandPressed": "#adadad", + "neutralForeground3BrandSelected": "#adadad", + "neutralForeground3Hover": "#adadad", + "neutralForeground3Pressed": "#adadad", + "neutralForeground3Selected": "#adadad", + "neutralForeground4": "#adadad", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#5c5c5c", + "neutralForegroundDisabled1": "#5c5c5c", + "neutralForegroundDisabled2": "#2e2e2e", + "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#ffffff", + "neutralForegroundInvertedLinkHover": "#000000", + "neutralForegroundInvertedLinkPressed": "#000000", + "neutralForegroundInvertedLinkSelected": "#000000", + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#000000", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#000000", + "neutralStencil1": "#575757", + "neutralStencil2": "#333333", + "neutralStroke1": "#4d4d4d", + "neutralStroke1Hover": "#4d4d4d", + "neutralStroke1Pressed": "#4d4d4d", + "neutralStroke1Selected": "#4d4d4d", + "neutralStroke2": "#3d3d3d", + "neutralStroke3": "#3d3d3d", + "neutralStrokeAccessible": "#9e9e9e", + "neutralStrokeAccessibleHover": "#9e9e9e", + "neutralStrokeAccessiblePressed": "#9e9e9e", + "neutralStrokeAccessibleSelected": "#9e9e9e", + "neutralStrokeDisabled": "#424242", + "neutralStrokeFocus1": "#000000", + "neutralStrokeFocus2": "#ffffff", + "outofofficeBackground1": "#3a1136", + "outofofficeBackground2": "#6d2064", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#c239b3", + "outofofficeBorder2": "#d161c4", + "outofofficeBorderActive": "#da7ed0", + "outofofficeForeground1": "#da7ed0", + "outofofficeForeground2": "#edbbe7", + "outofofficeForeground3": "#d161c4", + "personaActivityGlow": "#479ef5", + "personaActivityRing": "#000000", + "presenceAvailable": "#3db838", + "presenceAway": "#eaa300", + "presenceDnd": "#d7494c", + "presenceOof": "#d161c4", + "primaryButtonBackground": "#479ef5", + "primaryButtonBackgroundDisabled": "#525252", + "primaryButtonBackgroundHovered": "#479ef5", + "primaryButtonBackgroundPressed": "#96c6fa", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#ffffff", + "primaryButtonText": "#000000", + "primaryButtonTextDisabled": "#5c5c5c", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#bc2f32", + "redBackground3": "#d13438", + "redBorder1": "#dc5e62", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#e37d80", + "redForeground3": "#e37d80", + "severeBackground1": "#411200", + "severeBackground2": "#c43501", + "severeBackground3": "#da3b01", + "severeBorder1": "#e36537", + "severeBorder2": "#e9835e", + "severeBorderActive": "#e9835e", + "severeForeground1": "#e9835e", + "severeForeground2": "#e9835e", + "severeForeground3": "#e9835e", + "severeStroke1": "#e36537", + "strokeFocus1": "#000000", + "strokeFocus2": "#ffffff", + "subText": "#d6d6d6", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#3d3d3d", + "subtleBackgroundPressed": "#1f1f1f", + "subtleBackgroundSelected": "#383838", + "successBackground1": "#052505", + "successBackground2": "#0e700e", + "successBackground3": "#107c10", + "successBorder1": "#359b35", + "successBorder2": "#9fd89f", + "successBorderActive": "#54b054", + "successForeground1": "#54b054", + "successForeground2": "#54b054", + "successForeground3": "#9fd89f", + "successForegroundInverted": "#107c10", + "successStroke1": "#359b35", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#3d3d3d", + "warningBackground1": "#4c4400", + "warningBackground2": "#e4cc00", + "warningBackground3": "#fde300", + "warningBorder1": "#c0ad00", + "warningBorder2": "#fdea3d", + "warningBorderActive": "#feee66", + "warningForeground1": "#feee66", + "warningForeground2": "#feee66", + "warningForeground3": "#fdea3d", + "warningForegroundInverted": "#817400", + "warningStroke1": "#c0ad00", }, "components": {}, "host": { @@ -988,13 +1983,13 @@ exports[`defaultFluentHighConstrastTheme 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", - "primary": "Segoe UI", - "sansSerif": "System", - "secondary": "Segoe UI", - "serif": "System", + "cursive": "Roboto", + "monospace": "Roboto", + "numeric": "Roboto", + "primary": "Roboto", + "sansSerif": "Roboto", + "secondary": "Roboto", + "serif": "Roboto", }, "sizes": { "body": 14, @@ -1007,139 +2002,214 @@ exports[`defaultFluentHighConstrastTheme 1`] = ` }, "variants": { "body1": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "400", }, "body1Strong": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "500", }, "body2": { - "face": "primary", - "size": "body", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "400", }, "body2Strong": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "500", }, "bodySemibold": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "500", }, "bodyStandard": { - "face": "primary", - "size": "body", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "400", }, "caption1": { - "face": "primary", - "size": "caption", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "400", }, "caption1Strong": { - "face": "primary", - "size": "caption", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "500", + }, + "caption2": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 12, + "weight": "400", }, "captionStandard": { - "face": "primary", - "size": "caption", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "400", }, "display": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": -0.5, + "lineHeight": 72, + "size": 60, + "weight": "400", }, "headerSemibold": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "600", }, "headerStandard": { - "face": "primary", - "size": "header", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", }, "heroLargeSemibold": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": -0.5, + "lineHeight": 72, + "size": 60, + "weight": "400", }, "heroLargeStandard": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "face": "Roboto", + "letterSpacing": -0.25, + "lineHeight": 48, + "size": 34, + "weight": "400", }, "heroSemibold": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "600", }, "heroStandard": { - "face": "primary", - "size": "hero", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "400", }, "largeTitle": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "face": "Roboto", + "letterSpacing": -0.25, + "lineHeight": 48, + "size": 34, + "weight": "400", }, "secondarySemibold": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "500", }, "secondaryStandard": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "400", }, "subheaderSemibold": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "600", }, "subheaderStandard": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", }, "subtitle1": { - "face": "primary", - "size": "header", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", }, "subtitle1Strong": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "600", }, "subtitle2": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", }, "subtitle2Strong": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "600", }, "title1": { - "face": "primary", - "size": "hero", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "400", }, "title1Strong": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "600", + }, + "title2": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", + }, + "title3": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", }, }, "weights": { @@ -1150,160 +2220,186 @@ exports[`defaultFluentHighConstrastTheme 1`] = ` } `; -exports[`defaultFluentTheme 1`] = ` +exports[`high contrast light theme 1`] = ` { "colors": { "accentButtonBackground": "#0f6cbd", - "actionLink": "#323130", + "actionLink": "#242424", "background": "#ffffff", - "bodyDivider": "#edebe9", + "bodyDivider": "#e0e0e0", "bodyFrameBackground": "#ffffff", - "bodyFrameDivider": "#edebe9", - "bodyStandoutBackground": "#faf9f8", - "bodyText": "#323130", - "bodyTextChecked": "#000000", + "bodyFrameDivider": "#e0e0e0", + "bodyStandoutBackground": "#ffffff", + "bodyText": "#242424", + "bodyTextChecked": "#242424", "brandBackground": "#0f6cbd", "brandBackground2": "#115ea3", "brandBackground2Pressed": "#0c3b5e", "brandBackground2Selected": "#0e4775", "brandBackground3": "#0f548c", "brandBackgroundDisabled": "#b4d6fa", + "brandBackgroundHover": "#0f6cbd", "brandBackgroundInverted": "#ffffff", "brandBackgroundInvertedDisabled": "#ffffff", "brandBackgroundPressed": "#0e4775", "brandBackgroundSelected": "#0f548c", + "brandBackgroundStatic": "#0f6cbd", "brandBackgroundTint": "#cfe4fa", "brandForeground1": "#0f6cbd", + "brandForeground1Disabled": "#2886de", "brandForeground1Pressed": "#0e4775", "brandForeground1Selected": "#0f548c", + "brandForeground2": "#0f6cbd", "brandForegroundDisabled1": "#2886de", "brandForegroundDisabled2": "#b4d6fa", + "brandForegroundLink": "#0f6cbd", + "brandForegroundLinkHover": "#0f6cbd", + "brandForegroundLinkPressed": "#0e4775", + "brandForegroundLinkSelected": "#0f548c", "brandForegroundTint": "#0f548c", "brandStroke1": "#0f6cbd", "brandStroke1Pressed": "#0e4775", "brandStroke1Selected": "#0f548c", + "brandStroke2": "#2886de", + "brandStrokeTint": "#2886de", "brandedBackground": "#0f6cbd", - "brandedDisabledBorder": "#f3f2f1", - "brandedFocusedSecondaryContent": "#faf9f8", - "brandedHoveredSecondaryContent": "#faf9f8", - "brandedPressedSecondaryContent": "#faf9f8", - "brandedSecondaryContent": "#faf9f8", - "buttonBackground": "#f3f2f1", - "buttonBackgroundChecked": "#c8c6c4", - "buttonBackgroundDisabled": "#f3f2f1", - "buttonBackgroundHovered": "#edebe9", - "buttonBackgroundPressed": "#edebe9", - "buttonBorder": "#8a8886", - "buttonBorderDisabled": "#f3f2f1", - "buttonBorderFocused": "#8a8886", - "buttonText": "#323130", - "buttonTextChecked": "#201f1e", - "buttonTextDisabled": "#a19f9d", - "buttonTextHovered": "#201f1e", - "buttonTextPressed": "#201f1e", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#e0e0e0", + "buttonBackgroundHovered": "#ffffff", + "buttonBackgroundPressed": "#e0e0e0", + "buttonBorder": "#d1d1d1", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#242424", + "buttonTextChecked": "#242424", + "buttonTextDisabled": "#bdbdbd", + "buttonTextHovered": "#242424", + "buttonTextPressed": "#242424", "checkboxBackground": "#0f6cbd", - "checkboxBackgroundDisabled": "#f3f2f1", - "checkboxBorderColor": "#8a8886", + "checkboxBackgroundDisabled": "#e0e0e0", + "checkboxBorderColor": "#616161", "checkmarkColor": "#ffffff", + "compoundBrandBackground1": "#0f6cbd", + "compoundBrandBackground1Hover": "#0f6cbd", + "compoundBrandBackground1Pressed": "#0e4775", + "compoundBrandForeground1": "#0f6cbd", + "compoundBrandForeground1Hover": "#0f6cbd", + "compoundBrandForeground1Pressed": "#0e4775", + "compoundBrandStroke1": "#0f6cbd", + "compoundBrandStroke1Hover": "#0f6cbd", + "compoundBrandStroke1Pressed": "#0e4775", "dangerBackground1": "#fdf6f6", "dangerBackground2": "#d13438", + "dangerBackground3": "#d13438", + "dangerBorder1": "#dc5e62", + "dangerBorder2": "#d13438", + "dangerBorderActive": "#d13438", "dangerForeground1": "#bc2f32", "dangerForeground2": "#d13438", - "defaultBackground": "#f3f2f1", - "defaultBorder": "#8a8886", - "defaultCheckedBackground": "#c8c6c4", - "defaultCheckedContent": "#201f1e", - "defaultCheckedHoveredBackground": "#edebe9", - "defaultCheckedHoveredContent": "#201f1e", - "defaultContent": "#323130", - "defaultDisabledBackground": "#f3f2f1", - "defaultDisabledBorder": "#f3f2f1", - "defaultDisabledContent": "#a19f9d", - "defaultDisabledIcon": "#a19f9d", - "defaultFocusedBackground": "#edebe9", - "defaultFocusedBorder": "#8a8886", - "defaultFocusedContent": "#201f1e", - "defaultFocusedIcon": "#201f1e", - "defaultHoveredBackground": "#edebe9", - "defaultHoveredBorder": "#8a8886", - "defaultHoveredContent": "#201f1e", - "defaultHoveredIcon": "#201f1e", - "defaultHoveredSecondaryContent": "#a19f9d", - "defaultIcon": "#323130", - "defaultPressedBackground": "#edebe9", - "defaultPressedBorder": "#8a8886", - "defaultPressedContent": "#201f1e", - "defaultPressedIcon": "#201f1e", - "defaultPressedSecondaryContent": "#a19f9d", - "disabledBackground": "#f3f2f1", - "disabledBodyText": "#a19f9d", - "disabledText": "#a19f9d", - "errorText": "#a4262c", - "focusBorder": "#605e5c", - "ghostBackground": "#ffffff", - "ghostBorder": "#ffffff", - "ghostCheckedBackground": "#edebe9", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#f3f2f1", - "ghostCheckedHoveredBorder": "#201f1e", - "ghostCheckedHoveredContent": "#201f1e", - "ghostContent": "#323130", - "ghostDisabledBackground": "#ffffff", - "ghostDisabledBorder": "#ffffff", - "ghostDisabledContent": "#a19f9d", - "ghostDisabledIcon": "#a19f9d", - "ghostFocusedBackground": "#f3f2f1", - "ghostFocusedBorder": "#8a8886", - "ghostFocusedContent": "#201f1e", - "ghostFocusedIcon": "#201f1e", - "ghostFocusedSecondaryContent": "#605e5c", - "ghostHoveredBackground": "#f3f2f1", - "ghostHoveredBorder": "#f3f2f1", - "ghostHoveredContent": "#201f1e", - "ghostHoveredIcon": "#201f1e", - "ghostHoveredSecondaryContent": "#605e5c", - "ghostIcon": "#323130", - "ghostPressedBackground": "#edebe9", - "ghostPressedBorder": "#edebe9", - "ghostPressedContent": "#201f1e", - "ghostPressedIcon": "#201f1e", - "ghostPressedSecondaryContent": "#605e5c", - "ghostSecondaryContent": "#605e5c", + "dangerForeground3": "#d13438", + "dangerForegroundInverted": "#dc5e62", + "dangerStroke1": "#dc5e62", + "defaultBackground": "#ffffff", + "defaultBorder": "#d1d1d1", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#242424", + "defaultCheckedHoveredBackground": "#ffffff", + "defaultCheckedHoveredContent": "#242424", + "defaultContent": "#242424", + "defaultDisabledBackground": "#e0e0e0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#bdbdbd", + "defaultDisabledIcon": "#bdbdbd", + "defaultFocusedBackground": "#ffffff", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#242424", + "defaultFocusedIcon": "#242424", + "defaultHoveredBackground": "#ffffff", + "defaultHoveredBorder": "#d1d1d1", + "defaultHoveredContent": "#242424", + "defaultHoveredIcon": "#242424", + "defaultHoveredSecondaryContent": "#808080", + "defaultIcon": "#242424", + "defaultPressedBackground": "#e0e0e0", + "defaultPressedBorder": "#d1d1d1", + "defaultPressedContent": "#242424", + "defaultPressedIcon": "#242424", + "defaultPressedSecondaryContent": "#808080", + "disabledBackground": "#e0e0e0", + "disabledBodyText": "#bdbdbd", + "disabledText": "#bdbdbd", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#616161", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#616161", + "ghostContent": "#242424", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#bdbdbd", + "ghostDisabledIcon": "#bdbdbd", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#242424", + "ghostFocusedIcon": "#242424", + "ghostFocusedSecondaryContent": "#808080", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#242424", + "ghostHoveredIcon": "#242424", + "ghostHoveredSecondaryContent": "#808080", + "ghostIcon": "#242424", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#242424", + "ghostPressedIcon": "#242424", + "ghostPressedSecondaryContent": "#808080", + "ghostSecondaryContent": "#808080", "inputBackground": "#ffffff", - "inputBorder": "#a19f9d", + "inputBorder": "#d1d1d1", "inputFocusBorderAlt": "#0f6cbd", - "inputPlaceholderText": "#605e5c", - "inputText": "#323130", + "inputPlaceholderText": "#808080", + "inputText": "#242424", "link": "#0f6cbd", - "linkHovered": "#0c3b5e", - "linkPressed": "#0f548c", - "listHeaderBackgroundHovered": "#f3f2f1", - "listHeaderBackgroundPressed": "#edebe9", + "linkHovered": "#0f6cbd", + "linkPressed": "#0e4775", + "listHeaderBackgroundHovered": "#ffffff", + "listHeaderBackgroundPressed": "#e0e0e0", "menuBackground": "#ffffff", - "menuDivider": "#c8c6c4", - "menuIcon": "#0f6cbd", - "menuItemBackgroundHovered": "#f3f2f1", - "menuItemBackgroundPressed": "#edebe9", - "menuItemText": "#323130", - "menuItemTextHovered": "#201f1e", + "menuDivider": "#e0e0e0", + "menuIcon": "#616161", + "menuItemBackgroundHovered": "#ffffff", + "menuItemBackgroundPressed": "#e0e0e0", + "menuItemText": "#242424", + "menuItemTextHovered": "#242424", "neutralBackground1": "#ffffff", - "neutralBackground1Hover": undefined, + "neutralBackground1Hover": "#ffffff", "neutralBackground1Pressed": "#e0e0e0", "neutralBackground1Selected": "#ebebeb", "neutralBackground2": "#ffffff", - "neutralBackground2Hover": undefined, + "neutralBackground2Hover": "#ffffff", "neutralBackground2Pressed": "#e0e0e0", "neutralBackground2Selected": "#ebebeb", "neutralBackground3": "#ffffff", - "neutralBackground3Hover": undefined, + "neutralBackground3Hover": "#ffffff", "neutralBackground3Pressed": "#e0e0e0", "neutralBackground3Selected": "#ebebeb", "neutralBackground4": "#fafafa", - "neutralBackground4Hover": undefined, + "neutralBackground4Hover": "#fafafa", "neutralBackground4Pressed": "#dbdbdb", "neutralBackground4Selected": "#e6e6e6", "neutralBackground5": "#f0f0f0", - "neutralBackground5Hover": undefined, + "neutralBackground5Hover": "#f0f0f0", "neutralBackground5Pressed": "#d1d1d1", "neutralBackground5Selected": "#dbdbdb", "neutralBackground6": "#d1d1d1", @@ -1314,41 +2410,63 @@ exports[`defaultFluentTheme 1`] = ` "neutralBackgroundLightStatic": "#ffffff", "neutralBackgroundLightStaticDisabled": "#ffffff", "neutralForeground1": "#242424", - "neutralForeground1Hover": undefined, - "neutralForeground1Pressed": undefined, - "neutralForeground1Selected": undefined, + "neutralForeground1Hover": "#242424", + "neutralForeground1Pressed": "#242424", + "neutralForeground1Selected": "#242424", "neutralForeground2": "#616161", - "neutralForeground2BrandHover": undefined, - "neutralForeground2BrandPressed": undefined, - "neutralForeground2BrandSelected": undefined, - "neutralForeground2Hover": undefined, - "neutralForeground2Pressed": undefined, - "neutralForeground2Selected": undefined, + "neutralForeground2BrandHover": "#616161", + "neutralForeground2BrandPressed": "#616161", + "neutralForeground2BrandSelected": "#616161", + "neutralForeground2Hover": "#616161", + "neutralForeground2Pressed": "#616161", + "neutralForeground2Selected": "#616161", "neutralForeground3": "#808080", - "neutralForeground3BrandHover": undefined, - "neutralForeground3BrandPressed": undefined, - "neutralForeground3BrandSelected": undefined, - "neutralForeground3Hover": undefined, - "neutralForeground3Pressed": undefined, - "neutralForeground3Selected": undefined, + "neutralForeground3BrandHover": "#808080", + "neutralForeground3BrandPressed": "#808080", + "neutralForeground3BrandSelected": "#808080", + "neutralForeground3Hover": "#808080", + "neutralForeground3Pressed": "#808080", + "neutralForeground3Selected": "#808080", + "neutralForeground4": "#808080", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#bdbdbd", "neutralForegroundDisabled1": "#bdbdbd", "neutralForegroundDisabled2": "#ffffff", "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#ffffff", + "neutralForegroundInvertedLinkHover": "#ffffff", + "neutralForegroundInvertedLinkPressed": "#ffffff", + "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#ffffff", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#e6e6e6", "neutralStencil2": "#fafafa", "neutralStroke1": "#d1d1d1", - "neutralStroke1Hover": undefined, - "neutralStroke1Pressed": undefined, - "neutralStroke1Selected": undefined, + "neutralStroke1Hover": "#d1d1d1", + "neutralStroke1Pressed": "#d1d1d1", + "neutralStroke1Selected": "#d1d1d1", "neutralStroke2": "#e0e0e0", + "neutralStroke3": "#e0e0e0", "neutralStrokeAccessible": "#616161", - "neutralStrokeAccessibleHover": undefined, - "neutralStrokeAccessiblePressed": undefined, - "neutralStrokeAccessibleSelected": undefined, + "neutralStrokeAccessibleHover": "#616161", + "neutralStrokeAccessiblePressed": "#616161", + "neutralStrokeAccessibleSelected": "#616161", "neutralStrokeDisabled": "#e0e0e0", "neutralStrokeFocus1": "#ffffff", "neutralStrokeFocus2": "#000000", + "outofofficeBackground1": "#fdf5fc", + "outofofficeBackground2": "#edbbe7", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#edbbe7", + "outofofficeBorder2": "#c239b3", + "outofofficeBorderActive": "#c239b3", + "outofofficeForeground1": "#af33a1", + "outofofficeForeground2": "#6d2064", + "outofofficeForeground3": "#c239b3", "personaActivityGlow": "#0f6cbd", "personaActivityRing": "#ffffff", "presenceAvailable": "#13a10e", @@ -1356,33 +2474,75 @@ exports[`defaultFluentTheme 1`] = ` "presenceDnd": "#d13438", "presenceOof": "#c239b3", "primaryButtonBackground": "#0f6cbd", - "primaryButtonBackgroundDisabled": "#f3f2f1", - "primaryButtonBackgroundHovered": "#115ea3", - "primaryButtonBackgroundPressed": "#0f548c", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", + "primaryButtonBackgroundDisabled": "#e0e0e0", + "primaryButtonBackgroundHovered": "#0f6cbd", + "primaryButtonBackgroundPressed": "#0e4775", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#000000", "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#d2d0ce", + "primaryButtonTextDisabled": "#bdbdbd", "primaryButtonTextHovered": "#ffffff", "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#d13438", + "redBackground3": "#d13438", + "redBorder1": "#dc5e62", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#d13438", + "redForeground3": "#d13438", "severeBackground1": "#fdf6f3", "severeBackground2": "#da3b01", + "severeBackground3": "#da3b01", + "severeBorder1": "#de501c", + "severeBorder2": "#da3b01", + "severeBorderActive": "#da3b01", "severeForeground1": "#c43501", "severeForeground2": "#c43501", - "subText": "#605e5c", + "severeForeground3": "#da3b01", + "severeStroke1": "#de501c", + "strokeFocus1": "#ffffff", + "strokeFocus2": "#000000", + "subText": "#616161", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#f5f5f5", + "subtleBackgroundPressed": "#e0e0e0", + "subtleBackgroundSelected": "#ebebeb", "successBackground1": "#f1faf1", "successBackground2": "#107c10", + "successBackground3": "#107c10", + "successBorder1": "#359b35", + "successBorder2": "#107c10", + "successBorderActive": "#107c10", "successForeground1": "#0e700e", "successForeground2": "#107c10", - "variantBorder": "#edebe9", + "successForeground3": "#107c10", + "successForegroundInverted": "#359b35", + "successStroke1": "#359b35", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#e0e0e0", "warningBackground1": "#fffef5", "warningBackground2": "#fde300", + "warningBackground3": "#fde300", + "warningBorder1": "#817400", + "warningBorder2": "#fde300", + "warningBorderActive": "#fde300", "warningForeground1": "#817400", "warningForeground2": "#817400", + "warningForeground3": "#fde300", + "warningForegroundInverted": "#fef7b2", + "warningStroke1": "#817400", }, "components": {}, "host": { - "appearance": "light", + "appearance": "highContrast", }, "shadows": { "shadow16": { @@ -1563,13 +2723,13 @@ exports[`defaultFluentTheme 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", - "primary": "Segoe UI", - "sansSerif": "System", - "secondary": "Segoe UI", - "serif": "System", + "cursive": "Roboto", + "monospace": "Roboto", + "numeric": "Roboto", + "primary": "Roboto", + "sansSerif": "Roboto", + "secondary": "Roboto", + "serif": "Roboto", }, "sizes": { "body": 14, @@ -1582,139 +2742,214 @@ exports[`defaultFluentTheme 1`] = ` }, "variants": { "body1": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "400", }, "body1Strong": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "500", }, "body2": { - "face": "primary", - "size": "body", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "400", }, "body2Strong": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "500", }, "bodySemibold": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "500", }, "bodyStandard": { - "face": "primary", - "size": "body", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 18, + "size": 14, + "weight": "400", }, "caption1": { - "face": "primary", - "size": "caption", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "400", }, "caption1Strong": { - "face": "primary", - "size": "caption", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "500", + }, + "caption2": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 12, + "weight": "400", }, "captionStandard": { - "face": "primary", - "size": "caption", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 16, + "size": 13, + "weight": "400", }, "display": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": -0.5, + "lineHeight": 72, + "size": 60, + "weight": "400", }, "headerSemibold": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "600", }, "headerStandard": { - "face": "primary", - "size": "header", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", }, "heroLargeSemibold": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": -0.5, + "lineHeight": 72, + "size": 60, + "weight": "400", }, "heroLargeStandard": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "face": "Roboto", + "letterSpacing": -0.25, + "lineHeight": 48, + "size": 34, + "weight": "400", }, "heroSemibold": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "600", }, "heroStandard": { - "face": "primary", - "size": "hero", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "400", }, "largeTitle": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "face": "Roboto", + "letterSpacing": -0.25, + "lineHeight": 48, + "size": 34, + "weight": "400", }, "secondarySemibold": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "500", }, "secondaryStandard": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 16, + "weight": "400", }, "subheaderSemibold": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "600", }, "subheaderStandard": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", }, "subtitle1": { - "face": "primary", - "size": "header", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", }, "subtitle1Strong": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "600", }, "subtitle2": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", }, "subtitle2Strong": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "600", }, "title1": { - "face": "primary", - "size": "hero", - "weight": "regular", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "400", }, "title1Strong": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 32, + "size": 24, + "weight": "600", + }, + "title2": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 20, + "weight": "500", + }, + "title3": { + "face": "Roboto", + "letterSpacing": 0, + "lineHeight": 24, + "size": 18, + "weight": "500", }, }, "weights": { diff --git a/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.ios.ts.snap b/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.ios.ts.snap index 19baf088fd..2dd1fb957d 100644 --- a/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.ios.ts.snap +++ b/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.ios.ts.snap @@ -3,152 +3,183 @@ exports[`defaultFluentDarkTheme 1`] = ` { "colors": { - "accentButtonBackground": "#0c3b5e", - "actionLink": "#f3f2f1", - "background": "#1b1a19", - "bodyDivider": "#292827", - "bodyFrameBackground": "#1b1a19", - "bodyFrameDivider": "#292827", - "bodyStandoutBackground": "#201f1e", - "bodyText": "#f3f2f1", + "accentButtonBackground": "#479ef5", + "actionLink": "#ffffff", + "background": "#000000", + "bodyDivider": "#3d3d3d", + "bodyFrameBackground": "#000000", + "bodyFrameDivider": "#3d3d3d", + "bodyStandoutBackground": "#1f1f1f", + "bodyText": "#ffffff", "bodyTextChecked": "#ffffff", "brandBackground": "#479ef5", - "brandBackground2": undefined, - "brandBackground2Pressed": undefined, - "brandBackground2Selected": undefined, - "brandBackground3": undefined, + "brandBackground2": "#479ef5", + "brandBackground2Pressed": "#96c6fa", + "brandBackground2Selected": "#77b7f7", + "brandBackground3": "#479ef5", "brandBackgroundDisabled": "#0c3b5e", + "brandBackgroundHover": "#479ef5", + "brandBackgroundInverted": "#b8b8b8", + "brandBackgroundInvertedDisabled": "#525252", "brandBackgroundPressed": "#96c6fa", "brandBackgroundSelected": "#77b7f7", + "brandBackgroundStatic": "#479ef5", "brandBackgroundTint": "#0c3b5e", "brandForeground1": "#479ef5", + "brandForeground1Disabled": "#2886de", "brandForeground1Pressed": "#96c6fa", "brandForeground1Selected": "#77b7f7", + "brandForeground2": "#479ef5", "brandForegroundDisabled1": "#2886de", "brandForegroundDisabled2": "#0c3b5e", + "brandForegroundLink": "#479ef5", + "brandForegroundLinkHover": "#479ef5", + "brandForegroundLinkPressed": "#96c6fa", + "brandForegroundLinkSelected": "#77b7f7", "brandForegroundTint": "#96c6fa", "brandStroke1": "#479ef5", "brandStroke1Pressed": "#96c6fa", "brandStroke1Selected": "#77b7f7", + "brandStroke2": "#479ef5", "brandStrokeTint": "#479ef5", - "brandedBackground": "#2886de", - "brandedDisabledBorder": "#252423", - "brandedFocusedSecondaryContent": "#201f1e", - "brandedHoveredSecondaryContent": "#201f1e", - "brandedPressedSecondaryContent": "#201f1e", - "brandedSecondaryContent": "#201f1e", - "buttonBackground": "#252423", - "buttonBackgroundChecked": "#484644", - "buttonBackgroundDisabled": "#252423", - "buttonBackgroundHovered": "#292827", - "buttonBackgroundPressed": "#292827", - "buttonBorder": "#979693", - "buttonBorderDisabled": "#252423", - "buttonBorderFocused": "#979693", + "brandedBackground": "#479ef5", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#000000", + "buttonBackground": "#000000", + "buttonBackgroundChecked": "#242424", + "buttonBackgroundDisabled": "#525252", + "buttonBackgroundHovered": "#000000", + "buttonBackgroundPressed": "#2e2e2e", + "buttonBorder": "#4d4d4d", + "buttonBorderDisabled": "#424242", + "buttonBorderFocused": "#ffffff", "buttonText": "#ffffff", - "buttonTextChecked": "#faf9f8", - "buttonTextDisabled": "#797775", - "buttonTextHovered": "#f3f2f1", - "buttonTextPressed": "#faf9f8", - "checkboxBackground": "#2886de", - "checkboxBackgroundDisabled": "#252423", - "checkboxBorderColor": "#979693", - "checkmarkColor": "#1b1a19", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#5c5c5c", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#479ef5", + "checkboxBackgroundDisabled": "#525252", + "checkboxBorderColor": "#9e9e9e", + "checkmarkColor": "#000000", + "compoundBrandBackground1": "#479ef5", + "compoundBrandBackground1Hover": "#479ef5", + "compoundBrandBackground1Pressed": "#96c6fa", + "compoundBrandForeground1": "#479ef5", + "compoundBrandForeground1Hover": "#479ef5", + "compoundBrandForeground1Pressed": "#96c6fa", + "compoundBrandStroke1": "#479ef5", + "compoundBrandStroke1Hover": "#479ef5", + "compoundBrandStroke1Pressed": "#96c6fa", "dangerBackground1": "#3f1011", "dangerBackground2": "#bc2f32", + "dangerBackground3": "#d13438", + "dangerBorder1": "#dc5e62", + "dangerBorder2": "#dc5e62", + "dangerBorderActive": "#e37d80", "dangerForeground1": "#e37d80", "dangerForeground2": "#e37d80", + "dangerForeground3": "#e37d80", + "dangerForegroundInverted": "#d13438", "dangerStroke1": "#dc5e62", - "defaultBackground": "#252423", - "defaultBorder": "#979693", - "defaultCheckedBackground": "#484644", - "defaultCheckedContent": "#faf9f8", - "defaultCheckedHoveredBackground": "#292827", - "defaultCheckedHoveredContent": "#f3f2f1", + "defaultBackground": "#000000", + "defaultBorder": "#4d4d4d", + "defaultCheckedBackground": "#242424", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#000000", + "defaultCheckedHoveredContent": "#ffffff", "defaultContent": "#ffffff", - "defaultDisabledBackground": "#252423", - "defaultDisabledBorder": "#252423", - "defaultDisabledContent": "#797775", - "defaultDisabledIcon": "#797775", - "defaultFocusedBackground": "#292827", - "defaultFocusedBorder": "#979693", - "defaultFocusedContent": "#f3f2f1", - "defaultFocusedIcon": "#f3f2f1", - "defaultHoveredBackground": "#292827", - "defaultHoveredBorder": "#979693", - "defaultHoveredContent": "#f3f2f1", - "defaultHoveredIcon": "#f3f2f1", - "defaultHoveredSecondaryContent": "#797775", + "defaultDisabledBackground": "#525252", + "defaultDisabledBorder": "#424242", + "defaultDisabledContent": "#5c5c5c", + "defaultDisabledIcon": "#5c5c5c", + "defaultFocusedBackground": "#000000", + "defaultFocusedBorder": "#ffffff", + "defaultFocusedContent": "#ffffff", + "defaultFocusedIcon": "#ffffff", + "defaultHoveredBackground": "#000000", + "defaultHoveredBorder": "#4d4d4d", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#adadad", "defaultIcon": "#ffffff", - "defaultPressedBackground": "#292827", - "defaultPressedBorder": "#979693", - "defaultPressedContent": "#faf9f8", - "defaultPressedIcon": "#faf9f8", - "defaultPressedSecondaryContent": "#797775", - "disabledBackground": "#323130", - "disabledBodyText": "#797775", - "disabledText": "#797775", - "errorText": "#ff5f5f", - "focusBorder": "#a19f9d", - "ghostBackground": "#1b1a19", - "ghostBorder": "#1b1a19", - "ghostCheckedBackground": "#292827", - "ghostCheckedContent": "#ffffff", - "ghostCheckedHoveredBackground": "#252423", - "ghostCheckedHoveredBorder": "#faf9f8", - "ghostCheckedHoveredContent": "#faf9f8", - "ghostContent": "#f3f2f1", - "ghostDisabledBackground": "#1b1a19", - "ghostDisabledBorder": "#1b1a19", - "ghostDisabledContent": "#797775", - "ghostDisabledIcon": "#797775", - "ghostFocusedBackground": "#252423", - "ghostFocusedBorder": "#979693", - "ghostFocusedContent": "#faf9f8", - "ghostFocusedIcon": "#faf9f8", - "ghostFocusedSecondaryContent": "#a19f9d", - "ghostHoveredBackground": "#252423", - "ghostHoveredBorder": "#252423", - "ghostHoveredContent": "#faf9f8", - "ghostHoveredIcon": "#faf9f8", - "ghostHoveredSecondaryContent": "#a19f9d", - "ghostIcon": "#f3f2f1", - "ghostPressedBackground": "#292827", - "ghostPressedBorder": "#292827", - "ghostPressedContent": "#faf9f8", - "ghostPressedIcon": "#faf9f8", - "ghostPressedSecondaryContent": "#a19f9d", - "ghostSecondaryContent": "#a19f9d", - "inputBackground": "#1b1a19", - "inputBorder": "#797775", - "inputFocusBorderAlt": "#2886de", - "inputPlaceholderText": "#a19f9d", - "inputText": "#f3f2f1", - "link": "#2886de", - "linkHovered": "#62abf5", - "linkPressed": "#479ef5", - "listHeaderBackgroundHovered": "#252423", - "listHeaderBackgroundPressed": "#292827", - "menuBackground": "#252423", - "menuDivider": "#484644", - "menuIcon": "#479ef5", - "menuItemBackgroundHovered": "#323130", - "menuItemBackgroundPressed": "#3b3a39", - "menuItemText": "#f3f2f1", - "menuItemTextHovered": "#faf9f8", + "defaultPressedBackground": "#2e2e2e", + "defaultPressedBorder": "#4d4d4d", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#adadad", + "disabledBackground": "#525252", + "disabledBodyText": "#5c5c5c", + "disabledText": "#5c5c5c", + "errorText": "#e37d80", + "focusBorder": "#ffffff", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#383838", + "ghostCheckedContent": "#d6d6d6", + "ghostCheckedHoveredBackground": "#3d3d3d", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#d6d6d6", + "ghostContent": "#ffffff", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#5c5c5c", + "ghostDisabledIcon": "#5c5c5c", + "ghostFocusedBackground": "#3d3d3d", + "ghostFocusedBorder": "#ffffff", + "ghostFocusedContent": "#ffffff", + "ghostFocusedIcon": "#ffffff", + "ghostFocusedSecondaryContent": "#adadad", + "ghostHoveredBackground": "#3d3d3d", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#adadad", + "ghostIcon": "#ffffff", + "ghostPressedBackground": "#1f1f1f", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#adadad", + "ghostSecondaryContent": "#adadad", + "inputBackground": "#000000", + "inputBorder": "#4d4d4d", + "inputFocusBorderAlt": "#479ef5", + "inputPlaceholderText": "#adadad", + "inputText": "#ffffff", + "link": "#479ef5", + "linkHovered": "#479ef5", + "linkPressed": "#96c6fa", + "listHeaderBackgroundHovered": "#000000", + "listHeaderBackgroundPressed": "#2e2e2e", + "menuBackground": "#000000", + "menuDivider": "#3d3d3d", + "menuIcon": "#d6d6d6", + "menuItemBackgroundHovered": "#000000", + "menuItemBackgroundPressed": "#2e2e2e", + "menuItemText": "#ffffff", + "menuItemTextHovered": "#ffffff", "neutralBackground1": "#000000", + "neutralBackground1Hover": "#000000", "neutralBackground1Pressed": "#2e2e2e", "neutralBackground1Selected": "#242424", "neutralBackground2": "#1f1f1f", + "neutralBackground2Hover": "#1f1f1f", "neutralBackground2Pressed": "#4d4d4d", "neutralBackground2Selected": "#424242", "neutralBackground3": "#292929", + "neutralBackground3Hover": "#292929", "neutralBackground3Pressed": "#575757", "neutralBackground3Selected": "#4d4d4d", "neutralBackground4": "#333333", + "neutralBackground4Hover": "#333333", "neutralBackground4Pressed": "#616161", "neutralBackground4Selected": "#575757", "neutralBackground5": "#3d3d3d", + "neutralBackground5Hover": "#3d3d3d", "neutralBackground5Pressed": "#6b6b6b", "neutralBackground5Selected": "#616161", "neutralBackground6": "#5c5c5c", @@ -159,53 +190,134 @@ exports[`defaultFluentDarkTheme 1`] = ` "neutralBackgroundLightStatic": "#ffffff", "neutralBackgroundLightStaticDisabled": "#adadad", "neutralForeground1": "#ffffff", + "neutralForeground1Hover": "#ffffff", + "neutralForeground1Pressed": "#ffffff", + "neutralForeground1Selected": "#ffffff", "neutralForeground2": "#d6d6d6", + "neutralForeground2BrandHover": "#d6d6d6", + "neutralForeground2BrandPressed": "#d6d6d6", + "neutralForeground2BrandSelected": "#d6d6d6", + "neutralForeground2Hover": "#d6d6d6", + "neutralForeground2Pressed": "#d6d6d6", + "neutralForeground2Selected": "#d6d6d6", "neutralForeground3": "#adadad", + "neutralForeground3BrandHover": "#adadad", + "neutralForeground3BrandPressed": "#adadad", + "neutralForeground3BrandSelected": "#adadad", + "neutralForeground3Hover": "#adadad", + "neutralForeground3Pressed": "#adadad", + "neutralForeground3Selected": "#adadad", + "neutralForeground4": "#adadad", "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#5c5c5c", "neutralForegroundDisabled1": "#5c5c5c", "neutralForegroundDisabled2": "#2e2e2e", + "neutralForegroundInverted": "#000000", + "neutralForegroundInvertedLink": "#000000", + "neutralForegroundInvertedLinkHover": "#000000", + "neutralForegroundInvertedLinkPressed": "#000000", + "neutralForegroundInvertedLinkSelected": "#000000", "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#000000", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", "neutralForegroundOnColor": "#000000", "neutralStencil1": "#575757", "neutralStencil2": "#333333", "neutralStroke1": "#4d4d4d", + "neutralStroke1Hover": "#4d4d4d", + "neutralStroke1Pressed": "#4d4d4d", + "neutralStroke1Selected": "#4d4d4d", "neutralStroke2": "#3d3d3d", + "neutralStroke3": "#3d3d3d", "neutralStrokeAccessible": "#9e9e9e", + "neutralStrokeAccessibleHover": "#9e9e9e", + "neutralStrokeAccessiblePressed": "#9e9e9e", + "neutralStrokeAccessibleSelected": "#9e9e9e", "neutralStrokeDisabled": "#424242", "neutralStrokeFocus1": "#000000", "neutralStrokeFocus2": "#ffffff", - "personaActivityGlow": "#2886de", - "personaActivityRing": "#1b1a19", + "outofofficeBackground1": "#3a1136", + "outofofficeBackground2": "#6d2064", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#c239b3", + "outofofficeBorder2": "#d161c4", + "outofofficeBorderActive": "#da7ed0", + "outofofficeForeground1": "#da7ed0", + "outofofficeForeground2": "#edbbe7", + "outofofficeForeground3": "#d161c4", + "personaActivityGlow": "#479ef5", + "personaActivityRing": "#000000", "presenceAvailable": "#3db838", "presenceAway": "#eaa300", "presenceDnd": "#d7494c", "presenceOof": "#d161c4", - "primaryButtonBackground": "#2886de", - "primaryButtonBackgroundDisabled": "#252423", + "primaryButtonBackground": "#479ef5", + "primaryButtonBackgroundDisabled": "#525252", "primaryButtonBackgroundHovered": "#479ef5", - "primaryButtonBackgroundPressed": "#479ef5", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", - "primaryButtonText": "#1b1a19", - "primaryButtonTextDisabled": "#3b3a39", - "primaryButtonTextHovered": "#1b1a19", - "primaryButtonTextPressed": "#1b1a19", + "primaryButtonBackgroundPressed": "#96c6fa", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#ffffff", + "primaryButtonText": "#000000", + "primaryButtonTextDisabled": "#5c5c5c", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#bc2f32", + "redBackground3": "#d13438", + "redBorder1": "#dc5e62", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#e37d80", + "redForeground3": "#e37d80", "severeBackground1": "#411200", "severeBackground2": "#c43501", + "severeBackground3": "#da3b01", + "severeBorder1": "#e36537", + "severeBorder2": "#e9835e", + "severeBorderActive": "#e9835e", "severeForeground1": "#e9835e", "severeForeground2": "#e9835e", + "severeForeground3": "#e9835e", "severeStroke1": "#e36537", - "subText": "#a19f9d", + "strokeFocus1": "#000000", + "strokeFocus2": "#ffffff", + "subText": "#d6d6d6", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#3d3d3d", + "subtleBackgroundPressed": "#1f1f1f", + "subtleBackgroundSelected": "#383838", "successBackground1": "#052505", "successBackground2": "#0e700e", + "successBackground3": "#107c10", + "successBorder1": "#359b35", + "successBorder2": "#9fd89f", + "successBorderActive": "#54b054", "successForeground1": "#54b054", "successForeground2": "#54b054", + "successForeground3": "#9fd89f", + "successForegroundInverted": "#107c10", "successStroke1": "#359b35", - "variantBorder": "#292827", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#3d3d3d", "warningBackground1": "#4c4400", "warningBackground2": "#e4cc00", + "warningBackground3": "#fde300", + "warningBorder1": "#c0ad00", + "warningBorder2": "#fdea3d", + "warningBorderActive": "#feee66", "warningForeground1": "#feee66", "warningForeground2": "#feee66", + "warningForeground3": "#fdea3d", + "warningForegroundInverted": "#817400", "warningStroke1": "#c0ad00", }, "components": {}, @@ -410,139 +522,244 @@ exports[`defaultFluentDarkTheme 1`] = ` }, "variants": { "body1": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "400", }, "body1Strong": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "600", }, "body2": { - "face": "primary", - "size": "body", - "weight": "regular", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "400", }, "body2Strong": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "600", }, "bodySemibold": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "600", }, "bodyStandard": { - "face": "primary", - "size": "body", - "weight": "regular", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "400", }, "caption1": { - "face": "primary", - "size": "caption", - "weight": "regular", + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "400", }, "caption1Strong": { - "face": "primary", - "size": "caption", - "weight": "semiBold", + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "600", + }, + "caption2": { + "dynamicTypeRamp": "caption1", + "face": "System", + "letterSpacing": 0, + "lineHeight": 16, + "size": 12, + "weight": "400", }, "captionStandard": { - "face": "primary", - "size": "caption", - "weight": "regular", + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "400", }, "display": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.26, + "lineHeight": 70, + "size": 60, + "weight": "700", }, "headerSemibold": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "headerStandard": { - "face": "primary", - "size": "header", - "weight": "regular", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "heroLargeSemibold": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.26, + "lineHeight": 70, + "size": 60, + "weight": "700", }, "heroLargeStandard": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.4, + "lineHeight": 41, + "size": 34, + "weight": "700", }, "heroSemibold": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "600", }, "heroStandard": { - "face": "primary", - "size": "hero", - "weight": "regular", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "700", }, "largeTitle": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.4, + "lineHeight": 41, + "size": 34, + "weight": "700", }, "secondarySemibold": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "600", }, "secondaryStandard": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "400", }, "subheaderSemibold": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "subheaderStandard": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "subtitle1": { - "face": "primary", - "size": "header", - "weight": "regular", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "subtitle1Strong": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "subtitle2": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "subtitle2Strong": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "title1": { - "face": "primary", - "size": "hero", - "weight": "regular", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "700", }, "title1Strong": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "600", + }, + "title2": { + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", + }, + "title3": { + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, }, "weights": { @@ -553,155 +770,186 @@ exports[`defaultFluentDarkTheme 1`] = ` } `; -exports[`defaultFluentHighConstrastTheme 1`] = ` +exports[`defaultFluentTheme 1`] = ` { "colors": { - "accentButtonBackground": "#000000", - "actionLink": "#ffff00", - "background": "#000000", - "bodyDivider": "#ffffff", - "bodyFrameBackground": "#000000", - "bodyFrameDivider": "#000000", - "bodyStandoutBackground": "#000000", - "bodyText": "#ffffff", - "bodyTextChecked": "#000000", + "accentButtonBackground": "#0f6cbd", + "actionLink": "#242424", + "background": "#ffffff", + "bodyDivider": "#e0e0e0", + "bodyFrameBackground": "#ffffff", + "bodyFrameDivider": "#e0e0e0", + "bodyStandoutBackground": "#ffffff", + "bodyText": "#242424", + "bodyTextChecked": "#242424", "brandBackground": "#0f6cbd", "brandBackground2": "#115ea3", "brandBackground2Pressed": "#0c3b5e", "brandBackground2Selected": "#0e4775", "brandBackground3": "#0f548c", "brandBackgroundDisabled": "#b4d6fa", + "brandBackgroundHover": "#0f6cbd", + "brandBackgroundInverted": "#757575", + "brandBackgroundInvertedDisabled": "#e0e0e0", "brandBackgroundPressed": "#0e4775", "brandBackgroundSelected": "#0f548c", + "brandBackgroundStatic": "#0f6cbd", "brandBackgroundTint": "#cfe4fa", "brandForeground1": "#0f6cbd", + "brandForeground1Disabled": "#2886de", "brandForeground1Pressed": "#0e4775", "brandForeground1Selected": "#0f548c", + "brandForeground2": "#0f6cbd", "brandForegroundDisabled1": "#2886de", "brandForegroundDisabled2": "#b4d6fa", + "brandForegroundLink": "#0f6cbd", + "brandForegroundLinkHover": "#0f6cbd", + "brandForegroundLinkPressed": "#0e4775", + "brandForegroundLinkSelected": "#0f548c", "brandForegroundTint": "#0f548c", "brandStroke1": "#0f6cbd", "brandStroke1Pressed": "#0e4775", "brandStroke1Selected": "#0f548c", + "brandStroke2": "#2886de", "brandStrokeTint": "#2886de", - "brandedBackground": "#000000", - "brandedDisabledBorder": "#3ff23f", + "brandedBackground": "#0f6cbd", + "brandedDisabledBorder": "#00000000", "brandedFocusedSecondaryContent": "#ffffff", - "brandedHoveredSecondaryContent": "#000000", - "brandedPressedSecondaryContent": "#000000", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", "brandedSecondaryContent": "#ffffff", - "buttonBackground": "#000000", - "buttonBackgroundChecked": "#1aebff", - "buttonBackgroundDisabled": "#000000", - "buttonBackgroundHovered": "#1aebff", - "buttonBackgroundPressed": "#1aebff", - "buttonBorder": "#ffffff", - "buttonBorderDisabled": "#3ff23f", - "buttonBorderFocused": "#ffffff", - "buttonText": "#ffffff", - "buttonTextChecked": "#000000", - "buttonTextDisabled": "#3ff23f", - "buttonTextHovered": "#000000", - "buttonTextPressed": "#000000", - "checkboxBackground": "#000000", - "checkboxBackgroundDisabled": "#000000", - "checkboxBorderColor": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#e0e0e0", + "buttonBackgroundHovered": "#ffffff", + "buttonBackgroundPressed": "#e0e0e0", + "buttonBorder": "#d1d1d1", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#242424", + "buttonTextChecked": "#242424", + "buttonTextDisabled": "#bdbdbd", + "buttonTextHovered": "#242424", + "buttonTextPressed": "#242424", + "checkboxBackground": "#0f6cbd", + "checkboxBackgroundDisabled": "#e0e0e0", + "checkboxBorderColor": "#616161", "checkmarkColor": "#ffffff", + "compoundBrandBackground1": "#0f6cbd", + "compoundBrandBackground1Hover": "#0f6cbd", + "compoundBrandBackground1Pressed": "#0e4775", + "compoundBrandForeground1": "#0f6cbd", + "compoundBrandForeground1Hover": "#0f6cbd", + "compoundBrandForeground1Pressed": "#0e4775", + "compoundBrandStroke1": "#0f6cbd", + "compoundBrandStroke1Hover": "#0f6cbd", + "compoundBrandStroke1Pressed": "#0e4775", "dangerBackground1": "#fdf6f6", "dangerBackground2": "#d13438", + "dangerBackground3": "#d13438", + "dangerBorder1": "#dc5e62", + "dangerBorder2": "#d13438", + "dangerBorderActive": "#d13438", "dangerForeground1": "#bc2f32", "dangerForeground2": "#d13438", + "dangerForeground3": "#d13438", + "dangerForegroundInverted": "#dc5e62", "dangerStroke1": "#dc5e62", - "defaultBackground": "#000000", - "defaultBorder": "#ffffff", - "defaultCheckedBackground": "#1aebff", - "defaultCheckedContent": "#000000", - "defaultCheckedHoveredBackground": "#1aebff", - "defaultCheckedHoveredContent": "#000000", - "defaultContent": "#ffffff", - "defaultDisabledBackground": "#000000", - "defaultDisabledBorder": "#3ff23f", - "defaultDisabledContent": "#3ff23f", - "defaultDisabledIcon": "#3ff23f", - "defaultFocusedBackground": "#000000", - "defaultFocusedBorder": "#ffffff", - "defaultFocusedContent": "#ffffff", - "defaultFocusedIcon": "#ffffff", - "defaultHoveredBackground": "#1aebff", - "defaultHoveredBorder": "#1aebff", - "defaultHoveredContent": "#000000", - "defaultHoveredIcon": "#000000", - "defaultHoveredSecondaryContent": "#000000", - "defaultIcon": "#ffffff", - "defaultPressedBackground": "#1aebff", - "defaultPressedBorder": "#1aebff", - "defaultPressedContent": "#000000", - "defaultPressedIcon": "#000000", - "defaultPressedSecondaryContent": "#000000", - "disabledBackground": "#000000", - "disabledBodyText": "#3ff23f", - "disabledText": "#3ff23f", - "errorText": "#ffffff", - "focusBorder": "#ffffff", - "ghostBackground": "#000000", - "ghostBorder": "#000000", - "ghostCheckedBackground": "#1aebff", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#1aebff", - "ghostCheckedHoveredBorder": "#000000", - "ghostCheckedHoveredContent": "#000000", - "ghostContent": "#ffffff", - "ghostDisabledBackground": "#000000", - "ghostDisabledBorder": "#000000", - "ghostDisabledContent": "#3ff23f", - "ghostDisabledIcon": "#3ff23f", - "ghostFocusedBackground": "#000000", - "ghostFocusedBorder": "#ffffff", - "ghostFocusedContent": "#ffffff", - "ghostFocusedIcon": "#ffffff", - "ghostFocusedSecondaryContent": "#ffffff", - "ghostHoveredBackground": "#1aebff", - "ghostHoveredBorder": "#1aebff", - "ghostHoveredContent": "#000000", - "ghostHoveredIcon": "#000000", - "ghostHoveredSecondaryContent": "#000000", - "ghostIcon": "#ffffff", - "ghostPressedBackground": "#1aebff", - "ghostPressedBorder": "#1aebff", - "ghostPressedContent": "#000000", - "ghostPressedIcon": "#000000", - "ghostPressedSecondaryContent": "#000000", - "ghostSecondaryContent": "#ffffff", - "inputBackground": "#000000", - "inputBorder": "#ffffff", - "inputFocusBorderAlt": "#ffffff", - "inputPlaceholderText": "#ffffff", - "inputText": "#ffffff", - "link": "#ffff00", - "linkHovered": "#ffffff", - "linkPressed": "#ffffff", - "listHeaderBackgroundHovered": "#1aebff", - "listHeaderBackgroundPressed": "#1aebff", - "menuBackground": "#000000", - "menuDivider": "#ffffff", - "menuIcon": "#ffffff", - "menuItemBackgroundHovered": "#1aebff", - "menuItemBackgroundPressed": "#1aebff", - "menuItemText": "#ffffff", - "menuItemTextHovered": "#000000", + "defaultBackground": "#ffffff", + "defaultBorder": "#d1d1d1", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#242424", + "defaultCheckedHoveredBackground": "#ffffff", + "defaultCheckedHoveredContent": "#242424", + "defaultContent": "#242424", + "defaultDisabledBackground": "#e0e0e0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#bdbdbd", + "defaultDisabledIcon": "#bdbdbd", + "defaultFocusedBackground": "#ffffff", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#242424", + "defaultFocusedIcon": "#242424", + "defaultHoveredBackground": "#ffffff", + "defaultHoveredBorder": "#d1d1d1", + "defaultHoveredContent": "#242424", + "defaultHoveredIcon": "#242424", + "defaultHoveredSecondaryContent": "#808080", + "defaultIcon": "#242424", + "defaultPressedBackground": "#e0e0e0", + "defaultPressedBorder": "#d1d1d1", + "defaultPressedContent": "#242424", + "defaultPressedIcon": "#242424", + "defaultPressedSecondaryContent": "#808080", + "disabledBackground": "#e0e0e0", + "disabledBodyText": "#bdbdbd", + "disabledText": "#bdbdbd", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#616161", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#616161", + "ghostContent": "#242424", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#bdbdbd", + "ghostDisabledIcon": "#bdbdbd", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#242424", + "ghostFocusedIcon": "#242424", + "ghostFocusedSecondaryContent": "#808080", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#242424", + "ghostHoveredIcon": "#242424", + "ghostHoveredSecondaryContent": "#808080", + "ghostIcon": "#242424", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#242424", + "ghostPressedIcon": "#242424", + "ghostPressedSecondaryContent": "#808080", + "ghostSecondaryContent": "#808080", + "inputBackground": "#ffffff", + "inputBorder": "#d1d1d1", + "inputFocusBorderAlt": "#0f6cbd", + "inputPlaceholderText": "#808080", + "inputText": "#242424", + "link": "#0f6cbd", + "linkHovered": "#0f6cbd", + "linkPressed": "#0e4775", + "listHeaderBackgroundHovered": "#ffffff", + "listHeaderBackgroundPressed": "#e0e0e0", + "menuBackground": "#ffffff", + "menuDivider": "#e0e0e0", + "menuIcon": "#616161", + "menuItemBackgroundHovered": "#ffffff", + "menuItemBackgroundPressed": "#e0e0e0", + "menuItemText": "#242424", + "menuItemTextHovered": "#242424", "neutralBackground1": "#ffffff", + "neutralBackground1Hover": "#ffffff", "neutralBackground1Pressed": "#e0e0e0", "neutralBackground1Selected": "#ebebeb", "neutralBackground2": "#ffffff", + "neutralBackground2Hover": "#ffffff", "neutralBackground2Pressed": "#e0e0e0", "neutralBackground2Selected": "#ebebeb", "neutralBackground3": "#ffffff", + "neutralBackground3Hover": "#ffffff", "neutralBackground3Pressed": "#e0e0e0", "neutralBackground3Selected": "#ebebeb", "neutralBackground4": "#fafafa", + "neutralBackground4Hover": "#fafafa", "neutralBackground4Pressed": "#dbdbdb", "neutralBackground4Selected": "#e6e6e6", "neutralBackground5": "#f0f0f0", + "neutralBackground5Hover": "#f0f0f0", "neutralBackground5Pressed": "#d1d1d1", "neutralBackground5Selected": "#dbdbdb", "neutralBackground6": "#d1d1d1", @@ -712,58 +960,139 @@ exports[`defaultFluentHighConstrastTheme 1`] = ` "neutralBackgroundLightStatic": "#ffffff", "neutralBackgroundLightStaticDisabled": "#ffffff", "neutralForeground1": "#242424", + "neutralForeground1Hover": "#242424", + "neutralForeground1Pressed": "#242424", + "neutralForeground1Selected": "#242424", "neutralForeground2": "#616161", + "neutralForeground2BrandHover": "#616161", + "neutralForeground2BrandPressed": "#616161", + "neutralForeground2BrandSelected": "#616161", + "neutralForeground2Hover": "#616161", + "neutralForeground2Pressed": "#616161", + "neutralForeground2Selected": "#616161", "neutralForeground3": "#808080", + "neutralForeground3BrandHover": "#808080", + "neutralForeground3BrandPressed": "#808080", + "neutralForeground3BrandSelected": "#808080", + "neutralForeground3Hover": "#808080", + "neutralForeground3Pressed": "#808080", + "neutralForeground3Selected": "#808080", + "neutralForeground4": "#808080", "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#bdbdbd", "neutralForegroundDisabled1": "#bdbdbd", "neutralForegroundDisabled2": "#ffffff", + "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#ffffff", + "neutralForegroundInvertedLinkHover": "#ffffff", + "neutralForegroundInvertedLinkPressed": "#ffffff", + "neutralForegroundInvertedLinkSelected": "#ffffff", "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#ffffff", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#e6e6e6", "neutralStencil2": "#fafafa", "neutralStroke1": "#d1d1d1", + "neutralStroke1Hover": "#d1d1d1", + "neutralStroke1Pressed": "#d1d1d1", + "neutralStroke1Selected": "#d1d1d1", "neutralStroke2": "#e0e0e0", + "neutralStroke3": "#e0e0e0", "neutralStrokeAccessible": "#616161", + "neutralStrokeAccessibleHover": "#616161", + "neutralStrokeAccessiblePressed": "#616161", + "neutralStrokeAccessibleSelected": "#616161", "neutralStrokeDisabled": "#e0e0e0", "neutralStrokeFocus1": "#ffffff", "neutralStrokeFocus2": "#000000", - "personaActivityGlow": "transparent", + "outofofficeBackground1": "#fdf5fc", + "outofofficeBackground2": "#edbbe7", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#edbbe7", + "outofofficeBorder2": "#c239b3", + "outofofficeBorderActive": "#c239b3", + "outofofficeForeground1": "#af33a1", + "outofofficeForeground2": "#6d2064", + "outofofficeForeground3": "#c239b3", + "personaActivityGlow": "#0f6cbd", "personaActivityRing": "#ffffff", "presenceAvailable": "#13a10e", "presenceAway": "#eaa300", "presenceDnd": "#d13438", "presenceOof": "#c239b3", - "primaryButtonBackground": "#000000", - "primaryButtonBackgroundDisabled": "#000000", - "primaryButtonBackgroundHovered": "#1aebff", - "primaryButtonBackgroundPressed": "#1aebff", - "primaryButtonBorder": "#ffffff", - "primaryButtonBorderFocused": "#ffffff", + "primaryButtonBackground": "#0f6cbd", + "primaryButtonBackgroundDisabled": "#e0e0e0", + "primaryButtonBackgroundHovered": "#0f6cbd", + "primaryButtonBackgroundPressed": "#0e4775", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#000000", "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#3ff23f", - "primaryButtonTextHovered": "#000000", - "primaryButtonTextPressed": "#000000", + "primaryButtonTextDisabled": "#bdbdbd", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#d13438", + "redBackground3": "#d13438", + "redBorder1": "#dc5e62", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#d13438", + "redForeground3": "#d13438", "severeBackground1": "#fdf6f3", "severeBackground2": "#da3b01", + "severeBackground3": "#da3b01", + "severeBorder1": "#de501c", + "severeBorder2": "#da3b01", + "severeBorderActive": "#da3b01", "severeForeground1": "#c43501", "severeForeground2": "#a62d01", + "severeForeground3": "#da3b01", "severeStroke1": "#de501c", - "subText": "#ffffff", + "strokeFocus1": "#ffffff", + "strokeFocus2": "#000000", + "subText": "#616161", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#f5f5f5", + "subtleBackgroundPressed": "#e0e0e0", + "subtleBackgroundSelected": "#ebebeb", "successBackground1": "#f1faf1", "successBackground2": "#107c10", + "successBackground3": "#107c10", + "successBorder1": "#359b35", + "successBorder2": "#107c10", + "successBorderActive": "#107c10", "successForeground1": "#0e700e", "successForeground2": "#107c10", + "successForeground3": "#107c10", + "successForegroundInverted": "#359b35", "successStroke1": "#359b35", - "variantBorder": "#ffffff", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#e0e0e0", "warningBackground1": "#fffef5", "warningBackground2": "#fde300", + "warningBackground3": "#fde300", + "warningBorder1": "#817400", + "warningBorder2": "#fde300", + "warningBorderActive": "#fde300", "warningForeground1": "#817400", "warningForeground2": "#817400", + "warningForeground3": "#fde300", + "warningForegroundInverted": "#fef7b2", "warningStroke1": "#817400", }, "components": {}, "host": { - "appearance": "highContrast", + "appearance": "light", }, "shadows": { "shadow16": { @@ -963,139 +1292,244 @@ exports[`defaultFluentHighConstrastTheme 1`] = ` }, "variants": { "body1": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "400", }, "body1Strong": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "600", }, "body2": { - "face": "primary", - "size": "body", - "weight": "regular", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "400", }, "body2Strong": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "600", }, "bodySemibold": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "600", }, "bodyStandard": { - "face": "primary", - "size": "body", - "weight": "regular", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "400", }, "caption1": { - "face": "primary", - "size": "caption", - "weight": "regular", + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "400", }, "caption1Strong": { - "face": "primary", - "size": "caption", - "weight": "semiBold", + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "600", + }, + "caption2": { + "dynamicTypeRamp": "caption1", + "face": "System", + "letterSpacing": 0, + "lineHeight": 16, + "size": 12, + "weight": "400", }, "captionStandard": { - "face": "primary", - "size": "caption", - "weight": "regular", + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "400", }, "display": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.26, + "lineHeight": 70, + "size": 60, + "weight": "700", }, "headerSemibold": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "headerStandard": { - "face": "primary", - "size": "header", - "weight": "regular", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "heroLargeSemibold": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.26, + "lineHeight": 70, + "size": 60, + "weight": "700", }, "heroLargeStandard": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.4, + "lineHeight": 41, + "size": 34, + "weight": "700", }, "heroSemibold": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "600", }, "heroStandard": { - "face": "primary", - "size": "hero", - "weight": "regular", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "700", }, "largeTitle": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.4, + "lineHeight": 41, + "size": 34, + "weight": "700", }, "secondarySemibold": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "600", }, "secondaryStandard": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "400", }, "subheaderSemibold": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "subheaderStandard": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "subtitle1": { - "face": "primary", - "size": "header", - "weight": "regular", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "subtitle1Strong": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "subtitle2": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "subtitle2Strong": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "title1": { - "face": "primary", - "size": "hero", - "weight": "regular", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "700", }, "title1Strong": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "600", + }, + "title2": { + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", + }, + "title3": { + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, }, "weights": { @@ -1106,155 +1540,956 @@ exports[`defaultFluentHighConstrastTheme 1`] = ` } `; -exports[`defaultFluentTheme 1`] = ` +exports[`high contrast dark theme 1`] = ` +{ + "colors": { + "accentButtonBackground": "#479ef5", + "actionLink": "#ffffff", + "background": "#000000", + "bodyDivider": "#3d3d3d", + "bodyFrameBackground": "#000000", + "bodyFrameDivider": "#3d3d3d", + "bodyStandoutBackground": "#1f1f1f", + "bodyText": "#ffffff", + "bodyTextChecked": "#ffffff", + "brandBackground": "#479ef5", + "brandBackground2": "#479ef5", + "brandBackground2Pressed": "#96c6fa", + "brandBackground2Selected": "#77b7f7", + "brandBackground3": "#479ef5", + "brandBackgroundDisabled": "#0c3b5e", + "brandBackgroundHover": "#479ef5", + "brandBackgroundInverted": "#b8b8b8", + "brandBackgroundInvertedDisabled": "#525252", + "brandBackgroundPressed": "#96c6fa", + "brandBackgroundSelected": "#77b7f7", + "brandBackgroundStatic": "#479ef5", + "brandBackgroundTint": "#0c3b5e", + "brandForeground1": "#479ef5", + "brandForeground1Disabled": "#2886de", + "brandForeground1Pressed": "#96c6fa", + "brandForeground1Selected": "#77b7f7", + "brandForeground2": "#479ef5", + "brandForegroundDisabled1": "#2886de", + "brandForegroundDisabled2": "#0c3b5e", + "brandForegroundLink": "#479ef5", + "brandForegroundLinkHover": "#479ef5", + "brandForegroundLinkPressed": "#96c6fa", + "brandForegroundLinkSelected": "#77b7f7", + "brandForegroundTint": "#96c6fa", + "brandStroke1": "#479ef5", + "brandStroke1Pressed": "#96c6fa", + "brandStroke1Selected": "#77b7f7", + "brandStroke2": "#479ef5", + "brandStrokeTint": "#479ef5", + "brandedBackground": "#479ef5", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#000000", + "buttonBackground": "#000000", + "buttonBackgroundChecked": "#242424", + "buttonBackgroundDisabled": "#525252", + "buttonBackgroundHovered": "#000000", + "buttonBackgroundPressed": "#2e2e2e", + "buttonBorder": "#4d4d4d", + "buttonBorderDisabled": "#424242", + "buttonBorderFocused": "#ffffff", + "buttonText": "#ffffff", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#5c5c5c", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#479ef5", + "checkboxBackgroundDisabled": "#525252", + "checkboxBorderColor": "#9e9e9e", + "checkmarkColor": "#000000", + "compoundBrandBackground1": "#479ef5", + "compoundBrandBackground1Hover": "#479ef5", + "compoundBrandBackground1Pressed": "#96c6fa", + "compoundBrandForeground1": "#479ef5", + "compoundBrandForeground1Hover": "#479ef5", + "compoundBrandForeground1Pressed": "#96c6fa", + "compoundBrandStroke1": "#479ef5", + "compoundBrandStroke1Hover": "#479ef5", + "compoundBrandStroke1Pressed": "#96c6fa", + "dangerBackground1": "#3f1011", + "dangerBackground2": "#bc2f32", + "dangerBackground3": "#d13438", + "dangerBorder1": "#dc5e62", + "dangerBorder2": "#dc5e62", + "dangerBorderActive": "#e37d80", + "dangerForeground1": "#e37d80", + "dangerForeground2": "#e37d80", + "dangerForeground3": "#e37d80", + "dangerForegroundInverted": "#d13438", + "dangerStroke1": "#dc5e62", + "defaultBackground": "#000000", + "defaultBorder": "#4d4d4d", + "defaultCheckedBackground": "#242424", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#000000", + "defaultCheckedHoveredContent": "#ffffff", + "defaultContent": "#ffffff", + "defaultDisabledBackground": "#525252", + "defaultDisabledBorder": "#424242", + "defaultDisabledContent": "#5c5c5c", + "defaultDisabledIcon": "#5c5c5c", + "defaultFocusedBackground": "#000000", + "defaultFocusedBorder": "#ffffff", + "defaultFocusedContent": "#ffffff", + "defaultFocusedIcon": "#ffffff", + "defaultHoveredBackground": "#000000", + "defaultHoveredBorder": "#4d4d4d", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#adadad", + "defaultIcon": "#ffffff", + "defaultPressedBackground": "#2e2e2e", + "defaultPressedBorder": "#4d4d4d", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#adadad", + "disabledBackground": "#525252", + "disabledBodyText": "#5c5c5c", + "disabledText": "#5c5c5c", + "errorText": "#e37d80", + "focusBorder": "#ffffff", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#383838", + "ghostCheckedContent": "#d6d6d6", + "ghostCheckedHoveredBackground": "#3d3d3d", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#d6d6d6", + "ghostContent": "#ffffff", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#5c5c5c", + "ghostDisabledIcon": "#5c5c5c", + "ghostFocusedBackground": "#3d3d3d", + "ghostFocusedBorder": "#ffffff", + "ghostFocusedContent": "#ffffff", + "ghostFocusedIcon": "#ffffff", + "ghostFocusedSecondaryContent": "#adadad", + "ghostHoveredBackground": "#3d3d3d", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#adadad", + "ghostIcon": "#ffffff", + "ghostPressedBackground": "#1f1f1f", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#adadad", + "ghostSecondaryContent": "#adadad", + "inputBackground": "#000000", + "inputBorder": "#4d4d4d", + "inputFocusBorderAlt": "#479ef5", + "inputPlaceholderText": "#adadad", + "inputText": "#ffffff", + "link": "#479ef5", + "linkHovered": "#479ef5", + "linkPressed": "#96c6fa", + "listHeaderBackgroundHovered": "#000000", + "listHeaderBackgroundPressed": "#2e2e2e", + "menuBackground": "#000000", + "menuDivider": "#3d3d3d", + "menuIcon": "#d6d6d6", + "menuItemBackgroundHovered": "#000000", + "menuItemBackgroundPressed": "#2e2e2e", + "menuItemText": "#ffffff", + "menuItemTextHovered": "#ffffff", + "neutralBackground1": "#000000", + "neutralBackground1Hover": "#000000", + "neutralBackground1Pressed": "#2e2e2e", + "neutralBackground1Selected": "#242424", + "neutralBackground2": "#1f1f1f", + "neutralBackground2Hover": "#1f1f1f", + "neutralBackground2Pressed": "#4d4d4d", + "neutralBackground2Selected": "#424242", + "neutralBackground3": "#292929", + "neutralBackground3Hover": "#292929", + "neutralBackground3Pressed": "#575757", + "neutralBackground3Selected": "#4d4d4d", + "neutralBackground4": "#333333", + "neutralBackground4Hover": "#333333", + "neutralBackground4Pressed": "#616161", + "neutralBackground4Selected": "#575757", + "neutralBackground5": "#3d3d3d", + "neutralBackground5Hover": "#3d3d3d", + "neutralBackground5Pressed": "#6b6b6b", + "neutralBackground5Selected": "#616161", + "neutralBackground6": "#5c5c5c", + "neutralBackgroundCanvas": "#141414", + "neutralBackgroundDarkStatic": "#3d3d3d", + "neutralBackgroundDisabled": "#525252", + "neutralBackgroundInverted": "#b8b8b8", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#adadad", + "neutralForeground1": "#ffffff", + "neutralForeground1Hover": "#ffffff", + "neutralForeground1Pressed": "#ffffff", + "neutralForeground1Selected": "#ffffff", + "neutralForeground2": "#d6d6d6", + "neutralForeground2BrandHover": "#d6d6d6", + "neutralForeground2BrandPressed": "#d6d6d6", + "neutralForeground2BrandSelected": "#d6d6d6", + "neutralForeground2Hover": "#d6d6d6", + "neutralForeground2Pressed": "#d6d6d6", + "neutralForeground2Selected": "#d6d6d6", + "neutralForeground3": "#adadad", + "neutralForeground3BrandHover": "#adadad", + "neutralForeground3BrandPressed": "#adadad", + "neutralForeground3BrandSelected": "#adadad", + "neutralForeground3Hover": "#adadad", + "neutralForeground3Pressed": "#adadad", + "neutralForeground3Selected": "#adadad", + "neutralForeground4": "#adadad", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#5c5c5c", + "neutralForegroundDisabled1": "#5c5c5c", + "neutralForegroundDisabled2": "#2e2e2e", + "neutralForegroundInverted": "#000000", + "neutralForegroundInvertedLink": "#000000", + "neutralForegroundInvertedLinkHover": "#000000", + "neutralForegroundInvertedLinkPressed": "#000000", + "neutralForegroundInvertedLinkSelected": "#000000", + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#000000", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#000000", + "neutralStencil1": "#575757", + "neutralStencil2": "#333333", + "neutralStroke1": "#4d4d4d", + "neutralStroke1Hover": "#4d4d4d", + "neutralStroke1Pressed": "#4d4d4d", + "neutralStroke1Selected": "#4d4d4d", + "neutralStroke2": "#3d3d3d", + "neutralStroke3": "#3d3d3d", + "neutralStrokeAccessible": "#9e9e9e", + "neutralStrokeAccessibleHover": "#9e9e9e", + "neutralStrokeAccessiblePressed": "#9e9e9e", + "neutralStrokeAccessibleSelected": "#9e9e9e", + "neutralStrokeDisabled": "#424242", + "neutralStrokeFocus1": "#000000", + "neutralStrokeFocus2": "#ffffff", + "outofofficeBackground1": "#3a1136", + "outofofficeBackground2": "#6d2064", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#c239b3", + "outofofficeBorder2": "#d161c4", + "outofofficeBorderActive": "#da7ed0", + "outofofficeForeground1": "#da7ed0", + "outofofficeForeground2": "#edbbe7", + "outofofficeForeground3": "#d161c4", + "personaActivityGlow": "#479ef5", + "personaActivityRing": "#000000", + "presenceAvailable": "#3db838", + "presenceAway": "#eaa300", + "presenceDnd": "#d7494c", + "presenceOof": "#d161c4", + "primaryButtonBackground": "#479ef5", + "primaryButtonBackgroundDisabled": "#525252", + "primaryButtonBackgroundHovered": "#479ef5", + "primaryButtonBackgroundPressed": "#96c6fa", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#ffffff", + "primaryButtonText": "#000000", + "primaryButtonTextDisabled": "#5c5c5c", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#bc2f32", + "redBackground3": "#d13438", + "redBorder1": "#dc5e62", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#e37d80", + "redForeground3": "#e37d80", + "severeBackground1": "#411200", + "severeBackground2": "#c43501", + "severeBackground3": "#da3b01", + "severeBorder1": "#e36537", + "severeBorder2": "#e9835e", + "severeBorderActive": "#e9835e", + "severeForeground1": "#e9835e", + "severeForeground2": "#e9835e", + "severeForeground3": "#e9835e", + "severeStroke1": "#e36537", + "strokeFocus1": "#000000", + "strokeFocus2": "#ffffff", + "subText": "#d6d6d6", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#3d3d3d", + "subtleBackgroundPressed": "#1f1f1f", + "subtleBackgroundSelected": "#383838", + "successBackground1": "#052505", + "successBackground2": "#0e700e", + "successBackground3": "#107c10", + "successBorder1": "#359b35", + "successBorder2": "#9fd89f", + "successBorderActive": "#54b054", + "successForeground1": "#54b054", + "successForeground2": "#54b054", + "successForeground3": "#9fd89f", + "successForegroundInverted": "#107c10", + "successStroke1": "#359b35", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#3d3d3d", + "warningBackground1": "#4c4400", + "warningBackground2": "#e4cc00", + "warningBackground3": "#fde300", + "warningBorder1": "#c0ad00", + "warningBorder2": "#fdea3d", + "warningBorderActive": "#feee66", + "warningForeground1": "#feee66", + "warningForeground2": "#feee66", + "warningForeground3": "#fdea3d", + "warningForegroundInverted": "#817400", + "warningStroke1": "#c0ad00", + }, + "components": {}, + "host": { + "appearance": "highContrast", + }, + "shadows": { + "shadow16": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000047", + "x": 0, + "y": 8, + }, + }, + "shadow16brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000040", + "x": 0, + "y": 8, + }, + }, + "shadow2": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000047", + "x": 0, + "y": 1, + }, + }, + "shadow28": { + "ambient": { + "blur": 8, + "color": "#00000066", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#0000007a", + "x": 0, + "y": 14, + }, + }, + "shadow28brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#00000040", + "x": 0, + "y": 14, + }, + }, + "shadow2brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000040", + "x": 0, + "y": 1, + }, + }, + "shadow4": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000047", + "x": 0, + "y": 2, + }, + }, + "shadow4brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000040", + "x": 0, + "y": 2, + }, + }, + "shadow64": { + "ambient": { + "blur": 8, + "color": "#00000066", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#0000007a", + "x": 0, + "y": 32, + }, + }, + "shadow64brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#00000040", + "x": 0, + "y": 32, + }, + }, + "shadow8": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000047", + "x": 0, + "y": 4, + }, + }, + "shadow8brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000040", + "x": 0, + "y": 4, + }, + }, + }, + "spacing": { + "l1": "20px", + "l2": "32px", + "m": "16px", + "s1": "8px", + "s2": "4px", + }, + "typography": { + "families": { + "cursive": "System", + "monospace": "System", + "numeric": "System", + "primary": "System", + "sansSerif": "System", + "secondary": "System", + "serif": "System", + }, + "sizes": { + "body": 15, + "caption": 12, + "header": 20, + "hero": 28, + "heroLarge": 60, + "secondary": 13, + "subheader": 17, + }, + "variants": { + "body1": { + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "400", + }, + "body1Strong": { + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "600", + }, + "body2": { + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "400", + }, + "body2Strong": { + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "600", + }, + "bodySemibold": { + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "600", + }, + "bodyStandard": { + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "400", + }, + "caption1": { + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "400", + }, + "caption1Strong": { + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "600", + }, + "caption2": { + "dynamicTypeRamp": "caption1", + "face": "System", + "letterSpacing": 0, + "lineHeight": 16, + "size": 12, + "weight": "400", + }, + "captionStandard": { + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "400", + }, + "display": { + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.26, + "lineHeight": 70, + "size": 60, + "weight": "700", + }, + "headerSemibold": { + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", + }, + "headerStandard": { + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", + }, + "heroLargeSemibold": { + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.26, + "lineHeight": 70, + "size": 60, + "weight": "700", + }, + "heroLargeStandard": { + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.4, + "lineHeight": 41, + "size": 34, + "weight": "700", + }, + "heroSemibold": { + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "600", + }, + "heroStandard": { + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "700", + }, + "largeTitle": { + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.4, + "lineHeight": 41, + "size": 34, + "weight": "700", + }, + "secondarySemibold": { + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "600", + }, + "secondaryStandard": { + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "400", + }, + "subheaderSemibold": { + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", + }, + "subheaderStandard": { + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", + }, + "subtitle1": { + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", + }, + "subtitle1Strong": { + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", + }, + "subtitle2": { + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", + }, + "subtitle2Strong": { + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", + }, + "title1": { + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "700", + }, + "title1Strong": { + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "600", + }, + "title2": { + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", + }, + "title3": { + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", + }, + }, + "weights": { + "regular": "400", + "semiBold": "600", + }, + }, +} +`; + +exports[`high contrast light theme 1`] = ` { "colors": { "accentButtonBackground": "#0f6cbd", - "actionLink": "#323130", + "actionLink": "#242424", "background": "#ffffff", - "bodyDivider": "#edebe9", + "bodyDivider": "#e0e0e0", "bodyFrameBackground": "#ffffff", - "bodyFrameDivider": "#edebe9", - "bodyStandoutBackground": "#faf9f8", - "bodyText": "#323130", - "bodyTextChecked": "#000000", + "bodyFrameDivider": "#e0e0e0", + "bodyStandoutBackground": "#ffffff", + "bodyText": "#242424", + "bodyTextChecked": "#242424", "brandBackground": "#0f6cbd", "brandBackground2": "#115ea3", "brandBackground2Pressed": "#0c3b5e", "brandBackground2Selected": "#0e4775", "brandBackground3": "#0f548c", "brandBackgroundDisabled": "#b4d6fa", + "brandBackgroundHover": "#0f6cbd", + "brandBackgroundInverted": "#757575", + "brandBackgroundInvertedDisabled": "#e0e0e0", "brandBackgroundPressed": "#0e4775", "brandBackgroundSelected": "#0f548c", + "brandBackgroundStatic": "#0f6cbd", "brandBackgroundTint": "#cfe4fa", "brandForeground1": "#0f6cbd", + "brandForeground1Disabled": "#2886de", "brandForeground1Pressed": "#0e4775", "brandForeground1Selected": "#0f548c", + "brandForeground2": "#0f6cbd", "brandForegroundDisabled1": "#2886de", "brandForegroundDisabled2": "#b4d6fa", + "brandForegroundLink": "#0f6cbd", + "brandForegroundLinkHover": "#0f6cbd", + "brandForegroundLinkPressed": "#0e4775", + "brandForegroundLinkSelected": "#0f548c", "brandForegroundTint": "#0f548c", "brandStroke1": "#0f6cbd", "brandStroke1Pressed": "#0e4775", "brandStroke1Selected": "#0f548c", + "brandStroke2": "#2886de", "brandStrokeTint": "#2886de", "brandedBackground": "#0f6cbd", - "brandedDisabledBorder": "#f3f2f1", - "brandedFocusedSecondaryContent": "#faf9f8", - "brandedHoveredSecondaryContent": "#faf9f8", - "brandedPressedSecondaryContent": "#faf9f8", - "brandedSecondaryContent": "#faf9f8", - "buttonBackground": "#f3f2f1", - "buttonBackgroundChecked": "#c8c6c4", - "buttonBackgroundDisabled": "#f3f2f1", - "buttonBackgroundHovered": "#edebe9", - "buttonBackgroundPressed": "#edebe9", - "buttonBorder": "#8a8886", - "buttonBorderDisabled": "#f3f2f1", - "buttonBorderFocused": "#8a8886", - "buttonText": "#323130", - "buttonTextChecked": "#201f1e", - "buttonTextDisabled": "#a19f9d", - "buttonTextHovered": "#201f1e", - "buttonTextPressed": "#201f1e", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#e0e0e0", + "buttonBackgroundHovered": "#ffffff", + "buttonBackgroundPressed": "#e0e0e0", + "buttonBorder": "#d1d1d1", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#242424", + "buttonTextChecked": "#242424", + "buttonTextDisabled": "#bdbdbd", + "buttonTextHovered": "#242424", + "buttonTextPressed": "#242424", "checkboxBackground": "#0f6cbd", - "checkboxBackgroundDisabled": "#f3f2f1", - "checkboxBorderColor": "#8a8886", + "checkboxBackgroundDisabled": "#e0e0e0", + "checkboxBorderColor": "#616161", "checkmarkColor": "#ffffff", + "compoundBrandBackground1": "#0f6cbd", + "compoundBrandBackground1Hover": "#0f6cbd", + "compoundBrandBackground1Pressed": "#0e4775", + "compoundBrandForeground1": "#0f6cbd", + "compoundBrandForeground1Hover": "#0f6cbd", + "compoundBrandForeground1Pressed": "#0e4775", + "compoundBrandStroke1": "#0f6cbd", + "compoundBrandStroke1Hover": "#0f6cbd", + "compoundBrandStroke1Pressed": "#0e4775", "dangerBackground1": "#fdf6f6", "dangerBackground2": "#d13438", + "dangerBackground3": "#d13438", + "dangerBorder1": "#dc5e62", + "dangerBorder2": "#d13438", + "dangerBorderActive": "#d13438", "dangerForeground1": "#bc2f32", "dangerForeground2": "#d13438", + "dangerForeground3": "#d13438", + "dangerForegroundInverted": "#dc5e62", "dangerStroke1": "#dc5e62", - "defaultBackground": "#f3f2f1", - "defaultBorder": "#8a8886", - "defaultCheckedBackground": "#c8c6c4", - "defaultCheckedContent": "#201f1e", - "defaultCheckedHoveredBackground": "#edebe9", - "defaultCheckedHoveredContent": "#201f1e", - "defaultContent": "#323130", - "defaultDisabledBackground": "#f3f2f1", - "defaultDisabledBorder": "#f3f2f1", - "defaultDisabledContent": "#a19f9d", - "defaultDisabledIcon": "#a19f9d", - "defaultFocusedBackground": "#edebe9", - "defaultFocusedBorder": "#8a8886", - "defaultFocusedContent": "#201f1e", - "defaultFocusedIcon": "#201f1e", - "defaultHoveredBackground": "#edebe9", - "defaultHoveredBorder": "#8a8886", - "defaultHoveredContent": "#201f1e", - "defaultHoveredIcon": "#201f1e", - "defaultHoveredSecondaryContent": "#a19f9d", - "defaultIcon": "#323130", - "defaultPressedBackground": "#edebe9", - "defaultPressedBorder": "#8a8886", - "defaultPressedContent": "#201f1e", - "defaultPressedIcon": "#201f1e", - "defaultPressedSecondaryContent": "#a19f9d", - "disabledBackground": "#f3f2f1", - "disabledBodyText": "#a19f9d", - "disabledText": "#a19f9d", - "errorText": "#a4262c", - "focusBorder": "#605e5c", - "ghostBackground": "#ffffff", - "ghostBorder": "#ffffff", - "ghostCheckedBackground": "#edebe9", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#f3f2f1", - "ghostCheckedHoveredBorder": "#201f1e", - "ghostCheckedHoveredContent": "#201f1e", - "ghostContent": "#323130", - "ghostDisabledBackground": "#ffffff", - "ghostDisabledBorder": "#ffffff", - "ghostDisabledContent": "#a19f9d", - "ghostDisabledIcon": "#a19f9d", - "ghostFocusedBackground": "#f3f2f1", - "ghostFocusedBorder": "#8a8886", - "ghostFocusedContent": "#201f1e", - "ghostFocusedIcon": "#201f1e", - "ghostFocusedSecondaryContent": "#605e5c", - "ghostHoveredBackground": "#f3f2f1", - "ghostHoveredBorder": "#f3f2f1", - "ghostHoveredContent": "#201f1e", - "ghostHoveredIcon": "#201f1e", - "ghostHoveredSecondaryContent": "#605e5c", - "ghostIcon": "#323130", - "ghostPressedBackground": "#edebe9", - "ghostPressedBorder": "#edebe9", - "ghostPressedContent": "#201f1e", - "ghostPressedIcon": "#201f1e", - "ghostPressedSecondaryContent": "#605e5c", - "ghostSecondaryContent": "#605e5c", + "defaultBackground": "#ffffff", + "defaultBorder": "#d1d1d1", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#242424", + "defaultCheckedHoveredBackground": "#ffffff", + "defaultCheckedHoveredContent": "#242424", + "defaultContent": "#242424", + "defaultDisabledBackground": "#e0e0e0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#bdbdbd", + "defaultDisabledIcon": "#bdbdbd", + "defaultFocusedBackground": "#ffffff", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#242424", + "defaultFocusedIcon": "#242424", + "defaultHoveredBackground": "#ffffff", + "defaultHoveredBorder": "#d1d1d1", + "defaultHoveredContent": "#242424", + "defaultHoveredIcon": "#242424", + "defaultHoveredSecondaryContent": "#808080", + "defaultIcon": "#242424", + "defaultPressedBackground": "#e0e0e0", + "defaultPressedBorder": "#d1d1d1", + "defaultPressedContent": "#242424", + "defaultPressedIcon": "#242424", + "defaultPressedSecondaryContent": "#808080", + "disabledBackground": "#e0e0e0", + "disabledBodyText": "#bdbdbd", + "disabledText": "#bdbdbd", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#616161", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#616161", + "ghostContent": "#242424", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#bdbdbd", + "ghostDisabledIcon": "#bdbdbd", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#242424", + "ghostFocusedIcon": "#242424", + "ghostFocusedSecondaryContent": "#808080", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#242424", + "ghostHoveredIcon": "#242424", + "ghostHoveredSecondaryContent": "#808080", + "ghostIcon": "#242424", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#242424", + "ghostPressedIcon": "#242424", + "ghostPressedSecondaryContent": "#808080", + "ghostSecondaryContent": "#808080", "inputBackground": "#ffffff", - "inputBorder": "#a19f9d", + "inputBorder": "#d1d1d1", "inputFocusBorderAlt": "#0f6cbd", - "inputPlaceholderText": "#605e5c", - "inputText": "#323130", + "inputPlaceholderText": "#808080", + "inputText": "#242424", "link": "#0f6cbd", - "linkHovered": "#0c3b5e", - "linkPressed": "#0f548c", - "listHeaderBackgroundHovered": "#f3f2f1", - "listHeaderBackgroundPressed": "#edebe9", + "linkHovered": "#0f6cbd", + "linkPressed": "#0e4775", + "listHeaderBackgroundHovered": "#ffffff", + "listHeaderBackgroundPressed": "#e0e0e0", "menuBackground": "#ffffff", - "menuDivider": "#c8c6c4", - "menuIcon": "#0f6cbd", - "menuItemBackgroundHovered": "#f3f2f1", - "menuItemBackgroundPressed": "#edebe9", - "menuItemText": "#323130", - "menuItemTextHovered": "#201f1e", + "menuDivider": "#e0e0e0", + "menuIcon": "#616161", + "menuItemBackgroundHovered": "#ffffff", + "menuItemBackgroundPressed": "#e0e0e0", + "menuItemText": "#242424", + "menuItemTextHovered": "#242424", "neutralBackground1": "#ffffff", + "neutralBackground1Hover": "#ffffff", "neutralBackground1Pressed": "#e0e0e0", "neutralBackground1Selected": "#ebebeb", "neutralBackground2": "#ffffff", + "neutralBackground2Hover": "#ffffff", "neutralBackground2Pressed": "#e0e0e0", "neutralBackground2Selected": "#ebebeb", "neutralBackground3": "#ffffff", + "neutralBackground3Hover": "#ffffff", "neutralBackground3Pressed": "#e0e0e0", "neutralBackground3Selected": "#ebebeb", "neutralBackground4": "#fafafa", + "neutralBackground4Hover": "#fafafa", "neutralBackground4Pressed": "#dbdbdb", "neutralBackground4Selected": "#e6e6e6", "neutralBackground5": "#f0f0f0", + "neutralBackground5Hover": "#f0f0f0", "neutralBackground5Pressed": "#d1d1d1", "neutralBackground5Selected": "#dbdbdb", "neutralBackground6": "#d1d1d1", @@ -1265,21 +2500,63 @@ exports[`defaultFluentTheme 1`] = ` "neutralBackgroundLightStatic": "#ffffff", "neutralBackgroundLightStaticDisabled": "#ffffff", "neutralForeground1": "#242424", + "neutralForeground1Hover": "#242424", + "neutralForeground1Pressed": "#242424", + "neutralForeground1Selected": "#242424", "neutralForeground2": "#616161", + "neutralForeground2BrandHover": "#616161", + "neutralForeground2BrandPressed": "#616161", + "neutralForeground2BrandSelected": "#616161", + "neutralForeground2Hover": "#616161", + "neutralForeground2Pressed": "#616161", + "neutralForeground2Selected": "#616161", "neutralForeground3": "#808080", + "neutralForeground3BrandHover": "#808080", + "neutralForeground3BrandPressed": "#808080", + "neutralForeground3BrandSelected": "#808080", + "neutralForeground3Hover": "#808080", + "neutralForeground3Pressed": "#808080", + "neutralForeground3Selected": "#808080", + "neutralForeground4": "#808080", "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#bdbdbd", "neutralForegroundDisabled1": "#bdbdbd", "neutralForegroundDisabled2": "#ffffff", + "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#ffffff", + "neutralForegroundInvertedLinkHover": "#ffffff", + "neutralForegroundInvertedLinkPressed": "#ffffff", + "neutralForegroundInvertedLinkSelected": "#ffffff", "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#ffffff", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#e6e6e6", "neutralStencil2": "#fafafa", "neutralStroke1": "#d1d1d1", + "neutralStroke1Hover": "#d1d1d1", + "neutralStroke1Pressed": "#d1d1d1", + "neutralStroke1Selected": "#d1d1d1", "neutralStroke2": "#e0e0e0", + "neutralStroke3": "#e0e0e0", "neutralStrokeAccessible": "#616161", + "neutralStrokeAccessibleHover": "#616161", + "neutralStrokeAccessiblePressed": "#616161", + "neutralStrokeAccessibleSelected": "#616161", "neutralStrokeDisabled": "#e0e0e0", "neutralStrokeFocus1": "#ffffff", "neutralStrokeFocus2": "#000000", + "outofofficeBackground1": "#fdf5fc", + "outofofficeBackground2": "#edbbe7", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#edbbe7", + "outofofficeBorder2": "#c239b3", + "outofofficeBorderActive": "#c239b3", + "outofofficeForeground1": "#af33a1", + "outofofficeForeground2": "#6d2064", + "outofofficeForeground3": "#c239b3", "personaActivityGlow": "#0f6cbd", "personaActivityRing": "#ffffff", "presenceAvailable": "#13a10e", @@ -1287,48 +2564,87 @@ exports[`defaultFluentTheme 1`] = ` "presenceDnd": "#d13438", "presenceOof": "#c239b3", "primaryButtonBackground": "#0f6cbd", - "primaryButtonBackgroundDisabled": "#f3f2f1", - "primaryButtonBackgroundHovered": "#115ea3", - "primaryButtonBackgroundPressed": "#0f548c", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", + "primaryButtonBackgroundDisabled": "#e0e0e0", + "primaryButtonBackgroundHovered": "#0f6cbd", + "primaryButtonBackgroundPressed": "#0e4775", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#000000", "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#d2d0ce", + "primaryButtonTextDisabled": "#bdbdbd", "primaryButtonTextHovered": "#ffffff", "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#d13438", + "redBackground3": "#d13438", + "redBorder1": "#dc5e62", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#d13438", + "redForeground3": "#d13438", "severeBackground1": "#fdf6f3", "severeBackground2": "#da3b01", + "severeBackground3": "#da3b01", + "severeBorder1": "#de501c", + "severeBorder2": "#da3b01", + "severeBorderActive": "#da3b01", "severeForeground1": "#c43501", "severeForeground2": "#a62d01", + "severeForeground3": "#da3b01", "severeStroke1": "#de501c", - "subText": "#605e5c", + "strokeFocus1": "#ffffff", + "strokeFocus2": "#000000", + "subText": "#616161", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#f5f5f5", + "subtleBackgroundPressed": "#e0e0e0", + "subtleBackgroundSelected": "#ebebeb", "successBackground1": "#f1faf1", "successBackground2": "#107c10", + "successBackground3": "#107c10", + "successBorder1": "#359b35", + "successBorder2": "#107c10", + "successBorderActive": "#107c10", "successForeground1": "#0e700e", "successForeground2": "#107c10", + "successForeground3": "#107c10", + "successForegroundInverted": "#359b35", "successStroke1": "#359b35", - "variantBorder": "#edebe9", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#e0e0e0", "warningBackground1": "#fffef5", "warningBackground2": "#fde300", + "warningBackground3": "#fde300", + "warningBorder1": "#817400", + "warningBorder2": "#fde300", + "warningBorderActive": "#fde300", "warningForeground1": "#817400", "warningForeground2": "#817400", + "warningForeground3": "#fde300", + "warningForegroundInverted": "#fef7b2", "warningStroke1": "#817400", }, "components": {}, "host": { - "appearance": "light", + "appearance": "highContrast", }, "shadows": { "shadow16": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 16, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 8, }, @@ -1350,13 +2666,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow2": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 2, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 1, }, @@ -1364,13 +2680,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow28": { "ambient": { "blur": 8, - "color": "#00000033", + "color": "#00000066", "x": 0, "y": 0, }, "key": { "blur": 28, - "color": "#0000003d", + "color": "#0000007a", "x": 0, "y": 14, }, @@ -1406,13 +2722,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow4": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 4, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 2, }, @@ -1434,13 +2750,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow64": { "ambient": { "blur": 8, - "color": "#00000033", + "color": "#00000066", "x": 0, "y": 0, }, "key": { "blur": 64, - "color": "#0000003d", + "color": "#0000007a", "x": 0, "y": 32, }, @@ -1462,13 +2778,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow8": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 8, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 4, }, @@ -1516,139 +2832,244 @@ exports[`defaultFluentTheme 1`] = ` }, "variants": { "body1": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "400", }, "body1Strong": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "600", }, "body2": { - "face": "primary", - "size": "body", - "weight": "regular", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "400", }, "body2Strong": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "600", }, "bodySemibold": { - "face": "primary", - "size": "body", - "weight": "semiBold", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "600", }, "bodyStandard": { - "face": "primary", - "size": "body", - "weight": "regular", + "dynamicTypeRamp": "subheadline", + "face": "System", + "letterSpacing": -0.23, + "lineHeight": 20, + "size": 15, + "weight": "400", }, "caption1": { - "face": "primary", - "size": "caption", - "weight": "regular", + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "400", }, "caption1Strong": { - "face": "primary", - "size": "caption", - "weight": "semiBold", + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "600", + }, + "caption2": { + "dynamicTypeRamp": "caption1", + "face": "System", + "letterSpacing": 0, + "lineHeight": 16, + "size": 12, + "weight": "400", }, "captionStandard": { - "face": "primary", - "size": "caption", - "weight": "regular", + "dynamicTypeRamp": "footnote", + "face": "System", + "letterSpacing": -0.08, + "lineHeight": 18, + "size": 13, + "weight": "400", }, "display": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.26, + "lineHeight": 70, + "size": 60, + "weight": "700", }, "headerSemibold": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "headerStandard": { - "face": "primary", - "size": "header", - "weight": "regular", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "heroLargeSemibold": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.26, + "lineHeight": 70, + "size": 60, + "weight": "700", }, "heroLargeStandard": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.4, + "lineHeight": 41, + "size": 34, + "weight": "700", }, "heroSemibold": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "600", }, "heroStandard": { - "face": "primary", - "size": "hero", - "weight": "regular", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "700", }, "largeTitle": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", + "dynamicTypeRamp": "largeTitle", + "face": "System", + "letterSpacing": 0.4, + "lineHeight": 41, + "size": 34, + "weight": "700", }, "secondarySemibold": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "600", }, "secondaryStandard": { - "face": "primary", - "size": "secondary", - "weight": "regular", + "dynamicTypeRamp": "body", + "face": "System", + "letterSpacing": -0.43, + "lineHeight": 22, + "size": 17, + "weight": "400", }, "subheaderSemibold": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "subheaderStandard": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "subtitle1": { - "face": "primary", - "size": "header", - "weight": "regular", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "subtitle1Strong": { - "face": "primary", - "size": "header", - "weight": "semiBold", + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", }, "subtitle2": { - "face": "primary", - "size": "subheader", - "weight": "regular", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "subtitle2Strong": { - "face": "primary", - "size": "subheader", - "weight": "semiBold", + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, "title1": { - "face": "primary", - "size": "hero", - "weight": "regular", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "700", }, "title1Strong": { - "face": "primary", - "size": "hero", - "weight": "semiBold", + "dynamicTypeRamp": "title1", + "face": "System", + "letterSpacing": 0.38, + "lineHeight": 34, + "size": 28, + "weight": "600", + }, + "title2": { + "dynamicTypeRamp": "title2", + "face": "System", + "letterSpacing": -0.26, + "lineHeight": 28, + "size": 22, + "weight": "600", + }, + "title3": { + "dynamicTypeRamp": "title3", + "face": "System", + "letterSpacing": -0.45, + "lineHeight": 25, + "size": 20, + "weight": "600", }, }, "weights": { diff --git a/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.macos.ts.snap b/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.macos.ts.snap index 861be6b0a4..7516a1ccb2 100644 --- a/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.macos.ts.snap +++ b/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.macos.ts.snap @@ -3,64 +3,77 @@ exports[`defaultFluentDarkTheme 1`] = ` { "colors": { - "accentButtonBackground": "#185abd", - "actionLink": "#f3f2f1", - "background": "#1b1a19", - "bodyDivider": "#292827", - "bodyFrameBackground": "#1b1a19", - "bodyFrameDivider": "#292827", - "bodyStandoutBackground": "#201f1e", - "bodyText": "#f3f2f1", + "accentButtonBackground": "#0086f0", + "actionLink": "#ffffff", + "background": "#000000", + "bodyDivider": "#575757", + "bodyFrameBackground": "#000000", + "bodyFrameDivider": "#575757", + "bodyStandoutBackground": "#575757", + "bodyText": "#ffffff", "bodyTextChecked": "#ffffff", - "brandBackground": "#1651aa", - "brandBackground2": "#004578", - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": "#185abd", - "brandBackgroundPressed": "#004578", - "brandBackgroundSelected": "#13458f", - "brandBackgroundStatic": "#185abd", - "brandForeground1": "#6794d7", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": "#aec6eb", - "brandForegroundLink": "#2e6ac5", - "brandForegroundLinkHover": "#aec6eb", - "brandForegroundLinkPressed": "#6794d7", - "brandForegroundLinkSelected": "#2e6ac5", - "brandStroke1": "#2e6ac5", - "brandStroke2": "#0e336a", - "brandedBackground": "#2e6ac5", - "brandedDisabledBorder": "#252423", - "brandedFocusedSecondaryContent": "#201f1e", - "brandedHoveredSecondaryContent": "#201f1e", - "brandedPressedSecondaryContent": "#201f1e", - "brandedSecondaryContent": "#201f1e", - "buttonBackground": "#252423", - "buttonBackgroundChecked": "#484644", - "buttonBackgroundDisabled": "#252423", - "buttonBackgroundHovered": "#292827", - "buttonBackgroundPressed": "#292827", - "buttonBorder": "#979693", - "buttonBorderDisabled": "#252423", - "buttonBorderFocused": "#979693", + "brandBackground": "#0086f0", + "brandBackground2": "#092c47", + "brandBackground2Pressed": "#1890f1", + "brandBackground2Selected": "#3aa0f3", + "brandBackground3": "#092c47", + "brandBackgroundDisabled": "#575757", + "brandBackgroundHover": "#1890f1", + "brandBackgroundInverted": "#ffffff", + "brandBackgroundInvertedDisabled": "#575757", + "brandBackgroundPressed": "#1890f1", + "brandBackgroundSelected": "#3aa0f3", + "brandBackgroundStatic": "#0086f0", + "brandBackgroundTint": "#092c47", + "brandForeground1": "#0086f0", + "brandForeground1Disabled": "#c2c2c2", + "brandForeground1Pressed": "#6cb8f6", + "brandForeground1Selected": "#3aa0f3", + "brandForeground2": "#092c47", + "brandForegroundDisabled1": "#c2c2c2", + "brandForegroundDisabled2": "#c2c2c2", + "brandForegroundLink": "#043862", + "brandForegroundLinkHover": "#092c47", + "brandForegroundLinkPressed": "#0078d4", + "brandForegroundLinkSelected": "#092c47", + "brandForegroundTint": "#092c47", + "brandStroke1": "#0086f0", + "brandStroke1Pressed": "#6cb8f6", + "brandStroke1Selected": "#3aa0f3", + "brandStroke2": "#004c87", + "brandStrokeTint": "#004c87", + "brandedBackground": "#0086f0", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#000000", + "buttonBackgroundChecked": "#383838", + "buttonBackgroundDisabled": "#575757", + "buttonBackgroundHovered": "#3d3d3d", + "buttonBackgroundPressed": "#5c5c5c", + "buttonBorder": "#3d3d3d", + "buttonBorderDisabled": "#525252", + "buttonBorderFocused": "#ffffff", "buttonText": "#ffffff", - "buttonTextChecked": "#faf9f8", - "buttonTextDisabled": "#797775", - "buttonTextHovered": "#f3f2f1", - "buttonTextPressed": "#faf9f8", - "checkboxBackground": "#2e6ac5", - "checkboxBackgroundDisabled": "#252423", - "checkboxBorderColor": "#979693", - "checkmarkColor": "#1b1a19", - "compoundBrandBackground1": "#2e6ac5", - "compoundBrandBackground1Hover": "#6794d7", - "compoundBrandBackground1Pressed": "#185abd", - "compoundBrandForeground1": "#2e6ac5", - "compoundBrandForeground1Hover": "#6794d7", - "compoundBrandForeground1Pressed": "#185abd", - "compoundBrandStroke1": "#2e6ac5", - "compoundBrandStroke1Hover": "#6794d7", - "compoundBrandStroke1Pressed": "#185abd", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#b8b8b8", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#0086f0", + "checkboxBackgroundDisabled": "#575757", + "checkboxBorderColor": "#adadad", + "checkmarkColor": "#ffffff", + "compoundBrandBackground1": "#0086f0", + "compoundBrandBackground1Hover": "#1890f1", + "compoundBrandBackground1Pressed": "#6cb8f6", + "compoundBrandForeground1": "#043862", + "compoundBrandForeground1Hover": "#092c47", + "compoundBrandForeground1Pressed": "#0078d4", + "compoundBrandStroke1": "#0086f0", + "compoundBrandStroke1Hover": "#1890f1", + "compoundBrandStroke1Pressed": "#6cb8f6", "dangerBackground1": "#3f1011", "dangerBackground2": "#751d1f", "dangerBackground3": "#d13438", @@ -71,148 +84,160 @@ exports[`defaultFluentDarkTheme 1`] = ` "dangerForeground2": "#f1bbbc", "dangerForeground3": "#e37d80", "dangerForegroundInverted": "#d13438", - "defaultBackground": "#252423", - "defaultBorder": "#979693", - "defaultCheckedBackground": "#484644", - "defaultCheckedContent": "#faf9f8", - "defaultCheckedHoveredBackground": "#292827", - "defaultCheckedHoveredContent": "#f3f2f1", + "dangerStroke1": "#d13438", + "defaultBackground": "#000000", + "defaultBorder": "#3d3d3d", + "defaultCheckedBackground": "#383838", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#3d3d3d", + "defaultCheckedHoveredContent": "#ffffff", "defaultContent": "#ffffff", - "defaultDisabledBackground": "#252423", - "defaultDisabledBorder": "#252423", - "defaultDisabledContent": "#797775", - "defaultDisabledIcon": "#797775", - "defaultFocusedBackground": "#292827", - "defaultFocusedBorder": "#979693", - "defaultFocusedContent": "#f3f2f1", - "defaultFocusedIcon": "#f3f2f1", - "defaultHoveredBackground": "#292827", - "defaultHoveredBorder": "#979693", - "defaultHoveredContent": "#f3f2f1", - "defaultHoveredIcon": "#f3f2f1", - "defaultHoveredSecondaryContent": "#797775", + "defaultDisabledBackground": "#575757", + "defaultDisabledBorder": "#525252", + "defaultDisabledContent": "#b8b8b8", + "defaultDisabledIcon": "#b8b8b8", + "defaultFocusedBackground": "#3d3d3d", + "defaultFocusedBorder": "#ffffff", + "defaultFocusedContent": "#ffffff", + "defaultFocusedIcon": "#ffffff", + "defaultHoveredBackground": "#3d3d3d", + "defaultHoveredBorder": "#757575", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#d6d6d6", "defaultIcon": "#ffffff", - "defaultPressedBackground": "#292827", - "defaultPressedBorder": "#979693", - "defaultPressedContent": "#faf9f8", - "defaultPressedIcon": "#faf9f8", - "defaultPressedSecondaryContent": "#797775", - "disabledBackground": "#323130", - "disabledBodyText": "#797775", - "disabledText": "#797775", - "errorText": "#ff5f5f", - "focusBorder": "#a19f9d", - "ghostBackground": "#1b1a19", - "ghostBorder": "#1b1a19", - "ghostCheckedBackground": "#292827", + "defaultPressedBackground": "#5c5c5c", + "defaultPressedBorder": "#6b6b6b", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#d6d6d6", + "disabledBackground": "#575757", + "disabledBodyText": "#b8b8b8", + "disabledText": "#b8b8b8", + "errorText": "#e37d80", + "focusBorder": "#ffffff", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#383838", "ghostCheckedContent": "#ffffff", - "ghostCheckedHoveredBackground": "#252423", - "ghostCheckedHoveredBorder": "#faf9f8", - "ghostCheckedHoveredContent": "#faf9f8", - "ghostContent": "#f3f2f1", - "ghostDisabledBackground": "#1b1a19", - "ghostDisabledBorder": "#1b1a19", - "ghostDisabledContent": "#797775", - "ghostDisabledIcon": "#797775", - "ghostFocusedBackground": "#252423", - "ghostFocusedBorder": "#979693", - "ghostFocusedContent": "#faf9f8", - "ghostFocusedIcon": "#faf9f8", - "ghostFocusedSecondaryContent": "#a19f9d", - "ghostHoveredBackground": "#252423", - "ghostHoveredBorder": "#252423", - "ghostHoveredContent": "#faf9f8", - "ghostHoveredIcon": "#faf9f8", - "ghostHoveredSecondaryContent": "#a19f9d", - "ghostIcon": "#f3f2f1", - "ghostPressedBackground": "#292827", - "ghostPressedBorder": "#292827", - "ghostPressedContent": "#faf9f8", - "ghostPressedIcon": "#faf9f8", - "ghostPressedSecondaryContent": "#a19f9d", - "ghostSecondaryContent": "#a19f9d", - "inputBackground": "#1b1a19", - "inputBorder": "#797775", - "inputFocusBorderAlt": "#2e6ac5", - "inputPlaceholderText": "#a19f9d", - "inputText": "#f3f2f1", - "link": "#2e6ac5", - "linkHovered": "#82c7ff", - "linkPressed": "#aec6eb", - "listHeaderBackgroundHovered": "#252423", - "listHeaderBackgroundPressed": "#292827", - "menuBackground": "#252423", - "menuDivider": "#484644", - "menuIcon": "#6794d7", - "menuItemBackgroundHovered": "#323130", - "menuItemBackgroundPressed": "#3b3a39", - "menuItemText": "#f3f2f1", - "menuItemTextHovered": "#faf9f8", - "neutralBackground1": "#292929", + "ghostCheckedHoveredBackground": "#3d3d3d", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#ffffff", + "ghostContent": "#ffffff", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#b8b8b8", + "ghostDisabledIcon": "#b8b8b8", + "ghostFocusedBackground": "#3d3d3d", + "ghostFocusedBorder": "#ffffff", + "ghostFocusedContent": "#ffffff", + "ghostFocusedIcon": "#ffffff", + "ghostFocusedSecondaryContent": "#adadad", + "ghostHoveredBackground": "#3d3d3d", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#d6d6d6", + "ghostIcon": "#ffffff", + "ghostPressedBackground": "#1f1f1f", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#d6d6d6", + "ghostSecondaryContent": "#adadad", + "inputBackground": "#000000", + "inputBorder": "#3d3d3d", + "inputFocusBorderAlt": "#0086f0", + "inputPlaceholderText": "#858585", + "inputText": "#ffffff", + "link": "#043862", + "linkHovered": "#092c47", + "linkPressed": "#0078d4", + "listHeaderBackgroundHovered": "#3d3d3d", + "listHeaderBackgroundPressed": "#5c5c5c", + "menuBackground": "#000000", + "menuDivider": "#575757", + "menuIcon": "#ffffff", + "menuItemBackgroundHovered": "#3d3d3d", + "menuItemBackgroundPressed": "#5c5c5c", + "menuItemText": "#ffffff", + "menuItemTextHovered": "#ffffff", + "neutralBackground1": "#000000", "neutralBackground1Hover": "#3d3d3d", - "neutralBackground1Pressed": "#1f1f1f", + "neutralBackground1Pressed": "#5c5c5c", "neutralBackground1Selected": "#383838", - "neutralBackground2": "#1f1f1f", + "neutralBackground2": "#575757", "neutralBackground2Hover": "#333333", - "neutralBackground2Pressed": "#141414", + "neutralBackground2Pressed": "#707070", "neutralBackground2Selected": "#2e2e2e", - "neutralBackground3": "#141414", + "neutralBackground3": "#575757", "neutralBackground3Hover": "#292929", "neutralBackground3Pressed": "#0a0a0a", "neutralBackground3Selected": "#242424", - "neutralBackground4": "#0a0a0a", + "neutralBackground4": "#1f1f1f", "neutralBackground4Hover": "#1f1f1f", "neutralBackground4Pressed": "#000000", "neutralBackground4Selected": "#1a1a1a", - "neutralBackground5": "#000000", + "neutralBackground5": "#5c5c5c", "neutralBackground5Hover": "#141414", "neutralBackground5Pressed": "#050505", "neutralBackground5Selected": "#0f0f0f", "neutralBackground6": "#333333", - "neutralBackgroundDisabled": "#141414", + "neutralBackgroundCanvas": "#000000", + "neutralBackgroundDarkStatic": "#3d3d3d", + "neutralBackgroundDisabled": "#575757", "neutralBackgroundInverted": "#ffffff", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#575757", "neutralForeground1": "#ffffff", "neutralForeground1Hover": "#ffffff", "neutralForeground1Pressed": "#ffffff", "neutralForeground1Selected": "#ffffff", - "neutralForeground2": "#d6d6d6", - "neutralForeground2BrandHover": "#6794d7", - "neutralForeground2BrandPressed": "#2e6ac5", - "neutralForeground2BrandSelected": "#6794d7", + "neutralForeground2": "#ffffff", + "neutralForeground2BrandHover": "#092c47", + "neutralForeground2BrandPressed": "#0078d4", + "neutralForeground2BrandSelected": "#092c47", "neutralForeground2Hover": "#ffffff", "neutralForeground2Pressed": "#ffffff", "neutralForeground2Selected": "#ffffff", "neutralForeground3": "#adadad", - "neutralForeground3BrandHover": "#6794d7", - "neutralForeground3BrandPressed": "#2e6ac5", - "neutralForeground3BrandSelected": "#6794d7", + "neutralForeground3BrandHover": "#092c47", + "neutralForeground3BrandPressed": "#0078d4", + "neutralForeground3BrandSelected": "#092c47", "neutralForeground3Hover": "#d6d6d6", "neutralForeground3Pressed": "#d6d6d6", "neutralForeground3Selected": "#d6d6d6", - "neutralForeground4": "#999999", - "neutralForegroundDisabled": "#5c5c5c", - "neutralForegroundInverted": "#242424", - "neutralForegroundInvertedLink": "#ffffff", - "neutralForegroundInvertedLinkHover": "#ffffff", - "neutralForegroundInvertedLinkPressed": "#ffffff", - "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForeground4": "#858585", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#b8b8b8", + "neutralForegroundDisabled1": "#b8b8b8", + "neutralForegroundDisabled2": "#b8b8b8", + "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#292929", + "neutralForegroundInvertedLinkHover": "#292929", + "neutralForegroundInvertedLinkPressed": "#292929", + "neutralForegroundInvertedLinkSelected": "#292929", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#ffffff", "neutralForegroundOnBrandHover": "#ffffff", "neutralForegroundOnBrandPressed": "#ffffff", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#333333", "neutralStencil2": "#575757", - "neutralStroke1": "#666666", + "neutralStroke1": "#3d3d3d", "neutralStroke1Hover": "#757575", "neutralStroke1Pressed": "#6b6b6b", "neutralStroke1Selected": "#707070", - "neutralStroke2": "#525252", - "neutralStroke3": "#3d3d3d", + "neutralStroke2": "#575757", + "neutralStroke3": "#666666", "neutralStrokeAccessible": "#adadad", "neutralStrokeAccessibleHover": "#bdbdbd", "neutralStrokeAccessiblePressed": "#b3b3b3", - "neutralStrokeAccessibleSelected": "#6794d7", - "neutralStrokeDisabled": "#424242", + "neutralStrokeAccessibleSelected": "#0086f0", + "neutralStrokeDisabled": "#525252", + "neutralStrokeFocus1": "#000000", + "neutralStrokeFocus2": "#ffffff", "outofofficeBackground1": "#3a1136", "outofofficeBackground2": "#6d2064", "outofofficeBackground3": "#c239b3", @@ -222,18 +247,31 @@ exports[`defaultFluentDarkTheme 1`] = ` "outofofficeForeground1": "#da7ed0", "outofofficeForeground2": "#edbbe7", "outofofficeForeground3": "#d161c4", - "personaActivityGlow": "#2e6ac5", - "personaActivityRing": "#1b1a19", - "primaryButtonBackground": "#2e6ac5", - "primaryButtonBackgroundDisabled": "#252423", - "primaryButtonBackgroundHovered": "#6794d7", - "primaryButtonBackgroundPressed": "#aec6eb", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", - "primaryButtonText": "#1b1a19", - "primaryButtonTextDisabled": "#3b3a39", - "primaryButtonTextHovered": "#1b1a19", - "primaryButtonTextPressed": "#1b1a19", + "personaActivityGlow": "#0086f0", + "personaActivityRing": "#000000", + "presenceAvailable": "#54b054", + "presenceAway": "#feee66", + "presenceDnd": "#e37d80", + "presenceOof": "#da7ed0", + "primaryButtonBackground": "#0086f0", + "primaryButtonBackgroundDisabled": "#575757", + "primaryButtonBackgroundHovered": "#1890f1", + "primaryButtonBackgroundPressed": "#1890f1", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#ffffff", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#b8b8b8", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#751d1f", + "redBackground3": "#d13438", + "redBorder1": "#d13438", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#f1bbbc", + "redForeground3": "#e37d80", "severeBackground1": "#411200", "severeBackground2": "#7a2101", "severeBackground3": "#da3b01", @@ -243,23 +281,705 @@ exports[`defaultFluentDarkTheme 1`] = ` "severeForeground1": "#e9835e", "severeForeground2": "#f4bfab", "severeForeground3": "#e9835e", + "severeStroke1": "#da3b01", "strokeFocus1": "#000000", "strokeFocus2": "#ffffff", - "subText": "#a19f9d", + "subText": "#ffffff", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#3d3d3d", + "subtleBackgroundPressed": "#1f1f1f", + "subtleBackgroundSelected": "#383838", + "successBackground1": "#052505", + "successBackground2": "#094509", + "successBackground3": "#107c10", + "successBorder1": "#107c10", + "successBorder2": "#9fd89f", + "successBorderActive": "#54b054", + "successForeground1": "#54b054", + "successForeground2": "#9fd89f", + "successForeground3": "#9fd89f", + "successForegroundInverted": "#107c10", + "successStroke1": "#107c10", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#575757", + "warningBackground1": "#4c4400", + "warningBackground2": "#817400", + "warningBackground3": "#fde300", + "warningBorder1": "#fde300", + "warningBorder2": "#fdea3d", + "warningBorderActive": "#feee66", + "warningForeground1": "#feee66", + "warningForeground2": "#fef7b2", + "warningForeground3": "#fdea3d", + "warningForegroundInverted": "#817400", + "warningStroke1": "#fde300", + }, + "components": {}, + "host": { + "appearance": "dark", + }, + "shadows": { + "shadow16": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000047", + "x": 0, + "y": 8, + }, + }, + "shadow16brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000040", + "x": 0, + "y": 8, + }, + }, + "shadow2": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000047", + "x": 0, + "y": 1, + }, + }, + "shadow28": { + "ambient": { + "blur": 8, + "color": "#00000066", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#0000007a", + "x": 0, + "y": 14, + }, + }, + "shadow28brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#00000040", + "x": 0, + "y": 14, + }, + }, + "shadow2brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000040", + "x": 0, + "y": 1, + }, + }, + "shadow4": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000047", + "x": 0, + "y": 2, + }, + }, + "shadow4brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000040", + "x": 0, + "y": 2, + }, + }, + "shadow64": { + "ambient": { + "blur": 8, + "color": "#00000066", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#0000007a", + "x": 0, + "y": 32, + }, + }, + "shadow64brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#00000040", + "x": 0, + "y": 32, + }, + }, + "shadow8": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000047", + "x": 0, + "y": 4, + }, + }, + "shadow8brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000040", + "x": 0, + "y": 4, + }, + }, + }, + "spacing": { + "l1": "20px", + "l2": "32px", + "m": "16px", + "s1": "8px", + "s2": "4px", + }, + "typography": { + "families": { + "cursive": "Helvetica Neue", + "monospace": "Courier New", + "numeric": "Helvetica Neue", + "primary": "Helvetica Neue", + "sansSerif": "Helvetica Neue", + "secondary": "Helvetica Neue", + "serif": "Helvetica Neue", + }, + "sizes": { + "body": 14, + "caption": 10, + "header": 20, + "hero": 28, + "heroLarge": 40, + "secondary": 12, + "subheader": 16, + }, + "variants": { + "body1": { + "face": "primary", + "size": 12, + "weight": "400", + }, + "body1Strong": { + "face": "primary", + "size": 12, + "weight": "600", + }, + "body2": { + "face": "primary", + "size": 14, + "weight": "400", + }, + "body2Strong": { + "face": "primary", + "size": 14, + "weight": "600", + }, + "bodySemibold": { + "face": "primary", + "size": 14, + "weight": "600", + }, + "bodyStandard": { + "face": "primary", + "size": 14, + "weight": "400", + }, + "caption1": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "caption1Strong": { + "face": "primary", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "captionStandard": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "display": { + "face": "primary", + "size": 40, + "weight": "600", + }, + "headerSemibold": { + "face": "primary", + "size": 20, + "weight": "600", + }, + "headerStandard": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "heroLargeSemibold": { + "face": "primary", + "size": 40, + "weight": "600", + }, + "heroLargeStandard": { + "face": "primary", + "size": 40, + "weight": "400", + }, + "heroSemibold": { + "face": "primary", + "size": 28, + "weight": "600", + }, + "heroStandard": { + "face": "primary", + "size": 28, + "weight": "400", + }, + "largeTitle": { + "face": "primary", + "size": 40, + "weight": "400", + }, + "secondarySemibold": { + "face": "primary", + "size": 12, + "weight": "600", + }, + "secondaryStandard": { + "face": "primary", + "size": 12, + "weight": "400", + }, + "subheaderSemibold": { + "face": "primary", + "size": 16, + "weight": "600", + }, + "subheaderStandard": { + "face": "primary", + "size": 16, + "weight": "400", + }, + "subtitle1": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "subtitle1Strong": { + "face": "primary", + "size": 20, + "weight": "600", + }, + "subtitle2": { + "face": "primary", + "size": 16, + "weight": "400", + }, + "subtitle2Strong": { + "face": "primary", + "size": 16, + "weight": "600", + }, + "title1": { + "face": "primary", + "size": 28, + "weight": "400", + }, + "title1Strong": { + "face": "primary", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", + }, + }, + "weights": { + "regular": "400", + "semiBold": "600", + }, + }, +} +`; + +exports[`defaultFluentTheme 1`] = ` +{ + "colors": { + "accentButtonBackground": "#0078d4", + "actionLink": "#242424", + "background": "#ffffff", + "bodyDivider": "#d6d6d6", + "bodyFrameBackground": "#ffffff", + "bodyFrameDivider": "#d6d6d6", + "bodyStandoutBackground": "#ffffff", + "bodyText": "#242424", + "bodyTextChecked": "#242424", + "brandBackground": "#0078d4", + "brandBackground2": "#eff6fc", + "brandBackground2Pressed": "#106ebe", + "brandBackground2Selected": "#005a9e", + "brandBackground3": "#eff6fc", + "brandBackgroundDisabled": "#d1d1d1", + "brandBackgroundHover": "#106ebe", + "brandBackgroundInverted": "#616161", + "brandBackgroundInvertedDisabled": "#f0f0f0", + "brandBackgroundPressed": "#106ebe", + "brandBackgroundSelected": "#005a9e", + "brandBackgroundStatic": "#0078d4", + "brandBackgroundTint": "#eff6fc", + "brandForeground1": "#0078d4", + "brandForeground1Disabled": "#757575", + "brandForeground1Pressed": "#004578", + "brandForeground1Selected": "#005a9e", + "brandForeground2": "#106ebe", + "brandForegroundDisabled1": "#757575", + "brandForegroundDisabled2": "#757575", + "brandForegroundLink": "#0078d4", + "brandForegroundLinkHover": "#106ebe", + "brandForegroundLinkPressed": "#004578", + "brandForegroundLinkSelected": "#005a9e", + "brandForegroundTint": "#106ebe", + "brandStroke1": "#0078d4", + "brandStroke1Pressed": "#004578", + "brandStroke1Selected": "#005a9e", + "brandStroke2": "#c7e0f4", + "brandStrokeTint": "#c7e0f4", + "brandedBackground": "#0078d4", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#f0f0f0", + "buttonBackgroundHovered": "#f5f5f5", + "buttonBackgroundPressed": "#ebebeb", + "buttonBorder": "#f0f0f0", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#242424", + "buttonTextChecked": "#242424", + "buttonTextDisabled": "#757575", + "buttonTextHovered": "#242424", + "buttonTextPressed": "#242424", + "checkboxBackground": "#0078d4", + "checkboxBackgroundDisabled": "#f0f0f0", + "checkboxBorderColor": "#616161", + "checkmarkColor": "#ffffff", + "compoundBrandBackground1": "#0078d4", + "compoundBrandBackground1Hover": "#106ebe", + "compoundBrandBackground1Pressed": "#004578", + "compoundBrandForeground1": "#0078d4", + "compoundBrandForeground1Hover": "#106ebe", + "compoundBrandForeground1Pressed": "#004578", + "compoundBrandStroke1": "#0078d4", + "compoundBrandStroke1Hover": "#106ebe", + "compoundBrandStroke1Pressed": "#004578", + "dangerBackground1": "#fdf6f6", + "dangerBackground2": "#f1bbbc", + "dangerBackground3": "#d13438", + "dangerBorder1": "#f1bbbc", + "dangerBorder2": "#d13438", + "dangerBorderActive": "#d13438", + "dangerForeground1": "#bc2f32", + "dangerForeground2": "#751d1f", + "dangerForeground3": "#d13438", + "dangerForegroundInverted": "#dc5e62", + "dangerStroke1": "#f1bbbc", + "defaultBackground": "#ffffff", + "defaultBorder": "#f0f0f0", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#242424", + "defaultCheckedHoveredBackground": "#f5f5f5", + "defaultCheckedHoveredContent": "#242424", + "defaultContent": "#242424", + "defaultDisabledBackground": "#f0f0f0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#757575", + "defaultDisabledIcon": "#757575", + "defaultFocusedBackground": "#f5f5f5", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#242424", + "defaultFocusedIcon": "#242424", + "defaultHoveredBackground": "#f5f5f5", + "defaultHoveredBorder": "#c7c7c7", + "defaultHoveredContent": "#242424", + "defaultHoveredIcon": "#242424", + "defaultHoveredSecondaryContent": "#424242", + "defaultIcon": "#242424", + "defaultPressedBackground": "#ebebeb", + "defaultPressedBorder": "#b3b3b3", + "defaultPressedContent": "#242424", + "defaultPressedIcon": "#242424", + "defaultPressedSecondaryContent": "#424242", + "disabledBackground": "#f0f0f0", + "disabledBodyText": "#757575", + "disabledText": "#757575", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#242424", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#242424", + "ghostContent": "#242424", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#757575", + "ghostDisabledIcon": "#757575", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#242424", + "ghostFocusedIcon": "#242424", + "ghostFocusedSecondaryContent": "#616161", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#242424", + "ghostHoveredIcon": "#242424", + "ghostHoveredSecondaryContent": "#424242", + "ghostIcon": "#242424", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#242424", + "ghostPressedIcon": "#242424", + "ghostPressedSecondaryContent": "#424242", + "ghostSecondaryContent": "#616161", + "inputBackground": "#ffffff", + "inputBorder": "#f0f0f0", + "inputFocusBorderAlt": "#0078d4", + "inputPlaceholderText": "#808080", + "inputText": "#242424", + "link": "#0078d4", + "linkHovered": "#106ebe", + "linkPressed": "#004578", + "listHeaderBackgroundHovered": "#f5f5f5", + "listHeaderBackgroundPressed": "#ebebeb", + "menuBackground": "#ffffff", + "menuDivider": "#d6d6d6", + "menuIcon": "#000000", + "menuItemBackgroundHovered": "#f5f5f5", + "menuItemBackgroundPressed": "#ebebeb", + "menuItemText": "#242424", + "menuItemTextHovered": "#242424", + "neutralBackground1": "#ffffff", + "neutralBackground1Hover": "#f5f5f5", + "neutralBackground1Pressed": "#ebebeb", + "neutralBackground1Selected": "#ebebeb", + "neutralBackground2": "#ffffff", + "neutralBackground2Hover": "#f0f0f0", + "neutralBackground2Pressed": "#ebebeb", + "neutralBackground2Selected": "#e6e6e6", + "neutralBackground3": "#f5f5f5", + "neutralBackground3Hover": "#ebebeb", + "neutralBackground3Pressed": "#d6d6d6", + "neutralBackground3Selected": "#e0e0e0", + "neutralBackground4": "#f0f0f0", + "neutralBackground4Hover": "#fafafa", + "neutralBackground4Pressed": "#f5f5f5", + "neutralBackground4Selected": "#ffffff", + "neutralBackground5": "#ebebeb", + "neutralBackground5Hover": "#f5f5f5", + "neutralBackground5Pressed": "#f0f0f0", + "neutralBackground5Selected": "#fafafa", + "neutralBackground6": "#e6e6e6", + "neutralBackgroundCanvas": "#ffffff", + "neutralBackgroundDarkStatic": "#242424", + "neutralBackgroundDisabled": "#f0f0f0", + "neutralBackgroundInverted": "#616161", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#f0f0f0", + "neutralForeground1": "#242424", + "neutralForeground1Hover": "#242424", + "neutralForeground1Pressed": "#242424", + "neutralForeground1Selected": "#242424", + "neutralForeground2": "#000000", + "neutralForeground2BrandHover": "#106ebe", + "neutralForeground2BrandPressed": "#004578", + "neutralForeground2BrandSelected": "#005a9e", + "neutralForeground2Hover": "#242424", + "neutralForeground2Pressed": "#242424", + "neutralForeground2Selected": "#242424", + "neutralForeground3": "#616161", + "neutralForeground3BrandHover": "#106ebe", + "neutralForeground3BrandPressed": "#004578", + "neutralForeground3BrandSelected": "#005a9e", + "neutralForeground3Hover": "#424242", + "neutralForeground3Pressed": "#424242", + "neutralForeground3Selected": "#424242", + "neutralForeground4": "#808080", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#757575", + "neutralForegroundDisabled1": "#757575", + "neutralForegroundDisabled2": "#757575", + "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#ffffff", + "neutralForegroundInvertedLinkHover": "#ffffff", + "neutralForegroundInvertedLinkPressed": "#ffffff", + "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#ffffff", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", + "neutralStencil1": "#e6e6e6", + "neutralStencil2": "#fafafa", + "neutralStroke1": "#f0f0f0", + "neutralStroke1Hover": "#c7c7c7", + "neutralStroke1Pressed": "#b3b3b3", + "neutralStroke1Selected": "#bdbdbd", + "neutralStroke2": "#d6d6d6", + "neutralStroke3": "#f0f0f0", + "neutralStrokeAccessible": "#616161", + "neutralStrokeAccessibleHover": "#575757", + "neutralStrokeAccessiblePressed": "#4d4d4d", + "neutralStrokeAccessibleSelected": "#0078d4", + "neutralStrokeDisabled": "#e0e0e0", + "neutralStrokeFocus1": "#ffffff", + "neutralStrokeFocus2": "#000000", + "outofofficeBackground1": "#fdf5fc", + "outofofficeBackground2": "#edbbe7", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#edbbe7", + "outofofficeBorder2": "#c239b3", + "outofofficeBorderActive": "#c239b3", + "outofofficeForeground1": "#af33a1", + "outofofficeForeground2": "#6d2064", + "outofofficeForeground3": "#c239b3", + "personaActivityGlow": "#0078d4", + "personaActivityRing": "#ffffff", + "presenceAvailable": "#0e700e", + "presenceAway": "#817400", + "presenceDnd": "#bc2f32", + "presenceOof": "#af33a1", + "primaryButtonBackground": "#0078d4", + "primaryButtonBackgroundDisabled": "#f0f0f0", + "primaryButtonBackgroundHovered": "#106ebe", + "primaryButtonBackgroundPressed": "#106ebe", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#000000", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#757575", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#f1bbbc", + "redBackground3": "#d13438", + "redBorder1": "#f1bbbc", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#751d1f", + "redForeground3": "#d13438", + "severeBackground1": "#fdf6f3", + "severeBackground2": "#f4bfab", + "severeBackground3": "#da3b01", + "severeBorder1": "#f4bfab", + "severeBorder2": "#da3b01", + "severeBorderActive": "#da3b01", + "severeForeground1": "#c43501", + "severeForeground2": "#7a2101", + "severeForeground3": "#da3b01", + "severeStroke1": "#f4bfab", + "strokeFocus1": "#ffffff", + "strokeFocus2": "#000000", + "subText": "#000000", "subtleBackground": "#00000000", - "subtleBackgroundHover": "#383838", - "subtleBackgroundPressed": "#2e2e2e", - "subtleBackgroundSelected": "#333333", - "successBackground1": "#052505", - "successBackground2": "#094509", + "subtleBackgroundHover": "#f5f5f5", + "subtleBackgroundPressed": "#e0e0e0", + "subtleBackgroundSelected": "#ebebeb", + "successBackground1": "#f1faf1", + "successBackground2": "#9fd89f", "successBackground3": "#107c10", - "successBorder1": "#107c10", - "successBorder2": "#9fd89f", - "successBorderActive": "#54b054", - "successForeground1": "#54b054", - "successForeground2": "#9fd89f", - "successForeground3": "#9fd89f", - "successForegroundInverted": "#107c10", + "successBorder1": "#9fd89f", + "successBorder2": "#107c10", + "successBorderActive": "#107c10", + "successForeground1": "#0e700e", + "successForeground2": "#094509", + "successForeground3": "#107c10", + "successForegroundInverted": "#359b35", + "successStroke1": "#9fd89f", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -267,33 +987,34 @@ exports[`defaultFluentDarkTheme 1`] = ` "transparentStroke": "#00000000", "transparentStrokeDisabled": "#00000000", "transparentStrokeInteractive": "#00000000", - "variantBorder": "#292827", - "warningBackground1": "#4c4400", - "warningBackground2": "#817400", + "variantBorder": "#d6d6d6", + "warningBackground1": "#fffef5", + "warningBackground2": "#fef7b2", "warningBackground3": "#fde300", - "warningBorder1": "#fde300", - "warningBorder2": "#fdea3d", - "warningBorderActive": "#feee66", - "warningForeground1": "#feee66", - "warningForeground2": "#fef7b2", - "warningForeground3": "#fdea3d", - "warningForegroundInverted": "#817400", + "warningBorder1": "#fef7b2", + "warningBorder2": "#fde300", + "warningBorderActive": "#fde300", + "warningForeground1": "#817400", + "warningForeground2": "#817400", + "warningForeground3": "#fde300", + "warningForegroundInverted": "#fef7b2", + "warningStroke1": "#fef7b2", }, "components": {}, "host": { - "appearance": "dark", + "appearance": "light", }, "shadows": { "shadow16": { "ambient": { "blur": 2, - "color": "#0000003d", + "color": "#0000001f", "x": 0, "y": 0, }, "key": { "blur": 16, - "color": "#00000047", + "color": "#00000024", "x": 0, "y": 8, }, @@ -315,13 +1036,13 @@ exports[`defaultFluentDarkTheme 1`] = ` "shadow2": { "ambient": { "blur": 2, - "color": "#0000003d", + "color": "#0000001f", "x": 0, "y": 0, }, "key": { "blur": 2, - "color": "#00000047", + "color": "#00000024", "x": 0, "y": 1, }, @@ -329,13 +1050,13 @@ exports[`defaultFluentDarkTheme 1`] = ` "shadow28": { "ambient": { "blur": 8, - "color": "#00000066", + "color": "#00000033", "x": 0, "y": 0, }, "key": { "blur": 28, - "color": "#0000007a", + "color": "#0000003d", "x": 0, "y": 14, }, @@ -371,13 +1092,13 @@ exports[`defaultFluentDarkTheme 1`] = ` "shadow4": { "ambient": { "blur": 2, - "color": "#0000003d", + "color": "#0000001f", "x": 0, "y": 0, }, "key": { "blur": 4, - "color": "#00000047", + "color": "#00000024", "x": 0, "y": 2, }, @@ -399,13 +1120,13 @@ exports[`defaultFluentDarkTheme 1`] = ` "shadow64": { "ambient": { "blur": 8, - "color": "#00000066", + "color": "#00000033", "x": 0, "y": 0, }, "key": { "blur": 64, - "color": "#0000007a", + "color": "#0000003d", "x": 0, "y": 32, }, @@ -427,13 +1148,13 @@ exports[`defaultFluentDarkTheme 1`] = ` "shadow8": { "ambient": { "blur": 2, - "color": "#0000003d", + "color": "#0000001f", "x": 0, "y": 0, }, "key": { "blur": 8, - "color": "#00000047", + "color": "#00000024", "x": 0, "y": 4, }, @@ -462,13 +1183,13 @@ exports[`defaultFluentDarkTheme 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", - "primary": "System", - "sansSerif": "System", - "secondary": "System", - "serif": "System", + "cursive": "Helvetica Neue", + "monospace": "Courier New", + "numeric": "Helvetica Neue", + "primary": "Helvetica Neue", + "sansSerif": "Helvetica Neue", + "secondary": "Helvetica Neue", + "serif": "Helvetica Neue", }, "sizes": { "body": 14, @@ -482,138 +1203,153 @@ exports[`defaultFluentDarkTheme 1`] = ` "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { @@ -624,852 +1360,325 @@ exports[`defaultFluentDarkTheme 1`] = ` } `; -exports[`defaultFluentHighConstrastTheme 1`] = ` +exports[`high contrast dark theme 1`] = ` { "colors": { - "accentButtonBackground": "#000000", - "actionLink": "#ffff00", + "accentButtonBackground": "#0086f0", + "actionLink": "#ffffff", "background": "#000000", - "bodyDivider": "#ffffff", + "bodyDivider": "#a8a8a8", "bodyFrameBackground": "#000000", - "bodyFrameDivider": "#000000", - "bodyStandoutBackground": "#000000", + "bodyFrameDivider": "#a8a8a8", + "bodyStandoutBackground": "#575757", "bodyText": "#ffffff", - "bodyTextChecked": "#000000", - "brandBackground": { - "semantic": [ - "SystemColorButtonFaceColor", - ], - }, - "brandBackground2": { - "semantic": [ - "SystemColorButtonFaceColor", - ], - }, - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "brandBackgroundPressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "brandBackgroundSelected": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "brandBackgroundStatic": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "brandForeground1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": { - "semantic": [ - "SystemColorButtonTextColor", - ], - }, - "brandForegroundLink": { - "semantic": [ - "SystemColorHotlightColor", - ], - }, - "brandForegroundLinkHover": { - "semantic": [ - "SystemColorHotlightColor", - ], - }, - "brandForegroundLinkPressed": { - "semantic": [ - "SystemColorHotlightColor", - ], - }, - "brandForegroundLinkSelected": { - "semantic": [ - "SystemColorHotlightColor", - ], - }, - "brandStroke1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "brandStroke2": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "brandedBackground": "#000000", - "brandedDisabledBorder": "#3ff23f", + "bodyTextChecked": "#ffffff", + "brandBackground": "#0086f0", + "brandBackground2": "#092c47", + "brandBackground2Pressed": "#1890f1", + "brandBackground2Selected": "#3aa0f3", + "brandBackground3": "#092c47", + "brandBackgroundDisabled": "#575757", + "brandBackgroundHover": "#1890f1", + "brandBackgroundInverted": "#ffffff", + "brandBackgroundInvertedDisabled": "#575757", + "brandBackgroundPressed": "#1890f1", + "brandBackgroundSelected": "#3aa0f3", + "brandBackgroundStatic": "#0086f0", + "brandBackgroundTint": "#092c47", + "brandForeground1": "#0086f0", + "brandForeground1Disabled": "#c2c2c2", + "brandForeground1Pressed": "#6cb8f6", + "brandForeground1Selected": "#3aa0f3", + "brandForeground2": "#092c47", + "brandForegroundDisabled1": "#c2c2c2", + "brandForegroundDisabled2": "#c2c2c2", + "brandForegroundLink": "#043862", + "brandForegroundLinkHover": "#092c47", + "brandForegroundLinkPressed": "#0078d4", + "brandForegroundLinkSelected": "#092c47", + "brandForegroundTint": "#092c47", + "brandStroke1": "#0086f0", + "brandStroke1Pressed": "#6cb8f6", + "brandStroke1Selected": "#3aa0f3", + "brandStroke2": "#004c87", + "brandStrokeTint": "#004c87", + "brandedBackground": "#0086f0", + "brandedDisabledBorder": "#d6d6d6", "brandedFocusedSecondaryContent": "#ffffff", - "brandedHoveredSecondaryContent": "#000000", - "brandedPressedSecondaryContent": "#000000", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", "brandedSecondaryContent": "#ffffff", "buttonBackground": "#000000", - "buttonBackgroundChecked": "#1aebff", - "buttonBackgroundDisabled": "#000000", - "buttonBackgroundHovered": "#1aebff", - "buttonBackgroundPressed": "#1aebff", - "buttonBorder": "#ffffff", - "buttonBorderDisabled": "#3ff23f", + "buttonBackgroundChecked": "#383838", + "buttonBackgroundDisabled": "#575757", + "buttonBackgroundHovered": "#3d3d3d", + "buttonBackgroundPressed": "#5c5c5c", + "buttonBorder": "#adadad", + "buttonBorderDisabled": "#525252", "buttonBorderFocused": "#ffffff", "buttonText": "#ffffff", - "buttonTextChecked": "#000000", - "buttonTextDisabled": "#3ff23f", - "buttonTextHovered": "#000000", - "buttonTextPressed": "#000000", - "checkboxBackground": "#000000", - "checkboxBackgroundDisabled": "#000000", - "checkboxBorderColor": "#ffffff", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#b8b8b8", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#0086f0", + "checkboxBackgroundDisabled": "#575757", + "checkboxBorderColor": "#d6d6d6", "checkmarkColor": "#ffffff", - "compoundBrandBackground1": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandBackground1Hover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandBackground1Pressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandForeground1": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandForeground1Hover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandForeground1Pressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandStroke1": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandStroke1Hover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandStroke1Pressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "dangerBackground1": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "dangerBackground2": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "dangerBackground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "dangerBorder1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "dangerBorder2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "dangerBorderActive": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "dangerForeground1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "dangerForeground2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "dangerForeground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "dangerForegroundInverted": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, + "compoundBrandBackground1": "#0086f0", + "compoundBrandBackground1Hover": "#1890f1", + "compoundBrandBackground1Pressed": "#6cb8f6", + "compoundBrandForeground1": "#043862", + "compoundBrandForeground1Hover": "#092c47", + "compoundBrandForeground1Pressed": "#0078d4", + "compoundBrandStroke1": "#0086f0", + "compoundBrandStroke1Hover": "#1890f1", + "compoundBrandStroke1Pressed": "#6cb8f6", + "dangerBackground1": "#3f1011", + "dangerBackground2": "#751d1f", + "dangerBackground3": "#d13438", + "dangerBorder1": "#d13438", + "dangerBorder2": "#dc5e62", + "dangerBorderActive": "#e37d80", + "dangerForeground1": "#e37d80", + "dangerForeground2": "#f1bbbc", + "dangerForeground3": "#e37d80", + "dangerForegroundInverted": "#d13438", + "dangerStroke1": "#d13438", "defaultBackground": "#000000", - "defaultBorder": "#ffffff", - "defaultCheckedBackground": "#1aebff", - "defaultCheckedContent": "#000000", - "defaultCheckedHoveredBackground": "#1aebff", - "defaultCheckedHoveredContent": "#000000", + "defaultBorder": "#adadad", + "defaultCheckedBackground": "#383838", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#3d3d3d", + "defaultCheckedHoveredContent": "#ffffff", "defaultContent": "#ffffff", - "defaultDisabledBackground": "#000000", - "defaultDisabledBorder": "#3ff23f", - "defaultDisabledContent": "#3ff23f", - "defaultDisabledIcon": "#3ff23f", - "defaultFocusedBackground": "#000000", + "defaultDisabledBackground": "#575757", + "defaultDisabledBorder": "#525252", + "defaultDisabledContent": "#b8b8b8", + "defaultDisabledIcon": "#b8b8b8", + "defaultFocusedBackground": "#3d3d3d", "defaultFocusedBorder": "#ffffff", "defaultFocusedContent": "#ffffff", "defaultFocusedIcon": "#ffffff", - "defaultHoveredBackground": "#1aebff", - "defaultHoveredBorder": "#1aebff", - "defaultHoveredContent": "#000000", - "defaultHoveredIcon": "#000000", - "defaultHoveredSecondaryContent": "#000000", + "defaultHoveredBackground": "#3d3d3d", + "defaultHoveredBorder": "#757575", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#d6d6d6", "defaultIcon": "#ffffff", - "defaultPressedBackground": "#1aebff", - "defaultPressedBorder": "#1aebff", - "defaultPressedContent": "#000000", - "defaultPressedIcon": "#000000", - "defaultPressedSecondaryContent": "#000000", - "disabledBackground": "#000000", - "disabledBodyText": "#3ff23f", - "disabledText": "#3ff23f", - "errorText": "#ffffff", + "defaultPressedBackground": "#5c5c5c", + "defaultPressedBorder": "#6b6b6b", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#d6d6d6", + "disabledBackground": "#575757", + "disabledBodyText": "#b8b8b8", + "disabledText": "#b8b8b8", + "errorText": "#e37d80", "focusBorder": "#ffffff", - "ghostBackground": "#000000", - "ghostBorder": "#000000", - "ghostCheckedBackground": "#1aebff", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#1aebff", - "ghostCheckedHoveredBorder": "#000000", - "ghostCheckedHoveredContent": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#3aa0f3", + "ghostCheckedBackground": "#383838", + "ghostCheckedContent": "#ffffff", + "ghostCheckedHoveredBackground": "#3d3d3d", + "ghostCheckedHoveredBorder": "#3aa0f3", + "ghostCheckedHoveredContent": "#ffffff", "ghostContent": "#ffffff", - "ghostDisabledBackground": "#000000", - "ghostDisabledBorder": "#000000", - "ghostDisabledContent": "#3ff23f", - "ghostDisabledIcon": "#3ff23f", - "ghostFocusedBackground": "#000000", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#d6d6d6", + "ghostDisabledContent": "#b8b8b8", + "ghostDisabledIcon": "#b8b8b8", + "ghostFocusedBackground": "#3d3d3d", "ghostFocusedBorder": "#ffffff", "ghostFocusedContent": "#ffffff", "ghostFocusedIcon": "#ffffff", - "ghostFocusedSecondaryContent": "#ffffff", - "ghostHoveredBackground": "#1aebff", - "ghostHoveredBorder": "#1aebff", - "ghostHoveredContent": "#000000", - "ghostHoveredIcon": "#000000", - "ghostHoveredSecondaryContent": "#000000", + "ghostFocusedSecondaryContent": "#d6d6d6", + "ghostHoveredBackground": "#3d3d3d", + "ghostHoveredBorder": "#3aa0f3", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#d6d6d6", "ghostIcon": "#ffffff", - "ghostPressedBackground": "#1aebff", - "ghostPressedBorder": "#1aebff", - "ghostPressedContent": "#000000", - "ghostPressedIcon": "#000000", - "ghostPressedSecondaryContent": "#000000", - "ghostSecondaryContent": "#ffffff", + "ghostPressedBackground": "#1f1f1f", + "ghostPressedBorder": "#3aa0f3", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#d6d6d6", + "ghostSecondaryContent": "#d6d6d6", "inputBackground": "#000000", - "inputBorder": "#ffffff", - "inputFocusBorderAlt": "#ffffff", - "inputPlaceholderText": "#ffffff", + "inputBorder": "#adadad", + "inputFocusBorderAlt": "#0086f0", + "inputPlaceholderText": "#d6d6d6", "inputText": "#ffffff", - "link": "#ffff00", - "linkHovered": "#ffffff", - "linkPressed": "#ffffff", - "listHeaderBackgroundHovered": "#1aebff", - "listHeaderBackgroundPressed": "#1aebff", + "link": "#043862", + "linkHovered": "#092c47", + "linkPressed": "#0078d4", + "listHeaderBackgroundHovered": "#3d3d3d", + "listHeaderBackgroundPressed": "#5c5c5c", "menuBackground": "#000000", - "menuDivider": "#ffffff", + "menuDivider": "#a8a8a8", "menuIcon": "#ffffff", - "menuItemBackgroundHovered": "#1aebff", - "menuItemBackgroundPressed": "#1aebff", + "menuItemBackgroundHovered": "#3d3d3d", + "menuItemBackgroundPressed": "#5c5c5c", "menuItemText": "#ffffff", - "menuItemTextHovered": "#000000", - "neutralBackground1": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "neutralBackground1Hover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground1Pressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground1Selected": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground2": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "neutralBackground2Hover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground2Pressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground2Selected": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground3": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "neutralBackground3Hover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground3Pressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground3Selected": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground4": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "neutralBackground4Hover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground4Pressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground4Selected": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground5": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "neutralBackground5Hover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground5Pressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground5Selected": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground6": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "neutralBackgroundDisabled": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "neutralBackgroundInverted": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "neutralForeground1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "neutralForeground1Hover": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground1Pressed": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground1Selected": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "neutralForeground2BrandHover": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground2BrandPressed": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground2BrandSelected": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground2Hover": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground2Pressed": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground2Selected": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "neutralForeground3BrandHover": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground3BrandPressed": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground3BrandSelected": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground3Hover": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground3Pressed": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground3Selected": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForeground4": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "neutralForegroundDisabled": { - "semantic": [ - "SystemColorGrayTextColor", - ], - }, - "neutralForegroundInverted": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "neutralForegroundInvertedLink": { - "semantic": [ - "SystemColorHotlightColor", - ], - }, - "neutralForegroundInvertedLinkHover": { - "semantic": [ - "SystemColorHotlightColor", - ], - }, - "neutralForegroundInvertedLinkPressed": { - "semantic": [ - "SystemColorHotlightColor", - ], - }, - "neutralForegroundInvertedLinkSelected": { - "semantic": [ - "SystemColorHotlightColor", - ], - }, - "neutralForegroundOnBrand": { - "semantic": [ - "SystemColorButtonTextColor", - ], - }, - "neutralForegroundOnBrandHover": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForegroundOnBrandPressed": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralForegroundOnBrandSelected": { - "semantic": [ - "SystemColorHighlightTextColor", - ], - }, - "neutralStencil1": "#141414", - "neutralStencil2": "#858585", - "neutralStroke1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "neutralStroke1Hover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralStroke1Pressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralStroke1Selected": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralStroke2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "neutralStroke3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "neutralStrokeAccessible": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "neutralStrokeAccessibleHover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralStrokeAccessiblePressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralStrokeAccessibleSelected": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "neutralStrokeDisabled": { - "semantic": [ - "SystemColorGrayTextColor", - ], - }, - "outofofficeBackground1": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "outofofficeBackground2": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "outofofficeBackground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "outofofficeBorder1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "outofofficeBorder2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "outofofficeBorderActive": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "outofofficeForeground1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "outofofficeForeground2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "outofofficeForeground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "personaActivityGlow": "transparent", - "personaActivityRing": "#ffffff", - "primaryButtonBackground": "#000000", - "primaryButtonBackgroundDisabled": "#000000", - "primaryButtonBackgroundHovered": "#1aebff", - "primaryButtonBackgroundPressed": "#1aebff", - "primaryButtonBorder": "#ffffff", + "menuItemTextHovered": "#ffffff", + "neutralBackground1": "#000000", + "neutralBackground1Hover": "#3d3d3d", + "neutralBackground1Pressed": "#5c5c5c", + "neutralBackground1Selected": "#383838", + "neutralBackground2": "#575757", + "neutralBackground2Hover": "#333333", + "neutralBackground2Pressed": "#707070", + "neutralBackground2Selected": "#2e2e2e", + "neutralBackground3": "#575757", + "neutralBackground3Hover": "#292929", + "neutralBackground3Pressed": "#0a0a0a", + "neutralBackground3Selected": "#242424", + "neutralBackground4": "#1f1f1f", + "neutralBackground4Hover": "#1f1f1f", + "neutralBackground4Pressed": "#000000", + "neutralBackground4Selected": "#1a1a1a", + "neutralBackground5": "#5c5c5c", + "neutralBackground5Hover": "#141414", + "neutralBackground5Pressed": "#050505", + "neutralBackground5Selected": "#0f0f0f", + "neutralBackground6": "#333333", + "neutralBackgroundCanvas": "#000000", + "neutralBackgroundDarkStatic": "#3d3d3d", + "neutralBackgroundDisabled": "#575757", + "neutralBackgroundInverted": "#ffffff", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#575757", + "neutralForeground1": "#ffffff", + "neutralForeground1Hover": "#ffffff", + "neutralForeground1Pressed": "#ffffff", + "neutralForeground1Selected": "#ffffff", + "neutralForeground2": "#ffffff", + "neutralForeground2BrandHover": "#092c47", + "neutralForeground2BrandPressed": "#0078d4", + "neutralForeground2BrandSelected": "#092c47", + "neutralForeground2Hover": "#ffffff", + "neutralForeground2Pressed": "#ffffff", + "neutralForeground2Selected": "#ffffff", + "neutralForeground3": "#d6d6d6", + "neutralForeground3BrandHover": "#092c47", + "neutralForeground3BrandPressed": "#0078d4", + "neutralForeground3BrandSelected": "#092c47", + "neutralForeground3Hover": "#d6d6d6", + "neutralForeground3Pressed": "#d6d6d6", + "neutralForeground3Selected": "#d6d6d6", + "neutralForeground4": "#d6d6d6", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#b8b8b8", + "neutralForegroundDisabled1": "#b8b8b8", + "neutralForegroundDisabled2": "#b8b8b8", + "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#292929", + "neutralForegroundInvertedLinkHover": "#292929", + "neutralForegroundInvertedLinkPressed": "#292929", + "neutralForegroundInvertedLinkSelected": "#292929", + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#ffffff", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", + "neutralStencil1": "#333333", + "neutralStencil2": "#575757", + "neutralStroke1": "#adadad", + "neutralStroke1Hover": "#757575", + "neutralStroke1Pressed": "#6b6b6b", + "neutralStroke1Selected": "#707070", + "neutralStroke2": "#a8a8a8", + "neutralStroke3": "#adadad", + "neutralStrokeAccessible": "#d6d6d6", + "neutralStrokeAccessibleHover": "#bdbdbd", + "neutralStrokeAccessiblePressed": "#b3b3b3", + "neutralStrokeAccessibleSelected": "#0086f0", + "neutralStrokeDisabled": "#525252", + "neutralStrokeFocus1": "#000000", + "neutralStrokeFocus2": "#ffffff", + "outofofficeBackground1": "#3a1136", + "outofofficeBackground2": "#6d2064", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#c239b3", + "outofofficeBorder2": "#d161c4", + "outofofficeBorderActive": "#da7ed0", + "outofofficeForeground1": "#da7ed0", + "outofofficeForeground2": "#edbbe7", + "outofofficeForeground3": "#d161c4", + "personaActivityGlow": "#0086f0", + "personaActivityRing": "#000000", + "presenceAvailable": "#54b054", + "presenceAway": "#feee66", + "presenceDnd": "#e37d80", + "presenceOof": "#da7ed0", + "primaryButtonBackground": "#0086f0", + "primaryButtonBackgroundDisabled": "#575757", + "primaryButtonBackgroundHovered": "#1890f1", + "primaryButtonBackgroundPressed": "#1890f1", + "primaryButtonBorder": "#3aa0f3", "primaryButtonBorderFocused": "#ffffff", "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#3ff23f", - "primaryButtonTextHovered": "#000000", - "primaryButtonTextPressed": "#000000", - "severeBackground1": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "severeBackground2": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "severeBackground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "severeBorder1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "severeBorder2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "severeBorderActive": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "severeForeground1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "severeForeground2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "severeForeground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "strokeFocus1": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "strokeFocus2": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, + "primaryButtonTextDisabled": "#b8b8b8", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#751d1f", + "redBackground3": "#d13438", + "redBorder1": "#d13438", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#f1bbbc", + "redForeground3": "#e37d80", + "severeBackground1": "#411200", + "severeBackground2": "#7a2101", + "severeBackground3": "#da3b01", + "severeBorder1": "#da3b01", + "severeBorder2": "#e9835e", + "severeBorderActive": "#e9835e", + "severeForeground1": "#e9835e", + "severeForeground2": "#f4bfab", + "severeForeground3": "#e9835e", + "severeStroke1": "#da3b01", + "strokeFocus1": "#000000", + "strokeFocus2": "#ffffff", "subText": "#ffffff", "subtleBackground": "#00000000", - "subtleBackgroundHover": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "subtleBackgroundPressed": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "subtleBackgroundSelected": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "successBackground1": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "successBackground2": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "successBackground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "successBorder1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "successBorder2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "successBorderActive": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "successForeground1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "successForeground2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "successForeground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "successForegroundInverted": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, + "subtleBackgroundHover": "#3d3d3d", + "subtleBackgroundPressed": "#1f1f1f", + "subtleBackgroundSelected": "#383838", + "successBackground1": "#052505", + "successBackground2": "#094509", + "successBackground3": "#107c10", + "successBorder1": "#107c10", + "successBorder2": "#9fd89f", + "successBorderActive": "#54b054", + "successForeground1": "#54b054", + "successForeground2": "#9fd89f", + "successForeground3": "#9fd89f", + "successForegroundInverted": "#107c10", + "successStroke1": "#107c10", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", "transparentBackgroundSelected": "#00000000", - "transparentStroke": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "transparentStrokeDisabled": { - "semantic": [ - "SystemColorGrayTextColor", - ], - }, - "transparentStrokeInteractive": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "variantBorder": "#ffffff", - "warningBackground1": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "warningBackground2": { - "semantic": [ - "SystemColorWindowColor", - ], - }, - "warningBackground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "warningBorder1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "warningBorder2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "warningBorderActive": { - "semantic": [ - "SystemColorHighlightColor", - ], - }, - "warningForeground1": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "warningForeground2": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "warningForeground3": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, - "warningForegroundInverted": { - "semantic": [ - "SystemColorWindowTextColor", - ], - }, + "transparentStroke": "#3aa0f3", + "transparentStrokeDisabled": "#d6d6d6", + "transparentStrokeInteractive": "#a8a8a8", + "variantBorder": "#a8a8a8", + "warningBackground1": "#4c4400", + "warningBackground2": "#817400", + "warningBackground3": "#fde300", + "warningBorder1": "#fde300", + "warningBorder2": "#fdea3d", + "warningBorderActive": "#feee66", + "warningForeground1": "#feee66", + "warningForeground2": "#fef7b2", + "warningForeground3": "#fdea3d", + "warningForegroundInverted": "#817400", + "warningStroke1": "#fde300", }, "components": {}, "host": { @@ -1654,13 +1863,13 @@ exports[`defaultFluentHighConstrastTheme 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", - "primary": "System", - "sansSerif": "System", - "secondary": "System", - "serif": "System", + "cursive": "Helvetica Neue", + "monospace": "Courier New", + "numeric": "Helvetica Neue", + "primary": "Helvetica Neue", + "sansSerif": "Helvetica Neue", + "secondary": "Helvetica Neue", + "serif": "Helvetica Neue", }, "sizes": { "body": 14, @@ -1674,138 +1883,153 @@ exports[`defaultFluentHighConstrastTheme 1`] = ` "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { @@ -1816,67 +2040,80 @@ exports[`defaultFluentHighConstrastTheme 1`] = ` } `; -exports[`defaultFluentTheme 1`] = ` +exports[`high contrast light theme 1`] = ` { "colors": { - "accentButtonBackground": "#185abd", - "actionLink": "#323130", + "accentButtonBackground": "#0078d4", + "actionLink": "#000000", "background": "#ffffff", - "bodyDivider": "#edebe9", + "bodyDivider": "#000000", "bodyFrameBackground": "#ffffff", - "bodyFrameDivider": "#edebe9", - "bodyStandoutBackground": "#faf9f8", - "bodyText": "#323130", + "bodyFrameDivider": "#000000", + "bodyStandoutBackground": "#ffffff", + "bodyText": "#000000", "bodyTextChecked": "#000000", - "brandBackground": "#185abd", + "brandBackground": "#0078d4", "brandBackground2": "#eff6fc", - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": "#1651aa", - "brandBackgroundPressed": "#004578", - "brandBackgroundSelected": "#13458f", - "brandBackgroundStatic": "#185abd", - "brandForeground1": "#185abd", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": "#1651aa", - "brandForegroundLink": "#1651aa", - "brandForegroundLinkHover": "#13458f", + "brandBackground2Pressed": "#106ebe", + "brandBackground2Selected": "#005a9e", + "brandBackground3": "#eff6fc", + "brandBackgroundDisabled": "#d1d1d1", + "brandBackgroundHover": "#106ebe", + "brandBackgroundInverted": "#616161", + "brandBackgroundInvertedDisabled": "#f0f0f0", + "brandBackgroundPressed": "#106ebe", + "brandBackgroundSelected": "#005a9e", + "brandBackgroundStatic": "#0078d4", + "brandBackgroundTint": "#eff6fc", + "brandForeground1": "#0078d4", + "brandForeground1Disabled": "#757575", + "brandForeground1Pressed": "#004578", + "brandForeground1Selected": "#005a9e", + "brandForeground2": "#106ebe", + "brandForegroundDisabled1": "#757575", + "brandForegroundDisabled2": "#757575", + "brandForegroundLink": "#0078d4", + "brandForegroundLinkHover": "#106ebe", "brandForegroundLinkPressed": "#004578", - "brandForegroundLinkSelected": "#1651aa", - "brandStroke1": "#185abd", - "brandStroke2": "#d2e0f4", - "brandedBackground": "#185abd", - "brandedDisabledBorder": "#f3f2f1", - "brandedFocusedSecondaryContent": "#faf9f8", - "brandedHoveredSecondaryContent": "#faf9f8", - "brandedPressedSecondaryContent": "#faf9f8", - "brandedSecondaryContent": "#faf9f8", - "buttonBackground": "#f3f2f1", - "buttonBackgroundChecked": "#c8c6c4", - "buttonBackgroundDisabled": "#f3f2f1", - "buttonBackgroundHovered": "#edebe9", - "buttonBackgroundPressed": "#edebe9", - "buttonBorder": "#8a8886", - "buttonBorderDisabled": "#f3f2f1", - "buttonBorderFocused": "#8a8886", - "buttonText": "#323130", - "buttonTextChecked": "#201f1e", - "buttonTextDisabled": "#a19f9d", - "buttonTextHovered": "#201f1e", - "buttonTextPressed": "#201f1e", - "checkboxBackground": "#185abd", - "checkboxBackgroundDisabled": "#f3f2f1", - "checkboxBorderColor": "#8a8886", + "brandForegroundLinkSelected": "#005a9e", + "brandForegroundTint": "#106ebe", + "brandStroke1": "#0078d4", + "brandStroke1Pressed": "#004578", + "brandStroke1Selected": "#005a9e", + "brandStroke2": "#c7e0f4", + "brandStrokeTint": "#c7e0f4", + "brandedBackground": "#0078d4", + "brandedDisabledBorder": "#bdbdbd", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#f0f0f0", + "buttonBackgroundHovered": "#f5f5f5", + "buttonBackgroundPressed": "#ebebeb", + "buttonBorder": "#616161", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#000000", + "buttonTextChecked": "#000000", + "buttonTextDisabled": "#757575", + "buttonTextHovered": "#000000", + "buttonTextPressed": "#000000", + "checkboxBackground": "#0078d4", + "checkboxBackgroundDisabled": "#f0f0f0", + "checkboxBorderColor": "#242424", "checkmarkColor": "#ffffff", - "compoundBrandBackground1": "#185abd", - "compoundBrandBackground1Hover": "#1651aa", - "compoundBrandBackground1Pressed": "#13458f", - "compoundBrandForeground1": "#185abd", - "compoundBrandForeground1Hover": "#1651aa", - "compoundBrandForeground1Pressed": "#13458f", - "compoundBrandStroke1": "#185abd", - "compoundBrandStroke1Hover": "#1651aa", - "compoundBrandStroke1Pressed": "#13458f", + "compoundBrandBackground1": "#0078d4", + "compoundBrandBackground1Hover": "#106ebe", + "compoundBrandBackground1Pressed": "#004578", + "compoundBrandForeground1": "#0078d4", + "compoundBrandForeground1Hover": "#106ebe", + "compoundBrandForeground1Pressed": "#004578", + "compoundBrandStroke1": "#0078d4", + "compoundBrandStroke1Hover": "#106ebe", + "compoundBrandStroke1Pressed": "#004578", "dangerBackground1": "#fdf6f6", "dangerBackground2": "#f1bbbc", "dangerBackground3": "#d13438", @@ -1887,90 +2124,91 @@ exports[`defaultFluentTheme 1`] = ` "dangerForeground2": "#751d1f", "dangerForeground3": "#d13438", "dangerForegroundInverted": "#dc5e62", - "defaultBackground": "#f3f2f1", - "defaultBorder": "#8a8886", - "defaultCheckedBackground": "#c8c6c4", - "defaultCheckedContent": "#201f1e", - "defaultCheckedHoveredBackground": "#edebe9", - "defaultCheckedHoveredContent": "#201f1e", - "defaultContent": "#323130", - "defaultDisabledBackground": "#f3f2f1", - "defaultDisabledBorder": "#f3f2f1", - "defaultDisabledContent": "#a19f9d", - "defaultDisabledIcon": "#a19f9d", - "defaultFocusedBackground": "#edebe9", - "defaultFocusedBorder": "#8a8886", - "defaultFocusedContent": "#201f1e", - "defaultFocusedIcon": "#201f1e", - "defaultHoveredBackground": "#edebe9", - "defaultHoveredBorder": "#8a8886", - "defaultHoveredContent": "#201f1e", - "defaultHoveredIcon": "#201f1e", - "defaultHoveredSecondaryContent": "#a19f9d", - "defaultIcon": "#323130", - "defaultPressedBackground": "#edebe9", - "defaultPressedBorder": "#8a8886", - "defaultPressedContent": "#201f1e", - "defaultPressedIcon": "#201f1e", - "defaultPressedSecondaryContent": "#a19f9d", - "disabledBackground": "#f3f2f1", - "disabledBodyText": "#a19f9d", - "disabledText": "#a19f9d", - "errorText": "#a4262c", - "focusBorder": "#605e5c", - "ghostBackground": "#ffffff", - "ghostBorder": "#ffffff", - "ghostCheckedBackground": "#edebe9", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#f3f2f1", - "ghostCheckedHoveredBorder": "#201f1e", - "ghostCheckedHoveredContent": "#201f1e", - "ghostContent": "#323130", - "ghostDisabledBackground": "#ffffff", - "ghostDisabledBorder": "#ffffff", - "ghostDisabledContent": "#a19f9d", - "ghostDisabledIcon": "#a19f9d", - "ghostFocusedBackground": "#f3f2f1", - "ghostFocusedBorder": "#8a8886", - "ghostFocusedContent": "#201f1e", - "ghostFocusedIcon": "#201f1e", - "ghostFocusedSecondaryContent": "#605e5c", - "ghostHoveredBackground": "#f3f2f1", - "ghostHoveredBorder": "#f3f2f1", - "ghostHoveredContent": "#201f1e", - "ghostHoveredIcon": "#201f1e", - "ghostHoveredSecondaryContent": "#605e5c", - "ghostIcon": "#323130", - "ghostPressedBackground": "#edebe9", - "ghostPressedBorder": "#edebe9", - "ghostPressedContent": "#201f1e", - "ghostPressedIcon": "#201f1e", - "ghostPressedSecondaryContent": "#605e5c", - "ghostSecondaryContent": "#605e5c", + "dangerStroke1": "#f1bbbc", + "defaultBackground": "#ffffff", + "defaultBorder": "#616161", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#000000", + "defaultCheckedHoveredBackground": "#f5f5f5", + "defaultCheckedHoveredContent": "#000000", + "defaultContent": "#000000", + "defaultDisabledBackground": "#f0f0f0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#757575", + "defaultDisabledIcon": "#757575", + "defaultFocusedBackground": "#f5f5f5", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#000000", + "defaultFocusedIcon": "#000000", + "defaultHoveredBackground": "#f5f5f5", + "defaultHoveredBorder": "#c7c7c7", + "defaultHoveredContent": "#000000", + "defaultHoveredIcon": "#000000", + "defaultHoveredSecondaryContent": "#424242", + "defaultIcon": "#000000", + "defaultPressedBackground": "#ebebeb", + "defaultPressedBorder": "#b3b3b3", + "defaultPressedContent": "#000000", + "defaultPressedIcon": "#000000", + "defaultPressedSecondaryContent": "#424242", + "disabledBackground": "#f0f0f0", + "disabledBodyText": "#757575", + "disabledText": "#757575", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#242424", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#000000", + "ghostCheckedHoveredContent": "#242424", + "ghostContent": "#000000", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#bdbdbd", + "ghostDisabledContent": "#757575", + "ghostDisabledIcon": "#757575", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#000000", + "ghostFocusedIcon": "#000000", + "ghostFocusedSecondaryContent": "#000000", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#000000", + "ghostHoveredContent": "#000000", + "ghostHoveredIcon": "#000000", + "ghostHoveredSecondaryContent": "#424242", + "ghostIcon": "#000000", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#000000", + "ghostPressedContent": "#000000", + "ghostPressedIcon": "#000000", + "ghostPressedSecondaryContent": "#424242", + "ghostSecondaryContent": "#000000", "inputBackground": "#ffffff", - "inputBorder": "#a19f9d", - "inputFocusBorderAlt": "#185abd", - "inputPlaceholderText": "#605e5c", - "inputText": "#323130", - "link": "#185abd", - "linkHovered": "#004578", - "linkPressed": "#13458f", - "listHeaderBackgroundHovered": "#f3f2f1", - "listHeaderBackgroundPressed": "#edebe9", + "inputBorder": "#616161", + "inputFocusBorderAlt": "#0078d4", + "inputPlaceholderText": "#424242", + "inputText": "#000000", + "link": "#0078d4", + "linkHovered": "#106ebe", + "linkPressed": "#004578", + "listHeaderBackgroundHovered": "#f5f5f5", + "listHeaderBackgroundPressed": "#ebebeb", "menuBackground": "#ffffff", - "menuDivider": "#c8c6c4", - "menuIcon": "#185abd", - "menuItemBackgroundHovered": "#f3f2f1", - "menuItemBackgroundPressed": "#edebe9", - "menuItemText": "#323130", - "menuItemTextHovered": "#201f1e", + "menuDivider": "#000000", + "menuIcon": "#000000", + "menuItemBackgroundHovered": "#f5f5f5", + "menuItemBackgroundPressed": "#ebebeb", + "menuItemText": "#000000", + "menuItemTextHovered": "#000000", "neutralBackground1": "#ffffff", "neutralBackground1Hover": "#f5f5f5", - "neutralBackground1Pressed": "#e0e0e0", + "neutralBackground1Pressed": "#ebebeb", "neutralBackground1Selected": "#ebebeb", - "neutralBackground2": "#fafafa", + "neutralBackground2": "#ffffff", "neutralBackground2Hover": "#f0f0f0", - "neutralBackground2Pressed": "#dbdbdb", + "neutralBackground2Pressed": "#ebebeb", "neutralBackground2Selected": "#e6e6e6", "neutralBackground3": "#f5f5f5", "neutralBackground3Hover": "#ebebeb", @@ -1985,50 +2223,61 @@ exports[`defaultFluentTheme 1`] = ` "neutralBackground5Pressed": "#f0f0f0", "neutralBackground5Selected": "#fafafa", "neutralBackground6": "#e6e6e6", + "neutralBackgroundCanvas": "#ffffff", + "neutralBackgroundDarkStatic": "#242424", "neutralBackgroundDisabled": "#f0f0f0", "neutralBackgroundInverted": "#616161", - "neutralForeground1": "#242424", - "neutralForeground1Hover": "#242424", - "neutralForeground1Pressed": "#242424", - "neutralForeground1Selected": "#242424", - "neutralForeground2": "#424242", - "neutralForeground2BrandHover": "#185abd", - "neutralForeground2BrandPressed": "#1651aa", - "neutralForeground2BrandSelected": "#185abd", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#f0f0f0", + "neutralForeground1": "#000000", + "neutralForeground1Hover": "#000000", + "neutralForeground1Pressed": "#000000", + "neutralForeground1Selected": "#000000", + "neutralForeground2": "#000000", + "neutralForeground2BrandHover": "#106ebe", + "neutralForeground2BrandPressed": "#004578", + "neutralForeground2BrandSelected": "#005a9e", "neutralForeground2Hover": "#242424", "neutralForeground2Pressed": "#242424", "neutralForeground2Selected": "#242424", - "neutralForeground3": "#616161", - "neutralForeground3BrandHover": "#185abd", - "neutralForeground3BrandPressed": "#1651aa", - "neutralForeground3BrandSelected": "#185abd", + "neutralForeground3": "#000000", + "neutralForeground3BrandHover": "#106ebe", + "neutralForeground3BrandPressed": "#004578", + "neutralForeground3BrandSelected": "#005a9e", "neutralForeground3Hover": "#424242", "neutralForeground3Pressed": "#424242", "neutralForeground3Selected": "#424242", - "neutralForeground4": "#707070", - "neutralForegroundDisabled": "#bdbdbd", + "neutralForeground4": "#424242", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#757575", + "neutralForegroundDisabled1": "#757575", + "neutralForegroundDisabled2": "#757575", "neutralForegroundInverted": "#ffffff", "neutralForegroundInvertedLink": "#ffffff", "neutralForegroundInvertedLinkHover": "#ffffff", "neutralForegroundInvertedLinkPressed": "#ffffff", "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#ffffff", "neutralForegroundOnBrandHover": "#ffffff", "neutralForegroundOnBrandPressed": "#ffffff", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#e6e6e6", "neutralStencil2": "#fafafa", - "neutralStroke1": "#d1d1d1", + "neutralStroke1": "#616161", "neutralStroke1Hover": "#c7c7c7", "neutralStroke1Pressed": "#b3b3b3", "neutralStroke1Selected": "#bdbdbd", - "neutralStroke2": "#e0e0e0", - "neutralStroke3": "#f0f0f0", - "neutralStrokeAccessible": "#616161", + "neutralStroke2": "#000000", + "neutralStroke3": "#616161", + "neutralStrokeAccessible": "#242424", "neutralStrokeAccessibleHover": "#575757", "neutralStrokeAccessiblePressed": "#4d4d4d", - "neutralStrokeAccessibleSelected": "#185abd", + "neutralStrokeAccessibleSelected": "#0078d4", "neutralStrokeDisabled": "#e0e0e0", + "neutralStrokeFocus1": "#ffffff", + "neutralStrokeFocus2": "#000000", "outofofficeBackground1": "#fdf5fc", "outofofficeBackground2": "#edbbe7", "outofofficeBackground3": "#c239b3", @@ -2038,18 +2287,31 @@ exports[`defaultFluentTheme 1`] = ` "outofofficeForeground1": "#af33a1", "outofofficeForeground2": "#6d2064", "outofofficeForeground3": "#c239b3", - "personaActivityGlow": "#185abd", + "personaActivityGlow": "#0078d4", "personaActivityRing": "#ffffff", - "primaryButtonBackground": "#185abd", - "primaryButtonBackgroundDisabled": "#f3f2f1", - "primaryButtonBackgroundHovered": "#1651aa", - "primaryButtonBackgroundPressed": "#13458f", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", + "presenceAvailable": "#0e700e", + "presenceAway": "#817400", + "presenceDnd": "#bc2f32", + "presenceOof": "#af33a1", + "primaryButtonBackground": "#0078d4", + "primaryButtonBackgroundDisabled": "#f0f0f0", + "primaryButtonBackgroundHovered": "#106ebe", + "primaryButtonBackgroundPressed": "#106ebe", + "primaryButtonBorder": "#000000", + "primaryButtonBorderFocused": "#000000", "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#d2d0ce", + "primaryButtonTextDisabled": "#757575", "primaryButtonTextHovered": "#ffffff", "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#f1bbbc", + "redBackground3": "#d13438", + "redBorder1": "#f1bbbc", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#751d1f", + "redForeground3": "#d13438", "severeBackground1": "#fdf6f3", "severeBackground2": "#f4bfab", "severeBackground3": "#da3b01", @@ -2059,9 +2321,10 @@ exports[`defaultFluentTheme 1`] = ` "severeForeground1": "#c43501", "severeForeground2": "#7a2101", "severeForeground3": "#da3b01", + "severeStroke1": "#f4bfab", "strokeFocus1": "#ffffff", "strokeFocus2": "#000000", - "subText": "#605e5c", + "subText": "#000000", "subtleBackground": "#00000000", "subtleBackgroundHover": "#f5f5f5", "subtleBackgroundPressed": "#e0e0e0", @@ -2076,14 +2339,15 @@ exports[`defaultFluentTheme 1`] = ` "successForeground2": "#094509", "successForeground3": "#107c10", "successForegroundInverted": "#359b35", + "successStroke1": "#9fd89f", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", "transparentBackgroundSelected": "#00000000", - "transparentStroke": "#00000000", - "transparentStrokeDisabled": "#00000000", - "transparentStrokeInteractive": "#00000000", - "variantBorder": "#edebe9", + "transparentStroke": "#000000", + "transparentStrokeDisabled": "#bdbdbd", + "transparentStrokeInteractive": "#666666", + "variantBorder": "#000000", "warningBackground1": "#fffef5", "warningBackground2": "#fef7b2", "warningBackground3": "#fde300", @@ -2094,22 +2358,23 @@ exports[`defaultFluentTheme 1`] = ` "warningForeground2": "#817400", "warningForeground3": "#fde300", "warningForegroundInverted": "#fef7b2", + "warningStroke1": "#fef7b2", }, "components": {}, "host": { - "appearance": "light", + "appearance": "highContrast", }, "shadows": { "shadow16": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 16, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 8, }, @@ -2131,13 +2396,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow2": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 2, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 1, }, @@ -2145,13 +2410,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow28": { "ambient": { "blur": 8, - "color": "#00000033", + "color": "#00000066", "x": 0, "y": 0, }, "key": { "blur": 28, - "color": "#0000003d", + "color": "#0000007a", "x": 0, "y": 14, }, @@ -2187,13 +2452,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow4": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 4, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 2, }, @@ -2215,13 +2480,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow64": { "ambient": { "blur": 8, - "color": "#00000033", + "color": "#00000066", "x": 0, "y": 0, }, "key": { "blur": 64, - "color": "#0000003d", + "color": "#0000007a", "x": 0, "y": 32, }, @@ -2243,13 +2508,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow8": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 8, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 4, }, @@ -2278,13 +2543,13 @@ exports[`defaultFluentTheme 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", - "primary": "System", - "sansSerif": "System", - "secondary": "System", - "serif": "System", + "cursive": "Helvetica Neue", + "monospace": "Courier New", + "numeric": "Helvetica Neue", + "primary": "Helvetica Neue", + "sansSerif": "Helvetica Neue", + "secondary": "Helvetica Neue", + "serif": "Helvetica Neue", }, "sizes": { "body": 14, @@ -2298,138 +2563,153 @@ exports[`defaultFluentTheme 1`] = ` "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { diff --git a/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.win32.ts.snap b/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.win32.ts.snap index fdeef02cf4..7f9af812b0 100644 --- a/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.win32.ts.snap +++ b/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.win32.ts.snap @@ -4,63 +4,76 @@ exports[`defaultFluentDarkTheme 1`] = ` { "colors": { "accentButtonBackground": "#185abd", - "actionLink": "#f3f2f1", - "background": "#1b1a19", - "bodyDivider": "#292827", - "bodyFrameBackground": "#1b1a19", - "bodyFrameDivider": "#292827", - "bodyStandoutBackground": "#201f1e", - "bodyText": "#f3f2f1", + "actionLink": "#ffffff", + "background": "#292929", + "bodyDivider": "#525252", + "bodyFrameBackground": "#292929", + "bodyFrameDivider": "#525252", + "bodyStandoutBackground": "#1f1f1f", + "bodyText": "#ffffff", "bodyTextChecked": "#ffffff", - "brandBackground": "#1651aa", - "brandBackground2": "#004578", - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": "#185abd", - "brandBackgroundPressed": "#004578", + "brandBackground": "#185abd", + "brandBackground2": "#d2e0f4", + "brandBackground2Pressed": "#0e336a", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#d2e0f4", + "brandBackgroundDisabled": "#141414", + "brandBackgroundHover": "#1651aa", + "brandBackgroundInverted": "#ffffff", + "brandBackgroundInvertedDisabled": "#141414", + "brandBackgroundPressed": "#0e336a", "brandBackgroundSelected": "#13458f", "brandBackgroundStatic": "#185abd", - "brandForeground1": "#6794d7", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": "#aec6eb", - "brandForegroundLink": "#2e6ac5", - "brandForegroundLinkHover": "#aec6eb", - "brandForegroundLinkPressed": "#6794d7", - "brandForegroundLinkSelected": "#2e6ac5", - "brandStroke1": "#2e6ac5", - "brandStroke2": "#0e336a", - "brandedBackground": "#2e6ac5", - "brandedDisabledBorder": "#252423", - "brandedFocusedSecondaryContent": "#201f1e", - "brandedHoveredSecondaryContent": "#201f1e", - "brandedPressedSecondaryContent": "#201f1e", - "brandedSecondaryContent": "#201f1e", - "buttonBackground": "#252423", - "buttonBackgroundChecked": "#484644", - "buttonBackgroundDisabled": "#252423", - "buttonBackgroundHovered": "#292827", - "buttonBackgroundPressed": "#292827", - "buttonBorder": "#979693", - "buttonBorderDisabled": "#252423", - "buttonBorderFocused": "#979693", + "brandBackgroundTint": "#d2e0f4", + "brandForeground1": "#aec6eb", + "brandForeground1Disabled": "#5c5c5c", + "brandForeground1Pressed": "#aec6eb", + "brandForeground1Selected": "#aec6eb", + "brandForeground2": "#d2e0f4", + "brandForegroundDisabled1": "#5c5c5c", + "brandForegroundDisabled2": "#5c5c5c", + "brandForegroundLink": "#aec6eb", + "brandForegroundLinkHover": "#d2e0f4", + "brandForegroundLinkPressed": "#2e6ac5", + "brandForegroundLinkSelected": "#d2e0f4", + "brandForegroundTint": "#d2e0f4", + "brandStroke1": "#185abd", + "brandStroke1Pressed": "#185abd", + "brandStroke1Selected": "#185abd", + "brandStroke2": "#6794d7", + "brandStrokeTint": "#6794d7", + "brandedBackground": "#185abd", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#292929", + "buttonBackgroundChecked": "#383838", + "buttonBackgroundDisabled": "#141414", + "buttonBackgroundHovered": "#3d3d3d", + "buttonBackgroundPressed": "#1f1f1f", + "buttonBorder": "#666666", + "buttonBorderDisabled": "#424242", + "buttonBorderFocused": "#ffffff", "buttonText": "#ffffff", - "buttonTextChecked": "#faf9f8", - "buttonTextDisabled": "#797775", - "buttonTextHovered": "#f3f2f1", - "buttonTextPressed": "#faf9f8", - "checkboxBackground": "#2e6ac5", - "checkboxBackgroundDisabled": "#252423", - "checkboxBorderColor": "#979693", - "checkmarkColor": "#1b1a19", - "compoundBrandBackground1": "#2e6ac5", - "compoundBrandBackground1Hover": "#6794d7", - "compoundBrandBackground1Pressed": "#185abd", - "compoundBrandForeground1": "#2e6ac5", - "compoundBrandForeground1Hover": "#6794d7", - "compoundBrandForeground1Pressed": "#185abd", - "compoundBrandStroke1": "#2e6ac5", - "compoundBrandStroke1Hover": "#6794d7", - "compoundBrandStroke1Pressed": "#185abd", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#5c5c5c", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#185abd", + "checkboxBackgroundDisabled": "#141414", + "checkboxBorderColor": "#adadad", + "checkmarkColor": "#ffffff", + "compoundBrandBackground1": "#185abd", + "compoundBrandBackground1Hover": "#1651aa", + "compoundBrandBackground1Pressed": "#0e336a", + "compoundBrandForeground1": "#aec6eb", + "compoundBrandForeground1Hover": "#d2e0f4", + "compoundBrandForeground1Pressed": "#2e6ac5", + "compoundBrandStroke1": "#185abd", + "compoundBrandStroke1Hover": "#1651aa", + "compoundBrandStroke1Pressed": "#0e336a", "dangerBackground1": "#3f1011", "dangerBackground2": "#751d1f", "dangerBackground3": "#d13438", @@ -71,83 +84,84 @@ exports[`defaultFluentDarkTheme 1`] = ` "dangerForeground2": "#f1bbbc", "dangerForeground3": "#e37d80", "dangerForegroundInverted": "#d13438", - "defaultBackground": "#252423", - "defaultBorder": "#979693", - "defaultCheckedBackground": "#484644", - "defaultCheckedContent": "#faf9f8", - "defaultCheckedHoveredBackground": "#292827", - "defaultCheckedHoveredContent": "#f3f2f1", + "dangerStroke1": "#d13438", + "defaultBackground": "#292929", + "defaultBorder": "#666666", + "defaultCheckedBackground": "#383838", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#3d3d3d", + "defaultCheckedHoveredContent": "#ffffff", "defaultContent": "#ffffff", - "defaultDisabledBackground": "#252423", - "defaultDisabledBorder": "#252423", - "defaultDisabledContent": "#797775", - "defaultDisabledIcon": "#797775", - "defaultFocusedBackground": "#292827", - "defaultFocusedBorder": "#979693", - "defaultFocusedContent": "#f3f2f1", - "defaultFocusedIcon": "#f3f2f1", - "defaultHoveredBackground": "#292827", - "defaultHoveredBorder": "#979693", - "defaultHoveredContent": "#f3f2f1", - "defaultHoveredIcon": "#f3f2f1", - "defaultHoveredSecondaryContent": "#797775", + "defaultDisabledBackground": "#141414", + "defaultDisabledBorder": "#424242", + "defaultDisabledContent": "#5c5c5c", + "defaultDisabledIcon": "#5c5c5c", + "defaultFocusedBackground": "#3d3d3d", + "defaultFocusedBorder": "#ffffff", + "defaultFocusedContent": "#ffffff", + "defaultFocusedIcon": "#ffffff", + "defaultHoveredBackground": "#3d3d3d", + "defaultHoveredBorder": "#757575", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#d6d6d6", "defaultIcon": "#ffffff", - "defaultPressedBackground": "#292827", - "defaultPressedBorder": "#979693", - "defaultPressedContent": "#faf9f8", - "defaultPressedIcon": "#faf9f8", - "defaultPressedSecondaryContent": "#797775", - "disabledBackground": "#323130", - "disabledBodyText": "#797775", - "disabledText": "#797775", - "errorText": "#ff5f5f", - "focusBorder": "#a19f9d", - "ghostBackground": "#1b1a19", - "ghostBorder": "#1b1a19", - "ghostCheckedBackground": "#292827", + "defaultPressedBackground": "#1f1f1f", + "defaultPressedBorder": "#6b6b6b", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#d6d6d6", + "disabledBackground": "#141414", + "disabledBodyText": "#5c5c5c", + "disabledText": "#5c5c5c", + "errorText": "#e37d80", + "focusBorder": "#ffffff", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#383838", "ghostCheckedContent": "#ffffff", - "ghostCheckedHoveredBackground": "#252423", - "ghostCheckedHoveredBorder": "#faf9f8", - "ghostCheckedHoveredContent": "#faf9f8", - "ghostContent": "#f3f2f1", - "ghostDisabledBackground": "#1b1a19", - "ghostDisabledBorder": "#1b1a19", - "ghostDisabledContent": "#797775", - "ghostDisabledIcon": "#797775", - "ghostFocusedBackground": "#252423", - "ghostFocusedBorder": "#979693", - "ghostFocusedContent": "#faf9f8", - "ghostFocusedIcon": "#faf9f8", - "ghostFocusedSecondaryContent": "#a19f9d", - "ghostHoveredBackground": "#252423", - "ghostHoveredBorder": "#252423", - "ghostHoveredContent": "#faf9f8", - "ghostHoveredIcon": "#faf9f8", - "ghostHoveredSecondaryContent": "#a19f9d", - "ghostIcon": "#f3f2f1", - "ghostPressedBackground": "#292827", - "ghostPressedBorder": "#292827", - "ghostPressedContent": "#faf9f8", - "ghostPressedIcon": "#faf9f8", - "ghostPressedSecondaryContent": "#a19f9d", - "ghostSecondaryContent": "#a19f9d", - "inputBackground": "#1b1a19", - "inputBorder": "#797775", - "inputFocusBorderAlt": "#2e6ac5", - "inputPlaceholderText": "#a19f9d", - "inputText": "#f3f2f1", - "link": "#2e6ac5", - "linkHovered": "#82c7ff", - "linkPressed": "#aec6eb", - "listHeaderBackgroundHovered": "#252423", - "listHeaderBackgroundPressed": "#292827", - "menuBackground": "#252423", - "menuDivider": "#484644", - "menuIcon": "#6794d7", - "menuItemBackgroundHovered": "#323130", - "menuItemBackgroundPressed": "#3b3a39", - "menuItemText": "#f3f2f1", - "menuItemTextHovered": "#faf9f8", + "ghostCheckedHoveredBackground": "#3d3d3d", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#ffffff", + "ghostContent": "#ffffff", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#5c5c5c", + "ghostDisabledIcon": "#5c5c5c", + "ghostFocusedBackground": "#3d3d3d", + "ghostFocusedBorder": "#ffffff", + "ghostFocusedContent": "#ffffff", + "ghostFocusedIcon": "#ffffff", + "ghostFocusedSecondaryContent": "#adadad", + "ghostHoveredBackground": "#3d3d3d", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#d6d6d6", + "ghostIcon": "#ffffff", + "ghostPressedBackground": "#1f1f1f", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#d6d6d6", + "ghostSecondaryContent": "#adadad", + "inputBackground": "#292929", + "inputBorder": "#666666", + "inputFocusBorderAlt": "#185abd", + "inputPlaceholderText": "#999999", + "inputText": "#ffffff", + "link": "#aec6eb", + "linkHovered": "#d2e0f4", + "linkPressed": "#2e6ac5", + "listHeaderBackgroundHovered": "#3d3d3d", + "listHeaderBackgroundPressed": "#1f1f1f", + "menuBackground": "#292929", + "menuDivider": "#525252", + "menuIcon": "#d6d6d6", + "menuItemBackgroundHovered": "#3d3d3d", + "menuItemBackgroundPressed": "#1f1f1f", + "menuItemText": "#ffffff", + "menuItemTextHovered": "#ffffff", "neutralBackground1": "#292929", "neutralBackground1Hover": "#3d3d3d", "neutralBackground1Pressed": "#1f1f1f", @@ -169,37 +183,46 @@ exports[`defaultFluentDarkTheme 1`] = ` "neutralBackground5Pressed": "#050505", "neutralBackground5Selected": "#0f0f0f", "neutralBackground6": "#333333", + "neutralBackgroundCanvas": "#292929", + "neutralBackgroundDarkStatic": "#3d3d3d", "neutralBackgroundDisabled": "#141414", "neutralBackgroundInverted": "#ffffff", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#141414", "neutralForeground1": "#ffffff", "neutralForeground1Hover": "#ffffff", "neutralForeground1Pressed": "#ffffff", "neutralForeground1Selected": "#ffffff", "neutralForeground2": "#d6d6d6", - "neutralForeground2BrandHover": "#6794d7", + "neutralForeground2BrandHover": "#d2e0f4", "neutralForeground2BrandPressed": "#2e6ac5", - "neutralForeground2BrandSelected": "#6794d7", + "neutralForeground2BrandSelected": "#d2e0f4", "neutralForeground2Hover": "#ffffff", "neutralForeground2Pressed": "#ffffff", "neutralForeground2Selected": "#ffffff", "neutralForeground3": "#adadad", - "neutralForeground3BrandHover": "#6794d7", + "neutralForeground3BrandHover": "#d2e0f4", "neutralForeground3BrandPressed": "#2e6ac5", - "neutralForeground3BrandSelected": "#6794d7", + "neutralForeground3BrandSelected": "#d2e0f4", "neutralForeground3Hover": "#d6d6d6", "neutralForeground3Pressed": "#d6d6d6", "neutralForeground3Selected": "#d6d6d6", "neutralForeground4": "#999999", + "neutralForegroundDarkStatic": "#000000", "neutralForegroundDisabled": "#5c5c5c", - "neutralForegroundInverted": "#242424", - "neutralForegroundInvertedLink": "#ffffff", - "neutralForegroundInvertedLinkHover": "#ffffff", - "neutralForegroundInvertedLinkPressed": "#ffffff", - "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundDisabled1": "#5c5c5c", + "neutralForegroundDisabled2": "#5c5c5c", + "neutralForegroundInverted": "#000000", + "neutralForegroundInvertedLink": "#292929", + "neutralForegroundInvertedLinkHover": "#292929", + "neutralForegroundInvertedLinkPressed": "#292929", + "neutralForegroundInvertedLinkSelected": "#292929", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#ffffff", "neutralForegroundOnBrandHover": "#ffffff", "neutralForegroundOnBrandPressed": "#ffffff", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#333333", "neutralStencil2": "#575757", "neutralStroke1": "#666666", @@ -211,8 +234,10 @@ exports[`defaultFluentDarkTheme 1`] = ` "neutralStrokeAccessible": "#adadad", "neutralStrokeAccessibleHover": "#bdbdbd", "neutralStrokeAccessiblePressed": "#b3b3b3", - "neutralStrokeAccessibleSelected": "#6794d7", + "neutralStrokeAccessibleSelected": "#185abd", "neutralStrokeDisabled": "#424242", + "neutralStrokeFocus1": "#000000", + "neutralStrokeFocus2": "#ffffff", "outofofficeBackground1": "#3a1136", "outofofficeBackground2": "#6d2064", "outofofficeBackground3": "#c239b3", @@ -222,18 +247,31 @@ exports[`defaultFluentDarkTheme 1`] = ` "outofofficeForeground1": "#da7ed0", "outofofficeForeground2": "#edbbe7", "outofofficeForeground3": "#d161c4", - "personaActivityGlow": "#2e6ac5", - "personaActivityRing": "#1b1a19", - "primaryButtonBackground": "#2e6ac5", - "primaryButtonBackgroundDisabled": "#252423", - "primaryButtonBackgroundHovered": "#6794d7", - "primaryButtonBackgroundPressed": "#aec6eb", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", - "primaryButtonText": "#1b1a19", - "primaryButtonTextDisabled": "#3b3a39", - "primaryButtonTextHovered": "#1b1a19", - "primaryButtonTextPressed": "#1b1a19", + "personaActivityGlow": "#185abd", + "personaActivityRing": "#292929", + "presenceAvailable": "#54b054", + "presenceAway": "#feee66", + "presenceDnd": "#e37d80", + "presenceOof": "#da7ed0", + "primaryButtonBackground": "#185abd", + "primaryButtonBackgroundDisabled": "#141414", + "primaryButtonBackgroundHovered": "#1651aa", + "primaryButtonBackgroundPressed": "#0e336a", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#ffffff", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#5c5c5c", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#751d1f", + "redBackground3": "#d13438", + "redBorder1": "#d13438", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#f1bbbc", + "redForeground3": "#e37d80", "severeBackground1": "#411200", "severeBackground2": "#7a2101", "severeBackground3": "#da3b01", @@ -243,13 +281,14 @@ exports[`defaultFluentDarkTheme 1`] = ` "severeForeground1": "#e9835e", "severeForeground2": "#f4bfab", "severeForeground3": "#e9835e", + "severeStroke1": "#da3b01", "strokeFocus1": "#000000", "strokeFocus2": "#ffffff", - "subText": "#a19f9d", + "subText": "#d6d6d6", "subtleBackground": "#00000000", - "subtleBackgroundHover": "#383838", - "subtleBackgroundPressed": "#2e2e2e", - "subtleBackgroundSelected": "#333333", + "subtleBackgroundHover": "#3d3d3d", + "subtleBackgroundPressed": "#1f1f1f", + "subtleBackgroundSelected": "#383838", "successBackground1": "#052505", "successBackground2": "#094509", "successBackground3": "#107c10", @@ -260,6 +299,7 @@ exports[`defaultFluentDarkTheme 1`] = ` "successForeground2": "#9fd89f", "successForeground3": "#9fd89f", "successForegroundInverted": "#107c10", + "successStroke1": "#107c10", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -267,7 +307,7 @@ exports[`defaultFluentDarkTheme 1`] = ` "transparentStroke": "#00000000", "transparentStrokeDisabled": "#00000000", "transparentStrokeInteractive": "#00000000", - "variantBorder": "#292827", + "variantBorder": "#525252", "warningBackground1": "#4c4400", "warningBackground2": "#817400", "warningBackground3": "#fde300", @@ -278,6 +318,7 @@ exports[`defaultFluentDarkTheme 1`] = ` "warningForeground2": "#fef7b2", "warningForeground3": "#fdea3d", "warningForegroundInverted": "#817400", + "warningStroke1": "#fde300", }, "components": {}, "host": { @@ -462,13 +503,13 @@ exports[`defaultFluentDarkTheme 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -482,138 +523,153 @@ exports[`defaultFluentDarkTheme 1`] = ` "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { @@ -624,1492 +680,4125 @@ exports[`defaultFluentDarkTheme 1`] = ` } `; -exports[`defaultFluentHighConstrastTheme 1`] = ` +exports[`defaultFluentTheme 1`] = ` { "colors": { - "accentButtonBackground": "#000000", - "actionLink": "#ffff00", - "background": "#000000", - "bodyDivider": "#ffffff", - "bodyFrameBackground": "#000000", - "bodyFrameDivider": "#000000", - "bodyStandoutBackground": "#000000", - "bodyText": "#ffffff", - "bodyTextChecked": "#000000", - "brandBackground": { - "resource_paths": [ - "ButtonFace", - ], - }, - "brandBackground2": { - "resource_paths": [ - "ButtonFace", - ], - }, - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": { - "resource_paths": [ - "Highlight", - ], - }, - "brandBackgroundPressed": { - "resource_paths": [ - "Highlight", - ], - }, - "brandBackgroundSelected": { - "resource_paths": [ - "Highlight", - ], - }, - "brandBackgroundStatic": { - "resource_paths": [ - "Window", - ], - }, - "brandForeground1": { - "resource_paths": [ - "WindowText", - ], - }, - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": { - "resource_paths": [ - "ButtonText", - ], - }, - "brandForegroundLink": { - "resource_paths": [ - "Hotlight", - ], - }, - "brandForegroundLinkHover": { - "resource_paths": [ - "Hotlight", - ], - }, - "brandForegroundLinkPressed": { - "resource_paths": [ - "Hotlight", - ], - }, - "brandForegroundLinkSelected": { - "resource_paths": [ - "Hotlight", - ], - }, - "brandStroke1": { - "resource_paths": [ - "WindowText", - ], - }, - "brandStroke2": { - "resource_paths": [ - "Window", - ], - }, - "brandedBackground": "#000000", - "brandedDisabledBorder": "#3ff23f", + "accentButtonBackground": "#185abd", + "actionLink": "#242424", + "background": "#ffffff", + "bodyDivider": "#e0e0e0", + "bodyFrameBackground": "#ffffff", + "bodyFrameDivider": "#e0e0e0", + "bodyStandoutBackground": "#fafafa", + "bodyText": "#242424", + "bodyTextChecked": "#242424", + "brandBackground": "#185abd", + "brandBackground2": "#d2e0f4", + "brandBackground2Pressed": "#0e336a", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#d2e0f4", + "brandBackgroundDisabled": "#f0f0f0", + "brandBackgroundHover": "#1651aa", + "brandBackgroundInverted": "#616161", + "brandBackgroundInvertedDisabled": "#f0f0f0", + "brandBackgroundPressed": "#0e336a", + "brandBackgroundSelected": "#13458f", + "brandBackgroundStatic": "#185abd", + "brandBackgroundTint": "#d2e0f4", + "brandForeground1": "#185abd", + "brandForeground1Disabled": "#bdbdbd", + "brandForeground1Pressed": "#185abd", + "brandForeground1Selected": "#185abd", + "brandForeground2": "#1651aa", + "brandForegroundDisabled1": "#bdbdbd", + "brandForegroundDisabled2": "#bdbdbd", + "brandForegroundLink": "#185abd", + "brandForegroundLinkHover": "#1651aa", + "brandForegroundLinkPressed": "#0e336a", + "brandForegroundLinkSelected": "#13458f", + "brandForegroundTint": "#1651aa", + "brandStroke1": "#185abd", + "brandStroke1Pressed": "#185abd", + "brandStroke1Selected": "#185abd", + "brandStroke2": "#6794d7", + "brandStrokeTint": "#6794d7", + "brandedBackground": "#185abd", + "brandedDisabledBorder": "#00000000", "brandedFocusedSecondaryContent": "#ffffff", - "brandedHoveredSecondaryContent": "#000000", - "brandedPressedSecondaryContent": "#000000", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", "brandedSecondaryContent": "#ffffff", - "buttonBackground": "#000000", - "buttonBackgroundChecked": "#1aebff", - "buttonBackgroundDisabled": "#000000", - "buttonBackgroundHovered": "#1aebff", - "buttonBackgroundPressed": "#1aebff", - "buttonBorder": "#ffffff", - "buttonBorderDisabled": "#3ff23f", - "buttonBorderFocused": "#ffffff", - "buttonText": "#ffffff", - "buttonTextChecked": "#000000", - "buttonTextDisabled": "#3ff23f", - "buttonTextHovered": "#000000", - "buttonTextPressed": "#000000", - "checkboxBackground": "#000000", - "checkboxBackgroundDisabled": "#000000", - "checkboxBorderColor": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#f0f0f0", + "buttonBackgroundHovered": "#f5f5f5", + "buttonBackgroundPressed": "#e0e0e0", + "buttonBorder": "#d1d1d1", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#242424", + "buttonTextChecked": "#242424", + "buttonTextDisabled": "#bdbdbd", + "buttonTextHovered": "#242424", + "buttonTextPressed": "#242424", + "checkboxBackground": "#185abd", + "checkboxBackgroundDisabled": "#f0f0f0", + "checkboxBorderColor": "#616161", "checkmarkColor": "#ffffff", - "compoundBrandBackground1": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandBackground1Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandBackground1Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandForeground1": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandForeground1Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandForeground1Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandStroke1": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandStroke1Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "compoundBrandStroke1Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "dangerBackground1": { - "resource_paths": [ - "Window", - ], - }, - "dangerBackground2": { - "resource_paths": [ - "Window", - ], - }, - "dangerBackground3": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerBorder1": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerBorder2": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerBorderActive": { - "resource_paths": [ - "Highlight", - ], - }, - "dangerForeground1": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerForeground2": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerForeground3": { - "resource_paths": [ - "WindowText", - ], - }, - "dangerForegroundInverted": { - "resource_paths": [ - "WindowText", - ], - }, - "defaultBackground": "#000000", - "defaultBorder": "#ffffff", - "defaultCheckedBackground": "#1aebff", - "defaultCheckedContent": "#000000", - "defaultCheckedHoveredBackground": "#1aebff", - "defaultCheckedHoveredContent": "#000000", - "defaultContent": "#ffffff", - "defaultDisabledBackground": "#000000", - "defaultDisabledBorder": "#3ff23f", - "defaultDisabledContent": "#3ff23f", - "defaultDisabledIcon": "#3ff23f", - "defaultFocusedBackground": "#000000", - "defaultFocusedBorder": "#ffffff", - "defaultFocusedContent": "#ffffff", - "defaultFocusedIcon": "#ffffff", - "defaultHoveredBackground": "#1aebff", - "defaultHoveredBorder": "#1aebff", - "defaultHoveredContent": "#000000", - "defaultHoveredIcon": "#000000", - "defaultHoveredSecondaryContent": "#000000", - "defaultIcon": "#ffffff", - "defaultPressedBackground": "#1aebff", - "defaultPressedBorder": "#1aebff", - "defaultPressedContent": "#000000", - "defaultPressedIcon": "#000000", - "defaultPressedSecondaryContent": "#000000", - "disabledBackground": "#000000", - "disabledBodyText": "#3ff23f", - "disabledText": "#3ff23f", - "errorText": "#ffffff", - "focusBorder": "#ffffff", - "ghostBackground": "#000000", - "ghostBorder": "#000000", - "ghostCheckedBackground": "#1aebff", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#1aebff", - "ghostCheckedHoveredBorder": "#000000", - "ghostCheckedHoveredContent": "#000000", - "ghostContent": "#ffffff", - "ghostDisabledBackground": "#000000", - "ghostDisabledBorder": "#000000", - "ghostDisabledContent": "#3ff23f", - "ghostDisabledIcon": "#3ff23f", - "ghostFocusedBackground": "#000000", - "ghostFocusedBorder": "#ffffff", - "ghostFocusedContent": "#ffffff", - "ghostFocusedIcon": "#ffffff", - "ghostFocusedSecondaryContent": "#ffffff", - "ghostHoveredBackground": "#1aebff", - "ghostHoveredBorder": "#1aebff", - "ghostHoveredContent": "#000000", - "ghostHoveredIcon": "#000000", - "ghostHoveredSecondaryContent": "#000000", - "ghostIcon": "#ffffff", - "ghostPressedBackground": "#1aebff", - "ghostPressedBorder": "#1aebff", - "ghostPressedContent": "#000000", - "ghostPressedIcon": "#000000", - "ghostPressedSecondaryContent": "#000000", - "ghostSecondaryContent": "#ffffff", - "inputBackground": "#000000", - "inputBorder": "#ffffff", - "inputFocusBorderAlt": "#ffffff", - "inputPlaceholderText": "#ffffff", - "inputText": "#ffffff", - "link": "#ffff00", - "linkHovered": "#ffffff", - "linkPressed": "#ffffff", - "listHeaderBackgroundHovered": "#1aebff", - "listHeaderBackgroundPressed": "#1aebff", - "menuBackground": "#000000", - "menuDivider": "#ffffff", - "menuIcon": "#ffffff", - "menuItemBackgroundHovered": "#1aebff", - "menuItemBackgroundPressed": "#1aebff", - "menuItemText": "#ffffff", - "menuItemTextHovered": "#000000", - "neutralBackground1": { - "resource_paths": [ - "Window", - ], - }, - "neutralBackground1Hover": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground1Pressed": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground1Selected": { - "resource_paths": [ - "Highlight", - ], - }, - "neutralBackground2": { - "resource_paths": [ - "Window", - ], - }, - "neutralBackground2Hover": { - "resource_paths": [ - "Highlight", - ], + "compoundBrandBackground1": "#185abd", + "compoundBrandBackground1Hover": "#1651aa", + "compoundBrandBackground1Pressed": "#0e336a", + "compoundBrandForeground1": "#185abd", + "compoundBrandForeground1Hover": "#1651aa", + "compoundBrandForeground1Pressed": "#0e336a", + "compoundBrandStroke1": "#185abd", + "compoundBrandStroke1Hover": "#1651aa", + "compoundBrandStroke1Pressed": "#0e336a", + "dangerBackground1": "#fdf6f6", + "dangerBackground2": "#f1bbbc", + "dangerBackground3": "#d13438", + "dangerBorder1": "#f1bbbc", + "dangerBorder2": "#d13438", + "dangerBorderActive": "#d13438", + "dangerForeground1": "#bc2f32", + "dangerForeground2": "#751d1f", + "dangerForeground3": "#d13438", + "dangerForegroundInverted": "#dc5e62", + "dangerStroke1": "#f1bbbc", + "defaultBackground": "#ffffff", + "defaultBorder": "#d1d1d1", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#242424", + "defaultCheckedHoveredBackground": "#f5f5f5", + "defaultCheckedHoveredContent": "#242424", + "defaultContent": "#242424", + "defaultDisabledBackground": "#f0f0f0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#bdbdbd", + "defaultDisabledIcon": "#bdbdbd", + "defaultFocusedBackground": "#f5f5f5", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#242424", + "defaultFocusedIcon": "#242424", + "defaultHoveredBackground": "#f5f5f5", + "defaultHoveredBorder": "#c7c7c7", + "defaultHoveredContent": "#242424", + "defaultHoveredIcon": "#242424", + "defaultHoveredSecondaryContent": "#424242", + "defaultIcon": "#242424", + "defaultPressedBackground": "#e0e0e0", + "defaultPressedBorder": "#b3b3b3", + "defaultPressedContent": "#242424", + "defaultPressedIcon": "#242424", + "defaultPressedSecondaryContent": "#424242", + "disabledBackground": "#f0f0f0", + "disabledBodyText": "#bdbdbd", + "disabledText": "#bdbdbd", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#242424", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#242424", + "ghostContent": "#242424", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#bdbdbd", + "ghostDisabledIcon": "#bdbdbd", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#242424", + "ghostFocusedIcon": "#242424", + "ghostFocusedSecondaryContent": "#616161", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#242424", + "ghostHoveredIcon": "#242424", + "ghostHoveredSecondaryContent": "#424242", + "ghostIcon": "#242424", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#242424", + "ghostPressedIcon": "#242424", + "ghostPressedSecondaryContent": "#424242", + "ghostSecondaryContent": "#616161", + "inputBackground": "#ffffff", + "inputBorder": "#d1d1d1", + "inputFocusBorderAlt": "#185abd", + "inputPlaceholderText": "#707070", + "inputText": "#242424", + "link": "#185abd", + "linkHovered": "#1651aa", + "linkPressed": "#0e336a", + "listHeaderBackgroundHovered": "#f5f5f5", + "listHeaderBackgroundPressed": "#e0e0e0", + "menuBackground": "#ffffff", + "menuDivider": "#e0e0e0", + "menuIcon": "#424242", + "menuItemBackgroundHovered": "#f5f5f5", + "menuItemBackgroundPressed": "#e0e0e0", + "menuItemText": "#242424", + "menuItemTextHovered": "#242424", + "neutralBackground1": "#ffffff", + "neutralBackground1Hover": "#f5f5f5", + "neutralBackground1Pressed": "#e0e0e0", + "neutralBackground1Selected": "#ebebeb", + "neutralBackground2": "#fafafa", + "neutralBackground2Hover": "#f0f0f0", + "neutralBackground2Pressed": "#dbdbdb", + "neutralBackground2Selected": "#e6e6e6", + "neutralBackground3": "#f5f5f5", + "neutralBackground3Hover": "#ebebeb", + "neutralBackground3Pressed": "#d6d6d6", + "neutralBackground3Selected": "#e0e0e0", + "neutralBackground4": "#f0f0f0", + "neutralBackground4Hover": "#fafafa", + "neutralBackground4Pressed": "#f5f5f5", + "neutralBackground4Selected": "#ffffff", + "neutralBackground5": "#ebebeb", + "neutralBackground5Hover": "#f5f5f5", + "neutralBackground5Pressed": "#f0f0f0", + "neutralBackground5Selected": "#fafafa", + "neutralBackground6": "#e6e6e6", + "neutralBackgroundCanvas": "#ffffff", + "neutralBackgroundDarkStatic": "#242424", + "neutralBackgroundDisabled": "#f0f0f0", + "neutralBackgroundInverted": "#616161", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#f0f0f0", + "neutralForeground1": "#242424", + "neutralForeground1Hover": "#242424", + "neutralForeground1Pressed": "#242424", + "neutralForeground1Selected": "#242424", + "neutralForeground2": "#424242", + "neutralForeground2BrandHover": "#1651aa", + "neutralForeground2BrandPressed": "#0e336a", + "neutralForeground2BrandSelected": "#13458f", + "neutralForeground2Hover": "#242424", + "neutralForeground2Pressed": "#242424", + "neutralForeground2Selected": "#242424", + "neutralForeground3": "#616161", + "neutralForeground3BrandHover": "#1651aa", + "neutralForeground3BrandPressed": "#0e336a", + "neutralForeground3BrandSelected": "#13458f", + "neutralForeground3Hover": "#424242", + "neutralForeground3Pressed": "#424242", + "neutralForeground3Selected": "#424242", + "neutralForeground4": "#707070", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#bdbdbd", + "neutralForegroundDisabled1": "#bdbdbd", + "neutralForegroundDisabled2": "#bdbdbd", + "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#ffffff", + "neutralForegroundInvertedLinkHover": "#ffffff", + "neutralForegroundInvertedLinkPressed": "#ffffff", + "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#ffffff", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", + "neutralStencil1": "#e6e6e6", + "neutralStencil2": "#fafafa", + "neutralStroke1": "#d1d1d1", + "neutralStroke1Hover": "#c7c7c7", + "neutralStroke1Pressed": "#b3b3b3", + "neutralStroke1Selected": "#bdbdbd", + "neutralStroke2": "#e0e0e0", + "neutralStroke3": "#f0f0f0", + "neutralStrokeAccessible": "#616161", + "neutralStrokeAccessibleHover": "#575757", + "neutralStrokeAccessiblePressed": "#4d4d4d", + "neutralStrokeAccessibleSelected": "#185abd", + "neutralStrokeDisabled": "#e0e0e0", + "neutralStrokeFocus1": "#ffffff", + "neutralStrokeFocus2": "#000000", + "outofofficeBackground1": "#fdf5fc", + "outofofficeBackground2": "#edbbe7", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#edbbe7", + "outofofficeBorder2": "#c239b3", + "outofofficeBorderActive": "#c239b3", + "outofofficeForeground1": "#af33a1", + "outofofficeForeground2": "#6d2064", + "outofofficeForeground3": "#c239b3", + "personaActivityGlow": "#185abd", + "personaActivityRing": "#ffffff", + "presenceAvailable": "#0e700e", + "presenceAway": "#817400", + "presenceDnd": "#bc2f32", + "presenceOof": "#af33a1", + "primaryButtonBackground": "#185abd", + "primaryButtonBackgroundDisabled": "#f0f0f0", + "primaryButtonBackgroundHovered": "#1651aa", + "primaryButtonBackgroundPressed": "#0e336a", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#000000", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#bdbdbd", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#f1bbbc", + "redBackground3": "#d13438", + "redBorder1": "#f1bbbc", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#751d1f", + "redForeground3": "#d13438", + "severeBackground1": "#fdf6f3", + "severeBackground2": "#f4bfab", + "severeBackground3": "#da3b01", + "severeBorder1": "#f4bfab", + "severeBorder2": "#da3b01", + "severeBorderActive": "#da3b01", + "severeForeground1": "#c43501", + "severeForeground2": "#7a2101", + "severeForeground3": "#da3b01", + "severeStroke1": "#f4bfab", + "strokeFocus1": "#ffffff", + "strokeFocus2": "#000000", + "subText": "#424242", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#f5f5f5", + "subtleBackgroundPressed": "#e0e0e0", + "subtleBackgroundSelected": "#ebebeb", + "successBackground1": "#f1faf1", + "successBackground2": "#9fd89f", + "successBackground3": "#107c10", + "successBorder1": "#9fd89f", + "successBorder2": "#107c10", + "successBorderActive": "#107c10", + "successForeground1": "#0e700e", + "successForeground2": "#094509", + "successForeground3": "#107c10", + "successForegroundInverted": "#359b35", + "successStroke1": "#9fd89f", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#e0e0e0", + "warningBackground1": "#fffef5", + "warningBackground2": "#fef7b2", + "warningBackground3": "#fde300", + "warningBorder1": "#fef7b2", + "warningBorder2": "#fde300", + "warningBorderActive": "#fde300", + "warningForeground1": "#817400", + "warningForeground2": "#817400", + "warningForeground3": "#fde300", + "warningForegroundInverted": "#fef7b2", + "warningStroke1": "#fef7b2", + }, + "components": {}, + "host": { + "appearance": "light", + }, + "shadows": { + "shadow16": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000024", + "x": 0, + "y": 8, + }, }, - "neutralBackground2Pressed": { - "resource_paths": [ - "Highlight", - ], + "shadow16brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000040", + "x": 0, + "y": 8, + }, }, - "neutralBackground2Selected": { - "resource_paths": [ - "Highlight", - ], + "shadow2": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000024", + "x": 0, + "y": 1, + }, }, - "neutralBackground3": { - "resource_paths": [ - "Window", - ], + "shadow28": { + "ambient": { + "blur": 8, + "color": "#00000033", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#0000003d", + "x": 0, + "y": 14, + }, }, - "neutralBackground3Hover": { - "resource_paths": [ - "Highlight", - ], + "shadow28brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#00000040", + "x": 0, + "y": 14, + }, }, - "neutralBackground3Pressed": { - "resource_paths": [ - "Highlight", - ], + "shadow2brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000040", + "x": 0, + "y": 1, + }, }, - "neutralBackground3Selected": { - "resource_paths": [ - "Highlight", - ], + "shadow4": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000024", + "x": 0, + "y": 2, + }, }, - "neutralBackground4": { + "shadow4brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000040", + "x": 0, + "y": 2, + }, + }, + "shadow64": { + "ambient": { + "blur": 8, + "color": "#00000033", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#0000003d", + "x": 0, + "y": 32, + }, + }, + "shadow64brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#00000040", + "x": 0, + "y": 32, + }, + }, + "shadow8": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000024", + "x": 0, + "y": 4, + }, + }, + "shadow8brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000040", + "x": 0, + "y": 4, + }, + }, + }, + "spacing": { + "l1": "20px", + "l2": "32px", + "m": "16px", + "s1": "8px", + "s2": "4px", + }, + "typography": { + "families": { + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", + "primary": "Segoe UI", + "sansSerif": "Segoe UI", + "secondary": "Segoe UI", + "serif": "Segoe UI", + }, + "sizes": { + "body": 14, + "caption": 10, + "header": 20, + "hero": 28, + "heroLarge": 40, + "secondary": 12, + "subheader": 16, + }, + "variants": { + "body1": { + "face": "primary", + "size": 12, + "weight": "400", + }, + "body1Strong": { + "face": "primary", + "size": 12, + "weight": "600", + }, + "body2": { + "face": "primary", + "size": 14, + "weight": "400", + }, + "body2Strong": { + "face": "primary", + "size": 14, + "weight": "600", + }, + "bodySemibold": { + "face": "primary", + "size": 14, + "weight": "600", + }, + "bodyStandard": { + "face": "primary", + "size": 14, + "weight": "400", + }, + "caption1": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "caption1Strong": { + "face": "primary", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "captionStandard": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "display": { + "face": "primary", + "size": 40, + "weight": "600", + }, + "headerSemibold": { + "face": "primary", + "size": 20, + "weight": "600", + }, + "headerStandard": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "heroLargeSemibold": { + "face": "primary", + "size": 40, + "weight": "600", + }, + "heroLargeStandard": { + "face": "primary", + "size": 40, + "weight": "400", + }, + "heroSemibold": { + "face": "primary", + "size": 28, + "weight": "600", + }, + "heroStandard": { + "face": "primary", + "size": 28, + "weight": "400", + }, + "largeTitle": { + "face": "primary", + "size": 40, + "weight": "400", + }, + "secondarySemibold": { + "face": "primary", + "size": 12, + "weight": "600", + }, + "secondaryStandard": { + "face": "primary", + "size": 12, + "weight": "400", + }, + "subheaderSemibold": { + "face": "primary", + "size": 16, + "weight": "600", + }, + "subheaderStandard": { + "face": "primary", + "size": 16, + "weight": "400", + }, + "subtitle1": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "subtitle1Strong": { + "face": "primary", + "size": 20, + "weight": "600", + }, + "subtitle2": { + "face": "primary", + "size": 16, + "weight": "400", + }, + "subtitle2Strong": { + "face": "primary", + "size": 16, + "weight": "600", + }, + "title1": { + "face": "primary", + "size": 28, + "weight": "400", + }, + "title1Strong": { + "face": "primary", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", + }, + }, + "weights": { + "regular": "400", + "semiBold": "600", + }, + }, +} +`; + +exports[`high contrast dark theme 1`] = ` +{ + "colors": { + "accentButtonBackground": { "resource_paths": [ - "Window", + "ButtonFace", ], }, - "neutralBackground4Hover": { + "actionLink": { "resource_paths": [ - "Highlight", + "WindowText", ], }, - "neutralBackground4Pressed": { + "background": { "resource_paths": [ - "Highlight", + "Window", ], }, - "neutralBackground4Selected": { + "bodyDivider": { "resource_paths": [ - "Highlight", + "WindowText", ], }, - "neutralBackground5": { + "bodyFrameBackground": { "resource_paths": [ "Window", ], }, - "neutralBackground5Hover": { + "bodyFrameDivider": { "resource_paths": [ - "Highlight", + "WindowText", ], }, - "neutralBackground5Pressed": { + "bodyStandoutBackground": { "resource_paths": [ - "Highlight", + "Window", ], }, - "neutralBackground5Selected": { + "bodyText": { "resource_paths": [ - "Highlight", + "WindowText", ], }, - "neutralBackground6": { + "bodyTextChecked": { "resource_paths": [ - "Window", + "HighlightText", ], }, - "neutralBackgroundDisabled": { + "brandBackground": { "resource_paths": [ - "Window", + "ButtonFace", ], }, - "neutralBackgroundInverted": { + "brandBackground2": { "resource_paths": [ - "WindowText", + "ButtonFace", ], }, - "neutralForeground1": { + "brandBackground2Pressed": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "neutralForeground1Hover": { + "brandBackground2Selected": { "resource_paths": [ - "HighlightText", + "Highlight", ], }, - "neutralForeground1Pressed": { + "brandBackground3": { "resource_paths": [ - "HighlightText", + "ButtonFace", ], }, - "neutralForeground1Selected": { + "brandBackgroundDisabled": { "resource_paths": [ - "HighlightText", + "Window", ], }, - "neutralForeground2": { + "brandBackgroundHover": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "neutralForeground2BrandHover": { + "brandBackgroundInverted": { "resource_paths": [ - "HighlightText", + "WindowText", ], }, - "neutralForeground2BrandPressed": { + "brandBackgroundInvertedDisabled": { "resource_paths": [ - "HighlightText", + "Window", ], }, - "neutralForeground2BrandSelected": { + "brandBackgroundPressed": { "resource_paths": [ - "HighlightText", + "Highlight", ], }, - "neutralForeground2Hover": { + "brandBackgroundSelected": { "resource_paths": [ - "HighlightText", + "Highlight", ], }, - "neutralForeground2Pressed": { + "brandBackgroundStatic": { "resource_paths": [ - "HighlightText", + "Window", ], }, - "neutralForeground2Selected": { + "brandBackgroundTint": { "resource_paths": [ - "HighlightText", + "ButtonFace", ], }, - "neutralForeground3": { + "brandForeground1": { "resource_paths": [ "WindowText", ], }, - "neutralForeground3BrandHover": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground3BrandPressed": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground3BrandSelected": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForeground3Hover": { + "brandForeground1Disabled": { "resource_paths": [ - "HighlightText", + "GrayText", ], }, - "neutralForeground3Pressed": { + "brandForeground1Pressed": { "resource_paths": [ - "HighlightText", + "WindowText", ], }, - "neutralForeground3Selected": { + "brandForeground1Selected": { "resource_paths": [ - "HighlightText", + "WindowText", ], }, - "neutralForeground4": { + "brandForeground2": { "resource_paths": [ - "WindowText", + "ButtonText", ], }, - "neutralForegroundDisabled": { + "brandForegroundDisabled1": { "resource_paths": [ "GrayText", ], }, - "neutralForegroundInverted": { + "brandForegroundDisabled2": { "resource_paths": [ - "Window", + "GrayText", ], }, - "neutralForegroundInvertedLink": { + "brandForegroundLink": { "resource_paths": [ "Hotlight", ], }, - "neutralForegroundInvertedLinkHover": { + "brandForegroundLinkHover": { "resource_paths": [ "Hotlight", ], }, - "neutralForegroundInvertedLinkPressed": { + "brandForegroundLinkPressed": { "resource_paths": [ "Hotlight", ], }, - "neutralForegroundInvertedLinkSelected": { + "brandForegroundLinkSelected": { "resource_paths": [ "Hotlight", ], }, - "neutralForegroundOnBrand": { + "brandForegroundTint": { "resource_paths": [ "ButtonText", ], }, - "neutralForegroundOnBrandHover": { - "resource_paths": [ - "HighlightText", - ], - }, - "neutralForegroundOnBrandPressed": { + "brandStroke1": { "resource_paths": [ - "HighlightText", + "WindowText", ], }, - "neutralForegroundOnBrandSelected": { + "brandStroke1Pressed": { "resource_paths": [ - "HighlightText", + "WindowText", ], }, - "neutralStencil1": "#141414", - "neutralStencil2": "#858585", - "neutralStroke1": { + "brandStroke1Selected": { "resource_paths": [ "WindowText", ], }, - "neutralStroke1Hover": { + "brandStroke2": { "resource_paths": [ - "Highlight", + "Window", ], }, - "neutralStroke1Pressed": { + "brandStrokeTint": { "resource_paths": [ - "Highlight", + "Window", ], }, - "neutralStroke1Selected": { + "brandedBackground": { "resource_paths": [ - "Highlight", + "ButtonFace", ], }, - "neutralStroke2": { + "brandedDisabledBorder": { "resource_paths": [ - "WindowText", + "GrayText", ], }, - "neutralStroke3": { + "brandedFocusedSecondaryContent": { "resource_paths": [ - "WindowText", + "HighlightText", ], }, - "neutralStrokeAccessible": { + "brandedHoveredSecondaryContent": { "resource_paths": [ - "WindowText", + "HighlightText", ], }, - "neutralStrokeAccessibleHover": { + "brandedPressedSecondaryContent": { "resource_paths": [ - "Highlight", + "HighlightText", ], }, - "neutralStrokeAccessiblePressed": { + "brandedSecondaryContent": { "resource_paths": [ - "Highlight", + "ButtonText", ], }, - "neutralStrokeAccessibleSelected": { + "buttonBackground": { "resource_paths": [ - "Highlight", + "Window", ], }, - "neutralStrokeDisabled": { + "buttonBackgroundChecked": { "resource_paths": [ - "GrayText", + "Highlight", ], }, - "outofofficeBackground1": { + "buttonBackgroundDisabled": { "resource_paths": [ "Window", ], }, - "outofofficeBackground2": { + "buttonBackgroundHovered": { "resource_paths": [ - "Window", + "Highlight", ], }, - "outofofficeBackground3": { + "buttonBackgroundPressed": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "outofofficeBorder1": { + "buttonBorder": { "resource_paths": [ "WindowText", ], }, - "outofofficeBorder2": { + "buttonBorderDisabled": { "resource_paths": [ - "WindowText", + "GrayText", ], }, - "outofofficeBorderActive": { + "buttonBorderFocused": { "resource_paths": [ "Highlight", ], }, - "outofofficeForeground1": { + "buttonText": { "resource_paths": [ "WindowText", ], }, - "outofofficeForeground2": { + "buttonTextChecked": { "resource_paths": [ - "WindowText", + "HighlightText", ], }, - "outofofficeForeground3": { + "buttonTextDisabled": { "resource_paths": [ - "WindowText", + "GrayText", ], }, - "personaActivityGlow": "transparent", - "personaActivityRing": "#ffffff", - "primaryButtonBackground": "#000000", - "primaryButtonBackgroundDisabled": "#000000", - "primaryButtonBackgroundHovered": "#1aebff", - "primaryButtonBackgroundPressed": "#1aebff", - "primaryButtonBorder": "#ffffff", - "primaryButtonBorderFocused": "#ffffff", - "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#3ff23f", - "primaryButtonTextHovered": "#000000", - "primaryButtonTextPressed": "#000000", - "severeBackground1": { + "buttonTextHovered": { "resource_paths": [ - "Window", + "HighlightText", ], }, - "severeBackground2": { + "buttonTextPressed": { "resource_paths": [ - "Window", + "HighlightText", ], }, - "severeBackground3": { + "checkboxBackground": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "severeBorder1": { + "checkboxBackgroundDisabled": { "resource_paths": [ - "WindowText", + "Window", ], }, - "severeBorder2": { + "checkboxBorderColor": { "resource_paths": [ "WindowText", ], }, - "severeBorderActive": { + "checkmarkColor": { + "resource_paths": [ + "ButtonText", + ], + }, + "compoundBrandBackground1": { "resource_paths": [ "Highlight", ], }, - "severeForeground1": { + "compoundBrandBackground1Hover": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "severeForeground2": { + "compoundBrandBackground1Pressed": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "severeForeground3": { + "compoundBrandForeground1": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "strokeFocus1": { + "compoundBrandForeground1Hover": { "resource_paths": [ - "Window", + "Highlight", ], }, - "strokeFocus2": { + "compoundBrandForeground1Pressed": { "resource_paths": [ "Highlight", ], }, - "subText": "#ffffff", - "subtleBackground": "#00000000", - "subtleBackgroundHover": { + "compoundBrandStroke1": { "resource_paths": [ "Highlight", ], }, - "subtleBackgroundPressed": { + "compoundBrandStroke1Hover": { "resource_paths": [ "Highlight", ], }, - "subtleBackgroundSelected": { + "compoundBrandStroke1Pressed": { "resource_paths": [ "Highlight", ], }, - "successBackground1": { + "dangerBackground1": { "resource_paths": [ "Window", ], }, - "successBackground2": { + "dangerBackground2": { "resource_paths": [ "Window", ], }, - "successBackground3": { + "dangerBackground3": { "resource_paths": [ "WindowText", ], }, - "successBorder1": { + "dangerBorder1": { "resource_paths": [ "WindowText", ], }, - "successBorder2": { + "dangerBorder2": { "resource_paths": [ "WindowText", ], }, - "successBorderActive": { + "dangerBorderActive": { "resource_paths": [ "Highlight", ], }, - "successForeground1": { + "dangerForeground1": { "resource_paths": [ "WindowText", ], }, - "successForeground2": { + "dangerForeground2": { "resource_paths": [ "WindowText", ], }, - "successForeground3": { + "dangerForeground3": { "resource_paths": [ "WindowText", ], }, - "successForegroundInverted": { + "dangerForegroundInverted": { "resource_paths": [ "WindowText", ], }, - "transparentBackground": "#00000000", - "transparentBackgroundHover": "#00000000", - "transparentBackgroundPressed": "#00000000", - "transparentBackgroundSelected": "#00000000", - "transparentStroke": { + "dangerStroke1": { "resource_paths": [ "WindowText", ], }, - "transparentStrokeDisabled": { + "defaultBackground": { "resource_paths": [ - "GrayText", + "Window", ], }, - "transparentStrokeInteractive": { + "defaultBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "defaultCheckedBackground": { "resource_paths": [ "Highlight", ], }, - "variantBorder": "#ffffff", - "warningBackground1": { + "defaultCheckedContent": { "resource_paths": [ - "Window", + "HighlightText", ], }, - "warningBackground2": { + "defaultCheckedHoveredBackground": { "resource_paths": [ - "Window", + "Highlight", ], }, - "warningBackground3": { + "defaultCheckedHoveredContent": { "resource_paths": [ - "WindowText", + "HighlightText", ], }, - "warningBorder1": { + "defaultContent": { "resource_paths": [ "WindowText", ], }, - "warningBorder2": { + "defaultDisabledBackground": { "resource_paths": [ - "WindowText", + "Window", ], }, - "warningBorderActive": { + "defaultDisabledBorder": { "resource_paths": [ - "Highlight", + "GrayText", ], }, - "warningForeground1": { + "defaultDisabledContent": { "resource_paths": [ - "WindowText", + "GrayText", ], }, - "warningForeground2": { + "defaultDisabledIcon": { "resource_paths": [ - "WindowText", + "GrayText", ], }, - "warningForeground3": { + "defaultFocusedBackground": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - "warningForegroundInverted": { + "defaultFocusedBorder": { "resource_paths": [ - "WindowText", + "Highlight", ], }, - }, - "components": {}, - "host": { - "appearance": "highContrast", - }, - "shadows": { - "shadow16": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 16, - "color": "#00000047", - "x": 0, - "y": 8, - }, + "defaultFocusedContent": { + "resource_paths": [ + "HighlightText", + ], }, - "shadow16brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 16, - "color": "#00000040", - "x": 0, - "y": 8, - }, + "defaultFocusedIcon": { + "resource_paths": [ + "HighlightText", + ], }, - "shadow2": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 2, - "color": "#00000047", - "x": 0, - "y": 1, - }, + "defaultHoveredBackground": { + "resource_paths": [ + "Highlight", + ], }, - "shadow28": { - "ambient": { - "blur": 8, - "color": "#00000066", - "x": 0, - "y": 0, - }, - "key": { - "blur": 28, - "color": "#0000007a", - "x": 0, - "y": 14, - }, + "defaultHoveredBorder": { + "resource_paths": [ + "Highlight", + ], }, - "shadow28brand": { - "ambient": { - "blur": 8, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 28, - "color": "#00000040", - "x": 0, - "y": 14, - }, + "defaultHoveredContent": { + "resource_paths": [ + "HighlightText", + ], }, - "shadow2brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 2, - "color": "#00000040", - "x": 0, - "y": 1, - }, + "defaultHoveredIcon": { + "resource_paths": [ + "HighlightText", + ], }, - "shadow4": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 4, - "color": "#00000047", - "x": 0, - "y": 2, - }, + "defaultHoveredSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], }, - "shadow4brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 4, - "color": "#00000040", - "x": 0, - "y": 2, - }, + "defaultIcon": { + "resource_paths": [ + "WindowText", + ], }, - "shadow64": { - "ambient": { - "blur": 8, - "color": "#00000066", - "x": 0, - "y": 0, - }, - "key": { - "blur": 64, - "color": "#0000007a", - "x": 0, - "y": 32, - }, + "defaultPressedBackground": { + "resource_paths": [ + "Highlight", + ], }, - "shadow64brand": { - "ambient": { - "blur": 8, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 64, - "color": "#00000040", - "x": 0, - "y": 32, - }, + "defaultPressedBorder": { + "resource_paths": [ + "Highlight", + ], }, - "shadow8": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 8, - "color": "#00000047", - "x": 0, - "y": 4, - }, + "defaultPressedContent": { + "resource_paths": [ + "HighlightText", + ], }, - "shadow8brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 8, - "color": "#00000040", - "x": 0, - "y": 4, - }, + "defaultPressedIcon": { + "resource_paths": [ + "HighlightText", + ], }, - }, - "spacing": { - "l1": "20px", - "l2": "32px", - "m": "16px", - "s1": "8px", - "s2": "4px", - }, - "typography": { - "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", - "primary": "Segoe UI", - "sansSerif": "System", - "secondary": "Segoe UI", - "serif": "System", + "defaultPressedSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], }, - "sizes": { - "body": 14, - "caption": 10, - "header": 20, - "hero": 28, - "heroLarge": 40, - "secondary": 12, - "subheader": 16, + "disabledBackground": { + "resource_paths": [ + "Window", + ], }, - "variants": { - "body1": { - "face": "primary", - "size": "secondary", - "weight": "regular", - }, - "body1Strong": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", - }, - "body2": { - "face": "primary", - "size": "body", - "weight": "regular", - }, - "body2Strong": { - "face": "primary", - "size": "body", - "weight": "semiBold", - }, - "bodySemibold": { - "face": "primary", - "size": "body", - "weight": "semiBold", - }, - "bodyStandard": { - "face": "primary", - "size": "body", - "weight": "regular", - }, - "caption1": { - "face": "primary", - "size": "caption", - "weight": "regular", - }, - "caption1Strong": { - "face": "primary", - "size": "caption", - "weight": "semiBold", - }, - "captionStandard": { - "face": "primary", - "size": "caption", - "weight": "regular", - }, - "display": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", - }, - "headerSemibold": { - "face": "primary", - "size": "header", - "weight": "semiBold", - }, - "headerStandard": { - "face": "primary", - "size": "header", - "weight": "regular", - }, - "heroLargeSemibold": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", - }, - "heroLargeStandard": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", - }, - "heroSemibold": { - "face": "primary", - "size": "hero", - "weight": "semiBold", - }, - "heroStandard": { - "face": "primary", - "size": "hero", - "weight": "regular", - }, - "largeTitle": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", - }, - "secondarySemibold": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", + "disabledBodyText": { + "resource_paths": [ + "GrayText", + ], + }, + "disabledText": { + "resource_paths": [ + "GrayText", + ], + }, + "errorText": { + "resource_paths": [ + "WindowText", + ], + }, + "focusBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostBackground": "#00000000", + "ghostBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostCheckedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostCheckedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostCheckedHoveredBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostCheckedHoveredBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostCheckedHoveredContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostContent": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": { + "resource_paths": [ + "GrayText", + ], + }, + "ghostDisabledContent": { + "resource_paths": [ + "GrayText", + ], + }, + "ghostDisabledIcon": { + "resource_paths": [ + "GrayText", + ], + }, + "ghostFocusedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostFocusedBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostFocusedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostFocusedIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostFocusedSecondaryContent": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostHoveredBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostHoveredBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostHoveredContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostHoveredIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostHoveredSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostIcon": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostPressedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostPressedBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostPressedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostPressedIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostPressedSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostSecondaryContent": { + "resource_paths": [ + "WindowText", + ], + }, + "inputBackground": { + "resource_paths": [ + "Window", + ], + }, + "inputBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "inputFocusBorderAlt": { + "resource_paths": [ + "Highlight", + ], + }, + "inputPlaceholderText": { + "resource_paths": [ + "WindowText", + ], + }, + "inputText": { + "resource_paths": [ + "WindowText", + ], + }, + "link": { + "resource_paths": [ + "Hotlight", + ], + }, + "linkHovered": { + "resource_paths": [ + "Hotlight", + ], + }, + "linkPressed": { + "resource_paths": [ + "Hotlight", + ], + }, + "listHeaderBackgroundHovered": { + "resource_paths": [ + "Highlight", + ], + }, + "listHeaderBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "menuBackground": { + "resource_paths": [ + "Window", + ], + }, + "menuDivider": { + "resource_paths": [ + "WindowText", + ], + }, + "menuIcon": { + "resource_paths": [ + "WindowText", + ], + }, + "menuItemBackgroundHovered": { + "resource_paths": [ + "Highlight", + ], + }, + "menuItemBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "menuItemText": { + "resource_paths": [ + "WindowText", + ], + }, + "menuItemTextHovered": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralBackground1": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackground1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground1Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground2": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackground2Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground2Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground2Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground3": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackground3Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground3Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground3Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground4": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackground4Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground4Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground4Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground5": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackground5Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground5Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground5Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground6": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackgroundCanvas": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackgroundDarkStatic": "#3d3d3d", + "neutralBackgroundDisabled": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackgroundInverted": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": { + "resource_paths": [ + "Window", + ], + }, + "neutralForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralForeground1Hover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground1Pressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground1Selected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralForeground2BrandHover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2BrandPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2BrandSelected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2Hover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2Pressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2Selected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralForeground3BrandHover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3BrandPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3BrandSelected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3Hover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3Pressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3Selected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground4": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralForegroundDisabled1": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralForegroundDisabled2": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralForegroundInverted": { + "resource_paths": [ + "Window", + ], + }, + "neutralForegroundInvertedLink": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundInvertedLinkHover": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundInvertedLinkPressed": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundInvertedLinkSelected": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": { + "resource_paths": [ + "ButtonText", + ], + }, + "neutralForegroundOnBrandHover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForegroundOnBrandPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForegroundOnBrandSelected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForegroundOnColor": { + "resource_paths": [ + "ButtonText", + ], + }, + "neutralStencil1": "#141414", + "neutralStencil2": "#858585", + "neutralStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStroke1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStroke1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStroke1Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStroke2": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStroke3": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStrokeAccessible": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStrokeAccessibleHover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStrokeAccessiblePressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStrokeAccessibleSelected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStrokeDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralStrokeFocus1": { + "resource_paths": [ + "Window", + ], + }, + "neutralStrokeFocus2": { + "resource_paths": [ + "Highlight", + ], + }, + "outofofficeBackground1": { + "resource_paths": [ + "Window", + ], + }, + "outofofficeBackground2": { + "resource_paths": [ + "Window", + ], + }, + "outofofficeBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "outofofficeForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "personaActivityGlow": { + "resource_paths": [ + "ButtonFace", + ], + }, + "personaActivityRing": { + "resource_paths": [ + "Window", + ], + }, + "presenceAvailable": { + "resource_paths": [ + "WindowText", + ], + }, + "presenceAway": { + "resource_paths": [ + "WindowText", + ], + }, + "presenceDnd": { + "resource_paths": [ + "WindowText", + ], + }, + "presenceOof": { + "resource_paths": [ + "WindowText", + ], + }, + "primaryButtonBackground": { + "resource_paths": [ + "ButtonFace", + ], + }, + "primaryButtonBackgroundDisabled": { + "resource_paths": [ + "Window", + ], + }, + "primaryButtonBackgroundHovered": { + "resource_paths": [ + "Highlight", + ], + }, + "primaryButtonBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "primaryButtonBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "primaryButtonBorderFocused": { + "resource_paths": [ + "Highlight", + ], + }, + "primaryButtonText": { + "resource_paths": [ + "ButtonText", + ], + }, + "primaryButtonTextDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "primaryButtonTextHovered": { + "resource_paths": [ + "HighlightText", + ], + }, + "primaryButtonTextPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "redBackground1": { + "resource_paths": [ + "Window", + ], + }, + "redBackground2": { + "resource_paths": [ + "Window", + ], + }, + "redBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "redBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "redBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "redBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "redForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "redForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "redForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "severeBackground1": { + "resource_paths": [ + "Window", + ], + }, + "severeBackground2": { + "resource_paths": [ + "Window", + ], + }, + "severeBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "severeBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "severeBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "severeBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "severeForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "severeForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "severeForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "severeStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + "strokeFocus1": { + "resource_paths": [ + "Window", + ], + }, + "strokeFocus2": { + "resource_paths": [ + "Highlight", + ], + }, + "subText": { + "resource_paths": [ + "WindowText", + ], + }, + "subtleBackground": "#00000000", + "subtleBackgroundHover": { + "resource_paths": [ + "Highlight", + ], + }, + "subtleBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "subtleBackgroundSelected": { + "resource_paths": [ + "Highlight", + ], + }, + "successBackground1": { + "resource_paths": [ + "Window", + ], + }, + "successBackground2": { + "resource_paths": [ + "Window", + ], + }, + "successBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "successBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "successBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "successBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "successForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "successForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "successForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "successForegroundInverted": { + "resource_paths": [ + "WindowText", + ], + }, + "successStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": { + "resource_paths": [ + "WindowText", + ], + }, + "transparentStrokeDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "transparentStrokeInteractive": { + "resource_paths": [ + "Highlight", + ], + }, + "variantBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "warningBackground1": { + "resource_paths": [ + "Window", + ], + }, + "warningBackground2": { + "resource_paths": [ + "Window", + ], + }, + "warningBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "warningBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "warningBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "warningBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "warningForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "warningForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "warningForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "warningForegroundInverted": { + "resource_paths": [ + "WindowText", + ], + }, + "warningStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + }, + "components": {}, + "host": { + "appearance": "highContrast", + }, + "shadows": { + "shadow16": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000047", + "x": 0, + "y": 8, + }, + }, + "shadow16brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000040", + "x": 0, + "y": 8, + }, + }, + "shadow2": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000047", + "x": 0, + "y": 1, + }, + }, + "shadow28": { + "ambient": { + "blur": 8, + "color": "#00000066", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#0000007a", + "x": 0, + "y": 14, + }, + }, + "shadow28brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#00000040", + "x": 0, + "y": 14, + }, + }, + "shadow2brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000040", + "x": 0, + "y": 1, + }, + }, + "shadow4": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000047", + "x": 0, + "y": 2, + }, + }, + "shadow4brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000040", + "x": 0, + "y": 2, + }, + }, + "shadow64": { + "ambient": { + "blur": 8, + "color": "#00000066", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#0000007a", + "x": 0, + "y": 32, + }, + }, + "shadow64brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#00000040", + "x": 0, + "y": 32, + }, + }, + "shadow8": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000047", + "x": 0, + "y": 4, + }, + }, + "shadow8brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000040", + "x": 0, + "y": 4, + }, + }, + }, + "spacing": { + "l1": "20px", + "l2": "32px", + "m": "16px", + "s1": "8px", + "s2": "4px", + }, + "typography": { + "families": { + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", + "primary": "Segoe UI", + "sansSerif": "Segoe UI", + "secondary": "Segoe UI", + "serif": "Segoe UI", + }, + "sizes": { + "body": 14, + "caption": 10, + "header": 20, + "hero": 28, + "heroLarge": 40, + "secondary": 12, + "subheader": 16, + }, + "variants": { + "body1": { + "face": "primary", + "size": 12, + "weight": "400", + }, + "body1Strong": { + "face": "primary", + "size": 12, + "weight": "600", + }, + "body2": { + "face": "primary", + "size": 14, + "weight": "400", + }, + "body2Strong": { + "face": "primary", + "size": 14, + "weight": "600", + }, + "bodySemibold": { + "face": "primary", + "size": 14, + "weight": "600", + }, + "bodyStandard": { + "face": "primary", + "size": 14, + "weight": "400", + }, + "caption1": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "caption1Strong": { + "face": "primary", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "captionStandard": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "display": { + "face": "primary", + "size": 40, + "weight": "600", + }, + "headerSemibold": { + "face": "primary", + "size": 20, + "weight": "600", + }, + "headerStandard": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "heroLargeSemibold": { + "face": "primary", + "size": 40, + "weight": "600", + }, + "heroLargeStandard": { + "face": "primary", + "size": 40, + "weight": "400", + }, + "heroSemibold": { + "face": "primary", + "size": 28, + "weight": "600", + }, + "heroStandard": { + "face": "primary", + "size": 28, + "weight": "400", + }, + "largeTitle": { + "face": "primary", + "size": 40, + "weight": "400", + }, + "secondarySemibold": { + "face": "primary", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, - "weights": { - "regular": "400", - "semiBold": "600", + "weights": { + "regular": "400", + "semiBold": "600", + }, + }, +} +`; + +exports[`high contrast light theme 1`] = ` +{ + "colors": { + "accentButtonBackground": { + "resource_paths": [ + "ButtonFace", + ], + }, + "actionLink": { + "resource_paths": [ + "WindowText", + ], + }, + "background": { + "resource_paths": [ + "Window", + ], + }, + "bodyDivider": { + "resource_paths": [ + "WindowText", + ], + }, + "bodyFrameBackground": { + "resource_paths": [ + "Window", + ], + }, + "bodyFrameDivider": { + "resource_paths": [ + "WindowText", + ], + }, + "bodyStandoutBackground": { + "resource_paths": [ + "Window", + ], + }, + "bodyText": { + "resource_paths": [ + "WindowText", + ], + }, + "bodyTextChecked": { + "resource_paths": [ + "HighlightText", + ], + }, + "brandBackground": { + "resource_paths": [ + "ButtonFace", + ], + }, + "brandBackground2": { + "resource_paths": [ + "ButtonFace", + ], + }, + "brandBackground2Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "brandBackground2Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "brandBackground3": { + "resource_paths": [ + "ButtonFace", + ], + }, + "brandBackgroundDisabled": { + "resource_paths": [ + "Window", + ], + }, + "brandBackgroundHover": { + "resource_paths": [ + "Highlight", + ], + }, + "brandBackgroundInverted": { + "resource_paths": [ + "WindowText", + ], + }, + "brandBackgroundInvertedDisabled": { + "resource_paths": [ + "Window", + ], + }, + "brandBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "brandBackgroundSelected": { + "resource_paths": [ + "Highlight", + ], + }, + "brandBackgroundStatic": { + "resource_paths": [ + "Window", + ], + }, + "brandBackgroundTint": { + "resource_paths": [ + "ButtonFace", + ], + }, + "brandForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "brandForeground1Disabled": { + "resource_paths": [ + "GrayText", + ], + }, + "brandForeground1Pressed": { + "resource_paths": [ + "WindowText", + ], + }, + "brandForeground1Selected": { + "resource_paths": [ + "WindowText", + ], + }, + "brandForeground2": { + "resource_paths": [ + "ButtonText", + ], + }, + "brandForegroundDisabled1": { + "resource_paths": [ + "GrayText", + ], + }, + "brandForegroundDisabled2": { + "resource_paths": [ + "GrayText", + ], + }, + "brandForegroundLink": { + "resource_paths": [ + "Hotlight", + ], + }, + "brandForegroundLinkHover": { + "resource_paths": [ + "Hotlight", + ], + }, + "brandForegroundLinkPressed": { + "resource_paths": [ + "Hotlight", + ], + }, + "brandForegroundLinkSelected": { + "resource_paths": [ + "Hotlight", + ], + }, + "brandForegroundTint": { + "resource_paths": [ + "ButtonText", + ], + }, + "brandStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + "brandStroke1Pressed": { + "resource_paths": [ + "WindowText", + ], + }, + "brandStroke1Selected": { + "resource_paths": [ + "WindowText", + ], + }, + "brandStroke2": { + "resource_paths": [ + "Window", + ], + }, + "brandStrokeTint": { + "resource_paths": [ + "Window", + ], + }, + "brandedBackground": { + "resource_paths": [ + "ButtonFace", + ], + }, + "brandedDisabledBorder": { + "resource_paths": [ + "GrayText", + ], + }, + "brandedFocusedSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "brandedHoveredSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "brandedPressedSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "brandedSecondaryContent": { + "resource_paths": [ + "ButtonText", + ], + }, + "buttonBackground": { + "resource_paths": [ + "Window", + ], + }, + "buttonBackgroundChecked": { + "resource_paths": [ + "Highlight", + ], + }, + "buttonBackgroundDisabled": { + "resource_paths": [ + "Window", + ], + }, + "buttonBackgroundHovered": { + "resource_paths": [ + "Highlight", + ], + }, + "buttonBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "buttonBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "buttonBorderDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "buttonBorderFocused": { + "resource_paths": [ + "Highlight", + ], + }, + "buttonText": { + "resource_paths": [ + "WindowText", + ], + }, + "buttonTextChecked": { + "resource_paths": [ + "HighlightText", + ], + }, + "buttonTextDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "buttonTextHovered": { + "resource_paths": [ + "HighlightText", + ], + }, + "buttonTextPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "checkboxBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "checkboxBackgroundDisabled": { + "resource_paths": [ + "Window", + ], + }, + "checkboxBorderColor": { + "resource_paths": [ + "WindowText", + ], + }, + "checkmarkColor": { + "resource_paths": [ + "ButtonText", + ], + }, + "compoundBrandBackground1": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandBackground1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandBackground1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandForeground1": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandForeground1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandForeground1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandStroke1": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandStroke1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "compoundBrandStroke1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "dangerBackground1": { + "resource_paths": [ + "Window", + ], + }, + "dangerBackground2": { + "resource_paths": [ + "Window", + ], + }, + "dangerBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "dangerForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerForegroundInverted": { + "resource_paths": [ + "WindowText", + ], + }, + "dangerStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + "defaultBackground": { + "resource_paths": [ + "Window", + ], + }, + "defaultBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "defaultCheckedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultCheckedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultCheckedHoveredBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultCheckedHoveredContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultContent": { + "resource_paths": [ + "WindowText", + ], + }, + "defaultDisabledBackground": { + "resource_paths": [ + "Window", + ], + }, + "defaultDisabledBorder": { + "resource_paths": [ + "GrayText", + ], + }, + "defaultDisabledContent": { + "resource_paths": [ + "GrayText", + ], + }, + "defaultDisabledIcon": { + "resource_paths": [ + "GrayText", + ], + }, + "defaultFocusedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultFocusedBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultFocusedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultFocusedIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultHoveredBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultHoveredBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultHoveredContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultHoveredIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultHoveredSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultIcon": { + "resource_paths": [ + "WindowText", + ], + }, + "defaultPressedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultPressedBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "defaultPressedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultPressedIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "defaultPressedSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "disabledBackground": { + "resource_paths": [ + "Window", + ], + }, + "disabledBodyText": { + "resource_paths": [ + "GrayText", + ], + }, + "disabledText": { + "resource_paths": [ + "GrayText", + ], + }, + "errorText": { + "resource_paths": [ + "WindowText", + ], + }, + "focusBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostBackground": "#00000000", + "ghostBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostCheckedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostCheckedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostCheckedHoveredBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostCheckedHoveredBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostCheckedHoveredContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostContent": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": { + "resource_paths": [ + "GrayText", + ], + }, + "ghostDisabledContent": { + "resource_paths": [ + "GrayText", + ], + }, + "ghostDisabledIcon": { + "resource_paths": [ + "GrayText", + ], + }, + "ghostFocusedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostFocusedBorder": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostFocusedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostFocusedIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostFocusedSecondaryContent": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostHoveredBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostHoveredBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostHoveredContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostHoveredIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostHoveredSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostIcon": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostPressedBackground": { + "resource_paths": [ + "Highlight", + ], + }, + "ghostPressedBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "ghostPressedContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostPressedIcon": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostPressedSecondaryContent": { + "resource_paths": [ + "HighlightText", + ], + }, + "ghostSecondaryContent": { + "resource_paths": [ + "WindowText", + ], + }, + "inputBackground": { + "resource_paths": [ + "Window", + ], + }, + "inputBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "inputFocusBorderAlt": { + "resource_paths": [ + "Highlight", + ], + }, + "inputPlaceholderText": { + "resource_paths": [ + "WindowText", + ], + }, + "inputText": { + "resource_paths": [ + "WindowText", + ], + }, + "link": { + "resource_paths": [ + "Hotlight", + ], + }, + "linkHovered": { + "resource_paths": [ + "Hotlight", + ], + }, + "linkPressed": { + "resource_paths": [ + "Hotlight", + ], + }, + "listHeaderBackgroundHovered": { + "resource_paths": [ + "Highlight", + ], + }, + "listHeaderBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "menuBackground": { + "resource_paths": [ + "Window", + ], + }, + "menuDivider": { + "resource_paths": [ + "WindowText", + ], + }, + "menuIcon": { + "resource_paths": [ + "WindowText", + ], + }, + "menuItemBackgroundHovered": { + "resource_paths": [ + "Highlight", + ], + }, + "menuItemBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "menuItemText": { + "resource_paths": [ + "WindowText", + ], + }, + "menuItemTextHovered": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralBackground1": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackground1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground1Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground2": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackground2Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground2Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground2Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground3": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackground3Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground3Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground3Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground4": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackground4Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground4Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground4Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground5": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackground5Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground5Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground5Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralBackground6": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackgroundCanvas": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackgroundDarkStatic": "#3d3d3d", + "neutralBackgroundDisabled": { + "resource_paths": [ + "Window", + ], + }, + "neutralBackgroundInverted": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": { + "resource_paths": [ + "Window", + ], + }, + "neutralForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralForeground1Hover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground1Pressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground1Selected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralForeground2BrandHover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2BrandPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2BrandSelected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2Hover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2Pressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground2Selected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralForeground3BrandHover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3BrandPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3BrandSelected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3Hover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3Pressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground3Selected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForeground4": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralForegroundDisabled1": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralForegroundDisabled2": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralForegroundInverted": { + "resource_paths": [ + "Window", + ], + }, + "neutralForegroundInvertedLink": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundInvertedLinkHover": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundInvertedLinkPressed": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundInvertedLinkSelected": { + "resource_paths": [ + "Hotlight", + ], + }, + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": { + "resource_paths": [ + "ButtonText", + ], + }, + "neutralForegroundOnBrandHover": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForegroundOnBrandPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForegroundOnBrandSelected": { + "resource_paths": [ + "HighlightText", + ], + }, + "neutralForegroundOnColor": { + "resource_paths": [ + "ButtonText", + ], + }, + "neutralStencil1": "#141414", + "neutralStencil2": "#858585", + "neutralStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStroke1Hover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStroke1Pressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStroke1Selected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStroke2": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStroke3": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStrokeAccessible": { + "resource_paths": [ + "WindowText", + ], + }, + "neutralStrokeAccessibleHover": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStrokeAccessiblePressed": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStrokeAccessibleSelected": { + "resource_paths": [ + "Highlight", + ], + }, + "neutralStrokeDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "neutralStrokeFocus1": { + "resource_paths": [ + "Window", + ], + }, + "neutralStrokeFocus2": { + "resource_paths": [ + "Highlight", + ], + }, + "outofofficeBackground1": { + "resource_paths": [ + "Window", + ], + }, + "outofofficeBackground2": { + "resource_paths": [ + "Window", + ], + }, + "outofofficeBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "outofofficeForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "outofofficeForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "personaActivityGlow": { + "resource_paths": [ + "ButtonFace", + ], + }, + "personaActivityRing": { + "resource_paths": [ + "Window", + ], + }, + "presenceAvailable": { + "resource_paths": [ + "WindowText", + ], + }, + "presenceAway": { + "resource_paths": [ + "WindowText", + ], + }, + "presenceDnd": { + "resource_paths": [ + "WindowText", + ], + }, + "presenceOof": { + "resource_paths": [ + "WindowText", + ], + }, + "primaryButtonBackground": { + "resource_paths": [ + "ButtonFace", + ], + }, + "primaryButtonBackgroundDisabled": { + "resource_paths": [ + "Window", + ], + }, + "primaryButtonBackgroundHovered": { + "resource_paths": [ + "Highlight", + ], + }, + "primaryButtonBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "primaryButtonBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "primaryButtonBorderFocused": { + "resource_paths": [ + "Highlight", + ], + }, + "primaryButtonText": { + "resource_paths": [ + "ButtonText", + ], + }, + "primaryButtonTextDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "primaryButtonTextHovered": { + "resource_paths": [ + "HighlightText", + ], + }, + "primaryButtonTextPressed": { + "resource_paths": [ + "HighlightText", + ], + }, + "redBackground1": { + "resource_paths": [ + "Window", + ], + }, + "redBackground2": { + "resource_paths": [ + "Window", + ], + }, + "redBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "redBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "redBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "redBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "redForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "redForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "redForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "severeBackground1": { + "resource_paths": [ + "Window", + ], + }, + "severeBackground2": { + "resource_paths": [ + "Window", + ], + }, + "severeBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "severeBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "severeBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "severeBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "severeForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "severeForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "severeForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "severeStroke1": { + "resource_paths": [ + "WindowText", + ], + }, + "strokeFocus1": { + "resource_paths": [ + "Window", + ], + }, + "strokeFocus2": { + "resource_paths": [ + "Highlight", + ], + }, + "subText": { + "resource_paths": [ + "WindowText", + ], }, - }, -} -`; - -exports[`defaultFluentTheme 1`] = ` -{ - "colors": { - "accentButtonBackground": "#185abd", - "actionLink": "#323130", - "background": "#ffffff", - "bodyDivider": "#edebe9", - "bodyFrameBackground": "#ffffff", - "bodyFrameDivider": "#edebe9", - "bodyStandoutBackground": "#faf9f8", - "bodyText": "#323130", - "bodyTextChecked": "#000000", - "brandBackground": "#185abd", - "brandBackground2": "#eff6fc", - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": "#1651aa", - "brandBackgroundPressed": "#004578", - "brandBackgroundSelected": "#13458f", - "brandBackgroundStatic": "#185abd", - "brandForeground1": "#185abd", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": "#1651aa", - "brandForegroundLink": "#1651aa", - "brandForegroundLinkHover": "#13458f", - "brandForegroundLinkPressed": "#004578", - "brandForegroundLinkSelected": "#1651aa", - "brandStroke1": "#185abd", - "brandStroke2": "#d2e0f4", - "brandedBackground": "#185abd", - "brandedDisabledBorder": "#f3f2f1", - "brandedFocusedSecondaryContent": "#faf9f8", - "brandedHoveredSecondaryContent": "#faf9f8", - "brandedPressedSecondaryContent": "#faf9f8", - "brandedSecondaryContent": "#faf9f8", - "buttonBackground": "#f3f2f1", - "buttonBackgroundChecked": "#c8c6c4", - "buttonBackgroundDisabled": "#f3f2f1", - "buttonBackgroundHovered": "#edebe9", - "buttonBackgroundPressed": "#edebe9", - "buttonBorder": "#8a8886", - "buttonBorderDisabled": "#f3f2f1", - "buttonBorderFocused": "#8a8886", - "buttonText": "#323130", - "buttonTextChecked": "#201f1e", - "buttonTextDisabled": "#a19f9d", - "buttonTextHovered": "#201f1e", - "buttonTextPressed": "#201f1e", - "checkboxBackground": "#185abd", - "checkboxBackgroundDisabled": "#f3f2f1", - "checkboxBorderColor": "#8a8886", - "checkmarkColor": "#ffffff", - "compoundBrandBackground1": "#185abd", - "compoundBrandBackground1Hover": "#1651aa", - "compoundBrandBackground1Pressed": "#13458f", - "compoundBrandForeground1": "#185abd", - "compoundBrandForeground1Hover": "#1651aa", - "compoundBrandForeground1Pressed": "#13458f", - "compoundBrandStroke1": "#185abd", - "compoundBrandStroke1Hover": "#1651aa", - "compoundBrandStroke1Pressed": "#13458f", - "dangerBackground1": "#fdf6f6", - "dangerBackground2": "#f1bbbc", - "dangerBackground3": "#d13438", - "dangerBorder1": "#f1bbbc", - "dangerBorder2": "#d13438", - "dangerBorderActive": "#d13438", - "dangerForeground1": "#bc2f32", - "dangerForeground2": "#751d1f", - "dangerForeground3": "#d13438", - "dangerForegroundInverted": "#dc5e62", - "defaultBackground": "#f3f2f1", - "defaultBorder": "#8a8886", - "defaultCheckedBackground": "#c8c6c4", - "defaultCheckedContent": "#201f1e", - "defaultCheckedHoveredBackground": "#edebe9", - "defaultCheckedHoveredContent": "#201f1e", - "defaultContent": "#323130", - "defaultDisabledBackground": "#f3f2f1", - "defaultDisabledBorder": "#f3f2f1", - "defaultDisabledContent": "#a19f9d", - "defaultDisabledIcon": "#a19f9d", - "defaultFocusedBackground": "#edebe9", - "defaultFocusedBorder": "#8a8886", - "defaultFocusedContent": "#201f1e", - "defaultFocusedIcon": "#201f1e", - "defaultHoveredBackground": "#edebe9", - "defaultHoveredBorder": "#8a8886", - "defaultHoveredContent": "#201f1e", - "defaultHoveredIcon": "#201f1e", - "defaultHoveredSecondaryContent": "#a19f9d", - "defaultIcon": "#323130", - "defaultPressedBackground": "#edebe9", - "defaultPressedBorder": "#8a8886", - "defaultPressedContent": "#201f1e", - "defaultPressedIcon": "#201f1e", - "defaultPressedSecondaryContent": "#a19f9d", - "disabledBackground": "#f3f2f1", - "disabledBodyText": "#a19f9d", - "disabledText": "#a19f9d", - "errorText": "#a4262c", - "focusBorder": "#605e5c", - "ghostBackground": "#ffffff", - "ghostBorder": "#ffffff", - "ghostCheckedBackground": "#edebe9", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#f3f2f1", - "ghostCheckedHoveredBorder": "#201f1e", - "ghostCheckedHoveredContent": "#201f1e", - "ghostContent": "#323130", - "ghostDisabledBackground": "#ffffff", - "ghostDisabledBorder": "#ffffff", - "ghostDisabledContent": "#a19f9d", - "ghostDisabledIcon": "#a19f9d", - "ghostFocusedBackground": "#f3f2f1", - "ghostFocusedBorder": "#8a8886", - "ghostFocusedContent": "#201f1e", - "ghostFocusedIcon": "#201f1e", - "ghostFocusedSecondaryContent": "#605e5c", - "ghostHoveredBackground": "#f3f2f1", - "ghostHoveredBorder": "#f3f2f1", - "ghostHoveredContent": "#201f1e", - "ghostHoveredIcon": "#201f1e", - "ghostHoveredSecondaryContent": "#605e5c", - "ghostIcon": "#323130", - "ghostPressedBackground": "#edebe9", - "ghostPressedBorder": "#edebe9", - "ghostPressedContent": "#201f1e", - "ghostPressedIcon": "#201f1e", - "ghostPressedSecondaryContent": "#605e5c", - "ghostSecondaryContent": "#605e5c", - "inputBackground": "#ffffff", - "inputBorder": "#a19f9d", - "inputFocusBorderAlt": "#185abd", - "inputPlaceholderText": "#605e5c", - "inputText": "#323130", - "link": "#185abd", - "linkHovered": "#004578", - "linkPressed": "#13458f", - "listHeaderBackgroundHovered": "#f3f2f1", - "listHeaderBackgroundPressed": "#edebe9", - "menuBackground": "#ffffff", - "menuDivider": "#c8c6c4", - "menuIcon": "#185abd", - "menuItemBackgroundHovered": "#f3f2f1", - "menuItemBackgroundPressed": "#edebe9", - "menuItemText": "#323130", - "menuItemTextHovered": "#201f1e", - "neutralBackground1": "#ffffff", - "neutralBackground1Hover": "#f5f5f5", - "neutralBackground1Pressed": "#e0e0e0", - "neutralBackground1Selected": "#ebebeb", - "neutralBackground2": "#fafafa", - "neutralBackground2Hover": "#f0f0f0", - "neutralBackground2Pressed": "#dbdbdb", - "neutralBackground2Selected": "#e6e6e6", - "neutralBackground3": "#f5f5f5", - "neutralBackground3Hover": "#ebebeb", - "neutralBackground3Pressed": "#d6d6d6", - "neutralBackground3Selected": "#e0e0e0", - "neutralBackground4": "#f0f0f0", - "neutralBackground4Hover": "#fafafa", - "neutralBackground4Pressed": "#f5f5f5", - "neutralBackground4Selected": "#ffffff", - "neutralBackground5": "#ebebeb", - "neutralBackground5Hover": "#f5f5f5", - "neutralBackground5Pressed": "#f0f0f0", - "neutralBackground5Selected": "#fafafa", - "neutralBackground6": "#e6e6e6", - "neutralBackgroundDisabled": "#f0f0f0", - "neutralBackgroundInverted": "#616161", - "neutralForeground1": "#242424", - "neutralForeground1Hover": "#242424", - "neutralForeground1Pressed": "#242424", - "neutralForeground1Selected": "#242424", - "neutralForeground2": "#424242", - "neutralForeground2BrandHover": "#185abd", - "neutralForeground2BrandPressed": "#1651aa", - "neutralForeground2BrandSelected": "#185abd", - "neutralForeground2Hover": "#242424", - "neutralForeground2Pressed": "#242424", - "neutralForeground2Selected": "#242424", - "neutralForeground3": "#616161", - "neutralForeground3BrandHover": "#185abd", - "neutralForeground3BrandPressed": "#1651aa", - "neutralForeground3BrandSelected": "#185abd", - "neutralForeground3Hover": "#424242", - "neutralForeground3Pressed": "#424242", - "neutralForeground3Selected": "#424242", - "neutralForeground4": "#707070", - "neutralForegroundDisabled": "#bdbdbd", - "neutralForegroundInverted": "#ffffff", - "neutralForegroundInvertedLink": "#ffffff", - "neutralForegroundInvertedLinkHover": "#ffffff", - "neutralForegroundInvertedLinkPressed": "#ffffff", - "neutralForegroundInvertedLinkSelected": "#ffffff", - "neutralForegroundOnBrand": "#ffffff", - "neutralForegroundOnBrandHover": "#ffffff", - "neutralForegroundOnBrandPressed": "#ffffff", - "neutralForegroundOnBrandSelected": "#ffffff", - "neutralStencil1": "#e6e6e6", - "neutralStencil2": "#fafafa", - "neutralStroke1": "#d1d1d1", - "neutralStroke1Hover": "#c7c7c7", - "neutralStroke1Pressed": "#b3b3b3", - "neutralStroke1Selected": "#bdbdbd", - "neutralStroke2": "#e0e0e0", - "neutralStroke3": "#f0f0f0", - "neutralStrokeAccessible": "#616161", - "neutralStrokeAccessibleHover": "#575757", - "neutralStrokeAccessiblePressed": "#4d4d4d", - "neutralStrokeAccessibleSelected": "#185abd", - "neutralStrokeDisabled": "#e0e0e0", - "outofofficeBackground1": "#fdf5fc", - "outofofficeBackground2": "#edbbe7", - "outofofficeBackground3": "#c239b3", - "outofofficeBorder1": "#edbbe7", - "outofofficeBorder2": "#c239b3", - "outofofficeBorderActive": "#c239b3", - "outofofficeForeground1": "#af33a1", - "outofofficeForeground2": "#6d2064", - "outofofficeForeground3": "#c239b3", - "personaActivityGlow": "#185abd", - "personaActivityRing": "#ffffff", - "primaryButtonBackground": "#185abd", - "primaryButtonBackgroundDisabled": "#f3f2f1", - "primaryButtonBackgroundHovered": "#1651aa", - "primaryButtonBackgroundPressed": "#13458f", - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", - "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#d2d0ce", - "primaryButtonTextHovered": "#ffffff", - "primaryButtonTextPressed": "#ffffff", - "severeBackground1": "#fdf6f3", - "severeBackground2": "#f4bfab", - "severeBackground3": "#da3b01", - "severeBorder1": "#f4bfab", - "severeBorder2": "#da3b01", - "severeBorderActive": "#da3b01", - "severeForeground1": "#c43501", - "severeForeground2": "#7a2101", - "severeForeground3": "#da3b01", - "strokeFocus1": "#ffffff", - "strokeFocus2": "#000000", - "subText": "#605e5c", "subtleBackground": "#00000000", - "subtleBackgroundHover": "#f5f5f5", - "subtleBackgroundPressed": "#e0e0e0", - "subtleBackgroundSelected": "#ebebeb", - "successBackground1": "#f1faf1", - "successBackground2": "#9fd89f", - "successBackground3": "#107c10", - "successBorder1": "#9fd89f", - "successBorder2": "#107c10", - "successBorderActive": "#107c10", - "successForeground1": "#0e700e", - "successForeground2": "#094509", - "successForeground3": "#107c10", - "successForegroundInverted": "#359b35", + "subtleBackgroundHover": { + "resource_paths": [ + "Highlight", + ], + }, + "subtleBackgroundPressed": { + "resource_paths": [ + "Highlight", + ], + }, + "subtleBackgroundSelected": { + "resource_paths": [ + "Highlight", + ], + }, + "successBackground1": { + "resource_paths": [ + "Window", + ], + }, + "successBackground2": { + "resource_paths": [ + "Window", + ], + }, + "successBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "successBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "successBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "successBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "successForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "successForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "successForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "successForegroundInverted": { + "resource_paths": [ + "WindowText", + ], + }, + "successStroke1": { + "resource_paths": [ + "WindowText", + ], + }, "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", "transparentBackgroundSelected": "#00000000", - "transparentStroke": "#00000000", - "transparentStrokeDisabled": "#00000000", - "transparentStrokeInteractive": "#00000000", - "variantBorder": "#edebe9", - "warningBackground1": "#fffef5", - "warningBackground2": "#fef7b2", - "warningBackground3": "#fde300", - "warningBorder1": "#fef7b2", - "warningBorder2": "#fde300", - "warningBorderActive": "#fde300", - "warningForeground1": "#817400", - "warningForeground2": "#817400", - "warningForeground3": "#fde300", - "warningForegroundInverted": "#fef7b2", + "transparentStroke": { + "resource_paths": [ + "WindowText", + ], + }, + "transparentStrokeDisabled": { + "resource_paths": [ + "GrayText", + ], + }, + "transparentStrokeInteractive": { + "resource_paths": [ + "Highlight", + ], + }, + "variantBorder": { + "resource_paths": [ + "WindowText", + ], + }, + "warningBackground1": { + "resource_paths": [ + "Window", + ], + }, + "warningBackground2": { + "resource_paths": [ + "Window", + ], + }, + "warningBackground3": { + "resource_paths": [ + "WindowText", + ], + }, + "warningBorder1": { + "resource_paths": [ + "WindowText", + ], + }, + "warningBorder2": { + "resource_paths": [ + "WindowText", + ], + }, + "warningBorderActive": { + "resource_paths": [ + "Highlight", + ], + }, + "warningForeground1": { + "resource_paths": [ + "WindowText", + ], + }, + "warningForeground2": { + "resource_paths": [ + "WindowText", + ], + }, + "warningForeground3": { + "resource_paths": [ + "WindowText", + ], + }, + "warningForegroundInverted": { + "resource_paths": [ + "WindowText", + ], + }, + "warningStroke1": { + "resource_paths": [ + "WindowText", + ], + }, }, "components": {}, "host": { - "appearance": "light", + "appearance": "highContrast", }, "shadows": { "shadow16": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 16, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 8, }, @@ -2131,13 +4820,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow2": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 2, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 1, }, @@ -2145,13 +4834,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow28": { "ambient": { "blur": 8, - "color": "#00000033", + "color": "#00000066", "x": 0, "y": 0, }, "key": { "blur": 28, - "color": "#0000003d", + "color": "#0000007a", "x": 0, "y": 14, }, @@ -2187,13 +4876,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow4": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 4, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 2, }, @@ -2215,13 +4904,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow64": { "ambient": { "blur": 8, - "color": "#00000033", + "color": "#00000066", "x": 0, "y": 0, }, "key": { "blur": 64, - "color": "#0000003d", + "color": "#0000007a", "x": 0, "y": 32, }, @@ -2243,13 +4932,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow8": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 8, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 4, }, @@ -2278,13 +4967,13 @@ exports[`defaultFluentTheme 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -2298,138 +4987,153 @@ exports[`defaultFluentTheme 1`] = ` "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { diff --git a/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.windows.ts.snap b/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.windows.ts.snap index 75892f1df8..7de65b729d 100644 --- a/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.windows.ts.snap +++ b/packages/theming/default-theme/src/__tests__/__snapshots__/defaultThemes.test.windows.ts.snap @@ -3,55 +3,68 @@ exports[`defaultFluentDarkTheme 1`] = ` { "colors": { - "accentButtonBackground": undefined, - "actionLink": "#f3f2f1", - "background": "#1b1a19", - "bodyDivider": "#292827", - "bodyFrameBackground": "#1b1a19", - "bodyFrameDivider": "#292827", - "bodyStandoutBackground": "#201f1e", - "bodyText": "#f3f2f1", + "accentButtonBackground": "#1651aa", + "actionLink": "#ffffff", + "background": "#292929", + "bodyDivider": "#525252", + "bodyFrameBackground": "#292929", + "bodyFrameDivider": "#525252", + "bodyStandoutBackground": "#1f1f1f", + "bodyText": "#ffffff", "bodyTextChecked": "#ffffff", "brandBackground": "#1651aa", "brandBackground2": "#004578", - "brandBackgroundDisabled": undefined, + "brandBackground2Pressed": "#004578", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#004578", + "brandBackgroundDisabled": "#141414", "brandBackgroundHover": "#185abd", + "brandBackgroundInverted": "#ffffff", + "brandBackgroundInvertedDisabled": "#141414", "brandBackgroundPressed": "#004578", "brandBackgroundSelected": "#13458f", "brandBackgroundStatic": "#185abd", + "brandBackgroundTint": "#004578", "brandForeground1": "#6794d7", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, + "brandForeground1Disabled": "#5c5c5c", + "brandForeground1Pressed": "#6794d7", + "brandForeground1Selected": "#6794d7", "brandForeground2": "#aec6eb", + "brandForegroundDisabled1": "#5c5c5c", + "brandForegroundDisabled2": "#5c5c5c", "brandForegroundLink": "#2e6ac5", "brandForegroundLinkHover": "#aec6eb", "brandForegroundLinkPressed": "#6794d7", "brandForegroundLinkSelected": "#2e6ac5", + "brandForegroundTint": "#aec6eb", "brandStroke1": "#2e6ac5", + "brandStroke1Pressed": "#2e6ac5", + "brandStroke1Selected": "#2e6ac5", "brandStroke2": "#0e336a", - "brandedBackground": undefined, - "brandedDisabledBorder": "#252423", - "brandedFocusedSecondaryContent": "#201f1e", - "brandedHoveredSecondaryContent": "#201f1e", - "brandedPressedSecondaryContent": "#201f1e", - "brandedSecondaryContent": "#201f1e", - "buttonBackground": "#252423", - "buttonBackgroundChecked": "#484644", - "buttonBackgroundDisabled": "#252423", - "buttonBackgroundHovered": "#292827", - "buttonBackgroundPressed": "#292827", - "buttonBorder": "#979693", - "buttonBorderDisabled": "#252423", - "buttonBorderFocused": "#979693", + "brandStrokeTint": "#0e336a", + "brandedBackground": "#1651aa", + "brandedDisabledBorder": "#00000000", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", + "buttonBackground": "#292929", + "buttonBackgroundChecked": "#383838", + "buttonBackgroundDisabled": "#141414", + "buttonBackgroundHovered": "#3d3d3d", + "buttonBackgroundPressed": "#1f1f1f", + "buttonBorder": "#666666", + "buttonBorderDisabled": "#424242", + "buttonBorderFocused": "#ffffff", "buttonText": "#ffffff", - "buttonTextChecked": "#faf9f8", - "buttonTextDisabled": "#797775", - "buttonTextHovered": "#f3f2f1", - "buttonTextPressed": "#faf9f8", - "checkboxBackground": undefined, - "checkboxBackgroundDisabled": "#252423", - "checkboxBorderColor": "#979693", - "checkmarkColor": "#1b1a19", + "buttonTextChecked": "#ffffff", + "buttonTextDisabled": "#5c5c5c", + "buttonTextHovered": "#ffffff", + "buttonTextPressed": "#ffffff", + "checkboxBackground": "#2e6ac5", + "checkboxBackgroundDisabled": "#141414", + "checkboxBorderColor": "#adadad", + "checkmarkColor": "#ffffff", "compoundBrandBackground1": "#2e6ac5", "compoundBrandBackground1Hover": "#6794d7", "compoundBrandBackground1Pressed": "#185abd", @@ -71,83 +84,84 @@ exports[`defaultFluentDarkTheme 1`] = ` "dangerForeground2": "#f1bbbc", "dangerForeground3": "#e37d80", "dangerForegroundInverted": "#d13438", - "defaultBackground": "#252423", - "defaultBorder": "#979693", - "defaultCheckedBackground": "#484644", - "defaultCheckedContent": "#faf9f8", - "defaultCheckedHoveredBackground": "#292827", - "defaultCheckedHoveredContent": "#f3f2f1", + "dangerStroke1": "#d13438", + "defaultBackground": "#292929", + "defaultBorder": "#666666", + "defaultCheckedBackground": "#383838", + "defaultCheckedContent": "#ffffff", + "defaultCheckedHoveredBackground": "#3d3d3d", + "defaultCheckedHoveredContent": "#ffffff", "defaultContent": "#ffffff", - "defaultDisabledBackground": "#252423", - "defaultDisabledBorder": "#252423", - "defaultDisabledContent": "#797775", - "defaultDisabledIcon": "#797775", - "defaultFocusedBackground": "#292827", - "defaultFocusedBorder": "#979693", - "defaultFocusedContent": "#f3f2f1", - "defaultFocusedIcon": "#f3f2f1", - "defaultHoveredBackground": "#292827", - "defaultHoveredBorder": "#979693", - "defaultHoveredContent": "#f3f2f1", - "defaultHoveredIcon": "#f3f2f1", - "defaultHoveredSecondaryContent": "#797775", + "defaultDisabledBackground": "#141414", + "defaultDisabledBorder": "#424242", + "defaultDisabledContent": "#5c5c5c", + "defaultDisabledIcon": "#5c5c5c", + "defaultFocusedBackground": "#3d3d3d", + "defaultFocusedBorder": "#ffffff", + "defaultFocusedContent": "#ffffff", + "defaultFocusedIcon": "#ffffff", + "defaultHoveredBackground": "#3d3d3d", + "defaultHoveredBorder": "#757575", + "defaultHoveredContent": "#ffffff", + "defaultHoveredIcon": "#ffffff", + "defaultHoveredSecondaryContent": "#d6d6d6", "defaultIcon": "#ffffff", - "defaultPressedBackground": "#292827", - "defaultPressedBorder": "#979693", - "defaultPressedContent": "#faf9f8", - "defaultPressedIcon": "#faf9f8", - "defaultPressedSecondaryContent": "#797775", - "disabledBackground": "#323130", - "disabledBodyText": "#797775", - "disabledText": "#797775", - "errorText": "#ff5f5f", - "focusBorder": "#a19f9d", - "ghostBackground": "#1b1a19", - "ghostBorder": "#1b1a19", - "ghostCheckedBackground": "#292827", + "defaultPressedBackground": "#1f1f1f", + "defaultPressedBorder": "#6b6b6b", + "defaultPressedContent": "#ffffff", + "defaultPressedIcon": "#ffffff", + "defaultPressedSecondaryContent": "#d6d6d6", + "disabledBackground": "#141414", + "disabledBodyText": "#5c5c5c", + "disabledText": "#5c5c5c", + "errorText": "#e37d80", + "focusBorder": "#ffffff", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#333333", "ghostCheckedContent": "#ffffff", - "ghostCheckedHoveredBackground": "#252423", - "ghostCheckedHoveredBorder": "#faf9f8", - "ghostCheckedHoveredContent": "#faf9f8", - "ghostContent": "#f3f2f1", - "ghostDisabledBackground": "#1b1a19", - "ghostDisabledBorder": "#1b1a19", - "ghostDisabledContent": "#797775", - "ghostDisabledIcon": "#797775", - "ghostFocusedBackground": "#252423", - "ghostFocusedBorder": "#979693", - "ghostFocusedContent": "#faf9f8", - "ghostFocusedIcon": "#faf9f8", - "ghostFocusedSecondaryContent": "#a19f9d", - "ghostHoveredBackground": "#252423", - "ghostHoveredBorder": "#252423", - "ghostHoveredContent": "#faf9f8", - "ghostHoveredIcon": "#faf9f8", - "ghostHoveredSecondaryContent": "#a19f9d", - "ghostIcon": "#f3f2f1", - "ghostPressedBackground": "#292827", - "ghostPressedBorder": "#292827", - "ghostPressedContent": "#faf9f8", - "ghostPressedIcon": "#faf9f8", - "ghostPressedSecondaryContent": "#a19f9d", - "ghostSecondaryContent": "#a19f9d", - "inputBackground": "#1b1a19", - "inputBorder": "#797775", - "inputFocusBorderAlt": undefined, - "inputPlaceholderText": "#a19f9d", - "inputText": "#f3f2f1", - "link": undefined, - "linkHovered": undefined, - "linkPressed": undefined, - "listHeaderBackgroundHovered": "#252423", - "listHeaderBackgroundPressed": "#292827", - "menuBackground": "#252423", - "menuDivider": "#484644", - "menuIcon": undefined, - "menuItemBackgroundHovered": "#323130", - "menuItemBackgroundPressed": "#3b3a39", - "menuItemText": "#f3f2f1", - "menuItemTextHovered": "#faf9f8", + "ghostCheckedHoveredBackground": "#383838", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#ffffff", + "ghostContent": "#ffffff", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#5c5c5c", + "ghostDisabledIcon": "#5c5c5c", + "ghostFocusedBackground": "#383838", + "ghostFocusedBorder": "#ffffff", + "ghostFocusedContent": "#ffffff", + "ghostFocusedIcon": "#ffffff", + "ghostFocusedSecondaryContent": "#adadad", + "ghostHoveredBackground": "#383838", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#ffffff", + "ghostHoveredIcon": "#ffffff", + "ghostHoveredSecondaryContent": "#d6d6d6", + "ghostIcon": "#ffffff", + "ghostPressedBackground": "#2e2e2e", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#ffffff", + "ghostPressedIcon": "#ffffff", + "ghostPressedSecondaryContent": "#d6d6d6", + "ghostSecondaryContent": "#adadad", + "inputBackground": "#292929", + "inputBorder": "#666666", + "inputFocusBorderAlt": "#2e6ac5", + "inputPlaceholderText": "#999999", + "inputText": "#ffffff", + "link": "#2e6ac5", + "linkHovered": "#aec6eb", + "linkPressed": "#6794d7", + "listHeaderBackgroundHovered": "#3d3d3d", + "listHeaderBackgroundPressed": "#1f1f1f", + "menuBackground": "#292929", + "menuDivider": "#525252", + "menuIcon": "#d6d6d6", + "menuItemBackgroundHovered": "#3d3d3d", + "menuItemBackgroundPressed": "#1f1f1f", + "menuItemText": "#ffffff", + "menuItemTextHovered": "#ffffff", "neutralBackground1": "#292929", "neutralBackground1Hover": "#3d3d3d", "neutralBackground1Pressed": "#1f1f1f", @@ -169,8 +183,12 @@ exports[`defaultFluentDarkTheme 1`] = ` "neutralBackground5Pressed": "#050505", "neutralBackground5Selected": "#0f0f0f", "neutralBackground6": "#333333", + "neutralBackgroundCanvas": "#292929", + "neutralBackgroundDarkStatic": "#3d3d3d", "neutralBackgroundDisabled": "#141414", "neutralBackgroundInverted": "#ffffff", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#141414", "neutralForeground1": "#ffffff", "neutralForeground1Hover": "#ffffff", "neutralForeground1Pressed": "#ffffff", @@ -190,16 +208,21 @@ exports[`defaultFluentDarkTheme 1`] = ` "neutralForeground3Pressed": "#d6d6d6", "neutralForeground3Selected": "#d6d6d6", "neutralForeground4": "#999999", + "neutralForegroundDarkStatic": "#000000", "neutralForegroundDisabled": "#5c5c5c", + "neutralForegroundDisabled1": "#5c5c5c", + "neutralForegroundDisabled2": "#5c5c5c", "neutralForegroundInverted": "#242424", "neutralForegroundInvertedLink": "#ffffff", "neutralForegroundInvertedLinkHover": "#ffffff", "neutralForegroundInvertedLinkPressed": "#ffffff", "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#ffffff", "neutralForegroundOnBrandHover": "#ffffff", "neutralForegroundOnBrandPressed": "#ffffff", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#333333", "neutralStencil2": "#575757", "neutralStroke1": "#666666", @@ -213,6 +236,8 @@ exports[`defaultFluentDarkTheme 1`] = ` "neutralStrokeAccessiblePressed": "#b3b3b3", "neutralStrokeAccessibleSelected": "#6794d7", "neutralStrokeDisabled": "#424242", + "neutralStrokeFocus1": "#000000", + "neutralStrokeFocus2": "#ffffff", "outofofficeBackground1": "#3a1136", "outofofficeBackground2": "#6d2064", "outofofficeBackground3": "#c239b3", @@ -222,18 +247,31 @@ exports[`defaultFluentDarkTheme 1`] = ` "outofofficeForeground1": "#da7ed0", "outofofficeForeground2": "#edbbe7", "outofofficeForeground3": "#d161c4", - "personaActivityGlow": undefined, - "personaActivityRing": "#1b1a19", - "primaryButtonBackground": undefined, - "primaryButtonBackgroundDisabled": "#252423", - "primaryButtonBackgroundHovered": undefined, - "primaryButtonBackgroundPressed": undefined, - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", - "primaryButtonText": "#1b1a19", - "primaryButtonTextDisabled": "#3b3a39", - "primaryButtonTextHovered": "#1b1a19", - "primaryButtonTextPressed": "#1b1a19", + "personaActivityGlow": "#1651aa", + "personaActivityRing": "#292929", + "presenceAvailable": "#54b054", + "presenceAway": "#feee66", + "presenceDnd": "#e37d80", + "presenceOof": "#da7ed0", + "primaryButtonBackground": "#1651aa", + "primaryButtonBackgroundDisabled": "#141414", + "primaryButtonBackgroundHovered": "#185abd", + "primaryButtonBackgroundPressed": "#004578", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#ffffff", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#5c5c5c", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#3f1011", + "redBackground2": "#751d1f", + "redBackground3": "#d13438", + "redBorder1": "#d13438", + "redBorder2": "#dc5e62", + "redBorderActive": "#e37d80", + "redForeground1": "#e37d80", + "redForeground2": "#f1bbbc", + "redForeground3": "#e37d80", "severeBackground1": "#411200", "severeBackground2": "#7a2101", "severeBackground3": "#da3b01", @@ -243,9 +281,10 @@ exports[`defaultFluentDarkTheme 1`] = ` "severeForeground1": "#e9835e", "severeForeground2": "#f4bfab", "severeForeground3": "#e9835e", + "severeStroke1": "#da3b01", "strokeFocus1": "#000000", "strokeFocus2": "#ffffff", - "subText": "#a19f9d", + "subText": "#d6d6d6", "subtleBackground": "#00000000", "subtleBackgroundHover": "#383838", "subtleBackgroundPressed": "#2e2e2e", @@ -260,6 +299,7 @@ exports[`defaultFluentDarkTheme 1`] = ` "successForeground2": "#9fd89f", "successForeground3": "#9fd89f", "successForegroundInverted": "#107c10", + "successStroke1": "#107c10", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -267,7 +307,7 @@ exports[`defaultFluentDarkTheme 1`] = ` "transparentStroke": "#00000000", "transparentStrokeDisabled": "#00000000", "transparentStrokeInteractive": "#00000000", - "variantBorder": "#292827", + "variantBorder": "#525252", "warningBackground1": "#4c4400", "warningBackground2": "#817400", "warningBackground3": "#fde300", @@ -278,6 +318,7 @@ exports[`defaultFluentDarkTheme 1`] = ` "warningForeground2": "#fef7b2", "warningForeground3": "#fdea3d", "warningForegroundInverted": "#817400", + "warningStroke1": "#fde300", }, "components": {}, "host": { @@ -462,13 +503,13 @@ exports[`defaultFluentDarkTheme 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -482,138 +523,153 @@ exports[`defaultFluentDarkTheme 1`] = ` "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { @@ -624,1492 +680,4125 @@ exports[`defaultFluentDarkTheme 1`] = ` } `; -exports[`defaultFluentHighConstrastTheme 1`] = ` +exports[`defaultFluentTheme 1`] = ` { "colors": { - "accentButtonBackground": "#000000", - "actionLink": "#ffff00", - "background": "#000000", - "bodyDivider": "#ffffff", - "bodyFrameBackground": "#000000", - "bodyFrameDivider": "#000000", - "bodyStandoutBackground": "#000000", - "bodyText": "#ffffff", - "bodyTextChecked": "#000000", - "brandBackground": { - "windowsbrush": [ - "SystemColorButtonFaceColor", - ], - }, - "brandBackground2": { - "windowsbrush": [ - "SystemColorButtonFaceColor", - ], - }, - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "brandBackgroundPressed": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "brandBackgroundSelected": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "brandBackgroundStatic": { - "windowsbrush": [ - "SystemColorWindowColor", - ], - }, - "brandForeground1": { - "windowsbrush": [ - "SystemColorWindowTextColor", - ], - }, - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": { - "windowsbrush": [ - "SystemColorButtonTextColor", - ], - }, - "brandForegroundLink": { - "windowsbrush": [ - "SystemColorHotlightColor", - ], - }, - "brandForegroundLinkHover": { - "windowsbrush": [ - "SystemColorHotlightColor", - ], - }, - "brandForegroundLinkPressed": { - "windowsbrush": [ - "SystemColorHotlightColor", - ], - }, - "brandForegroundLinkSelected": { - "windowsbrush": [ - "SystemColorHotlightColor", - ], - }, - "brandStroke1": { - "windowsbrush": [ - "SystemColorWindowTextColor", - ], - }, - "brandStroke2": { - "windowsbrush": [ - "SystemColorWindowColor", - ], - }, - "brandedBackground": "#000000", - "brandedDisabledBorder": "#3ff23f", + "accentButtonBackground": "#185abd", + "actionLink": "#242424", + "background": "#ffffff", + "bodyDivider": "#e0e0e0", + "bodyFrameBackground": "#ffffff", + "bodyFrameDivider": "#e0e0e0", + "bodyStandoutBackground": "#fafafa", + "bodyText": "#242424", + "bodyTextChecked": "#242424", + "brandBackground": "#185abd", + "brandBackground2": "#eff6fc", + "brandBackground2Pressed": "#004578", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#eff6fc", + "brandBackgroundDisabled": "#f0f0f0", + "brandBackgroundHover": "#1651aa", + "brandBackgroundInverted": "#616161", + "brandBackgroundInvertedDisabled": "#f0f0f0", + "brandBackgroundPressed": "#004578", + "brandBackgroundSelected": "#13458f", + "brandBackgroundStatic": "#185abd", + "brandBackgroundTint": "#eff6fc", + "brandForeground1": "#185abd", + "brandForeground1Disabled": "#bdbdbd", + "brandForeground1Pressed": "#185abd", + "brandForeground1Selected": "#185abd", + "brandForeground2": "#1651aa", + "brandForegroundDisabled1": "#bdbdbd", + "brandForegroundDisabled2": "#bdbdbd", + "brandForegroundLink": "#1651aa", + "brandForegroundLinkHover": "#13458f", + "brandForegroundLinkPressed": "#004578", + "brandForegroundLinkSelected": "#1651aa", + "brandForegroundTint": "#1651aa", + "brandStroke1": "#185abd", + "brandStroke1Pressed": "#185abd", + "brandStroke1Selected": "#185abd", + "brandStroke2": "#d2e0f4", + "brandStrokeTint": "#d2e0f4", + "brandedBackground": "#185abd", + "brandedDisabledBorder": "#00000000", "brandedFocusedSecondaryContent": "#ffffff", - "brandedHoveredSecondaryContent": "#000000", - "brandedPressedSecondaryContent": "#000000", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", "brandedSecondaryContent": "#ffffff", - "buttonBackground": "#000000", - "buttonBackgroundChecked": "#1aebff", - "buttonBackgroundDisabled": "#000000", - "buttonBackgroundHovered": "#1aebff", - "buttonBackgroundPressed": "#1aebff", - "buttonBorder": "#ffffff", - "buttonBorderDisabled": "#3ff23f", - "buttonBorderFocused": "#ffffff", - "buttonText": "#ffffff", - "buttonTextChecked": "#000000", - "buttonTextDisabled": "#3ff23f", - "buttonTextHovered": "#000000", - "buttonTextPressed": "#000000", - "checkboxBackground": "#000000", - "checkboxBackgroundDisabled": "#000000", - "checkboxBorderColor": "#ffffff", + "buttonBackground": "#ffffff", + "buttonBackgroundChecked": "#ebebeb", + "buttonBackgroundDisabled": "#f0f0f0", + "buttonBackgroundHovered": "#f5f5f5", + "buttonBackgroundPressed": "#e0e0e0", + "buttonBorder": "#d1d1d1", + "buttonBorderDisabled": "#e0e0e0", + "buttonBorderFocused": "#000000", + "buttonText": "#242424", + "buttonTextChecked": "#242424", + "buttonTextDisabled": "#bdbdbd", + "buttonTextHovered": "#242424", + "buttonTextPressed": "#242424", + "checkboxBackground": "#185abd", + "checkboxBackgroundDisabled": "#f0f0f0", + "checkboxBorderColor": "#616161", "checkmarkColor": "#ffffff", - "compoundBrandBackground1": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandBackground1Hover": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandBackground1Pressed": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandForeground1": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandForeground1Hover": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandForeground1Pressed": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandStroke1": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandStroke1Hover": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "compoundBrandStroke1Pressed": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "dangerBackground1": { - "windowsbrush": [ - "SystemColorWindowColor", - ], - }, - "dangerBackground2": { - "windowsbrush": [ - "SystemColorWindowColor", - ], - }, - "dangerBackground3": { - "windowsbrush": [ - "SystemColorWindowTextColor", - ], - }, - "dangerBorder1": { - "windowsbrush": [ - "SystemColorWindowTextColor", - ], - }, - "dangerBorder2": { - "windowsbrush": [ - "SystemColorWindowTextColor", - ], - }, - "dangerBorderActive": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "dangerForeground1": { - "windowsbrush": [ - "SystemColorWindowTextColor", - ], - }, - "dangerForeground2": { - "windowsbrush": [ - "SystemColorWindowTextColor", - ], - }, - "dangerForeground3": { - "windowsbrush": [ - "SystemColorWindowTextColor", - ], - }, - "dangerForegroundInverted": { - "windowsbrush": [ - "SystemColorWindowTextColor", - ], - }, - "defaultBackground": "#000000", - "defaultBorder": "#ffffff", - "defaultCheckedBackground": "#1aebff", - "defaultCheckedContent": "#000000", - "defaultCheckedHoveredBackground": "#1aebff", - "defaultCheckedHoveredContent": "#000000", - "defaultContent": "#ffffff", - "defaultDisabledBackground": "#000000", - "defaultDisabledBorder": "#3ff23f", - "defaultDisabledContent": "#3ff23f", - "defaultDisabledIcon": "#3ff23f", - "defaultFocusedBackground": "#000000", - "defaultFocusedBorder": "#ffffff", - "defaultFocusedContent": "#ffffff", - "defaultFocusedIcon": "#ffffff", - "defaultHoveredBackground": "#1aebff", - "defaultHoveredBorder": "#1aebff", - "defaultHoveredContent": "#000000", - "defaultHoveredIcon": "#000000", - "defaultHoveredSecondaryContent": "#000000", - "defaultIcon": "#ffffff", - "defaultPressedBackground": "#1aebff", - "defaultPressedBorder": "#1aebff", - "defaultPressedContent": "#000000", - "defaultPressedIcon": "#000000", - "defaultPressedSecondaryContent": "#000000", - "disabledBackground": "#000000", - "disabledBodyText": "#3ff23f", - "disabledText": "#3ff23f", - "errorText": "#ffffff", - "focusBorder": "#ffffff", - "ghostBackground": "#000000", - "ghostBorder": "#000000", - "ghostCheckedBackground": "#1aebff", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#1aebff", - "ghostCheckedHoveredBorder": "#000000", - "ghostCheckedHoveredContent": "#000000", - "ghostContent": "#ffffff", - "ghostDisabledBackground": "#000000", - "ghostDisabledBorder": "#000000", - "ghostDisabledContent": "#3ff23f", - "ghostDisabledIcon": "#3ff23f", - "ghostFocusedBackground": "#000000", - "ghostFocusedBorder": "#ffffff", - "ghostFocusedContent": "#ffffff", - "ghostFocusedIcon": "#ffffff", - "ghostFocusedSecondaryContent": "#ffffff", - "ghostHoveredBackground": "#1aebff", - "ghostHoveredBorder": "#1aebff", - "ghostHoveredContent": "#000000", - "ghostHoveredIcon": "#000000", - "ghostHoveredSecondaryContent": "#000000", - "ghostIcon": "#ffffff", - "ghostPressedBackground": "#1aebff", - "ghostPressedBorder": "#1aebff", - "ghostPressedContent": "#000000", - "ghostPressedIcon": "#000000", - "ghostPressedSecondaryContent": "#000000", - "ghostSecondaryContent": "#ffffff", - "inputBackground": "#000000", - "inputBorder": "#ffffff", - "inputFocusBorderAlt": "#ffffff", - "inputPlaceholderText": "#ffffff", - "inputText": "#ffffff", - "link": "#ffff00", - "linkHovered": "#ffffff", - "linkPressed": "#ffffff", - "listHeaderBackgroundHovered": "#1aebff", - "listHeaderBackgroundPressed": "#1aebff", - "menuBackground": "#000000", - "menuDivider": "#ffffff", - "menuIcon": "#ffffff", - "menuItemBackgroundHovered": "#1aebff", - "menuItemBackgroundPressed": "#1aebff", - "menuItemText": "#ffffff", - "menuItemTextHovered": "#000000", - "neutralBackground1": { - "windowsbrush": [ - "SystemColorWindowColor", - ], - }, - "neutralBackground1Hover": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground1Pressed": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground1Selected": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground2": { - "windowsbrush": [ - "SystemColorWindowColor", - ], - }, - "neutralBackground2Hover": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground2Pressed": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], - }, - "neutralBackground2Selected": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], + "compoundBrandBackground1": "#185abd", + "compoundBrandBackground1Hover": "#1651aa", + "compoundBrandBackground1Pressed": "#13458f", + "compoundBrandForeground1": "#185abd", + "compoundBrandForeground1Hover": "#1651aa", + "compoundBrandForeground1Pressed": "#13458f", + "compoundBrandStroke1": "#185abd", + "compoundBrandStroke1Hover": "#1651aa", + "compoundBrandStroke1Pressed": "#13458f", + "dangerBackground1": "#fdf6f6", + "dangerBackground2": "#f1bbbc", + "dangerBackground3": "#d13438", + "dangerBorder1": "#f1bbbc", + "dangerBorder2": "#d13438", + "dangerBorderActive": "#d13438", + "dangerForeground1": "#bc2f32", + "dangerForeground2": "#751d1f", + "dangerForeground3": "#d13438", + "dangerForegroundInverted": "#dc5e62", + "dangerStroke1": "#f1bbbc", + "defaultBackground": "#ffffff", + "defaultBorder": "#d1d1d1", + "defaultCheckedBackground": "#ebebeb", + "defaultCheckedContent": "#242424", + "defaultCheckedHoveredBackground": "#f5f5f5", + "defaultCheckedHoveredContent": "#242424", + "defaultContent": "#242424", + "defaultDisabledBackground": "#f0f0f0", + "defaultDisabledBorder": "#e0e0e0", + "defaultDisabledContent": "#bdbdbd", + "defaultDisabledIcon": "#bdbdbd", + "defaultFocusedBackground": "#f5f5f5", + "defaultFocusedBorder": "#000000", + "defaultFocusedContent": "#242424", + "defaultFocusedIcon": "#242424", + "defaultHoveredBackground": "#f5f5f5", + "defaultHoveredBorder": "#c7c7c7", + "defaultHoveredContent": "#242424", + "defaultHoveredIcon": "#242424", + "defaultHoveredSecondaryContent": "#424242", + "defaultIcon": "#242424", + "defaultPressedBackground": "#e0e0e0", + "defaultPressedBorder": "#b3b3b3", + "defaultPressedContent": "#242424", + "defaultPressedIcon": "#242424", + "defaultPressedSecondaryContent": "#424242", + "disabledBackground": "#f0f0f0", + "disabledBodyText": "#bdbdbd", + "disabledText": "#bdbdbd", + "errorText": "#bc2f32", + "focusBorder": "#000000", + "ghostBackground": "#00000000", + "ghostBorder": "#00000000", + "ghostCheckedBackground": "#ebebeb", + "ghostCheckedContent": "#242424", + "ghostCheckedHoveredBackground": "#f5f5f5", + "ghostCheckedHoveredBorder": "#00000000", + "ghostCheckedHoveredContent": "#242424", + "ghostContent": "#242424", + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": "#00000000", + "ghostDisabledContent": "#bdbdbd", + "ghostDisabledIcon": "#bdbdbd", + "ghostFocusedBackground": "#f5f5f5", + "ghostFocusedBorder": "#000000", + "ghostFocusedContent": "#242424", + "ghostFocusedIcon": "#242424", + "ghostFocusedSecondaryContent": "#616161", + "ghostHoveredBackground": "#f5f5f5", + "ghostHoveredBorder": "#00000000", + "ghostHoveredContent": "#242424", + "ghostHoveredIcon": "#242424", + "ghostHoveredSecondaryContent": "#424242", + "ghostIcon": "#242424", + "ghostPressedBackground": "#e0e0e0", + "ghostPressedBorder": "#00000000", + "ghostPressedContent": "#242424", + "ghostPressedIcon": "#242424", + "ghostPressedSecondaryContent": "#424242", + "ghostSecondaryContent": "#616161", + "inputBackground": "#ffffff", + "inputBorder": "#d1d1d1", + "inputFocusBorderAlt": "#185abd", + "inputPlaceholderText": "#707070", + "inputText": "#242424", + "link": "#1651aa", + "linkHovered": "#13458f", + "linkPressed": "#004578", + "listHeaderBackgroundHovered": "#f5f5f5", + "listHeaderBackgroundPressed": "#e0e0e0", + "menuBackground": "#ffffff", + "menuDivider": "#e0e0e0", + "menuIcon": "#424242", + "menuItemBackgroundHovered": "#f5f5f5", + "menuItemBackgroundPressed": "#e0e0e0", + "menuItemText": "#242424", + "menuItemTextHovered": "#242424", + "neutralBackground1": "#ffffff", + "neutralBackground1Hover": "#f5f5f5", + "neutralBackground1Pressed": "#e0e0e0", + "neutralBackground1Selected": "#ebebeb", + "neutralBackground2": "#fafafa", + "neutralBackground2Hover": "#f0f0f0", + "neutralBackground2Pressed": "#dbdbdb", + "neutralBackground2Selected": "#e6e6e6", + "neutralBackground3": "#f5f5f5", + "neutralBackground3Hover": "#ebebeb", + "neutralBackground3Pressed": "#d6d6d6", + "neutralBackground3Selected": "#e0e0e0", + "neutralBackground4": "#f0f0f0", + "neutralBackground4Hover": "#fafafa", + "neutralBackground4Pressed": "#f5f5f5", + "neutralBackground4Selected": "#ffffff", + "neutralBackground5": "#ebebeb", + "neutralBackground5Hover": "#f5f5f5", + "neutralBackground5Pressed": "#f0f0f0", + "neutralBackground5Selected": "#fafafa", + "neutralBackground6": "#e6e6e6", + "neutralBackgroundCanvas": "#ffffff", + "neutralBackgroundDarkStatic": "#242424", + "neutralBackgroundDisabled": "#f0f0f0", + "neutralBackgroundInverted": "#616161", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#f0f0f0", + "neutralForeground1": "#242424", + "neutralForeground1Hover": "#242424", + "neutralForeground1Pressed": "#242424", + "neutralForeground1Selected": "#242424", + "neutralForeground2": "#424242", + "neutralForeground2BrandHover": "#185abd", + "neutralForeground2BrandPressed": "#1651aa", + "neutralForeground2BrandSelected": "#185abd", + "neutralForeground2Hover": "#242424", + "neutralForeground2Pressed": "#242424", + "neutralForeground2Selected": "#242424", + "neutralForeground3": "#616161", + "neutralForeground3BrandHover": "#185abd", + "neutralForeground3BrandPressed": "#1651aa", + "neutralForeground3BrandSelected": "#185abd", + "neutralForeground3Hover": "#424242", + "neutralForeground3Pressed": "#424242", + "neutralForeground3Selected": "#424242", + "neutralForeground4": "#707070", + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": "#bdbdbd", + "neutralForegroundDisabled1": "#bdbdbd", + "neutralForegroundDisabled2": "#bdbdbd", + "neutralForegroundInverted": "#ffffff", + "neutralForegroundInvertedLink": "#ffffff", + "neutralForegroundInvertedLinkHover": "#ffffff", + "neutralForegroundInvertedLinkPressed": "#ffffff", + "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": "#ffffff", + "neutralForegroundOnBrandHover": "#ffffff", + "neutralForegroundOnBrandPressed": "#ffffff", + "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", + "neutralStencil1": "#e6e6e6", + "neutralStencil2": "#fafafa", + "neutralStroke1": "#d1d1d1", + "neutralStroke1Hover": "#c7c7c7", + "neutralStroke1Pressed": "#b3b3b3", + "neutralStroke1Selected": "#bdbdbd", + "neutralStroke2": "#e0e0e0", + "neutralStroke3": "#f0f0f0", + "neutralStrokeAccessible": "#616161", + "neutralStrokeAccessibleHover": "#575757", + "neutralStrokeAccessiblePressed": "#4d4d4d", + "neutralStrokeAccessibleSelected": "#185abd", + "neutralStrokeDisabled": "#e0e0e0", + "neutralStrokeFocus1": "#ffffff", + "neutralStrokeFocus2": "#000000", + "outofofficeBackground1": "#fdf5fc", + "outofofficeBackground2": "#edbbe7", + "outofofficeBackground3": "#c239b3", + "outofofficeBorder1": "#edbbe7", + "outofofficeBorder2": "#c239b3", + "outofofficeBorderActive": "#c239b3", + "outofofficeForeground1": "#af33a1", + "outofofficeForeground2": "#6d2064", + "outofofficeForeground3": "#c239b3", + "personaActivityGlow": "#185abd", + "personaActivityRing": "#ffffff", + "presenceAvailable": "#0e700e", + "presenceAway": "#817400", + "presenceDnd": "#bc2f32", + "presenceOof": "#af33a1", + "primaryButtonBackground": "#185abd", + "primaryButtonBackgroundDisabled": "#f0f0f0", + "primaryButtonBackgroundHovered": "#1651aa", + "primaryButtonBackgroundPressed": "#004578", + "primaryButtonBorder": "#00000000", + "primaryButtonBorderFocused": "#000000", + "primaryButtonText": "#ffffff", + "primaryButtonTextDisabled": "#bdbdbd", + "primaryButtonTextHovered": "#ffffff", + "primaryButtonTextPressed": "#ffffff", + "redBackground1": "#fdf6f6", + "redBackground2": "#f1bbbc", + "redBackground3": "#d13438", + "redBorder1": "#f1bbbc", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#751d1f", + "redForeground3": "#d13438", + "severeBackground1": "#fdf6f3", + "severeBackground2": "#f4bfab", + "severeBackground3": "#da3b01", + "severeBorder1": "#f4bfab", + "severeBorder2": "#da3b01", + "severeBorderActive": "#da3b01", + "severeForeground1": "#c43501", + "severeForeground2": "#7a2101", + "severeForeground3": "#da3b01", + "severeStroke1": "#f4bfab", + "strokeFocus1": "#ffffff", + "strokeFocus2": "#000000", + "subText": "#424242", + "subtleBackground": "#00000000", + "subtleBackgroundHover": "#f5f5f5", + "subtleBackgroundPressed": "#e0e0e0", + "subtleBackgroundSelected": "#ebebeb", + "successBackground1": "#f1faf1", + "successBackground2": "#9fd89f", + "successBackground3": "#107c10", + "successBorder1": "#9fd89f", + "successBorder2": "#107c10", + "successBorderActive": "#107c10", + "successForeground1": "#0e700e", + "successForeground2": "#094509", + "successForeground3": "#107c10", + "successForegroundInverted": "#359b35", + "successStroke1": "#9fd89f", + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": "#00000000", + "transparentStrokeDisabled": "#00000000", + "transparentStrokeInteractive": "#00000000", + "variantBorder": "#e0e0e0", + "warningBackground1": "#fffef5", + "warningBackground2": "#fef7b2", + "warningBackground3": "#fde300", + "warningBorder1": "#fef7b2", + "warningBorder2": "#fde300", + "warningBorderActive": "#fde300", + "warningForeground1": "#817400", + "warningForeground2": "#817400", + "warningForeground3": "#fde300", + "warningForegroundInverted": "#fef7b2", + "warningStroke1": "#fef7b2", + }, + "components": {}, + "host": { + "appearance": "light", + }, + "shadows": { + "shadow16": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000024", + "x": 0, + "y": 8, + }, }, - "neutralBackground3": { - "windowsbrush": [ - "SystemColorWindowColor", - ], + "shadow16brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000040", + "x": 0, + "y": 8, + }, }, - "neutralBackground3Hover": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], + "shadow2": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000024", + "x": 0, + "y": 1, + }, }, - "neutralBackground3Pressed": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], + "shadow28": { + "ambient": { + "blur": 8, + "color": "#00000033", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#0000003d", + "x": 0, + "y": 14, + }, }, - "neutralBackground3Selected": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], + "shadow28brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#00000040", + "x": 0, + "y": 14, + }, }, - "neutralBackground4": { - "windowsbrush": [ - "SystemColorWindowColor", - ], + "shadow2brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000040", + "x": 0, + "y": 1, + }, }, - "neutralBackground4Hover": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], + "shadow4": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000024", + "x": 0, + "y": 2, + }, }, - "neutralBackground4Pressed": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], + "shadow4brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000040", + "x": 0, + "y": 2, + }, }, - "neutralBackground4Selected": { - "windowsbrush": [ - "SystemColorHighlightColor", - ], + "shadow64": { + "ambient": { + "blur": 8, + "color": "#00000033", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#0000003d", + "x": 0, + "y": 32, + }, }, - "neutralBackground5": { + "shadow64brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#00000040", + "x": 0, + "y": 32, + }, + }, + "shadow8": { + "ambient": { + "blur": 2, + "color": "#0000001f", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000024", + "x": 0, + "y": 4, + }, + }, + "shadow8brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000040", + "x": 0, + "y": 4, + }, + }, + }, + "spacing": { + "l1": "20px", + "l2": "32px", + "m": "16px", + "s1": "8px", + "s2": "4px", + }, + "typography": { + "families": { + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", + "primary": "Segoe UI", + "sansSerif": "Segoe UI", + "secondary": "Segoe UI", + "serif": "Segoe UI", + }, + "sizes": { + "body": 14, + "caption": 10, + "header": 20, + "hero": 28, + "heroLarge": 40, + "secondary": 12, + "subheader": 16, + }, + "variants": { + "body1": { + "face": "primary", + "size": 12, + "weight": "400", + }, + "body1Strong": { + "face": "primary", + "size": 12, + "weight": "600", + }, + "body2": { + "face": "primary", + "size": 14, + "weight": "400", + }, + "body2Strong": { + "face": "primary", + "size": 14, + "weight": "600", + }, + "bodySemibold": { + "face": "primary", + "size": 14, + "weight": "600", + }, + "bodyStandard": { + "face": "primary", + "size": 14, + "weight": "400", + }, + "caption1": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "caption1Strong": { + "face": "primary", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "captionStandard": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "display": { + "face": "primary", + "size": 40, + "weight": "600", + }, + "headerSemibold": { + "face": "primary", + "size": 20, + "weight": "600", + }, + "headerStandard": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "heroLargeSemibold": { + "face": "primary", + "size": 40, + "weight": "600", + }, + "heroLargeStandard": { + "face": "primary", + "size": 40, + "weight": "400", + }, + "heroSemibold": { + "face": "primary", + "size": 28, + "weight": "600", + }, + "heroStandard": { + "face": "primary", + "size": 28, + "weight": "400", + }, + "largeTitle": { + "face": "primary", + "size": 40, + "weight": "400", + }, + "secondarySemibold": { + "face": "primary", + "size": 12, + "weight": "600", + }, + "secondaryStandard": { + "face": "primary", + "size": 12, + "weight": "400", + }, + "subheaderSemibold": { + "face": "primary", + "size": 16, + "weight": "600", + }, + "subheaderStandard": { + "face": "primary", + "size": 16, + "weight": "400", + }, + "subtitle1": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "subtitle1Strong": { + "face": "primary", + "size": 20, + "weight": "600", + }, + "subtitle2": { + "face": "primary", + "size": 16, + "weight": "400", + }, + "subtitle2Strong": { + "face": "primary", + "size": 16, + "weight": "600", + }, + "title1": { + "face": "primary", + "size": 28, + "weight": "400", + }, + "title1Strong": { + "face": "primary", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", + }, + }, + "weights": { + "regular": "400", + "semiBold": "600", + }, + }, +} +`; + +exports[`high contrast dark theme 1`] = ` +{ + "colors": { + "accentButtonBackground": { "windowsbrush": [ - "SystemColorWindowColor", + "SystemColorButtonFaceColor", ], }, - "neutralBackground5Hover": { + "actionLink": { "windowsbrush": [ - "SystemColorHighlightColor", + "SystemColorWindowTextColor", ], }, - "neutralBackground5Pressed": { + "background": { "windowsbrush": [ - "SystemColorHighlightColor", + "SystemColorWindowColor", ], }, - "neutralBackground5Selected": { + "bodyDivider": { "windowsbrush": [ - "SystemColorHighlightColor", + "SystemColorWindowTextColor", ], }, - "neutralBackground6": { + "bodyFrameBackground": { "windowsbrush": [ "SystemColorWindowColor", ], }, - "neutralBackgroundDisabled": { + "bodyFrameDivider": { "windowsbrush": [ - "SystemColorWindowColor", + "SystemColorWindowTextColor", ], }, - "neutralBackgroundInverted": { + "bodyStandoutBackground": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorWindowColor", ], }, - "neutralForeground1": { + "bodyText": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "neutralForeground1Hover": { + "bodyTextChecked": { "windowsbrush": [ "SystemColorHighlightTextColor", ], }, - "neutralForeground1Pressed": { + "brandBackground": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorButtonFaceColor", ], }, - "neutralForeground1Selected": { + "brandBackground2": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorButtonFaceColor", ], }, - "neutralForeground2": { + "brandBackground2Pressed": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightColor", ], }, - "neutralForeground2BrandHover": { + "brandBackground2Selected": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorHighlightColor", ], }, - "neutralForeground2BrandPressed": { + "brandBackground3": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorButtonFaceColor", ], }, - "neutralForeground2BrandSelected": { + "brandBackgroundDisabled": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorWindowColor", ], }, - "neutralForeground2Hover": { + "brandBackgroundHover": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorHighlightColor", ], }, - "neutralForeground2Pressed": { + "brandBackgroundInverted": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorWindowTextColor", ], }, - "neutralForeground2Selected": { + "brandBackgroundInvertedDisabled": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorWindowColor", ], }, - "neutralForeground3": { + "brandBackgroundPressed": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightColor", ], }, - "neutralForeground3BrandHover": { + "brandBackgroundSelected": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorHighlightColor", ], }, - "neutralForeground3BrandPressed": { + "brandBackgroundStatic": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorWindowColor", ], }, - "neutralForeground3BrandSelected": { + "brandBackgroundTint": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorButtonFaceColor", ], }, - "neutralForeground3Hover": { + "brandForeground1": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorWindowTextColor", ], }, - "neutralForeground3Pressed": { + "brandForeground1Disabled": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorGrayTextColor", ], }, - "neutralForeground3Selected": { + "brandForeground1Pressed": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorWindowTextColor", ], }, - "neutralForeground4": { + "brandForeground1Selected": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "neutralForegroundDisabled": { + "brandForeground2": { "windowsbrush": [ - "SystemColorGrayTextColor", + "SystemColorButtonTextColor", ], }, - "neutralForegroundInverted": { + "brandForegroundDisabled1": { "windowsbrush": [ - "SystemColorWindowColor", + "SystemColorGrayTextColor", ], }, - "neutralForegroundInvertedLink": { + "brandForegroundDisabled2": { "windowsbrush": [ - "SystemColorHotlightColor", + "SystemColorGrayTextColor", ], }, - "neutralForegroundInvertedLinkHover": { + "brandForegroundLink": { "windowsbrush": [ "SystemColorHotlightColor", ], }, - "neutralForegroundInvertedLinkPressed": { + "brandForegroundLinkHover": { "windowsbrush": [ "SystemColorHotlightColor", ], }, - "neutralForegroundInvertedLinkSelected": { + "brandForegroundLinkPressed": { "windowsbrush": [ "SystemColorHotlightColor", ], }, - "neutralForegroundOnBrand": { + "brandForegroundLinkSelected": { "windowsbrush": [ - "SystemColorButtonTextColor", + "SystemColorHotlightColor", ], }, - "neutralForegroundOnBrandHover": { + "brandForegroundTint": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorButtonTextColor", ], }, - "neutralForegroundOnBrandPressed": { + "brandStroke1": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorWindowTextColor", ], }, - "neutralForegroundOnBrandSelected": { + "brandStroke1Pressed": { "windowsbrush": [ - "SystemColorHighlightTextColor", + "SystemColorWindowTextColor", ], }, - "neutralStencil1": "#141414", - "neutralStencil2": "#858585", - "neutralStroke1": { + "brandStroke1Selected": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "neutralStroke1Hover": { + "brandStroke2": { "windowsbrush": [ - "SystemColorHighlightColor", + "SystemColorWindowColor", ], }, - "neutralStroke1Pressed": { + "brandStrokeTint": { "windowsbrush": [ - "SystemColorHighlightColor", + "SystemColorWindowColor", ], }, - "neutralStroke1Selected": { + "brandedBackground": { "windowsbrush": [ - "SystemColorHighlightColor", + "SystemColorButtonFaceColor", ], }, - "neutralStroke2": { + "brandedDisabledBorder": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorGrayTextColor", ], }, - "neutralStroke3": { + "brandedFocusedSecondaryContent": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightTextColor", ], }, - "neutralStrokeAccessible": { + "brandedHoveredSecondaryContent": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightTextColor", ], }, - "neutralStrokeAccessibleHover": { + "brandedPressedSecondaryContent": { "windowsbrush": [ - "SystemColorHighlightColor", + "SystemColorHighlightTextColor", ], }, - "neutralStrokeAccessiblePressed": { + "brandedSecondaryContent": { "windowsbrush": [ - "SystemColorHighlightColor", + "SystemColorButtonTextColor", ], }, - "neutralStrokeAccessibleSelected": { + "buttonBackground": { "windowsbrush": [ - "SystemColorHighlightColor", + "SystemColorWindowColor", ], }, - "neutralStrokeDisabled": { + "buttonBackgroundChecked": { "windowsbrush": [ - "SystemColorGrayTextColor", + "SystemColorHighlightColor", ], }, - "outofofficeBackground1": { + "buttonBackgroundDisabled": { "windowsbrush": [ "SystemColorWindowColor", ], }, - "outofofficeBackground2": { + "buttonBackgroundHovered": { "windowsbrush": [ - "SystemColorWindowColor", + "SystemColorHighlightColor", ], }, - "outofofficeBackground3": { + "buttonBackgroundPressed": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightColor", ], }, - "outofofficeBorder1": { + "buttonBorder": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "outofofficeBorder2": { + "buttonBorderDisabled": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorGrayTextColor", ], }, - "outofofficeBorderActive": { + "buttonBorderFocused": { "windowsbrush": [ "SystemColorHighlightColor", ], }, - "outofofficeForeground1": { + "buttonText": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "outofofficeForeground2": { + "buttonTextChecked": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightTextColor", ], }, - "outofofficeForeground3": { + "buttonTextDisabled": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorGrayTextColor", ], }, - "personaActivityGlow": "transparent", - "personaActivityRing": "#ffffff", - "primaryButtonBackground": "#000000", - "primaryButtonBackgroundDisabled": "#000000", - "primaryButtonBackgroundHovered": "#1aebff", - "primaryButtonBackgroundPressed": "#1aebff", - "primaryButtonBorder": "#ffffff", - "primaryButtonBorderFocused": "#ffffff", - "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#3ff23f", - "primaryButtonTextHovered": "#000000", - "primaryButtonTextPressed": "#000000", - "severeBackground1": { + "buttonTextHovered": { "windowsbrush": [ - "SystemColorWindowColor", + "SystemColorHighlightTextColor", ], }, - "severeBackground2": { + "buttonTextPressed": { "windowsbrush": [ - "SystemColorWindowColor", + "SystemColorHighlightTextColor", ], }, - "severeBackground3": { + "checkboxBackground": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightColor", ], }, - "severeBorder1": { + "checkboxBackgroundDisabled": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorWindowColor", ], }, - "severeBorder2": { + "checkboxBorderColor": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "severeBorderActive": { + "checkmarkColor": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "compoundBrandBackground1": { "windowsbrush": [ "SystemColorHighlightColor", ], }, - "severeForeground1": { + "compoundBrandBackground1Hover": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightColor", ], }, - "severeForeground2": { + "compoundBrandBackground1Pressed": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightColor", ], }, - "severeForeground3": { + "compoundBrandForeground1": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightColor", ], }, - "strokeFocus1": { + "compoundBrandForeground1Hover": { "windowsbrush": [ - "SystemColorWindowColor", + "SystemColorHighlightColor", ], }, - "strokeFocus2": { + "compoundBrandForeground1Pressed": { "windowsbrush": [ "SystemColorHighlightColor", ], }, - "subText": "#ffffff", - "subtleBackground": "#00000000", - "subtleBackgroundHover": { + "compoundBrandStroke1": { "windowsbrush": [ "SystemColorHighlightColor", ], }, - "subtleBackgroundPressed": { + "compoundBrandStroke1Hover": { "windowsbrush": [ "SystemColorHighlightColor", ], }, - "subtleBackgroundSelected": { + "compoundBrandStroke1Pressed": { "windowsbrush": [ "SystemColorHighlightColor", ], }, - "successBackground1": { + "dangerBackground1": { "windowsbrush": [ "SystemColorWindowColor", ], }, - "successBackground2": { + "dangerBackground2": { "windowsbrush": [ "SystemColorWindowColor", ], }, - "successBackground3": { + "dangerBackground3": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "successBorder1": { + "dangerBorder1": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "successBorder2": { + "dangerBorder2": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "successBorderActive": { + "dangerBorderActive": { "windowsbrush": [ "SystemColorHighlightColor", ], }, - "successForeground1": { + "dangerForeground1": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "successForeground2": { + "dangerForeground2": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "successForeground3": { + "dangerForeground3": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "successForegroundInverted": { + "dangerForegroundInverted": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "transparentBackground": "#00000000", - "transparentBackgroundHover": "#00000000", - "transparentBackgroundPressed": "#00000000", - "transparentBackgroundSelected": "#00000000", - "transparentStroke": { + "dangerStroke1": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "transparentStrokeDisabled": { + "defaultBackground": { "windowsbrush": [ - "SystemColorGrayTextColor", + "SystemColorWindowColor", ], }, - "transparentStrokeInteractive": { + "defaultBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "defaultCheckedBackground": { "windowsbrush": [ "SystemColorHighlightColor", ], }, - "variantBorder": "#ffffff", - "warningBackground1": { + "defaultCheckedContent": { "windowsbrush": [ - "SystemColorWindowColor", + "SystemColorHighlightTextColor", ], }, - "warningBackground2": { + "defaultCheckedHoveredBackground": { "windowsbrush": [ - "SystemColorWindowColor", + "SystemColorHighlightColor", ], }, - "warningBackground3": { + "defaultCheckedHoveredContent": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightTextColor", ], }, - "warningBorder1": { + "defaultContent": { "windowsbrush": [ "SystemColorWindowTextColor", ], }, - "warningBorder2": { + "defaultDisabledBackground": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorWindowColor", ], }, - "warningBorderActive": { + "defaultDisabledBorder": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "defaultDisabledContent": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "defaultDisabledIcon": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "defaultFocusedBackground": { "windowsbrush": [ "SystemColorHighlightColor", ], }, - "warningForeground1": { + "defaultFocusedBorder": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightColor", ], }, - "warningForeground2": { + "defaultFocusedContent": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightTextColor", ], }, - "warningForeground3": { + "defaultFocusedIcon": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightTextColor", ], }, - "warningForegroundInverted": { + "defaultHoveredBackground": { "windowsbrush": [ - "SystemColorWindowTextColor", + "SystemColorHighlightColor", ], }, - }, - "components": {}, - "host": { - "appearance": "highContrast", - }, - "shadows": { - "shadow16": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 16, - "color": "#00000047", - "x": 0, - "y": 8, - }, + "defaultHoveredBorder": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], }, - "shadow16brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 16, - "color": "#00000040", - "x": 0, - "y": 8, - }, + "defaultHoveredContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], }, - "shadow2": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 2, - "color": "#00000047", - "x": 0, - "y": 1, - }, + "defaultHoveredIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], }, - "shadow28": { - "ambient": { - "blur": 8, - "color": "#00000066", - "x": 0, - "y": 0, - }, - "key": { - "blur": 28, - "color": "#0000007a", - "x": 0, - "y": 14, - }, + "defaultHoveredSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], }, - "shadow28brand": { - "ambient": { - "blur": 8, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 28, - "color": "#00000040", - "x": 0, - "y": 14, - }, + "defaultIcon": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], }, - "shadow2brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 2, - "color": "#00000040", - "x": 0, - "y": 1, - }, + "defaultPressedBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], }, - "shadow4": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 4, - "color": "#00000047", - "x": 0, - "y": 2, - }, + "defaultPressedBorder": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], }, - "shadow4brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 4, - "color": "#00000040", - "x": 0, - "y": 2, - }, + "defaultPressedContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], }, - "shadow64": { - "ambient": { - "blur": 8, - "color": "#00000066", - "x": 0, - "y": 0, - }, - "key": { - "blur": 64, - "color": "#0000007a", - "x": 0, - "y": 32, - }, + "defaultPressedIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], }, - "shadow64brand": { - "ambient": { - "blur": 8, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 64, - "color": "#00000040", - "x": 0, - "y": 32, - }, + "defaultPressedSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], }, - "shadow8": { - "ambient": { - "blur": 2, - "color": "#0000003d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 8, - "color": "#00000047", - "x": 0, - "y": 4, - }, + "disabledBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], }, - "shadow8brand": { - "ambient": { - "blur": 2, - "color": "#0000004d", - "x": 0, - "y": 0, - }, - "key": { - "blur": 8, - "color": "#00000040", - "x": 0, - "y": 4, - }, + "disabledBodyText": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], }, - }, - "spacing": { - "l1": "20px", - "l2": "32px", - "m": "16px", - "s1": "8px", - "s2": "4px", - }, - "typography": { - "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", - "primary": "Segoe UI", - "sansSerif": "System", - "secondary": "Segoe UI", - "serif": "System", + "disabledText": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], }, - "sizes": { - "body": 14, - "caption": 10, - "header": 20, - "hero": 28, - "heroLarge": 40, - "secondary": 12, - "subheader": 16, + "errorText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], }, - "variants": { - "body1": { - "face": "primary", - "size": "secondary", - "weight": "regular", - }, - "body1Strong": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", - }, - "body2": { - "face": "primary", - "size": "body", - "weight": "regular", - }, - "body2Strong": { - "face": "primary", - "size": "body", - "weight": "semiBold", - }, - "bodySemibold": { - "face": "primary", - "size": "body", - "weight": "semiBold", - }, - "bodyStandard": { - "face": "primary", - "size": "body", - "weight": "regular", - }, - "caption1": { - "face": "primary", - "size": "caption", - "weight": "regular", - }, - "caption1Strong": { - "face": "primary", - "size": "caption", - "weight": "semiBold", - }, - "captionStandard": { - "face": "primary", - "size": "caption", - "weight": "regular", - }, - "display": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", - }, - "headerSemibold": { - "face": "primary", - "size": "header", - "weight": "semiBold", - }, - "headerStandard": { - "face": "primary", - "size": "header", - "weight": "regular", - }, - "heroLargeSemibold": { - "face": "primary", - "size": "heroLarge", - "weight": "semiBold", - }, - "heroLargeStandard": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", - }, - "heroSemibold": { - "face": "primary", - "size": "hero", - "weight": "semiBold", - }, - "heroStandard": { - "face": "primary", - "size": "hero", - "weight": "regular", - }, - "largeTitle": { - "face": "primary", - "size": "heroLarge", - "weight": "regular", - }, - "secondarySemibold": { - "face": "primary", - "size": "secondary", - "weight": "semiBold", - }, - "secondaryStandard": { + "focusBorder": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostBackground": "#00000000", + "ghostBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostCheckedBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostCheckedContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostCheckedHoveredBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostCheckedHoveredBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostCheckedHoveredContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostContent": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "ghostDisabledContent": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "ghostDisabledIcon": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "ghostFocusedBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostFocusedBorder": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostFocusedContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostFocusedIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostFocusedSecondaryContent": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostHoveredBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostHoveredBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostHoveredContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostHoveredIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostHoveredSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostIcon": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostPressedBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostPressedBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostPressedContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostPressedIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostPressedSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostSecondaryContent": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "inputBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "inputBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "inputFocusBorderAlt": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "inputPlaceholderText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "inputText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "link": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "linkHovered": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "linkPressed": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "listHeaderBackgroundHovered": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "listHeaderBackgroundPressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "menuBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "menuDivider": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "menuIcon": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "menuItemBackgroundHovered": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "menuItemBackgroundPressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "menuItemText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "menuItemTextHovered": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackground1Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground1Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground1Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackground2Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground2Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground2Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground3": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackground3Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground3Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground3Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground4": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackground4Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground4Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground4Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground5": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackground5Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground5Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground5Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground6": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackgroundCanvas": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackgroundDarkStatic": "#3d3d3d", + "neutralBackgroundDisabled": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackgroundInverted": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralForeground1Hover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground1Pressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground1Selected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralForeground2BrandHover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2BrandPressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2BrandSelected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2Hover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2Pressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2Selected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralForeground3BrandHover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3BrandPressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3BrandSelected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3Hover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3Pressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3Selected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground4": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "neutralForegroundDisabled1": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "neutralForegroundDisabled2": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "neutralForegroundInverted": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralForegroundInvertedLink": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "neutralForegroundInvertedLinkHover": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "neutralForegroundInvertedLinkPressed": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "neutralForegroundInvertedLinkSelected": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "neutralForegroundOnBrandHover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForegroundOnBrandPressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForegroundOnBrandSelected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForegroundOnColor": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "neutralStencil1": "#141414", + "neutralStencil2": "#858585", + "neutralStroke1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralStroke1Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStroke1Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStroke1Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStroke2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralStroke3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralStrokeAccessible": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralStrokeAccessibleHover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStrokeAccessiblePressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStrokeAccessibleSelected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStrokeDisabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "neutralStrokeFocus1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralStrokeFocus2": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "outofofficeBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "outofofficeBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "outofofficeBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "outofofficeBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "outofofficeBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "outofofficeBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "outofofficeForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "outofofficeForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "outofofficeForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "personaActivityGlow": { + "windowsbrush": [ + "SystemColorButtonFaceColor", + ], + }, + "personaActivityRing": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "presenceAvailable": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "presenceAway": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "presenceDnd": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "presenceOof": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "primaryButtonBackground": { + "windowsbrush": [ + "SystemColorButtonFaceColor", + ], + }, + "primaryButtonBackgroundDisabled": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "primaryButtonBackgroundHovered": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "primaryButtonBackgroundPressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "primaryButtonBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "primaryButtonBorderFocused": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "primaryButtonText": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "primaryButtonTextDisabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "primaryButtonTextHovered": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "primaryButtonTextPressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "redBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "redBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "redBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "redBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "redBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "redBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "redForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "redForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "redForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "severeBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "severeBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "severeForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeStroke1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "strokeFocus1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "strokeFocus2": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "subText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "subtleBackground": "#00000000", + "subtleBackgroundHover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "subtleBackgroundPressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "subtleBackgroundSelected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "successBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "successBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "successBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "successForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successForegroundInverted": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successStroke1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "transparentBackground": "#00000000", + "transparentBackgroundHover": "#00000000", + "transparentBackgroundPressed": "#00000000", + "transparentBackgroundSelected": "#00000000", + "transparentStroke": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "transparentStrokeDisabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "transparentStrokeInteractive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "variantBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "warningBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "warningBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "warningForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningForegroundInverted": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningStroke1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + }, + "components": {}, + "host": { + "appearance": "highContrast", + }, + "shadows": { + "shadow16": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000047", + "x": 0, + "y": 8, + }, + }, + "shadow16brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 16, + "color": "#00000040", + "x": 0, + "y": 8, + }, + }, + "shadow2": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000047", + "x": 0, + "y": 1, + }, + }, + "shadow28": { + "ambient": { + "blur": 8, + "color": "#00000066", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#0000007a", + "x": 0, + "y": 14, + }, + }, + "shadow28brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 28, + "color": "#00000040", + "x": 0, + "y": 14, + }, + }, + "shadow2brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 2, + "color": "#00000040", + "x": 0, + "y": 1, + }, + }, + "shadow4": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000047", + "x": 0, + "y": 2, + }, + }, + "shadow4brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 4, + "color": "#00000040", + "x": 0, + "y": 2, + }, + }, + "shadow64": { + "ambient": { + "blur": 8, + "color": "#00000066", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#0000007a", + "x": 0, + "y": 32, + }, + }, + "shadow64brand": { + "ambient": { + "blur": 8, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 64, + "color": "#00000040", + "x": 0, + "y": 32, + }, + }, + "shadow8": { + "ambient": { + "blur": 2, + "color": "#0000003d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000047", + "x": 0, + "y": 4, + }, + }, + "shadow8brand": { + "ambient": { + "blur": 2, + "color": "#0000004d", + "x": 0, + "y": 0, + }, + "key": { + "blur": 8, + "color": "#00000040", + "x": 0, + "y": 4, + }, + }, + }, + "spacing": { + "l1": "20px", + "l2": "32px", + "m": "16px", + "s1": "8px", + "s2": "4px", + }, + "typography": { + "families": { + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", + "primary": "Segoe UI", + "sansSerif": "Segoe UI", + "secondary": "Segoe UI", + "serif": "Segoe UI", + }, + "sizes": { + "body": 14, + "caption": 10, + "header": 20, + "hero": 28, + "heroLarge": 40, + "secondary": 12, + "subheader": 16, + }, + "variants": { + "body1": { + "face": "primary", + "size": 12, + "weight": "400", + }, + "body1Strong": { + "face": "primary", + "size": 12, + "weight": "600", + }, + "body2": { + "face": "primary", + "size": 14, + "weight": "400", + }, + "body2Strong": { + "face": "primary", + "size": 14, + "weight": "600", + }, + "bodySemibold": { + "face": "primary", + "size": 14, + "weight": "600", + }, + "bodyStandard": { + "face": "primary", + "size": 14, + "weight": "400", + }, + "caption1": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "caption1Strong": { + "face": "primary", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "captionStandard": { + "face": "primary", + "size": 10, + "weight": "400", + }, + "display": { + "face": "primary", + "size": 40, + "weight": "600", + }, + "headerSemibold": { + "face": "primary", + "size": 20, + "weight": "600", + }, + "headerStandard": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "heroLargeSemibold": { + "face": "primary", + "size": 40, + "weight": "600", + }, + "heroLargeStandard": { + "face": "primary", + "size": 40, + "weight": "400", + }, + "heroSemibold": { + "face": "primary", + "size": 28, + "weight": "600", + }, + "heroStandard": { + "face": "primary", + "size": 28, + "weight": "400", + }, + "largeTitle": { + "face": "primary", + "size": 40, + "weight": "400", + }, + "secondarySemibold": { + "face": "primary", + "size": 12, + "weight": "600", + }, + "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, - "weights": { - "regular": "400", - "semiBold": "600", + "weights": { + "regular": "400", + "semiBold": "600", + }, + }, +} +`; + +exports[`high contrast light theme 1`] = ` +{ + "colors": { + "accentButtonBackground": { + "windowsbrush": [ + "SystemColorButtonFaceColor", + ], + }, + "actionLink": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "background": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "bodyDivider": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "bodyFrameBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "bodyFrameDivider": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "bodyStandoutBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "bodyText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "bodyTextChecked": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "brandBackground": { + "windowsbrush": [ + "SystemColorButtonFaceColor", + ], + }, + "brandBackground2": { + "windowsbrush": [ + "SystemColorButtonFaceColor", + ], + }, + "brandBackground2Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "brandBackground2Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "brandBackground3": { + "windowsbrush": [ + "SystemColorButtonFaceColor", + ], + }, + "brandBackgroundDisabled": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "brandBackgroundHover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "brandBackgroundInverted": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "brandBackgroundInvertedDisabled": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "brandBackgroundPressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "brandBackgroundSelected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "brandBackgroundStatic": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "brandBackgroundTint": { + "windowsbrush": [ + "SystemColorButtonFaceColor", + ], + }, + "brandForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "brandForeground1Disabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "brandForeground1Pressed": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "brandForeground1Selected": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "brandForeground2": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "brandForegroundDisabled1": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "brandForegroundDisabled2": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "brandForegroundLink": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "brandForegroundLinkHover": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "brandForegroundLinkPressed": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "brandForegroundLinkSelected": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "brandForegroundTint": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "brandStroke1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "brandStroke1Pressed": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "brandStroke1Selected": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "brandStroke2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "brandStrokeTint": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "brandedBackground": { + "windowsbrush": [ + "SystemColorButtonFaceColor", + ], + }, + "brandedDisabledBorder": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "brandedFocusedSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "brandedHoveredSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "brandedPressedSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "brandedSecondaryContent": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "buttonBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "buttonBackgroundChecked": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "buttonBackgroundDisabled": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "buttonBackgroundHovered": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "buttonBackgroundPressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "buttonBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "buttonBorderDisabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "buttonBorderFocused": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "buttonText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "buttonTextChecked": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "buttonTextDisabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "buttonTextHovered": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "buttonTextPressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "checkboxBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "checkboxBackgroundDisabled": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "checkboxBorderColor": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "checkmarkColor": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "compoundBrandBackground1": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "compoundBrandBackground1Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "compoundBrandBackground1Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "compoundBrandForeground1": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "compoundBrandForeground1Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "compoundBrandForeground1Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "compoundBrandStroke1": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "compoundBrandStroke1Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "compoundBrandStroke1Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "dangerBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "dangerBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "dangerBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "dangerBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "dangerBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "dangerBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "dangerForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "dangerForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "dangerForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "dangerForegroundInverted": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "dangerStroke1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "defaultBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "defaultBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "defaultCheckedBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "defaultCheckedContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "defaultCheckedHoveredBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "defaultCheckedHoveredContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "defaultContent": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "defaultDisabledBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "defaultDisabledBorder": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "defaultDisabledContent": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "defaultDisabledIcon": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "defaultFocusedBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "defaultFocusedBorder": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "defaultFocusedContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "defaultFocusedIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "defaultHoveredBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "defaultHoveredBorder": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "defaultHoveredContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "defaultHoveredIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "defaultHoveredSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "defaultIcon": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "defaultPressedBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "defaultPressedBorder": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "defaultPressedContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "defaultPressedIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "defaultPressedSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "disabledBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "disabledBodyText": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "disabledText": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "errorText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "focusBorder": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostBackground": "#00000000", + "ghostBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostCheckedBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostCheckedContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostCheckedHoveredBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostCheckedHoveredBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostCheckedHoveredContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostContent": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostDisabledBackground": "#00000000", + "ghostDisabledBorder": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "ghostDisabledContent": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "ghostDisabledIcon": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "ghostFocusedBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostFocusedBorder": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostFocusedContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostFocusedIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostFocusedSecondaryContent": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostHoveredBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostHoveredBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostHoveredContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostHoveredIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostHoveredSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostIcon": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostPressedBackground": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "ghostPressedBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "ghostPressedContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostPressedIcon": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostPressedSecondaryContent": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "ghostSecondaryContent": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "inputBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "inputBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "inputFocusBorderAlt": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "inputPlaceholderText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "inputText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "link": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "linkHovered": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "linkPressed": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "listHeaderBackgroundHovered": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "listHeaderBackgroundPressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "menuBackground": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "menuDivider": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "menuIcon": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "menuItemBackgroundHovered": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "menuItemBackgroundPressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "menuItemText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "menuItemTextHovered": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackground1Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground1Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground1Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackground2Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground2Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground2Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground3": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackground3Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground3Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground3Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground4": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackground4Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground4Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground4Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground5": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackground5Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground5Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground5Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralBackground6": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackgroundCanvas": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackgroundDarkStatic": "#3d3d3d", + "neutralBackgroundDisabled": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralBackgroundInverted": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralForeground1Hover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground1Pressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground1Selected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralForeground2BrandHover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2BrandPressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2BrandSelected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2Hover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2Pressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground2Selected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralForeground3BrandHover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3BrandPressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3BrandSelected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3Hover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3Pressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground3Selected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForeground4": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralForegroundDarkStatic": "#000000", + "neutralForegroundDisabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "neutralForegroundDisabled1": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "neutralForegroundDisabled2": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "neutralForegroundInverted": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralForegroundInvertedLink": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "neutralForegroundInvertedLinkHover": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "neutralForegroundInvertedLinkPressed": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "neutralForegroundInvertedLinkSelected": { + "windowsbrush": [ + "SystemColorHotlightColor", + ], + }, + "neutralForegroundLightStatic": "#ffffff", + "neutralForegroundOnBrand": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "neutralForegroundOnBrandHover": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForegroundOnBrandPressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForegroundOnBrandSelected": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "neutralForegroundOnColor": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "neutralStencil1": "#141414", + "neutralStencil2": "#858585", + "neutralStroke1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralStroke1Hover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStroke1Pressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStroke1Selected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStroke2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralStroke3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralStrokeAccessible": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "neutralStrokeAccessibleHover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStrokeAccessiblePressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStrokeAccessibleSelected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "neutralStrokeDisabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "neutralStrokeFocus1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "neutralStrokeFocus2": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "outofofficeBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "outofofficeBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "outofofficeBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "outofofficeBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "outofofficeBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "outofofficeBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "outofofficeForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "outofofficeForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "outofofficeForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "personaActivityGlow": { + "windowsbrush": [ + "SystemColorButtonFaceColor", + ], + }, + "personaActivityRing": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "presenceAvailable": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "presenceAway": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "presenceDnd": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "presenceOof": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "primaryButtonBackground": { + "windowsbrush": [ + "SystemColorButtonFaceColor", + ], + }, + "primaryButtonBackgroundDisabled": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "primaryButtonBackgroundHovered": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "primaryButtonBackgroundPressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "primaryButtonBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "primaryButtonBorderFocused": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "primaryButtonText": { + "windowsbrush": [ + "SystemColorButtonTextColor", + ], + }, + "primaryButtonTextDisabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "primaryButtonTextHovered": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "primaryButtonTextPressed": { + "windowsbrush": [ + "SystemColorHighlightTextColor", + ], + }, + "redBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "redBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "redBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "redBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "redBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "redBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "redForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "redForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "redForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "severeBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "severeBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "severeForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "severeStroke1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "strokeFocus1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "strokeFocus2": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "subText": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], }, - }, -} -`; - -exports[`defaultFluentTheme 1`] = ` -{ - "colors": { - "accentButtonBackground": undefined, - "actionLink": "#323130", - "background": "#ffffff", - "bodyDivider": "#edebe9", - "bodyFrameBackground": "#ffffff", - "bodyFrameDivider": "#edebe9", - "bodyStandoutBackground": "#faf9f8", - "bodyText": "#323130", - "bodyTextChecked": "#000000", - "brandBackground": "#185abd", - "brandBackground2": "#eff6fc", - "brandBackgroundDisabled": undefined, - "brandBackgroundHover": "#1651aa", - "brandBackgroundPressed": "#004578", - "brandBackgroundSelected": "#13458f", - "brandBackgroundStatic": "#185abd", - "brandForeground1": "#185abd", - "brandForeground1Disabled": undefined, - "brandForeground1Pressed": undefined, - "brandForeground2": "#1651aa", - "brandForegroundLink": "#1651aa", - "brandForegroundLinkHover": "#13458f", - "brandForegroundLinkPressed": "#004578", - "brandForegroundLinkSelected": "#1651aa", - "brandStroke1": "#185abd", - "brandStroke2": "#d2e0f4", - "brandedBackground": undefined, - "brandedDisabledBorder": "#f3f2f1", - "brandedFocusedSecondaryContent": "#faf9f8", - "brandedHoveredSecondaryContent": "#faf9f8", - "brandedPressedSecondaryContent": "#faf9f8", - "brandedSecondaryContent": "#faf9f8", - "buttonBackground": "#f3f2f1", - "buttonBackgroundChecked": "#c8c6c4", - "buttonBackgroundDisabled": "#f3f2f1", - "buttonBackgroundHovered": "#edebe9", - "buttonBackgroundPressed": "#edebe9", - "buttonBorder": "#8a8886", - "buttonBorderDisabled": "#f3f2f1", - "buttonBorderFocused": "#8a8886", - "buttonText": "#323130", - "buttonTextChecked": "#201f1e", - "buttonTextDisabled": "#a19f9d", - "buttonTextHovered": "#201f1e", - "buttonTextPressed": "#201f1e", - "checkboxBackground": undefined, - "checkboxBackgroundDisabled": "#f3f2f1", - "checkboxBorderColor": "#8a8886", - "checkmarkColor": "#ffffff", - "compoundBrandBackground1": "#185abd", - "compoundBrandBackground1Hover": "#1651aa", - "compoundBrandBackground1Pressed": "#13458f", - "compoundBrandForeground1": "#185abd", - "compoundBrandForeground1Hover": "#1651aa", - "compoundBrandForeground1Pressed": "#13458f", - "compoundBrandStroke1": "#185abd", - "compoundBrandStroke1Hover": "#1651aa", - "compoundBrandStroke1Pressed": "#13458f", - "dangerBackground1": "#fdf6f6", - "dangerBackground2": "#f1bbbc", - "dangerBackground3": "#d13438", - "dangerBorder1": "#f1bbbc", - "dangerBorder2": "#d13438", - "dangerBorderActive": "#d13438", - "dangerForeground1": "#bc2f32", - "dangerForeground2": "#751d1f", - "dangerForeground3": "#d13438", - "dangerForegroundInverted": "#dc5e62", - "defaultBackground": "#f3f2f1", - "defaultBorder": "#8a8886", - "defaultCheckedBackground": "#c8c6c4", - "defaultCheckedContent": "#201f1e", - "defaultCheckedHoveredBackground": "#edebe9", - "defaultCheckedHoveredContent": "#201f1e", - "defaultContent": "#323130", - "defaultDisabledBackground": "#f3f2f1", - "defaultDisabledBorder": "#f3f2f1", - "defaultDisabledContent": "#a19f9d", - "defaultDisabledIcon": "#a19f9d", - "defaultFocusedBackground": "#edebe9", - "defaultFocusedBorder": "#8a8886", - "defaultFocusedContent": "#201f1e", - "defaultFocusedIcon": "#201f1e", - "defaultHoveredBackground": "#edebe9", - "defaultHoveredBorder": "#8a8886", - "defaultHoveredContent": "#201f1e", - "defaultHoveredIcon": "#201f1e", - "defaultHoveredSecondaryContent": "#a19f9d", - "defaultIcon": "#323130", - "defaultPressedBackground": "#edebe9", - "defaultPressedBorder": "#8a8886", - "defaultPressedContent": "#201f1e", - "defaultPressedIcon": "#201f1e", - "defaultPressedSecondaryContent": "#a19f9d", - "disabledBackground": "#f3f2f1", - "disabledBodyText": "#a19f9d", - "disabledText": "#a19f9d", - "errorText": "#a4262c", - "focusBorder": "#605e5c", - "ghostBackground": "#ffffff", - "ghostBorder": "#ffffff", - "ghostCheckedBackground": "#edebe9", - "ghostCheckedContent": "#000000", - "ghostCheckedHoveredBackground": "#f3f2f1", - "ghostCheckedHoveredBorder": "#201f1e", - "ghostCheckedHoveredContent": "#201f1e", - "ghostContent": "#323130", - "ghostDisabledBackground": "#ffffff", - "ghostDisabledBorder": "#ffffff", - "ghostDisabledContent": "#a19f9d", - "ghostDisabledIcon": "#a19f9d", - "ghostFocusedBackground": "#f3f2f1", - "ghostFocusedBorder": "#8a8886", - "ghostFocusedContent": "#201f1e", - "ghostFocusedIcon": "#201f1e", - "ghostFocusedSecondaryContent": "#605e5c", - "ghostHoveredBackground": "#f3f2f1", - "ghostHoveredBorder": "#f3f2f1", - "ghostHoveredContent": "#201f1e", - "ghostHoveredIcon": "#201f1e", - "ghostHoveredSecondaryContent": "#605e5c", - "ghostIcon": "#323130", - "ghostPressedBackground": "#edebe9", - "ghostPressedBorder": "#edebe9", - "ghostPressedContent": "#201f1e", - "ghostPressedIcon": "#201f1e", - "ghostPressedSecondaryContent": "#605e5c", - "ghostSecondaryContent": "#605e5c", - "inputBackground": "#ffffff", - "inputBorder": "#a19f9d", - "inputFocusBorderAlt": undefined, - "inputPlaceholderText": "#605e5c", - "inputText": "#323130", - "link": undefined, - "linkHovered": undefined, - "linkPressed": undefined, - "listHeaderBackgroundHovered": "#f3f2f1", - "listHeaderBackgroundPressed": "#edebe9", - "menuBackground": "#ffffff", - "menuDivider": "#c8c6c4", - "menuIcon": undefined, - "menuItemBackgroundHovered": "#f3f2f1", - "menuItemBackgroundPressed": "#edebe9", - "menuItemText": "#323130", - "menuItemTextHovered": "#201f1e", - "neutralBackground1": "#ffffff", - "neutralBackground1Hover": "#f5f5f5", - "neutralBackground1Pressed": "#e0e0e0", - "neutralBackground1Selected": "#ebebeb", - "neutralBackground2": "#fafafa", - "neutralBackground2Hover": "#f0f0f0", - "neutralBackground2Pressed": "#dbdbdb", - "neutralBackground2Selected": "#e6e6e6", - "neutralBackground3": "#f5f5f5", - "neutralBackground3Hover": "#ebebeb", - "neutralBackground3Pressed": "#d6d6d6", - "neutralBackground3Selected": "#e0e0e0", - "neutralBackground4": "#f0f0f0", - "neutralBackground4Hover": "#fafafa", - "neutralBackground4Pressed": "#f5f5f5", - "neutralBackground4Selected": "#ffffff", - "neutralBackground5": "#ebebeb", - "neutralBackground5Hover": "#f5f5f5", - "neutralBackground5Pressed": "#f0f0f0", - "neutralBackground5Selected": "#fafafa", - "neutralBackground6": "#e6e6e6", - "neutralBackgroundDisabled": "#f0f0f0", - "neutralBackgroundInverted": "#616161", - "neutralForeground1": "#242424", - "neutralForeground1Hover": "#242424", - "neutralForeground1Pressed": "#242424", - "neutralForeground1Selected": "#242424", - "neutralForeground2": "#424242", - "neutralForeground2BrandHover": "#185abd", - "neutralForeground2BrandPressed": "#1651aa", - "neutralForeground2BrandSelected": "#185abd", - "neutralForeground2Hover": "#242424", - "neutralForeground2Pressed": "#242424", - "neutralForeground2Selected": "#242424", - "neutralForeground3": "#616161", - "neutralForeground3BrandHover": "#185abd", - "neutralForeground3BrandPressed": "#1651aa", - "neutralForeground3BrandSelected": "#185abd", - "neutralForeground3Hover": "#424242", - "neutralForeground3Pressed": "#424242", - "neutralForeground3Selected": "#424242", - "neutralForeground4": "#707070", - "neutralForegroundDisabled": "#bdbdbd", - "neutralForegroundInverted": "#ffffff", - "neutralForegroundInvertedLink": "#ffffff", - "neutralForegroundInvertedLinkHover": "#ffffff", - "neutralForegroundInvertedLinkPressed": "#ffffff", - "neutralForegroundInvertedLinkSelected": "#ffffff", - "neutralForegroundOnBrand": "#ffffff", - "neutralForegroundOnBrandHover": "#ffffff", - "neutralForegroundOnBrandPressed": "#ffffff", - "neutralForegroundOnBrandSelected": "#ffffff", - "neutralStencil1": "#e6e6e6", - "neutralStencil2": "#fafafa", - "neutralStroke1": "#d1d1d1", - "neutralStroke1Hover": "#c7c7c7", - "neutralStroke1Pressed": "#b3b3b3", - "neutralStroke1Selected": "#bdbdbd", - "neutralStroke2": "#e0e0e0", - "neutralStroke3": "#f0f0f0", - "neutralStrokeAccessible": "#616161", - "neutralStrokeAccessibleHover": "#575757", - "neutralStrokeAccessiblePressed": "#4d4d4d", - "neutralStrokeAccessibleSelected": "#185abd", - "neutralStrokeDisabled": "#e0e0e0", - "outofofficeBackground1": "#fdf5fc", - "outofofficeBackground2": "#edbbe7", - "outofofficeBackground3": "#c239b3", - "outofofficeBorder1": "#edbbe7", - "outofofficeBorder2": "#c239b3", - "outofofficeBorderActive": "#c239b3", - "outofofficeForeground1": "#af33a1", - "outofofficeForeground2": "#6d2064", - "outofofficeForeground3": "#c239b3", - "personaActivityGlow": undefined, - "personaActivityRing": "#ffffff", - "primaryButtonBackground": undefined, - "primaryButtonBackgroundDisabled": "#f3f2f1", - "primaryButtonBackgroundHovered": undefined, - "primaryButtonBackgroundPressed": undefined, - "primaryButtonBorder": "transparent", - "primaryButtonBorderFocused": "transparent", - "primaryButtonText": "#ffffff", - "primaryButtonTextDisabled": "#d2d0ce", - "primaryButtonTextHovered": "#ffffff", - "primaryButtonTextPressed": "#ffffff", - "severeBackground1": "#fdf6f3", - "severeBackground2": "#f4bfab", - "severeBackground3": "#da3b01", - "severeBorder1": "#f4bfab", - "severeBorder2": "#da3b01", - "severeBorderActive": "#da3b01", - "severeForeground1": "#c43501", - "severeForeground2": "#7a2101", - "severeForeground3": "#da3b01", - "strokeFocus1": "#ffffff", - "strokeFocus2": "#000000", - "subText": "#605e5c", "subtleBackground": "#00000000", - "subtleBackgroundHover": "#f5f5f5", - "subtleBackgroundPressed": "#e0e0e0", - "subtleBackgroundSelected": "#ebebeb", - "successBackground1": "#f1faf1", - "successBackground2": "#9fd89f", - "successBackground3": "#107c10", - "successBorder1": "#9fd89f", - "successBorder2": "#107c10", - "successBorderActive": "#107c10", - "successForeground1": "#0e700e", - "successForeground2": "#094509", - "successForeground3": "#107c10", - "successForegroundInverted": "#359b35", + "subtleBackgroundHover": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "subtleBackgroundPressed": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "subtleBackgroundSelected": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "successBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "successBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "successBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "successForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successForegroundInverted": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "successStroke1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", "transparentBackgroundSelected": "#00000000", - "transparentStroke": "#00000000", - "transparentStrokeDisabled": "#00000000", - "transparentStrokeInteractive": "#00000000", - "variantBorder": "#edebe9", - "warningBackground1": "#fffef5", - "warningBackground2": "#fef7b2", - "warningBackground3": "#fde300", - "warningBorder1": "#fef7b2", - "warningBorder2": "#fde300", - "warningBorderActive": "#fde300", - "warningForeground1": "#817400", - "warningForeground2": "#817400", - "warningForeground3": "#fde300", - "warningForegroundInverted": "#fef7b2", + "transparentStroke": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "transparentStrokeDisabled": { + "windowsbrush": [ + "SystemColorGrayTextColor", + ], + }, + "transparentStrokeInteractive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "variantBorder": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningBackground1": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "warningBackground2": { + "windowsbrush": [ + "SystemColorWindowColor", + ], + }, + "warningBackground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningBorder1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningBorder2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningBorderActive": { + "windowsbrush": [ + "SystemColorHighlightColor", + ], + }, + "warningForeground1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningForeground2": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningForeground3": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningForegroundInverted": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, + "warningStroke1": { + "windowsbrush": [ + "SystemColorWindowTextColor", + ], + }, }, "components": {}, "host": { - "appearance": "light", + "appearance": "highContrast", }, "shadows": { "shadow16": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 16, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 8, }, @@ -2131,13 +4820,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow2": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 2, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 1, }, @@ -2145,13 +4834,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow28": { "ambient": { "blur": 8, - "color": "#00000033", + "color": "#00000066", "x": 0, "y": 0, }, "key": { "blur": 28, - "color": "#0000003d", + "color": "#0000007a", "x": 0, "y": 14, }, @@ -2187,13 +4876,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow4": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 4, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 2, }, @@ -2215,13 +4904,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow64": { "ambient": { "blur": 8, - "color": "#00000033", + "color": "#00000066", "x": 0, "y": 0, }, "key": { "blur": 64, - "color": "#0000003d", + "color": "#0000007a", "x": 0, "y": 32, }, @@ -2243,13 +4932,13 @@ exports[`defaultFluentTheme 1`] = ` "shadow8": { "ambient": { "blur": 2, - "color": "#0000001f", + "color": "#0000003d", "x": 0, "y": 0, }, "key": { "blur": 8, - "color": "#00000024", + "color": "#00000047", "x": 0, "y": 4, }, @@ -2278,13 +4967,13 @@ exports[`defaultFluentTheme 1`] = ` }, "typography": { "families": { - "cursive": "System", - "monospace": "System", - "numeric": "System", + "cursive": "Segoe UI", + "monospace": "Consolas", + "numeric": "Bahnschrift", "primary": "Segoe UI", - "sansSerif": "System", + "sansSerif": "Segoe UI", "secondary": "Segoe UI", - "serif": "System", + "serif": "Segoe UI", }, "sizes": { "body": 14, @@ -2298,138 +4987,153 @@ exports[`defaultFluentTheme 1`] = ` "variants": { "body1": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "body1Strong": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "body2": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "body2Strong": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodySemibold": { "face": "primary", - "size": "body", - "weight": "semiBold", + "size": 14, + "weight": "600", }, "bodyStandard": { "face": "primary", - "size": "body", - "weight": "regular", + "size": 14, + "weight": "400", }, "caption1": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", - "size": "caption", - "weight": "regular", + "size": 10, + "weight": "400", }, "display": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "headerSemibold": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "headerStandard": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "heroLargeSemibold": { "face": "primary", - "size": "heroLarge", - "weight": "semiBold", + "size": 40, + "weight": "600", }, "heroLargeStandard": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "heroSemibold": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", }, "heroStandard": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "largeTitle": { "face": "primary", - "size": "heroLarge", - "weight": "regular", + "size": 40, + "weight": "400", }, "secondarySemibold": { "face": "primary", - "size": "secondary", - "weight": "semiBold", + "size": 12, + "weight": "600", }, "secondaryStandard": { "face": "primary", - "size": "secondary", - "weight": "regular", + "size": 12, + "weight": "400", }, "subheaderSemibold": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "subheaderStandard": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle1": { "face": "primary", - "size": "header", - "weight": "regular", + "size": 20, + "weight": "400", }, "subtitle1Strong": { "face": "primary", - "size": "header", - "weight": "semiBold", + "size": 20, + "weight": "600", }, "subtitle2": { "face": "primary", - "size": "subheader", - "weight": "regular", + "size": 16, + "weight": "400", }, "subtitle2Strong": { "face": "primary", - "size": "subheader", - "weight": "semiBold", + "size": 16, + "weight": "600", }, "title1": { "face": "primary", - "size": "hero", - "weight": "regular", + "size": 28, + "weight": "400", }, "title1Strong": { "face": "primary", - "size": "hero", - "weight": "semiBold", + "size": 28, + "weight": "600", + }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", }, }, "weights": { diff --git a/packages/theming/default-theme/src/__tests__/default-theme.test.ts b/packages/theming/default-theme/src/__tests__/default-theme.test.ts index eebc8328eb..592f9d69fd 100644 --- a/packages/theming/default-theme/src/__tests__/default-theme.test.ts +++ b/packages/theming/default-theme/src/__tests__/default-theme.test.ts @@ -1,8 +1,6 @@ -import type { ThemeOptions, AppearanceOptions } from '@fluentui-react-native/design/theming'; +import type { ThemeOptions } from '@fluentui-react-native/design/theming'; -import { createColorAliasTokens, createShadowAliasTokens } from '../createAliasTokens'; -import { createDefaultTheme } from '../createDefaultTheme'; -import { defaultFluentTheme, defaultFluentDarkTheme } from '../defaultTheme'; +import { createDefaultTheme, defaultFluentTheme, defaultFluentDarkTheme } from '../index'; const defaultThemeOptions: ThemeOptions[][] = [ [{ appearance: 'light', defaultAppearance: 'light' }], @@ -12,8 +10,6 @@ const defaultThemeOptions: ThemeOptions[][] = [ [{ appearance: 'dynamic', defaultAppearance: 'light' }], ]; -const appearanceOptions: AppearanceOptions[] = ['light', 'dark', 'highContrast']; - beforeAll(() => { jest.mock('react-native/Libraries/Utilities/Appearance', () => ({ getColorScheme: () => 'dark', @@ -57,15 +53,3 @@ describe('createDefaultTheme test', () => { expect(reference.theme.host.appearance).toBe('dark'); }); }); - -describe('createColorAliasTokens test', () => { - it.concurrent.each(appearanceOptions)('appearanceOptions - %s', async (appearanceOption: AppearanceOptions) => { - expect(createColorAliasTokens(appearanceOption)).toMatchSnapshot(); - }); -}); - -describe('createShadowAliasTokens test', () => { - it.concurrent.each(appearanceOptions)('appearanceOptions - %s', async (appearanceOption: AppearanceOptions) => { - expect(createShadowAliasTokens(appearanceOption)).toMatchSnapshot(); - }); -}); diff --git a/packages/theming/default-theme/src/__tests__/defaultThemes.test.android.ts b/packages/theming/default-theme/src/__tests__/defaultThemes.test.android.ts index 988677a134..b111ccd885 100644 --- a/packages/theming/default-theme/src/__tests__/defaultThemes.test.android.ts +++ b/packages/theming/default-theme/src/__tests__/defaultThemes.test.android.ts @@ -1,4 +1,4 @@ -import { defaultFluentTheme, defaultFluentDarkTheme, defaultFluentHighConstrastTheme } from '../defaultTheme'; +import { createDefaultTheme, defaultFluentDarkTheme, defaultFluentTheme } from '../index'; it('defaultFluentTheme', () => { expect(defaultFluentTheme).toMatchSnapshot(); @@ -8,6 +8,11 @@ it('defaultFluentDarkTheme', () => { expect(defaultFluentDarkTheme).toMatchSnapshot(); }); -it('defaultFluentHighConstrastTheme', () => { - expect(defaultFluentHighConstrastTheme).toMatchSnapshot(); +it.each(['light', 'dark'] as const)('high contrast %s theme', (colorScheme) => { + const theme = createDefaultTheme({ appearance: 'highContrast' }).resolveTheme({ + colorScheme, + contrast: 'highContrast', + interfaceLevel: 'base', + }); + expect(theme).toMatchSnapshot(); }); diff --git a/packages/theming/default-theme/src/__tests__/defaultThemes.test.ios.ts b/packages/theming/default-theme/src/__tests__/defaultThemes.test.ios.ts index 988677a134..b111ccd885 100644 --- a/packages/theming/default-theme/src/__tests__/defaultThemes.test.ios.ts +++ b/packages/theming/default-theme/src/__tests__/defaultThemes.test.ios.ts @@ -1,4 +1,4 @@ -import { defaultFluentTheme, defaultFluentDarkTheme, defaultFluentHighConstrastTheme } from '../defaultTheme'; +import { createDefaultTheme, defaultFluentDarkTheme, defaultFluentTheme } from '../index'; it('defaultFluentTheme', () => { expect(defaultFluentTheme).toMatchSnapshot(); @@ -8,6 +8,11 @@ it('defaultFluentDarkTheme', () => { expect(defaultFluentDarkTheme).toMatchSnapshot(); }); -it('defaultFluentHighConstrastTheme', () => { - expect(defaultFluentHighConstrastTheme).toMatchSnapshot(); +it.each(['light', 'dark'] as const)('high contrast %s theme', (colorScheme) => { + const theme = createDefaultTheme({ appearance: 'highContrast' }).resolveTheme({ + colorScheme, + contrast: 'highContrast', + interfaceLevel: 'base', + }); + expect(theme).toMatchSnapshot(); }); diff --git a/packages/theming/default-theme/src/__tests__/defaultThemes.test.macos.ts b/packages/theming/default-theme/src/__tests__/defaultThemes.test.macos.ts index 988677a134..b111ccd885 100644 --- a/packages/theming/default-theme/src/__tests__/defaultThemes.test.macos.ts +++ b/packages/theming/default-theme/src/__tests__/defaultThemes.test.macos.ts @@ -1,4 +1,4 @@ -import { defaultFluentTheme, defaultFluentDarkTheme, defaultFluentHighConstrastTheme } from '../defaultTheme'; +import { createDefaultTheme, defaultFluentDarkTheme, defaultFluentTheme } from '../index'; it('defaultFluentTheme', () => { expect(defaultFluentTheme).toMatchSnapshot(); @@ -8,6 +8,11 @@ it('defaultFluentDarkTheme', () => { expect(defaultFluentDarkTheme).toMatchSnapshot(); }); -it('defaultFluentHighConstrastTheme', () => { - expect(defaultFluentHighConstrastTheme).toMatchSnapshot(); +it.each(['light', 'dark'] as const)('high contrast %s theme', (colorScheme) => { + const theme = createDefaultTheme({ appearance: 'highContrast' }).resolveTheme({ + colorScheme, + contrast: 'highContrast', + interfaceLevel: 'base', + }); + expect(theme).toMatchSnapshot(); }); diff --git a/packages/theming/default-theme/src/__tests__/defaultThemes.test.win32.ts b/packages/theming/default-theme/src/__tests__/defaultThemes.test.win32.ts index 988677a134..b111ccd885 100644 --- a/packages/theming/default-theme/src/__tests__/defaultThemes.test.win32.ts +++ b/packages/theming/default-theme/src/__tests__/defaultThemes.test.win32.ts @@ -1,4 +1,4 @@ -import { defaultFluentTheme, defaultFluentDarkTheme, defaultFluentHighConstrastTheme } from '../defaultTheme'; +import { createDefaultTheme, defaultFluentDarkTheme, defaultFluentTheme } from '../index'; it('defaultFluentTheme', () => { expect(defaultFluentTheme).toMatchSnapshot(); @@ -8,6 +8,11 @@ it('defaultFluentDarkTheme', () => { expect(defaultFluentDarkTheme).toMatchSnapshot(); }); -it('defaultFluentHighConstrastTheme', () => { - expect(defaultFluentHighConstrastTheme).toMatchSnapshot(); +it.each(['light', 'dark'] as const)('high contrast %s theme', (colorScheme) => { + const theme = createDefaultTheme({ appearance: 'highContrast' }).resolveTheme({ + colorScheme, + contrast: 'highContrast', + interfaceLevel: 'base', + }); + expect(theme).toMatchSnapshot(); }); diff --git a/packages/theming/default-theme/src/__tests__/defaultThemes.test.windows.ts b/packages/theming/default-theme/src/__tests__/defaultThemes.test.windows.ts index 988677a134..b111ccd885 100644 --- a/packages/theming/default-theme/src/__tests__/defaultThemes.test.windows.ts +++ b/packages/theming/default-theme/src/__tests__/defaultThemes.test.windows.ts @@ -1,4 +1,4 @@ -import { defaultFluentTheme, defaultFluentDarkTheme, defaultFluentHighConstrastTheme } from '../defaultTheme'; +import { createDefaultTheme, defaultFluentDarkTheme, defaultFluentTheme } from '../index'; it('defaultFluentTheme', () => { expect(defaultFluentTheme).toMatchSnapshot(); @@ -8,6 +8,11 @@ it('defaultFluentDarkTheme', () => { expect(defaultFluentDarkTheme).toMatchSnapshot(); }); -it('defaultFluentHighConstrastTheme', () => { - expect(defaultFluentHighConstrastTheme).toMatchSnapshot(); +it.each(['light', 'dark'] as const)('high contrast %s theme', (colorScheme) => { + const theme = createDefaultTheme({ appearance: 'highContrast' }).resolveTheme({ + colorScheme, + contrast: 'highContrast', + interfaceLevel: 'base', + }); + expect(theme).toMatchSnapshot(); }); diff --git a/packages/theming/default-theme/src/createAliasTokens.ts b/packages/theming/default-theme/src/createAliasTokens.ts deleted file mode 100644 index f6e55a87bc..0000000000 --- a/packages/theming/default-theme/src/createAliasTokens.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { memoize } from '@fluentui-react-native/framework-base'; -import { getAliasTokens, getShadowTokens } from '@fluentui-react-native/design/tokens/legacy'; -import type { AliasColorTokens, AppearanceOptions, ThemeShadowDefinition } from '@fluentui-react-native/design/theming'; -import { mapPipelineToShadow, mapPipelineToTheme } from '@fluentui-react-native/design/theming'; - -function createColorAliasTokensWorker(mode: AppearanceOptions): AliasColorTokens { - const aliasTokens = getAliasTokens(mode); - return mapPipelineToTheme(aliasTokens); -} - -export const createColorAliasTokens = memoize(createColorAliasTokensWorker); - -function createShadowAliasTokensWorker(mode: AppearanceOptions): ThemeShadowDefinition { - const aliasTokens = getShadowTokens(mode); - return mapPipelineToShadow(aliasTokens); -} - -export const createShadowAliasTokens = memoize(createShadowAliasTokensWorker); diff --git a/packages/theming/default-theme/src/createDefaultTheme.ts b/packages/theming/default-theme/src/createDefaultTheme.ts index 0268a457a3..23fc2fc3eb 100644 --- a/packages/theming/default-theme/src/createDefaultTheme.ts +++ b/packages/theming/default-theme/src/createDefaultTheme.ts @@ -1,37 +1,21 @@ -import { ThemeReference } from '@fluentui-react-native/design/theming'; +import { appearanceOptionsFromLegacy, resolveThemeAppearance, ThemeReference } from '@fluentui-react-native/design/theming'; import type { Theme, ThemeOptions } from '@fluentui-react-native/design/theming'; -import { - appearanceOptionFromResolved, - appearanceOptionsFromLegacy, - getCurrentAppearance, - resolveThemeAppearance, -} from '@fluentui-react-native/design/theming'; -import assertNever from 'assert-never'; - -import { defaultFluentDarkTheme, defaultFluentHighConstrastTheme, defaultFluentTheme } from './defaultTheme'; +import { fluentTheme } from '@fluentui-react-native/design/themes'; +/** + * Create a theme reference for legacy theme options. It resolves the design package's Fluent themes, including the + * high-contrast themes, for the requested appearance. + */ export function createDefaultTheme(options: ThemeOptions = {}): ThemeReference { + const getAppearance = () => appearanceOptionsFromLegacy(options.appearance ?? options.defaultAppearance ?? 'light'); + const getFallbackAppearance = () => resolveThemeAppearance(appearanceOptionsFromLegacy(options.defaultAppearance ?? 'light')).resolved; return new ThemeReference({ base: {} as Theme, - getAppearance: () => appearanceOptionsFromLegacy(options.appearance ?? options.defaultAppearance ?? 'light'), - getFallbackAppearance: () => resolveThemeAppearance(appearanceOptionsFromLegacy(options.defaultAppearance ?? 'light')).resolved, + getAppearance, + getFallbackAppearance, recipes: [ - (_theme, resolvedAppearance) => { - const current = resolvedAppearance - ? appearanceOptionFromResolved(resolvedAppearance) - : getCurrentAppearance(options.appearance, options.defaultAppearance ?? 'light'); - switch (current) { - case 'light': - return defaultFluentTheme; - case 'dark': - case 'darkElevated': - return defaultFluentDarkTheme; - case 'highContrast': - return defaultFluentHighConstrastTheme; - default: - assertNever(current); - } - }, + (_theme, appearance) => + fluentTheme.resolveTheme(appearance ?? resolveThemeAppearance(getAppearance(), undefined, getFallbackAppearance()).resolved), ], }); } diff --git a/packages/theming/default-theme/src/defaultColors.ts b/packages/theming/default-theme/src/defaultColors.ts deleted file mode 100644 index 2969323c6e..0000000000 --- a/packages/theming/default-theme/src/defaultColors.ts +++ /dev/null @@ -1,325 +0,0 @@ -import type { Palette, FabricWebPalette, ThemeColorDefinition } from '@fluentui-react-native/design/theming'; - -import { createColorAliasTokens } from './createAliasTokens'; - -/** - * Generate a palette from a set of fabric web colors, like those output from the theme designer. - * - * @param palette - fabric web palette definition. This allows initializing our color values in the same - * manner the fabric web does it - */ -export function paletteFromFabricColors(p: FabricWebPalette, isInverted?: boolean): Palette { - return { - background: p.white, - bodyStandoutBackground: p.neutralLighterAlt, - bodyFrameBackground: p.white, - bodyFrameDivider: p.neutralLight, - bodyText: p.neutralPrimary, - bodyTextChecked: p.black, - subText: p.neutralSecondary, - bodyDivider: p.neutralLight, - - disabledBackground: isInverted ? p.neutralQuaternaryAlt : p.neutralLighter, - disabledText: p.neutralTertiary, - disabledBodyText: p.neutralTertiary, - - focusBorder: p.neutralSecondary, - variantBorder: p.neutralLight, - - errorText: !isInverted ? p.redDark : '#ff5f5f', - inputBorder: p.neutralTertiary, - inputBackground: p.white, - inputFocusBorderAlt: p.themePrimary, - inputText: p.neutralPrimary, - inputPlaceholderText: p.neutralSecondary, - - buttonBackground: p.neutralLighter, - buttonBackgroundChecked: p.neutralTertiaryAlt, - buttonBackgroundHovered: p.neutralLight, - buttonBackgroundPressed: p.neutralLight, - buttonBackgroundDisabled: p.neutralLighter, - buttonBorder: p.neutralSecondaryAlt, - buttonText: isInverted ? p.black : p.neutralPrimary, - buttonTextHovered: isInverted ? p.neutralPrimary : p.neutralDark, - buttonTextChecked: p.neutralDark, - buttonTextPressed: p.neutralDark, - buttonTextDisabled: p.neutralTertiary, - buttonBorderDisabled: p.neutralLighter, - buttonBorderFocused: p.neutralSecondaryAlt, - - primaryButtonBackground: p.themePrimary, - primaryButtonBackgroundHovered: p.themeDarkAlt, - primaryButtonBackgroundPressed: p.themeDark, - primaryButtonBackgroundDisabled: p.neutralLighter, - primaryButtonBorder: 'transparent', - primaryButtonBorderFocused: 'transparent', - primaryButtonText: p.white, - primaryButtonTextHovered: p.white, - primaryButtonTextPressed: p.white, - primaryButtonTextDisabled: p.neutralQuaternary, - - accentButtonBackground: p.accent, - - menuBackground: isInverted ? p.neutralLighter : p.white, - menuDivider: isInverted ? p.neutralTertiaryAlt : p.neutralTertiaryAlt, - menuIcon: isInverted ? p.themeDarkAlt : p.themePrimary, - menuItemBackgroundHovered: isInverted ? p.neutralQuaternaryAlt : p.neutralLighter, - menuItemBackgroundPressed: isInverted ? p.neutralQuaternary : p.neutralLight, - menuItemText: p.neutralPrimary, - menuItemTextHovered: p.neutralDark, - - listHeaderBackgroundHovered: p.neutralLighter, - listHeaderBackgroundPressed: p.neutralLight, - - actionLink: p.neutralPrimary, - link: p.themePrimary, - linkHovered: p.themeDarker, - linkPressed: p.themeDark, - - // Control Color Tokens - defaultBackground: p.neutralLighter, - defaultBorder: p.neutralSecondaryAlt, - defaultContent: isInverted ? p.black : p.neutralPrimary, - defaultIcon: isInverted ? p.black : p.neutralPrimary, - - defaultHoveredBackground: p.neutralLight, - defaultHoveredBorder: p.neutralSecondaryAlt, - defaultHoveredContent: isInverted ? p.neutralPrimary : p.neutralDark, - defaultHoveredIcon: isInverted ? p.neutralPrimary : p.neutralDark, - - defaultFocusedBackground: p.neutralLight, - defaultFocusedBorder: p.neutralSecondaryAlt, - defaultFocusedContent: isInverted ? p.neutralPrimary : p.neutralDark, - defaultFocusedIcon: isInverted ? p.neutralPrimary : p.neutralDark, - - defaultPressedBackground: p.neutralLight, - defaultPressedBorder: p.neutralSecondaryAlt, - defaultPressedContent: p.neutralDark, - defaultPressedIcon: p.neutralDark, - - defaultDisabledBackground: p.neutralLighter, - defaultDisabledBorder: p.neutralLighter, - defaultDisabledContent: p.neutralTertiary, - defaultDisabledIcon: p.neutralTertiary, - - ghostBackground: p.white, - ghostBorder: p.white, - ghostContent: p.neutralPrimary, - ghostIcon: p.neutralPrimary, - - ghostHoveredBackground: p.neutralLighter, - ghostHoveredBorder: p.neutralLighter, - ghostHoveredContent: p.neutralDark, - ghostHoveredIcon: p.neutralDark, - - ghostFocusedBackground: p.neutralLighter, - ghostFocusedBorder: p.neutralSecondaryAlt, - ghostFocusedContent: p.neutralDark, - ghostFocusedIcon: p.neutralDark, - - ghostPressedBackground: p.neutralLight, - ghostPressedBorder: p.neutralLight, - ghostPressedContent: p.neutralDark, - ghostPressedIcon: p.neutralDark, - - ghostDisabledBackground: p.white, - ghostDisabledBorder: p.white, - ghostDisabledContent: p.neutralTertiary, - ghostDisabledIcon: p.neutralTertiary, - - brandedBackground: p.themePrimary, - - brandedDisabledBorder: p.neutralLighter, - - defaultCheckedBackground: p.neutralTertiaryAlt, - defaultCheckedContent: p.neutralDark, - defaultCheckedHoveredBackground: p.neutralLight, - defaultCheckedHoveredContent: isInverted ? p.neutralPrimary : p.neutralDark, - - ghostCheckedBackground: p.neutralLight, - ghostCheckedContent: p.black, - ghostCheckedHoveredBackground: p.neutralLighter, - ghostCheckedHoveredContent: p.neutralDark, - ghostCheckedHoveredBorder: p.neutralDark, - - ghostSecondaryContent: p.neutralSecondary, - ghostFocusedSecondaryContent: p.neutralSecondary, - ghostHoveredSecondaryContent: p.neutralSecondary, - ghostPressedSecondaryContent: p.neutralSecondary, - - brandedSecondaryContent: p.neutralLighterAlt, - brandedFocusedSecondaryContent: p.neutralLighterAlt, - brandedHoveredSecondaryContent: p.neutralLighterAlt, - brandedPressedSecondaryContent: p.neutralLighterAlt, - - defaultHoveredSecondaryContent: p.neutralTertiary, - defaultPressedSecondaryContent: p.neutralTertiary, - - checkmarkColor: p.white, - checkboxBackground: p.themePrimary, - checkboxBackgroundDisabled: p.neutralLighter, - checkboxBorderColor: p.neutralSecondaryAlt, - - personaActivityRing: p.white, - personaActivityGlow: p.themePrimary, - }; -} - -export function getStockWebHCPalette(): ThemeColorDefinition { - return { - background: '#000000', - bodyStandoutBackground: '#000000', - bodyFrameBackground: '#000000', - bodyFrameDivider: '#000000', - bodyText: '#ffffff', - bodyTextChecked: '#000000', - subText: '#ffffff', - bodyDivider: '#ffffff', - - disabledBackground: '#000000', - disabledText: '#3ff23f', - disabledBodyText: '#3ff23f', - - focusBorder: '#ffffff', - variantBorder: '#ffffff', - - errorText: '#ffffff', - - inputBorder: '#ffffff', - inputBackground: '#000000', - inputFocusBorderAlt: '#ffffff', - inputText: '#ffffff', - inputPlaceholderText: '#ffffff', - - buttonBackground: '#000000', - buttonBackgroundChecked: '#1aebff', - buttonBackgroundHovered: '#1aebff', - buttonBackgroundPressed: '#1aebff', - buttonBackgroundDisabled: '#000000', - buttonBorder: '#ffffff', - buttonText: '#ffffff', - buttonTextHovered: '#000000', - buttonTextChecked: '#000000', - buttonTextPressed: '#000000', - buttonTextDisabled: '#3ff23f', - buttonBorderDisabled: '#3ff23f', - buttonBorderFocused: '#ffffff', - - primaryButtonBackground: '#000000', - primaryButtonBackgroundHovered: '#1aebff', - primaryButtonBackgroundPressed: '#1aebff', - primaryButtonBackgroundDisabled: '#000000', - primaryButtonBorder: '#ffffff', - primaryButtonBorderFocused: '#ffffff', - primaryButtonText: '#ffffff', - primaryButtonTextHovered: '#000000', - primaryButtonTextPressed: '#000000', - primaryButtonTextDisabled: '#3ff23f', - - accentButtonBackground: '#000000', - - menuBackground: '#000000', - menuDivider: '#ffffff', - menuIcon: '#ffffff', - menuItemBackgroundHovered: '#1aebff', - menuItemBackgroundPressed: '#1aebff', - menuItemText: '#ffffff', - menuItemTextHovered: '#000000', - - listHeaderBackgroundHovered: '#1aebff', - listHeaderBackgroundPressed: '#1aebff', - - actionLink: '#ffff00', - link: '#ffff00', - linkHovered: '#ffffff', - linkPressed: '#ffffff', - - // Control Color Tokens - defaultBackground: '#000000', - defaultBorder: '#ffffff', - defaultContent: '#ffffff', - defaultIcon: '#ffffff', - - defaultHoveredBackground: '#1aebff', - defaultHoveredBorder: '#1aebff', - defaultHoveredContent: '#000000', - defaultHoveredIcon: '#000000', - - defaultFocusedBackground: '#000000', - defaultFocusedBorder: '#ffffff', - defaultFocusedContent: '#ffffff', - defaultFocusedIcon: '#ffffff', - - defaultPressedBackground: '#1aebff', - defaultPressedBorder: '#1aebff', - defaultPressedContent: '#000000', - defaultPressedIcon: '#000000', - - defaultDisabledBackground: '#000000', - defaultDisabledBorder: '#3ff23f', - defaultDisabledContent: '#3ff23f', - defaultDisabledIcon: '#3ff23f', - - ghostBackground: '#000000', - ghostBorder: '#000000', - ghostContent: '#ffffff', - ghostIcon: '#ffffff', - - ghostHoveredBackground: '#1aebff', - ghostHoveredBorder: '#1aebff', - ghostHoveredContent: '#000000', - ghostHoveredIcon: '#000000', - - ghostFocusedBackground: '#000000', - ghostFocusedBorder: '#ffffff', - ghostFocusedContent: '#ffffff', - ghostFocusedIcon: '#ffffff', - - ghostPressedBackground: '#1aebff', - ghostPressedBorder: '#1aebff', - ghostPressedContent: '#000000', - ghostPressedIcon: '#000000', - - ghostDisabledBackground: '#000000', - ghostDisabledBorder: '#000000', - ghostDisabledContent: '#3ff23f', - ghostDisabledIcon: '#3ff23f', - - brandedBackground: '#000000', - - brandedDisabledBorder: '#3ff23f', - - defaultCheckedBackground: '#1aebff', - defaultCheckedContent: '#000000', - defaultCheckedHoveredBackground: '#1aebff', - defaultCheckedHoveredContent: '#000000', - - ghostCheckedBackground: '#1aebff', - ghostCheckedContent: '#000000', - ghostCheckedHoveredBackground: '#1aebff', - ghostCheckedHoveredContent: '#000000', - ghostCheckedHoveredBorder: '#000000', - - ghostSecondaryContent: '#ffffff', - ghostFocusedSecondaryContent: '#ffffff', - ghostHoveredSecondaryContent: '#000000', - ghostPressedSecondaryContent: '#000000', - - brandedSecondaryContent: '#ffffff', - brandedFocusedSecondaryContent: '#ffffff', - brandedHoveredSecondaryContent: '#000000', - brandedPressedSecondaryContent: '#000000', - - defaultHoveredSecondaryContent: '#000000', - defaultPressedSecondaryContent: '#000000', - - checkmarkColor: '#ffffff', - checkboxBackground: '#000000', - checkboxBackgroundDisabled: '#000000', - checkboxBorderColor: '#ffffff', - - personaActivityRing: '#ffffff', - personaActivityGlow: 'transparent', // glow probably doesn't make sense on HC - ...createColorAliasTokens('highContrast'), - }; -} diff --git a/packages/theming/default-theme/src/defaultTheme.ts b/packages/theming/default-theme/src/defaultTheme.ts deleted file mode 100644 index 19a231f300..0000000000 --- a/packages/theming/default-theme/src/defaultTheme.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { getDefaultLegacyTheme } from '@fluentui-react-native/design/theming/compat/defaults'; - -export const defaultFluentTheme = getDefaultLegacyTheme({ - colorScheme: 'light', - contrast: 'standard', - interfaceLevel: 'base', -}); - -export const defaultFluentDarkTheme = getDefaultLegacyTheme({ - colorScheme: 'dark', - contrast: 'standard', - interfaceLevel: 'base', -}); - -export const defaultFluentHighConstrastTheme = getDefaultLegacyTheme({ - colorScheme: 'dark', - contrast: 'highContrast', - interfaceLevel: 'base', -}); diff --git a/packages/theming/default-theme/src/index.ts b/packages/theming/default-theme/src/index.ts index 4d25a17a24..07130710a7 100644 --- a/packages/theming/default-theme/src/index.ts +++ b/packages/theming/default-theme/src/index.ts @@ -1,3 +1,2 @@ -export { defaultFluentTheme, defaultFluentDarkTheme } from './defaultTheme'; +export { fluentLightTheme as defaultFluentTheme, fluentDarkTheme as defaultFluentDarkTheme } from '@fluentui-react-native/design/themes'; export { createDefaultTheme } from './createDefaultTheme'; -export { createColorAliasTokens as createAliasTokens } from './createAliasTokens'; diff --git a/packages/theming/default-theme/src/stockWebPalette.macos.ts b/packages/theming/default-theme/src/stockWebPalette.macos.ts deleted file mode 100644 index 3502caf002..0000000000 --- a/packages/theming/default-theme/src/stockWebPalette.macos.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { globalTokens } from '@fluentui-react-native/design/tokens/legacy'; -import type { ThemeColorDefinition } from '@fluentui-react-native/design/theming'; -import { colorBlack, colorBurgundyPrimary, colorRedPrimary, colorWhite } from '@fluentui-react-native/design/tokens/global'; - -import { createColorAliasTokens } from './createAliasTokens'; -import { paletteFromFabricColors } from './defaultColors'; - -export function getStockWebPalette(): ThemeColorDefinition { - return { - ...paletteFromFabricColors({ - black: colorBlack, - neutralDark: '#201f1e', - neutralPrimary: '#323130', - neutralPrimaryAlt: '#3b3a39', - neutralSecondary: '#605e5c', - neutralSecondaryAlt: '#8a8886', - neutralTertiary: '#a19f9d', - neutralTertiaryAlt: '#c8c6c4', - neutralQuaternary: '#d2d0ce', - neutralQuaternaryAlt: '#e1dfdd', - neutralLight: '#edebe9', - neutralLighter: '#f3f2f1', - neutralLighterAlt: '#faf9f8', - white: colorWhite, - // Shared Colors - red: colorRedPrimary, - redDark: colorBurgundyPrimary, - - themeDarker: globalTokens.color.brand.shade40, - themeDark: globalTokens.color.brand.shade20, - themeDarkAlt: globalTokens.color.brand.shade10, - themePrimary: globalTokens.color.brand.primary, - themeSecondary: '#2b88d8', - themeTertiary: '#71afe5', - themeLight: globalTokens.color.brand.tint40, - themeLighter: globalTokens.color.brand.tint50, - themeLighterAlt: globalTokens.color.brand.tint60, - accent: globalTokens.color.brand.primary, - blackTranslucent40: 'rgba(0,0,0,.4)', - }), - ...createColorAliasTokens('light'), - }; -} - -export function getStockWebDarkPalette(): ThemeColorDefinition { - return { - ...paletteFromFabricColors( - { - // colors taken from fluentui DarkCustomizations.ts - themeDarker: '#82c7ff', - themeDark: globalTokens.color.brand.tint30, - themeDarkAlt: globalTokens.color.brand.tint20, - themePrimary: globalTokens.color.brand.tint10, - themeSecondary: globalTokens.color.brand.primary, - themeTertiary: '#235a85', - themeLight: globalTokens.color.brand.shade30, - themeLighter: globalTokens.color.brand.shade50, - themeLighterAlt: globalTokens.color.brand.shade60, - black: colorWhite, - neutralDark: '#faf9f8', - neutralPrimary: '#f3f2f1', - neutralPrimaryAlt: '#c8c6c4', - neutralSecondary: '#a19f9d', - neutralSecondaryAlt: '#979693', - neutralTertiary: '#797775', - neutralTertiaryAlt: '#484644', - neutralQuaternary: '#3b3a39', - neutralQuaternaryAlt: '#323130', - neutralLight: '#292827', - neutralLighter: '#252423', - neutralLighterAlt: '#201f1e', - white: '#1b1a19', - red: colorRedPrimary, - accent: globalTokens.color.brand.primary, - redDark: '#f1707b', - blackTranslucent40: 'rgba(0,0,0,.4)', - }, - true, - ), - ...createColorAliasTokens('dark'), - }; -} diff --git a/packages/theming/default-theme/src/stockWebPalette.ts b/packages/theming/default-theme/src/stockWebPalette.ts deleted file mode 100644 index dd7b3b40cb..0000000000 --- a/packages/theming/default-theme/src/stockWebPalette.ts +++ /dev/null @@ -1,107 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { globalTokens } from '@fluentui-react-native/design/tokens/legacy'; -import type { ThemeColorDefinition } from '@fluentui-react-native/design/theming'; -import { colorBlack, colorBurgundyPrimary, colorRedPrimary, colorWhite } from '@fluentui-react-native/design/tokens/global'; - -import { createColorAliasTokens } from './createAliasTokens'; -import { paletteFromFabricColors } from './defaultColors'; - -export function getStockWebPalette(): ThemeColorDefinition { - return { - ...paletteFromFabricColors({ - black: colorBlack, - neutralDark: '#201f1e', - neutralPrimary: '#323130', - neutralPrimaryAlt: '#3b3a39', - neutralSecondary: '#605e5c', - neutralSecondaryAlt: '#8a8886', - neutralTertiary: '#a19f9d', - neutralTertiaryAlt: '#c8c6c4', - neutralQuaternary: '#d2d0ce', - neutralQuaternaryAlt: '#e1dfdd', - neutralLight: '#edebe9', - neutralLighter: '#f3f2f1', - neutralLighterAlt: '#faf9f8', - white: colorWhite, - // Shared Colors - red: colorRedPrimary, - redDark: colorBurgundyPrimary, - - // @ts-expect-error - accent: globalTokens.color.brand80, - blackTranslucent40: 'rgba(0,0,0,.4)', - - // Colors to be deprecated - // @ts-expect-error - themeDarker: globalTokens.color.brand40, - // @ts-expect-error - themeDark: globalTokens.color.brand60, - // @ts-expect-error - themeDarkAlt: globalTokens.color.brand70, - // @ts-expect-error - themePrimary: globalTokens.color.brand80, - // @ts-expect-error - themeSecondary: globalTokens.color.brand90, - // @ts-expect-error - themeTertiary: globalTokens.color.brand120, - // @ts-expect-error - themeLight: globalTokens.color.brand140, - // @ts-expect-error - themeLighter: globalTokens.color.brand150, - // @ts-expect-error - themeLighterAlt: globalTokens.color.brand160, - }), - ...createColorAliasTokens('light'), - }; -} - -export function getStockWebDarkPalette(): ThemeColorDefinition { - return { - ...paletteFromFabricColors( - { - // colors taken from fluentui DarkCustomizations.ts - black: colorWhite, - neutralDark: '#faf9f8', - neutralPrimary: '#f3f2f1', - neutralPrimaryAlt: '#c8c6c4', - neutralSecondary: '#a19f9d', - neutralSecondaryAlt: '#979693', - neutralTertiary: '#797775', - neutralTertiaryAlt: '#484644', - neutralQuaternary: '#3b3a39', - neutralQuaternaryAlt: '#323130', - neutralLight: '#292827', - neutralLighter: '#252423', - neutralLighterAlt: '#201f1e', - white: '#1b1a19', - red: colorRedPrimary, - // @ts-expect-error - accent: globalTokens.color.brand40, - redDark: '#f1707b', - blackTranslucent40: 'rgba(0,0,0,.4)', - - // Colors to be deprecated - // @ts-expect-error - themeDarker: globalTokens.color.brand110, - // @ts-expect-error - themeDark: globalTokens.color.brand100, - // @ts-expect-error - themeDarkAlt: globalTokens.color.brand100, - // @ts-expect-error - themePrimary: globalTokens.color.brand90, - // @ts-expect-error - themeSecondary: globalTokens.color.brand90, - // @ts-expect-error - themeTertiary: globalTokens.color.brand60, - // @ts-expect-error - themeLight: globalTokens.color.brand50, - // @ts-expect-error - themeLighter: globalTokens.color.brand40, - // @ts-expect-error - themeLighterAlt: globalTokens.color.brand30, - }, - true, - ), - ...createColorAliasTokens('dark'), - }; -} diff --git a/packages/theming/default-theme/src/stockWebPalette.win32.ts b/packages/theming/default-theme/src/stockWebPalette.win32.ts deleted file mode 100644 index 3502caf002..0000000000 --- a/packages/theming/default-theme/src/stockWebPalette.win32.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { globalTokens } from '@fluentui-react-native/design/tokens/legacy'; -import type { ThemeColorDefinition } from '@fluentui-react-native/design/theming'; -import { colorBlack, colorBurgundyPrimary, colorRedPrimary, colorWhite } from '@fluentui-react-native/design/tokens/global'; - -import { createColorAliasTokens } from './createAliasTokens'; -import { paletteFromFabricColors } from './defaultColors'; - -export function getStockWebPalette(): ThemeColorDefinition { - return { - ...paletteFromFabricColors({ - black: colorBlack, - neutralDark: '#201f1e', - neutralPrimary: '#323130', - neutralPrimaryAlt: '#3b3a39', - neutralSecondary: '#605e5c', - neutralSecondaryAlt: '#8a8886', - neutralTertiary: '#a19f9d', - neutralTertiaryAlt: '#c8c6c4', - neutralQuaternary: '#d2d0ce', - neutralQuaternaryAlt: '#e1dfdd', - neutralLight: '#edebe9', - neutralLighter: '#f3f2f1', - neutralLighterAlt: '#faf9f8', - white: colorWhite, - // Shared Colors - red: colorRedPrimary, - redDark: colorBurgundyPrimary, - - themeDarker: globalTokens.color.brand.shade40, - themeDark: globalTokens.color.brand.shade20, - themeDarkAlt: globalTokens.color.brand.shade10, - themePrimary: globalTokens.color.brand.primary, - themeSecondary: '#2b88d8', - themeTertiary: '#71afe5', - themeLight: globalTokens.color.brand.tint40, - themeLighter: globalTokens.color.brand.tint50, - themeLighterAlt: globalTokens.color.brand.tint60, - accent: globalTokens.color.brand.primary, - blackTranslucent40: 'rgba(0,0,0,.4)', - }), - ...createColorAliasTokens('light'), - }; -} - -export function getStockWebDarkPalette(): ThemeColorDefinition { - return { - ...paletteFromFabricColors( - { - // colors taken from fluentui DarkCustomizations.ts - themeDarker: '#82c7ff', - themeDark: globalTokens.color.brand.tint30, - themeDarkAlt: globalTokens.color.brand.tint20, - themePrimary: globalTokens.color.brand.tint10, - themeSecondary: globalTokens.color.brand.primary, - themeTertiary: '#235a85', - themeLight: globalTokens.color.brand.shade30, - themeLighter: globalTokens.color.brand.shade50, - themeLighterAlt: globalTokens.color.brand.shade60, - black: colorWhite, - neutralDark: '#faf9f8', - neutralPrimary: '#f3f2f1', - neutralPrimaryAlt: '#c8c6c4', - neutralSecondary: '#a19f9d', - neutralSecondaryAlt: '#979693', - neutralTertiary: '#797775', - neutralTertiaryAlt: '#484644', - neutralQuaternary: '#3b3a39', - neutralQuaternaryAlt: '#323130', - neutralLight: '#292827', - neutralLighter: '#252423', - neutralLighterAlt: '#201f1e', - white: '#1b1a19', - red: colorRedPrimary, - accent: globalTokens.color.brand.primary, - redDark: '#f1707b', - blackTranslucent40: 'rgba(0,0,0,.4)', - }, - true, - ), - ...createColorAliasTokens('dark'), - }; -} diff --git a/packages/theming/default-theme/tsconfig.json b/packages/theming/default-theme/tsconfig.json index 58f7e57aae..9698ec893e 100644 --- a/packages/theming/default-theme/tsconfig.json +++ b/packages/theming/default-theme/tsconfig.json @@ -11,9 +11,6 @@ { "path": "../../agentic/design/tsconfig.json" }, - { - "path": "../../framework-base/tsconfig.json" - }, { "path": "../../../scripts/tsconfig.json" } diff --git a/packages/theming/win32-theme/src/__tests__/__snapshots__/win32-theme.test.ts.snap b/packages/theming/win32-theme/src/__tests__/__snapshots__/win32-theme.test.ts.snap index a0c4995644..4eefe9b5dc 100644 --- a/packages/theming/win32-theme/src/__tests__/__snapshots__/win32-theme.test.ts.snap +++ b/packages/theming/win32-theme/src/__tests__/__snapshots__/win32-theme.test.ts.snap @@ -2452,24 +2452,37 @@ exports[`createOfficeTheme test 1`] = ` "bodyTextChecked": "#262626", "brandBackground": "#D83B01", "brandBackground2": "#d2e0f4", + "brandBackground2Pressed": "#0e336a", + "brandBackground2Selected": "#13458f", + "brandBackground3": "#d2e0f4", "brandBackgroundHover": "#F29F71", + "brandBackgroundInverted": "#616161", + "brandBackgroundInvertedDisabled": "#f0f0f0", "brandBackgroundPressed": "#A22C01", "brandBackgroundSelected": "#13458f", "brandBackgroundStatic": "#185abd", + "brandBackgroundTint": "#d2e0f4", "brandForeground1": "#185abd", + "brandForeground1Selected": "#185abd", "brandForeground2": "#1651aa", + "brandForegroundDisabled1": "#bdbdbd", + "brandForegroundDisabled2": "#bdbdbd", "brandForegroundLink": "#185abd", "brandForegroundLinkHover": "#1651aa", "brandForegroundLinkPressed": "#0e336a", "brandForegroundLinkSelected": "#13458f", + "brandForegroundTint": "#1651aa", "brandStroke1": "#D83B01", + "brandStroke1Pressed": "#185abd", + "brandStroke1Selected": "#185abd", "brandStroke2": "#d2e0f4", + "brandStrokeTint": "#6794d7", "brandedBackground": "#D83B01", "brandedDisabledBorder": "#D2D2D2", - "brandedFocusedSecondaryContent": "#faf9f8", - "brandedHoveredSecondaryContent": "#faf9f8", - "brandedPressedSecondaryContent": "#faf9f8", - "brandedSecondaryContent": "#faf9f8", + "brandedFocusedSecondaryContent": "#ffffff", + "brandedHoveredSecondaryContent": "#ffffff", + "brandedPressedSecondaryContent": "#ffffff", + "brandedSecondaryContent": "#ffffff", "buttonBackground": "#E6E6E6", "buttonBackgroundChecked": "#E6E6E6", "buttonBackgroundDisabled": "#E6E6E6", @@ -2484,8 +2497,8 @@ exports[`createOfficeTheme test 1`] = ` "buttonTextHovered": "#262626", "buttonTextPressed": "#262626", "checkboxBackground": "#185abd", - "checkboxBackgroundDisabled": "#f3f2f1", - "checkboxBorderColor": "#8a8886", + "checkboxBackgroundDisabled": "#f0f0f0", + "checkboxBorderColor": "#616161", "checkmarkColor": "#ffffff", "compoundBrandBackground1": "#D83B01", "compoundBrandBackground1Hover": "#EA6115", @@ -2506,6 +2519,7 @@ exports[`createOfficeTheme test 1`] = ` "dangerForeground2": "#751d1f", "dangerForeground3": "#d13438", "dangerForegroundInverted": "#dc5e62", + "dangerStroke1": "#f1bbbc", "defaultBackground": "#E6E6E6", "defaultBorder": "#969696", "defaultCheckedBackground": "#E6E6E6", @@ -2525,13 +2539,13 @@ exports[`createOfficeTheme test 1`] = ` "defaultHoveredBorder": "#FBDFD0", "defaultHoveredContent": "#262626", "defaultHoveredIcon": "#262626", - "defaultHoveredSecondaryContent": "#a19f9d", + "defaultHoveredSecondaryContent": "#424242", "defaultIcon": "#262626", "defaultPressedBackground": "#FBDFD0", "defaultPressedBorder": "#EA6115", "defaultPressedContent": "#262626", "defaultPressedIcon": "#262626", - "defaultPressedSecondaryContent": "#a19f9d", + "defaultPressedSecondaryContent": "#424242", "disabledBackground": "#F3F3F3", "disabledBodyText": "#B1B1B1", "disabledText": "#B1B1B1", @@ -2604,8 +2618,12 @@ exports[`createOfficeTheme test 1`] = ` "neutralBackground5Pressed": "#f0f0f0", "neutralBackground5Selected": "#fafafa", "neutralBackground6": "#e6e6e6", + "neutralBackgroundCanvas": "#ffffff", + "neutralBackgroundDarkStatic": "#242424", "neutralBackgroundDisabled": "#E6E6E6", "neutralBackgroundInverted": "#737373", + "neutralBackgroundLightStatic": "#ffffff", + "neutralBackgroundLightStaticDisabled": "#f0f0f0", "neutralForeground1": "#262626", "neutralForeground1Hover": "#262626", "neutralForeground1Pressed": "#262626", @@ -2625,16 +2643,21 @@ exports[`createOfficeTheme test 1`] = ` "neutralForeground3Pressed": "#424242", "neutralForeground3Selected": "#424242", "neutralForeground4": "#666666", + "neutralForegroundDarkStatic": "#000000", "neutralForegroundDisabled": "#B1B1B1", + "neutralForegroundDisabled1": "#bdbdbd", + "neutralForegroundDisabled2": "#bdbdbd", "neutralForegroundInverted": "#ffffff", "neutralForegroundInvertedLink": "#FFFFFF", "neutralForegroundInvertedLinkHover": "#D2D2D2", "neutralForegroundInvertedLinkPressed": "#B1B1B1", "neutralForegroundInvertedLinkSelected": "#ffffff", + "neutralForegroundLightStatic": "#ffffff", "neutralForegroundOnBrand": "#FFFFFF", "neutralForegroundOnBrandHover": "#FFFFFF", "neutralForegroundOnBrandPressed": "#FFFFFF", "neutralForegroundOnBrandSelected": "#ffffff", + "neutralForegroundOnColor": "#ffffff", "neutralStencil1": "#262626", "neutralStencil2": "#fafafa", "neutralStroke1": "#969696", @@ -2648,6 +2671,8 @@ exports[`createOfficeTheme test 1`] = ` "neutralStrokeAccessiblePressed": "#737373", "neutralStrokeAccessibleSelected": "#185abd", "neutralStrokeDisabled": "#D2D2D2", + "neutralStrokeFocus1": "#ffffff", + "neutralStrokeFocus2": "#000000", "outofofficeBackground1": "#fdf5fc", "outofofficeBackground2": "#edbbe7", "outofofficeBackground3": "#c239b3", @@ -2659,6 +2684,10 @@ exports[`createOfficeTheme test 1`] = ` "outofofficeForeground3": "#c239b3", "personaActivityGlow": "#185abd", "personaActivityRing": "#ffffff", + "presenceAvailable": "#0e700e", + "presenceAway": "#817400", + "presenceDnd": "#bc2f32", + "presenceOof": "#af33a1", "primaryButtonBackground": "#D83B01", "primaryButtonBackgroundDisabled": "#E6E6E6", "primaryButtonBackgroundHovered": "#F29F71", @@ -2669,6 +2698,15 @@ exports[`createOfficeTheme test 1`] = ` "primaryButtonTextDisabled": "#B1B1B1", "primaryButtonTextHovered": "#FFFFFF", "primaryButtonTextPressed": "#FFFFFF", + "redBackground1": "#fdf6f6", + "redBackground2": "#f1bbbc", + "redBackground3": "#d13438", + "redBorder1": "#f1bbbc", + "redBorder2": "#d13438", + "redBorderActive": "#d13438", + "redForeground1": "#bc2f32", + "redForeground2": "#751d1f", + "redForeground3": "#d13438", "severeBackground1": "#fdf6f3", "severeBackground2": "#f4bfab", "severeBackground3": "#da3b01", @@ -2678,6 +2716,7 @@ exports[`createOfficeTheme test 1`] = ` "severeForeground1": "#c43501", "severeForeground2": "#7a2101", "severeForeground3": "#da3b01", + "severeStroke1": "#f4bfab", "strokeFocus1": "#ffffff", "strokeFocus2": "#969696", "subText": "#666666", @@ -2695,6 +2734,7 @@ exports[`createOfficeTheme test 1`] = ` "successForeground2": "#094509", "successForeground3": "#107c10", "successForegroundInverted": "#359b35", + "successStroke1": "#9fd89f", "transparentBackground": "#00000000", "transparentBackgroundHover": "#00000000", "transparentBackgroundPressed": "#00000000", @@ -2713,6 +2753,7 @@ exports[`createOfficeTheme test 1`] = ` "warningForeground2": "#817400", "warningForeground3": "#fde300", "warningForegroundInverted": "#fef7b2", + "warningStroke1": "#fef7b2", }, "host": { "appearance": "light", @@ -3108,8 +3149,13 @@ exports[`createOfficeTheme test 1`] = ` }, "caption1Strong": { "face": "primary", - "size": "caption", - "weight": "semiBold", + "size": 10, + "weight": "600", + }, + "caption2": { + "face": "primary", + "size": 10, + "weight": "400", }, "captionStandard": { "face": "primary", @@ -3206,6 +3252,16 @@ exports[`createOfficeTheme test 1`] = ` "size": 28, "weight": "600", }, + "title2": { + "face": "primary", + "size": 20, + "weight": "400", + }, + "title3": { + "face": "primary", + "size": 16, + "weight": "400", + }, }, "weights": { "regular": "400", diff --git a/yarn.lock b/yarn.lock index 5e6872b3ec..cf1f587433 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2966,7 +2966,6 @@ __metadata: dependencies: "@babel/core": "catalog:" "@fluentui-react-native/design": "workspace:*" - "@fluentui-react-native/framework-base": "workspace:*" "@fluentui-react-native/scripts": "workspace:*" "@office-iss/react-native-win32": "npm:^0.81.8" "@react-native-community/cli": "npm:^20.0.0" @@ -2975,7 +2974,6 @@ __metadata: "@react-native/babel-preset": "npm:^0.81.0" "@react-native/metro-config": "npm:^0.81.0" "@types/react": "npm:~19.1.4" - assert-never: "npm:^1.2.1" react: "npm:19.1.4" react-native: "npm:^0.81.6" react-native-macos: "npm:^0.81.0" From 46305a22854f6e496a82e7d98a0aa6f55021c31b Mon Sep 17 00:00:00 2001 From: Jason Morse <jasonmo360@gmail.com> Date: Mon, 2 Nov 2026 11:38:37 -0800 Subject: [PATCH 17/18] design: move Fluent 2 token JSON consumers behind a deprecated entry point Move the Fluent 2 token loaders and pipeline mappers into src/deprecated, exposed as @fluentui-react-native/design/deprecated. Only tests and other deprecated code may import it (R-DESIGN-003, enforced by the design import-boundary test). Remove the legacy default theme, its stock web palettes, and the tokens/legacy and theming/compat/defaults entry points, which had no in-repository consumers. themeFromFlexTokens now uses the generated Fluent theme for the appearance as its base, so the theming entry point no longer bundles the token JSON. Repoint the android, apple, and win32 themes, the theme-tokens and theming-utils shims, and the tester at the deprecated entry point. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/design-deprecated-entry-point.md | 12 + .../theming-design-deprecated-imports.md | 10 + apps/bundle-size/baseline.json | 104 +++--- apps/bundle-size/scenarios.json | 27 +- .../ColorTokens/ColorTokenTest.tsx | 2 +- packages/agentic/design/AGENTS.md | 5 +- packages/agentic/design/package.json | 18 +- .../agentic/design/references/contributing.md | 24 +- .../agentic/design/references/entry-points.md | 92 ++--- .../design/references/remaining-work.md | 20 +- packages/agentic/design/references/theming.md | 23 +- packages/agentic/design/references/tokens.md | 14 +- .../agentic/design/scripts/fluent-tokens.cts | 8 +- .../__snapshots__/mapPipeline.test.ts.snap} | 0 .../deprecated/__tests__/mapPipeline.test.ts | 57 ++++ .../agentic/design/src/deprecated/index.ts | 5 + .../mapPipelineToShadow.ts | 2 +- .../mapPipelineToTheme.android.ts | 4 +- .../mapPipelineToTheme.ios.ts | 6 +- .../mapPipelineToTheme.ts | 4 +- .../tokens/getTokens.android.ts | 2 +- .../tokens/getTokens.ios.ts | 2 +- .../tokens/getTokens.ts | 2 +- .../__tests__/processAliasTokens.test.ts | 0 .../tokens/highContrast/processAliasTokens.ts | 0 .../tokens/highContrast/tokens-alias.ts | 0 .../tokens/highContrast/tokens-alias.win32.ts | 0 .../tokens/tokens-global.android.ts | 0 .../tokens/tokens-global.ios.ts | 0 .../tokens/tokens-global.ts | 0 .../tokens/tokens-global.win32.ts | 0 .../fluent/__tests__/theming-utils.test.ts | 57 ---- .../__tests__/defaultLegacyTheme.test.ios.ts | 20 -- .../fluent/compat/createLegacyAliasTokens.ts | 20 -- .../src/fluent/compat/defaultLegacyColors.ts | 315 ------------------ .../fluent/compat/defaultLegacyTheme.test.ts | 70 ---- .../src/fluent/compat/defaultLegacyTheme.ts | 135 -------- .../agentic/design/src/fluent/compat/index.ts | 1 - .../fluent/compat/stockWebPalette.macos.ts | 79 ----- .../src/fluent/compat/stockWebPalette.ts | 100 ------ .../fluent/compat/stockWebPalette.win32.ts | 79 ----- .../fluent/compat/themeFromFlexTokens.test.ts | 37 +- .../src/fluent/compat/themeFromFlexTokens.ts | 19 +- .../src/fluent/defaults/fluentTokens.test.ts | 10 +- .../agentic/design/src/fluent/tokens/index.ts | 3 - .../compatibilityBaseline.test.ts.snap | 82 ++--- .../__snapshots__/entryPoints.test.ts.snap | 31 +- .../compatibilityBaseline.test.ts | 10 +- .../test/compatibility/entryPoints.test.ts | 3 +- .../compatibility/entryPoints.types.test.ts | 20 +- .../compatibility/importBoundaries.test.ts | 60 +++- .../design/src/themes/fluent/fluentTheme.ts | 15 +- .../src/themes/fluent/fluentThemes.test.tsx | 20 +- .../src/themes/fluent/selectFluentTheme.ts | 18 + packages/agentic/design/src/theming/index.ts | 2 - packages/shim/theme-tokens/README.md | 8 +- packages/shim/theme-tokens/src/index.ts | 4 +- packages/shim/theming-utils/README.md | 7 +- packages/shim/theming-utils/src/index.ts | 15 +- .../android-theme/src/createAliasTokens.ts | 3 +- .../src/createFontAliasTokens.ts | 3 +- .../src/createFontAliasTokens.ios.ts | 2 +- .../apple-theme/src/createMacOSAliasTokens.ts | 2 +- .../apple-theme/src/createiOSAliasTokens.ts | 3 +- .../src/createBrandedThemeWithAlias.ts | 2 +- .../win32-theme/src/createFontAliasTokens.ts | 2 +- .../src/createOfficeAliasTokens.ts | 2 +- .../win32-theme/src/getOfficeTokens.ts | 2 +- 68 files changed, 506 insertions(+), 1198 deletions(-) create mode 100644 .changeset/design-deprecated-entry-point.md create mode 100644 .changeset/theming-design-deprecated-imports.md rename packages/agentic/design/src/{fluent/__tests__/__snapshots__/theming-utils.test.ts.snap => deprecated/__tests__/__snapshots__/mapPipeline.test.ts.snap} (100%) create mode 100644 packages/agentic/design/src/deprecated/__tests__/mapPipeline.test.ts create mode 100644 packages/agentic/design/src/deprecated/index.ts rename packages/agentic/design/src/{fluent => deprecated}/mapPipelineToShadow.ts (95%) rename packages/agentic/design/src/{fluent => deprecated}/mapPipelineToTheme.android.ts (98%) rename packages/agentic/design/src/{fluent => deprecated}/mapPipelineToTheme.ios.ts (97%) rename packages/agentic/design/src/{fluent => deprecated}/mapPipelineToTheme.ts (98%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/getTokens.android.ts (94%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/getTokens.ios.ts (95%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/getTokens.ts (94%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/highContrast/__tests__/processAliasTokens.test.ts (100%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/highContrast/processAliasTokens.ts (100%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/highContrast/tokens-alias.ts (100%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/highContrast/tokens-alias.win32.ts (100%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/tokens-global.android.ts (100%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/tokens-global.ios.ts (100%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/tokens-global.ts (100%) rename packages/agentic/design/src/{fluent => deprecated}/tokens/tokens-global.win32.ts (100%) delete mode 100644 packages/agentic/design/src/fluent/compat/__tests__/defaultLegacyTheme.test.ios.ts delete mode 100644 packages/agentic/design/src/fluent/compat/createLegacyAliasTokens.ts delete mode 100644 packages/agentic/design/src/fluent/compat/defaultLegacyColors.ts delete mode 100644 packages/agentic/design/src/fluent/compat/defaultLegacyTheme.test.ts delete mode 100644 packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts delete mode 100644 packages/agentic/design/src/fluent/compat/stockWebPalette.macos.ts delete mode 100644 packages/agentic/design/src/fluent/compat/stockWebPalette.ts delete mode 100644 packages/agentic/design/src/fluent/compat/stockWebPalette.win32.ts delete mode 100644 packages/agentic/design/src/fluent/tokens/index.ts create mode 100644 packages/agentic/design/src/themes/fluent/selectFluentTheme.ts diff --git a/.changeset/design-deprecated-entry-point.md b/.changeset/design-deprecated-entry-point.md new file mode 100644 index 0000000000..32092eacea --- /dev/null +++ b/.changeset/design-deprecated-entry-point.md @@ -0,0 +1,12 @@ +--- +'@fluentui-react-native/design': minor +--- + +Breaking: move every module that loads the Fluent 2 token JSON into a new `@fluentui-react-native/design/deprecated` +entry point, reserved for tests and the existing platform themes. It exports `getAliasTokens`, `getShadowTokens`, +`globalTokens`, `hcAliasTokens`, `mapPipelineToTheme`, `mapFontPipelineToTheme`, and `mapPipelineToShadow`. The +`theming` entry point no longer exports the pipeline mappers, and the `tokens/legacy` and `theming/compat/defaults` +entry points and `getDefaultLegacyTheme` are removed; use the Fluent themes from `@fluentui-react-native/design/themes` +for complete default themes. `themeFromFlexTokens` now fills the values Flex cannot represent from the generated Fluent +theme for the appearance instead of the removed legacy defaults, so the `theming` entry point no longer bundles the +token JSON. diff --git a/.changeset/theming-design-deprecated-imports.md b/.changeset/theming-design-deprecated-imports.md new file mode 100644 index 0000000000..0d7013966f --- /dev/null +++ b/.changeset/theming-design-deprecated-imports.md @@ -0,0 +1,10 @@ +--- +'@fluentui-react-native/android-theme': patch +'@fluentui-react-native/apple-theme': patch +'@fluentui-react-native/win32-theme': patch +'@fluentui-react-native/theme-tokens': patch +'@fluentui-react-native/theming-utils': patch +--- + +Import the Fluent 2 token loaders and pipeline mappers from `@fluentui-react-native/design/deprecated`. Theme values and +the shims' exports are unchanged. diff --git a/apps/bundle-size/baseline.json b/apps/bundle-size/baseline.json index 8dbb042906..7eae7325d2 100644 --- a/apps/bundle-size/baseline.json +++ b/apps/bundle-size/baseline.json @@ -104,33 +104,33 @@ { "platform": "macos", "scenario": "design-legacy-theme", - "rawBytes": 79069, - "gzipBytes": 17346, - "moduleCount": 54, - "metafileInputCount": 93, + "rawBytes": 39106, + "gzipBytes": 9004, + "moduleCount": 42, + "metafileInputCount": 82, "workspaceModules": { - "@fluentui-react-native/design": 24, - "@fluentui-react-native/framework-base": 21 + "@fluentui-react-native/design": 23, + "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 39865, - "@fluentui-react-native/framework-base": 2517 + "@fluentui-react-native/design": 37097, + "@fluentui-react-native/framework-base": 1967 } }, { "platform": "macos", "scenario": "design-legacy-theme-from-flex", - "rawBytes": 99833, - "gzipBytes": 24406, - "moduleCount": 67, - "metafileInputCount": 93, + "rawBytes": 59872, + "gzipBytes": 16095, + "moduleCount": 54, + "metafileInputCount": 82, "workspaceModules": { - "@fluentui-react-native/design": 37, - "@fluentui-react-native/framework-base": 21 + "@fluentui-react-native/design": 35, + "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 60615, - "@fluentui-react-native/framework-base": 2527 + "@fluentui-react-native/design": 57863, + "@fluentui-react-native/framework-base": 1967 } }, { @@ -139,7 +139,7 @@ "rawBytes": 18739, "gzipBytes": 4009, "moduleCount": 7, - "metafileInputCount": 67, + "metafileInputCount": 68, "workspaceModules": { "@fluentui-react-native/design": 6 }, @@ -150,16 +150,16 @@ { "platform": "macos", "scenario": "design-fluent-theme", - "rawBytes": 27436, - "gzipBytes": 6730, - "moduleCount": 34, - "metafileInputCount": 67, + "rawBytes": 27455, + "gzipBytes": 6743, + "moduleCount": 35, + "metafileInputCount": 68, "workspaceModules": { - "@fluentui-react-native/design": 15, + "@fluentui-react-native/design": 16, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 25427, + "@fluentui-react-native/design": 25446, "@fluentui-react-native/framework-base": 1973 } }, @@ -169,7 +169,7 @@ "rawBytes": 27343, "gzipBytes": 6694, "moduleCount": 32, - "metafileInputCount": 67, + "metafileInputCount": 68, "workspaceModules": { "@fluentui-react-native/design": 13, "@fluentui-react-native/framework-base": 18 @@ -185,7 +185,7 @@ "rawBytes": 23368, "gzipBytes": 8032, "moduleCount": 33, - "metafileInputCount": 67, + "metafileInputCount": 68, "workspaceModules": { "@fluentui-react-native/design": 16, "@fluentui-react-native/framework-base": 16 @@ -201,7 +201,7 @@ "rawBytes": 23432, "gzipBytes": 8064, "moduleCount": 33, - "metafileInputCount": 67, + "metafileInputCount": 68, "workspaceModules": { "@fluentui-react-native/design": 16, "@fluentui-react-native/framework-base": 16 @@ -314,33 +314,33 @@ { "platform": "windows", "scenario": "design-legacy-theme", - "rawBytes": 78948, - "gzipBytes": 17286, - "moduleCount": 54, - "metafileInputCount": 94, + "rawBytes": 42907, + "gzipBytes": 9653, + "moduleCount": 42, + "metafileInputCount": 83, "workspaceModules": { - "@fluentui-react-native/design": 24, - "@fluentui-react-native/framework-base": 21 + "@fluentui-react-native/design": 23, + "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 39745, - "@fluentui-react-native/framework-base": 2517 + "@fluentui-react-native/design": 40895, + "@fluentui-react-native/framework-base": 1970 } }, { "platform": "windows", "scenario": "design-legacy-theme-from-flex", - "rawBytes": 99696, - "gzipBytes": 24337, - "moduleCount": 67, - "metafileInputCount": 94, + "rawBytes": 63686, + "gzipBytes": 16781, + "moduleCount": 54, + "metafileInputCount": 83, "workspaceModules": { - "@fluentui-react-native/design": 37, - "@fluentui-react-native/framework-base": 21 + "@fluentui-react-native/design": 35, + "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 60478, - "@fluentui-react-native/framework-base": 2527 + "@fluentui-react-native/design": 61677, + "@fluentui-react-native/framework-base": 1967 } }, { @@ -349,7 +349,7 @@ "rawBytes": 22592, "gzipBytes": 4610, "moduleCount": 7, - "metafileInputCount": 68, + "metafileInputCount": 69, "workspaceModules": { "@fluentui-react-native/design": 6 }, @@ -360,16 +360,16 @@ { "platform": "windows", "scenario": "design-fluent-theme", - "rawBytes": 31229, - "gzipBytes": 7311, - "moduleCount": 34, - "metafileInputCount": 68, + "rawBytes": 31248, + "gzipBytes": 7323, + "moduleCount": 35, + "metafileInputCount": 69, "workspaceModules": { - "@fluentui-react-native/design": 15, + "@fluentui-react-native/design": 16, "@fluentui-react-native/framework-base": 18 }, "workspaceBytes": { - "@fluentui-react-native/design": 29208, + "@fluentui-react-native/design": 29227, "@fluentui-react-native/framework-base": 1985 } }, @@ -379,7 +379,7 @@ "rawBytes": 31131, "gzipBytes": 7279, "moduleCount": 32, - "metafileInputCount": 68, + "metafileInputCount": 69, "workspaceModules": { "@fluentui-react-native/design": 13, "@fluentui-react-native/framework-base": 18 @@ -395,7 +395,7 @@ "rawBytes": 23356, "gzipBytes": 8025, "moduleCount": 33, - "metafileInputCount": 68, + "metafileInputCount": 69, "workspaceModules": { "@fluentui-react-native/design": 16, "@fluentui-react-native/framework-base": 16 @@ -411,7 +411,7 @@ "rawBytes": 23420, "gzipBytes": 8058, "moduleCount": 33, - "metafileInputCount": 68, + "metafileInputCount": 69, "workspaceModules": { "@fluentui-react-native/design": 16, "@fluentui-react-native/framework-base": 16 diff --git a/apps/bundle-size/scenarios.json b/apps/bundle-size/scenarios.json index b6bb2418bf..2ad4fd7240 100644 --- a/apps/bundle-size/scenarios.json +++ b/apps/bundle-size/scenarios.json @@ -15,7 +15,7 @@ "name": "design-theme-state", "module": "@fluentui-react-native/design", "exports": ["FlexThemeReference", "ThemeProvider", "useThemeState"], - "forbiddenInputPatterns": ["/design/src/fluent/", "/design/src/test/", "/color-lib/compositing."], + "forbiddenInputPatterns": ["/design/src/fluent/", "/design/src/deprecated/", "/design/src/test/", "/color-lib/compositing."], "requiredInputPatterns": [ "/design/src/flex/flexThemeReference.", "/design/src/flex/useThemeState.", @@ -27,7 +27,7 @@ "name": "design-themed-root", "module": "@fluentui-react-native/design", "exports": ["ThemedRoot", "useRootSettings", "useThemeState"], - "forbiddenInputPatterns": ["/design/src/fluent/", "/design/src/test/", "/color-lib/compositing."], + "forbiddenInputPatterns": ["/design/src/fluent/", "/design/src/deprecated/", "/design/src/test/", "/color-lib/compositing."], "requiredInputPatterns": ["/design/src/flex/useThemeState.", "/design/src/theming/ThemedRoot."], "requiredOutputPatterns": ["/color-lib/interaction.", "/design/src/flex/colors/interactionPolicy."] }, @@ -49,12 +49,7 @@ "exports": ["ThemeReference"] } ], - "forbiddenInputPatterns": [ - "/design/src/fluent/compat/", - "/design/src/fluent/tokens/", - "/design/src/test/", - "/color-lib/compositing." - ], + "forbiddenInputPatterns": ["/design/src/fluent/compat/", "/design/src/deprecated/", "/design/src/test/", "/color-lib/compositing."], "requiredInputPatterns": ["/design/src/fluent/themeReference."], "forbiddenOutputPatterns": ["/design/src/flex/flexThemeReference."], "requiredOutputPatterns": ["/color-lib/interaction.", "/design/src/flex/colors/interactionPolicy."] @@ -63,7 +58,7 @@ "name": "design-legacy-theme", "module": "@fluentui-react-native/design/theming", "exports": ["ThemeProvider", "ThemeReference", "useTheme"], - "forbiddenInputPatterns": ["/design/src/test/"], + "forbiddenInputPatterns": ["/design/src/deprecated/", "/design/src/test/"], "requiredInputPatterns": ["/design/src/theming/ThemeProvider."], "forbiddenOutputPatterns": ["/color-lib/", "/design/src/flex/"], "requiredOutputPatterns": ["/design/src/fluent/themeReference.", "/design/src/fluent/useTheme."] @@ -72,9 +67,11 @@ "name": "design-legacy-theme-from-flex", "module": "@fluentui-react-native/design/theming", "exports": ["FlexThemeReference", "ThemeProvider", "useTheme"], + "forbiddenInputPatterns": ["/design/src/deprecated/", "/design/src/test/"], "requiredInputPatterns": [ "/design/src/fluent/compat/themeFromFlexTokens.", - "/design/src/fluent/tokens/", + "/design/src/themes/fluent/selectFluentTheme.", + "/design/src/fluent/defaults/fluentTokens.generated.", "/design/src/fluent/useTheme." ] }, @@ -84,7 +81,7 @@ "exports": ["fluentLightTheme"], "forbiddenInputPatterns": [ "/design/src/fluent/compat/", - "/design/src/fluent/tokens/", + "/design/src/deprecated/", "/design/src/fluent/useTheme.", "/design/src/test/" ], @@ -106,7 +103,7 @@ "exports": ["fluentTheme"], "forbiddenInputPatterns": [ "/design/src/fluent/compat/", - "/design/src/fluent/tokens/", + "/design/src/deprecated/", "/design/src/fluent/useTheme.", "/design/src/test/" ], @@ -126,7 +123,7 @@ "exports": ["fluentHcTheme"], "forbiddenInputPatterns": [ "/design/src/fluent/compat/", - "/design/src/fluent/tokens/", + "/design/src/deprecated/", "/design/src/fluent/useTheme.", "/design/src/test/" ], @@ -151,7 +148,7 @@ "exports": ["flexTheme"], "forbiddenInputPatterns": [ "/design/src/fluent/compat/", - "/design/src/fluent/tokens/", + "/design/src/deprecated/", "/design/src/fluent/useTheme.", "/design/src/test/", "/color-lib/compositing." @@ -166,7 +163,7 @@ "exports": ["flexWarmTheme"], "forbiddenInputPatterns": [ "/design/src/fluent/compat/", - "/design/src/fluent/tokens/", + "/design/src/deprecated/", "/design/src/fluent/useTheme.", "/design/src/test/", "/color-lib/compositing." diff --git a/apps/tester-core/src/TestComponents/ColorTokens/ColorTokenTest.tsx b/apps/tester-core/src/TestComponents/ColorTokens/ColorTokenTest.tsx index e0501bb8b3..aaef09d932 100644 --- a/apps/tester-core/src/TestComponents/ColorTokens/ColorTokenTest.tsx +++ b/apps/tester-core/src/TestComponents/ColorTokens/ColorTokenTest.tsx @@ -5,7 +5,7 @@ import { View, StyleSheet, Platform } from 'react-native'; import { Text, ToggleButton } from '@fluentui/react-native'; import { COLORTOKENS_TEST_COMPONENT, COLORTOKEN_TESTPAGE } from '@fluentui-react-native/e2e-testing'; import type { SvgIconProps } from '@fluentui-react-native/icon'; -import { globalTokens } from '@fluentui-react-native/design/tokens/legacy'; +import { globalTokens } from '@fluentui-react-native/design/deprecated'; import type { Theme } from '@fluentui-react-native/design/theming'; import { useTheme } from '@fluentui-react-native/design/theming'; import { themedStyleSheet } from '@fluentui-react-native/design/styling/stylesheet'; diff --git a/packages/agentic/design/AGENTS.md b/packages/agentic/design/AGENTS.md index 32bcdf67c3..190617829c 100644 --- a/packages/agentic/design/AGENTS.md +++ b/packages/agentic/design/AGENTS.md @@ -29,7 +29,7 @@ repository reference `components.agentic.styles-and-tokens`. models, and neither hook constructs the model it does not return. - Key caches by source, revision, and resolved appearance, keep them outside author-owned objects, and give every new `ThemeState` a new style registry. -- Keep the root entry point free of the legacy projection, legacy token payloads, and color compositing; it reaches +- Keep the root entry point free of the legacy projection, deprecated token data, and color compositing; it reaches the color library's interaction algorithm only through the Flex interaction policy. Legacy and optional APIs stay behind their subpaths. - Keep color resolution lazy: resolving, merging, and reading rest never run the interaction algorithm, and a derived @@ -37,6 +37,9 @@ repository reference `components.agentic.styles-and-tokens`. - Treat `src/tokens/mappings/flex-token-map.yaml` as the canonical token mapping (R-DESIGN-001), and regenerate rather than edit generated token and projection files. - Production code must not depend on the `testing` entry point (R-DESIGN-002). +- Keep the Fluent 2 token JSON loaders and pipeline mappers in `src/deprecated/`. Only tests, other deprecated code, + build scripts, and the existing deprecated consumers may use them, and no other entry point may reach them + (R-DESIGN-003). - Update the owning reference with every behavior or API change, and record unfinished work only in `references/remaining-work.md` (R-PKGDOC-009). diff --git a/packages/agentic/design/package.json b/packages/agentic/design/package.json index 9c4491305e..ec0a23be81 100644 --- a/packages/agentic/design/package.json +++ b/packages/agentic/design/package.json @@ -39,12 +39,6 @@ "import": "./lib/tokens/global.generated.js", "default": "./src/tokens/global.generated.ts" }, - "./tokens/legacy": { - "types": "./lib/fluent/tokens/index.d.ts", - "react-native": "./src/fluent/tokens/index.ts", - "import": "./lib/fluent/tokens/index.js", - "default": "./src/fluent/tokens/index.ts" - }, "./color-lib": { "types": "./lib/color-lib/index.d.ts", "react-native": "./src/color-lib/index.ts", @@ -69,12 +63,6 @@ "import": "./lib/fluent/compat/index.js", "default": "./src/fluent/compat/index.ts" }, - "./theming/compat/defaults": { - "types": "./lib/fluent/compat/defaultLegacyTheme.d.ts", - "react-native": "./src/fluent/compat/defaultLegacyTheme.ts", - "import": "./lib/fluent/compat/defaultLegacyTheme.js", - "default": "./src/fluent/compat/defaultLegacyTheme.ts" - }, "./themes": { "types": "./lib/themes/index.d.ts", "react-native": "./src/themes/index.ts", @@ -87,6 +75,12 @@ "import": "./lib/test/index.js", "default": "./src/test/index.ts" }, + "./deprecated": { + "types": "./lib/deprecated/index.d.ts", + "react-native": "./src/deprecated/index.ts", + "import": "./lib/deprecated/index.js", + "default": "./src/deprecated/index.ts" + }, "./styling": { "types": "./lib/styling/index.d.ts", "react-native": "./src/styling/index.ts", diff --git a/packages/agentic/design/references/contributing.md b/packages/agentic/design/references/contributing.md index f3084f15b9..09d0fb9dc4 100644 --- a/packages/agentic/design/references/contributing.md +++ b/packages/agentic/design/references/contributing.md @@ -18,25 +18,27 @@ owner_paths: | `src/flex/adapters/` | The engine-free Theme-to-Flex adapter and its Fluent-native fallbacks | | `src/flex/colors/` | Authored color normalization, the resolved color envelope, token classification, and the interaction policy | | `src/fluent/` | Legacy Fluent theme types, `ThemeReference`, `useTheme`, platform utilities, and legacy styling | -| `src/fluent/compat/` | The Flex-to-legacy projection and complete legacy defaults; never reachable from the root | -| `src/fluent/tokens/` | Legacy alias, shadow, and global token data | +| `src/fluent/compat/` | The Flex-to-legacy projection onto the Fluent themes; never reachable from the root | | `src/themes/` | Ready-made Fluent themes from the generated Fluent 2 tokens and Flex themes from the x3 defaults | | `src/tokens/` | Generated global tokens and shared token attributes | | `src/tokens/mappings/` | The canonical token map and its generated projections; see `tokens.md` | | `src/styling/` | Shared state style factories and the `styling` facade; see `styling.md` | | `src/color-lib/` | Raw, token-free color algorithms; see `color-lib.md` | +| `src/deprecated/` | Fluent 2 token JSON loaders and pipeline mappers behind `./deprecated`; see `entry-points.md` | | `src/test/` | Test-only fixtures, compatibility baselines, and color validation; see `testing.md` | | `src/index.ts` | The modern root entry point; see `entry-points.md` for every subpath | Shared modules may import types from either model. At runtime, only the `theming` facade, the `themes` entry, and the legacy subpaths reach `src/fluent/`; the root and `styling` graphs may reach `src/flex/` but never `src/fluent/`. Dependencies point one way: `src/flex/colors/` may import `src/color-lib/`, but `src/color-lib/` imports only its own -modules and shared types. Production code never imports `src/test/`. Source paths are private: consumers use the package -subpaths in `entry-points.md`, never `src/` or `lib/` paths. +modules and shared types. Production code never imports `src/test/`, and only `src/deprecated/` imports the Fluent 2 +token JSON packages. Source paths are private: consumers use the package subpaths in `entry-points.md`, never `src/` or +`lib/` paths. -The package's scripts directory holds `codegen.cts`, which runs before every build, the token-mapping check and -upstream drift tools, and the x3 defaults generator, all described in `tokens.md`. Generated token, projection, and -default files are committed; change their inputs and regenerate rather than editing them. +The package's scripts directory holds `codegen.cts`, which runs before every build, the token-mapping check and upstream +drift tools, and the x3 defaults generator, all described in `tokens.md`. The Fluent token generator applies the +deprecated pipeline mappers from `src/deprecated/` at build time. Generated token, projection, and default files are +committed; change their inputs and regenerate rather than editing them. ## Invariants @@ -48,7 +50,7 @@ default files are committed; change their inputs and regenerate rather than edit run the bundle-size scenarios too when changing imports between these areas. - Keep `src/themes/` a consumer of generated tokens. `src/themes/fluent/` may reach `ThemeReference`, the generated Fluent tokens, and the generated global tokens, but never `src/flex/`, `src/color-lib/`, `useTheme`, - `src/fluent/compat/`, or the legacy token payloads, and it authors no color value that the generated alias colors lack. + `src/fluent/compat/`, or `src/deprecated/`, and it authors no color value that the generated alias colors lack. `src/themes/flex/` exposes the x3 default descriptions unchanged and never reaches `src/fluent/` or `color-lib/compositing`. The tests under `src/themes/`, the import-boundary test, and the `design-fluent-*` and `design-flex-*` bundle-size scenarios guard this. @@ -60,11 +62,13 @@ default files are committed; change their inputs and regenerate rather than edit - Keep the experimental native appearance modules and platform theme packages out of this package's dependencies; platform theme packages inject their sources. - Production code must not import the `testing` entry point (R-DESIGN-002). +- Keep the Fluent 2 token JSON behind `src/deprecated/`: only tests, other deprecated modules, build scripts, and the + existing deprecated consumers may use it, and no other production entry point may reach it (R-DESIGN-003). ## Tests -Jest runs with the macOS platform preset declared in `package.json`. A test named `*.test.<platform>.ts`, such as -`defaultLegacyTheme.test.ios.ts`, runs under that platform, so add one when a platform implementation file changes. +Jest runs with the macOS platform preset declared in `package.json`. A test named `*.test.<platform>.ts` runs under +that platform, so add one when a platform implementation file changes. Iterate with a focused selection, such as `yarn test themeRuntime` or `yarn test --findRelatedTests src/theming/appearance.ts`. `src/test/compatibility/` holds the public-surface, legacy-runtime, and import-boundary baselines; update their snapshots only for an intended compatibility change. diff --git a/packages/agentic/design/references/entry-points.md b/packages/agentic/design/references/entry-points.md index d3d680cedc..df9c54bc7f 100644 --- a/packages/agentic/design/references/entry-points.md +++ b/packages/agentic/design/references/entry-points.md @@ -10,54 +10,70 @@ owner_paths: The package is `sideEffects: false` and exposes explicit subpaths so consumers load only the graph they use. Export public symbols by name from each entry point; do not add barrel re-exports. -| Subpath | Contents | -| --------------------------- | -------------------------------------------------------------------------------------------------------------------------- | -| `.` (root) | Modern theming (`ThemeProvider`, `ThemedRoot`, `FlexThemeReference`, hooks), Flex token types | -| `./theming` | The complete modern and legacy theming API, including `ThemeReference` and `useTheme` | -| `./theming/legacy-source` | `ThemeReference` without the legacy consumption graph | -| `./theming/compat` | `themeFromFlexTokens` and `getDefaultLegacyTheme` | -| `./theming/compat/defaults` | `getDefaultLegacyTheme` alone, for platform theme packages | -| `./themes` | Ready-made themes: `fluentLightTheme`, `fluentDarkTheme`, `fluentHcTheme`, `fluentTheme`, `flexTheme`, and `flexWarmTheme` | -| `./tokens/global` | Generated platform global token constants | -| `./tokens/legacy` | Legacy alias, shadow, and global token data | -| `./color-lib` | Raw color parsing, conversion, compositing, and interaction algorithms; see `color-lib.md` | -| `./styling` | State and color style factories; see `styling.md` | -| `./styling/stylesheet` | The legacy `themedStyleSheet` helper | -| `./styling/tokens` | Legacy token-to-style builders | -| `./testing` | Test-only fixtures and validation; see `testing.md` | +| Subpath | Contents | +| ------------------------- | -------------------------------------------------------------------------------------------------------------------------- | +| `.` (root) | Modern theming (`ThemeProvider`, `ThemedRoot`, `FlexThemeReference`, hooks), Flex token types | +| `./theming` | The complete modern and legacy theming API, including `ThemeReference` and `useTheme` | +| `./theming/legacy-source` | `ThemeReference` without the legacy consumption graph | +| `./theming/compat` | `themeFromFlexTokens`, which projects Flex tokens onto the Fluent theme for the appearance | +| `./themes` | Ready-made themes: `fluentLightTheme`, `fluentDarkTheme`, `fluentHcTheme`, `fluentTheme`, `flexTheme`, and `flexWarmTheme` | +| `./tokens/global` | Generated platform global token constants | +| `./color-lib` | Raw color parsing, conversion, compositing, and interaction algorithms; see `color-lib.md` | +| `./styling` | State and color style factories; see `styling.md` | +| `./styling/stylesheet` | The legacy `themedStyleSheet` helper | +| `./styling/tokens` | Legacy token-to-style builders | +| `./testing` | Test-only fixtures and validation; see `testing.md` | +| `./deprecated` | Fluent 2 token JSON loaders and pipeline mappers, restricted to existing consumers; see [below](#deprecated-entry-point) | The `apps/bundle-size` `design-*` scenarios guard these boundaries. Input patterns check the import graph and output -patterns check the modules a tree-shaken bundle retains. The modern root and legacy-source scenarios forbid the -compatibility and legacy-token modules and `color-lib/compositing`. The modern root scenarios and the legacy-source -scenario, which pairs a legacy `ThemeReference` with `useThemeState`, require the retained Flex interaction policy and -`color-lib/interaction`; the legacy-source scenario also forbids a retained `FlexThemeReference`. Only the legacy theme -scenario forbids any retained `color-lib/` or `flex/` module. The Fluent theme scenarios forbid `useTheme` and the -compatibility and legacy-token modules from the import graph and any retained `flex/`, `color-lib/`, or Flex theme -module, and a bundle that imports only `fluentLightTheme` retains no other theme and no `ThemeReference`, while one that -imports only `fluentHcTheme` retains only the high-contrast themes. The Flex -theme scenarios require the x3 defaults and forbid `fluent/` and `color-lib/compositing`. The color-library and -legacy-projection scenarios require their expected modules. Every scenario also requires a module it is expected to load, -so a moved file cannot make a forbidden pattern pass vacuously. +patterns check the modules a tree-shaken bundle retains. Every design scenario except the color-library one forbids +`src/deprecated/` from the import graph. The modern root and legacy-source scenarios forbid the compatibility modules +and `color-lib/compositing`. The modern root scenarios and the legacy-source scenario, which pairs a legacy +`ThemeReference` with `useThemeState`, require the retained Flex interaction policy and `color-lib/interaction`; the +legacy-source scenario also forbids a retained `FlexThemeReference`. Only the legacy theme scenario forbids any retained +`color-lib/` or `flex/` module. The Fluent theme scenarios forbid `useTheme` and the compatibility modules from the +import graph and any retained `flex/`, `color-lib/`, or Flex theme module, and a bundle that imports only +`fluentLightTheme` retains no other theme and no `ThemeReference`, while one that imports only `fluentHcTheme` retains +only the high-contrast themes. The Flex theme scenarios require the x3 defaults and forbid `fluent/` and +`color-lib/compositing`. The color-library scenario requires its algorithms, and the legacy-projection scenario requires +the projection, the Fluent theme selection, and the generated Fluent tokens it projects onto. Every scenario also +requires a module it is expected to load, so a moved file cannot make a forbidden pattern pass vacuously. The package specifiers above are the supported import surface. Source and build paths such as `src/fluent/...` or `lib/...` are private implementation details that may move without a breaking change. +## Deprecated entry point + +`./deprecated` is built from `src/deprecated/`, the only design source that imports the Fluent 2 token JSON from the +`@fluentui-react-native/design-tokens-*` packages. It exports the token loaders (`getAliasTokens`, `getShadowTokens`, +`globalTokens`, and `hcAliasTokens`) and the pipeline mappers that turn that JSON into theme values +(`mapPipelineToTheme`, `mapFontPipelineToTheme`, and `mapPipelineToShadow`). It has no replacement API: new code uses +the ready-made themes from `./themes`, whose generated tokens the build derives from the same JSON with these mappers. + +- **R-DESIGN-003:** Only tests, other `src/deprecated/` modules, and build scripts may use `src/deprecated/`, and only + the existing deprecated consumers may import `@fluentui-react-native/design/deprecated`: the `theme-tokens` and + `theming-utils` shims, the Android, Apple, and Win32 theme packages, and the private tester app. No other design + source imports a `design-tokens-*` package, and no other production entry point reaches `src/deprecated/`. + +`src/test/compatibility/importBoundaries.test.ts` enforces the rule inside this package, and the bundle-size scenarios +forbid `src/deprecated/` from the other design entry points. `remaining-work.md` tracks retiring the entry point. + ## Compatibility packages `@fluentui-react-native/design` is the definition site for the symbols below. The legacy packages listed here are compatibility entry points and contain only explicit named re-exports. -| Legacy package | Exported symbols | Owning design entry point | Definition | -| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------- | -| `@fluentui-react-native/theme` | `ThemeProvider`, `ThemeProviderProps`, `ThemeReference`, `OnThemeChange`, `ThemeRecipe`, `ThemeTransform` | `@fluentui-react-native/design/theming` | `src/theming/ThemeProvider.tsx`, `src/fluent/themeReference.ts` | -| `@fluentui-react-native/theme-types` | `AliasColorTokens`, `AppearanceOptions`, `BaseShadowAliasTokens`, `Color`, `FabricWebPalette`, `FontDynamicTypeRamp`, `FontFamilies`, `FontFamily`, `FontFamilyValue`, `FontSize`, `FontSizeValuePoints`, `FontSizes`, `FontWeight`, `FontWeightValue`, `FontWeights`, `OfficePalette`, `Palette`, `PaletteBackgroundColors`, `PaletteTextColors`, `PartialPalette`, `PartialShadowDefinition`, `PartialTheme`, `PartialTypography`, `ShadowToken`, `ShadowValue`, `Spacing`, `TextStyling`, `Theme`, `ThemeColorDefinition`, `ThemeContext`, `ThemeOptions`, `ThemeShadowDefinition`, `Typography`, `Variant`, `VariantValue`, `Variants`, `useTheme` | `@fluentui-react-native/design/theming` | `src/theming/context.ts`, `src/fluent/types/` | -| `@fluentui-react-native/theming-utils` | `getCurrentAppearance`, `isHighContrast`, `mapFontPipelineToTheme`, `mapPipelineToShadow`, `mapPipelineToTheme`, `setIsHighContrast` | `@fluentui-react-native/design/theming` | `src/fluent/platformUtils.*.ts`, `src/fluent/mapPipelineToShadow.ts`, `src/fluent/mapPipelineToTheme*.ts` | -| `@fluentui-react-native/theme-tokens` | `getAliasTokens`, `getShadowTokens`, `globalTokens` | `@fluentui-react-native/design/tokens/legacy` | `src/fluent/tokens/` | -| `@fluentui-react-native/tokens` | `backgroundColorTokens`, `borderStyles`, `borderTokens`, `colorTokens`, `fontStyles`, `foregroundColorTokens`, `getPaletteFromTheme`, `layoutStyles`, `layoutTokens`, `shadowStyles`, `shadowTokens`, `styleFunction`, `textTokens`, `tokenBuilder`, `FontDecorationTokens`, `FontStyleTokens`, `FontTokens`, `FontVariantTokens`, `IBackgroundColorTokens`, `IBorderTokens`, `IColorTokens`, `IForegroundColorTokens`, `IShadowTokens`, `LayoutTokens`, `LookupThemePart`, `OperationSet`, `StyleFactoryFunction`, `StyleFactoryFunctionRaw`, `StyleFactoryOperation`, `TokenBuilder` | `@fluentui-react-native/design/styling/tokens` | `src/fluent/styling/tokens/` | -| `@fluentui-react-native/themed-stylesheet` | `NamedStyles`, `themedStyleSheet` | `@fluentui-react-native/design/styling/stylesheet` | `src/fluent/styling/stylesheet/themedStyleSheet.ts` | - -The three optional entry points (`tokens/legacy`, `styling/tokens`, and -`styling/stylesheet`) are intentionally absent from the design root barrel. -This keeps legacy token data and styling infrastructure out of consumers that +| Legacy package | Exported symbols | Owning design entry point | Definition | +| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | +| `@fluentui-react-native/theme` | `ThemeProvider`, `ThemeProviderProps`, `ThemeReference`, `OnThemeChange`, `ThemeRecipe`, `ThemeTransform` | `@fluentui-react-native/design/theming` | `src/theming/ThemeProvider.tsx`, `src/fluent/themeReference.ts` | +| `@fluentui-react-native/theme-types` | `AliasColorTokens`, `AppearanceOptions`, `BaseShadowAliasTokens`, `Color`, `FabricWebPalette`, `FontDynamicTypeRamp`, `FontFamilies`, `FontFamily`, `FontFamilyValue`, `FontSize`, `FontSizeValuePoints`, `FontSizes`, `FontWeight`, `FontWeightValue`, `FontWeights`, `OfficePalette`, `Palette`, `PaletteBackgroundColors`, `PaletteTextColors`, `PartialPalette`, `PartialShadowDefinition`, `PartialTheme`, `PartialTypography`, `ShadowToken`, `ShadowValue`, `Spacing`, `TextStyling`, `Theme`, `ThemeColorDefinition`, `ThemeContext`, `ThemeOptions`, `ThemeShadowDefinition`, `Typography`, `Variant`, `VariantValue`, `Variants`, `useTheme` | `@fluentui-react-native/design/theming` | `src/theming/context.ts`, `src/fluent/types/` | +| `@fluentui-react-native/theming-utils` | `getCurrentAppearance`, `isHighContrast`, `setIsHighContrast`; the deprecated `mapFontPipelineToTheme`, `mapPipelineToShadow`, and `mapPipelineToTheme` | `@fluentui-react-native/design/theming` and `@fluentui-react-native/design/deprecated` | `src/fluent/platformUtils.*.ts`, `src/deprecated/mapPipelineToShadow.ts`, `src/deprecated/mapPipelineToTheme*.ts` | +| `@fluentui-react-native/theme-tokens` | `getAliasTokens`, `getShadowTokens`, `globalTokens`, `hcAliasTokens` (deprecated) | `@fluentui-react-native/design/deprecated` | `src/deprecated/` | +| `@fluentui-react-native/tokens` | `backgroundColorTokens`, `borderStyles`, `borderTokens`, `colorTokens`, `fontStyles`, `foregroundColorTokens`, `getPaletteFromTheme`, `layoutStyles`, `layoutTokens`, `shadowStyles`, `shadowTokens`, `styleFunction`, `textTokens`, `tokenBuilder`, `FontDecorationTokens`, `FontStyleTokens`, `FontTokens`, `FontVariantTokens`, `IBackgroundColorTokens`, `IBorderTokens`, `IColorTokens`, `IForegroundColorTokens`, `IShadowTokens`, `LayoutTokens`, `LookupThemePart`, `OperationSet`, `StyleFactoryFunction`, `StyleFactoryFunctionRaw`, `StyleFactoryOperation`, `TokenBuilder` | `@fluentui-react-native/design/styling/tokens` | `src/fluent/styling/tokens/` | +| `@fluentui-react-native/themed-stylesheet` | `NamedStyles`, `themedStyleSheet` | `@fluentui-react-native/design/styling/stylesheet` | `src/fluent/styling/stylesheet/themedStyleSheet.ts` | + +The optional `deprecated`, `styling/tokens`, and `styling/stylesheet` entry +points are intentionally absent from the design root barrel. This keeps +deprecated token data and legacy styling infrastructure out of consumers that only use the current design APIs. diff --git a/packages/agentic/design/references/remaining-work.md b/packages/agentic/design/references/remaining-work.md index 4413828630..ac05b1c6ca 100644 --- a/packages/agentic/design/references/remaining-work.md +++ b/packages/agentic/design/references/remaining-work.md @@ -75,10 +75,22 @@ behavior is documented in `theming.md`, `tokens.md`, and `entry-points.md`. - **Outcome:** `fluentTheme` selects distinct themes for elevated appearances. - **Current state:** `themes` provides light, dark, and high-contrast Fluent themes. The generated Fluent tokens already - supply `lightElevated` and `darkElevated` color and shadow sets (`tokens.md`), but `fluentTheme` resolves elevated - requests by color scheme alone. -- **Done when:** the owner approves how elevated appearances map to those sets, and `fluentTheme` selects the matching - theme by the resolved interface level. + supply `lightElevated` and `darkElevated` color and shadow sets (`tokens.md`), but `fluentTheme` and the Flex-to-legacy + projection, which share `selectFluentTheme`, resolve elevated requests by color scheme alone. +- **Done when:** the owner approves how elevated appearances map to those sets, and `selectFluentTheme` selects the + matching theme by the resolved interface level. + +## Retire the deprecated entry point + +- **Outcome:** no package reads the Fluent 2 token JSON at runtime, and `@fluentui-react-native/design/deprecated`, + `src/deprecated/`, and the runtime `design-tokens-*` dependencies are removed. +- **Current state:** the Android, Apple, and Win32 theme packages build their legacy themes from the JSON through + `./deprecated`, the `theme-tokens` and `theming-utils` shims re-export it, and the private tester app reads the + `globalTokens` palettes (R-DESIGN-003). The generated Fluent sets already provide each platform's alias colors, + shadows, and font aliases (`tokens.md`), and the build still derives them from the JSON with the deprecated mappers. +- **Done when:** the platform themes and the tester read the generated Fluent sets, generated global tokens, or Flex + tokens instead, the shims drop the deprecated re-exports in a release that permits the break, and the build reads the + JSON without runtime modules. ## Dependent work owned by other packages diff --git a/packages/agentic/design/references/theming.md b/packages/agentic/design/references/theming.md index 768603d125..f38db516f8 100644 --- a/packages/agentic/design/references/theming.md +++ b/packages/agentic/design/references/theming.md @@ -107,13 +107,13 @@ back to an appearance reuses its entry within a revision, and a revision change A request has `colorScheme` (`light`, `dark`, or `system`), `contrast` (`standard`, `highContrast`, or `system`), and `interfaceLevel` (`base`, `elevated`, or `system`), plus an optional `colorTone` (`cool` or `warm`). The resolved -appearance is always concrete. `colorTone` is a design choice rather than a platform setting, so appearance sources never -supply it: it resolves from the provider or root request, then the source's `appearance` option, then the fallback +appearance is always concrete. `colorTone` is a design choice rather than a platform setting, so appearance sources +never supply it: it resolves from the provider or root request, then the source's `appearance` option, then the fallback appearance, then `cool`. A nested `ThemedRoot` inherits it with the other requested axes, and a raw legacy `ThemeContext` boundary resolves to `cool`. Caches key a warm appearance separately; cool keeps the existing -`colorScheme|contrast|interfaceLevel` key, and the complete legacy defaults do not vary by tone. A -`ThemeAppearanceSource` provides a stable `getSnapshot()` and a `subscribe()` that installs native listeners only while -subscribed; create one with `createThemeAppearanceSource`. +`colorScheme|contrast|interfaceLevel` key, and the Fluent theme that backs the legacy projection does not vary by tone. +A `ThemeAppearanceSource` provides a stable `getSnapshot()` and a `subscribe()` that installs native listeners only +while subscribed; create one with `createThemeAppearanceSource`. | Platform | Platform appearance source | | -------------- | --------------------------------------------------------------------------------------------- | @@ -186,15 +186,16 @@ const theme = new FlexThemeReference({ base: flexWarmTheme, appearance: { colorS The package root exports only the modern authoring and consumption APIs. It reaches the forward Theme-to-Flex adapter, which `useThemeState` needs for legacy sources, and the Flex interaction policy with the raw `color-lib` interaction -algorithm, but not `useTheme`, the reverse converter, the complete legacy defaults, or legacy token payloads. The legacy -`ThemeReference`, `useTheme`, and `ThemeProvider` graphs reach neither Flex nor `color-lib`. An app that pairs a legacy -`ThemeReference` with `useThemeState` reaches the forward adapter and, through the default theme state, the x3 defaults -and the interaction policy with `color-lib/interaction`, but not `FlexThemeReference`, `color-lib/compositing`, or the -compatibility projection. `entry-points.md` lists every subpath. +algorithm, but not `useTheme`, the reverse converter, the Fluent themes it projects onto, or deprecated token data. The +legacy `ThemeReference`, `useTheme`, and `ThemeProvider` graphs reach neither Flex nor `color-lib`. An app that pairs a +legacy `ThemeReference` with `useThemeState` reaches the forward adapter and, through the default theme state, the x3 +defaults and the interaction policy with `color-lib/interaction`, but not `FlexThemeReference`, `color-lib/compositing`, +or the compatibility projection. `entry-points.md` lists every subpath. `themeFromFlexTokens` in `theming/compat` builds a complete `Theme` in this order: -1. the appearance-specific complete legacy base from `getDefaultLegacyTheme`; +1. the generated Fluent theme for the platform and appearance, selected as `fluentTheme` selects it, which supplies + every value Flex cannot represent; 2. the source's `legacyFallback`, which preserves component recipes, custom colors, and host metadata that Flex cannot represent; 3. the generated Flex projection, so mapped Flex values are authoritative; diff --git a/packages/agentic/design/references/tokens.md b/packages/agentic/design/references/tokens.md index 859e619b4a..3401cc4be9 100644 --- a/packages/agentic/design/references/tokens.md +++ b/packages/agentic/design/references/tokens.md @@ -6,7 +6,7 @@ owner_paths: - packages/agentic/design/src/flex/tokens.types.ts - packages/agentic/design/src/flex/defaults - packages/agentic/design/src/flex/adapters - - packages/agentic/design/src/fluent/tokens + - packages/agentic/design/src/deprecated - packages/agentic/design/scripts --- @@ -23,7 +23,7 @@ owner_paths: | ------------------------------ | ------------------------------------------------- | --------------------------------------------------------------------------- | | Flex semantic tokens | `FlexTokens` from `@fluentui-react-native/design` | `src/flex/tokens.types.ts`; x3 defaults in `src/flex/defaults/` | | Platform global tokens | `@fluentui-react-native/design/tokens/global` | Generated into `src/tokens/global.generated.ts` and `src/tokens/generated/` | -| Legacy alias and shadow tokens | `@fluentui-react-native/design/tokens/legacy` | `src/fluent/tokens/`, for legacy themes only | +| Deprecated Fluent 2 token data | `@fluentui-react-native/design/deprecated` | `src/deprecated/`, for existing platform themes only (R-DESIGN-003) | `FlexTokens` groups `color` (one `InteractiveColor` with `rest`, `hover`, and `pressed` per semantic color; see `flex-colors.md`), `shadow`, `fontWeight`, `fontFamily`, `fontSize`, `lineHeight`, `borderRadius`, `spacing`, @@ -42,8 +42,9 @@ The package's `prebuild` script (`codegen.cts`) generates the global token files `@fluentui-react-native/design-tokens-*` packages and regenerates both mapping projections. It also generates `src/fluent/defaults/fluentTokens.generated.ts` (Win32) and its Windows, macOS, iOS, and Android variants. These modules contain complete Fluent alias colors, shadows, and font aliases, which the `themes` entry point consumes (`theming.md`). -The runtime pipeline mappers and existing theme construction are unchanged. Do not edit generated files; change their -inputs and rebuild. +The generator applies the deprecated pipeline mappers from `src/deprecated/` at build time, so runtime code outside that +directory reads Fluent 2 values only from these generated modules (R-DESIGN-003). Do not edit generated files; change +their inputs and rebuild. Every generated platform module exports `light`, `dark`, `lightElevated`, `darkElevated`, `hcLight`, and `hcDark` color and shadow sets, plus `fontAliasTokens`. Colors satisfy `Required<AliasColorTokens>` (including deprecated red @@ -119,8 +120,9 @@ never derives states: a state that neither the Theme nor a fallback supplies equals rest. X3 default changes therefore never alter projected legacy themes. Legacy `{ ambient, key }` Theme shadows become `[ambient, key]` layers. A complete -legacy Theme also requires values that Flex cannot represent; those values are -supplied by the lazy compatibility base under `src/fluent/compat`. +legacy Theme also requires values that Flex cannot represent; the Flex-to-legacy +projection takes those values from the Fluent theme for the appearance +(`theming.md`). ### Internal consistency diff --git a/packages/agentic/design/scripts/fluent-tokens.cts b/packages/agentic/design/scripts/fluent-tokens.cts index 28f27f6d79..418e03b883 100644 --- a/packages/agentic/design/scripts/fluent-tokens.cts +++ b/packages/agentic/design/scripts/fluent-tokens.cts @@ -3,7 +3,7 @@ import type { AliasColorTokens } from '../src/fluent/types/Color.types'; import type { Variants, VariantValue } from '../src/fluent/types/Typography.types'; const { GeneratedFile, ValuePool, expression, makeComment } = require('@fluentui-react-native/scripts'); const path = require('node:path'); -const { mapPipelineToShadow } = require('../src/fluent/mapPipelineToShadow.ts'); +const { mapPipelineToShadow } = require('../src/deprecated/mapPipelineToShadow.ts'); type Appearance = 'light' | 'dark' | 'lightElevated' | 'darkElevated' | 'hcLight' | 'hcDark'; type ColorKey = keyof AliasColorTokens; @@ -12,7 +12,7 @@ type PipelineTokens = Record<string, Record<string, string | number>>; type PlatformData = { /** Token package directory for each appearance the platform supplies. Light supplies the font aliases. */ paths: Partial<Record<Appearance, string>> & { light: string; dark: string }; - /** Pipeline mapper module in src/fluent for the platform. */ + /** Pipeline mapper module in src/deprecated for the platform. */ mapper: string; filename: string; /** Native name for a pipeline `PlatformColor(Name)` system color. Defaults to the Win32 name. */ @@ -170,7 +170,7 @@ function definedEntries<T>(values: Record<string, T | undefined>): Record<string } function mapColors(tokens: PipelineTokens, mapper: string, keys?: Set<ColorKey>): Record<string, string> { - const { mapPipelineToTheme } = require(`../src/fluent/${mapper}`); + const { mapPipelineToTheme } = require(`../src/deprecated/${mapper}`); const colors = definedEntries<string>(mapPipelineToTheme(tokens)); // Keep native states that a legacy mapper omits, but do not add keys outside the alias contract. if (keys) { @@ -272,7 +272,7 @@ const legacyFontAliases: Record<string, string> = { }; function mapFonts(platformData: PlatformData): Record<string, VariantValue> { - const { mapFontPipelineToTheme } = require(`../src/fluent/${platformData.mapper}`); + const { mapFontPipelineToTheme } = require(`../src/deprecated/${platformData.mapper}`); const { font } = require(`${platformData.paths.light}tokens-global.json`); const defaults = Object.fromEntries( Object.entries(fontRamp).map(([name, [size, weight]]) => [ diff --git a/packages/agentic/design/src/fluent/__tests__/__snapshots__/theming-utils.test.ts.snap b/packages/agentic/design/src/deprecated/__tests__/__snapshots__/mapPipeline.test.ts.snap similarity index 100% rename from packages/agentic/design/src/fluent/__tests__/__snapshots__/theming-utils.test.ts.snap rename to packages/agentic/design/src/deprecated/__tests__/__snapshots__/mapPipeline.test.ts.snap diff --git a/packages/agentic/design/src/deprecated/__tests__/mapPipeline.test.ts b/packages/agentic/design/src/deprecated/__tests__/mapPipeline.test.ts new file mode 100644 index 0000000000..510fde43f2 --- /dev/null +++ b/packages/agentic/design/src/deprecated/__tests__/mapPipeline.test.ts @@ -0,0 +1,57 @@ +import blackAliasTokens from '@fluentui-react-native/design-tokens-win32/black/tokens-aliases.json'; +import colorfulAliasTokens from '@fluentui-react-native/design-tokens-win32/colorful/tokens-aliases.json'; +import darkGrayAliasTokens from '@fluentui-react-native/design-tokens-win32/darkgray/tokens-aliases.json'; +import hcShadowTokens from '@fluentui-react-native/design-tokens-win32/hc/tokens-shadow.json'; +import darkAliasTokens from '@fluentui-react-native/design-tokens-windows/dark/tokens-aliases.json'; +import darkShadowTokens from '@fluentui-react-native/design-tokens-windows/dark/tokens-shadow.json'; +import lightAliasTokens from '@fluentui-react-native/design-tokens-windows/light/tokens-aliases.json'; +import lightShadowTokens from '@fluentui-react-native/design-tokens-windows/light/tokens-shadow.json'; + +import { mapPipelineToShadow } from '../mapPipelineToShadow'; +import { mapPipelineToTheme, mapFontPipelineToTheme } from '../mapPipelineToTheme'; + +describe('mapPipelineToTheme test', () => { + it('lightAliasTokens', () => { + const aliasColorTokens = mapPipelineToTheme(lightAliasTokens); + expect(aliasColorTokens).toMatchSnapshot(); + }); + + it('darkAliasTokens', () => { + const aliasColorTokens = mapPipelineToTheme(darkAliasTokens); + expect(aliasColorTokens).toMatchSnapshot(); + }); +}); + +describe('mapFontPipelineToTheme test', () => { + it('colorfulAliasTokens', () => { + const fontTheme = mapFontPipelineToTheme(colorfulAliasTokens); + expect(fontTheme).toMatchSnapshot(); + }); + + it('darkGrayAliasTokens', () => { + const fontTheme = mapFontPipelineToTheme(darkGrayAliasTokens); + expect(fontTheme).toMatchSnapshot(); + }); + + it('blackAliasTokens', () => { + const fontTheme = mapFontPipelineToTheme(blackAliasTokens); + expect(fontTheme).toMatchSnapshot(); + }); +}); + +describe('mapPipelineToShadow test', () => { + it('lightShadowTokens', () => { + const fontTheme = mapPipelineToShadow(lightShadowTokens); + expect(fontTheme).toMatchSnapshot(); + }); + + it('darkShadowTokens', () => { + const fontTheme = mapPipelineToShadow(darkShadowTokens); + expect(fontTheme).toMatchSnapshot(); + }); + + it('hcShadowTokens', () => { + const fontTheme = mapPipelineToShadow(hcShadowTokens); + expect(fontTheme).toMatchSnapshot(); + }); +}); diff --git a/packages/agentic/design/src/deprecated/index.ts b/packages/agentic/design/src/deprecated/index.ts new file mode 100644 index 0000000000..84879e05e5 --- /dev/null +++ b/packages/agentic/design/src/deprecated/index.ts @@ -0,0 +1,5 @@ +export { getAliasTokens, getShadowTokens } from './tokens/getTokens'; +export { default as globalTokens } from './tokens/tokens-global'; +export { hcAliasTokens } from './tokens/highContrast/tokens-alias'; +export { mapFontPipelineToTheme, mapPipelineToTheme } from './mapPipelineToTheme'; +export { mapPipelineToShadow } from './mapPipelineToShadow'; diff --git a/packages/agentic/design/src/fluent/mapPipelineToShadow.ts b/packages/agentic/design/src/deprecated/mapPipelineToShadow.ts similarity index 95% rename from packages/agentic/design/src/fluent/mapPipelineToShadow.ts rename to packages/agentic/design/src/deprecated/mapPipelineToShadow.ts index fcde469cfa..efa5220085 100644 --- a/packages/agentic/design/src/fluent/mapPipelineToShadow.ts +++ b/packages/agentic/design/src/deprecated/mapPipelineToShadow.ts @@ -1,4 +1,4 @@ -import type { ThemeShadowDefinition } from './types/Shadow.types'; +import type { ThemeShadowDefinition } from '../fluent/types/Shadow.types'; /** * Given design token pipeline output for shadow tokens, creates an object that can be used in Theme object. diff --git a/packages/agentic/design/src/fluent/mapPipelineToTheme.android.ts b/packages/agentic/design/src/deprecated/mapPipelineToTheme.android.ts similarity index 98% rename from packages/agentic/design/src/fluent/mapPipelineToTheme.android.ts rename to packages/agentic/design/src/deprecated/mapPipelineToTheme.android.ts index 1fc2744f00..38082d5900 100644 --- a/packages/agentic/design/src/fluent/mapPipelineToTheme.android.ts +++ b/packages/agentic/design/src/deprecated/mapPipelineToTheme.android.ts @@ -1,5 +1,5 @@ -import type { AliasColorTokens } from './types/Color.types'; -import type { Variants, VariantValue } from './types/Typography.types'; +import type { AliasColorTokens } from '../fluent/types/Color.types'; +import type { Variants, VariantValue } from '../fluent/types/Typography.types'; // API that maps tokens coming from the android token pipeline to Theme color values. export function mapPipelineToTheme(pipelineOutput: any): AliasColorTokens { diff --git a/packages/agentic/design/src/fluent/mapPipelineToTheme.ios.ts b/packages/agentic/design/src/deprecated/mapPipelineToTheme.ios.ts similarity index 97% rename from packages/agentic/design/src/fluent/mapPipelineToTheme.ios.ts rename to packages/agentic/design/src/deprecated/mapPipelineToTheme.ios.ts index 48639002e4..e4e9cc19c7 100644 --- a/packages/agentic/design/src/fluent/mapPipelineToTheme.ios.ts +++ b/packages/agentic/design/src/deprecated/mapPipelineToTheme.ios.ts @@ -1,6 +1,6 @@ -import type { FontStyleTokens } from './styling/tokens'; -import type { AliasColorTokens } from './types/Color.types'; -import type { FontDynamicTypeRamp, Variants, VariantValue } from './types/Typography.types'; +import type { FontStyleTokens } from '../fluent/styling/tokens'; +import type { AliasColorTokens } from '../fluent/types/Color.types'; +import type { FontDynamicTypeRamp, Variants, VariantValue } from '../fluent/types/Typography.types'; // API that maps tokens coming from the iOS token pipeline to Theme color values. export function mapPipelineToTheme(pipelineOutput: any): AliasColorTokens { diff --git a/packages/agentic/design/src/fluent/mapPipelineToTheme.ts b/packages/agentic/design/src/deprecated/mapPipelineToTheme.ts similarity index 98% rename from packages/agentic/design/src/fluent/mapPipelineToTheme.ts rename to packages/agentic/design/src/deprecated/mapPipelineToTheme.ts index 2d948624d6..c6a5d1c70c 100644 --- a/packages/agentic/design/src/fluent/mapPipelineToTheme.ts +++ b/packages/agentic/design/src/deprecated/mapPipelineToTheme.ts @@ -1,5 +1,5 @@ -import type { AliasColorTokens } from './types/Color.types'; -import type { Variants } from './types/Typography.types'; +import type { AliasColorTokens } from '../fluent/types/Color.types'; +import type { Variants } from '../fluent/types/Typography.types'; export function mapPipelineToTheme(pipelineOutput: any): AliasColorTokens { return { diff --git a/packages/agentic/design/src/fluent/tokens/getTokens.android.ts b/packages/agentic/design/src/deprecated/tokens/getTokens.android.ts similarity index 94% rename from packages/agentic/design/src/fluent/tokens/getTokens.android.ts rename to packages/agentic/design/src/deprecated/tokens/getTokens.android.ts index 90872f2dbe..b81860e14f 100644 --- a/packages/agentic/design/src/fluent/tokens/getTokens.android.ts +++ b/packages/agentic/design/src/deprecated/tokens/getTokens.android.ts @@ -2,7 +2,7 @@ import darkAliasTokens from '@fluentui-react-native/design-tokens-android/dark/t import darkShadowTokens from '@fluentui-react-native/design-tokens-android/dark/tokens-shadow.json'; import lightAliasTokens from '@fluentui-react-native/design-tokens-android/light/tokens-aliases.json'; import lightShadowTokens from '@fluentui-react-native/design-tokens-android/light/tokens-shadow.json'; -import type { AppearanceOptions } from '../types/Theme.types'; +import type { AppearanceOptions } from '../../fluent/types/Theme.types'; export function getAliasTokens(mode: AppearanceOptions) { if (mode === 'light') { diff --git a/packages/agentic/design/src/fluent/tokens/getTokens.ios.ts b/packages/agentic/design/src/deprecated/tokens/getTokens.ios.ts similarity index 95% rename from packages/agentic/design/src/fluent/tokens/getTokens.ios.ts rename to packages/agentic/design/src/deprecated/tokens/getTokens.ios.ts index f46d59589b..328eefa302 100644 --- a/packages/agentic/design/src/fluent/tokens/getTokens.ios.ts +++ b/packages/agentic/design/src/deprecated/tokens/getTokens.ios.ts @@ -3,7 +3,7 @@ import iOSDarkShadowTokens from '@fluentui-react-native/design-tokens-ios/dark/t import iOSDarkElevatedAliasTokens from '@fluentui-react-native/design-tokens-ios/elevateddark/tokens-aliases.json'; import iOSLightAliasTokens from '@fluentui-react-native/design-tokens-ios/light/tokens-aliases.json'; import iOSLightShadowTokens from '@fluentui-react-native/design-tokens-ios/light/tokens-shadow.json'; -import type { AppearanceOptions } from '../types/Theme.types'; +import type { AppearanceOptions } from '../../fluent/types/Theme.types'; import { assertNever } from 'assert-never'; export function getAliasTokens(mode: AppearanceOptions) { diff --git a/packages/agentic/design/src/fluent/tokens/getTokens.ts b/packages/agentic/design/src/deprecated/tokens/getTokens.ts similarity index 94% rename from packages/agentic/design/src/fluent/tokens/getTokens.ts rename to packages/agentic/design/src/deprecated/tokens/getTokens.ts index 07d6c201d6..b3ced7533d 100644 --- a/packages/agentic/design/src/fluent/tokens/getTokens.ts +++ b/packages/agentic/design/src/deprecated/tokens/getTokens.ts @@ -3,7 +3,7 @@ import darkAliasTokens from '@fluentui-react-native/design-tokens-windows/dark/t import darkShadowTokens from '@fluentui-react-native/design-tokens-windows/dark/tokens-shadow.json'; import lightAliasTokens from '@fluentui-react-native/design-tokens-windows/light/tokens-aliases.json'; import lightShadowTokens from '@fluentui-react-native/design-tokens-windows/light/tokens-shadow.json'; -import type { AppearanceOptions } from '../types/Theme.types'; +import type { AppearanceOptions } from '../../fluent/types/Theme.types'; import { assertNever } from 'assert-never'; import { hcAliasTokens } from './highContrast/tokens-alias'; diff --git a/packages/agentic/design/src/fluent/tokens/highContrast/__tests__/processAliasTokens.test.ts b/packages/agentic/design/src/deprecated/tokens/highContrast/__tests__/processAliasTokens.test.ts similarity index 100% rename from packages/agentic/design/src/fluent/tokens/highContrast/__tests__/processAliasTokens.test.ts rename to packages/agentic/design/src/deprecated/tokens/highContrast/__tests__/processAliasTokens.test.ts diff --git a/packages/agentic/design/src/fluent/tokens/highContrast/processAliasTokens.ts b/packages/agentic/design/src/deprecated/tokens/highContrast/processAliasTokens.ts similarity index 100% rename from packages/agentic/design/src/fluent/tokens/highContrast/processAliasTokens.ts rename to packages/agentic/design/src/deprecated/tokens/highContrast/processAliasTokens.ts diff --git a/packages/agentic/design/src/fluent/tokens/highContrast/tokens-alias.ts b/packages/agentic/design/src/deprecated/tokens/highContrast/tokens-alias.ts similarity index 100% rename from packages/agentic/design/src/fluent/tokens/highContrast/tokens-alias.ts rename to packages/agentic/design/src/deprecated/tokens/highContrast/tokens-alias.ts diff --git a/packages/agentic/design/src/fluent/tokens/highContrast/tokens-alias.win32.ts b/packages/agentic/design/src/deprecated/tokens/highContrast/tokens-alias.win32.ts similarity index 100% rename from packages/agentic/design/src/fluent/tokens/highContrast/tokens-alias.win32.ts rename to packages/agentic/design/src/deprecated/tokens/highContrast/tokens-alias.win32.ts diff --git a/packages/agentic/design/src/fluent/tokens/tokens-global.android.ts b/packages/agentic/design/src/deprecated/tokens/tokens-global.android.ts similarity index 100% rename from packages/agentic/design/src/fluent/tokens/tokens-global.android.ts rename to packages/agentic/design/src/deprecated/tokens/tokens-global.android.ts diff --git a/packages/agentic/design/src/fluent/tokens/tokens-global.ios.ts b/packages/agentic/design/src/deprecated/tokens/tokens-global.ios.ts similarity index 100% rename from packages/agentic/design/src/fluent/tokens/tokens-global.ios.ts rename to packages/agentic/design/src/deprecated/tokens/tokens-global.ios.ts diff --git a/packages/agentic/design/src/fluent/tokens/tokens-global.ts b/packages/agentic/design/src/deprecated/tokens/tokens-global.ts similarity index 100% rename from packages/agentic/design/src/fluent/tokens/tokens-global.ts rename to packages/agentic/design/src/deprecated/tokens/tokens-global.ts diff --git a/packages/agentic/design/src/fluent/tokens/tokens-global.win32.ts b/packages/agentic/design/src/deprecated/tokens/tokens-global.win32.ts similarity index 100% rename from packages/agentic/design/src/fluent/tokens/tokens-global.win32.ts rename to packages/agentic/design/src/deprecated/tokens/tokens-global.win32.ts diff --git a/packages/agentic/design/src/fluent/__tests__/theming-utils.test.ts b/packages/agentic/design/src/fluent/__tests__/theming-utils.test.ts index d39064c02d..10f542aa4c 100644 --- a/packages/agentic/design/src/fluent/__tests__/theming-utils.test.ts +++ b/packages/agentic/design/src/fluent/__tests__/theming-utils.test.ts @@ -1,15 +1,4 @@ -import blackAliasTokens from '@fluentui-react-native/design-tokens-win32/black/tokens-aliases.json'; -import colorfulAliasTokens from '@fluentui-react-native/design-tokens-win32/colorful/tokens-aliases.json'; -import darkGrayAliasTokens from '@fluentui-react-native/design-tokens-win32/darkgray/tokens-aliases.json'; -import hcShadowTokens from '@fluentui-react-native/design-tokens-win32/hc/tokens-shadow.json'; -import darkAliasTokens from '@fluentui-react-native/design-tokens-windows/dark/tokens-aliases.json'; -import darkShadowTokens from '@fluentui-react-native/design-tokens-windows/dark/tokens-shadow.json'; -import lightAliasTokens from '@fluentui-react-native/design-tokens-windows/light/tokens-aliases.json'; -import lightShadowTokens from '@fluentui-react-native/design-tokens-windows/light/tokens-shadow.json'; - import { getCurrentAppearance } from '../../theming'; -import { mapPipelineToShadow } from '../mapPipelineToShadow'; -import { mapPipelineToTheme, mapFontPipelineToTheme } from '../mapPipelineToTheme'; const fallBackAppearance = 'light'; @@ -40,49 +29,3 @@ describe('getCurrentAppearanceTable test', () => { expect(getCurrentAppearance(undefined, fallBackAppearance)).toBe(fallBackAppearance); }); }); - -describe('mapPipelineToTheme test', () => { - it('lightAliasTokens', () => { - const aliasColorTokens = mapPipelineToTheme(lightAliasTokens); - expect(aliasColorTokens).toMatchSnapshot(); - }); - - it('darkAliasTokens', () => { - const aliasColorTokens = mapPipelineToTheme(darkAliasTokens); - expect(aliasColorTokens).toMatchSnapshot(); - }); -}); - -describe('mapFontPipelineToTheme test', () => { - it('colorfulAliasTokens', () => { - const fontTheme = mapFontPipelineToTheme(colorfulAliasTokens); - expect(fontTheme).toMatchSnapshot(); - }); - - it('darkGrayAliasTokens', () => { - const fontTheme = mapFontPipelineToTheme(darkGrayAliasTokens); - expect(fontTheme).toMatchSnapshot(); - }); - - it('blackAliasTokens', () => { - const fontTheme = mapFontPipelineToTheme(blackAliasTokens); - expect(fontTheme).toMatchSnapshot(); - }); -}); - -describe('mapPipelineToShadow test', () => { - it('lightShadowTokens', () => { - const fontTheme = mapPipelineToShadow(lightShadowTokens); - expect(fontTheme).toMatchSnapshot(); - }); - - it('darkShadowTokens', () => { - const fontTheme = mapPipelineToShadow(darkShadowTokens); - expect(fontTheme).toMatchSnapshot(); - }); - - it('hcShadowTokens', () => { - const fontTheme = mapPipelineToShadow(hcShadowTokens); - expect(fontTheme).toMatchSnapshot(); - }); -}); diff --git a/packages/agentic/design/src/fluent/compat/__tests__/defaultLegacyTheme.test.ios.ts b/packages/agentic/design/src/fluent/compat/__tests__/defaultLegacyTheme.test.ios.ts deleted file mode 100644 index b534a9cdf3..0000000000 --- a/packages/agentic/design/src/fluent/compat/__tests__/defaultLegacyTheme.test.ios.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { getDefaultLegacyTheme } from '../defaultLegacyTheme'; - -const dark = { - colorScheme: 'dark', - contrast: 'standard', - interfaceLevel: 'base', -} as const; -const darkElevated = { - colorScheme: 'dark', - contrast: 'standard', - interfaceLevel: 'elevated', -} as const; - -it('uses elevated-dark iOS aliases for the legacy compatibility base', () => { - const darkTheme = getDefaultLegacyTheme(dark); - const elevatedTheme = getDefaultLegacyTheme(darkElevated); - - expect(elevatedTheme.colors.neutralBackground4).toBe('#424242'); - expect(elevatedTheme.colors.neutralBackground4).not.toBe(darkTheme.colors.neutralBackground4); -}); diff --git a/packages/agentic/design/src/fluent/compat/createLegacyAliasTokens.ts b/packages/agentic/design/src/fluent/compat/createLegacyAliasTokens.ts deleted file mode 100644 index 5ea18a461f..0000000000 --- a/packages/agentic/design/src/fluent/compat/createLegacyAliasTokens.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { memoize } from '@fluentui-react-native/framework-base'; - -import { getAliasTokens, getShadowTokens } from '../tokens'; -import { mapPipelineToShadow } from '../mapPipelineToShadow'; -import { mapPipelineToTheme } from '../mapPipelineToTheme'; -import type { AliasColorTokens } from '../types/Color.types'; -import type { ThemeShadowDefinition } from '../types/Shadow.types'; -import type { AppearanceOptions } from '../types/Theme.types'; - -function createLegacyColorAliasTokensWorker(mode: AppearanceOptions): AliasColorTokens { - return mapPipelineToTheme(getAliasTokens(mode)); -} - -export const createLegacyColorAliasTokens = memoize(createLegacyColorAliasTokensWorker); - -function createLegacyShadowAliasTokensWorker(mode: AppearanceOptions): ThemeShadowDefinition { - return mapPipelineToShadow(getShadowTokens(mode)); -} - -export const createLegacyShadowAliasTokens = memoize(createLegacyShadowAliasTokensWorker); diff --git a/packages/agentic/design/src/fluent/compat/defaultLegacyColors.ts b/packages/agentic/design/src/fluent/compat/defaultLegacyColors.ts deleted file mode 100644 index 458a9c56c3..0000000000 --- a/packages/agentic/design/src/fluent/compat/defaultLegacyColors.ts +++ /dev/null @@ -1,315 +0,0 @@ -import type { FabricWebPalette, Palette, ThemeColorDefinition } from '../types/Color.types'; - -import { createLegacyColorAliasTokens } from './createLegacyAliasTokens'; - -export function paletteFromFabricColors(palette: FabricWebPalette, isInverted?: boolean): Palette { - return { - background: palette.white, - bodyStandoutBackground: palette.neutralLighterAlt, - bodyFrameBackground: palette.white, - bodyFrameDivider: palette.neutralLight, - bodyText: palette.neutralPrimary, - bodyTextChecked: palette.black, - subText: palette.neutralSecondary, - bodyDivider: palette.neutralLight, - - disabledBackground: isInverted ? palette.neutralQuaternaryAlt : palette.neutralLighter, - disabledText: palette.neutralTertiary, - disabledBodyText: palette.neutralTertiary, - - focusBorder: palette.neutralSecondary, - variantBorder: palette.neutralLight, - - errorText: !isInverted ? palette.redDark : '#ff5f5f', - inputBorder: palette.neutralTertiary, - inputBackground: palette.white, - inputFocusBorderAlt: palette.themePrimary, - inputText: palette.neutralPrimary, - inputPlaceholderText: palette.neutralSecondary, - - buttonBackground: palette.neutralLighter, - buttonBackgroundChecked: palette.neutralTertiaryAlt, - buttonBackgroundHovered: palette.neutralLight, - buttonBackgroundPressed: palette.neutralLight, - buttonBackgroundDisabled: palette.neutralLighter, - buttonBorder: palette.neutralSecondaryAlt, - buttonText: isInverted ? palette.black : palette.neutralPrimary, - buttonTextHovered: isInverted ? palette.neutralPrimary : palette.neutralDark, - buttonTextChecked: palette.neutralDark, - buttonTextPressed: palette.neutralDark, - buttonTextDisabled: palette.neutralTertiary, - buttonBorderDisabled: palette.neutralLighter, - buttonBorderFocused: palette.neutralSecondaryAlt, - - primaryButtonBackground: palette.themePrimary, - primaryButtonBackgroundHovered: palette.themeDarkAlt, - primaryButtonBackgroundPressed: palette.themeDark, - primaryButtonBackgroundDisabled: palette.neutralLighter, - primaryButtonBorder: 'transparent', - primaryButtonBorderFocused: 'transparent', - primaryButtonText: palette.white, - primaryButtonTextHovered: palette.white, - primaryButtonTextPressed: palette.white, - primaryButtonTextDisabled: palette.neutralQuaternary, - - accentButtonBackground: palette.accent, - - menuBackground: isInverted ? palette.neutralLighter : palette.white, - menuDivider: palette.neutralTertiaryAlt, - menuIcon: isInverted ? palette.themeDarkAlt : palette.themePrimary, - menuItemBackgroundHovered: isInverted ? palette.neutralQuaternaryAlt : palette.neutralLighter, - menuItemBackgroundPressed: isInverted ? palette.neutralQuaternary : palette.neutralLight, - menuItemText: palette.neutralPrimary, - menuItemTextHovered: palette.neutralDark, - - listHeaderBackgroundHovered: palette.neutralLighter, - listHeaderBackgroundPressed: palette.neutralLight, - - actionLink: palette.neutralPrimary, - link: palette.themePrimary, - linkHovered: palette.themeDarker, - linkPressed: palette.themeDark, - - defaultBackground: palette.neutralLighter, - defaultBorder: palette.neutralSecondaryAlt, - defaultContent: isInverted ? palette.black : palette.neutralPrimary, - defaultIcon: isInverted ? palette.black : palette.neutralPrimary, - - defaultHoveredBackground: palette.neutralLight, - defaultHoveredBorder: palette.neutralSecondaryAlt, - defaultHoveredContent: isInverted ? palette.neutralPrimary : palette.neutralDark, - defaultHoveredIcon: isInverted ? palette.neutralPrimary : palette.neutralDark, - - defaultFocusedBackground: palette.neutralLight, - defaultFocusedBorder: palette.neutralSecondaryAlt, - defaultFocusedContent: isInverted ? palette.neutralPrimary : palette.neutralDark, - defaultFocusedIcon: isInverted ? palette.neutralPrimary : palette.neutralDark, - - defaultPressedBackground: palette.neutralLight, - defaultPressedBorder: palette.neutralSecondaryAlt, - defaultPressedContent: palette.neutralDark, - defaultPressedIcon: palette.neutralDark, - - defaultDisabledBackground: palette.neutralLighter, - defaultDisabledBorder: palette.neutralLighter, - defaultDisabledContent: palette.neutralTertiary, - defaultDisabledIcon: palette.neutralTertiary, - - ghostBackground: palette.white, - ghostBorder: palette.white, - ghostContent: palette.neutralPrimary, - ghostIcon: palette.neutralPrimary, - - ghostHoveredBackground: palette.neutralLighter, - ghostHoveredBorder: palette.neutralLighter, - ghostHoveredContent: palette.neutralDark, - ghostHoveredIcon: palette.neutralDark, - - ghostFocusedBackground: palette.neutralLighter, - ghostFocusedBorder: palette.neutralSecondaryAlt, - ghostFocusedContent: palette.neutralDark, - ghostFocusedIcon: palette.neutralDark, - - ghostPressedBackground: palette.neutralLight, - ghostPressedBorder: palette.neutralLight, - ghostPressedContent: palette.neutralDark, - ghostPressedIcon: palette.neutralDark, - - ghostDisabledBackground: palette.white, - ghostDisabledBorder: palette.white, - ghostDisabledContent: palette.neutralTertiary, - ghostDisabledIcon: palette.neutralTertiary, - - brandedBackground: palette.themePrimary, - brandedDisabledBorder: palette.neutralLighter, - - defaultCheckedBackground: palette.neutralTertiaryAlt, - defaultCheckedContent: palette.neutralDark, - defaultCheckedHoveredBackground: palette.neutralLight, - defaultCheckedHoveredContent: isInverted ? palette.neutralPrimary : palette.neutralDark, - - ghostCheckedBackground: palette.neutralLight, - ghostCheckedContent: palette.black, - ghostCheckedHoveredBackground: palette.neutralLighter, - ghostCheckedHoveredContent: palette.neutralDark, - ghostCheckedHoveredBorder: palette.neutralDark, - - ghostSecondaryContent: palette.neutralSecondary, - ghostFocusedSecondaryContent: palette.neutralSecondary, - ghostHoveredSecondaryContent: palette.neutralSecondary, - ghostPressedSecondaryContent: palette.neutralSecondary, - - brandedSecondaryContent: palette.neutralLighterAlt, - brandedFocusedSecondaryContent: palette.neutralLighterAlt, - brandedHoveredSecondaryContent: palette.neutralLighterAlt, - brandedPressedSecondaryContent: palette.neutralLighterAlt, - - defaultHoveredSecondaryContent: palette.neutralTertiary, - defaultPressedSecondaryContent: palette.neutralTertiary, - - checkmarkColor: palette.white, - checkboxBackground: palette.themePrimary, - checkboxBackgroundDisabled: palette.neutralLighter, - checkboxBorderColor: palette.neutralSecondaryAlt, - - personaActivityRing: palette.white, - personaActivityGlow: palette.themePrimary, - }; -} - -export function getStockWebHighContrastPalette(): ThemeColorDefinition { - return { - background: '#000000', - bodyStandoutBackground: '#000000', - bodyFrameBackground: '#000000', - bodyFrameDivider: '#000000', - bodyText: '#ffffff', - bodyTextChecked: '#000000', - subText: '#ffffff', - bodyDivider: '#ffffff', - - disabledBackground: '#000000', - disabledText: '#3ff23f', - disabledBodyText: '#3ff23f', - - focusBorder: '#ffffff', - variantBorder: '#ffffff', - - errorText: '#ffffff', - - inputBorder: '#ffffff', - inputBackground: '#000000', - inputFocusBorderAlt: '#ffffff', - inputText: '#ffffff', - inputPlaceholderText: '#ffffff', - - buttonBackground: '#000000', - buttonBackgroundChecked: '#1aebff', - buttonBackgroundHovered: '#1aebff', - buttonBackgroundPressed: '#1aebff', - buttonBackgroundDisabled: '#000000', - buttonBorder: '#ffffff', - buttonText: '#ffffff', - buttonTextHovered: '#000000', - buttonTextChecked: '#000000', - buttonTextPressed: '#000000', - buttonTextDisabled: '#3ff23f', - buttonBorderDisabled: '#3ff23f', - buttonBorderFocused: '#ffffff', - - primaryButtonBackground: '#000000', - primaryButtonBackgroundHovered: '#1aebff', - primaryButtonBackgroundPressed: '#1aebff', - primaryButtonBackgroundDisabled: '#000000', - primaryButtonBorder: '#ffffff', - primaryButtonBorderFocused: '#ffffff', - primaryButtonText: '#ffffff', - primaryButtonTextHovered: '#000000', - primaryButtonTextPressed: '#000000', - primaryButtonTextDisabled: '#3ff23f', - - accentButtonBackground: '#000000', - - menuBackground: '#000000', - menuDivider: '#ffffff', - menuIcon: '#ffffff', - menuItemBackgroundHovered: '#1aebff', - menuItemBackgroundPressed: '#1aebff', - menuItemText: '#ffffff', - menuItemTextHovered: '#000000', - - listHeaderBackgroundHovered: '#1aebff', - listHeaderBackgroundPressed: '#1aebff', - - actionLink: '#ffff00', - link: '#ffff00', - linkHovered: '#ffffff', - linkPressed: '#ffffff', - - defaultBackground: '#000000', - defaultBorder: '#ffffff', - defaultContent: '#ffffff', - defaultIcon: '#ffffff', - - defaultHoveredBackground: '#1aebff', - defaultHoveredBorder: '#1aebff', - defaultHoveredContent: '#000000', - defaultHoveredIcon: '#000000', - - defaultFocusedBackground: '#000000', - defaultFocusedBorder: '#ffffff', - defaultFocusedContent: '#ffffff', - defaultFocusedIcon: '#ffffff', - - defaultPressedBackground: '#1aebff', - defaultPressedBorder: '#1aebff', - defaultPressedContent: '#000000', - defaultPressedIcon: '#000000', - - defaultDisabledBackground: '#000000', - defaultDisabledBorder: '#3ff23f', - defaultDisabledContent: '#3ff23f', - defaultDisabledIcon: '#3ff23f', - - ghostBackground: '#000000', - ghostBorder: '#000000', - ghostContent: '#ffffff', - ghostIcon: '#ffffff', - - ghostHoveredBackground: '#1aebff', - ghostHoveredBorder: '#1aebff', - ghostHoveredContent: '#000000', - ghostHoveredIcon: '#000000', - - ghostFocusedBackground: '#000000', - ghostFocusedBorder: '#ffffff', - ghostFocusedContent: '#ffffff', - ghostFocusedIcon: '#ffffff', - - ghostPressedBackground: '#1aebff', - ghostPressedBorder: '#1aebff', - ghostPressedContent: '#000000', - ghostPressedIcon: '#000000', - - ghostDisabledBackground: '#000000', - ghostDisabledBorder: '#000000', - ghostDisabledContent: '#3ff23f', - ghostDisabledIcon: '#3ff23f', - - brandedBackground: '#000000', - brandedDisabledBorder: '#3ff23f', - - defaultCheckedBackground: '#1aebff', - defaultCheckedContent: '#000000', - defaultCheckedHoveredBackground: '#1aebff', - defaultCheckedHoveredContent: '#000000', - - ghostCheckedBackground: '#1aebff', - ghostCheckedContent: '#000000', - ghostCheckedHoveredBackground: '#1aebff', - ghostCheckedHoveredContent: '#000000', - ghostCheckedHoveredBorder: '#000000', - - ghostSecondaryContent: '#ffffff', - ghostFocusedSecondaryContent: '#ffffff', - ghostHoveredSecondaryContent: '#000000', - ghostPressedSecondaryContent: '#000000', - - brandedSecondaryContent: '#ffffff', - brandedFocusedSecondaryContent: '#ffffff', - brandedHoveredSecondaryContent: '#000000', - brandedPressedSecondaryContent: '#000000', - - defaultHoveredSecondaryContent: '#000000', - defaultPressedSecondaryContent: '#000000', - - checkmarkColor: '#ffffff', - checkboxBackground: '#000000', - checkboxBackgroundDisabled: '#000000', - checkboxBorderColor: '#ffffff', - - personaActivityRing: '#ffffff', - personaActivityGlow: 'transparent', - ...createLegacyColorAliasTokens('highContrast'), - }; -} diff --git a/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.test.ts b/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.test.ts deleted file mode 100644 index 890d5431f0..0000000000 --- a/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.test.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { getDefaultLegacyTheme } from './defaultLegacyTheme'; - -const light = { - colorScheme: 'light', - contrast: 'standard', - interfaceLevel: 'base', -} as const; -const dark = { - colorScheme: 'dark', - contrast: 'standard', - interfaceLevel: 'base', -} as const; -const darkElevated = { - colorScheme: 'dark', - contrast: 'standard', - interfaceLevel: 'elevated', -} as const; -const highContrast = { - colorScheme: 'dark', - contrast: 'highContrast', - interfaceLevel: 'base', -} as const; - -describe('getDefaultLegacyTheme', () => { - it('shares one legacy base across color tones', () => { - const lightTheme = getDefaultLegacyTheme(light); - - expect(getDefaultLegacyTheme({ ...light, colorTone: 'cool' })).toBe(lightTheme); - expect(getDefaultLegacyTheme({ ...light, colorTone: 'warm' })).toBe(lightTheme); - }); - - it('creates complete stable legacy bases lazily per resolved appearance', () => { - const lightTheme = getDefaultLegacyTheme(light); - const darkTheme = getDefaultLegacyTheme(dark); - - expect(getDefaultLegacyTheme(light)).toBe(lightTheme); - expect(getDefaultLegacyTheme(dark)).toBe(darkTheme); - expect(darkTheme).not.toBe(lightTheme); - - for (const theme of [lightTheme, darkTheme]) { - expect(theme.colors.background).toBeDefined(); - expect(theme.colors.bodyText).toBeDefined(); - expect(theme.colors.disabledText).toBeDefined(); - expect(theme.colors.inputBackground).toBeDefined(); - expect(theme.colors.buttonBackground).toBeDefined(); - expect(theme.colors.primaryButtonBackground).toBeDefined(); - expect(theme.colors.menuBackground).toBeDefined(); - expect(theme.colors.link).toBeDefined(); - expect(theme.typography.families.primary).toBeDefined(); - expect(theme.typography.sizes.body).toBeDefined(); - expect(theme.typography.weights.regular).toBeDefined(); - expect(theme.typography.variants.bodyStandard).toBeDefined(); - expect(theme.shadows.shadow2).toBeDefined(); - expect(theme.shadows.shadow64).toBeDefined(); - expect(theme.spacing.s1).toBeDefined(); - expect(theme.components).toEqual({}); - } - }); - - it('preserves elevated-dark and high-contrast compatibility appearances', () => { - const elevatedTheme = getDefaultLegacyTheme(darkElevated); - const highContrastTheme = getDefaultLegacyTheme(highContrast); - - expect(elevatedTheme.host.appearance).toBe('darkElevated'); - expect(elevatedTheme.colors.background).toBe(getDefaultLegacyTheme(dark).colors.background); - expect(highContrastTheme.host.appearance).toBe('highContrast'); - expect(highContrastTheme.colors.background).toBe('#000000'); - expect(highContrastTheme.colors.bodyText).toBe('#ffffff'); - }); -}); diff --git a/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts b/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts deleted file mode 100644 index 3a04d029e5..0000000000 --- a/packages/agentic/design/src/fluent/compat/defaultLegacyTheme.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { Platform } from 'react-native'; - -import { fontWeightRegular, fontWeightSemibold } from '../../tokens/global.generated'; -import globalTokens from '../tokens/tokens-global'; -import { appearanceOptionFromResolved, legacyThemeAppearanceKey } from '../../theming/appearance'; -import type { ResolvedThemeAppearance } from '../../types/appearance.types'; -import type { Theme, Spacing } from '../types/Theme.types'; -import type { FontSize, FontSizes, FontWeightValue, Typography, Variants } from '../types/Typography.types'; - -import { createLegacyShadowAliasTokens } from './createLegacyAliasTokens'; -import { getStockWebHighContrastPalette } from './defaultLegacyColors'; -import { getStockWebDarkPalette, getStockWebPalette } from './stockWebPalette'; - -let defaultTypography: Typography | undefined; -let defaultSpacing: Spacing | undefined; -const defaultThemes = new Map<string, Theme>(); - -function getDefaultTypography(): Typography { - if (defaultTypography) { - return defaultTypography; - } - - const typography = { - sizes: { - caption: globalTokens.font.size100 as FontSize, - secondary: globalTokens.font.size200 as FontSize, - body: globalTokens.font.size300 as FontSize, - subheader: globalTokens.font.size400 as FontSize, - header: globalTokens.font.size500 as FontSize, - hero: globalTokens.font.size700 as FontSize, - heroLarge: globalTokens.font.size900 as FontSize, - } as FontSizes, - weights: { - regular: fontWeightRegular as FontWeightValue, - semiBold: fontWeightSemibold as FontWeightValue, - }, - families: { - primary: 'Segoe UI', - secondary: 'Segoe UI', - cursive: 'System', - monospace: 'System', - numeric: 'System', - sansSerif: 'System', - serif: 'System', - }, - variants: { - captionStandard: { face: 'primary', size: 'caption', weight: 'regular' }, - secondaryStandard: { face: 'primary', size: 'secondary', weight: 'regular' }, - secondarySemibold: { face: 'primary', size: 'secondary', weight: 'semiBold' }, - bodyStandard: { face: 'primary', size: 'body', weight: 'regular' }, - bodySemibold: { face: 'primary', size: 'body', weight: 'semiBold' }, - subheaderStandard: { face: 'primary', size: 'subheader', weight: 'regular' }, - subheaderSemibold: { face: 'primary', size: 'subheader', weight: 'semiBold' }, - headerStandard: { face: 'primary', size: 'header', weight: 'regular' }, - headerSemibold: { face: 'primary', size: 'header', weight: 'semiBold' }, - heroStandard: { face: 'primary', size: 'hero', weight: 'regular' }, - heroSemibold: { face: 'primary', size: 'hero', weight: 'semiBold' }, - heroLargeStandard: { face: 'primary', size: 'heroLarge', weight: 'regular' }, - heroLargeSemibold: { face: 'primary', size: 'heroLarge', weight: 'semiBold' }, - caption1: { face: 'primary', size: 'caption', weight: 'regular' }, - caption1Strong: { face: 'primary', size: 'caption', weight: 'semiBold' }, - body1: { face: 'primary', size: 'secondary', weight: 'regular' }, - body1Strong: { face: 'primary', size: 'secondary', weight: 'semiBold' }, - body2: { face: 'primary', size: 'body', weight: 'regular' }, - body2Strong: { face: 'primary', size: 'body', weight: 'semiBold' }, - subtitle1: { face: 'primary', size: 'header', weight: 'regular' }, - subtitle1Strong: { face: 'primary', size: 'header', weight: 'semiBold' }, - subtitle2: { face: 'primary', size: 'subheader', weight: 'regular' }, - subtitle2Strong: { face: 'primary', size: 'subheader', weight: 'semiBold' }, - title1: { face: 'primary', size: 'hero', weight: 'regular' }, - title1Strong: { face: 'primary', size: 'hero', weight: 'semiBold' }, - largeTitle: { face: 'primary', size: 'heroLarge', weight: 'regular' }, - display: { face: 'primary', size: 'heroLarge', weight: 'semiBold' }, - } as Variants, - }; - - if (Platform.OS === 'macos' || Platform.OS === 'ios') { - typography.families = { - primary: 'System', - secondary: 'System', - cursive: 'System', - monospace: 'System', - numeric: 'System', - sansSerif: 'System', - serif: 'System', - }; - } - - defaultTypography = typography; - return typography; -} - -function getDefaultSpacing(): Spacing { - defaultSpacing ??= { - s2: '4px', - s1: '8px', - m: '16px', - l1: '20px', - l2: '32px', - }; - return defaultSpacing; -} - -/** - * Returns a complete legacy Theme without constructing any other appearance. - * The result is stable for one resolved appearance and safe to use as an - * immutable base for Flex-to-legacy projection. Legacy themes do not vary by - * tone, so every tone shares one Theme identity. - */ -export function getDefaultLegacyTheme(appearance: ResolvedThemeAppearance): Theme { - const key = legacyThemeAppearanceKey(appearance); - const cached = defaultThemes.get(key); - if (cached) { - return cached; - } - - const highContrast = appearance.contrast === 'highContrast'; - const dark = appearance.colorScheme === 'dark'; - const darkAppearance = appearance.interfaceLevel === 'elevated' ? 'darkElevated' : 'dark'; - const colors = highContrast ? getStockWebHighContrastPalette() : dark ? getStockWebDarkPalette(darkAppearance) : getStockWebPalette(); - const tokenAppearance = highContrast ? 'highContrast' : dark ? 'dark' : 'light'; - const theme: Theme = { - colors, - typography: getDefaultTypography(), - spacing: getDefaultSpacing(), - shadows: createLegacyShadowAliasTokens(tokenAppearance), - components: {}, - host: { - appearance: appearanceOptionFromResolved(appearance), - }, - }; - - defaultThemes.set(key, theme); - return theme; -} diff --git a/packages/agentic/design/src/fluent/compat/index.ts b/packages/agentic/design/src/fluent/compat/index.ts index af898637d1..d730c0c4db 100644 --- a/packages/agentic/design/src/fluent/compat/index.ts +++ b/packages/agentic/design/src/fluent/compat/index.ts @@ -1,3 +1,2 @@ -export { getDefaultLegacyTheme } from './defaultLegacyTheme'; export { themeFromFlexTokens } from './themeFromFlexTokens'; export type { FlatFlexTokens, ThemeFromFlexTokensOptions } from './themeFromFlexTokens'; diff --git a/packages/agentic/design/src/fluent/compat/stockWebPalette.macos.ts b/packages/agentic/design/src/fluent/compat/stockWebPalette.macos.ts deleted file mode 100644 index f5f729421e..0000000000 --- a/packages/agentic/design/src/fluent/compat/stockWebPalette.macos.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { colorBlack, colorBurgundyPrimary, colorRedPrimary, colorWhite } from '../../tokens/global.generated'; -import globalTokens from '../tokens/tokens-global'; -import type { ThemeColorDefinition } from '../types/Color.types'; - -import { createLegacyColorAliasTokens } from './createLegacyAliasTokens'; -import { paletteFromFabricColors } from './defaultLegacyColors'; - -export function getStockWebPalette(): ThemeColorDefinition { - return { - ...paletteFromFabricColors({ - black: colorBlack, - neutralDark: '#201f1e', - neutralPrimary: '#323130', - neutralPrimaryAlt: '#3b3a39', - neutralSecondary: '#605e5c', - neutralSecondaryAlt: '#8a8886', - neutralTertiary: '#a19f9d', - neutralTertiaryAlt: '#c8c6c4', - neutralQuaternary: '#d2d0ce', - neutralQuaternaryAlt: '#e1dfdd', - neutralLight: '#edebe9', - neutralLighter: '#f3f2f1', - neutralLighterAlt: '#faf9f8', - white: colorWhite, - red: colorRedPrimary, - redDark: colorBurgundyPrimary, - themeDarker: globalTokens.color.brand.shade40, - themeDark: globalTokens.color.brand.shade20, - themeDarkAlt: globalTokens.color.brand.shade10, - themePrimary: globalTokens.color.brand.primary, - themeSecondary: '#2b88d8', - themeTertiary: '#71afe5', - themeLight: globalTokens.color.brand.tint40, - themeLighter: globalTokens.color.brand.tint50, - themeLighterAlt: globalTokens.color.brand.tint60, - accent: globalTokens.color.brand.primary, - blackTranslucent40: 'rgba(0,0,0,.4)', - }), - ...createLegacyColorAliasTokens('light'), - }; -} - -export function getStockWebDarkPalette(appearance: 'dark' | 'darkElevated' = 'dark'): ThemeColorDefinition { - return { - ...paletteFromFabricColors( - { - themeDarker: '#82c7ff', - themeDark: globalTokens.color.brand.tint30, - themeDarkAlt: globalTokens.color.brand.tint20, - themePrimary: globalTokens.color.brand.tint10, - themeSecondary: globalTokens.color.brand.primary, - themeTertiary: '#235a85', - themeLight: globalTokens.color.brand.shade30, - themeLighter: globalTokens.color.brand.shade50, - themeLighterAlt: globalTokens.color.brand.shade60, - black: colorWhite, - neutralDark: '#faf9f8', - neutralPrimary: '#f3f2f1', - neutralPrimaryAlt: '#c8c6c4', - neutralSecondary: '#a19f9d', - neutralSecondaryAlt: '#979693', - neutralTertiary: '#797775', - neutralTertiaryAlt: '#484644', - neutralQuaternary: '#3b3a39', - neutralQuaternaryAlt: '#323130', - neutralLight: '#292827', - neutralLighter: '#252423', - neutralLighterAlt: '#201f1e', - white: '#1b1a19', - red: colorRedPrimary, - accent: globalTokens.color.brand.primary, - redDark: '#f1707b', - blackTranslucent40: 'rgba(0,0,0,.4)', - }, - true, - ), - ...createLegacyColorAliasTokens(appearance), - }; -} diff --git a/packages/agentic/design/src/fluent/compat/stockWebPalette.ts b/packages/agentic/design/src/fluent/compat/stockWebPalette.ts deleted file mode 100644 index c4168fb51b..0000000000 --- a/packages/agentic/design/src/fluent/compat/stockWebPalette.ts +++ /dev/null @@ -1,100 +0,0 @@ -/* eslint-disable @typescript-eslint/ban-ts-comment */ -import { colorBlack, colorBurgundyPrimary, colorRedPrimary, colorWhite } from '../../tokens/global.generated'; -import globalTokens from '../tokens/tokens-global'; -import type { ThemeColorDefinition } from '../types/Color.types'; - -import { createLegacyColorAliasTokens } from './createLegacyAliasTokens'; -import { paletteFromFabricColors } from './defaultLegacyColors'; - -export function getStockWebPalette(): ThemeColorDefinition { - return { - ...paletteFromFabricColors({ - black: colorBlack, - neutralDark: '#201f1e', - neutralPrimary: '#323130', - neutralPrimaryAlt: '#3b3a39', - neutralSecondary: '#605e5c', - neutralSecondaryAlt: '#8a8886', - neutralTertiary: '#a19f9d', - neutralTertiaryAlt: '#c8c6c4', - neutralQuaternary: '#d2d0ce', - neutralQuaternaryAlt: '#e1dfdd', - neutralLight: '#edebe9', - neutralLighter: '#f3f2f1', - neutralLighterAlt: '#faf9f8', - white: colorWhite, - red: colorRedPrimary, - redDark: colorBurgundyPrimary, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - accent: globalTokens.color.brand80, - blackTranslucent40: 'rgba(0,0,0,.4)', - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeDarker: globalTokens.color.brand40, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeDark: globalTokens.color.brand60, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeDarkAlt: globalTokens.color.brand70, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themePrimary: globalTokens.color.brand80, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeSecondary: globalTokens.color.brand90, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeTertiary: globalTokens.color.brand120, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeLight: globalTokens.color.brand140, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeLighter: globalTokens.color.brand150, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeLighterAlt: globalTokens.color.brand160, - }), - ...createLegacyColorAliasTokens('light'), - }; -} - -export function getStockWebDarkPalette(appearance: 'dark' | 'darkElevated' = 'dark'): ThemeColorDefinition { - return { - ...paletteFromFabricColors( - { - black: colorWhite, - neutralDark: '#faf9f8', - neutralPrimary: '#f3f2f1', - neutralPrimaryAlt: '#c8c6c4', - neutralSecondary: '#a19f9d', - neutralSecondaryAlt: '#979693', - neutralTertiary: '#797775', - neutralTertiaryAlt: '#484644', - neutralQuaternary: '#3b3a39', - neutralQuaternaryAlt: '#323130', - neutralLight: '#292827', - neutralLighter: '#252423', - neutralLighterAlt: '#201f1e', - white: '#1b1a19', - red: colorRedPrimary, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - accent: globalTokens.color.brand40, - redDark: '#f1707b', - blackTranslucent40: 'rgba(0,0,0,.4)', - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeDarker: globalTokens.color.brand110, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeDark: globalTokens.color.brand100, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeDarkAlt: globalTokens.color.brand100, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themePrimary: globalTokens.color.brand90, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeSecondary: globalTokens.color.brand90, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeTertiary: globalTokens.color.brand60, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeLight: globalTokens.color.brand50, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeLighter: globalTokens.color.brand40, - // @ts-expect-error The mobile token payloads retain the legacy flat brand ramp. - themeLighterAlt: globalTokens.color.brand30, - }, - true, - ), - ...createLegacyColorAliasTokens(appearance), - }; -} diff --git a/packages/agentic/design/src/fluent/compat/stockWebPalette.win32.ts b/packages/agentic/design/src/fluent/compat/stockWebPalette.win32.ts deleted file mode 100644 index f5f729421e..0000000000 --- a/packages/agentic/design/src/fluent/compat/stockWebPalette.win32.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { colorBlack, colorBurgundyPrimary, colorRedPrimary, colorWhite } from '../../tokens/global.generated'; -import globalTokens from '../tokens/tokens-global'; -import type { ThemeColorDefinition } from '../types/Color.types'; - -import { createLegacyColorAliasTokens } from './createLegacyAliasTokens'; -import { paletteFromFabricColors } from './defaultLegacyColors'; - -export function getStockWebPalette(): ThemeColorDefinition { - return { - ...paletteFromFabricColors({ - black: colorBlack, - neutralDark: '#201f1e', - neutralPrimary: '#323130', - neutralPrimaryAlt: '#3b3a39', - neutralSecondary: '#605e5c', - neutralSecondaryAlt: '#8a8886', - neutralTertiary: '#a19f9d', - neutralTertiaryAlt: '#c8c6c4', - neutralQuaternary: '#d2d0ce', - neutralQuaternaryAlt: '#e1dfdd', - neutralLight: '#edebe9', - neutralLighter: '#f3f2f1', - neutralLighterAlt: '#faf9f8', - white: colorWhite, - red: colorRedPrimary, - redDark: colorBurgundyPrimary, - themeDarker: globalTokens.color.brand.shade40, - themeDark: globalTokens.color.brand.shade20, - themeDarkAlt: globalTokens.color.brand.shade10, - themePrimary: globalTokens.color.brand.primary, - themeSecondary: '#2b88d8', - themeTertiary: '#71afe5', - themeLight: globalTokens.color.brand.tint40, - themeLighter: globalTokens.color.brand.tint50, - themeLighterAlt: globalTokens.color.brand.tint60, - accent: globalTokens.color.brand.primary, - blackTranslucent40: 'rgba(0,0,0,.4)', - }), - ...createLegacyColorAliasTokens('light'), - }; -} - -export function getStockWebDarkPalette(appearance: 'dark' | 'darkElevated' = 'dark'): ThemeColorDefinition { - return { - ...paletteFromFabricColors( - { - themeDarker: '#82c7ff', - themeDark: globalTokens.color.brand.tint30, - themeDarkAlt: globalTokens.color.brand.tint20, - themePrimary: globalTokens.color.brand.tint10, - themeSecondary: globalTokens.color.brand.primary, - themeTertiary: '#235a85', - themeLight: globalTokens.color.brand.shade30, - themeLighter: globalTokens.color.brand.shade50, - themeLighterAlt: globalTokens.color.brand.shade60, - black: colorWhite, - neutralDark: '#faf9f8', - neutralPrimary: '#f3f2f1', - neutralPrimaryAlt: '#c8c6c4', - neutralSecondary: '#a19f9d', - neutralSecondaryAlt: '#979693', - neutralTertiary: '#797775', - neutralTertiaryAlt: '#484644', - neutralQuaternary: '#3b3a39', - neutralQuaternaryAlt: '#323130', - neutralLight: '#292827', - neutralLighter: '#252423', - neutralLighterAlt: '#201f1e', - white: '#1b1a19', - red: colorRedPrimary, - accent: globalTokens.color.brand.primary, - redDark: '#f1707b', - blackTranslucent40: 'rgba(0,0,0,.4)', - }, - true, - ), - ...createLegacyColorAliasTokens(appearance), - }; -} diff --git a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts index d02fa3b449..b73e2c2083 100644 --- a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts +++ b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.test.ts @@ -2,9 +2,14 @@ import { createInteractiveColor } from '../../flex/colors/interactiveColor'; import { defaultFlexTokens } from '../../flex/defaults/defaultTokens'; import type { FlexTokens, SemanticColorTokenValues } from '../../flex/tokens.types'; import { restColorValues } from '../../test/fixtures/interactionColors'; -import type { PartialTheme } from '../types/Theme.types'; +import { fluentDarkTheme } from '../../themes/fluent/fluentDarkTheme'; +import { fluentHcDarkTheme } from '../../themes/fluent/fluentHcDarkTheme'; +import { fluentHcLightTheme } from '../../themes/fluent/fluentHcLightTheme'; +import { fluentLightTheme } from '../../themes/fluent/fluentLightTheme'; +import reverseProjection from '../../tokens/mappings/theme-from-flex.json' with { type: 'json' }; +import type { ResolvedThemeAppearance } from '../../types/appearance.types'; +import type { PartialTheme, Theme } from '../types/Theme.types'; -import { getDefaultLegacyTheme } from './defaultLegacyTheme'; import { themeFromFlexTokens } from './themeFromFlexTokens'; import type { FlatFlexTokens } from './themeFromFlexTokens'; @@ -13,6 +18,7 @@ const light = { contrast: 'standard', interfaceLevel: 'base', } as const; +const dark = { ...light, colorScheme: 'dark' } as const; function solid(value: string) { return createInteractiveColor(value, value, value); @@ -44,6 +50,31 @@ function createTokens(): FlexTokens { } describe('themeFromFlexTokens', () => { + it.each([ + [light, fluentLightTheme], + [dark, fluentDarkTheme], + [{ ...dark, interfaceLevel: 'elevated' }, fluentDarkTheme], + [{ ...light, contrast: 'highContrast' }, fluentHcLightTheme], + [{ ...dark, contrast: 'highContrast' }, fluentHcDarkTheme], + ] as [ResolvedThemeAppearance, Theme][])('fills values Flex cannot represent from the Fluent theme for %o', (appearance, base) => { + const baseline = JSON.stringify(base); + const projectedPaths = new Set(Object.keys(reverseProjection)); + const unmappedColors = Object.keys(base.colors).filter((name) => !projectedPaths.has(`colors.${name}`)); + + const theme = themeFromFlexTokens(createTokens(), appearance, { + fallback: { colors: { customLegacyColor: '#abcdef' } } as PartialTheme, + }); + + expect(unmappedColors.length).toBeGreaterThan(0); + for (const name of unmappedColors) { + expect([name, theme.colors[name]]).toEqual([name, base.colors[name]]); + } + expect(theme.typography.variants).toEqual(base.typography.variants); + expect(theme.spacing).toEqual(base.spacing); + expect(theme).not.toBe(base); + expect(JSON.stringify(base)).toBe(baseline); + }); + it('merges the base, legacy fallback, mapped Flex values, and final appearance in order', () => { const fallback = { name: 'Host theme', @@ -150,7 +181,7 @@ describe('themeFromFlexTokens', () => { expect(theme.shadows.shadow2).toEqual({ ambient: contour, key: keyLayer }); expect(theme.shadows.shadow4).toEqual({ ambient: keyLayer, key: keyLayer }); - expect(theme.shadows.shadow8).toEqual(getDefaultLegacyTheme(light).shadows.shadow8); + expect(theme.shadows.shadow8).toEqual(fluentLightTheme.shadows.shadow8); expect(theme.shadows.shadow16).toEqual({ ambient: defaultFlexTokens.shadow.high[0], key: defaultFlexTokens.shadow.high.at(-1) }); }); diff --git a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts index 01c43bfbfa..f79b5fdc15 100644 --- a/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts +++ b/packages/agentic/design/src/fluent/compat/themeFromFlexTokens.ts @@ -1,4 +1,5 @@ import type { FlexTokens, SemanticColorTokenValues, SemanticMotion, SemanticShadows, SemanticSpacing } from '../../flex/tokens.types'; +import { selectFluentTheme } from '../../themes/fluent/selectFluentTheme'; import reverseProjection from '../../tokens/mappings/theme-from-flex.json' with { type: 'json' }; import { appearanceOptionFromResolved } from '../../theming/appearance'; import type { ResolvedThemeAppearance } from '../../types/appearance.types'; @@ -7,8 +8,6 @@ import { mergeTheme } from '../mergeTheme'; import type { ShadowToken } from '../types/Shadow.types'; import type { PartialTheme, Theme } from '../types/Theme.types'; -import { getDefaultLegacyTheme } from './defaultLegacyTheme'; - type ReverseTransform = 'numberToPx' | 'shadowLayersToToken'; type ReverseProjectionEntry = { @@ -122,20 +121,20 @@ function projectThemeValues(tokens: FlexTokens | FlatFlexTokens): PartialTheme { /** * Project Flex tokens into a complete legacy Theme. * - * The compatibility base fills legacy-only values, the optional fallback adds - * author or host metadata, mapped Flex values remain authoritative, and the - * final host appearance reflects the resolved structured appearance. Reading - * a derived interaction state computes it. Layered Flex shadows project - * lossily to legacy { ambient, key } shadows: the first layer is ambient, the - * last is key, and middle layers are dropped. An empty shadow keeps the - * legacy base shadow. + * The Fluent theme for the appearance fills values that Flex cannot represent, + * the optional fallback adds author or host metadata, mapped Flex values remain + * authoritative, and the final host appearance reflects the resolved + * structured appearance. Reading a derived interaction state computes it. + * Layered Flex shadows project lossily to legacy { ambient, key } shadows: the + * first layer is ambient, the last is key, and middle layers are dropped. An + * empty shadow keeps the Fluent theme's shadow. */ export function themeFromFlexTokens( tokens: FlexTokens | FlatFlexTokens, appearance: ResolvedThemeAppearance, options?: { fallback?: Theme | PartialTheme }, ): Theme { - let theme = getDefaultLegacyTheme(appearance); + let theme = selectFluentTheme(appearance); if (options?.fallback) { theme = mergeTheme(theme, options.fallback as PartialTheme); } diff --git a/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts b/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts index a6794f1d8a..bcabc13d5a 100644 --- a/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts +++ b/packages/agentic/design/src/fluent/defaults/fluentTokens.test.ts @@ -12,15 +12,15 @@ import hcAliasTokens from '@fluentui-react-native/design-tokens-win32/hc/tokens- import hcShadowTokens from '@fluentui-react-native/design-tokens-win32/hc/tokens-shadow.json'; import { PlatformColor } from 'react-native'; -import { mapPipelineToShadow } from '../mapPipelineToShadow'; -import { mapFontPipelineToTheme, mapPipelineToTheme } from '../mapPipelineToTheme'; -import * as androidMapper from '../mapPipelineToTheme.android'; -import * as iosMapper from '../mapPipelineToTheme.ios'; +import { mapPipelineToShadow } from '../../deprecated/mapPipelineToShadow'; +import { mapFontPipelineToTheme, mapPipelineToTheme } from '../../deprecated/mapPipelineToTheme'; +import * as androidMapper from '../../deprecated/mapPipelineToTheme.android'; +import * as iosMapper from '../../deprecated/mapPipelineToTheme.ios'; import { processAliasTokens, transformWin32PlatformColorName, transformWindowsPlatformColorName, -} from '../tokens/highContrast/processAliasTokens'; +} from '../../deprecated/tokens/highContrast/processAliasTokens'; import * as android from './fluentTokens.generated.android'; import * as ios from './fluentTokens.generated.ios'; import * as macos from './fluentTokens.generated.macos'; diff --git a/packages/agentic/design/src/fluent/tokens/index.ts b/packages/agentic/design/src/fluent/tokens/index.ts deleted file mode 100644 index cc73c61e27..0000000000 --- a/packages/agentic/design/src/fluent/tokens/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { default as globalTokens } from './tokens-global'; -export { getAliasTokens, getShadowTokens } from './getTokens'; -export { hcAliasTokens } from './highContrast/tokens-alias'; diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap index 9ef644b2e7..e4587d1d4e 100644 --- a/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/compatibilityBaseline.test.ts.snap @@ -2,49 +2,49 @@ exports[`Flex default baseline keeps the dark legacy projection of the default Flex tokens 1`] = ` { - "colorCount": 274, - "colors": "bc2282479a31f977", + "colorCount": 318, + "colors": "00e96311260ec7a0", "components": "75484377ab62c281", "host": "e8e4ef993a27738e", "shadows": "6cc8dc2e49311041", "spacing": "ae5c5f37376210ff", - "typography": "758be399ff81061a", + "typography": "03f7ecba1c80477d", } `; exports[`Flex default baseline keeps the darkElevated legacy projection of the default Flex tokens 1`] = ` { - "colorCount": 274, - "colors": "bc2282479a31f977", + "colorCount": 318, + "colors": "00e96311260ec7a0", "components": "75484377ab62c281", "host": "f94ca80c0bbf7966", "shadows": "6cc8dc2e49311041", "spacing": "ae5c5f37376210ff", - "typography": "758be399ff81061a", + "typography": "03f7ecba1c80477d", } `; exports[`Flex default baseline keeps the highContrast legacy projection of the default Flex tokens 1`] = ` { - "colorCount": 274, - "colors": "a560e8f2d3b4fa4a", + "colorCount": 318, + "colors": "95d8ba84933eb351", "components": "75484377ab62c281", "host": "9db06d0a5ce1e422", "shadows": "6cc8dc2e49311041", "spacing": "ae5c5f37376210ff", - "typography": "758be399ff81061a", + "typography": "03f7ecba1c80477d", } `; exports[`Flex default baseline keeps the light legacy projection of the default Flex tokens 1`] = ` { - "colorCount": 274, - "colors": "9466ef021b8d326d", + "colorCount": 318, + "colors": "17121c304beef7e4", "components": "75484377ab62c281", "host": "6be4fd450402dc4f", "shadows": "6cc8dc2e49311041", "spacing": "ae5c5f37376210ff", - "typography": "758be399ff81061a", + "typography": "03f7ecba1c80477d", } `; @@ -64,12 +64,12 @@ exports[`Flex default baseline keeps the values consumers read from the default } `; -exports[`legacy compatibility baseline keeps Flex values converted from the dark default legacy theme 1`] = ` +exports[`legacy compatibility baseline keeps Flex values converted from the dark Fluent projection base 1`] = ` { "borderRadius": "13bd91dc683ef515", - "color": "8b3240b5c9086b86", + "color": "79755e1e202aa0e8", "colorCount": 119, - "fontFamily": "1563f269b690db9d", + "fontFamily": "7a4e96787cf538ad", "fontSize": "52fa58b4bacaf329", "fontWeight": "8fe4b9b24b1f62c7", "lineHeight": "e10b09e52a79eb29", @@ -80,12 +80,12 @@ exports[`legacy compatibility baseline keeps Flex values converted from the dark } `; -exports[`legacy compatibility baseline keeps Flex values converted from the darkElevated default legacy theme 1`] = ` +exports[`legacy compatibility baseline keeps Flex values converted from the darkElevated Fluent projection base 1`] = ` { "borderRadius": "13bd91dc683ef515", - "color": "8b3240b5c9086b86", + "color": "79755e1e202aa0e8", "colorCount": 119, - "fontFamily": "1563f269b690db9d", + "fontFamily": "7a4e96787cf538ad", "fontSize": "52fa58b4bacaf329", "fontWeight": "8fe4b9b24b1f62c7", "lineHeight": "e10b09e52a79eb29", @@ -96,12 +96,12 @@ exports[`legacy compatibility baseline keeps Flex values converted from the dark } `; -exports[`legacy compatibility baseline keeps Flex values converted from the highContrast default legacy theme 1`] = ` +exports[`legacy compatibility baseline keeps Flex values converted from the highContrast Fluent projection base 1`] = ` { "borderRadius": "13bd91dc683ef515", - "color": "428227abcd661352", + "color": "a6b03a11b350d9af", "colorCount": 119, - "fontFamily": "1563f269b690db9d", + "fontFamily": "7a4e96787cf538ad", "fontSize": "52fa58b4bacaf329", "fontWeight": "8fe4b9b24b1f62c7", "lineHeight": "e10b09e52a79eb29", @@ -112,12 +112,12 @@ exports[`legacy compatibility baseline keeps Flex values converted from the high } `; -exports[`legacy compatibility baseline keeps Flex values converted from the light default legacy theme 1`] = ` +exports[`legacy compatibility baseline keeps Flex values converted from the light Fluent projection base 1`] = ` { "borderRadius": "13bd91dc683ef515", - "color": "847181f1c8ec73a4", + "color": "6887e2160d35b879", "colorCount": 119, - "fontFamily": "1563f269b690db9d", + "fontFamily": "7a4e96787cf538ad", "fontSize": "52fa58b4bacaf329", "fontWeight": "8fe4b9b24b1f62c7", "lineHeight": "e10b09e52a79eb29", @@ -144,50 +144,50 @@ exports[`legacy compatibility baseline keeps Flex values converted from the mock } `; -exports[`legacy compatibility baseline keeps the dark default legacy theme 1`] = ` +exports[`legacy compatibility baseline keeps the dark Fluent projection base 1`] = ` { - "colorCount": 275, - "colors": "6e9e7b821c45c476", + "colorCount": 316, + "colors": "b56d0c7ca32cf2cf", "components": "44136fa355b3678a", "host": "e8e4ef993a27738e", "shadows": "3388fc7114c96ee3", "spacing": "ae5c5f37376210ff", - "typography": "1c07bfca1b48a07f", + "typography": "03f7ecba1c80477d", } `; -exports[`legacy compatibility baseline keeps the darkElevated default legacy theme 1`] = ` +exports[`legacy compatibility baseline keeps the darkElevated Fluent projection base 1`] = ` { - "colorCount": 275, - "colors": "6e9e7b821c45c476", + "colorCount": 316, + "colors": "b56d0c7ca32cf2cf", "components": "44136fa355b3678a", - "host": "f94ca80c0bbf7966", + "host": "e8e4ef993a27738e", "shadows": "3388fc7114c96ee3", "spacing": "ae5c5f37376210ff", - "typography": "1c07bfca1b48a07f", + "typography": "03f7ecba1c80477d", } `; -exports[`legacy compatibility baseline keeps the highContrast default legacy theme 1`] = ` +exports[`legacy compatibility baseline keeps the highContrast Fluent projection base 1`] = ` { - "colorCount": 275, - "colors": "730a40d80e103538", + "colorCount": 316, + "colors": "bc1662992dbe6db5", "components": "44136fa355b3678a", "host": "9db06d0a5ce1e422", "shadows": "3388fc7114c96ee3", "spacing": "ae5c5f37376210ff", - "typography": "1c07bfca1b48a07f", + "typography": "03f7ecba1c80477d", } `; -exports[`legacy compatibility baseline keeps the light default legacy theme 1`] = ` +exports[`legacy compatibility baseline keeps the light Fluent projection base 1`] = ` { - "colorCount": 275, - "colors": "8b685906103f0ebf", + "colorCount": 316, + "colors": "e8b1164fbd03da1f", "components": "44136fa355b3678a", "host": "6be4fd450402dc4f", "shadows": "6cb9f79865a74b20", "spacing": "ae5c5f37376210ff", - "typography": "1c07bfca1b48a07f", + "typography": "03f7ecba1c80477d", } `; diff --git a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap index cf68da9683..dfc0a221e8 100644 --- a/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap +++ b/packages/agentic/design/src/test/compatibility/__snapshots__/entryPoints.test.ts.snap @@ -43,6 +43,18 @@ exports[`public entry points ./color-lib keeps its runtime export names 1`] = ` ] `; +exports[`public entry points ./deprecated keeps its runtime export names 1`] = ` +[ + "getAliasTokens: function", + "getShadowTokens: function", + "globalTokens: object", + "hcAliasTokens: object", + "mapFontPipelineToTheme: function", + "mapPipelineToShadow: function", + "mapPipelineToTheme: function", +] +`; + exports[`public entry points ./styling keeps its runtime export names 1`] = ` [ "colorStyleDef: function", @@ -124,9 +136,6 @@ exports[`public entry points ./theming keeps its runtime export names 1`] = ` "flexColor: function", "getCurrentAppearance: function", "isHighContrast: function", - "mapFontPipelineToTheme: function", - "mapPipelineToShadow: function", - "mapPipelineToTheme: function", "normalizeThemeAppearanceRequest: function", "resolveThemeAppearance: function", "selectColorEntry: function", @@ -141,17 +150,10 @@ exports[`public entry points ./theming keeps its runtime export names 1`] = ` exports[`public entry points ./theming/compat keeps its runtime export names 1`] = ` [ - "getDefaultLegacyTheme: function", "themeFromFlexTokens: function", ] `; -exports[`public entry points ./theming/compat/defaults keeps its runtime export names 1`] = ` -[ - "getDefaultLegacyTheme: function", -] -`; - exports[`public entry points ./theming/legacy-source keeps its runtime export names 1`] = ` [ "ThemeReference: function", @@ -1028,12 +1030,3 @@ exports[`public entry points ./tokens/global keeps its runtime export names 1`] "strokeWidthNone: number", ] `; - -exports[`public entry points ./tokens/legacy keeps its runtime export names 1`] = ` -[ - "getAliasTokens: function", - "getShadowTokens: function", - "globalTokens: object", - "hcAliasTokens: object", -] -`; diff --git a/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts b/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts index 93a5015d41..10eef486f8 100644 --- a/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts +++ b/packages/agentic/design/src/test/compatibility/compatibilityBaseline.test.ts @@ -1,7 +1,7 @@ import { PlatformColor } from 'react-native'; -import { getDefaultLegacyTheme } from '../../fluent/compat/defaultLegacyTheme'; import { themeFromFlexTokens } from '../../fluent/compat/themeFromFlexTokens'; +import { selectFluentTheme } from '../../themes/fluent/selectFluentTheme'; import type { ResolvedThemeAppearance } from '../../types/appearance.types'; import type { Theme } from '../../fluent/types/Theme.types'; import { mockTheme } from '../fixtures/mockTheme'; @@ -23,12 +23,12 @@ const appearances: [string, ResolvedThemeAppearance][] = [ * those values passes unchanged. */ describe('legacy compatibility baseline', () => { - it.each(appearances)('keeps the %s default legacy theme', (_name, appearance) => { - expect(themeFingerprints(getDefaultLegacyTheme(appearance))).toMatchSnapshot(); + it.each(appearances)('keeps the %s Fluent projection base', (_name, appearance) => { + expect(themeFingerprints(selectFluentTheme(appearance))).toMatchSnapshot(); }); - it.each(appearances)('keeps Flex values converted from the %s default legacy theme', (_name, appearance) => { - expect(flexTokenFingerprints(flexTokensFromTheme(getDefaultLegacyTheme(appearance)))).toMatchSnapshot(); + it.each(appearances)('keeps Flex values converted from the %s Fluent projection base', (_name, appearance) => { + expect(flexTokenFingerprints(flexTokensFromTheme(selectFluentTheme(appearance)))).toMatchSnapshot(); }); it('keeps Flex values converted from the mock theme', () => { diff --git a/packages/agentic/design/src/test/compatibility/entryPoints.test.ts b/packages/agentic/design/src/test/compatibility/entryPoints.test.ts index 0e91f91e56..45018161be 100644 --- a/packages/agentic/design/src/test/compatibility/entryPoints.test.ts +++ b/packages/agentic/design/src/test/compatibility/entryPoints.test.ts @@ -14,14 +14,13 @@ const packageJson = jest.requireActual<PackageJson>('../../../package.json'); const publicEntryPoints = [ '.', './tokens/global', - './tokens/legacy', './color-lib', './theming', './theming/legacy-source', './theming/compat', - './theming/compat/defaults', './themes', './testing', + './deprecated', './styling', './styling/stylesheet', './styling/tokens', diff --git a/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts b/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts index 53d064cf55..bd00e9958c 100644 --- a/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts +++ b/packages/agentic/design/src/test/compatibility/entryPoints.types.test.ts @@ -8,15 +8,20 @@ import type { ThemeAppearanceOptions as RootThemeAppearanceOptions, ThemeState, } from '../../index'; -import { getDefaultLegacyTheme as getDefaultLegacyThemeOnly } from '../../fluent/compat/defaultLegacyTheme'; -import { getDefaultLegacyTheme, themeFromFlexTokens } from '../../fluent/compat/index'; -import type { ThemeFromFlexTokensOptions } from '../../fluent/compat/index'; import { - getCurrentAppearance, - isHighContrast, + getAliasTokens, + getShadowTokens, + globalTokens, + hcAliasTokens, mapFontPipelineToTheme, mapPipelineToShadow, mapPipelineToTheme, +} from '../../deprecated/index'; +import { themeFromFlexTokens } from '../../fluent/compat/index'; +import type { ThemeFromFlexTokensOptions } from '../../fluent/compat/index'; +import { + getCurrentAppearance, + isHighContrast, resolveThemeAppearance, setIsHighContrast, ThemeContext, @@ -71,6 +76,7 @@ import { ThemeReference as LegacySourceThemeReference } from '../../fluent/legac import type { OnThemeChange as LegacySourceOnThemeChange, ThemeRecipe as LegacySourceThemeRecipe } from '../../fluent/legacySource'; import { themedStyleSheet } from '../../fluent/styling/stylesheet/index'; import type { NamedStyles } from '../../fluent/styling/stylesheet/index'; +import { fluentDarkTheme } from '../../themes/index'; import { backgroundColorTokens, borderStyles, @@ -105,7 +111,6 @@ import type { StyleFactoryOperation, TokenBuilder, } from '../../fluent/styling/tokens/index'; -import { getAliasTokens, getShadowTokens, globalTokens, hcAliasTokens } from '../../fluent/tokens/index'; /** * Every type name the compatibility packages re-export must remain importable @@ -213,8 +218,7 @@ describe('legacy compatibility types', () => { expect.objectContaining({ colorScheme: 'dark', contrast: 'standard', interfaceLevel: 'base' }), ); - const legacyTheme = getDefaultLegacyTheme(legacyAppearance); - expect(getDefaultLegacyThemeOnly(legacyAppearance)).toBe(legacyTheme); + const legacyTheme = fluentDarkTheme; expect(themeFromFlexTokens(flexTokensFromTheme(legacyTheme), legacyAppearance).host.appearance).toBe('dark'); const reference = new ThemeReference(legacyTheme, legacyTransform); diff --git a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts index d2802ffe12..3609408765 100644 --- a/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts +++ b/packages/agentic/design/src/test/compatibility/importBoundaries.test.ts @@ -152,13 +152,65 @@ describe('production code never depends on test collateral', () => { }); }); +describe('deprecated code stays behind its boundary', () => { + const deprecatedSpecifier = '@fluentui-react-native/design/deprecated'; + const tokenPackagePrefix = '@fluentui-react-native/design-tokens-'; + const nonDeprecatedProductionFiles = productionFiles.filter((file) => !toSrcPath(file).startsWith('deprecated/')); + + function importsTokenPackage(edge: ImportEdge): boolean { + return edge.specifier.startsWith(tokenPackagePrefix); + } + + it('detects the deprecated token payloads', () => { + expect(readImports(path.join(srcRoot, 'deprecated/tokens/getTokens.ts')).some(importsTokenPackage)).toBe(true); + expect(nonDeprecatedProductionFiles.length).toBeGreaterThan(50); + }); + + it('has no production import of src/deprecated or the deprecated entry point outside src/deprecated', () => { + const violations = nonDeprecatedProductionFiles.flatMap((file) => + readImports(file) + .filter((edge) => + edge.specifier.startsWith('.') + ? resolveRelative(file, edge.specifier).some((resolved) => toSrcPath(resolved).startsWith('deprecated/')) + : edge.specifier === deprecatedSpecifier || edge.specifier.startsWith(`${deprecatedSpecifier}/`), + ) + .map((edge) => `${toSrcPath(file)} -> ${edge.specifier}`), + ); + expect(violations).toEqual([]); + }); + + it('keeps the Fluent 2 token packages out of production code outside src/deprecated', () => { + const violations = nonDeprecatedProductionFiles.flatMap((file) => + readImports(file) + .filter(importsTokenPackage) + .map((edge) => `${toSrcPath(file)} -> ${edge.specifier}`), + ); + expect(violations).toEqual([]); + }); + + it('keeps every production entry point free of deprecated code', () => { + const packageJson = jest.requireActual<{ exports: Record<string, string | { 'react-native': string }> }>('../../../package.json'); + const entries = Object.entries(packageJson.exports).flatMap(([subpath, conditions]) => + typeof conditions === 'string' || subpath === './deprecated' || subpath === './testing' + ? [] + : [conditions['react-native'].slice('./src/'.length)], + ); + expect(entries).toContain('fluent/compat/index.ts'); + for (const entry of entries) { + expect([entry, reachedUnder(runtimeGraph(entry), 'deprecated/')]).toEqual([entry, []]); + } + expect(reachedUnder(runtimeGraph('deprecated/index.ts'), 'deprecated/').length).toBeGreaterThan(1); + }); +}); + describe('runtime graph ownership', () => { const legacyThemingGraph = runtimeGraph('theming/index.ts'); - it('detects the legacy projection and payloads from the legacy theming entry', () => { + it('detects the legacy projection and its Fluent base from the legacy theming entry', () => { expect(legacyThemingGraph).toContain('fluent/useTheme.ts'); expect(legacyThemingGraph).toContain('fluent/compat/themeFromFlexTokens.ts'); - expect(reachedUnder(legacyThemingGraph, 'fluent/tokens/').length).toBeGreaterThan(0); + expect(legacyThemingGraph).toContain('themes/fluent/selectFluentTheme.ts'); + expect(legacyThemingGraph).toContain('fluent/defaults/fluentTokens.generated.ts'); }); it('keeps the modern root free of legacy Fluent runtime and test collateral', () => { @@ -207,7 +259,7 @@ describe('runtime graph ownership', () => { const legacySourceGraph = runtimeGraph('fluent/legacySource.ts'); expect(legacySourceGraph).toContain('fluent/themeReference.ts'); expect(reachedUnder(legacySourceGraph, 'fluent/compat/')).toEqual([]); - expect(reachedUnder(legacySourceGraph, 'fluent/tokens/')).toEqual([]); + expect(reachedUnder(legacySourceGraph, 'deprecated/')).toEqual([]); }); it('keeps the themes entry free of the legacy projection, payloads, and test collateral', () => { @@ -215,7 +267,7 @@ describe('runtime graph ownership', () => { expect(themesGraph).toContain('themes/fluent/fluentTheme.ts'); expect(themesGraph).toContain('themes/flex/flexWarmTheme.ts'); expect(themesGraph).not.toContain('fluent/useTheme.ts'); - for (const prefix of ['test/', 'fluent/compat/', 'fluent/tokens/']) { + for (const prefix of ['test/', 'fluent/compat/', 'deprecated/']) { expect([prefix, reachedUnder(themesGraph, prefix)]).toEqual([prefix, []]); } }); diff --git a/packages/agentic/design/src/themes/fluent/fluentTheme.ts b/packages/agentic/design/src/themes/fluent/fluentTheme.ts index a4198a26aa..a66262bcbd 100644 --- a/packages/agentic/design/src/themes/fluent/fluentTheme.ts +++ b/packages/agentic/design/src/themes/fluent/fluentTheme.ts @@ -1,9 +1,6 @@ import { ThemeReference } from '../../fluent/themeReference'; import type { Theme } from '../../fluent/types/Theme.types'; -import { fluentDarkTheme } from './fluentDarkTheme'; -import { fluentHcDarkTheme } from './fluentHcDarkTheme'; -import { fluentHcLightTheme } from './fluentHcLightTheme'; -import { fluentLightTheme } from './fluentLightTheme'; +import { selectFluentTheme } from './selectFluentTheme'; /** * Theme source holding every Fluent theme. It follows the system appearance reported by the React Native `Appearance` @@ -14,13 +11,5 @@ import { fluentLightTheme } from './fluentLightTheme'; export const fluentTheme: ThemeReference = /* @__PURE__ */ new ThemeReference({ base: {} as Theme, appearance: { colorScheme: 'system', contrast: 'system', interfaceLevel: 'system' }, - recipes: [ - (_parent, appearance) => { - const dark = appearance?.colorScheme === 'dark'; - if (appearance?.contrast === 'highContrast') { - return dark ? fluentHcDarkTheme : fluentHcLightTheme; - } - return dark ? fluentDarkTheme : fluentLightTheme; - }, - ], + recipes: [(_parent, appearance) => selectFluentTheme(appearance)], }); diff --git a/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx b/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx index a5b8a3b7d7..e27a0ec362 100644 --- a/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx +++ b/packages/agentic/design/src/themes/fluent/fluentThemes.test.tsx @@ -4,7 +4,6 @@ import { Appearance } from 'react-native'; import { act, create } from 'react-test-renderer'; -import { getDefaultLegacyTheme } from '../../fluent/compat/defaultLegacyTheme'; import { darkAliasColors, darkShadows, @@ -25,6 +24,7 @@ import type { ResolvedThemeAppearance, ThemeAppearanceSource, ThemeAppearanceSou import { fluentDarkTheme, fluentHcTheme, fluentLightTheme, fluentTheme } from '../index'; import { fluentHcDarkTheme } from './fluentHcDarkTheme'; import { fluentHcLightTheme } from './fluentHcLightTheme'; +import { selectFluentTheme } from './selectFluentTheme'; const standardLight = { colorScheme: 'light', contrast: 'standard', interfaceLevel: 'base' } as const; const standardDark = { colorScheme: 'dark', contrast: 'standard', interfaceLevel: 'base' } as const; @@ -95,20 +95,14 @@ describe.each(themes)('Fluent %s theme', (_name, theme, aliasColors, shadows, ho expect(theme.spacing).toEqual({ s2: '4px', s1: '8px', m: '16px', l1: '20px', l2: '32px' }); }); - it('defines every key the legacy default theme defines, with no undefined values', () => { - const legacy = getDefaultLegacyTheme(appearance); - const missing = [ - ...Object.keys(legacy.colors).filter((key) => !(key in theme.colors)), - ...Object.keys(legacy.shadows).filter((key) => !(key in theme.shadows)), - ...Object.keys(legacy.typography.families).filter((key) => !(key in theme.typography.families)), - ...Object.keys(legacy.typography.sizes).filter((key) => !(key in theme.typography.sizes)), - ...Object.keys(legacy.typography.variants).filter((key) => !(key in theme.typography.variants)), - ...Object.keys(legacy.spacing).filter((key) => !(key in theme.spacing)), - ]; - - expect(missing).toEqual([]); + it('defines no undefined values', () => { expect(undefinedPaths(theme)).toEqual([]); }); + + it('is the Fluent theme selected for its appearance', () => { + expect(selectFluentTheme(appearance)).toBe(theme); + expect(selectFluentTheme({ ...appearance, interfaceLevel: 'elevated' })).toBe(theme); + }); }); describe('fluentTheme', () => { diff --git a/packages/agentic/design/src/themes/fluent/selectFluentTheme.ts b/packages/agentic/design/src/themes/fluent/selectFluentTheme.ts new file mode 100644 index 0000000000..e0d3662c11 --- /dev/null +++ b/packages/agentic/design/src/themes/fluent/selectFluentTheme.ts @@ -0,0 +1,18 @@ +import type { Theme } from '../../fluent/types/Theme.types'; +import type { ResolvedThemeAppearance } from '../../types/appearance.types'; +import { fluentDarkTheme } from './fluentDarkTheme'; +import { fluentHcDarkTheme } from './fluentHcDarkTheme'; +import { fluentHcLightTheme } from './fluentHcLightTheme'; +import { fluentLightTheme } from './fluentLightTheme'; + +/** + * Select the Fluent theme for a resolved appearance. High contrast selects the high-contrast theme for the color + * scheme; elevated appearances resolve by color scheme until those Fluent themes exist. + */ +export function selectFluentTheme(appearance: ResolvedThemeAppearance | undefined): Theme { + const dark = appearance?.colorScheme === 'dark'; + if (appearance?.contrast === 'highContrast') { + return dark ? fluentHcDarkTheme : fluentHcLightTheme; + } + return dark ? fluentDarkTheme : fluentLightTheme; +} diff --git a/packages/agentic/design/src/theming/index.ts b/packages/agentic/design/src/theming/index.ts index 584bbd46f8..57a81fabd2 100644 --- a/packages/agentic/design/src/theming/index.ts +++ b/packages/agentic/design/src/theming/index.ts @@ -78,5 +78,3 @@ export { ThemeReference } from '../fluent/themeReference'; export type { OnThemeChange, ThemeRecipe, ThemeReferenceOptions, ThemeTransform } from '../fluent/themeReference'; export type { FlexThemeSource, LegacyThemeSource, ThemeSource, ThemeSourceBase } from './themeSource'; export { getCurrentAppearance, isHighContrast, setIsHighContrast } from '../fluent/platformUtils'; -export { mapFontPipelineToTheme, mapPipelineToTheme } from '../fluent/mapPipelineToTheme'; -export { mapPipelineToShadow } from '../fluent/mapPipelineToShadow'; diff --git a/packages/shim/theme-tokens/README.md b/packages/shim/theme-tokens/README.md index a955de89ad..ded9907125 100644 --- a/packages/shim/theme-tokens/README.md +++ b/packages/shim/theme-tokens/README.md @@ -1,8 +1,10 @@ # Theme-tokens -> **Deprecated:** Import `globalTokens`, `getAliasTokens`, `getShadowTokens`, -> and `hcAliasTokens` from `@fluentui-react-native/design/tokens/legacy` -> instead. +> **Deprecated:** These Fluent 2 token values are deprecated and have no +> replacement API. They remain available from +> `@fluentui-react-native/design/deprecated` for existing platform themes; new +> code should use the generated Fluent themes from +> `@fluentui-react-native/design/themes`. This package is a compatibility shim and will not receive new APIs. It preserves the existing entry point while consumers migrate to the design package. diff --git a/packages/shim/theme-tokens/src/index.ts b/packages/shim/theme-tokens/src/index.ts index e57f4d2183..9ad9de3046 100644 --- a/packages/shim/theme-tokens/src/index.ts +++ b/packages/shim/theme-tokens/src/index.ts @@ -1,4 +1,4 @@ // This package is a compatibility shim. Legacy Fluent token values now live in -// the `@fluentui-react-native/design/tokens/legacy` submodule. These explicit +// the `@fluentui-react-native/design/deprecated` submodule. These explicit // re-exports preserve the existing `@fluentui-react-native/theme-tokens` entry point. -export { getAliasTokens, getShadowTokens, globalTokens, hcAliasTokens } from '@fluentui-react-native/design/tokens/legacy'; +export { getAliasTokens, getShadowTokens, globalTokens, hcAliasTokens } from '@fluentui-react-native/design/deprecated'; diff --git a/packages/shim/theming-utils/README.md b/packages/shim/theming-utils/README.md index 82c4b8e8a7..1caadd4192 100644 --- a/packages/shim/theming-utils/README.md +++ b/packages/shim/theming-utils/README.md @@ -1,7 +1,10 @@ # Theming Utils -> **Deprecated:** Import appearance and token-pipeline helpers from -> `@fluentui-react-native/design/theming` instead. +> **Deprecated:** Import the appearance helpers from +> `@fluentui-react-native/design/theming` instead. The token-pipeline mappers +> (`mapPipelineToTheme`, `mapFontPipelineToTheme`, and `mapPipelineToShadow`) +> are deprecated with no replacement; they remain available from +> `@fluentui-react-native/design/deprecated` for existing platform themes. This package is a compatibility shim and will not receive new APIs. It preserves the existing entry point while consumers migrate to the design package. diff --git a/packages/shim/theming-utils/src/index.ts b/packages/shim/theming-utils/src/index.ts index 077e7f4220..f77188776c 100644 --- a/packages/shim/theming-utils/src/index.ts +++ b/packages/shim/theming-utils/src/index.ts @@ -1,11 +1,6 @@ -// This package is a compatibility shim. Theme appearance and token-pipeline -// utilities now live in the `@fluentui-react-native/design/theming` submodule. +// This package is a compatibility shim. Theme appearance utilities now live in +// the `@fluentui-react-native/design/theming` submodule, and the deprecated +// token-pipeline mappers live in `@fluentui-react-native/design/deprecated`. // These explicit re-exports preserve the existing package entry point. -export { - getCurrentAppearance, - isHighContrast, - mapFontPipelineToTheme, - mapPipelineToShadow, - mapPipelineToTheme, - setIsHighContrast, -} from '@fluentui-react-native/design/theming'; +export { getCurrentAppearance, isHighContrast, setIsHighContrast } from '@fluentui-react-native/design/theming'; +export { mapFontPipelineToTheme, mapPipelineToShadow, mapPipelineToTheme } from '@fluentui-react-native/design/deprecated'; diff --git a/packages/theming/android-theme/src/createAliasTokens.ts b/packages/theming/android-theme/src/createAliasTokens.ts index f6e55a87bc..2eab70edbc 100644 --- a/packages/theming/android-theme/src/createAliasTokens.ts +++ b/packages/theming/android-theme/src/createAliasTokens.ts @@ -1,7 +1,6 @@ import { memoize } from '@fluentui-react-native/framework-base'; -import { getAliasTokens, getShadowTokens } from '@fluentui-react-native/design/tokens/legacy'; +import { getAliasTokens, getShadowTokens, mapPipelineToShadow, mapPipelineToTheme } from '@fluentui-react-native/design/deprecated'; import type { AliasColorTokens, AppearanceOptions, ThemeShadowDefinition } from '@fluentui-react-native/design/theming'; -import { mapPipelineToShadow, mapPipelineToTheme } from '@fluentui-react-native/design/theming'; function createColorAliasTokensWorker(mode: AppearanceOptions): AliasColorTokens { const aliasTokens = getAliasTokens(mode); diff --git a/packages/theming/android-theme/src/createFontAliasTokens.ts b/packages/theming/android-theme/src/createFontAliasTokens.ts index 6f5494f58c..563ba58aa3 100644 --- a/packages/theming/android-theme/src/createFontAliasTokens.ts +++ b/packages/theming/android-theme/src/createFontAliasTokens.ts @@ -1,7 +1,6 @@ import { memoize } from '@fluentui-react-native/framework-base'; -import { getAliasTokens } from '@fluentui-react-native/design/tokens/legacy'; +import { getAliasTokens, mapFontPipelineToTheme } from '@fluentui-react-native/design/deprecated'; import type { Variants } from '@fluentui-react-native/design/theming'; -import { mapFontPipelineToTheme } from '@fluentui-react-native/design/theming'; function createFontAliasTokensWorker(): Partial<Variants> { const aliasTokens = getAliasTokens('light'); diff --git a/packages/theming/apple-theme/src/createFontAliasTokens.ios.ts b/packages/theming/apple-theme/src/createFontAliasTokens.ios.ts index cacfcbf623..d1b8b18f77 100644 --- a/packages/theming/apple-theme/src/createFontAliasTokens.ios.ts +++ b/packages/theming/apple-theme/src/createFontAliasTokens.ios.ts @@ -1,7 +1,7 @@ import aliasTokens from '@fluentui-react-native/design-tokens-ios/light/tokens-aliases.json'; // Font alias tokens should be the same for all color styles import { memoize } from '@fluentui-react-native/framework-base'; +import { mapFontPipelineToTheme } from '@fluentui-react-native/design/deprecated'; import type { Variants } from '@fluentui-react-native/design/theming'; -import { mapFontPipelineToTheme } from '@fluentui-react-native/design/theming'; function createFontAliasTokensWorker(): Partial<Variants> { return mapFontPipelineToTheme(aliasTokens); diff --git a/packages/theming/apple-theme/src/createMacOSAliasTokens.ts b/packages/theming/apple-theme/src/createMacOSAliasTokens.ts index d2cc77eb70..75ede44e80 100644 --- a/packages/theming/apple-theme/src/createMacOSAliasTokens.ts +++ b/packages/theming/apple-theme/src/createMacOSAliasTokens.ts @@ -1,7 +1,7 @@ import { memoize } from '@fluentui-react-native/framework-base'; +import { mapPipelineToTheme, mapPipelineToShadow } from '@fluentui-react-native/design/deprecated'; import type { AliasColorTokens, AppearanceOptions } from '@fluentui-react-native/design/theming'; import type { ThemeShadowDefinition } from '@fluentui-react-native/design/theming'; -import { mapPipelineToTheme, mapPipelineToShadow } from '@fluentui-react-native/design/theming'; import { getMacOSAliasTokens, getMacOSShadowTokens } from './getMacOSTokens'; diff --git a/packages/theming/apple-theme/src/createiOSAliasTokens.ts b/packages/theming/apple-theme/src/createiOSAliasTokens.ts index 5f42550291..7a9fb438e0 100644 --- a/packages/theming/apple-theme/src/createiOSAliasTokens.ts +++ b/packages/theming/apple-theme/src/createiOSAliasTokens.ts @@ -1,8 +1,7 @@ import { memoize } from '@fluentui-react-native/framework-base'; -import { getAliasTokens, getShadowTokens } from '@fluentui-react-native/design/tokens/legacy'; +import { getAliasTokens, getShadowTokens, mapPipelineToTheme, mapPipelineToShadow } from '@fluentui-react-native/design/deprecated'; import type { AliasColorTokens, AppearanceOptions } from '@fluentui-react-native/design/theming'; import type { ThemeShadowDefinition } from '@fluentui-react-native/design/theming'; -import { mapPipelineToTheme, mapPipelineToShadow } from '@fluentui-react-native/design/theming'; function createiOSColorAliasTokensWorker(mode: AppearanceOptions): AliasColorTokens { const aliasTokens = getAliasTokens(mode); diff --git a/packages/theming/win32-theme/src/createBrandedThemeWithAlias.ts b/packages/theming/win32-theme/src/createBrandedThemeWithAlias.ts index fa97b55337..2eb992b707 100644 --- a/packages/theming/win32-theme/src/createBrandedThemeWithAlias.ts +++ b/packages/theming/win32-theme/src/createBrandedThemeWithAlias.ts @@ -1,6 +1,6 @@ import type { ColorValue } from 'react-native'; -import { globalTokens } from '@fluentui-react-native/design/tokens/legacy'; +import { globalTokens } from '@fluentui-react-native/design/deprecated'; import type { Theme, PartialTheme, AliasColorTokens } from '@fluentui-react-native/design/theming'; export function createBrandedThemeWithAlias(themeName: string, theme: Theme): PartialTheme { diff --git a/packages/theming/win32-theme/src/createFontAliasTokens.ts b/packages/theming/win32-theme/src/createFontAliasTokens.ts index 0bb272bf6e..c172f4de92 100644 --- a/packages/theming/win32-theme/src/createFontAliasTokens.ts +++ b/packages/theming/win32-theme/src/createFontAliasTokens.ts @@ -1,6 +1,6 @@ import { memoize } from '@fluentui-react-native/framework-base'; +import { mapFontPipelineToTheme } from '@fluentui-react-native/design/deprecated'; import type { Variants } from '@fluentui-react-native/design/theming'; -import { mapFontPipelineToTheme } from '@fluentui-react-native/design/theming'; import { getOfficeAliasTokens } from './getOfficeTokens'; diff --git a/packages/theming/win32-theme/src/createOfficeAliasTokens.ts b/packages/theming/win32-theme/src/createOfficeAliasTokens.ts index 0b4f447d5d..90540f488a 100644 --- a/packages/theming/win32-theme/src/createOfficeAliasTokens.ts +++ b/packages/theming/win32-theme/src/createOfficeAliasTokens.ts @@ -1,6 +1,6 @@ import { memoize } from '@fluentui-react-native/framework-base'; +import { mapPipelineToShadow, mapPipelineToTheme } from '@fluentui-react-native/design/deprecated'; import type { AliasColorTokens, ThemeShadowDefinition } from '@fluentui-react-native/design/theming'; -import { mapPipelineToShadow, mapPipelineToTheme } from '@fluentui-react-native/design/theming'; import { getOfficeAliasTokens, getOfficeShadowTokens } from './getOfficeTokens'; diff --git a/packages/theming/win32-theme/src/getOfficeTokens.ts b/packages/theming/win32-theme/src/getOfficeTokens.ts index 081faf497e..87b386d9bd 100644 --- a/packages/theming/win32-theme/src/getOfficeTokens.ts +++ b/packages/theming/win32-theme/src/getOfficeTokens.ts @@ -5,7 +5,7 @@ import colorfulShadowTokens from '@fluentui-react-native/design-tokens-win32/col import darkGrayAliasTokens from '@fluentui-react-native/design-tokens-win32/darkgray/tokens-aliases.json'; import darkGrayShadowTokens from '@fluentui-react-native/design-tokens-win32/darkgray/tokens-shadow.json'; import hcShadowTokens from '@fluentui-react-native/design-tokens-win32/hc/tokens-shadow.json'; -import { hcAliasTokens } from '@fluentui-react-native/design/tokens/legacy'; +import { hcAliasTokens } from '@fluentui-react-native/design/deprecated'; export function getOfficeAliasTokens(officeTheme: string) { if (officeTheme === 'White' || officeTheme === 'Colorful') { From c33e026c62ad6e7a4c6d8be19293a0f1669f16b5 Mon Sep 17 00:00:00 2001 From: Jason Morse <jasonmo360@gmail.com> Date: Mon, 2 Nov 2026 12:04:18 -0800 Subject: [PATCH 18/18] design: drop stale legacy-defaults claims from changeset and flex-colors reference The legacy default theme is removed, so the x3 Flex defaults changeset and the flex-colors reference no longer describe it as unchanged. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/design-x3-flex-defaults.md | 4 ++-- packages/agentic/design/references/flex-colors.md | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.changeset/design-x3-flex-defaults.md b/.changeset/design-x3-flex-defaults.md index 1343774ab7..2dc1835aac 100644 --- a/.changeset/design-x3-flex-defaults.md +++ b/.changeset/design-x3-flex-defaults.md @@ -2,8 +2,8 @@ '@fluentui-react-native/design': minor --- -Rework Flex tokens around the current x3 defaults. Legacy `ThemeReference` themes, `ThemeProvider`, `useTheme`, the -legacy Fluent defaults, and Flex tokens projected from legacy themes keep their values. +Rework Flex tokens around the current x3 defaults. Legacy `ThemeReference` themes, `ThemeProvider`, `useTheme`, and +Flex tokens projected from legacy themes keep their values. Breaking changes for Flex consumers and theme authors: diff --git a/packages/agentic/design/references/flex-colors.md b/packages/agentic/design/references/flex-colors.md index f1b3e32d1c..b688db9032 100644 --- a/packages/agentic/design/references/flex-colors.md +++ b/packages/agentic/design/references/flex-colors.md @@ -129,4 +129,5 @@ Other surfaces: - `legacyFallback` is unchanged and still supplies values Flex cannot represent to the projected legacy `Theme`. - `themeFromFlexTokens` accepts resolved tokens and still accepts the deprecated `FlatFlexTokens` shape. - `validateContrastPairs` audits resolved colors at rest; pass a flat map of state values to audit hover or pressed. -- Legacy `ThemeReference` themes, `ThemeProvider`, `useTheme`, and the legacy Fluent defaults are unchanged. +- Legacy `ThemeReference` themes, `ThemeProvider`, and `useTheme` are unchanged. The legacy default theme is removed: + `themeFromFlexTokens` fills values Flex cannot represent from the generated Fluent theme.