@unpunnyfuns/swatchbook-blocks 0.52.0 → 0.54.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
@@ -46,16 +46,16 @@ function formatColor(value, format, fallback = DEFAULT_FALLBACK) {
46
46
  function coerce(value) {
47
47
  if (!value || typeof value !== "object") return null;
48
48
  const v = value;
49
- const colorSpace = typeof v["colorSpace"] === "string" ? v["colorSpace"] : void 0;
50
- const components = Array.isArray(v["components"]) ? v["components"] : Array.isArray(v["channels"]) ? v["channels"] : void 0;
49
+ const colorSpace = typeof v.colorSpace === "string" ? v.colorSpace : void 0;
50
+ const components = Array.isArray(v.components) ? v.components : Array.isArray(v.channels) ? v.channels : void 0;
51
51
  if (!colorSpace || !components) {
52
- if (typeof v["hex"] === "string") return {
52
+ if (typeof v.hex === "string") return {
53
53
  colorSpace: "srgb",
54
- components: hexToComponents(v["hex"])
54
+ components: hexToComponents(v.hex)
55
55
  };
56
56
  return null;
57
57
  }
58
- const alpha = typeof v["alpha"] === "number" ? v["alpha"] : void 0;
58
+ const alpha = typeof v.alpha === "number" ? v.alpha : void 0;
59
59
  const hex = typeof v["hex"] === "string" ? v["hex"] : void 0;
60
60
  return {
61
61
  colorSpace,
@@ -926,11 +926,7 @@ function CopyButton$1({ value, label, variant = "icon", className }) {
926
926
  };
927
927
  }, []);
928
928
  const handleClick = useCallback(() => {
929
- try {
930
- navigator.clipboard?.writeText(value);
931
- } catch {
932
- return;
933
- }
929
+ navigator.clipboard?.writeText(value).catch(() => {});
934
930
  setCopied(true);
935
931
  if (timerRef.current !== null) clearTimeout(timerRef.current);
936
932
  timerRef.current = setTimeout(() => setCopied(false), 1500);
@@ -1658,13 +1654,13 @@ function formatShadow(v, colorFormat) {
1658
1654
  if (!layer || typeof layer !== "object") return formatUnknown(layer);
1659
1655
  const s = layer;
1660
1656
  const pieces = [
1661
- formatDimension$1(s["offsetX"]),
1662
- formatDimension$1(s["offsetY"]),
1663
- formatDimension$1(s["blur"]),
1664
- formatDimension$1(s["spread"]),
1665
- formatColor(s["color"], colorFormat).value
1657
+ formatDimension$1(s.offsetX),
1658
+ formatDimension$1(s.offsetY),
1659
+ formatDimension$1(s.blur),
1660
+ formatDimension$1(s.spread),
1661
+ formatColor(s.color, colorFormat).value
1666
1662
  ].filter((p) => p !== "");
1667
- if (s["inset"]) pieces.push("inset");
1663
+ if (s.inset) pieces.push("inset");
1668
1664
  return pieces.join(" ");
1669
1665
  }).join(", ");
1670
1666
  }
@@ -1672,9 +1668,9 @@ function formatBorder(v, colorFormat) {
1672
1668
  if (!v || typeof v !== "object") return formatUnknown(v);
1673
1669
  const b = v;
1674
1670
  return [
1675
- formatDimension$1(b["width"]),
1676
- formatPrimitive$1(b["style"]),
1677
- formatColor(b["color"], colorFormat).value
1671
+ formatDimension$1(b.width),
1672
+ formatPrimitive$1(b.style),
1673
+ formatColor(b.color, colorFormat).value
1678
1674
  ].filter((p) => p !== "").join(" ");
1679
1675
  }
1680
1676
  function formatUnknown(v) {
@@ -2999,27 +2995,27 @@ function CompositeBreakdownContent({ type, rawValue, partialAliasOf, resolved, c
2999
2995
  return renderKeyValueList([
3000
2996
  [
3001
2997
  "fontFamily",
3002
- formatFontFamily(v["fontFamily"]),
2998
+ formatFontFamily(v.fontFamily),
3003
2999
  aliasFor("fontFamily")
3004
3000
  ],
3005
3001
  [
3006
3002
  "fontSize",
3007
- formatDimensionValue(v["fontSize"]),
3003
+ formatDimensionValue(v.fontSize),
3008
3004
  aliasFor("fontSize")
3009
3005
  ],
3010
3006
  [
3011
3007
  "fontWeight",
3012
- formatPrimitive(v["fontWeight"]),
3008
+ formatPrimitive(v.fontWeight),
3013
3009
  aliasFor("fontWeight")
3014
3010
  ],
3015
3011
  [
3016
3012
  "lineHeight",
3017
- formatPrimitive(v["lineHeight"]),
3013
+ formatPrimitive(v.lineHeight),
3018
3014
  aliasFor("lineHeight")
3019
3015
  ],
3020
3016
  [
3021
3017
  "letterSpacing",
3022
- formatDimensionValue(v["letterSpacing"]),
3018
+ formatDimensionValue(v.letterSpacing),
3023
3019
  aliasFor("letterSpacing")
3024
3020
  ]
3025
3021
  ]);
@@ -3029,17 +3025,17 @@ function CompositeBreakdownContent({ type, rawValue, partialAliasOf, resolved, c
3029
3025
  return renderKeyValueList([
3030
3026
  [
3031
3027
  "color",
3032
- formatColorSubValue(v["color"], colorFormat),
3028
+ formatColorSubValue(v.color, colorFormat),
3033
3029
  aliasFor("color")
3034
3030
  ],
3035
3031
  [
3036
3032
  "width",
3037
- formatDimensionValue(v["width"]),
3033
+ formatDimensionValue(v.width),
3038
3034
  aliasFor("width")
3039
3035
  ],
3040
3036
  [
3041
3037
  "style",
3042
- formatPrimitive(v["style"]),
3038
+ formatPrimitive(v.style),
3043
3039
  aliasFor("style")
3044
3040
  ]
3045
3041
  ]);
@@ -3049,17 +3045,17 @@ function CompositeBreakdownContent({ type, rawValue, partialAliasOf, resolved, c
3049
3045
  return renderKeyValueList([
3050
3046
  [
3051
3047
  "duration",
3052
- formatDimensionValue(v["duration"]),
3048
+ formatDimensionValue(v.duration),
3053
3049
  aliasFor("duration")
3054
3050
  ],
3055
3051
  [
3056
3052
  "timingFunction",
3057
- formatPrimitive(v["timingFunction"]),
3053
+ formatPrimitive(v.timingFunction),
3058
3054
  aliasFor("timingFunction")
3059
3055
  ],
3060
3056
  [
3061
3057
  "delay",
3062
- formatDimensionValue(v["delay"]),
3058
+ formatDimensionValue(v.delay),
3063
3059
  aliasFor("delay")
3064
3060
  ]
3065
3061
  ]);
@@ -3081,32 +3077,32 @@ function CompositeBreakdownContent({ type, rawValue, partialAliasOf, resolved, c
3081
3077
  }),
3082
3078
  /* @__PURE__ */ jsx(KeyValueRow, {
3083
3079
  label: "color",
3084
- value: formatColorSubValue(v["color"], colorFormat),
3080
+ value: formatColorSubValue(v.color, colorFormat),
3085
3081
  alias: layerAliasFor(i, "color")
3086
3082
  }),
3087
3083
  /* @__PURE__ */ jsx(KeyValueRow, {
3088
3084
  label: "offsetX",
3089
- value: formatDimensionValue(v["offsetX"]),
3085
+ value: formatDimensionValue(v.offsetX),
3090
3086
  alias: layerAliasFor(i, "offsetX")
3091
3087
  }),
3092
3088
  /* @__PURE__ */ jsx(KeyValueRow, {
3093
3089
  label: "offsetY",
3094
- value: formatDimensionValue(v["offsetY"]),
3090
+ value: formatDimensionValue(v.offsetY),
3095
3091
  alias: layerAliasFor(i, "offsetY")
3096
3092
  }),
3097
3093
  /* @__PURE__ */ jsx(KeyValueRow, {
3098
3094
  label: "blur",
3099
- value: formatDimensionValue(v["blur"]),
3095
+ value: formatDimensionValue(v.blur),
3100
3096
  alias: layerAliasFor(i, "blur")
3101
3097
  }),
3102
3098
  /* @__PURE__ */ jsx(KeyValueRow, {
3103
3099
  label: "spread",
3104
- value: formatDimensionValue(v["spread"]),
3100
+ value: formatDimensionValue(v.spread),
3105
3101
  alias: layerAliasFor(i, "spread")
3106
3102
  }),
3107
- "inset" in v && /* @__PURE__ */ jsx(KeyValueRow, {
3103
+ v.inset !== void 0 && /* @__PURE__ */ jsx(KeyValueRow, {
3108
3104
  label: "inset",
3109
- value: formatPrimitive(v["inset"]),
3105
+ value: formatPrimitive(v.inset),
3110
3106
  alias: void 0
3111
3107
  })
3112
3108
  ]
@@ -3123,8 +3119,8 @@ function CompositeBreakdownContent({ type, rawValue, partialAliasOf, resolved, c
3123
3119
  children: stops.map((stop, i) => {
3124
3120
  const v = stop;
3125
3121
  return /* @__PURE__ */ jsx(KeyValueRow, {
3126
- label: `${((typeof v["position"] === "number" ? v["position"] : 0) * 100).toFixed(0)}%`,
3127
- value: formatColorSubValue(v["color"], colorFormat),
3122
+ label: `${((typeof v.position === "number" ? v.position : 0) * 100).toFixed(0)}%`,
3123
+ value: formatColorSubValue(v.color, colorFormat),
3128
3124
  alias: stopAliasFor(i)
3129
3125
  }, gradientStopKey(v, i));
3130
3126
  })
@@ -3215,16 +3211,16 @@ function subValueChain(aliasTarget, resolved) {
3215
3211
  }
3216
3212
  function shadowLayerKey(layer, fallback) {
3217
3213
  return `shadow|${[
3218
- layer["color"],
3219
- layer["offsetX"],
3220
- layer["offsetY"],
3221
- layer["blur"],
3222
- layer["spread"],
3223
- layer["inset"]
3214
+ layer.color,
3215
+ layer.offsetX,
3216
+ layer.offsetY,
3217
+ layer.blur,
3218
+ layer.spread,
3219
+ layer.inset
3224
3220
  ].map((p) => p === void 0 ? "" : JSON.stringify(p)).join("|")}|${fallback}`;
3225
3221
  }
3226
3222
  function gradientStopKey(stop, fallback) {
3227
- return `stop|${stop["position"] ?? fallback}|${JSON.stringify(stop["color"])}`;
3223
+ return `stop|${stop.position ?? fallback}|${JSON.stringify(stop.color)}`;
3228
3224
  }
3229
3225
  //#endregion
3230
3226
  //#region src/token-detail/CompositePreview.tsx
@@ -3600,7 +3596,30 @@ function TokenDetail({ path, heading }) {
3600
3596
  }
3601
3597
  //#endregion
3602
3598
  //#region src/internal/DetailOverlay.tsx
3599
+ /**
3600
+ * Selector for elements the trap considers focus stops. Mirrors the
3601
+ * "tabbable" set most focus-trap libraries use; the `:not(...)` clauses
3602
+ * skip the panel wrapper itself (we focus it manually on mount via its
3603
+ * own ref) and any explicitly-detabbed descendants.
3604
+ */
3605
+ const FOCUSABLE_SELECTOR = [
3606
+ "a[href]",
3607
+ "button:not([disabled])",
3608
+ "input:not([disabled])",
3609
+ "select:not([disabled])",
3610
+ "textarea:not([disabled])",
3611
+ "[tabindex]:not([tabindex=\"-1\"])"
3612
+ ].join(", ");
3603
3613
  function DetailOverlay({ path, onClose, testId = "swatchbook-overlay" }) {
3614
+ const panelRef = useRef(null);
3615
+ const openerRef = useRef(null);
3616
+ useEffect(() => {
3617
+ openerRef.current = document.activeElement instanceof HTMLElement ? document.activeElement : null;
3618
+ panelRef.current?.focus();
3619
+ return () => {
3620
+ openerRef.current?.focus();
3621
+ };
3622
+ }, []);
3604
3623
  useEffect(() => {
3605
3624
  const onKey = (e) => {
3606
3625
  if (e.key === "Escape") onClose();
@@ -3608,17 +3627,48 @@ function DetailOverlay({ path, onClose, testId = "swatchbook-overlay" }) {
3608
3627
  window.addEventListener("keydown", onKey);
3609
3628
  return () => window.removeEventListener("keydown", onKey);
3610
3629
  }, [onClose]);
3630
+ /**
3631
+ * Wrap Tab inside the panel: from the last focusable, jump to the first;
3632
+ * from the first (or from the panel itself), Shift+Tab jumps to the last.
3633
+ * Defers to the browser otherwise.
3634
+ */
3635
+ const onPanelKeyDown = (e) => {
3636
+ if (e.key !== "Tab") return;
3637
+ const panel = panelRef.current;
3638
+ if (!panel) return;
3639
+ const focusables = panel.querySelectorAll(FOCUSABLE_SELECTOR);
3640
+ if (focusables.length === 0) {
3641
+ e.preventDefault();
3642
+ return;
3643
+ }
3644
+ const first = focusables[0];
3645
+ const last = focusables[focusables.length - 1];
3646
+ const active = document.activeElement;
3647
+ if (!first || !last) return;
3648
+ if (e.shiftKey) {
3649
+ if (active === first || active === panel) {
3650
+ e.preventDefault();
3651
+ last.focus();
3652
+ }
3653
+ } else if (active === last) {
3654
+ e.preventDefault();
3655
+ first.focus();
3656
+ }
3657
+ };
3611
3658
  return /* @__PURE__ */ jsx("div", {
3612
3659
  className: "sb-detail-overlay__backdrop",
3613
3660
  onClick: onClose,
3614
3661
  role: "presentation",
3615
3662
  "data-testid": testId,
3616
3663
  children: /* @__PURE__ */ jsxs("div", {
3664
+ ref: panelRef,
3617
3665
  className: "sb-detail-overlay__panel",
3618
3666
  onClick: (e) => e.stopPropagation(),
3667
+ onKeyDown: onPanelKeyDown,
3619
3668
  role: "dialog",
3620
3669
  "aria-modal": "true",
3621
3670
  "aria-label": `Token detail for ${path}`,
3671
+ tabIndex: -1,
3622
3672
  children: [/* @__PURE__ */ jsx("button", {
3623
3673
  type: "button",
3624
3674
  className: "sb-detail-overlay__close",
@@ -3707,6 +3757,16 @@ function collectLeafPaths(nodes, out) {
3707
3757
  for (const node of nodes) if (node.kind === "leaf") out.push(node.path);
3708
3758
  else collectLeafPaths(node.children, out);
3709
3759
  }
3760
+ function flattenVisible(nodes, expanded, parentPath, out) {
3761
+ for (const node of nodes) {
3762
+ out.push({
3763
+ path: node.path,
3764
+ kind: node.kind,
3765
+ parentPath
3766
+ });
3767
+ if (node.kind === "group" && expanded.has(node.path)) flattenVisible(node.children, expanded, node.path, out);
3768
+ }
3769
+ }
3710
3770
  /**
3711
3771
  * Return a pruned copy of the tree keeping only leaves whose path is in
3712
3772
  * `matches`, plus the groups on the way to them. Every surviving group's
@@ -3786,6 +3846,125 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
3786
3846
  if (onSelect) onSelect(path);
3787
3847
  else setSelectedPath(path);
3788
3848
  }, [onSelect]);
3849
+ const [focusedPath, setFocusedPath] = useState(null);
3850
+ const treeItemRefs = useRef(/* @__PURE__ */ new Map());
3851
+ const registerTreeItem = useCallback((path) => (el) => {
3852
+ if (el) treeItemRefs.current.set(path, el);
3853
+ else treeItemRefs.current.delete(path);
3854
+ }, []);
3855
+ const flatVisible = useMemo(() => {
3856
+ const out = [];
3857
+ flattenVisible(visibleTree, effectiveExpanded, null, out);
3858
+ return out;
3859
+ }, [visibleTree, effectiveExpanded]);
3860
+ useEffect(() => {
3861
+ if (flatVisible.length === 0) {
3862
+ setFocusedPath(null);
3863
+ return;
3864
+ }
3865
+ setFocusedPath((prev) => {
3866
+ if (prev && flatVisible.some((entry) => entry.path === prev)) return prev;
3867
+ return flatVisible[0]?.path ?? null;
3868
+ });
3869
+ }, [flatVisible]);
3870
+ const focusByPath = useCallback((path) => {
3871
+ const node = treeItemRefs.current.get(path);
3872
+ if (node) {
3873
+ node.focus();
3874
+ setFocusedPath(path);
3875
+ } else setFocusedPath(path);
3876
+ }, []);
3877
+ useEffect(() => {
3878
+ if (focusedPath === null) return;
3879
+ const node = treeItemRefs.current.get(focusedPath);
3880
+ if (node && document.activeElement !== node) {
3881
+ const active = document.activeElement;
3882
+ if (active instanceof HTMLElement && active.closest("[role=\"tree\"]")) node.focus();
3883
+ }
3884
+ }, [focusedPath]);
3885
+ const handleTreeKeyDown = useCallback((e) => {
3886
+ if (flatVisible.length === 0) return;
3887
+ const active = document.activeElement;
3888
+ if (!(active instanceof HTMLLIElement)) return;
3889
+ const activePath = active.getAttribute("data-path");
3890
+ if (activePath === null) return;
3891
+ const currentIndex = flatVisible.findIndex((entry) => entry.path === activePath);
3892
+ if (currentIndex < 0) return;
3893
+ const current = flatVisible[currentIndex];
3894
+ if (!current) return;
3895
+ switch (e.key) {
3896
+ case "ArrowDown": {
3897
+ const next = flatVisible[currentIndex + 1];
3898
+ if (next) {
3899
+ e.preventDefault();
3900
+ focusByPath(next.path);
3901
+ }
3902
+ return;
3903
+ }
3904
+ case "ArrowUp": {
3905
+ const prev = flatVisible[currentIndex - 1];
3906
+ if (prev) {
3907
+ e.preventDefault();
3908
+ focusByPath(prev.path);
3909
+ }
3910
+ return;
3911
+ }
3912
+ case "Home": {
3913
+ const first = flatVisible[0];
3914
+ if (first) {
3915
+ e.preventDefault();
3916
+ focusByPath(first.path);
3917
+ }
3918
+ return;
3919
+ }
3920
+ case "End": {
3921
+ const last = flatVisible[flatVisible.length - 1];
3922
+ if (last) {
3923
+ e.preventDefault();
3924
+ focusByPath(last.path);
3925
+ }
3926
+ return;
3927
+ }
3928
+ case "ArrowRight":
3929
+ if (current.kind === "group") {
3930
+ if (!effectiveExpanded.has(current.path)) {
3931
+ e.preventDefault();
3932
+ toggle(current.path);
3933
+ return;
3934
+ }
3935
+ const firstChild = flatVisible[currentIndex + 1];
3936
+ if (firstChild && firstChild.parentPath === current.path) {
3937
+ e.preventDefault();
3938
+ focusByPath(firstChild.path);
3939
+ }
3940
+ }
3941
+ return;
3942
+ case "ArrowLeft":
3943
+ if (current.kind === "group" && effectiveExpanded.has(current.path)) {
3944
+ e.preventDefault();
3945
+ toggle(current.path);
3946
+ return;
3947
+ }
3948
+ if (current.parentPath !== null) {
3949
+ e.preventDefault();
3950
+ focusByPath(current.parentPath);
3951
+ }
3952
+ return;
3953
+ case "Enter":
3954
+ case " ":
3955
+ e.preventDefault();
3956
+ if (current.kind === "group") toggle(current.path);
3957
+ else handleLeafClick(current.path);
3958
+ return;
3959
+ default: return;
3960
+ }
3961
+ }, [
3962
+ flatVisible,
3963
+ effectiveExpanded,
3964
+ toggle,
3965
+ focusByPath,
3966
+ handleLeafClick
3967
+ ]);
3789
3968
  const typeLabel = typeFilter ? ` · ${[...typeFilter].map((t) => `$type=${t}`).join(", ")}` : "";
3790
3969
  const trimmedQuery = query.trim();
3791
3970
  const matchCount = useMemo(() => {
@@ -3834,10 +4013,15 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
3834
4013
  }) : /* @__PURE__ */ jsx("ul", {
3835
4014
  className: "sb-token-navigator__tree",
3836
4015
  role: "tree",
4016
+ "aria-label": "Token graph",
4017
+ onKeyDown: handleTreeKeyDown,
3837
4018
  children: visibleTree.map((node) => /* @__PURE__ */ jsx(TreeNodeRow, {
3838
4019
  node,
3839
4020
  expanded: effectiveExpanded,
4021
+ focusedPath,
4022
+ registerTreeItem,
3840
4023
  onToggle: toggle,
4024
+ onFocusPath: setFocusedPath,
3841
4025
  onLeafClick: handleLeafClick
3842
4026
  }, node.path || node.segment))
3843
4027
  }),
@@ -3849,29 +4033,31 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
3849
4033
  ]
3850
4034
  });
3851
4035
  }
3852
- function TreeNodeRow({ node, expanded, onToggle, onLeafClick }) {
4036
+ function TreeNodeRow({ node, expanded, focusedPath, registerTreeItem, onToggle, onFocusPath, onLeafClick }) {
3853
4037
  if (node.kind === "leaf") return /* @__PURE__ */ jsx(LeafRow, {
3854
4038
  node,
4039
+ focusedPath,
4040
+ registerTreeItem,
4041
+ onFocusPath,
3855
4042
  onLeafClick
3856
4043
  });
3857
4044
  const isOpen = expanded.has(node.path);
3858
- const onKey = (e) => {
3859
- if (e.key === "Enter" || e.key === " ") {
3860
- e.preventDefault();
3861
- onToggle(node.path);
3862
- }
3863
- };
4045
+ const isFocused = focusedPath === node.path;
3864
4046
  return /* @__PURE__ */ jsxs("li", {
4047
+ ref: registerTreeItem(node.path),
3865
4048
  role: "treeitem",
3866
4049
  "aria-expanded": isOpen,
4050
+ tabIndex: isFocused ? 0 : -1,
4051
+ onFocus: () => onFocusPath(node.path),
4052
+ "data-path": node.path,
4053
+ "data-testid": "token-navigator-group",
3867
4054
  children: [/* @__PURE__ */ jsxs("div", {
3868
- role: "button",
3869
- tabIndex: 0,
3870
4055
  className: "sb-token-navigator__group-row",
3871
- onClick: () => onToggle(node.path),
3872
- onKeyDown: onKey,
3873
- "data-path": node.path,
3874
- "data-testid": "token-navigator-group",
4056
+ "data-testid": "token-navigator-group-row",
4057
+ onClick: () => {
4058
+ onFocusPath(node.path);
4059
+ onToggle(node.path);
4060
+ },
3875
4061
  children: [
3876
4062
  /* @__PURE__ */ jsx("span", {
3877
4063
  className: "sb-token-navigator__caret",
@@ -3890,30 +4076,32 @@ function TreeNodeRow({ node, expanded, onToggle, onLeafClick }) {
3890
4076
  children: node.children.map((c) => /* @__PURE__ */ jsx(TreeNodeRow, {
3891
4077
  node: c,
3892
4078
  expanded,
4079
+ focusedPath,
4080
+ registerTreeItem,
3893
4081
  onToggle,
4082
+ onFocusPath,
3894
4083
  onLeafClick
3895
4084
  }, c.path || c.segment))
3896
4085
  })]
3897
4086
  });
3898
4087
  }
3899
- function LeafRow({ node, onLeafClick }) {
3900
- const onKey = (e) => {
3901
- if (e.key === "Enter" || e.key === " ") {
3902
- e.preventDefault();
3903
- onLeafClick(node.path);
3904
- }
3905
- };
4088
+ function LeafRow({ node, focusedPath, registerTreeItem, onFocusPath, onLeafClick }) {
3906
4089
  const type = node.token.$type ?? "";
4090
+ const isFocused = focusedPath === node.path;
3907
4091
  return /* @__PURE__ */ jsx("li", {
4092
+ ref: registerTreeItem(node.path),
3908
4093
  role: "treeitem",
4094
+ tabIndex: isFocused ? 0 : -1,
4095
+ onFocus: () => onFocusPath(node.path),
4096
+ "data-path": node.path,
4097
+ "data-testid": "token-navigator-leaf",
3909
4098
  children: /* @__PURE__ */ jsxs("div", {
3910
- role: "button",
3911
- tabIndex: 0,
3912
4099
  className: "sb-token-navigator__leaf-row",
3913
- onClick: () => onLeafClick(node.path),
3914
- onKeyDown: onKey,
3915
- "data-path": node.path,
3916
- "data-testid": "token-navigator-leaf",
4100
+ "data-testid": "token-navigator-leaf-row",
4101
+ onClick: () => {
4102
+ onFocusPath(node.path);
4103
+ onLeafClick(node.path);
4104
+ },
3917
4105
  children: [
3918
4106
  /* @__PURE__ */ jsx("span", {
3919
4107
  className: "sb-token-navigator__caret",
@@ -4165,7 +4353,7 @@ function asDimension(raw) {
4165
4353
  if (typeof raw === "string" || typeof raw === "number") return String(raw);
4166
4354
  if (typeof raw === "object") {
4167
4355
  const v = raw;
4168
- if ("value" in v && "unit" in v) return `${String(v["value"])}${String(v["unit"])}`;
4356
+ if (v.value !== void 0 && v.unit !== void 0) return `${String(v.value)}${String(v.unit)}`;
4169
4357
  }
4170
4358
  }
4171
4359
  function asFontFamily(raw) {
@@ -4173,11 +4361,11 @@ function asFontFamily(raw) {
4173
4361
  if (Array.isArray(raw)) return raw.map(String).join(", ");
4174
4362
  }
4175
4363
  function buildRow(path, composite) {
4176
- const fontFamily = asFontFamily(composite["fontFamily"]);
4177
- const fontSize = asDimension(composite["fontSize"]);
4178
- const fontWeight = composite["fontWeight"] == null ? void 0 : String(composite["fontWeight"]);
4179
- const lineHeight = composite["lineHeight"] == null ? void 0 : String(composite["lineHeight"]);
4180
- const letterSpacing = asDimension(composite["letterSpacing"]);
4364
+ const fontFamily = asFontFamily(composite.fontFamily);
4365
+ const fontSize = asDimension(composite.fontSize);
4366
+ const fontWeight = composite.fontWeight == null ? void 0 : String(composite.fontWeight);
4367
+ const lineHeight = composite.lineHeight == null ? void 0 : String(composite.lineHeight);
4368
+ const letterSpacing = asDimension(composite.letterSpacing);
4181
4369
  const sampleStyle = {};
4182
4370
  if (fontFamily) sampleStyle.fontFamily = fontFamily;
4183
4371
  if (fontSize) sampleStyle.fontSize = fontSize;