@unpunnyfuns/swatchbook-blocks 0.62.4 → 0.64.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.d.mts CHANGED
@@ -29,6 +29,12 @@ interface VirtualTokenShape {
29
29
  $type?: string | undefined;
30
30
  $value?: unknown;
31
31
  $description?: string | undefined;
32
+ /**
33
+ * DTCG `$deprecated` — `true` or a message string. Mirrors core's
34
+ * `SwatchbookToken.$deprecated`; reaches blocks via the resolved token
35
+ * map reconstructed from the wire `tokenGraph`.
36
+ */
37
+ $deprecated?: string | boolean | undefined;
32
38
  aliasOf?: string | undefined;
33
39
  aliasChain?: readonly string[] | undefined;
34
40
  aliasedBy?: readonly string[] | undefined;
package/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@ import { COLOR_FORMATS } from "@unpunnyfuns/swatchbook-core/color-formats";
3
3
  import { formatColor, parseColor } from "@unpunnyfuns/swatchbook-core/format-color";
4
4
  import { createContext, memo, useCallback, useContext, useDeferredValue, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
5
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
- import { getVariance, listPaths, resolveAllAt } from "@unpunnyfuns/swatchbook-core/graph";
6
+ import { getVariance, listPaths, resolveAllWithProvenanceAt } from "@unpunnyfuns/swatchbook-core/graph";
7
7
  import { makeCssVar } from "@unpunnyfuns/swatchbook-core/css-var";
8
8
  import { SWATCHBOOK_STYLE_ELEMENT_ID, ensureStyleElement } from "@unpunnyfuns/swatchbook-core/style-element";
9
9
  import { tupleToName } from "@unpunnyfuns/swatchbook-core/themes";
@@ -244,7 +244,7 @@ function defaultTuple(axes) {
244
244
  }
245
245
  function makeResolveAt(graph) {
246
246
  if (!graph) return () => ({});
247
- return (tuple) => resolveAllAt(graph, tuple);
247
+ return (tuple) => resolveAllWithProvenanceAt(graph, tuple);
248
248
  }
249
249
  function snapshotResolveAt(snapshot) {
250
250
  if (snapshot.resolveAt) return snapshot.resolveAt;
@@ -3455,6 +3455,8 @@ function TokenDetail({ path, heading }) {
3455
3455
  const gamut = isColor ? formatColor(token.$value, colorFormat) : null;
3456
3456
  const value = formatTokenValue(token.$value, token.$type, colorFormat, listing[path]);
3457
3457
  const outOfGamut = gamut?.outOfGamut ?? false;
3458
+ const dep = token.$deprecated;
3459
+ const isDeprecated = dep === true || typeof dep === "string" && dep.length > 0;
3458
3460
  return /* @__PURE__ */ jsxs("div", {
3459
3461
  ...wrapperAttrs,
3460
3462
  className: cx(wrapperAttrs["className"], "sb-token-detail"),
@@ -3463,6 +3465,19 @@ function TokenDetail({ path, heading }) {
3463
3465
  path,
3464
3466
  ...heading !== void 0 && { heading }
3465
3467
  }),
3468
+ isDeprecated && /* @__PURE__ */ jsxs("div", {
3469
+ className: "sb-token-detail__deprecated",
3470
+ "data-testid": "token-detail-deprecated",
3471
+ role: "note",
3472
+ children: [
3473
+ /* @__PURE__ */ jsx("span", {
3474
+ "aria-hidden": true,
3475
+ children: "⚠ "
3476
+ }),
3477
+ "Deprecated",
3478
+ typeof dep === "string" ? `: ${dep}` : ""
3479
+ ]
3480
+ }),
3466
3481
  /* @__PURE__ */ jsxs("div", {
3467
3482
  className: "sb-token-detail__section-header",
3468
3483
  children: ["Resolved value · ", activeTheme]
@@ -3593,6 +3608,219 @@ function findBodyChildContaining(node) {
3593
3608
  return cursor;
3594
3609
  }
3595
3610
  //#endregion
3611
+ //#region src/token-navigator/navigate.ts
3612
+ /**
3613
+ * The group paths to expand so `path` becomes visible in the tree — the
3614
+ * cumulative dotted prefixes of `path`, excluding `path` itself and any
3615
+ * prefix at or above `root` (the navigator's implicit root container is not
3616
+ * a group node). Matches `buildTree`'s full-dotted group-path scheme.
3617
+ */
3618
+ function ancestorGroupPaths(path, root) {
3619
+ const segments = path.split(".");
3620
+ const out = [];
3621
+ for (let i = 1; i < segments.length; i += 1) {
3622
+ const prefix = segments.slice(0, i).join(".");
3623
+ if (root && !prefix.startsWith(`${root}.`)) continue;
3624
+ out.push(prefix);
3625
+ }
3626
+ return out;
3627
+ }
3628
+ /**
3629
+ * Whether `path` survives the navigator's structural (`root` / `type`)
3630
+ * filters and exists in the resolved map — i.e. it can be selected in the
3631
+ * current tree. Transient search is NOT considered here: a target hidden
3632
+ * only by an active query is still "in view" once the query is cleared,
3633
+ * which the caller handles.
3634
+ */
3635
+ function isInView(path, ctx) {
3636
+ const token = ctx.resolved[path];
3637
+ if (!token) return false;
3638
+ if (ctx.root && !(path === ctx.root || path.startsWith(`${ctx.root}.`))) return false;
3639
+ if (ctx.typeFilter && !(token.$type !== void 0 && ctx.typeFilter.has(token.$type))) return false;
3640
+ return true;
3641
+ }
3642
+ //#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
3596
3824
  //#region src/TokenNavigator.tsx
3597
3825
  function buildTree(resolved, root, typeFilter) {
3598
3826
  const rootPrefix = root && root.length > 0 ? `${root}.` : "";
@@ -3769,6 +3997,37 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
3769
3997
  }, [onSelect, setSelectedPath]);
3770
3998
  const [storedFocus, setStoredFocus] = useState(null);
3771
3999
  const treeItemRefs = useRef(/* @__PURE__ */ new Map());
4000
+ const resolveInView = useCallback((path) => isInView(path, {
4001
+ resolved,
4002
+ root,
4003
+ typeFilter
4004
+ }), [
4005
+ resolved,
4006
+ root,
4007
+ typeFilter
4008
+ ]);
4009
+ const navigateTo = useCallback((target) => {
4010
+ setQuery("");
4011
+ setExpanded((prev) => {
4012
+ const next = new Set(prev);
4013
+ for (const p of ancestorGroupPaths(target, root)) next.add(p);
4014
+ return next;
4015
+ });
4016
+ if (onSelect) onSelect(target);
4017
+ else setSelectedPath(target);
4018
+ setStoredFocus(target);
4019
+ requestAnimationFrame(() => {
4020
+ const el = treeItemRefs.current.get(target);
4021
+ el?.scrollIntoView({ block: "nearest" });
4022
+ el?.focus();
4023
+ });
4024
+ }, [
4025
+ root,
4026
+ onSelect,
4027
+ setQuery,
4028
+ setExpanded,
4029
+ setSelectedPath
4030
+ ]);
3772
4031
  const registerTreeItem = useCallback((path) => (el) => {
3773
4032
  if (el) treeItemRefs.current.set(path, el);
3774
4033
  else treeItemRefs.current.delete(path);
@@ -3944,6 +4203,9 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
3944
4203
  onToggle: toggle,
3945
4204
  onFocusPath: setStoredFocus,
3946
4205
  onLeafClick: handleLeafClick,
4206
+ root,
4207
+ resolveInView,
4208
+ onNavigate: navigateTo,
3947
4209
  level: 1,
3948
4210
  setsize: visibleTree.length,
3949
4211
  posinset: i + 1
@@ -3957,13 +4219,16 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
3957
4219
  ]
3958
4220
  });
3959
4221
  }
3960
- function TreeNodeRow({ node, expanded, focusedPath, registerTreeItem, onToggle, onFocusPath, onLeafClick, level, setsize, posinset }) {
4222
+ function TreeNodeRow({ node, expanded, focusedPath, registerTreeItem, onToggle, onFocusPath, onLeafClick, root, resolveInView, onNavigate, level, setsize, posinset }) {
3961
4223
  if (node.kind === "leaf") return /* @__PURE__ */ jsx(LeafRow, {
3962
4224
  node,
3963
4225
  isFocused: focusedPath === node.path,
3964
4226
  registerTreeItem,
3965
4227
  onFocusPath,
3966
4228
  onLeafClick,
4229
+ root,
4230
+ resolveInView,
4231
+ onNavigate,
3967
4232
  level,
3968
4233
  setsize,
3969
4234
  posinset
@@ -4011,6 +4276,9 @@ function TreeNodeRow({ node, expanded, focusedPath, registerTreeItem, onToggle,
4011
4276
  onToggle,
4012
4277
  onFocusPath,
4013
4278
  onLeafClick,
4279
+ root,
4280
+ resolveInView,
4281
+ onNavigate,
4014
4282
  level: level + 1,
4015
4283
  setsize: node.children.length,
4016
4284
  posinset: i + 1
@@ -4018,8 +4286,13 @@ function TreeNodeRow({ node, expanded, focusedPath, registerTreeItem, onToggle,
4018
4286
  })]
4019
4287
  });
4020
4288
  }
4021
- const LeafRow = memo(function LeafRow({ node, isFocused, registerTreeItem, onFocusPath, onLeafClick, level, setsize, posinset }) {
4289
+ const LeafRow = memo(function LeafRow({ node, isFocused, registerTreeItem, onFocusPath, onLeafClick, root, resolveInView, onNavigate, level, setsize, posinset }) {
4022
4290
  const type = node.token.$type ?? "";
4291
+ const project = useProject();
4292
+ const colorFormat = useColorFormat();
4293
+ const variance = project.varianceByPath[node.path];
4294
+ const dep = node.token.$deprecated;
4295
+ const isDeprecated = dep === true || typeof dep === "string" && dep.length > 0;
4023
4296
  return /* @__PURE__ */ jsx("li", {
4024
4297
  ref: registerTreeItem(node.path),
4025
4298
  role: "treeitem",
@@ -4033,6 +4306,7 @@ const LeafRow = memo(function LeafRow({ node, isFocused, registerTreeItem, onFoc
4033
4306
  children: /* @__PURE__ */ jsxs("div", {
4034
4307
  className: "sb-token-navigator__leaf-row",
4035
4308
  "data-testid": "token-navigator-leaf-row",
4309
+ "data-deprecated": isDeprecated ? "true" : void 0,
4036
4310
  onClick: () => {
4037
4311
  onFocusPath(node.path);
4038
4312
  onLeafClick(node.path);
@@ -4051,6 +4325,15 @@ const LeafRow = memo(function LeafRow({ node, isFocused, registerTreeItem, onFoc
4051
4325
  className: "sb-token-navigator__type-pill",
4052
4326
  children: type
4053
4327
  }),
4328
+ /* @__PURE__ */ jsx(RowIndicators, {
4329
+ path: node.path,
4330
+ token: node.token,
4331
+ root,
4332
+ variance,
4333
+ colorFormat,
4334
+ canReference: resolveInView,
4335
+ onReferenceClick: onNavigate
4336
+ }),
4054
4337
  /* @__PURE__ */ jsx(LeafPreview, {
4055
4338
  path: node.path,
4056
4339
  token: node.token
@@ -4122,7 +4405,7 @@ const LeafPreview = memo(function LeafPreview({ path, token }) {
4122
4405
  //#endregion
4123
4406
  //#region src/TokenTable.tsx
4124
4407
  function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect, id }) {
4125
- const { resolved, activeTheme, activeAxes, cssVarPrefix, listing } = useProject();
4408
+ const { resolved, activeTheme, activeAxes, cssVarPrefix, listing, varianceByPath } = useProject();
4126
4409
  const colorFormat = useColorFormat();
4127
4410
  const blockKey = useBlockKey("TokenTable", [
4128
4411
  filter,
@@ -4216,79 +4499,110 @@ function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", s
4216
4499
  className: "sb-token-table__caption",
4217
4500
  children: captionText
4218
4501
  }),
4219
- /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [/* @__PURE__ */ jsx("th", {
4220
- className: cx("sb-token-table__th", "sb-token-table__th--path"),
4221
- children: "Path"
4222
- }), /* @__PURE__ */ jsx("th", {
4223
- className: cx("sb-token-table__th", "sb-token-table__th--value"),
4224
- children: "Value"
4225
- })] }) }),
4502
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
4503
+ /* @__PURE__ */ jsx("th", {
4504
+ className: cx("sb-token-table__th", "sb-token-table__th--path"),
4505
+ children: "Path"
4506
+ }),
4507
+ /* @__PURE__ */ jsx("th", {
4508
+ className: cx("sb-token-table__th", "sb-token-table__th--value"),
4509
+ children: "Value"
4510
+ }),
4511
+ /* @__PURE__ */ jsx("th", {
4512
+ className: "sb-token-table__th sb-token-table__th--refs",
4513
+ children: /* @__PURE__ */ jsx("span", {
4514
+ className: "sb-token-table__sr-status",
4515
+ children: "References and status"
4516
+ })
4517
+ })
4518
+ ] }) }),
4226
4519
  /* @__PURE__ */ jsxs("tbody", { children: [visibleRows.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", {
4227
- colSpan: 2,
4520
+ colSpan: 3,
4228
4521
  className: "sb-token-table__td sb-token-table__empty-row",
4229
4522
  children: [
4230
4523
  "No tokens match \"",
4231
4524
  query.trim(),
4232
4525
  "\"."
4233
4526
  ]
4234
- }) }), visibleRows.map((row) => /* @__PURE__ */ jsxs("tr", {
4235
- className: "sb-token-table__row",
4236
- onClick: () => handleRowClick(row.path),
4237
- onKeyDown: (e) => {
4238
- if (e.key === "Enter" || e.key === " ") {
4239
- e.preventDefault();
4240
- handleRowClick(row.path);
4241
- }
4242
- },
4243
- tabIndex: 0,
4244
- "aria-haspopup": "dialog",
4245
- "aria-label": `Inspect ${row.path}`,
4246
- "data-testid": "token-table-row",
4247
- "data-path": row.path,
4248
- children: [/* @__PURE__ */ jsx("td", {
4249
- className: cx("sb-token-table__td", "sb-token-table__path"),
4250
- children: row.path
4251
- }), /* @__PURE__ */ jsx("td", {
4252
- className: "sb-token-table__td",
4253
- children: /* @__PURE__ */ jsxs("span", {
4254
- className: "sb-token-table__value-cell",
4255
- children: [
4256
- row.type && /* @__PURE__ */ jsx("span", {
4257
- className: "sb-token-table__type-pill",
4258
- children: row.type
4259
- }),
4260
- row.isColor && /* @__PURE__ */ jsx("span", {
4261
- className: "sb-token-table__swatch",
4262
- style: { background: row.cssVar },
4263
- "aria-hidden": true
4264
- }),
4265
- /* @__PURE__ */ jsx("span", {
4266
- className: "sb-token-table__value-text",
4267
- title: row.value,
4268
- "data-testid": "token-table-value",
4269
- children: row.value
4270
- }),
4271
- row.outOfGamut && /* @__PURE__ */ jsx("span", {
4272
- title: "Out of sRGB gamut for this format",
4273
- "aria-label": "out of gamut",
4274
- className: "sb-token-table__gamut-warn",
4275
- children: ""
4276
- }),
4277
- /* @__PURE__ */ jsx("span", {
4278
- className: "sb-token-table__copy-wrap",
4279
- onClick: (e) => e.stopPropagation(),
4280
- onKeyDown: (e) => e.stopPropagation(),
4281
- role: "presentation",
4282
- children: /* @__PURE__ */ jsx(CopyButton$1, {
4283
- value: row.value,
4284
- label: `Copy value ${row.value}`,
4285
- className: "sb-token-table__copy"
4286
- })
4527
+ }) }), visibleRows.map((row) => {
4528
+ const token = resolved[row.path];
4529
+ const dep = token?.$deprecated;
4530
+ const isDeprecated = dep === true || typeof dep === "string" && dep.length > 0;
4531
+ return /* @__PURE__ */ jsxs("tr", {
4532
+ className: "sb-token-table__row",
4533
+ onClick: () => handleRowClick(row.path),
4534
+ onKeyDown: (e) => {
4535
+ if (e.key === "Enter" || e.key === " ") {
4536
+ e.preventDefault();
4537
+ handleRowClick(row.path);
4538
+ }
4539
+ },
4540
+ tabIndex: 0,
4541
+ "aria-haspopup": "dialog",
4542
+ "aria-label": `Inspect ${row.path}`,
4543
+ "data-testid": "token-table-row",
4544
+ "data-path": row.path,
4545
+ children: [
4546
+ /* @__PURE__ */ jsx("td", {
4547
+ className: cx("sb-token-table__td", "sb-token-table__path"),
4548
+ "data-deprecated": isDeprecated ? "true" : void 0,
4549
+ children: row.path
4550
+ }),
4551
+ /* @__PURE__ */ jsx("td", {
4552
+ className: "sb-token-table__td",
4553
+ children: /* @__PURE__ */ jsxs("span", {
4554
+ className: "sb-token-table__value-cell",
4555
+ children: [
4556
+ row.type && /* @__PURE__ */ jsx("span", {
4557
+ className: "sb-token-table__type-pill",
4558
+ children: row.type
4559
+ }),
4560
+ row.isColor && /* @__PURE__ */ jsx("span", {
4561
+ className: "sb-token-table__swatch",
4562
+ style: { background: row.cssVar },
4563
+ "aria-hidden": true
4564
+ }),
4565
+ /* @__PURE__ */ jsx("span", {
4566
+ className: "sb-token-table__value-text",
4567
+ title: row.value,
4568
+ "data-testid": "token-table-value",
4569
+ children: row.value
4570
+ }),
4571
+ row.outOfGamut && /* @__PURE__ */ jsx("span", {
4572
+ title: "Out of sRGB gamut for this format",
4573
+ "aria-label": "out of gamut",
4574
+ className: "sb-token-table__gamut-warn",
4575
+ children: "⚠"
4576
+ }),
4577
+ /* @__PURE__ */ jsx("span", {
4578
+ className: "sb-token-table__copy-wrap",
4579
+ onClick: (e) => e.stopPropagation(),
4580
+ onKeyDown: (e) => e.stopPropagation(),
4581
+ role: "presentation",
4582
+ children: /* @__PURE__ */ jsx(CopyButton$1, {
4583
+ value: row.value,
4584
+ label: `Copy value ${row.value}`,
4585
+ className: "sb-token-table__copy"
4586
+ })
4587
+ })
4588
+ ]
4287
4589
  })
4288
- ]
4289
- })
4290
- })]
4291
- }, row.path))] })
4590
+ }),
4591
+ /* @__PURE__ */ jsx("td", {
4592
+ className: "sb-token-table__td sb-token-table__refs",
4593
+ children: token && /* @__PURE__ */ jsx(RowIndicators, {
4594
+ path: row.path,
4595
+ token,
4596
+ root: void 0,
4597
+ variance: varianceByPath[row.path],
4598
+ colorFormat,
4599
+ canReference: (p) => p in resolved,
4600
+ onReferenceClick: (p) => setSelectedPath(p)
4601
+ })
4602
+ })
4603
+ ]
4604
+ }, row.path);
4605
+ })] })
4292
4606
  ]
4293
4607
  }),
4294
4608
  selectedPath !== null && /* @__PURE__ */ jsx(DetailOverlay, {