@unpunnyfuns/swatchbook-blocks 0.65.0 → 0.66.1

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/dist/index.mjs CHANGED
@@ -166,6 +166,7 @@ let snapshot = {
166
166
  diagnostics: [],
167
167
  css: "",
168
168
  cssVarPrefix: "",
169
+ indicators: {},
169
170
  listing: {},
170
171
  tokenGraph: {
171
172
  nodes: {},
@@ -185,6 +186,7 @@ function applyPatch(patch) {
185
186
  diagnostics: patch.diagnostics ?? snapshot.diagnostics,
186
187
  css: patch.css ?? snapshot.css,
187
188
  cssVarPrefix: patch.cssVarPrefix ?? snapshot.cssVarPrefix,
189
+ indicators: patch.indicators ?? snapshot.indicators,
188
190
  listing: patch.listing ?? snapshot.listing,
189
191
  tokenGraph: patch.tokenGraph ?? snapshot.tokenGraph,
190
192
  defaultTuple: patch.defaultTuple ?? snapshot.defaultTuple,
@@ -269,6 +271,7 @@ function useProject() {
269
271
  const activeTheme = snapshot?.activeTheme;
270
272
  const diagnostics = snapshot?.diagnostics;
271
273
  const cssVarPrefix = snapshot?.cssVarPrefix;
274
+ const indicators = snapshot?.indicators;
272
275
  const listing = snapshot?.listing;
273
276
  const tokenGraph = snapshot?.tokenGraph;
274
277
  const resolveAt = useMemo(() => {
@@ -285,6 +288,7 @@ function useProject() {
285
288
  resolved: resolveAt(activeAxes),
286
289
  diagnostics: diagnostics ?? [],
287
290
  cssVarPrefix: cssVarPrefix ?? "",
291
+ indicators: indicators ?? {},
288
292
  listing: listing ?? {},
289
293
  varianceByPath: derivedVarianceByPath,
290
294
  resolveAt
@@ -297,6 +301,7 @@ function useProject() {
297
301
  activeAxes,
298
302
  diagnostics,
299
303
  cssVarPrefix,
304
+ indicators,
300
305
  listing,
301
306
  derivedVarianceByPath,
302
307
  tokenGraph
@@ -330,6 +335,7 @@ function useVirtualModuleFallback(enabled) {
330
335
  resolved: resolveAt(activeAxes),
331
336
  diagnostics: tokens.diagnostics,
332
337
  cssVarPrefix: tokens.cssVarPrefix,
338
+ indicators: tokens.indicators,
333
339
  listing: tokens.listing,
334
340
  varianceByPath: fallbackVarianceByPath,
335
341
  resolveAt
@@ -339,6 +345,7 @@ function useVirtualModuleFallback(enabled) {
339
345
  tokens.axes,
340
346
  tokens.diagnostics,
341
347
  tokens.cssVarPrefix,
348
+ tokens.indicators,
342
349
  tokens.listing,
343
350
  fallbackVarianceByPath,
344
351
  resolveAt
@@ -760,6 +767,273 @@ function ColorPalette({ filter, groupBy, caption, sortBy = "path", sortDir = "as
760
767
  });
761
768
  }
762
769
  //#endregion
770
+ //#region src/indicators/resolve.ts
771
+ /** Established-on set; `description` and `composes` are opt-in. */
772
+ const DEFAULT_INDICATORS = {
773
+ alias: true,
774
+ variance: true,
775
+ gamut: true,
776
+ deprecation: true,
777
+ description: false,
778
+ composes: false
779
+ };
780
+ /**
781
+ * Normalize an `IndicatorsProp` into a full enabled-map. Precedence
782
+ * (lowest→highest): `DEFAULT_INDICATORS` → `baseline` (the project-wide
783
+ * `config.indicators` default) → per-block `prop`. An explicit boolean
784
+ * `prop` (`true`/`false`) forces every key on/off and wins over the
785
+ * baseline; an object `prop` overlays on top of defaults+baseline; an
786
+ * absent `prop` leaves the result at defaults overlaid with baseline.
787
+ */
788
+ function resolveIndicators(prop, baseline) {
789
+ if (prop === true) return {
790
+ alias: true,
791
+ variance: true,
792
+ gamut: true,
793
+ deprecation: true,
794
+ description: true,
795
+ composes: true
796
+ };
797
+ if (prop === false) return {
798
+ alias: false,
799
+ variance: false,
800
+ gamut: false,
801
+ deprecation: false,
802
+ description: false,
803
+ composes: false
804
+ };
805
+ return {
806
+ ...DEFAULT_INDICATORS,
807
+ ...baseline,
808
+ ...prop
809
+ };
810
+ }
811
+ //#endregion
812
+ //#region src/indicators/RowIndicators.tsx
813
+ function relativeLabel(path, root) {
814
+ if (root && path.startsWith(`${root}.`)) return path.slice(root.length + 1);
815
+ return path;
816
+ }
817
+ const COMPOSITE_TYPES = new Set([
818
+ "border",
819
+ "typography",
820
+ "transition",
821
+ "gradient",
822
+ "shadow"
823
+ ]);
824
+ function compositeFieldCount(token) {
825
+ if (!token.$type || !COMPOSITE_TYPES.has(token.$type)) return void 0;
826
+ const v = token.$value;
827
+ if (Array.isArray(v)) return v.length > 0 ? v.length : void 0;
828
+ if (v !== null && typeof v === "object") {
829
+ const n = Object.keys(v).length;
830
+ return n > 0 ? n : void 0;
831
+ }
832
+ }
833
+ /**
834
+ * The forward alias chain for one row. Full chain in `aria-label`; visually
835
+ * capped to first … last beyond two hops (no width measurement). Each shown
836
+ * node navigates when in view, else renders as plain text.
837
+ */
838
+ function ForwardChain({ chain, root, canReference, onReferenceClick }) {
839
+ const full = chain.map((p) => relativeLabel(p, root)).join(" → ");
840
+ const capped = chain.length > 2;
841
+ const shown = capped ? [chain[0], chain[chain.length - 1]] : [...chain];
842
+ return /* @__PURE__ */ jsxs("span", {
843
+ className: "sb-indicator__alias-forward",
844
+ "data-testid": "row-indicator-alias-forward",
845
+ "aria-label": `aliases ${full}`,
846
+ children: [/* @__PURE__ */ jsx("span", {
847
+ className: "sb-indicator__alias-arrow",
848
+ "aria-hidden": true,
849
+ children: "→"
850
+ }), shown.map((target, i) => {
851
+ const label = relativeLabel(target, root);
852
+ return /* @__PURE__ */ jsxs("span", { children: [canReference(target) ? /* @__PURE__ */ jsx("button", {
853
+ type: "button",
854
+ className: "sb-indicator__alias-node",
855
+ "data-testid": "alias-node",
856
+ "aria-label": target,
857
+ onClick: (e) => {
858
+ e.stopPropagation();
859
+ onReferenceClick(target);
860
+ },
861
+ children: label
862
+ }) : /* @__PURE__ */ jsx("span", {
863
+ className: "sb-indicator__alias-node sb-indicator__alias-node--offview",
864
+ "data-testid": "alias-node",
865
+ title: "outside current view",
866
+ children: label
867
+ }), capped && i === 0 ? /* @__PURE__ */ jsxs("span", {
868
+ className: "sb-indicator__alias-arrow",
869
+ "aria-hidden": true,
870
+ children: [
871
+ " ",
872
+ "→ … →",
873
+ " "
874
+ ]
875
+ }) : i < shown.length - 1 ? /* @__PURE__ */ jsxs("span", {
876
+ className: "sb-indicator__alias-arrow",
877
+ "aria-hidden": true,
878
+ children: [
879
+ " ",
880
+ "→",
881
+ " "
882
+ ]
883
+ }) : null] }, target);
884
+ })]
885
+ });
886
+ }
887
+ function DeprecatedBadge({ deprecated }) {
888
+ const label = typeof deprecated === "string" ? `deprecated: ${deprecated}` : "deprecated";
889
+ return /* @__PURE__ */ jsx("span", {
890
+ className: "sb-indicator__deprecated",
891
+ "data-testid": "row-indicator-deprecated",
892
+ title: label,
893
+ "aria-label": label,
894
+ children: "deprecated"
895
+ });
896
+ }
897
+ function VarianceBadge({ variance }) {
898
+ if (variance.kind === "constant") return null;
899
+ const axes = variance.varyingAxes;
900
+ const label = variance.kind === "single" ? variance.axis : `${axes.length} axes`;
901
+ return /* @__PURE__ */ jsxs("span", {
902
+ className: "sb-indicator__variance",
903
+ "data-testid": "row-indicator-variance",
904
+ "aria-label": `varies by ${axes.join(", ")}`,
905
+ children: [/* @__PURE__ */ jsx("span", {
906
+ className: "sb-indicator__variance-glyph",
907
+ "aria-hidden": true,
908
+ children: "⊹"
909
+ }), label]
910
+ });
911
+ }
912
+ function ReverseCount({ referents, canReference, onReferenceClick }) {
913
+ const [open, setOpen] = useState(false);
914
+ const wrapRef = useRef(null);
915
+ const count = referents.length;
916
+ const single = count === 1;
917
+ useEffect(() => {
918
+ if (single || !open) return;
919
+ (wrapRef.current?.querySelector("button[role=\"menuitem\"]:not(:disabled)"))?.focus();
920
+ const handlePointerDown = (e) => {
921
+ if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
922
+ };
923
+ document.addEventListener("pointerdown", handlePointerDown);
924
+ return () => {
925
+ document.removeEventListener("pointerdown", handlePointerDown);
926
+ };
927
+ }, [open, single]);
928
+ return /* @__PURE__ */ jsxs("span", {
929
+ ref: wrapRef,
930
+ className: "sb-indicator__reverse-wrap",
931
+ onKeyDown: (e) => {
932
+ if (e.key === "Escape") setOpen(false);
933
+ },
934
+ children: [/* @__PURE__ */ jsxs("button", {
935
+ type: "button",
936
+ className: "sb-indicator__alias-reverse",
937
+ "data-testid": "row-indicator-alias-reverse",
938
+ "aria-label": `referenced by ${count} ${count === 1 ? "token" : "tokens"}`,
939
+ "aria-haspopup": single ? void 0 : "menu",
940
+ "aria-expanded": single ? void 0 : open,
941
+ onClick: (e) => {
942
+ e.stopPropagation();
943
+ if (single) onReferenceClick(referents[0]);
944
+ else setOpen((v) => !v);
945
+ },
946
+ children: [/* @__PURE__ */ jsx("span", {
947
+ className: "sb-indicator__alias-arrow",
948
+ "aria-hidden": true,
949
+ children: "←"
950
+ }), count]
951
+ }), !single && open && /* @__PURE__ */ jsx("ul", {
952
+ className: "sb-indicator__reverse-menu",
953
+ role: "menu",
954
+ children: referents.map((ref) => /* @__PURE__ */ jsx("li", {
955
+ role: "none",
956
+ children: /* @__PURE__ */ jsx("button", {
957
+ type: "button",
958
+ role: "menuitem",
959
+ className: "sb-indicator__reverse-item",
960
+ disabled: !canReference(ref),
961
+ title: canReference(ref) ? void 0 : "outside current view",
962
+ onClick: (e) => {
963
+ e.stopPropagation();
964
+ setOpen(false);
965
+ onReferenceClick(ref);
966
+ },
967
+ children: ref
968
+ })
969
+ }, ref))
970
+ })]
971
+ });
972
+ }
973
+ /** Per-row indicator strip: alias references, variance, gamut, deprecation. */
974
+ function RowIndicators(props) {
975
+ const { token, root, variance, colorFormat, canReference, onReferenceClick } = props;
976
+ const en = props.enabled ?? resolveIndicators(void 0);
977
+ const aliasChain = Array.isArray(token.aliasChain) && token.aliasChain.length > 0 ? token.aliasChain : void 0;
978
+ const reverseCount = Array.isArray(token.aliasedBy) && token.aliasedBy.length > 0 ? token.aliasedBy.length : 0;
979
+ const isVarying = variance !== void 0 && variance.kind !== "constant";
980
+ const outOfGamut = token.$type === "color" && (formatColor(token.$value, colorFormat)?.outOfGamut ?? false);
981
+ const deprecated = token.$deprecated;
982
+ const isDeprecated = deprecated === true || typeof deprecated === "string" && deprecated.length > 0;
983
+ const description = typeof token.$description === "string" && token.$description.length > 0 ? token.$description : void 0;
984
+ const composesCount = en.composes ? compositeFieldCount(token) : void 0;
985
+ const showDeprecated = en.deprecation && isDeprecated;
986
+ const showForward = en.alias && aliasChain !== void 0;
987
+ const showReverse = en.alias && reverseCount > 0;
988
+ const showVariance = en.variance && isVarying;
989
+ const showGamut = en.gamut && outOfGamut;
990
+ const showDescription = en.description && description !== void 0;
991
+ const showComposes = composesCount !== void 0;
992
+ if (!showDeprecated && !showForward && !showReverse && !showVariance && !showGamut && !showDescription && !showComposes) return null;
993
+ return /* @__PURE__ */ jsxs("span", {
994
+ className: "sb-indicator__indicators",
995
+ children: [
996
+ showDeprecated && deprecated !== void 0 && /* @__PURE__ */ jsx(DeprecatedBadge, { deprecated }),
997
+ showForward && aliasChain && /* @__PURE__ */ jsx(ForwardChain, {
998
+ chain: aliasChain,
999
+ root,
1000
+ canReference,
1001
+ onReferenceClick
1002
+ }),
1003
+ showReverse && token.aliasedBy && /* @__PURE__ */ jsx(ReverseCount, {
1004
+ referents: token.aliasedBy,
1005
+ canReference,
1006
+ onReferenceClick
1007
+ }),
1008
+ showComposes && composesCount !== void 0 && /* @__PURE__ */ jsxs("span", {
1009
+ className: "sb-indicator__composes",
1010
+ "data-testid": "row-indicator-composes",
1011
+ title: `composes ${composesCount} parts`,
1012
+ "aria-label": `composes ${composesCount} parts`,
1013
+ children: [/* @__PURE__ */ jsx("span", {
1014
+ className: "sb-indicator__composes-glyph",
1015
+ "aria-hidden": true,
1016
+ children: "⊞"
1017
+ }), composesCount]
1018
+ }),
1019
+ showVariance && variance && /* @__PURE__ */ jsx(VarianceBadge, { variance }),
1020
+ showGamut && /* @__PURE__ */ jsx("span", {
1021
+ className: "sb-indicator__gamut",
1022
+ title: "Out of sRGB gamut for this format",
1023
+ "aria-label": "out of gamut",
1024
+ children: "⚠"
1025
+ }),
1026
+ showDescription && description !== void 0 && /* @__PURE__ */ jsx("span", {
1027
+ className: "sb-indicator__description",
1028
+ "data-testid": "row-indicator-description",
1029
+ title: description,
1030
+ "aria-label": `description: ${description}`,
1031
+ children: "ⓘ"
1032
+ })
1033
+ ]
1034
+ });
1035
+ }
1036
+ //#endregion
763
1037
  //#region src/internal/CopyButton.tsx
764
1038
  /**
765
1039
  * Copy the given string to the clipboard and briefly surface a "Copied!"
@@ -862,11 +1136,16 @@ function usePersistedState(key, initial) {
862
1136
  }
863
1137
  //#endregion
864
1138
  //#region src/ColorTable.tsx
1139
+ const NOOP_REFERENCE = () => {};
865
1140
  const BASE_LABEL = "base";
866
1141
  const COLUMN_COUNT = 6;
867
- function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect, variants, id }) {
868
- const { resolved, activeTheme, activeAxes, cssVarPrefix, listing } = useProject();
1142
+ function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect, variants, id, indicators }) {
1143
+ const { resolved, activeTheme, activeAxes, cssVarPrefix, listing, varianceByPath } = useProject();
869
1144
  const colorFormat = useColorFormat();
1145
+ const enabledIndicators = useMemo(() => ({
1146
+ ...resolveIndicators(indicators),
1147
+ gamut: false
1148
+ }), [indicators]);
870
1149
  const blockKey = useBlockKey("ColorTable", [
871
1150
  filter,
872
1151
  caption,
@@ -900,6 +1179,8 @@ function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searcha
900
1179
  const variant = {
901
1180
  label: match?.label ?? BASE_LABEL,
902
1181
  path,
1182
+ token,
1183
+ variance: varianceByPath[path],
903
1184
  cssVar: resolveCssVar(path, projectFields),
904
1185
  value: active.value,
905
1186
  outOfGamut: active.outOfGamut,
@@ -933,6 +1214,7 @@ function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searcha
933
1214
  resolved,
934
1215
  listing,
935
1216
  cssVarPrefix,
1217
+ varianceByPath,
936
1218
  filter,
937
1219
  sortBy,
938
1220
  sortDir,
@@ -1014,8 +1296,11 @@ function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searcha
1014
1296
  children: "CSS var"
1015
1297
  }),
1016
1298
  /* @__PURE__ */ jsx("th", {
1017
- className: "sb-color-table__th",
1018
- children: "Alias"
1299
+ className: "sb-color-table__th sb-color-table__th--refs",
1300
+ children: /* @__PURE__ */ jsx("span", {
1301
+ className: "sb-color-table__sr-only",
1302
+ children: "References and status"
1303
+ })
1019
1304
  }),
1020
1305
  /* @__PURE__ */ jsx("th", {
1021
1306
  className: "sb-color-table__th sb-color-table__th--expand",
@@ -1039,6 +1324,8 @@ function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searcha
1039
1324
  expanded: expandedByBase.has(group.base),
1040
1325
  onToggleExpand: toggleExpand,
1041
1326
  onSelectVariant: selectVariant,
1327
+ enabled: enabledIndicators,
1328
+ colorFormat,
1042
1329
  ...onSelect !== void 0 && { onSelect }
1043
1330
  }, group.base))] })
1044
1331
  ]
@@ -1046,10 +1333,12 @@ function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searcha
1046
1333
  })]
1047
1334
  });
1048
1335
  }
1049
- const GroupRow = memo(function GroupRow({ group, selectedLabel, expanded, onToggleExpand, onSelectVariant, onSelect }) {
1336
+ const GroupRow = memo(function GroupRow({ group, selectedLabel, expanded, onToggleExpand, onSelectVariant, onSelect, enabled, colorFormat }) {
1050
1337
  const multi = group.variants.length > 1;
1051
1338
  const active = group.variants.find((v) => v.label === selectedLabel) ?? group.variants[0];
1052
1339
  const nameText = multi ? group.base : active.path;
1340
+ const dep = active.token.$deprecated;
1341
+ const isDeprecated = dep === true || typeof dep === "string" && dep.length > 0;
1053
1342
  const handleRowActivate = () => {
1054
1343
  if (onSelect) onSelect(active.path);
1055
1344
  else onToggleExpand(group.base);
@@ -1080,6 +1369,7 @@ const GroupRow = memo(function GroupRow({ group, selectedLabel, expanded, onTogg
1080
1369
  }),
1081
1370
  /* @__PURE__ */ jsxs("td", {
1082
1371
  className: cx("sb-color-table__td", "sb-color-table__path"),
1372
+ "data-deprecated": enabled.deprecation && isDeprecated ? "true" : void 0,
1083
1373
  children: [/* @__PURE__ */ jsx("span", {
1084
1374
  className: "sb-color-table__path-text",
1085
1375
  children: nameText
@@ -1114,14 +1404,16 @@ const GroupRow = memo(function GroupRow({ group, selectedLabel, expanded, onTogg
1114
1404
  label: `Copy CSS var ${active.cssVar}`
1115
1405
  }),
1116
1406
  /* @__PURE__ */ jsx("td", {
1117
- className: "sb-color-table__td sb-color-table__alias",
1118
- children: active.aliasOf ? /* @__PURE__ */ jsx("span", {
1119
- className: "sb-color-table__alias-text",
1120
- children: active.aliasOf
1121
- }) : /* @__PURE__ */ jsx("span", {
1122
- className: "sb-color-table__alias-empty",
1123
- "aria-hidden": true,
1124
- children: "—"
1407
+ className: "sb-color-table__td sb-color-table__refs",
1408
+ children: /* @__PURE__ */ jsx(RowIndicators, {
1409
+ path: active.path,
1410
+ token: active.token,
1411
+ root: void 0,
1412
+ variance: active.variance,
1413
+ colorFormat,
1414
+ canReference: () => false,
1415
+ onReferenceClick: NOOP_REFERENCE,
1416
+ enabled
1125
1417
  })
1126
1418
  }),
1127
1419
  /* @__PURE__ */ jsx("td", {
@@ -3640,234 +3932,6 @@ function isInView(path, ctx) {
3640
3932
  return true;
3641
3933
  }
3642
3934
  //#endregion
3643
- //#region src/indicators/resolve.ts
3644
- /** Established-on set; `description` is opt-in. */
3645
- const DEFAULT_INDICATORS = {
3646
- alias: true,
3647
- variance: true,
3648
- gamut: true,
3649
- deprecation: true,
3650
- description: false
3651
- };
3652
- /** Normalize an `IndicatorsProp` into a full enabled-map by layering over the defaults. */
3653
- function resolveIndicators(prop) {
3654
- if (prop === void 0) return { ...DEFAULT_INDICATORS };
3655
- if (prop === true) return {
3656
- alias: true,
3657
- variance: true,
3658
- gamut: true,
3659
- deprecation: true,
3660
- description: true
3661
- };
3662
- if (prop === false) return {
3663
- alias: false,
3664
- variance: false,
3665
- gamut: false,
3666
- deprecation: false,
3667
- description: false
3668
- };
3669
- return {
3670
- ...DEFAULT_INDICATORS,
3671
- ...prop
3672
- };
3673
- }
3674
- //#endregion
3675
- //#region src/indicators/RowIndicators.tsx
3676
- function relativeLabel(path, root) {
3677
- if (root && path.startsWith(`${root}.`)) return path.slice(root.length + 1);
3678
- return path;
3679
- }
3680
- /**
3681
- * The forward alias chain for one row. Full chain in `aria-label`; visually
3682
- * capped to first … last beyond two hops (no width measurement). Each shown
3683
- * node navigates when in view, else renders as plain text.
3684
- */
3685
- function ForwardChain({ chain, root, canReference, onReferenceClick }) {
3686
- const full = chain.map((p) => relativeLabel(p, root)).join(" → ");
3687
- const capped = chain.length > 2;
3688
- const shown = capped ? [chain[0], chain[chain.length - 1]] : [...chain];
3689
- return /* @__PURE__ */ jsxs("span", {
3690
- className: "sb-indicator__alias-forward",
3691
- "data-testid": "row-indicator-alias-forward",
3692
- "aria-label": `aliases ${full}`,
3693
- children: [/* @__PURE__ */ jsx("span", {
3694
- className: "sb-indicator__alias-arrow",
3695
- "aria-hidden": true,
3696
- children: "→"
3697
- }), shown.map((target, i) => {
3698
- const label = relativeLabel(target, root);
3699
- return /* @__PURE__ */ jsxs("span", { children: [canReference(target) ? /* @__PURE__ */ jsx("button", {
3700
- type: "button",
3701
- className: "sb-indicator__alias-node",
3702
- "data-testid": "alias-node",
3703
- "aria-label": target,
3704
- onClick: (e) => {
3705
- e.stopPropagation();
3706
- onReferenceClick(target);
3707
- },
3708
- children: label
3709
- }) : /* @__PURE__ */ jsx("span", {
3710
- className: "sb-indicator__alias-node sb-indicator__alias-node--offview",
3711
- "data-testid": "alias-node",
3712
- title: "outside current view",
3713
- children: label
3714
- }), capped && i === 0 ? /* @__PURE__ */ jsxs("span", {
3715
- className: "sb-indicator__alias-arrow",
3716
- "aria-hidden": true,
3717
- children: [
3718
- " ",
3719
- "→ … →",
3720
- " "
3721
- ]
3722
- }) : i < shown.length - 1 ? /* @__PURE__ */ jsxs("span", {
3723
- className: "sb-indicator__alias-arrow",
3724
- "aria-hidden": true,
3725
- children: [
3726
- " ",
3727
- "→",
3728
- " "
3729
- ]
3730
- }) : null] }, target);
3731
- })]
3732
- });
3733
- }
3734
- function DeprecatedBadge({ deprecated }) {
3735
- const label = typeof deprecated === "string" ? `deprecated: ${deprecated}` : "deprecated";
3736
- return /* @__PURE__ */ jsx("span", {
3737
- className: "sb-indicator__deprecated",
3738
- "data-testid": "row-indicator-deprecated",
3739
- title: label,
3740
- "aria-label": label,
3741
- children: "deprecated"
3742
- });
3743
- }
3744
- function VarianceBadge({ variance }) {
3745
- if (variance.kind === "constant") return null;
3746
- const axes = variance.varyingAxes;
3747
- const label = variance.kind === "single" ? variance.axis : `${axes.length} axes`;
3748
- return /* @__PURE__ */ jsxs("span", {
3749
- className: "sb-indicator__variance",
3750
- "data-testid": "row-indicator-variance",
3751
- "aria-label": `varies by ${axes.join(", ")}`,
3752
- children: [/* @__PURE__ */ jsx("span", {
3753
- className: "sb-indicator__variance-glyph",
3754
- "aria-hidden": true,
3755
- children: "⊹"
3756
- }), label]
3757
- });
3758
- }
3759
- function ReverseCount({ referents, canReference, onReferenceClick }) {
3760
- const [open, setOpen] = useState(false);
3761
- const wrapRef = useRef(null);
3762
- const count = referents.length;
3763
- const single = count === 1;
3764
- useEffect(() => {
3765
- if (single || !open) return;
3766
- (wrapRef.current?.querySelector("button[role=\"menuitem\"]:not(:disabled)"))?.focus();
3767
- const handlePointerDown = (e) => {
3768
- if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
3769
- };
3770
- document.addEventListener("pointerdown", handlePointerDown);
3771
- return () => {
3772
- document.removeEventListener("pointerdown", handlePointerDown);
3773
- };
3774
- }, [open, single]);
3775
- return /* @__PURE__ */ jsxs("span", {
3776
- ref: wrapRef,
3777
- className: "sb-indicator__reverse-wrap",
3778
- onKeyDown: (e) => {
3779
- if (e.key === "Escape") setOpen(false);
3780
- },
3781
- children: [/* @__PURE__ */ jsxs("button", {
3782
- type: "button",
3783
- className: "sb-indicator__alias-reverse",
3784
- "data-testid": "row-indicator-alias-reverse",
3785
- "aria-label": `referenced by ${count} ${count === 1 ? "token" : "tokens"}`,
3786
- "aria-haspopup": single ? void 0 : "menu",
3787
- "aria-expanded": single ? void 0 : open,
3788
- onClick: (e) => {
3789
- e.stopPropagation();
3790
- if (single) onReferenceClick(referents[0]);
3791
- else setOpen((v) => !v);
3792
- },
3793
- children: [/* @__PURE__ */ jsx("span", {
3794
- className: "sb-indicator__alias-arrow",
3795
- "aria-hidden": true,
3796
- children: "←"
3797
- }), count]
3798
- }), !single && open && /* @__PURE__ */ jsx("ul", {
3799
- className: "sb-indicator__reverse-menu",
3800
- role: "menu",
3801
- children: referents.map((ref) => /* @__PURE__ */ jsx("li", {
3802
- role: "none",
3803
- children: /* @__PURE__ */ jsx("button", {
3804
- type: "button",
3805
- role: "menuitem",
3806
- className: "sb-indicator__reverse-item",
3807
- disabled: !canReference(ref),
3808
- title: canReference(ref) ? void 0 : "outside current view",
3809
- onClick: (e) => {
3810
- e.stopPropagation();
3811
- setOpen(false);
3812
- onReferenceClick(ref);
3813
- },
3814
- children: ref
3815
- })
3816
- }, ref))
3817
- })]
3818
- });
3819
- }
3820
- /** Per-row indicator strip: alias references, variance, gamut, deprecation. */
3821
- function RowIndicators(props) {
3822
- const { token, root, variance, colorFormat, canReference, onReferenceClick } = props;
3823
- const en = props.enabled ?? resolveIndicators(void 0);
3824
- const aliasChain = Array.isArray(token.aliasChain) && token.aliasChain.length > 0 ? token.aliasChain : void 0;
3825
- const reverseCount = Array.isArray(token.aliasedBy) && token.aliasedBy.length > 0 ? token.aliasedBy.length : 0;
3826
- const isVarying = variance !== void 0 && variance.kind !== "constant";
3827
- const outOfGamut = token.$type === "color" && (formatColor(token.$value, colorFormat)?.outOfGamut ?? false);
3828
- const deprecated = token.$deprecated;
3829
- const isDeprecated = deprecated === true || typeof deprecated === "string" && deprecated.length > 0;
3830
- const description = typeof token.$description === "string" && token.$description.length > 0 ? token.$description : void 0;
3831
- const showDeprecated = en.deprecation && isDeprecated;
3832
- const showForward = en.alias && aliasChain !== void 0;
3833
- const showReverse = en.alias && reverseCount > 0;
3834
- const showVariance = en.variance && isVarying;
3835
- const showGamut = en.gamut && outOfGamut;
3836
- const showDescription = en.description && description !== void 0;
3837
- if (!showDeprecated && !showForward && !showReverse && !showVariance && !showGamut && !showDescription) return null;
3838
- return /* @__PURE__ */ jsxs("span", {
3839
- className: "sb-indicator__indicators",
3840
- children: [
3841
- showDeprecated && deprecated !== void 0 && /* @__PURE__ */ jsx(DeprecatedBadge, { deprecated }),
3842
- showForward && aliasChain && /* @__PURE__ */ jsx(ForwardChain, {
3843
- chain: aliasChain,
3844
- root,
3845
- canReference,
3846
- onReferenceClick
3847
- }),
3848
- showReverse && token.aliasedBy && /* @__PURE__ */ jsx(ReverseCount, {
3849
- referents: token.aliasedBy,
3850
- canReference,
3851
- onReferenceClick
3852
- }),
3853
- showVariance && variance && /* @__PURE__ */ jsx(VarianceBadge, { variance }),
3854
- showGamut && /* @__PURE__ */ jsx("span", {
3855
- className: "sb-indicator__gamut",
3856
- title: "Out of sRGB gamut for this format",
3857
- "aria-label": "out of gamut",
3858
- children: "⚠"
3859
- }),
3860
- showDescription && description !== void 0 && /* @__PURE__ */ jsx("span", {
3861
- className: "sb-indicator__description",
3862
- "data-testid": "row-indicator-description",
3863
- title: description,
3864
- "aria-label": `description: ${description}`,
3865
- children: "ⓘ"
3866
- })
3867
- ]
3868
- });
3869
- }
3870
- //#endregion
3871
3935
  //#region src/TokenNavigator.tsx
3872
3936
  function buildTree(resolved, root, typeFilter) {
3873
3937
  const rootPrefix = root && root.length > 0 ? `${root}.` : "";
@@ -3972,7 +4036,7 @@ function pruneTreeForMatches(nodes, matches, expandOut) {
3972
4036
  return out;
3973
4037
  }
3974
4038
  function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true, onSelect, id, indicators }) {
3975
- const { resolved, activeTheme, activeAxes, cssVarPrefix } = useProject();
4039
+ const { resolved, activeTheme, activeAxes, cssVarPrefix, indicators: indicatorBaseline } = useProject();
3976
4040
  const blockKey = useBlockKey("TokenNavigator", [
3977
4041
  root,
3978
4042
  type === void 0 ? "" : typeof type === "string" ? type : type.join(","),
@@ -3982,7 +4046,7 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
3982
4046
  if (type === void 0) return void 0;
3983
4047
  return new Set(Array.isArray(type) ? type : [type]);
3984
4048
  }, [type]);
3985
- const enabledIndicators = useMemo(() => resolveIndicators(indicators), [indicators]);
4049
+ const enabledIndicators = useMemo(() => resolveIndicators(indicators, indicatorBaseline), [indicators, indicatorBaseline]);
3986
4050
  const tree = useMemo(() => buildTree(resolved, root, typeFilter), [
3987
4051
  resolved,
3988
4052
  root,
@@ -4457,7 +4521,7 @@ const LeafPreview = memo(function LeafPreview({ path, token }) {
4457
4521
  //#endregion
4458
4522
  //#region src/TokenTable.tsx
4459
4523
  function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect, id, indicators }) {
4460
- const { resolved, activeTheme, activeAxes, cssVarPrefix, listing, varianceByPath } = useProject();
4524
+ const { resolved, activeTheme, activeAxes, cssVarPrefix, listing, varianceByPath, indicators: indicatorBaseline } = useProject();
4461
4525
  const colorFormat = useColorFormat();
4462
4526
  const blockKey = useBlockKey("TokenTable", [
4463
4527
  filter,
@@ -4465,7 +4529,7 @@ function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", s
4465
4529
  caption,
4466
4530
  id
4467
4531
  ]);
4468
- const enabledIndicators = useMemo(() => resolveIndicators(indicators), [indicators]);
4532
+ const enabledIndicators = useMemo(() => resolveIndicators(indicators, indicatorBaseline), [indicators, indicatorBaseline]);
4469
4533
  const [selectedPath, setSelectedPath] = usePersistedState(`${blockKey}::selected`, null);
4470
4534
  const [query, setQuery] = usePersistedState(`${blockKey}::query`, "");
4471
4535
  const deferredQuery = useDeferredValue(query);