@vectoriox/iox-ui 5.11.0 → 5.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/design-core/index.d.ts +122 -36
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +217 -76
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui.mjs +152 -20
- package/fesm2022/vectoriox-iox-ui.mjs.map +1 -1
- package/index.d.ts +67 -4
- package/package.json +1 -1
- package/src/design-core/element-styles.ts +271 -0
- package/src/design-core/flavor.ts +11 -88
- package/src/design-core/public-api.ts +1 -0
- package/src/design-core/token-css.ts +25 -6
- package/styles/iox-forms.css +56 -5
package/design-core/index.d.ts
CHANGED
|
@@ -8193,10 +8193,17 @@ declare const REDUCED_TRANSPARENCY_OVERRIDES: Readonly<Record<string, string>>;
|
|
|
8193
8193
|
declare function tokensToVarMap(tokens: ReadonlyArray<DesignTokenLike> | null | undefined): Record<string, string>;
|
|
8194
8194
|
/** Only the tokens that carry a dark override, as `{ 'iox-name': darkValue }`. */
|
|
8195
8195
|
declare function tokensToDarkVarMap(tokens: ReadonlyArray<DesignTokenLike> | null | undefined): Record<string, string>;
|
|
8196
|
-
|
|
8196
|
+
/** A compiled colour mode — the contract's modes minus `auto`, which is a compile CHOICE, not values. */
|
|
8197
|
+
type ResolvedMode = Exclude<DesignMode, 'auto'>;
|
|
8197
8198
|
/** Every token's ROOT value in one mode, with `var(--iox-…)` references resolved against the same
|
|
8198
8199
|
* set (recursively; a reference cycle or an unknown token is left as written). */
|
|
8199
|
-
declare function resolveTokenValues(tokens: ReadonlyArray<DesignTokenLike> | null | undefined, mode?:
|
|
8200
|
+
declare function resolveTokenValues(tokens: ReadonlyArray<DesignTokenLike> | null | undefined, mode?: ResolvedMode): Record<string, string>;
|
|
8201
|
+
/**
|
|
8202
|
+
* `value` with every `var(--iox-…)` replaced by that token's resolved root value in `mode` — what
|
|
8203
|
+
* the Style panel's Detach writes, so the node keeps exactly what it showed as a literal. An unknown
|
|
8204
|
+
* token falls back to its declared fallback, else stays as written.
|
|
8205
|
+
*/
|
|
8206
|
+
declare function resolveTokenReferences(value: string, tokens: ReadonlyArray<DesignTokenLike> | null | undefined, mode?: ResolvedMode): string;
|
|
8200
8207
|
/**
|
|
8201
8208
|
* Section colour schemes (design-system plan §3c). Two rules, both about WHERE a custom property
|
|
8202
8209
|
* resolves:
|
|
@@ -8217,17 +8224,11 @@ declare function compileTokenCssBlocks(tokens: ReadonlyArray<DesignTokenLike> |
|
|
|
8217
8224
|
declare function compileTokenCss(tokens: ReadonlyArray<DesignTokenLike> | null | undefined, opts?: TokenCssOptions): string;
|
|
8218
8225
|
|
|
8219
8226
|
/**
|
|
8220
|
-
* Flavors (flavors-and-theming-plan.md, F1):
|
|
8221
|
-
*
|
|
8222
|
-
*
|
|
8223
|
-
*
|
|
8224
|
-
*
|
|
8225
|
-
* check that every referenced token exists.
|
|
8226
|
-
*
|
|
8227
|
-
* The fallback is the bootstrap: until F2 seeds the org's `designtokens` rows, no `--iox-*`
|
|
8228
|
-
* var is defined anywhere, and `var(--iox-radius-control, 4px)` must still paint identically
|
|
8229
|
-
* in the builder canvas and the SSR page. Once tokens ARE seeded (or re-themed), the var wins
|
|
8230
|
-
* over the fallback everywhere — which is exactly the §3 propagation story.
|
|
8227
|
+
* Flavors v1 (flavors-and-theming-plan.md, F1–F2): a pack is its TOKENS plus the accent hue
|
|
8228
|
+
* opinion the brand derivation reads. The per-type `defaults` map and its resolvers are gone
|
|
8229
|
+
* (design-system plan §3e, DS2): a new element is born wearing an ELEMENT STYLE
|
|
8230
|
+
* (`element-styles.ts`), which references tokens and is flavor-independent. Swiss survives only
|
|
8231
|
+
* until DS4 migrates orgs to Crisp.
|
|
8231
8232
|
*/
|
|
8232
8233
|
interface FlavorTokenDef {
|
|
8233
8234
|
name: string;
|
|
@@ -8247,36 +8248,121 @@ interface FlavorPack {
|
|
|
8247
8248
|
label: string;
|
|
8248
8249
|
blurb: string;
|
|
8249
8250
|
tokens: FlavorTokenDef[];
|
|
8250
|
-
/** type → styleTrait → TOKEN NAME (never a CSS value — see the module header). */
|
|
8251
|
-
defaults: Record<string, Record<string, string>>;
|
|
8252
8251
|
/** F2: the accent's hue rotation (degrees in OKLab) from the brand seed — a pack opinion. */
|
|
8253
8252
|
accentHueDeg?: number;
|
|
8254
8253
|
}
|
|
8255
|
-
/**
|
|
8256
|
-
declare function
|
|
8254
|
+
/** A pack's own sanity: every token row names itself and carries a value. Returns errors. */
|
|
8255
|
+
declare function validateFlavorPack(pack: FlavorPack): string[];
|
|
8256
|
+
/**
|
|
8257
|
+
* Swiss — the F1 pack: four tokens (control/surface radius, control/stack spacing) and the hue
|
|
8258
|
+
* opinion F2's brand step reads. Kept until DS4 migrates `flavorId: swiss` orgs to Crisp; its four
|
|
8259
|
+
* rows are the spec's `legacyAliases`.
|
|
8260
|
+
*/
|
|
8261
|
+
declare const SWISS_FLAVOR: FlavorPack;
|
|
8262
|
+
|
|
8257
8263
|
/**
|
|
8258
|
-
*
|
|
8259
|
-
*
|
|
8260
|
-
*
|
|
8261
|
-
*
|
|
8262
|
-
*
|
|
8264
|
+
* Element styles — the author's "classes" (design-system plan §3b). A named look is an EXACT trait
|
|
8265
|
+
* map written into a node; every value is a `var(--iox-…)` reference or a flavor-independent
|
|
8266
|
+
* keyword, so a re-theme rewrites token rows and every node wearing the style follows. No renderer
|
|
8267
|
+
* reads `elementStyle`: it records which look a node wears, for the panel row, Reset, adopt and AI.
|
|
8268
|
+
*
|
|
8269
|
+
* Works on two node shapes through one minimal interface, so the builder (a ComponentNode whose
|
|
8270
|
+
* values live in `styleTraits[].traits[].default`) and the server-side composer (a plain serialized
|
|
8271
|
+
* layout node with `styleProps`) share every function here.
|
|
8263
8272
|
*/
|
|
8264
|
-
declare
|
|
8273
|
+
declare enum ElementStyleState {
|
|
8274
|
+
Hover = "hover",
|
|
8275
|
+
Active = "active",
|
|
8276
|
+
Focus = "focus"
|
|
8277
|
+
}
|
|
8278
|
+
declare const ELEMENT_STYLE_STATES: ReadonlyArray<ElementStyleState>;
|
|
8279
|
+
interface ElementStyle {
|
|
8280
|
+
readonly id: string;
|
|
8281
|
+
readonly label: string;
|
|
8282
|
+
readonly group: string;
|
|
8283
|
+
readonly appliesTo: ReadonlyArray<string>;
|
|
8284
|
+
readonly base: Readonly<Record<string, string>>;
|
|
8285
|
+
readonly hover?: Readonly<Record<string, string>>;
|
|
8286
|
+
readonly active?: Readonly<Record<string, string>>;
|
|
8287
|
+
readonly focus?: Readonly<Record<string, string>>;
|
|
8288
|
+
}
|
|
8289
|
+
declare const ELEMENT_STYLES: ReadonlyArray<ElementStyle>;
|
|
8290
|
+
/** Legacy `Button.variant` → the element style it maps to (adopt, DS7). */
|
|
8291
|
+
declare const BUTTON_VARIANT_TO_STYLE: Readonly<Record<string, string>>;
|
|
8292
|
+
interface PalettePreset {
|
|
8293
|
+
readonly label: string;
|
|
8294
|
+
readonly type: string;
|
|
8295
|
+
readonly elementStyle: string;
|
|
8296
|
+
readonly traits?: Readonly<Record<string, string>>;
|
|
8297
|
+
readonly styleProps: Readonly<Record<string, string>>;
|
|
8298
|
+
}
|
|
8299
|
+
/** Palette entries that are a Container wearing an element style (Card · Panel · Navigation bar). */
|
|
8300
|
+
declare const PALETTE_PRESETS: ReadonlyArray<PalettePreset>;
|
|
8301
|
+
declare function elementStyleById(id: string | null | undefined): ElementStyle | undefined;
|
|
8302
|
+
/** The styles a node of `type` may wear — the Style panel's select. */
|
|
8303
|
+
declare function elementStylesFor(type: string): ElementStyle[];
|
|
8304
|
+
/** The minimal shape both a builder node and a serialized layout node satisfy. */
|
|
8305
|
+
interface ElementStyleTraitLike {
|
|
8306
|
+
name: string;
|
|
8307
|
+
default?: unknown;
|
|
8308
|
+
}
|
|
8309
|
+
interface ElementStyleTarget {
|
|
8310
|
+
type: string;
|
|
8311
|
+
elementStyle?: string;
|
|
8312
|
+
/** Builder shape: values live in `trait.default`. Wins when present. */
|
|
8313
|
+
styleTraits?: ReadonlyArray<{
|
|
8314
|
+
traits: ElementStyleTraitLike[];
|
|
8315
|
+
}>;
|
|
8316
|
+
/** Serialized shape: a flat map. Created on first write when the target has no `styleTraits`. */
|
|
8317
|
+
styleProps?: Record<string, unknown>;
|
|
8318
|
+
stateStyles?: Partial<Record<string, Record<string, unknown>>>;
|
|
8319
|
+
}
|
|
8320
|
+
/** One trait an element style owns: a base trait, or a trait inside a pseudo-state. */
|
|
8321
|
+
interface OwnedTrait {
|
|
8322
|
+
trait: string;
|
|
8323
|
+
state?: ElementStyleState;
|
|
8324
|
+
}
|
|
8325
|
+
declare enum OwnedTraitLink {
|
|
8326
|
+
/** The node still holds the style's value. */
|
|
8327
|
+
Linked = "linked",
|
|
8328
|
+
/** The author replaced it on this node. */
|
|
8329
|
+
Changed = "changed"
|
|
8330
|
+
}
|
|
8331
|
+
interface OwnedTraitStatus extends OwnedTrait {
|
|
8332
|
+
expected: string;
|
|
8333
|
+
actual: unknown;
|
|
8334
|
+
status: OwnedTraitLink;
|
|
8335
|
+
}
|
|
8336
|
+
interface ApplyElementStyleResult {
|
|
8337
|
+
applied: boolean;
|
|
8338
|
+
/** Base traits the target has no slot for — a builder node silently drops these, so a spec
|
|
8339
|
+
* asserts this list is empty for every style × every type it applies to. */
|
|
8340
|
+
unknownTraits: string[];
|
|
8341
|
+
}
|
|
8342
|
+
interface SwitchElementStyleResult {
|
|
8343
|
+
applied: boolean;
|
|
8344
|
+
/** Traits the old style owned whose value the author had changed — kept, never overwritten. */
|
|
8345
|
+
kept: OwnedTrait[];
|
|
8346
|
+
}
|
|
8347
|
+
/** Write the style's exact base map and its hover/active/focus maps into the target. */
|
|
8348
|
+
declare function applyElementStyle(target: ElementStyleTarget, id: string): ApplyElementStyleResult;
|
|
8265
8349
|
/**
|
|
8266
|
-
* The
|
|
8267
|
-
*
|
|
8268
|
-
*
|
|
8350
|
+
* The element style a NEW node of `type` is born wearing (the spec's `defaultElementStyle`), or null
|
|
8351
|
+
* when the type has none. `traits` is the node's own trait values (props) — a Heading's default
|
|
8352
|
+
* follows its `level`; a Heading with no level matches no rule.
|
|
8269
8353
|
*/
|
|
8270
|
-
declare function
|
|
8354
|
+
declare function defaultElementStyleFor(type: string, traits?: Readonly<Record<string, unknown>>): string | null;
|
|
8355
|
+
/** Per owned trait: does the node still hold the style's value (linked) or the author's (changed)? */
|
|
8356
|
+
declare function ownedTraitStatus(target: ElementStyleTarget, id: string): OwnedTraitStatus[];
|
|
8271
8357
|
/**
|
|
8272
|
-
*
|
|
8273
|
-
*
|
|
8274
|
-
*
|
|
8275
|
-
*
|
|
8358
|
+
* Move a node from one style to another, rewriting ONLY what the old style owned:
|
|
8359
|
+
* - an owned trait still holding the old style's value is released — a base trait goes back to
|
|
8360
|
+
* `baseline[trait]` (the type's unstyled value; deleted when the baseline has none), a state trait
|
|
8361
|
+
* is removed from its state map;
|
|
8362
|
+
* - an owned trait the author changed is KEPT, and the new style does not overwrite it.
|
|
8363
|
+
* Then the new style is written. Traits neither style owns are never touched.
|
|
8276
8364
|
*/
|
|
8277
|
-
declare
|
|
8278
|
-
/** What both renderers use until F2 lets an org choose. */
|
|
8279
|
-
declare const DEFAULT_FLAVOR: FlavorPack;
|
|
8365
|
+
declare function switchElementStyle(target: ElementStyleTarget, fromId: string | null | undefined, toId: string, baseline?: Readonly<Record<string, unknown>>): SwitchElementStyleResult;
|
|
8280
8366
|
|
|
8281
8367
|
/**
|
|
8282
8368
|
* BRAND DERIVATION (flavors plan §6, F2): one colour in, an asserted accessible ramp out.
|
|
@@ -8456,5 +8542,5 @@ declare function parseFontFamilies(stack: string): string[];
|
|
|
8456
8542
|
*/
|
|
8457
8543
|
declare function fontsForTokens(tokens: ReadonlyArray<DesignTokenLike> | null | undefined): string[];
|
|
8458
8544
|
|
|
8459
|
-
export { ACCENT_TOKEN_NAMES,
|
|
8460
|
-
export type { AccentBackgrounds, AccentTokenName, DensityId, DesignChoices, DesignMode, DesignTokenGroup, DesignTokenLike, DesignTokenRow, DesignTokenTier, DesignTokenType, FlavorPack, FlavorPackV2, FlavorRevertPlan, FlavorRevertSnapshot, FlavorSeedPlan, FlavorSpecToken, FlavorTokenDef, FontDescriptor, FontFormat, FontPair, FontRoleToken, FontStyle, LinearSpring, MotionId, OkLab, Rgb, SchemeId, ShapeId, StoredDesignTokenRow, TokenCssBlocks, TokenCssOptions };
|
|
8545
|
+
export { ACCENT_TOKEN_NAMES, BUTTON_VARIANT_TO_STYLE, DESIGN_TOKEN_GROUPS, DESIGN_TOKEN_TIERS, DESIGN_TOKEN_TYPES, ELEMENT_STYLES, ELEMENT_STYLE_STATES, ElementStyleState, FLAVOR_SPEC_VERSION, FONT_CATALOG, FONT_FAMILY_TOKENS, OwnedTraitLink, PALETTE_PRESETS, REDUCED_MOTION_OVERRIDES, REDUCED_TRANSPARENCY_OVERRIDES, REVERT_WINDOW_MS, SPEC_A11Y, SPEC_AXES, SPEC_BUTTON_VARIANT_TO_STYLE, SPEC_CONTRAST, SPEC_DEFAULT_ELEMENT_STYLE, SPEC_ELEMENT_STYLES, SPEC_FIELD_CLASS_BASELINE, SPEC_FLAVORS, SPEC_FLAVOR_PACKS, SPEC_FONTS, SPEC_FONT_ROLES, SPEC_LEGACY_ALIASES, SPEC_PALETTE_PRESETS, SPEC_SCHEMES, SPEC_SPRINGS, SPEC_TIERS, SPEC_TIER_IDS, SPEC_TOKEN_TYPES, SWISS_FLAVOR, USER_TOKEN_SOURCE, WCAG_AA_TEXT, apcaLc, applyElementStyle, buildFlavorTokens, buildFontFaceCss, compileSchemeCss, compileTokenCss, compileTokenCssBlocks, cssString, defaultDesignChoices, defaultElementStyleFor, deriveAccentTokens, deriveBrandTokens, elementStyleById, elementStylesFor, flavorSourceStamp, fontsForTokens, isDesignTokenGroup, isDesignTokenTier, isDesignTokenType, oklabToRgb, ownedTraitStatus, parseFontFamilies, parseHexColor, planFlavorRevert, planFlavorSeed, relativeLuminance, resolveTokenReferences, resolveTokenValues, revertAvailable, rgbToOklab, springToLinear, styleKeyToKebab, switchElementStyle, toHexColor, tokensToDarkVarMap, tokensToVarMap, userFontStack, validateFlavorPack, wcagContrastRatio };
|
|
8546
|
+
export type { AccentBackgrounds, AccentTokenName, ApplyElementStyleResult, DensityId, DesignChoices, DesignMode, DesignTokenGroup, DesignTokenLike, DesignTokenRow, DesignTokenTier, DesignTokenType, ElementStyle, ElementStyleTarget, ElementStyleTraitLike, FlavorPack, FlavorPackV2, FlavorRevertPlan, FlavorRevertSnapshot, FlavorSeedPlan, FlavorSpecToken, FlavorTokenDef, FontDescriptor, FontFormat, FontPair, FontRoleToken, FontStyle, LinearSpring, MotionId, OkLab, OwnedTrait, OwnedTraitStatus, PalettePreset, ResolvedMode, Rgb, SchemeId, ShapeId, StoredDesignTokenRow, SwitchElementStyleResult, TokenCssBlocks, TokenCssOptions };
|
|
@@ -9526,10 +9526,12 @@ function tokensToDarkVarMap(tokens) {
|
|
|
9526
9526
|
}
|
|
9527
9527
|
const TOKEN_REF = /var\(\s*--iox-([\w-]+)\s*(?:,([^()]*))?\)/g;
|
|
9528
9528
|
const PLACEHOLDER = /\{\{\s*([\w-]+)\s*\}\}/g;
|
|
9529
|
-
const
|
|
9529
|
+
const LIGHT = 'light';
|
|
9530
|
+
const DARK = 'dark';
|
|
9531
|
+
const modeValue = (t, mode) => (mode === DARK ? darkOf(t) ?? t.value : t.value);
|
|
9530
9532
|
/** Every token's ROOT value in one mode, with `var(--iox-…)` references resolved against the same
|
|
9531
9533
|
* set (recursively; a reference cycle or an unknown token is left as written). */
|
|
9532
|
-
function resolveTokenValues(tokens, mode =
|
|
9534
|
+
function resolveTokenValues(tokens, mode = LIGHT) {
|
|
9533
9535
|
const raw = new Map(usableTokens(tokens).map(t => [t.name, modeValue(t, mode)]));
|
|
9534
9536
|
const out = {};
|
|
9535
9537
|
const resolve = (name, trail) => {
|
|
@@ -9548,6 +9550,15 @@ function resolveTokenValues(tokens, mode = 'light') {
|
|
|
9548
9550
|
}
|
|
9549
9551
|
return out;
|
|
9550
9552
|
}
|
|
9553
|
+
/**
|
|
9554
|
+
* `value` with every `var(--iox-…)` replaced by that token's resolved root value in `mode` — what
|
|
9555
|
+
* the Style panel's Detach writes, so the node keeps exactly what it showed as a literal. An unknown
|
|
9556
|
+
* token falls back to its declared fallback, else stays as written.
|
|
9557
|
+
*/
|
|
9558
|
+
function resolveTokenReferences(value, tokens, mode = LIGHT) {
|
|
9559
|
+
const resolved = resolveTokenValues(tokens, mode);
|
|
9560
|
+
return value.replace(TOKEN_REF, (ref, name, fallback) => resolved[name] ?? (fallback !== undefined ? fallback.trim() : ref));
|
|
9561
|
+
}
|
|
9551
9562
|
/** A scheme value with its `{{token}}` placeholders replaced by resolved root values — or null
|
|
9552
9563
|
* when a placeholder names a token the set does not have (the declaration is then omitted). */
|
|
9553
9564
|
function substitute(template, resolved) {
|
|
@@ -9580,7 +9591,7 @@ function compileSchemeCss(tokens, scope) {
|
|
|
9580
9591
|
const rows = usableTokens(tokens);
|
|
9581
9592
|
if (!rows.length)
|
|
9582
9593
|
return '';
|
|
9583
|
-
const resolved = resolveTokenValues(rows,
|
|
9594
|
+
const resolved = resolveTokenValues(rows, LIGHT);
|
|
9584
9595
|
return nonDefaultSchemes().map(([id, set]) => rule(schemeSelector(id, scope), [
|
|
9585
9596
|
...schemeEntries(set, resolved),
|
|
9586
9597
|
...rows.filter(t => !(t.name in set) && t.value.includes(REFERENCE))
|
|
@@ -9590,8 +9601,8 @@ function compileSchemeCss(tokens, scope) {
|
|
|
9590
9601
|
/** The dark twin of both scheme rules: a re-declared token with a dark value would otherwise pin
|
|
9591
9602
|
* the LIGHT value inside the section, and a `{{token}}` swap was resolved from LIGHT values. */
|
|
9592
9603
|
function darkSchemeRules(rows, scope) {
|
|
9593
|
-
const light = resolveTokenValues(rows,
|
|
9594
|
-
const dark = resolveTokenValues(rows,
|
|
9604
|
+
const light = resolveTokenValues(rows, LIGHT);
|
|
9605
|
+
const dark = resolveTokenValues(rows, DARK);
|
|
9595
9606
|
const redeclared = rows.filter(t => {
|
|
9596
9607
|
const d = darkOf(t);
|
|
9597
9608
|
return d !== null && (t.value.includes(REFERENCE) || d.includes(REFERENCE));
|
|
@@ -9633,74 +9644,21 @@ function compileTokenCss(tokens, opts = {}) {
|
|
|
9633
9644
|
return [base, dark].filter(Boolean).join('\n');
|
|
9634
9645
|
}
|
|
9635
9646
|
|
|
9636
|
-
/**
|
|
9637
|
-
function
|
|
9638
|
-
const map = pack?.defaults?.[type];
|
|
9639
|
-
if (!map)
|
|
9640
|
-
return {};
|
|
9641
|
-
const byName = new Map((pack.tokens ?? []).map(t => [t.name, t.value]));
|
|
9642
|
-
const out = {};
|
|
9643
|
-
for (const [trait, tokenName] of Object.entries(map)) {
|
|
9644
|
-
const fallback = byName.get(tokenName);
|
|
9645
|
-
if (fallback === undefined)
|
|
9646
|
-
continue; // validator fails the build; runtime stays safe
|
|
9647
|
-
out[trait] = `var(--iox-${tokenName}, ${fallback})`;
|
|
9648
|
-
}
|
|
9649
|
-
return out;
|
|
9650
|
-
}
|
|
9651
|
-
/**
|
|
9652
|
-
* The ENGINE's half of the cascade: kebab `prop: var(…)` declarations for every pack default
|
|
9653
|
-
* the node's persisted styleProps does NOT set. Appended beside renderDefaultDeclarations —
|
|
9654
|
-
* same guard-on-undefined discipline, so a node saved post-F1 (var already serialised via the
|
|
9655
|
-
* builder's trait defaults) is untouched, and a legacy node picks the pack default up at
|
|
9656
|
-
* render time. Node styleProps always wins.
|
|
9657
|
-
*/
|
|
9658
|
-
function flavorDefaultDeclarations(type, styleProps, pack) {
|
|
9659
|
-
const sp = styleProps ?? {};
|
|
9660
|
-
const out = [];
|
|
9661
|
-
for (const [trait, value] of Object.entries(resolveFlavorDefaults(type, pack))) {
|
|
9662
|
-
if (sp[trait] === undefined)
|
|
9663
|
-
out.push(`${styleKeyToKebab(trait)}: ${value}`);
|
|
9664
|
-
}
|
|
9665
|
-
return out;
|
|
9666
|
-
}
|
|
9667
|
-
/**
|
|
9668
|
-
* The CI gate (flavors plan §10 C4): a pack may only name types and traits that exist in the
|
|
9669
|
-
* live component registry, and tokens it defines itself. Returns human-readable errors; a
|
|
9670
|
-
* consumer spec feeds it the REAL registry and asserts [].
|
|
9671
|
-
*/
|
|
9672
|
-
function validateFlavorPack(pack, knownTraitsByType) {
|
|
9647
|
+
/** A pack's own sanity: every token row names itself and carries a value. Returns errors. */
|
|
9648
|
+
function validateFlavorPack(pack) {
|
|
9673
9649
|
const errors = [];
|
|
9674
|
-
const tokenNames = new Set((pack.tokens ?? []).map(t => t.name));
|
|
9675
9650
|
for (const t of pack.tokens ?? []) {
|
|
9676
9651
|
if (!t.name)
|
|
9677
9652
|
errors.push(`${pack.id}: token with empty name`);
|
|
9678
9653
|
if (!t.value)
|
|
9679
9654
|
errors.push(`${pack.id}: token "${t.name}" has no value`);
|
|
9680
9655
|
}
|
|
9681
|
-
for (const [type, traits] of Object.entries(pack.defaults ?? {})) {
|
|
9682
|
-
const known = knownTraitsByType[type];
|
|
9683
|
-
if (!known) {
|
|
9684
|
-
errors.push(`${pack.id}: unknown component type "${type}"`);
|
|
9685
|
-
continue;
|
|
9686
|
-
}
|
|
9687
|
-
const knownSet = known instanceof Set ? known : new Set(known);
|
|
9688
|
-
for (const [trait, tokenName] of Object.entries(traits)) {
|
|
9689
|
-
if (!knownSet.has(trait))
|
|
9690
|
-
errors.push(`${pack.id}: "${type}" has no style trait "${trait}"`);
|
|
9691
|
-
if (!tokenNames.has(tokenName))
|
|
9692
|
-
errors.push(`${pack.id}: "${type}.${trait}" references undefined token "${tokenName}"`);
|
|
9693
|
-
if (/[:(]|^#|\d/.test(tokenName))
|
|
9694
|
-
errors.push(`${pack.id}: "${type}.${trait}" must name a token, not a value ("${tokenName}")`);
|
|
9695
|
-
}
|
|
9696
|
-
}
|
|
9697
9656
|
return errors;
|
|
9698
9657
|
}
|
|
9699
9658
|
/**
|
|
9700
|
-
* Swiss — the
|
|
9701
|
-
*
|
|
9702
|
-
*
|
|
9703
|
-
* legacy pages before anyone chose anything.
|
|
9659
|
+
* Swiss — the F1 pack: four tokens (control/surface radius, control/stack spacing) and the hue
|
|
9660
|
+
* opinion F2's brand step reads. Kept until DS4 migrates `flavorId: swiss` orgs to Crisp; its four
|
|
9661
|
+
* rows are the spec's `legacyAliases`.
|
|
9704
9662
|
*/
|
|
9705
9663
|
const SWISS_FLAVOR = {
|
|
9706
9664
|
id: 'swiss',
|
|
@@ -9713,20 +9671,203 @@ const SWISS_FLAVOR = {
|
|
|
9713
9671
|
{ name: 'space-control', value: '10px 18px', type: 'spacing', group: 'space' },
|
|
9714
9672
|
{ name: 'space-stack', value: '12px', type: 'spacing', group: 'space' },
|
|
9715
9673
|
],
|
|
9716
|
-
|
|
9717
|
-
Button: { borderRadius: 'radius-control', padding: 'space-control' },
|
|
9718
|
-
ButtonBlock: { borderRadius: 'radius-control', padding: 'space-control' },
|
|
9719
|
-
Card: { borderRadius: 'radius-surface' },
|
|
9720
|
-
},
|
|
9721
|
-
// F2: Swiss turns the seed toward a cool counterpoint. NOTE deliberately: the brand tokens
|
|
9722
|
-
// deriveBrandTokens() emits are SEEDED per org — they do not join `defaults` here, because a
|
|
9723
|
-
// colour default repaints legacy nodes whose saved styleProps lack the key (the engine fills
|
|
9724
|
-
// missing keys from config defaults). Coloured element defaults are a Swiss v2 upgrade
|
|
9725
|
-
// decision (§10 C2), taken with the picker in front of the author — never a side effect.
|
|
9674
|
+
// F2: Swiss turns the seed toward a cool counterpoint.
|
|
9726
9675
|
accentHueDeg: 150,
|
|
9727
9676
|
};
|
|
9728
|
-
|
|
9729
|
-
|
|
9677
|
+
|
|
9678
|
+
/**
|
|
9679
|
+
* Element styles — the author's "classes" (design-system plan §3b). A named look is an EXACT trait
|
|
9680
|
+
* map written into a node; every value is a `var(--iox-…)` reference or a flavor-independent
|
|
9681
|
+
* keyword, so a re-theme rewrites token rows and every node wearing the style follows. No renderer
|
|
9682
|
+
* reads `elementStyle`: it records which look a node wears, for the panel row, Reset, adopt and AI.
|
|
9683
|
+
*
|
|
9684
|
+
* Works on two node shapes through one minimal interface, so the builder (a ComponentNode whose
|
|
9685
|
+
* values live in `styleTraits[].traits[].default`) and the server-side composer (a plain serialized
|
|
9686
|
+
* layout node with `styleProps`) share every function here.
|
|
9687
|
+
*/
|
|
9688
|
+
var ElementStyleState;
|
|
9689
|
+
(function (ElementStyleState) {
|
|
9690
|
+
ElementStyleState["Hover"] = "hover";
|
|
9691
|
+
ElementStyleState["Active"] = "active";
|
|
9692
|
+
ElementStyleState["Focus"] = "focus";
|
|
9693
|
+
})(ElementStyleState || (ElementStyleState = {}));
|
|
9694
|
+
const ELEMENT_STYLE_STATES = [ElementStyleState.Hover, ElementStyleState.Active, ElementStyleState.Focus];
|
|
9695
|
+
const ELEMENT_STYLES = SPEC_ELEMENT_STYLES;
|
|
9696
|
+
/** Legacy `Button.variant` → the element style it maps to (adopt, DS7). */
|
|
9697
|
+
const BUTTON_VARIANT_TO_STYLE = SPEC_BUTTON_VARIANT_TO_STYLE;
|
|
9698
|
+
/** Palette entries that are a Container wearing an element style (Card · Panel · Navigation bar). */
|
|
9699
|
+
const PALETTE_PRESETS = SPEC_PALETTE_PRESETS;
|
|
9700
|
+
const BY_ID = new Map(ELEMENT_STYLES.map(s => [s.id, s]));
|
|
9701
|
+
function elementStyleById(id) {
|
|
9702
|
+
return id ? BY_ID.get(id) : undefined;
|
|
9703
|
+
}
|
|
9704
|
+
/** The styles a node of `type` may wear — the Style panel's select. */
|
|
9705
|
+
function elementStylesFor(type) {
|
|
9706
|
+
return ELEMENT_STYLES.filter(s => s.appliesTo.includes(type));
|
|
9707
|
+
}
|
|
9708
|
+
var OwnedTraitLink;
|
|
9709
|
+
(function (OwnedTraitLink) {
|
|
9710
|
+
/** The node still holds the style's value. */
|
|
9711
|
+
OwnedTraitLink["Linked"] = "linked";
|
|
9712
|
+
/** The author replaced it on this node. */
|
|
9713
|
+
OwnedTraitLink["Changed"] = "changed";
|
|
9714
|
+
})(OwnedTraitLink || (OwnedTraitLink = {}));
|
|
9715
|
+
const usesTraits = (t) => Array.isArray(t.styleTraits);
|
|
9716
|
+
function findTrait(target, name) {
|
|
9717
|
+
for (const group of target.styleTraits ?? []) {
|
|
9718
|
+
const hit = group.traits.find(tr => tr.name === name);
|
|
9719
|
+
if (hit)
|
|
9720
|
+
return hit;
|
|
9721
|
+
}
|
|
9722
|
+
return undefined;
|
|
9723
|
+
}
|
|
9724
|
+
function readBase(target, name) {
|
|
9725
|
+
return usesTraits(target) ? findTrait(target, name)?.default : target.styleProps?.[name];
|
|
9726
|
+
}
|
|
9727
|
+
/** False when a builder node has no such trait — the value would be dropped. */
|
|
9728
|
+
function writeBase(target, name, value) {
|
|
9729
|
+
if (usesTraits(target)) {
|
|
9730
|
+
const trait = findTrait(target, name);
|
|
9731
|
+
if (!trait)
|
|
9732
|
+
return false;
|
|
9733
|
+
trait.default = value;
|
|
9734
|
+
return true;
|
|
9735
|
+
}
|
|
9736
|
+
target.styleProps = target.styleProps ?? {};
|
|
9737
|
+
if (value === undefined)
|
|
9738
|
+
delete target.styleProps[name];
|
|
9739
|
+
else
|
|
9740
|
+
target.styleProps[name] = value;
|
|
9741
|
+
return true;
|
|
9742
|
+
}
|
|
9743
|
+
function readState(target, state, name) {
|
|
9744
|
+
return target.stateStyles?.[state]?.[name];
|
|
9745
|
+
}
|
|
9746
|
+
function writeState(target, state, name, value) {
|
|
9747
|
+
target.stateStyles = target.stateStyles ?? {};
|
|
9748
|
+
target.stateStyles[state] = { ...(target.stateStyles[state] ?? {}), [name]: value };
|
|
9749
|
+
}
|
|
9750
|
+
function deleteState(target, state, name) {
|
|
9751
|
+
const map = target.stateStyles?.[state];
|
|
9752
|
+
if (!map)
|
|
9753
|
+
return;
|
|
9754
|
+
const { [name]: _drop, ...rest } = map;
|
|
9755
|
+
if (Object.keys(rest).length)
|
|
9756
|
+
target.stateStyles[state] = rest;
|
|
9757
|
+
else
|
|
9758
|
+
delete target.stateStyles[state];
|
|
9759
|
+
}
|
|
9760
|
+
/** Every (state, trait, value) a style owns, base first. */
|
|
9761
|
+
function ownedEntries(style) {
|
|
9762
|
+
const out = [];
|
|
9763
|
+
for (const [trait, value] of Object.entries(style.base))
|
|
9764
|
+
out.push({ trait, value });
|
|
9765
|
+
for (const state of ELEMENT_STYLE_STATES) {
|
|
9766
|
+
for (const [trait, value] of Object.entries(style[state] ?? {}))
|
|
9767
|
+
out.push({ trait, state, value });
|
|
9768
|
+
}
|
|
9769
|
+
return out;
|
|
9770
|
+
}
|
|
9771
|
+
const sameOwned = (a, b) => a.trait === b.trait && a.state === b.state;
|
|
9772
|
+
function writeEntries(target, style, skip = []) {
|
|
9773
|
+
const unknown = [];
|
|
9774
|
+
for (const entry of ownedEntries(style)) {
|
|
9775
|
+
if (skip.some(s => sameOwned(s, entry)))
|
|
9776
|
+
continue;
|
|
9777
|
+
if (entry.state)
|
|
9778
|
+
writeState(target, entry.state, entry.trait, entry.value);
|
|
9779
|
+
else if (!writeBase(target, entry.trait, entry.value))
|
|
9780
|
+
unknown.push(entry.trait);
|
|
9781
|
+
}
|
|
9782
|
+
target.elementStyle = style.id;
|
|
9783
|
+
return unknown;
|
|
9784
|
+
}
|
|
9785
|
+
/** Write the style's exact base map and its hover/active/focus maps into the target. */
|
|
9786
|
+
function applyElementStyle(target, id) {
|
|
9787
|
+
const style = elementStyleById(id);
|
|
9788
|
+
if (!style)
|
|
9789
|
+
return { applied: false, unknownTraits: [] };
|
|
9790
|
+
return { applied: true, unknownTraits: writeEntries(target, style) };
|
|
9791
|
+
}
|
|
9792
|
+
const RULE_KEY = /^(\w+)(?:\[(\w+)=([^\]]+)\])?$/;
|
|
9793
|
+
const RANGE = /^([a-z]*)(\d+)\.\.\1(\d+)$/;
|
|
9794
|
+
function expandValues(raw) {
|
|
9795
|
+
const range = RANGE.exec(raw);
|
|
9796
|
+
if (!range)
|
|
9797
|
+
return [raw];
|
|
9798
|
+
const [, prefix, from, to] = range;
|
|
9799
|
+
const out = [];
|
|
9800
|
+
for (let n = Number(from); n <= Number(to); n++)
|
|
9801
|
+
out.push(`${prefix}${n}`);
|
|
9802
|
+
return out;
|
|
9803
|
+
}
|
|
9804
|
+
const DEFAULT_RULES = Object.entries(SPEC_DEFAULT_ELEMENT_STYLE).map(([key, style]) => {
|
|
9805
|
+
const m = RULE_KEY.exec(key);
|
|
9806
|
+
if (!m)
|
|
9807
|
+
throw new Error(`defaultElementStyle: unreadable key "${key}"`);
|
|
9808
|
+
const [, type, prop, raw] = m;
|
|
9809
|
+
return prop ? { type, prop, values: expandValues(raw), style } : { type, style };
|
|
9810
|
+
});
|
|
9811
|
+
/**
|
|
9812
|
+
* The element style a NEW node of `type` is born wearing (the spec's `defaultElementStyle`), or null
|
|
9813
|
+
* when the type has none. `traits` is the node's own trait values (props) — a Heading's default
|
|
9814
|
+
* follows its `level`; a Heading with no level matches no rule.
|
|
9815
|
+
*/
|
|
9816
|
+
function defaultElementStyleFor(type, traits = {}) {
|
|
9817
|
+
for (const rule of DEFAULT_RULES) {
|
|
9818
|
+
if (rule.type !== type)
|
|
9819
|
+
continue;
|
|
9820
|
+
if (!rule.prop)
|
|
9821
|
+
return rule.style;
|
|
9822
|
+
if (rule.values.includes(String(traits[rule.prop])))
|
|
9823
|
+
return rule.style;
|
|
9824
|
+
}
|
|
9825
|
+
return null;
|
|
9826
|
+
}
|
|
9827
|
+
/** Per owned trait: does the node still hold the style's value (linked) or the author's (changed)? */
|
|
9828
|
+
function ownedTraitStatus(target, id) {
|
|
9829
|
+
const style = elementStyleById(id);
|
|
9830
|
+
if (!style)
|
|
9831
|
+
return [];
|
|
9832
|
+
return ownedEntries(style).map(({ trait, state, value }) => {
|
|
9833
|
+
const actual = state ? readState(target, state, trait) : readBase(target, trait);
|
|
9834
|
+
return {
|
|
9835
|
+
trait, ...(state ? { state } : {}), expected: value, actual,
|
|
9836
|
+
status: actual === value ? OwnedTraitLink.Linked : OwnedTraitLink.Changed,
|
|
9837
|
+
};
|
|
9838
|
+
});
|
|
9839
|
+
}
|
|
9840
|
+
/**
|
|
9841
|
+
* Move a node from one style to another, rewriting ONLY what the old style owned:
|
|
9842
|
+
* - an owned trait still holding the old style's value is released — a base trait goes back to
|
|
9843
|
+
* `baseline[trait]` (the type's unstyled value; deleted when the baseline has none), a state trait
|
|
9844
|
+
* is removed from its state map;
|
|
9845
|
+
* - an owned trait the author changed is KEPT, and the new style does not overwrite it.
|
|
9846
|
+
* Then the new style is written. Traits neither style owns are never touched.
|
|
9847
|
+
*/
|
|
9848
|
+
function switchElementStyle(target, fromId, toId, baseline = {}) {
|
|
9849
|
+
const to = elementStyleById(toId);
|
|
9850
|
+
if (!to)
|
|
9851
|
+
return { applied: false, kept: [] };
|
|
9852
|
+
const kept = [];
|
|
9853
|
+
const from = elementStyleById(fromId);
|
|
9854
|
+
if (from) {
|
|
9855
|
+
for (const status of ownedTraitStatus(target, from.id)) {
|
|
9856
|
+
const ref = status.state ? { trait: status.trait, state: status.state } : { trait: status.trait };
|
|
9857
|
+
if (status.status === OwnedTraitLink.Changed) {
|
|
9858
|
+
if (status.actual !== undefined)
|
|
9859
|
+
kept.push(ref);
|
|
9860
|
+
continue;
|
|
9861
|
+
}
|
|
9862
|
+
if (ref.state)
|
|
9863
|
+
deleteState(target, ref.state, ref.trait);
|
|
9864
|
+
else
|
|
9865
|
+
writeBase(target, ref.trait, baseline[ref.trait]);
|
|
9866
|
+
}
|
|
9867
|
+
}
|
|
9868
|
+
writeEntries(target, to, kept);
|
|
9869
|
+
return { applied: true, kept };
|
|
9870
|
+
}
|
|
9730
9871
|
|
|
9731
9872
|
function parseHexColor(hex) {
|
|
9732
9873
|
const m = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i.exec((hex ?? '').trim());
|
|
@@ -10330,5 +10471,5 @@ function springToLinear(stiffness, damping) {
|
|
|
10330
10471
|
* Generated bundle index. Do not edit.
|
|
10331
10472
|
*/
|
|
10332
10473
|
|
|
10333
|
-
export { ACCENT_TOKEN_NAMES,
|
|
10474
|
+
export { ACCENT_TOKEN_NAMES, BUTTON_VARIANT_TO_STYLE, DESIGN_TOKEN_GROUPS, DESIGN_TOKEN_TIERS, DESIGN_TOKEN_TYPES, ELEMENT_STYLES, ELEMENT_STYLE_STATES, ElementStyleState, FLAVOR_SPEC_VERSION, FONT_CATALOG, FONT_FAMILY_TOKENS, OwnedTraitLink, PALETTE_PRESETS, REDUCED_MOTION_OVERRIDES, REDUCED_TRANSPARENCY_OVERRIDES, REVERT_WINDOW_MS, SPEC_A11Y, SPEC_AXES, SPEC_BUTTON_VARIANT_TO_STYLE, SPEC_CONTRAST, SPEC_DEFAULT_ELEMENT_STYLE, SPEC_ELEMENT_STYLES, SPEC_FIELD_CLASS_BASELINE, SPEC_FLAVORS, SPEC_FLAVOR_PACKS, SPEC_FONTS, SPEC_FONT_ROLES, SPEC_LEGACY_ALIASES, SPEC_PALETTE_PRESETS, SPEC_SCHEMES, SPEC_SPRINGS, SPEC_TIERS, SPEC_TIER_IDS, SPEC_TOKEN_TYPES, SWISS_FLAVOR, USER_TOKEN_SOURCE, WCAG_AA_TEXT, apcaLc, applyElementStyle, buildFlavorTokens, buildFontFaceCss, compileSchemeCss, compileTokenCss, compileTokenCssBlocks, cssString, defaultDesignChoices, defaultElementStyleFor, deriveAccentTokens, deriveBrandTokens, elementStyleById, elementStylesFor, flavorSourceStamp, fontsForTokens, isDesignTokenGroup, isDesignTokenTier, isDesignTokenType, oklabToRgb, ownedTraitStatus, parseFontFamilies, parseHexColor, planFlavorRevert, planFlavorSeed, relativeLuminance, resolveTokenReferences, resolveTokenValues, revertAvailable, rgbToOklab, springToLinear, styleKeyToKebab, switchElementStyle, toHexColor, tokensToDarkVarMap, tokensToVarMap, userFontStack, validateFlavorPack, wcagContrastRatio };
|
|
10334
10475
|
//# sourceMappingURL=vectoriox-iox-ui-design-core.mjs.map
|