@unpunnyfuns/swatchbook-blocks 0.64.0 → 0.66.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/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,187 +3932,6 @@ function isInView(path, ctx) {
3640
3932
  return true;
3641
3933
  }
3642
3934
  //#endregion
3643
- //#region src/indicators/RowIndicators.tsx
3644
- function relativeLabel(path, root) {
3645
- if (root && path.startsWith(`${root}.`)) return path.slice(root.length + 1);
3646
- return path;
3647
- }
3648
- /**
3649
- * The forward alias chain for one row. Full chain in `aria-label`; visually
3650
- * capped to first … last beyond two hops (no width measurement). Each shown
3651
- * node navigates when in view, else renders as plain text.
3652
- */
3653
- function ForwardChain({ chain, root, canReference, onReferenceClick }) {
3654
- const full = chain.map((p) => relativeLabel(p, root)).join(" → ");
3655
- const capped = chain.length > 2;
3656
- const shown = capped ? [chain[0], chain[chain.length - 1]] : [...chain];
3657
- return /* @__PURE__ */ jsxs("span", {
3658
- className: "sb-indicator__alias-forward",
3659
- "data-testid": "row-indicator-alias-forward",
3660
- "aria-label": `aliases ${full}`,
3661
- children: [/* @__PURE__ */ jsx("span", {
3662
- className: "sb-indicator__alias-arrow",
3663
- "aria-hidden": true,
3664
- children: "→"
3665
- }), shown.map((target, i) => {
3666
- const label = relativeLabel(target, root);
3667
- return /* @__PURE__ */ jsxs("span", { children: [canReference(target) ? /* @__PURE__ */ jsx("button", {
3668
- type: "button",
3669
- className: "sb-indicator__alias-node",
3670
- "data-testid": "alias-node",
3671
- "aria-label": target,
3672
- onClick: (e) => {
3673
- e.stopPropagation();
3674
- onReferenceClick(target);
3675
- },
3676
- children: label
3677
- }) : /* @__PURE__ */ jsx("span", {
3678
- className: "sb-indicator__alias-node sb-indicator__alias-node--offview",
3679
- "data-testid": "alias-node",
3680
- title: "outside current view",
3681
- children: label
3682
- }), capped && i === 0 ? /* @__PURE__ */ jsxs("span", {
3683
- className: "sb-indicator__alias-arrow",
3684
- "aria-hidden": true,
3685
- children: [
3686
- " ",
3687
- "→ … →",
3688
- " "
3689
- ]
3690
- }) : i < shown.length - 1 ? /* @__PURE__ */ jsxs("span", {
3691
- className: "sb-indicator__alias-arrow",
3692
- "aria-hidden": true,
3693
- children: [
3694
- " ",
3695
- "→",
3696
- " "
3697
- ]
3698
- }) : null] }, target);
3699
- })]
3700
- });
3701
- }
3702
- function DeprecatedBadge({ deprecated }) {
3703
- const label = typeof deprecated === "string" ? `deprecated: ${deprecated}` : "deprecated";
3704
- return /* @__PURE__ */ jsx("span", {
3705
- className: "sb-indicator__deprecated",
3706
- "data-testid": "row-indicator-deprecated",
3707
- title: label,
3708
- "aria-label": label,
3709
- children: "deprecated"
3710
- });
3711
- }
3712
- function VarianceBadge({ variance }) {
3713
- if (variance.kind === "constant") return null;
3714
- const axes = variance.varyingAxes;
3715
- const label = variance.kind === "single" ? variance.axis : `${axes.length} axes`;
3716
- return /* @__PURE__ */ jsxs("span", {
3717
- className: "sb-indicator__variance",
3718
- "data-testid": "row-indicator-variance",
3719
- "aria-label": `varies by ${axes.join(", ")}`,
3720
- children: [/* @__PURE__ */ jsx("span", {
3721
- className: "sb-indicator__variance-glyph",
3722
- "aria-hidden": true,
3723
- children: "⊹"
3724
- }), label]
3725
- });
3726
- }
3727
- function ReverseCount({ referents, canReference, onReferenceClick }) {
3728
- const [open, setOpen] = useState(false);
3729
- const wrapRef = useRef(null);
3730
- const count = referents.length;
3731
- const single = count === 1;
3732
- useEffect(() => {
3733
- if (single || !open) return;
3734
- (wrapRef.current?.querySelector("button[role=\"menuitem\"]:not(:disabled)"))?.focus();
3735
- const handlePointerDown = (e) => {
3736
- if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
3737
- };
3738
- document.addEventListener("pointerdown", handlePointerDown);
3739
- return () => {
3740
- document.removeEventListener("pointerdown", handlePointerDown);
3741
- };
3742
- }, [open, single]);
3743
- return /* @__PURE__ */ jsxs("span", {
3744
- ref: wrapRef,
3745
- className: "sb-indicator__reverse-wrap",
3746
- onKeyDown: (e) => {
3747
- if (e.key === "Escape") setOpen(false);
3748
- },
3749
- children: [/* @__PURE__ */ jsxs("button", {
3750
- type: "button",
3751
- className: "sb-indicator__alias-reverse",
3752
- "data-testid": "row-indicator-alias-reverse",
3753
- "aria-label": `referenced by ${count} ${count === 1 ? "token" : "tokens"}`,
3754
- "aria-haspopup": single ? void 0 : "menu",
3755
- "aria-expanded": single ? void 0 : open,
3756
- onClick: (e) => {
3757
- e.stopPropagation();
3758
- if (single) onReferenceClick(referents[0]);
3759
- else setOpen((v) => !v);
3760
- },
3761
- children: [/* @__PURE__ */ jsx("span", {
3762
- className: "sb-indicator__alias-arrow",
3763
- "aria-hidden": true,
3764
- children: "←"
3765
- }), count]
3766
- }), !single && open && /* @__PURE__ */ jsx("ul", {
3767
- className: "sb-indicator__reverse-menu",
3768
- role: "menu",
3769
- children: referents.map((ref) => /* @__PURE__ */ jsx("li", {
3770
- role: "none",
3771
- children: /* @__PURE__ */ jsx("button", {
3772
- type: "button",
3773
- role: "menuitem",
3774
- className: "sb-indicator__reverse-item",
3775
- disabled: !canReference(ref),
3776
- title: canReference(ref) ? void 0 : "outside current view",
3777
- onClick: (e) => {
3778
- e.stopPropagation();
3779
- setOpen(false);
3780
- onReferenceClick(ref);
3781
- },
3782
- children: ref
3783
- })
3784
- }, ref))
3785
- })]
3786
- });
3787
- }
3788
- /** Per-row indicator strip: alias references, variance, gamut, deprecation. */
3789
- function RowIndicators(props) {
3790
- const { token, root, variance, colorFormat, canReference, onReferenceClick } = props;
3791
- const aliasChain = Array.isArray(token.aliasChain) && token.aliasChain.length > 0 ? token.aliasChain : void 0;
3792
- const reverseCount = Array.isArray(token.aliasedBy) && token.aliasedBy.length > 0 ? token.aliasedBy.length : 0;
3793
- const isVarying = variance !== void 0 && variance.kind !== "constant";
3794
- const outOfGamut = token.$type === "color" && (formatColor(token.$value, colorFormat)?.outOfGamut ?? false);
3795
- const deprecated = token.$deprecated;
3796
- const isDeprecated = deprecated === true || typeof deprecated === "string" && deprecated.length > 0;
3797
- if (!aliasChain && reverseCount === 0 && !isVarying && !outOfGamut && !isDeprecated) return null;
3798
- return /* @__PURE__ */ jsxs("span", {
3799
- className: "sb-indicator__indicators",
3800
- children: [
3801
- isDeprecated && deprecated !== void 0 && /* @__PURE__ */ jsx(DeprecatedBadge, { deprecated }),
3802
- aliasChain && /* @__PURE__ */ jsx(ForwardChain, {
3803
- chain: aliasChain,
3804
- root,
3805
- canReference,
3806
- onReferenceClick
3807
- }),
3808
- reverseCount > 0 && token.aliasedBy && /* @__PURE__ */ jsx(ReverseCount, {
3809
- referents: token.aliasedBy,
3810
- canReference,
3811
- onReferenceClick
3812
- }),
3813
- variance && /* @__PURE__ */ jsx(VarianceBadge, { variance }),
3814
- outOfGamut && /* @__PURE__ */ jsx("span", {
3815
- className: "sb-indicator__gamut",
3816
- title: "Out of sRGB gamut for this format",
3817
- "aria-label": "out of gamut",
3818
- children: "⚠"
3819
- })
3820
- ]
3821
- });
3822
- }
3823
- //#endregion
3824
3935
  //#region src/TokenNavigator.tsx
3825
3936
  function buildTree(resolved, root, typeFilter) {
3826
3937
  const rootPrefix = root && root.length > 0 ? `${root}.` : "";
@@ -3924,8 +4035,8 @@ function pruneTreeForMatches(nodes, matches, expandOut) {
3924
4035
  }
3925
4036
  return out;
3926
4037
  }
3927
- function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true, onSelect, id }) {
3928
- const { resolved, activeTheme, activeAxes, cssVarPrefix } = useProject();
4038
+ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true, onSelect, id, indicators }) {
4039
+ const { resolved, activeTheme, activeAxes, cssVarPrefix, indicators: indicatorBaseline } = useProject();
3929
4040
  const blockKey = useBlockKey("TokenNavigator", [
3930
4041
  root,
3931
4042
  type === void 0 ? "" : typeof type === "string" ? type : type.join(","),
@@ -3935,6 +4046,7 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
3935
4046
  if (type === void 0) return void 0;
3936
4047
  return new Set(Array.isArray(type) ? type : [type]);
3937
4048
  }, [type]);
4049
+ const enabledIndicators = useMemo(() => resolveIndicators(indicators, indicatorBaseline), [indicators, indicatorBaseline]);
3938
4050
  const tree = useMemo(() => buildTree(resolved, root, typeFilter), [
3939
4051
  resolved,
3940
4052
  root,
@@ -4206,6 +4318,7 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
4206
4318
  root,
4207
4319
  resolveInView,
4208
4320
  onNavigate: navigateTo,
4321
+ enabled: enabledIndicators,
4209
4322
  level: 1,
4210
4323
  setsize: visibleTree.length,
4211
4324
  posinset: i + 1
@@ -4219,7 +4332,7 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
4219
4332
  ]
4220
4333
  });
4221
4334
  }
4222
- function TreeNodeRow({ node, expanded, focusedPath, registerTreeItem, onToggle, onFocusPath, onLeafClick, root, resolveInView, onNavigate, level, setsize, posinset }) {
4335
+ function TreeNodeRow({ node, expanded, focusedPath, registerTreeItem, onToggle, onFocusPath, onLeafClick, root, resolveInView, onNavigate, enabled, level, setsize, posinset }) {
4223
4336
  if (node.kind === "leaf") return /* @__PURE__ */ jsx(LeafRow, {
4224
4337
  node,
4225
4338
  isFocused: focusedPath === node.path,
@@ -4229,6 +4342,7 @@ function TreeNodeRow({ node, expanded, focusedPath, registerTreeItem, onToggle,
4229
4342
  root,
4230
4343
  resolveInView,
4231
4344
  onNavigate,
4345
+ enabled,
4232
4346
  level,
4233
4347
  setsize,
4234
4348
  posinset
@@ -4279,6 +4393,7 @@ function TreeNodeRow({ node, expanded, focusedPath, registerTreeItem, onToggle,
4279
4393
  root,
4280
4394
  resolveInView,
4281
4395
  onNavigate,
4396
+ enabled,
4282
4397
  level: level + 1,
4283
4398
  setsize: node.children.length,
4284
4399
  posinset: i + 1
@@ -4286,7 +4401,7 @@ function TreeNodeRow({ node, expanded, focusedPath, registerTreeItem, onToggle,
4286
4401
  })]
4287
4402
  });
4288
4403
  }
4289
- const LeafRow = memo(function LeafRow({ node, isFocused, registerTreeItem, onFocusPath, onLeafClick, root, resolveInView, onNavigate, level, setsize, posinset }) {
4404
+ const LeafRow = memo(function LeafRow({ node, isFocused, registerTreeItem, onFocusPath, onLeafClick, root, resolveInView, onNavigate, enabled, level, setsize, posinset }) {
4290
4405
  const type = node.token.$type ?? "";
4291
4406
  const project = useProject();
4292
4407
  const colorFormat = useColorFormat();
@@ -4306,7 +4421,7 @@ const LeafRow = memo(function LeafRow({ node, isFocused, registerTreeItem, onFoc
4306
4421
  children: /* @__PURE__ */ jsxs("div", {
4307
4422
  className: "sb-token-navigator__leaf-row",
4308
4423
  "data-testid": "token-navigator-leaf-row",
4309
- "data-deprecated": isDeprecated ? "true" : void 0,
4424
+ "data-deprecated": enabled.deprecation && isDeprecated ? "true" : void 0,
4310
4425
  onClick: () => {
4311
4426
  onFocusPath(node.path);
4312
4427
  onLeafClick(node.path);
@@ -4332,7 +4447,8 @@ const LeafRow = memo(function LeafRow({ node, isFocused, registerTreeItem, onFoc
4332
4447
  variance,
4333
4448
  colorFormat,
4334
4449
  canReference: resolveInView,
4335
- onReferenceClick: onNavigate
4450
+ onReferenceClick: onNavigate,
4451
+ enabled
4336
4452
  }),
4337
4453
  /* @__PURE__ */ jsx(LeafPreview, {
4338
4454
  path: node.path,
@@ -4404,8 +4520,8 @@ const LeafPreview = memo(function LeafPreview({ path, token }) {
4404
4520
  });
4405
4521
  //#endregion
4406
4522
  //#region src/TokenTable.tsx
4407
- function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect, id }) {
4408
- const { resolved, activeTheme, activeAxes, cssVarPrefix, listing, varianceByPath } = useProject();
4523
+ function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect, id, indicators }) {
4524
+ const { resolved, activeTheme, activeAxes, cssVarPrefix, listing, varianceByPath, indicators: indicatorBaseline } = useProject();
4409
4525
  const colorFormat = useColorFormat();
4410
4526
  const blockKey = useBlockKey("TokenTable", [
4411
4527
  filter,
@@ -4413,6 +4529,7 @@ function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", s
4413
4529
  caption,
4414
4530
  id
4415
4531
  ]);
4532
+ const enabledIndicators = useMemo(() => resolveIndicators(indicators, indicatorBaseline), [indicators, indicatorBaseline]);
4416
4533
  const [selectedPath, setSelectedPath] = usePersistedState(`${blockKey}::selected`, null);
4417
4534
  const [query, setQuery] = usePersistedState(`${blockKey}::query`, "");
4418
4535
  const deferredQuery = useDeferredValue(query);
@@ -4545,7 +4662,7 @@ function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", s
4545
4662
  children: [
4546
4663
  /* @__PURE__ */ jsx("td", {
4547
4664
  className: cx("sb-token-table__td", "sb-token-table__path"),
4548
- "data-deprecated": isDeprecated ? "true" : void 0,
4665
+ "data-deprecated": enabledIndicators.deprecation && isDeprecated ? "true" : void 0,
4549
4666
  children: row.path
4550
4667
  }),
4551
4668
  /* @__PURE__ */ jsx("td", {
@@ -4597,7 +4714,8 @@ function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", s
4597
4714
  variance: varianceByPath[row.path],
4598
4715
  colorFormat,
4599
4716
  canReference: (p) => p in resolved,
4600
- onReferenceClick: (p) => setSelectedPath(p)
4717
+ onReferenceClick: (p) => setSelectedPath(p),
4718
+ enabled: enabledIndicators
4601
4719
  })
4602
4720
  })
4603
4721
  ]