@vectoriox/iox-ui 5.23.0 → 5.25.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.
@@ -8797,10 +8797,26 @@ interface SeedExpectation {
8797
8797
  dark?: string;
8798
8798
  }
8799
8799
  /**
8800
- * What the PREVIOUS seed wrote, per row: a map by name, or a function of the stored row (a baseline
8801
- * that depends on WHICH seed stamped the row — the Swiss → Crisp migration's case).
8800
+ * What a previous seed wrote, per row: a map by name, or a function of the stored row (a baseline that
8801
+ * depends on WHICH seed stamped the row — the Swiss → Crisp migration's case). The function may name
8802
+ * several values: a machine row is untouched when it holds ANY of them (`designBaseline`: what the
8803
+ * previous design wrote, and what the row's own pack writes at its defaults).
8802
8804
  */
8803
- type SeedBaseline = ReadonlyMap<string, SeedExpectation> | ((row: StoredDesignTokenRow) => SeedExpectation | undefined);
8805
+ type SeedBaseline = ReadonlyMap<string, SeedExpectation> | ((row: StoredDesignTokenRow) => SeedExpectation | ReadonlyArray<SeedExpectation> | undefined);
8806
+ /** Options of a seed pass. */
8807
+ interface FlavorSeedOptions {
8808
+ /** Rows the author asked to take the look's values too ("Use the look's values for these too"):
8809
+ * written like an untouched row instead of being kept. */
8810
+ reclaim?: Iterable<string> | null;
8811
+ }
8812
+ /**
8813
+ * A machine-stamped row is untouched when it holds what a seed wrote — or that seed's LIGHT value with no
8814
+ * dark half at all: iox-cms dropped every `values.dark` from F0 to DS4.1, and no author edit produces that
8815
+ * shape (the Tokens panel edited the light value only, and since DS8 an edit makes the row `source: user`).
8816
+ * Judging it edited kept the six brand rows of every studio seeded before DS4.1 on the default blue for
8817
+ * good — a later brand never reached them.
8818
+ */
8819
+ declare function untouchedSeedRow(row: StoredDesignTokenRow, expected: ReadonlyArray<SeedExpectation>): boolean;
8804
8820
  /**
8805
8821
  * The seeding MERGE: desired tokens vs existing rows, deciding create / update / keep. The §10 C2
8806
8822
  * rule — "an upgrade only rewrites untouched rows" — is a comparison against what the PREVIOUS
@@ -8811,11 +8827,12 @@ type SeedBaseline = ReadonlyMap<string, SeedExpectation> | ((row: StoredDesignTo
8811
8827
  * choice, so a new choice may replace it. `group`/`tier` ride every write; a desired row's own
8812
8828
  * `source` (a chosen font's `user`) wins over the pack stamp. A machine-owned row that already holds
8813
8829
  * the desired value but another pack's stamp is RE-STAMPED (§10 C2 provenance: the stamp names the
8814
- * design that owns the row, so the next switch judges it against the right baseline).
8830
+ * design that owns the row, so the next switch judges it against the right baseline). A row named in
8831
+ * `options.reclaim` is written whatever it holds — the author chose the look's value over their own.
8815
8832
  */
8816
8833
  declare function planFlavorSeed(desired: ReadonlyArray<FlavorTokenDef & {
8817
8834
  source?: string;
8818
- }>, existing: ReadonlyArray<StoredDesignTokenRow>, stamp: string, baseline: SeedBaseline | null): FlavorSeedPlan;
8835
+ }>, existing: ReadonlyArray<StoredDesignTokenRow>, stamp: string, baseline: SeedBaseline | null, options?: FlavorSeedOptions): FlavorSeedPlan;
8819
8836
 
8820
8837
  interface LinearSpring {
8821
8838
  easing: string;
@@ -9126,10 +9143,25 @@ declare function designTokenRows(choices: DesignChoices): DesignTokenRow[];
9126
9143
  * (for an org with no design row, Crisp's defaults — exactly what DS2's interim seed wrote). In a
9127
9144
  * Swiss org the only v2 rows are that interim seed's, so they are judged against Crisp's DEFAULTS,
9128
9145
  * never against the brand-seeded Crisp the migration is about to write.
9146
+ *
9147
+ * A row a v2 pack stamped is ALSO untouched while it holds what that pack writes at its own defaults —
9148
+ * what DS2's interim seed, a first run and every pack card at its defaults wrote. Without it, one row
9149
+ * kept for any reason (a dark half iox-cms dropped, `untouchedSeedRow`) was judged against a design that
9150
+ * had moved on, apply after apply, and stayed on the old value for good: the studio's brand colour
9151
+ * reached the design row and never its accent.
9129
9152
  */
9130
9153
  declare function designBaseline(previous: StoredDesign): SeedBaseline;
9131
- /** Apply `next` over the org's rows, judged against `previous` — the plan FlavorApplyService runs. */
9132
- declare function planDesignApply(existing: ReadonlyArray<StoredDesignTokenRow>, previous: StoredDesign, next: DesignChoices): FlavorSeedPlan;
9154
+ /** Options of an apply. */
9155
+ interface DesignApplyOptions {
9156
+ /** The kept rows the author asked to take the look's values too (`FlavorSeedOptions.reclaim`). */
9157
+ reclaim?: FlavorSeedOptions['reclaim'];
9158
+ }
9159
+ /**
9160
+ * Apply `next` over the org's rows, judged against `previous` — the plan FlavorApplyService runs. The
9161
+ * plan's `kept` names the author's rows the look leaves alone; the Design card lists them before Apply,
9162
+ * and `options.reclaim` writes the look's value into the ones the author hands back.
9163
+ */
9164
+ declare function planDesignApply(existing: ReadonlyArray<StoredDesignTokenRow>, previous: StoredDesign, next: DesignChoices, options?: DesignApplyOptions): FlavorSeedPlan;
9133
9165
  /**
9134
9166
  * "Revert to previous look" over the org's rows — the ONE plan the Revert executes and its hint counts
9135
9167
  * (`kept`: the author's edits since the apply, left as they are). The apply's record of what it wrote
@@ -9143,12 +9175,18 @@ declare function missingDesignRows(existing: ReadonlyArray<{
9143
9175
  name: string;
9144
9176
  }>, choices: DesignChoices): DesignTokenRow[];
9145
9177
  /**
9146
- * The builder-load REPAIR (DS4.1): rows the design owns and nobody touched — stamped by the current
9147
- * pack, light value exactly the pack's — whose dark override differs from the pack's are rewritten.
9148
- * iox-cms dropped `values.dark` on every write from F0 to DS4 (`values` was an implicit relation),
9149
- * and a revert could leave the previous apply's dark behind; both leave a row whose light half is the
9150
- * design's and whose dark half is not. No author edit can produce that shape — the Tokens panel edits
9151
- * the light value only — so rewriting it heals existing orgs without the author doing anything.
9178
+ * The builder-load REPAIR (DS4.1): rows the design writes that are the machine's and nobody touched,
9179
+ * yet hold something other than the design's value, are rewritten — so an org heals on its next load
9180
+ * with no author action. Two shapes:
9181
+ * - stamped by the current pack, light value exactly the pack's, dark half not: iox-cms dropped
9182
+ * `values.dark` on every write from F0 to DS4 (`values` was an implicit relation), and a revert could
9183
+ * leave the previous apply's dark behind;
9184
+ * - stamped by a v2 pack and still holding what THAT pack writes at its own defaults (its dark half
9185
+ * possibly lost the same way) while the stored design says otherwise: an apply that judged the row
9186
+ * edited (before 5.24.0, a lost dark half did) left it on the default — the six brand rows of a studio
9187
+ * whose brand colour never reached its accent.
9188
+ * No author edit produces either shape — the Tokens panel edited the light value only, and since DS8 an
9189
+ * edit makes the row `source: user`, which this never touches.
9152
9190
  */
9153
9191
  declare function designTokenRepairs(existing: ReadonlyArray<StoredDesignTokenRow>, choices: DesignChoices): FlavorSeedPlan['update'];
9154
9192
  interface SwissMigration {
@@ -9193,5 +9231,5 @@ interface FontFamilyRemoval {
9193
9231
  */
9194
9232
  declare function planFontFamilyRemoval(existing: ReadonlyArray<StoredDesignTokenRow>, previous: StoredDesign, family: string): FontFamilyRemoval;
9195
9233
 
9196
- export { ACCENT_TOKEN_NAMES, AdoptOutcome, AdoptSkipReason, BUTTON_VARIANT_TO_STYLE, COLOR_SCHEMES, COLOR_SCHEME_TRAIT, COLOR_SCHEME_TYPES, ColorScheme, DEFAULT_FLAVOR_ID, DESIGN_TOKEN_GROUPS, DESIGN_TOKEN_TIERS, DESIGN_TOKEN_TYPES, DesignConfigKey, ELEMENT_STYLES, ELEMENT_STYLE_MARKER_CLASS, ELEMENT_STYLE_STATES, EMPTY_IMAGE_ATTRIBUTE, EMPTY_IMAGE_SRC, ElementStyleState, FLAVOR_SPEC_VERSION, FONT_CATALOG, FONT_FAMILY_TOKENS, FONT_FILE_ACCEPT, FONT_FILE_EXTENSIONS, FONT_FILE_FORMATS, FONT_STYLES, FONT_WEIGHTS, FontUploadError, GOOGLE_FONTS_CSS_ORIGIN, GOOGLE_FONTS_FILE_ORIGIN, MAX_FONT_FILE_BYTES, NEW_NODE_STYLE_DEFAULTS, OwnedTraitLink, PALETTE_PRESETS, PRE_DS2_FLAVOR_DEFAULTS, 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, SUPERSEDED_STYLE_VALUES, SWISS_FLAVOR, USER_TOKEN_SOURCE, WCAG_AA_TEXT, adoptElementStyles, adoptionStyleFor, apcaLc, applyElementStyle, applyHeadingLevelRule, buildFlavorTokens, buildFontFaceCss, catalogFontId, checkFontWeight, choicesForPack, colorSchemeClass, colorSchemeOf, compareFontWeights, compileSchemeCss, compileTokenCss, compileTokenCssBlocks, cssString, defaultDesignChoices, defaultElementStyleFor, deriveAccentTokens, deriveBrandTokens, designBaseline, designConfigEntries, designModeOf, designTokenRepairs, designTokenRows, elementStyleById, elementStyleClass, elementStylesFor, emptyImageLabelSrc, emptyImagePlaceholder, emptyImageSrc, flavorPackById, flavorSeedWrites, flavorSourceStamp, fontFamilyKey, fontFileName, fontFileStem, fontFormatOf, fontPreloads, fontRoleReferences, fontStackWithout, fontWeightCovers, fontWeightRange, fontWeightValue, fontsForTokens, formatFontFamilies, formatFontFamily, formatFontWeight, googleFontHref, groupFontFamilies, hasElementStyleMarker, isDesignTokenGroup, isDesignTokenTier, isDesignTokenType, isFontWeightRange, isRetiredFlavorId, legacyRuleTokenReferences, matchFontWeight, missingDesignRows, missingFontRoles, nodeDesignClasses, normalizeFontStyle, normalizeFontWeight, normalizeFontWeightValue, oklabToRgb, ownedTraitStatus, ownedTraitsOf, packDesignChoices, parseFontFamilies, parseFontWeight, parseHexColor, planDesignApply, planDesignRevert, planFlavorRevert, planFlavorSeed, planFontFamilyRemoval, planSwissMigration, previewElementStyleAdoption, previewFontWeight, readDesignConfig, readOwnedTrait, relativeLuminance, resolveDesignChoices, resolveTokenReferences, resolveTokenValues, revertAvailable, rgbToOklab, sameDesignChoices, specTokenNames, springToLinear, stackNamesFamily, styleKeyToKebab, switchElementStyle, syncNodeDesignClasses, toHexColor, tokenReferences, tokensToDarkVarMap, tokensToVarMap, unknownTokenReferences, userFontStack, validateFlavorPack, wcagContrastRatio, writeOwnedTrait };
9197
- export type { AccentBackgrounds, AccentTokenName, AdoptContext, AdoptReport, AdoptableNode, AdoptedNode, ApplyElementStyleResult, DensityId, DesignChoices, DesignClassSource, DesignConfigEntry, DesignMode, DesignTokenGroup, DesignTokenLike, DesignTokenRow, DesignTokenTier, DesignTokenType, ElementStyle, ElementStyleTarget, ElementStyleTraitLike, FlavorPack, FlavorPackV2, FlavorRevertPlan, FlavorRevertSnapshot, FlavorRevertWrite, FlavorSeedPlan, FlavorSpecToken, FlavorTokenDef, FontDescriptor, FontFamilyGroup, FontFamilyRemoval, FontFamilyToken, FontFormat, FontPair, FontRoleToken, FontStyle, FontWeight, FontWeightRange, FontsForTokensOptions, KeptEdit, LinearSpring, MissingFontRole, MotionId, OkLab, OwnedTrait, OwnedTraitStatus, PalettePreset, ResolvedMode, Rgb, SchemeId, SeedBaseline, SeedExpectation, ShapeId, SkippedNode, StoredDesign, StoredDesignTokenRow, SupersededStyleValue, SwissMigration, SwitchElementStyleResult, TokenCssBlocks, TokenCssOptions };
9234
+ export { ACCENT_TOKEN_NAMES, AdoptOutcome, AdoptSkipReason, BUTTON_VARIANT_TO_STYLE, COLOR_SCHEMES, COLOR_SCHEME_TRAIT, COLOR_SCHEME_TYPES, ColorScheme, DEFAULT_FLAVOR_ID, DESIGN_TOKEN_GROUPS, DESIGN_TOKEN_TIERS, DESIGN_TOKEN_TYPES, DesignConfigKey, ELEMENT_STYLES, ELEMENT_STYLE_MARKER_CLASS, ELEMENT_STYLE_STATES, EMPTY_IMAGE_ATTRIBUTE, EMPTY_IMAGE_SRC, ElementStyleState, FLAVOR_SPEC_VERSION, FONT_CATALOG, FONT_FAMILY_TOKENS, FONT_FILE_ACCEPT, FONT_FILE_EXTENSIONS, FONT_FILE_FORMATS, FONT_STYLES, FONT_WEIGHTS, FontUploadError, GOOGLE_FONTS_CSS_ORIGIN, GOOGLE_FONTS_FILE_ORIGIN, MAX_FONT_FILE_BYTES, NEW_NODE_STYLE_DEFAULTS, OwnedTraitLink, PALETTE_PRESETS, PRE_DS2_FLAVOR_DEFAULTS, 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, SUPERSEDED_STYLE_VALUES, SWISS_FLAVOR, USER_TOKEN_SOURCE, WCAG_AA_TEXT, adoptElementStyles, adoptionStyleFor, apcaLc, applyElementStyle, applyHeadingLevelRule, buildFlavorTokens, buildFontFaceCss, catalogFontId, checkFontWeight, choicesForPack, colorSchemeClass, colorSchemeOf, compareFontWeights, compileSchemeCss, compileTokenCss, compileTokenCssBlocks, cssString, defaultDesignChoices, defaultElementStyleFor, deriveAccentTokens, deriveBrandTokens, designBaseline, designConfigEntries, designModeOf, designTokenRepairs, designTokenRows, elementStyleById, elementStyleClass, elementStylesFor, emptyImageLabelSrc, emptyImagePlaceholder, emptyImageSrc, flavorPackById, flavorSeedWrites, flavorSourceStamp, fontFamilyKey, fontFileName, fontFileStem, fontFormatOf, fontPreloads, fontRoleReferences, fontStackWithout, fontWeightCovers, fontWeightRange, fontWeightValue, fontsForTokens, formatFontFamilies, formatFontFamily, formatFontWeight, googleFontHref, groupFontFamilies, hasElementStyleMarker, isDesignTokenGroup, isDesignTokenTier, isDesignTokenType, isFontWeightRange, isRetiredFlavorId, legacyRuleTokenReferences, matchFontWeight, missingDesignRows, missingFontRoles, nodeDesignClasses, normalizeFontStyle, normalizeFontWeight, normalizeFontWeightValue, oklabToRgb, ownedTraitStatus, ownedTraitsOf, packDesignChoices, parseFontFamilies, parseFontWeight, parseHexColor, planDesignApply, planDesignRevert, planFlavorRevert, planFlavorSeed, planFontFamilyRemoval, planSwissMigration, previewElementStyleAdoption, previewFontWeight, readDesignConfig, readOwnedTrait, relativeLuminance, resolveDesignChoices, resolveTokenReferences, resolveTokenValues, revertAvailable, rgbToOklab, sameDesignChoices, specTokenNames, springToLinear, stackNamesFamily, styleKeyToKebab, switchElementStyle, syncNodeDesignClasses, toHexColor, tokenReferences, tokensToDarkVarMap, tokensToVarMap, unknownTokenReferences, untouchedSeedRow, userFontStack, validateFlavorPack, wcagContrastRatio, writeOwnedTrait };
9235
+ export type { AccentBackgrounds, AccentTokenName, AdoptContext, AdoptReport, AdoptableNode, AdoptedNode, ApplyElementStyleResult, DensityId, DesignApplyOptions, DesignChoices, DesignClassSource, DesignConfigEntry, DesignMode, DesignTokenGroup, DesignTokenLike, DesignTokenRow, DesignTokenTier, DesignTokenType, ElementStyle, ElementStyleTarget, ElementStyleTraitLike, FlavorPack, FlavorPackV2, FlavorRevertPlan, FlavorRevertSnapshot, FlavorRevertWrite, FlavorSeedOptions, FlavorSeedPlan, FlavorSpecToken, FlavorTokenDef, FontDescriptor, FontFamilyGroup, FontFamilyRemoval, FontFamilyToken, FontFormat, FontPair, FontRoleToken, FontStyle, FontWeight, FontWeightRange, FontsForTokensOptions, KeptEdit, LinearSpring, MissingFontRole, MotionId, OkLab, OwnedTrait, OwnedTraitStatus, PalettePreset, ResolvedMode, Rgb, SchemeId, SeedBaseline, SeedExpectation, ShapeId, SkippedNode, StoredDesign, StoredDesignTokenRow, SupersededStyleValue, SwissMigration, SwitchElementStyleResult, TokenCssBlocks, TokenCssOptions };
@@ -11334,8 +11334,26 @@ function flavorSeedWrites(plan, existing) {
11334
11334
  }
11335
11335
  return out;
11336
11336
  }
11337
- const expectationFor = (baseline, row) => !baseline ? undefined : typeof baseline === 'function' ? baseline(row) : baseline.get(row.name);
11337
+ function expectationsFor(baseline, row) {
11338
+ if (!baseline)
11339
+ return [];
11340
+ const found = typeof baseline === 'function' ? baseline(row) : baseline.get(row.name);
11341
+ if (!found)
11342
+ return [];
11343
+ return (Array.isArray(found) ? found : [found]).filter(Boolean);
11344
+ }
11338
11345
  const sameValue = (row, e) => row.value === e.value && (row.values?.dark ?? '') === (e.dark ?? '');
11346
+ /**
11347
+ * A machine-stamped row is untouched when it holds what a seed wrote — or that seed's LIGHT value with no
11348
+ * dark half at all: iox-cms dropped every `values.dark` from F0 to DS4.1, and no author edit produces that
11349
+ * shape (the Tokens panel edited the light value only, and since DS8 an edit makes the row `source: user`).
11350
+ * Judging it edited kept the six brand rows of every studio seeded before DS4.1 on the default blue for
11351
+ * good — a later brand never reached them.
11352
+ */
11353
+ function untouchedSeedRow(row, expected) {
11354
+ const darkLost = isSeeded(row) && !row.values?.dark;
11355
+ return expected.some(e => sameValue(row, e) || (darkLost && row.value === e.value));
11356
+ }
11339
11357
  /**
11340
11358
  * The seeding MERGE: desired tokens vs existing rows, deciding create / update / keep. The §10 C2
11341
11359
  * rule — "an upgrade only rewrites untouched rows" — is a comparison against what the PREVIOUS
@@ -11346,10 +11364,12 @@ const sameValue = (row, e) => row.value === e.value && (row.values?.dark ?? '')
11346
11364
  * choice, so a new choice may replace it. `group`/`tier` ride every write; a desired row's own
11347
11365
  * `source` (a chosen font's `user`) wins over the pack stamp. A machine-owned row that already holds
11348
11366
  * the desired value but another pack's stamp is RE-STAMPED (§10 C2 provenance: the stamp names the
11349
- * design that owns the row, so the next switch judges it against the right baseline).
11367
+ * design that owns the row, so the next switch judges it against the right baseline). A row named in
11368
+ * `options.reclaim` is written whatever it holds — the author chose the look's value over their own.
11350
11369
  */
11351
- function planFlavorSeed(desired, existing, stamp, baseline) {
11370
+ function planFlavorSeed(desired, existing, stamp, baseline, options = {}) {
11352
11371
  const byName = new Map((existing ?? []).map(r => [r.name, r]));
11372
+ const reclaim = new Set(options.reclaim ?? []);
11353
11373
  const plan = { create: [], update: [], kept: [] };
11354
11374
  for (const def of desired ?? []) {
11355
11375
  if (!def?.name)
@@ -11367,17 +11387,18 @@ function planFlavorSeed(desired, existing, stamp, baseline) {
11367
11387
  });
11368
11388
  continue;
11369
11389
  }
11370
- const old = expectationFor(baseline, row);
11371
- const designOwned = isSeeded(row) || (row.source === USER_TOKEN_SOURCE && !!old && sameValue(row, old));
11372
- if (!designOwned) {
11390
+ const olds = expectationsFor(baseline, row);
11391
+ const reclaimed = reclaim.has(def.name);
11392
+ const designOwned = isSeeded(row) || (row.source === USER_TOKEN_SOURCE && olds.some(o => sameValue(row, o)));
11393
+ if (!designOwned && !reclaimed) {
11373
11394
  plan.kept.push(def.name);
11374
11395
  continue;
11375
11396
  }
11376
11397
  const sameAsDesired = row.value === def.value && (row.values?.dark ?? '') === (def.values?.dark ?? '');
11377
11398
  if (sameAsDesired && (row.source ?? '') === source)
11378
11399
  continue; // already exactly this
11379
- const untouched = !!old && sameValue(row, old);
11380
- if ((untouched || sameAsDesired) && row._id) {
11400
+ const untouched = untouchedSeedRow(row, olds);
11401
+ if ((untouched || sameAsDesired || reclaimed) && row._id) {
11381
11402
  plan.update.push({ id: row._id, data: { value: def.value, values: def.values ?? {}, source, ...classification(def) } });
11382
11403
  }
11383
11404
  else {
@@ -11629,28 +11650,53 @@ function swissExpectations(seed) {
11629
11650
  }
11630
11651
  return expectations(rows);
11631
11652
  }
11653
+ /** What a v2 pack writes at its OWN defaults, by pack id — computed once per id per caller. */
11654
+ function packDefaultsLookup() {
11655
+ const cache = new Map();
11656
+ return packId => {
11657
+ if (!cache.has(packId)) {
11658
+ const pack = isRetiredFlavorId(packId) ? undefined : flavorPackById(packId);
11659
+ cache.set(packId, pack && pack.id === packId ? expectations(designTokenRows(packDesignChoices(pack.id))) : undefined);
11660
+ }
11661
+ return cache.get(packId);
11662
+ };
11663
+ }
11632
11664
  /**
11633
11665
  * What the PREVIOUS design wrote, as a baseline keyed by the row's own stamp: a row Swiss stamped is
11634
11666
  * judged against what Swiss wrote, every other row against `buildFlavorTokens` of the stored choices
11635
11667
  * (for an org with no design row, Crisp's defaults — exactly what DS2's interim seed wrote). In a
11636
11668
  * Swiss org the only v2 rows are that interim seed's, so they are judged against Crisp's DEFAULTS,
11637
11669
  * never against the brand-seeded Crisp the migration is about to write.
11670
+ *
11671
+ * A row a v2 pack stamped is ALSO untouched while it holds what that pack writes at its own defaults —
11672
+ * what DS2's interim seed, a first run and every pack card at its defaults wrote. Without it, one row
11673
+ * kept for any reason (a dark half iox-cms dropped, `untouchedSeedRow`) was judged against a design that
11674
+ * had moved on, apply after apply, and stayed on the old value for good: the studio's brand colour
11675
+ * reached the design row and never its accent.
11638
11676
  */
11639
11677
  function designBaseline(previous) {
11640
11678
  const retired = isRetiredFlavorId(previous.storedFlavorId);
11641
11679
  const current = expectations(designTokenRows(retired ? packDesignChoices(previous.choices.flavorId) : previous.choices));
11642
11680
  const swiss = swissExpectations(retired ? previous.storedSeed : null);
11681
+ const packDefaults = packDefaultsLookup();
11643
11682
  return (row) => {
11644
11683
  const stampedBy = SEED_STAMP.exec(row.source ?? '')?.[1];
11645
- return stampedBy === SWISS_FLAVOR.id ? swiss.get(row.name) : current.get(row.name);
11684
+ if (stampedBy === SWISS_FLAVOR.id)
11685
+ return swiss.get(row.name);
11686
+ const ownDefault = stampedBy ? packDefaults(stampedBy)?.get(row.name) : undefined;
11687
+ return [current.get(row.name), ownDefault].filter((e) => !!e);
11646
11688
  };
11647
11689
  }
11648
- /** Apply `next` over the org's rows, judged against `previous` — the plan FlavorApplyService runs. */
11649
- function planDesignApply(existing, previous, next) {
11690
+ /**
11691
+ * Apply `next` over the org's rows, judged against `previous` — the plan FlavorApplyService runs. The
11692
+ * plan's `kept` names the author's rows the look leaves alone; the Design card lists them before Apply,
11693
+ * and `options.reclaim` writes the look's value into the ones the author hands back.
11694
+ */
11695
+ function planDesignApply(existing, previous, next, options = {}) {
11650
11696
  const pack = flavorPackById(next.flavorId);
11651
11697
  if (!pack)
11652
11698
  return { create: [], update: [], kept: [] };
11653
- return planFlavorSeed(designTokenRows(next), existing, flavorSourceStamp(pack.id), designBaseline(previous));
11699
+ return planFlavorSeed(designTokenRows(next), existing, flavorSourceStamp(pack.id), designBaseline(previous), { reclaim: options.reclaim });
11654
11700
  }
11655
11701
  /**
11656
11702
  * "Revert to previous look" over the org's rows — the ONE plan the Revert executes and its hint counts
@@ -11671,12 +11717,18 @@ function missingDesignRows(existing, choices) {
11671
11717
  return designTokenRows(choices).filter(r => !have.has(r.name));
11672
11718
  }
11673
11719
  /**
11674
- * The builder-load REPAIR (DS4.1): rows the design owns and nobody touched — stamped by the current
11675
- * pack, light value exactly the pack's — whose dark override differs from the pack's are rewritten.
11676
- * iox-cms dropped `values.dark` on every write from F0 to DS4 (`values` was an implicit relation),
11677
- * and a revert could leave the previous apply's dark behind; both leave a row whose light half is the
11678
- * design's and whose dark half is not. No author edit can produce that shape — the Tokens panel edits
11679
- * the light value only — so rewriting it heals existing orgs without the author doing anything.
11720
+ * The builder-load REPAIR (DS4.1): rows the design writes that are the machine's and nobody touched,
11721
+ * yet hold something other than the design's value, are rewritten — so an org heals on its next load
11722
+ * with no author action. Two shapes:
11723
+ * - stamped by the current pack, light value exactly the pack's, dark half not: iox-cms dropped
11724
+ * `values.dark` on every write from F0 to DS4 (`values` was an implicit relation), and a revert could
11725
+ * leave the previous apply's dark behind;
11726
+ * - stamped by a v2 pack and still holding what THAT pack writes at its own defaults (its dark half
11727
+ * possibly lost the same way) while the stored design says otherwise: an apply that judged the row
11728
+ * edited (before 5.24.0, a lost dark half did) left it on the default — the six brand rows of a studio
11729
+ * whose brand colour never reached its accent.
11730
+ * No author edit produces either shape — the Tokens panel edited the light value only, and since DS8 an
11731
+ * edit makes the row `source: user`, which this never touches.
11680
11732
  */
11681
11733
  function designTokenRepairs(existing, choices) {
11682
11734
  const pack = flavorPackById(choices.flavorId);
@@ -11684,12 +11736,18 @@ function designTokenRepairs(existing, choices) {
11684
11736
  return [];
11685
11737
  const stamp = flavorSourceStamp(pack.id);
11686
11738
  const desired = new Map(designTokenRows(choices).map(r => [r.name, r]));
11739
+ const packDefaults = packDefaultsLookup();
11687
11740
  const out = [];
11688
11741
  for (const row of existing ?? []) {
11689
11742
  const want = desired.get(row.name);
11690
- if (!want || !row._id || row.source !== stamp || want.source !== stamp || row.value !== want.value)
11743
+ if (!want || !row._id || want.source !== stamp)
11744
+ continue;
11745
+ if (row.value === want.value && (row.values?.dark ?? '') === (want.values?.dark ?? '') && row.source === stamp)
11691
11746
  continue;
11692
- if ((row.values?.dark ?? '') === (want.values?.dark ?? ''))
11747
+ const stampedBy = SEED_STAMP.exec(row.source ?? '')?.[1];
11748
+ const darkOnly = row.source === stamp && row.value === want.value;
11749
+ const ownDefault = stampedBy ? packDefaults(stampedBy)?.get(row.name) : undefined;
11750
+ if (!darkOnly && !(ownDefault && untouchedSeedRow(row, [ownDefault])))
11693
11751
  continue;
11694
11752
  out.push({ id: row._id, data: { value: want.value, values: want.values ?? {}, source: stamp, ...(want.group ? { group: want.group } : {}), ...(want.tier ? { tier: want.tier } : {}) } });
11695
11753
  }
@@ -11779,5 +11837,5 @@ function planFontFamilyRemoval(existing, previous, family) {
11779
11837
  * Generated bundle index. Do not edit.
11780
11838
  */
11781
11839
 
11782
- export { ACCENT_TOKEN_NAMES, AdoptOutcome, AdoptSkipReason, BUTTON_VARIANT_TO_STYLE, COLOR_SCHEMES, COLOR_SCHEME_TRAIT, COLOR_SCHEME_TYPES, ColorScheme, DEFAULT_FLAVOR_ID, DESIGN_TOKEN_GROUPS, DESIGN_TOKEN_TIERS, DESIGN_TOKEN_TYPES, DesignConfigKey, ELEMENT_STYLES, ELEMENT_STYLE_MARKER_CLASS, ELEMENT_STYLE_STATES, EMPTY_IMAGE_ATTRIBUTE, EMPTY_IMAGE_SRC, ElementStyleState, FLAVOR_SPEC_VERSION, FONT_CATALOG, FONT_FAMILY_TOKENS, FONT_FILE_ACCEPT, FONT_FILE_EXTENSIONS, FONT_FILE_FORMATS, FONT_STYLES, FONT_WEIGHTS, FontUploadError, GOOGLE_FONTS_CSS_ORIGIN, GOOGLE_FONTS_FILE_ORIGIN, MAX_FONT_FILE_BYTES, NEW_NODE_STYLE_DEFAULTS, OwnedTraitLink, PALETTE_PRESETS, PRE_DS2_FLAVOR_DEFAULTS, 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, SUPERSEDED_STYLE_VALUES, SWISS_FLAVOR, USER_TOKEN_SOURCE, WCAG_AA_TEXT, adoptElementStyles, adoptionStyleFor, apcaLc, applyElementStyle, applyHeadingLevelRule, buildFlavorTokens, buildFontFaceCss, catalogFontId, checkFontWeight, choicesForPack, colorSchemeClass, colorSchemeOf, compareFontWeights, compileSchemeCss, compileTokenCss, compileTokenCssBlocks, cssString, defaultDesignChoices, defaultElementStyleFor, deriveAccentTokens, deriveBrandTokens, designBaseline, designConfigEntries, designModeOf, designTokenRepairs, designTokenRows, elementStyleById, elementStyleClass, elementStylesFor, emptyImageLabelSrc, emptyImagePlaceholder, emptyImageSrc, flavorPackById, flavorSeedWrites, flavorSourceStamp, fontFamilyKey, fontFileName, fontFileStem, fontFormatOf, fontPreloads, fontRoleReferences, fontStackWithout, fontWeightCovers, fontWeightRange, fontWeightValue, fontsForTokens, formatFontFamilies, formatFontFamily, formatFontWeight, googleFontHref, groupFontFamilies, hasElementStyleMarker, isDesignTokenGroup, isDesignTokenTier, isDesignTokenType, isFontWeightRange, isRetiredFlavorId, legacyRuleTokenReferences, matchFontWeight, missingDesignRows, missingFontRoles, nodeDesignClasses, normalizeFontStyle, normalizeFontWeight, normalizeFontWeightValue, oklabToRgb, ownedTraitStatus, ownedTraitsOf, packDesignChoices, parseFontFamilies, parseFontWeight, parseHexColor, planDesignApply, planDesignRevert, planFlavorRevert, planFlavorSeed, planFontFamilyRemoval, planSwissMigration, previewElementStyleAdoption, previewFontWeight, readDesignConfig, readOwnedTrait, relativeLuminance, resolveDesignChoices, resolveTokenReferences, resolveTokenValues, revertAvailable, rgbToOklab, sameDesignChoices, specTokenNames, springToLinear, stackNamesFamily, styleKeyToKebab, switchElementStyle, syncNodeDesignClasses, toHexColor, tokenReferences, tokensToDarkVarMap, tokensToVarMap, unknownTokenReferences, userFontStack, validateFlavorPack, wcagContrastRatio, writeOwnedTrait };
11840
+ export { ACCENT_TOKEN_NAMES, AdoptOutcome, AdoptSkipReason, BUTTON_VARIANT_TO_STYLE, COLOR_SCHEMES, COLOR_SCHEME_TRAIT, COLOR_SCHEME_TYPES, ColorScheme, DEFAULT_FLAVOR_ID, DESIGN_TOKEN_GROUPS, DESIGN_TOKEN_TIERS, DESIGN_TOKEN_TYPES, DesignConfigKey, ELEMENT_STYLES, ELEMENT_STYLE_MARKER_CLASS, ELEMENT_STYLE_STATES, EMPTY_IMAGE_ATTRIBUTE, EMPTY_IMAGE_SRC, ElementStyleState, FLAVOR_SPEC_VERSION, FONT_CATALOG, FONT_FAMILY_TOKENS, FONT_FILE_ACCEPT, FONT_FILE_EXTENSIONS, FONT_FILE_FORMATS, FONT_STYLES, FONT_WEIGHTS, FontUploadError, GOOGLE_FONTS_CSS_ORIGIN, GOOGLE_FONTS_FILE_ORIGIN, MAX_FONT_FILE_BYTES, NEW_NODE_STYLE_DEFAULTS, OwnedTraitLink, PALETTE_PRESETS, PRE_DS2_FLAVOR_DEFAULTS, 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, SUPERSEDED_STYLE_VALUES, SWISS_FLAVOR, USER_TOKEN_SOURCE, WCAG_AA_TEXT, adoptElementStyles, adoptionStyleFor, apcaLc, applyElementStyle, applyHeadingLevelRule, buildFlavorTokens, buildFontFaceCss, catalogFontId, checkFontWeight, choicesForPack, colorSchemeClass, colorSchemeOf, compareFontWeights, compileSchemeCss, compileTokenCss, compileTokenCssBlocks, cssString, defaultDesignChoices, defaultElementStyleFor, deriveAccentTokens, deriveBrandTokens, designBaseline, designConfigEntries, designModeOf, designTokenRepairs, designTokenRows, elementStyleById, elementStyleClass, elementStylesFor, emptyImageLabelSrc, emptyImagePlaceholder, emptyImageSrc, flavorPackById, flavorSeedWrites, flavorSourceStamp, fontFamilyKey, fontFileName, fontFileStem, fontFormatOf, fontPreloads, fontRoleReferences, fontStackWithout, fontWeightCovers, fontWeightRange, fontWeightValue, fontsForTokens, formatFontFamilies, formatFontFamily, formatFontWeight, googleFontHref, groupFontFamilies, hasElementStyleMarker, isDesignTokenGroup, isDesignTokenTier, isDesignTokenType, isFontWeightRange, isRetiredFlavorId, legacyRuleTokenReferences, matchFontWeight, missingDesignRows, missingFontRoles, nodeDesignClasses, normalizeFontStyle, normalizeFontWeight, normalizeFontWeightValue, oklabToRgb, ownedTraitStatus, ownedTraitsOf, packDesignChoices, parseFontFamilies, parseFontWeight, parseHexColor, planDesignApply, planDesignRevert, planFlavorRevert, planFlavorSeed, planFontFamilyRemoval, planSwissMigration, previewElementStyleAdoption, previewFontWeight, readDesignConfig, readOwnedTrait, relativeLuminance, resolveDesignChoices, resolveTokenReferences, resolveTokenValues, revertAvailable, rgbToOklab, sameDesignChoices, specTokenNames, springToLinear, stackNamesFamily, styleKeyToKebab, switchElementStyle, syncNodeDesignClasses, toHexColor, tokenReferences, tokensToDarkVarMap, tokensToVarMap, unknownTokenReferences, untouchedSeedRow, userFontStack, validateFlavorPack, wcagContrastRatio, writeOwnedTrait };
11783
11841
  //# sourceMappingURL=vectoriox-iox-ui-design-core.mjs.map