@multiplatform.one/theme 9.0.1 → 9.0.3

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.
Files changed (119) hide show
  1. package/dist/cjs/theme/createThemes.cjs +153 -107
  2. package/dist/cjs/theme/createThemes.native.js +258 -198
  3. package/dist/cjs/theme/createThemes.native.js.map +1 -1
  4. package/dist/esm/audit/constraintAudit.native.js.map +1 -1
  5. package/dist/esm/audit/designTokens.native.js.map +1 -1
  6. package/dist/esm/audit/diffReport.native.js.map +1 -1
  7. package/dist/esm/audit/index.native.js.map +1 -1
  8. package/dist/esm/audit/themeMatrix.native.js.map +1 -1
  9. package/dist/esm/dates.native.js.map +1 -1
  10. package/dist/esm/devWarn.native.js.map +1 -1
  11. package/dist/esm/expo.native.js.map +1 -1
  12. package/dist/esm/figma/figmaTokens.native.js.map +1 -1
  13. package/dist/esm/font.native.js.map +1 -1
  14. package/dist/esm/fonts/createFontLoader.native.js.map +1 -1
  15. package/dist/esm/fonts/index.native.js.map +1 -1
  16. package/dist/esm/fonts/interFaces.native.js.map +1 -1
  17. package/dist/esm/fonts/types.native.js.map +1 -1
  18. package/dist/esm/index.gnome.native.js.map +1 -1
  19. package/dist/esm/index.native.js.map +1 -1
  20. package/dist/esm/keyboardFocusRing.native.js.map +1 -1
  21. package/dist/esm/menuRow.native.js.map +1 -1
  22. package/dist/esm/nativeTwins.native.js.map +1 -1
  23. package/dist/esm/numbers.native.js.map +1 -1
  24. package/dist/esm/theme/Heading.native.js.map +1 -1
  25. package/dist/esm/theme/IconSlot.native.js.map +1 -1
  26. package/dist/esm/theme/Intent.native.js.map +1 -1
  27. package/dist/esm/theme/Preset.native.js.map +1 -1
  28. package/dist/esm/theme/PresetContext.native.js.map +1 -1
  29. package/dist/esm/theme/Surface.native.js.map +1 -1
  30. package/dist/esm/theme/Text.native.js.map +1 -1
  31. package/dist/esm/theme/Tint.native.js.map +1 -1
  32. package/dist/esm/theme/accentInk.native.js.map +1 -1
  33. package/dist/esm/theme/activateThemeConfig.native.js.map +1 -1
  34. package/dist/esm/theme/animations/css.native.js.map +1 -1
  35. package/dist/esm/theme/animations/index.native.js.map +1 -1
  36. package/dist/esm/theme/animations/reactNative.native.js.map +1 -1
  37. package/dist/esm/theme/chartPalette.native.js.map +1 -1
  38. package/dist/esm/theme/colorRules.native.js.map +1 -1
  39. package/dist/esm/theme/controlTiers.native.js.map +1 -1
  40. package/dist/esm/theme/cookies.native.js.map +1 -1
  41. package/dist/esm/theme/createDefaultThemeConfig.native.js.map +1 -1
  42. package/dist/esm/theme/createThemes.mjs +153 -107
  43. package/dist/esm/theme/createThemes.mjs.map +1 -1
  44. package/dist/esm/theme/createThemes.native.js +258 -198
  45. package/dist/esm/theme/createThemes.native.js.map +1 -1
  46. package/dist/esm/theme/dedupeInherited.native.js.map +1 -1
  47. package/dist/esm/theme/defaults/accent.native.js.map +1 -1
  48. package/dist/esm/theme/defaults/base.native.js.map +1 -1
  49. package/dist/esm/theme/defaults/builderOptions.native.js.map +1 -1
  50. package/dist/esm/theme/defaults/categoryFonts.native.js.map +1 -1
  51. package/dist/esm/theme/defaults/fonts.native.js.map +1 -1
  52. package/dist/esm/theme/defaults/house.native.js.map +1 -1
  53. package/dist/esm/theme/defaults/index.native.js.map +1 -1
  54. package/dist/esm/theme/devtools/animationOptions.native.js.map +1 -1
  55. package/dist/esm/theme/devtools/buildSnapshot.native.js.map +1 -1
  56. package/dist/esm/theme/devtools/index.native.js.map +1 -1
  57. package/dist/esm/theme/devtools/knobIcons.native.js.map +1 -1
  58. package/dist/esm/theme/devtools/vizConstants.native.js.map +1 -1
  59. package/dist/esm/theme/dynamicType.native.js.map +1 -1
  60. package/dist/esm/theme/fieldFocus.native.js.map +1 -1
  61. package/dist/esm/theme/fillContrast.native.js.map +1 -1
  62. package/dist/esm/theme/focusState.native.js.map +1 -1
  63. package/dist/esm/theme/fontCategoryMetrics.native.js.map +1 -1
  64. package/dist/esm/theme/fontCategoryStacks.native.js.map +1 -1
  65. package/dist/esm/theme/glyphPaint.native.js.map +1 -1
  66. package/dist/esm/theme/glyphTint.native.js.map +1 -1
  67. package/dist/esm/theme/groupGeometry.native.js.map +1 -1
  68. package/dist/esm/theme/index.native.js.map +1 -1
  69. package/dist/esm/theme/intents.native.js.map +1 -1
  70. package/dist/esm/theme/knobs.native.js.map +1 -1
  71. package/dist/esm/theme/layoutTokens.native.js.map +1 -1
  72. package/dist/esm/theme/listRows.native.js.map +1 -1
  73. package/dist/esm/theme/mergedTokens.native.js.map +1 -1
  74. package/dist/esm/theme/motion.native.js.map +1 -1
  75. package/dist/esm/theme/motionStops.native.js.map +1 -1
  76. package/dist/esm/theme/motionTiming.native.js.map +1 -1
  77. package/dist/esm/theme/nativeMonoFamily.native.js.map +1 -1
  78. package/dist/esm/theme/nativePresetSwitch.native.js.map +1 -1
  79. package/dist/esm/theme/nativeSchemePreference.native.js.map +1 -1
  80. package/dist/esm/theme/nativeTheme.native.js.map +1 -1
  81. package/dist/esm/theme/nativeTransitionProps.native.js.map +1 -1
  82. package/dist/esm/theme/overlaySurfaces.native.js.map +1 -1
  83. package/dist/esm/theme/pageGutter.native.js.map +1 -1
  84. package/dist/esm/theme/preset.types.native.js.map +1 -1
  85. package/dist/esm/theme/presetPreview.native.js.map +1 -1
  86. package/dist/esm/theme/presetStore.native.js.map +1 -1
  87. package/dist/esm/theme/presetUserSync.native.js.map +1 -1
  88. package/dist/esm/theme/presets.native.js.map +1 -1
  89. package/dist/esm/theme/radiusClass.native.js.map +1 -1
  90. package/dist/esm/theme/radiusClassTable.generated.native.js.map +1 -1
  91. package/dist/esm/theme/ramps.native.js.map +1 -1
  92. package/dist/esm/theme/readableColor.native.js.map +1 -1
  93. package/dist/esm/theme/recipeInputs.native.js.map +1 -1
  94. package/dist/esm/theme/recipes.native.js.map +1 -1
  95. package/dist/esm/theme/resolveKnobs.native.js.map +1 -1
  96. package/dist/esm/theme/scale/activeScale.native.js.map +1 -1
  97. package/dist/esm/theme/scale/deriveRecipeInputs.native.js.map +1 -1
  98. package/dist/esm/theme/scale/index.native.js.map +1 -1
  99. package/dist/esm/theme/scale/scaleAttribute.native.js.map +1 -1
  100. package/dist/esm/theme/scale/scaleCss.native.js.map +1 -1
  101. package/dist/esm/theme/scale/scaleFonts.native.js.map +1 -1
  102. package/dist/esm/theme/scale/scaleInputs.native.js.map +1 -1
  103. package/dist/esm/theme/scale/themeScales.native.js.map +1 -1
  104. package/dist/esm/theme/scale/useActiveScale.native.js.map +1 -1
  105. package/dist/esm/theme/schemeStore.native.js.map +1 -1
  106. package/dist/esm/theme/shared.native.js.map +1 -1
  107. package/dist/esm/theme/sizeRecipes.native.js.map +1 -1
  108. package/dist/esm/theme/subsetThemes.native.js.map +1 -1
  109. package/dist/esm/theme/themeValue.native.js.map +1 -1
  110. package/dist/esm/theme/tileSizes.native.js.map +1 -1
  111. package/dist/esm/theme/tintHues.native.js.map +1 -1
  112. package/dist/esm/theme/tokenNumber.native.js.map +1 -1
  113. package/dist/esm/theme/touchManipulation.native.js.map +1 -1
  114. package/dist/esm/theme/useResolvedKnobs.native.js.map +1 -1
  115. package/dist/esm/theme/useTouchSurface.native.js.map +1 -1
  116. package/dist/esm/theme/v3TokenRoles.native.js.map +1 -1
  117. package/package.json +5 -5
  118. package/src/theme/createThemes.ts +233 -141
  119. package/types/theme/createThemes.d.ts.map +1 -1
@@ -312,99 +312,149 @@ function holdSelectionSurface(themes) {
312
312
  }
313
313
  return out;
314
314
  }
315
+ function ownerScope(scopes, name) {
316
+ return scopes.filter(scope => name === scope || name.startsWith(`${scope}_`)).reduce((longest, scope) => scope.length > longest.length ? scope : longest, "");
317
+ }
318
+ function clearsDarkGrounds(color, grounds) {
319
+ const brightest = Math.max(...grounds);
320
+ const luminance = luminanceOf(color);
321
+ return luminance !== null && luminance > brightest && grounds.every(ground => (0, import_colorRules.contrastRatio)(luminance, ground) >= import_builderOptions.darkHairlineContrast);
322
+ }
323
+ function darkHairlineOf(scope) {
324
+ const ramp = Array.from({
325
+ length: 12
326
+ }, (_, index) => scope[`color${index + 1}`]);
327
+ const grounds = [scope.background, scope.color4].map(color => luminanceOf(color));
328
+ if (grounds.some(ground => ground === null)) return void 0;
329
+ const hairline = ramp.findIndex((color, index) => index < 11 && clearsDarkGrounds(color, grounds));
330
+ return hairline < 0 ? void 0 : {
331
+ ramp,
332
+ hairline
333
+ };
334
+ }
335
+ const darkEdgeStateKeys = ["borderColor", "borderColorHover", "borderColorFocus", "borderColorPress"];
336
+ function darkEdgesOf(name, theme, scopeName, scope, {
337
+ ramp,
338
+ hairline
339
+ }) {
340
+ const medium = hairline + 1;
341
+ const surface = name === scopeName || theme.background === scope.color4;
342
+ const step = ramp.indexOf(theme.borderColor);
343
+ const shift = surface && step >= 0 ? medium - step : 0;
344
+ const moved = {};
345
+ if ("borderColorHairline" in theme || name === scopeName) moved.borderColorHairline = ramp[hairline];
346
+ if (shift <= 0) return moved;
347
+ for (const key of darkEdgeStateKeys) {
348
+ const at = ramp.indexOf(theme[key]);
349
+ if (at >= 0) moved[key] = ramp[Math.min(11, at + shift)];
350
+ }
351
+ return moved;
352
+ }
315
353
  function holdDarkEdges(themes) {
316
354
  const out = {
317
355
  ...themes
318
356
  };
319
357
  const scopes = Object.keys(themes).filter(name => /^dark(_[a-z]+)?$/.test(name));
320
- const ownerOf = name => scopes.filter(scope => name === scope || name.startsWith(`${scope}_`)).reduce((longest, scope) => scope.length > longest.length ? scope : longest, "");
321
358
  for (const scopeName of scopes) {
322
359
  if (/_(accent|active)$/.test(scopeName)) continue;
323
360
  const scope = themes[scopeName];
324
- const ramp = Array.from({
325
- length: 12
326
- }, (_, index) => scope[`color${index + 1}`]);
327
- const grounds = [scope.background, scope.color4].map(color => luminanceOf(color));
328
- if (grounds.some(ground => ground === null)) continue;
329
- const brightest = Math.max(...grounds);
330
- const clears = color => {
331
- const luminance = luminanceOf(color);
332
- return luminance !== null && luminance > brightest && grounds.every(ground => (0, import_colorRules.contrastRatio)(luminance, ground) >= import_builderOptions.darkHairlineContrast);
333
- };
334
- const hairline = ramp.findIndex((color, index) => index < 11 && clears(color));
335
- if (hairline < 0) continue;
336
- const medium = hairline + 1;
361
+ const pick = darkHairlineOf(scope);
362
+ if (!pick) continue;
337
363
  for (const [name, theme] of Object.entries(themes)) {
338
- if (ownerOf(name) !== scopeName) continue;
339
- const surface = name === scopeName || theme.background === scope.color4;
340
- const step = ramp.indexOf(theme.borderColor);
341
- const shift = surface && step >= 0 ? medium - step : 0;
342
- const moved = {};
343
- if ("borderColorHairline" in theme || name === scopeName) moved.borderColorHairline = ramp[hairline];
344
- if (shift > 0) {
345
- for (const key of ["borderColor", "borderColorHover", "borderColorFocus", "borderColorPress"]) {
346
- const at = ramp.indexOf(theme[key]);
347
- if (at >= 0) moved[key] = ramp[Math.min(11, at + shift)];
348
- }
349
- }
364
+ if (ownerScope(scopes, name) !== scopeName) continue;
350
365
  out[name] = {
351
366
  ...out[name],
352
- ...moved
367
+ ...darkEdgesOf(name, theme, scopeName, scope, pick)
353
368
  };
354
369
  }
355
370
  }
356
371
  return out;
357
372
  }
373
+ function firstClearing(neutral, grounds) {
374
+ const lums = grounds.map(ground => luminanceOf(ground));
375
+ if (lums.some(lum => lum === null)) return -1;
376
+ const darkest = Math.min(...lums);
377
+ const brightest = Math.max(...lums);
378
+ const light = (0, import_colorRules.isLightGround)(grounds[0]);
379
+ return neutral.findIndex(color => {
380
+ const lum = luminanceOf(color);
381
+ return lum !== null && (light ? lum < darkest : lum > brightest) && lums.every(ground => (0, import_colorRules.contrastRatio)(lum, ground) >= import_colorRules.minContrastRatio);
382
+ });
383
+ }
384
+ function inheritedValue(out, themes, name, key) {
385
+ for (let at = name; at; at = at.slice(0, Math.max(0, at.lastIndexOf("_")))) {
386
+ const value = (out[at] ?? themes[at])?.[key];
387
+ if (value !== void 0) return value;
388
+ if (!at.includes("_")) break;
389
+ }
390
+ return void 0;
391
+ }
392
+ function nearestStep(ramp, color) {
393
+ const lum = luminanceOf(color);
394
+ if (lum === null) return -1;
395
+ return ramp.reduce((best, step, index) => Math.abs((luminanceOf(step) ?? 2) - lum) < Math.abs((luminanceOf(ramp[best]) ?? 2) - lum) ? index : best, 0);
396
+ }
397
+ function fieldEdgesOf(themes, out, neutral, scopeName) {
398
+ const scope = themes[scopeName];
399
+ const field = `${scopeName}_Input`;
400
+ const edge = firstClearing(neutral, [scope.background, inheritedValue(out, themes, field, "background")]);
401
+ if (edge < 0) return void 0;
402
+ const ramp = Array.from({
403
+ length: 12
404
+ }, (_, index) => scope[`color${index + 1}`]);
405
+ const rest = nearestStep(ramp, inheritedValue(out, themes, field, "borderColor"));
406
+ const hover = nearestStep(ramp, inheritedValue(out, themes, field, "borderColorHover"));
407
+ return {
408
+ borderColorField: neutral[edge],
409
+ borderColorFieldHover: neutral[Math.min(11, Math.max(edge, edge + hover - rest))]
410
+ };
411
+ }
412
+ function intentFieldEdges(themes, out, scopeName, pages) {
413
+ const scope = themes[scopeName];
414
+ const field = `${scopeName}_Input`;
415
+ const ramp = Array.from({
416
+ length: 12
417
+ }, (_, index) => scope[`color${index + 1}`]);
418
+ const edge = firstClearing(ramp, [...pages, inheritedValue(out, themes, field, "background")]);
419
+ if (edge < 0) return {
420
+ borderColorField: inheritedValue(out, themes, field, "borderColor"),
421
+ borderColorFieldHover: inheritedValue(out, themes, field, "borderColorHover")
422
+ };
423
+ return {
424
+ borderColorField: ramp[edge],
425
+ borderColorFieldHover: ramp[Math.min(11, edge + 1)]
426
+ };
427
+ }
428
+ function controlEdgePatch(themes, out, scopeName, {
429
+ scheme,
430
+ neutral,
431
+ pages,
432
+ rootFields,
433
+ rootControl
434
+ }) {
435
+ const scope = themes[scopeName];
436
+ const patch = {};
437
+ if (scheme === "dark" && "switchTrackOff" in scope) patch.switchTrackOffBorder = scope.switchTrackOff;
438
+ if (semanticIntentNames.has(scopeName.slice(scheme.length + 1))) return Object.assign(patch, intentFieldEdges(themes, out, scopeName, pages));
439
+ const fields = fieldEdgesOf(themes, out, neutral, scopeName);
440
+ if (fields) {
441
+ for (const [key, value] of Object.entries(fields)) if (value !== rootFields[key]) patch[key] = value;
442
+ }
443
+ const control = firstClearing(neutral, [scope.background]);
444
+ if (control >= 0 && control !== rootControl) patch.borderColorControl = neutral[control];
445
+ return patch;
446
+ }
358
447
  function holdControlEdges(themes) {
359
448
  const out = {
360
449
  ...themes
361
450
  };
362
- const firstClearing = (neutral, grounds) => {
363
- const lums = grounds.map(ground => luminanceOf(ground));
364
- if (lums.some(lum => lum === null)) return -1;
365
- const darkest = Math.min(...lums);
366
- const brightest = Math.max(...lums);
367
- const light = (0, import_colorRules.isLightGround)(grounds[0]);
368
- return neutral.findIndex(color => {
369
- const lum = luminanceOf(color);
370
- return lum !== null && (light ? lum < darkest : lum > brightest) && lums.every(ground => (0, import_colorRules.contrastRatio)(lum, ground) >= import_colorRules.minContrastRatio);
371
- });
372
- };
373
- const resolved = (name, key) => {
374
- for (let at = name; at; at = at.slice(0, Math.max(0, at.lastIndexOf("_")))) {
375
- const value = (out[at] ?? themes[at])?.[key];
376
- if (value !== void 0) return value;
377
- if (!at.includes("_")) break;
378
- }
379
- return void 0;
380
- };
381
451
  for (const scheme of ["light", "dark"]) {
382
452
  const root = themes[scheme];
383
453
  if (!root) continue;
384
454
  const neutral = Array.from({
385
455
  length: 12
386
456
  }, (_, index) => root[`color${index + 1}`]);
387
- const fieldEdges = scopeName => {
388
- const scope = themes[scopeName];
389
- const field = `${scopeName}_Input`;
390
- const edge = firstClearing(neutral, [scope.background, resolved(field, "background")]);
391
- if (edge < 0) return void 0;
392
- const ramp = Array.from({
393
- length: 12
394
- }, (_, index) => scope[`color${index + 1}`]);
395
- const stepOf = color => {
396
- const lum = luminanceOf(color);
397
- if (lum === null) return -1;
398
- return ramp.reduce((best, step, index) => Math.abs((luminanceOf(step) ?? 2) - lum) < Math.abs((luminanceOf(ramp[best]) ?? 2) - lum) ? index : best, 0);
399
- };
400
- const rest = stepOf(resolved(field, "borderColor"));
401
- const hover = stepOf(resolved(field, "borderColorHover"));
402
- return {
403
- borderColorField: neutral[edge],
404
- borderColorFieldHover: neutral[Math.min(11, Math.max(edge, edge + hover - rest))]
405
- };
406
- };
407
- const rootFields = fieldEdges(scheme);
457
+ const rootFields = fieldEdgesOf(themes, out, neutral, scheme);
408
458
  const rootControl = firstClearing(neutral, [root.background]);
409
459
  if (!rootFields || rootControl < 0) continue;
410
460
  out[scheme] = {
@@ -415,26 +465,15 @@ function holdControlEdges(themes) {
415
465
  };
416
466
  const scopes = Object.keys(themes).filter(name => new RegExp(`^${scheme}_[a-z]+$`).test(name) && !/_(accent|active)$/.test(name));
417
467
  const pages = [root.background, ...scopes.filter(name => !semanticIntentNames.has(name.slice(scheme.length + 1))).map(name => themes[name].background)];
468
+ const context = {
469
+ scheme,
470
+ neutral,
471
+ pages,
472
+ rootFields,
473
+ rootControl
474
+ };
418
475
  for (const scopeName of scopes) {
419
- const scope = themes[scopeName];
420
- const patch = {};
421
- if (scheme === "dark" && "switchTrackOff" in scope) patch.switchTrackOffBorder = scope.switchTrackOff;
422
- if (semanticIntentNames.has(scopeName.slice(scheme.length + 1))) {
423
- const field = `${scopeName}_Input`;
424
- const ramp = Array.from({
425
- length: 12
426
- }, (_, index) => scope[`color${index + 1}`]);
427
- const edge = firstClearing(ramp, [...pages, resolved(field, "background")]);
428
- patch.borderColorField = edge < 0 ? resolved(field, "borderColor") : ramp[edge];
429
- patch.borderColorFieldHover = edge < 0 ? resolved(field, "borderColorHover") : ramp[Math.min(11, edge + 1)];
430
- } else {
431
- const fields = fieldEdges(scopeName);
432
- if (fields) {
433
- for (const [key, value] of Object.entries(fields)) if (value !== rootFields[key]) patch[key] = value;
434
- }
435
- const control = firstClearing(neutral, [scope.background]);
436
- if (control >= 0 && control !== rootControl) patch.borderColorControl = neutral[control];
437
- }
476
+ const patch = controlEdgePatch(themes, out, scopeName, context);
438
477
  if (Object.keys(patch).length > 0) out[scopeName] = {
439
478
  ...out[scopeName],
440
479
  ...patch
@@ -527,11 +566,7 @@ function holdSwitchTrack(themes) {
527
566
  if (scheme !== "dark" || !paint) continue;
528
567
  for (const intent of semanticIntentNames) {
529
568
  const scope = themes[`${scheme}_${intent}`];
530
- const off = luminanceOf(paint.switchTrackOff);
531
- if (!scope?.color4 || !scope.color5 || off === null) continue;
532
- const holds = (0, import_colorRules.inSwitchOffBand)(paint.switchTrackOff, scope.color4) && [scope.color4, scope.color5].every(ground => (0, import_colorRules.contrastRatio)(off, luminanceOf(ground) ?? off) >= import_colorRules.plateContrastRatio);
533
- if (holds) continue;
534
- const track = switchTrackPaint(base, scope.accentBackground ?? base.accentBackground, scope.color4, [base.color4, scope.color4, scope.color5]);
569
+ const track = intentSwitchTrack(base, scope, paint);
535
570
  if (track) out[`${scheme}_${intent}`] = {
536
571
  ...scope,
537
572
  ...track
@@ -540,6 +575,13 @@ function holdSwitchTrack(themes) {
540
575
  }
541
576
  return out;
542
577
  }
578
+ function intentSwitchTrack(base, scope, paint) {
579
+ const off = luminanceOf(paint.switchTrackOff);
580
+ if (!scope?.color4 || !scope.color5 || off === null) return void 0;
581
+ const holds = (0, import_colorRules.inSwitchOffBand)(paint.switchTrackOff, scope.color4) && [scope.color4, scope.color5].every(ground => (0, import_colorRules.contrastRatio)(off, luminanceOf(ground) ?? off) >= import_colorRules.plateContrastRatio);
582
+ if (holds) return void 0;
583
+ return switchTrackPaint(base, scope.accentBackground ?? base.accentBackground, scope.color4, [base.color4, scope.color4, scope.color5]);
584
+ }
543
585
  function switchTrackPaint(base, onFill, ground, raised = []) {
544
586
  const on = luminanceOf(onFill);
545
587
  if (!ground || on === null) return void 0;
@@ -718,7 +760,8 @@ function holdColorThemeAccent(themes) {
718
760
  const fillLum = luminanceOf(fill);
719
761
  const switchGround = (0, import_colorRules.switchOffGround)(scope) ?? scope.background;
720
762
  const rootHolds = rootOn === null || fillLum === null || (0, import_colorRules.contrastRatio)(rootOn, fillLum) >= switchStateContrastRatio && (0, import_colorRules.inSwitchOffBand)(base.switchTrackOff, switchGround) && ((0, import_colorRules.isLightGround)(scope.background) ? [] : [scope.color4, scope.color5]).every(ground => (0, import_colorRules.contrastRatio)(rootOn, luminanceOf(ground) ?? rootOn) >= import_colorRules.plateContrastRatio);
721
- const track = rootHolds ? void 0 : switchTrackPaint(base, fill, switchGround, (0, import_colorRules.isLightGround)(scope.background) ? [] : [base.color4, scope.color4, scope.color5]);
763
+ const trackGrounds = (0, import_colorRules.isLightGround)(scope.background) ? [] : [base.color4, scope.color4, scope.color5];
764
+ const track = rootHolds ? void 0 : switchTrackPaint(base, fill, switchGround, trackGrounds);
722
765
  for (const [name, theme] of Object.entries(themes)) {
723
766
  if (name === scopeName) {
724
767
  out[name] = {
@@ -836,26 +879,29 @@ function holdHouseIdentityInk(themes) {
836
879
  const base = themes[scheme];
837
880
  const blueInk = themes[`${scheme}_blue`]?.identityInk;
838
881
  if (!base?.identityInk || !blueInk || base.identityInk === blueInk) continue;
839
- const held = Array.from({
840
- length: 12
841
- }, (_, index) => index + 1).every(step => base[`accent${step}`] !== void 0 && base[`accent${step}`] === base[`blue${step}`]);
842
- if (!held) continue;
882
+ if (!accentIsBlue(base)) continue;
843
883
  for (const [name, theme] of Object.entries(themes)) {
844
- if (name !== scheme && !name.startsWith(`${scheme}_`)) continue;
845
- const scope = name.split("_")[1];
846
- if (scope === "accent" || childrenHues.includes(scope)) continue;
847
- if (theme.identityInk !== base.identityInk) continue;
848
- const values = (0, import_dedupeInherited.resolveThemeThroughParents)(themes, name);
849
- if ((0, import_accentInk.pickIdentityInk)([blueInk], (0, import_accentInk.pageSurfaces)(name, values)) === blueInk) {
850
- out[name] = {
851
- ...theme,
852
- identityInk: blueInk
853
- };
854
- }
884
+ if (takesBlueInk(themes, scheme, name, theme, base, blueInk)) out[name] = {
885
+ ...theme,
886
+ identityInk: blueInk
887
+ };
855
888
  }
856
889
  }
857
890
  return out;
858
891
  }
892
+ function accentIsBlue(base) {
893
+ return Array.from({
894
+ length: 12
895
+ }, (_, index) => index + 1).every(step => base[`accent${step}`] !== void 0 && base[`accent${step}`] === base[`blue${step}`]);
896
+ }
897
+ function takesBlueInk(themes, scheme, name, theme, base, blueInk) {
898
+ if (name !== scheme && !name.startsWith(`${scheme}_`)) return false;
899
+ const scope = name.split("_")[1];
900
+ if (scope === "accent" || childrenHues.includes(scope)) return false;
901
+ if (theme.identityInk !== base.identityInk) return false;
902
+ const values = (0, import_dedupeInherited.resolveThemeThroughParents)(themes, name);
903
+ return (0, import_accentInk.pickIdentityInk)([blueInk], (0, import_accentInk.pageSurfaces)(name, values)) === blueInk;
904
+ }
859
905
  const defaultLightShadows = {
860
906
  shadow1: "rgba(0,0,0,0.04)",
861
907
  shadow2: "rgba(0,0,0,0.08)",