@unpunnyfuns/swatchbook-blocks 0.16.0 → 0.18.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 +55 -17
- package/dist/index.mjs +2394 -2108
- package/dist/index.mjs.map +1 -1
- package/dist/style.css +681 -538
- package/package.json +3 -2
package/dist/index.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import './style.css';
|
|
2
2
|
import Color from "colorjs.io";
|
|
3
|
-
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { Fragment, createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
4
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { makeCSSVar } from "@terrazzo/token-tools/css";
|
|
5
6
|
import { addons } from "storybook/preview-api";
|
|
6
|
-
import { axes, css, cssVarPrefix, defaultTheme, diagnostics, presets, themes, themesResolved } from "virtual:swatchbook/tokens";
|
|
7
|
+
import { axes, css, cssVarPrefix, defaultTheme, diagnostics, listing, presets, themes, themesResolved } from "virtual:swatchbook/tokens";
|
|
7
8
|
import { fuzzyFilter } from "@unpunnyfuns/swatchbook-core/fuzzy";
|
|
8
9
|
import cx from "clsx";
|
|
9
10
|
import { analyzeAxisVariance } from "@unpunnyfuns/swatchbook-core/variance";
|
|
@@ -355,6 +356,7 @@ let snapshot = {
|
|
|
355
356
|
diagnostics,
|
|
356
357
|
css,
|
|
357
358
|
cssVarPrefix,
|
|
359
|
+
listing: listing ?? {},
|
|
358
360
|
version: 0
|
|
359
361
|
};
|
|
360
362
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -372,6 +374,7 @@ function ensureSubscribed() {
|
|
|
372
374
|
diagnostics: payload.diagnostics ?? snapshot.diagnostics,
|
|
373
375
|
css: payload.css ?? snapshot.css,
|
|
374
376
|
cssVarPrefix: payload.cssVarPrefix ?? snapshot.cssVarPrefix,
|
|
377
|
+
listing: payload.listing ?? snapshot.listing,
|
|
375
378
|
version: snapshot.version + 1
|
|
376
379
|
};
|
|
377
380
|
for (const cb of listeners) cb();
|
|
@@ -429,7 +432,8 @@ function snapshotToData(snapshot) {
|
|
|
429
432
|
themesResolved: snapshot.themesResolved,
|
|
430
433
|
resolved: snapshot.themesResolved[snapshot.activeTheme] ?? {},
|
|
431
434
|
diagnostics: snapshot.diagnostics,
|
|
432
|
-
cssVarPrefix: snapshot.cssVarPrefix
|
|
435
|
+
cssVarPrefix: snapshot.cssVarPrefix,
|
|
436
|
+
listing: snapshot.listing ?? {}
|
|
433
437
|
};
|
|
434
438
|
}
|
|
435
439
|
/**
|
|
@@ -478,12 +482,56 @@ function useVirtualModuleFallback(enabled) {
|
|
|
478
482
|
themesResolved: tokens.themesResolved,
|
|
479
483
|
resolved: tokens.themesResolved[activeTheme] ?? {},
|
|
480
484
|
diagnostics: tokens.diagnostics,
|
|
481
|
-
cssVarPrefix: tokens.cssVarPrefix
|
|
485
|
+
cssVarPrefix: tokens.cssVarPrefix,
|
|
486
|
+
listing: tokens.listing
|
|
482
487
|
};
|
|
483
488
|
}
|
|
489
|
+
/**
|
|
490
|
+
* Thin wrapper around Terrazzo's `makeCSSVar` so the block-display surface
|
|
491
|
+
* and `packages/core/src/css.ts`'s emitter share one implementation. Any
|
|
492
|
+
* future naming-policy shift in Terrazzo (casing, unicode, prefix handling)
|
|
493
|
+
* reaches both surfaces at once instead of needing a parallel update here.
|
|
494
|
+
*/
|
|
484
495
|
function makeCssVar(path, prefix) {
|
|
485
|
-
|
|
486
|
-
|
|
496
|
+
return prefix ? makeCSSVar(path, {
|
|
497
|
+
prefix,
|
|
498
|
+
wrapVar: true
|
|
499
|
+
}) : makeCSSVar(path, { wrapVar: true });
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Resolve a token's CSS var reference, preferring the authoritative name
|
|
503
|
+
* emitted by `@terrazzo/plugin-css` (as recorded by
|
|
504
|
+
* `@terrazzo/plugin-token-listing` in the snapshot's `listing` field).
|
|
505
|
+
* Falls back to `makeCssVar` when the listing lacks an entry for this
|
|
506
|
+
* path — covers non-resolver projects, hand-built snapshots, and any
|
|
507
|
+
* listing-plugin miss.
|
|
508
|
+
*/
|
|
509
|
+
function resolveCssVar(path, project) {
|
|
510
|
+
const listed = project.listing[path]?.names?.["css"];
|
|
511
|
+
if (listed) return `var(${listed})`;
|
|
512
|
+
return makeCssVar(path, project.cssVarPrefix);
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Resolve a color value's display string + gamut flag, preferring the
|
|
516
|
+
* listing's `previewValue` when the user's active color-format matches
|
|
517
|
+
* plugin-css's output (hex). For any other format we fall back to
|
|
518
|
+
* `formatColor` so the toolbar's inspection modes (rgb / hsl / oklch /
|
|
519
|
+
* raw) keep working — the listing has only one canonical format.
|
|
520
|
+
*
|
|
521
|
+
* Pass `path === undefined` when resolving a sub-color inside a composite
|
|
522
|
+
* (shadow / border / gradient stop): composites' `previewValue` covers
|
|
523
|
+
* the whole token's rendering, not the individual channel, so there's no
|
|
524
|
+
* listing entry to key against.
|
|
525
|
+
*/
|
|
526
|
+
function resolveColorValue(path, raw, colorFormat, project) {
|
|
527
|
+
if (path !== void 0 && colorFormat === "hex") {
|
|
528
|
+
const listed = project.listing[path]?.previewValue;
|
|
529
|
+
if (typeof listed === "string") return {
|
|
530
|
+
value: listed,
|
|
531
|
+
outOfGamut: false
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
return formatColor(raw, colorFormat);
|
|
487
535
|
}
|
|
488
536
|
/**
|
|
489
537
|
* Match a dot-separated DTCG token path against a block `filter` prop.
|
|
@@ -519,8 +567,7 @@ const sampleStyle$1 = {
|
|
|
519
567
|
borderRadius: 6
|
|
520
568
|
};
|
|
521
569
|
function BorderSample({ path }) {
|
|
522
|
-
const
|
|
523
|
-
const cssVar = makeCssVar(path, cssVarPrefix);
|
|
570
|
+
const cssVar = resolveCssVar(path, useProject());
|
|
524
571
|
return /* @__PURE__ */ jsx("div", {
|
|
525
572
|
style: {
|
|
526
573
|
...sampleStyle$1,
|
|
@@ -694,7 +741,8 @@ function formatSubColor$1(raw, format) {
|
|
|
694
741
|
return formatColor(raw, format).value;
|
|
695
742
|
}
|
|
696
743
|
function BorderPreview({ filter, caption, sortBy = "path", sortDir = "asc" }) {
|
|
697
|
-
const
|
|
744
|
+
const project = useProject();
|
|
745
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
698
746
|
const colorFormat = useColorFormat();
|
|
699
747
|
const rows = useMemo(() => {
|
|
700
748
|
return sortTokens(Object.entries(resolved).filter(([path, token]) => {
|
|
@@ -705,13 +753,13 @@ function BorderPreview({ filter, caption, sortBy = "path", sortDir = "asc" }) {
|
|
|
705
753
|
dir: sortDir
|
|
706
754
|
}).map(([path, token]) => ({
|
|
707
755
|
path,
|
|
708
|
-
cssVar:
|
|
756
|
+
cssVar: resolveCssVar(path, project),
|
|
709
757
|
value: token.$value ?? {}
|
|
710
758
|
}));
|
|
711
759
|
}, [
|
|
712
760
|
resolved,
|
|
713
761
|
filter,
|
|
714
|
-
|
|
762
|
+
project,
|
|
715
763
|
sortBy,
|
|
716
764
|
sortDir
|
|
717
765
|
]);
|
|
@@ -786,7 +834,8 @@ function fixedPrefixLength(filter) {
|
|
|
786
834
|
return fixed;
|
|
787
835
|
}
|
|
788
836
|
function ColorPalette({ filter, groupBy, caption, sortBy = "path", sortDir = "asc" }) {
|
|
789
|
-
const
|
|
837
|
+
const project = useProject();
|
|
838
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
790
839
|
const colorFormat = useColorFormat();
|
|
791
840
|
const groups = useMemo(() => {
|
|
792
841
|
const entries = sortTokens(Object.entries(resolved).filter(([path, token]) => {
|
|
@@ -804,11 +853,11 @@ function ColorPalette({ filter, groupBy, caption, sortBy = "path", sortDir = "as
|
|
|
804
853
|
const groupKey = segments.slice(0, effectiveGroupBy).join(".");
|
|
805
854
|
const leaf = segments.slice(effectiveGroupBy).join(".") || segments.at(-1) || path;
|
|
806
855
|
const list = bucket.get(groupKey) ?? [];
|
|
807
|
-
const formatted =
|
|
856
|
+
const formatted = resolveColorValue(path, token.$value, colorFormat, project);
|
|
808
857
|
list.push({
|
|
809
858
|
path,
|
|
810
859
|
leaf,
|
|
811
|
-
cssVar:
|
|
860
|
+
cssVar: resolveCssVar(path, project),
|
|
812
861
|
value: formatted.value,
|
|
813
862
|
outOfGamut: formatted.outOfGamut
|
|
814
863
|
});
|
|
@@ -819,7 +868,7 @@ function ColorPalette({ filter, groupBy, caption, sortBy = "path", sortDir = "as
|
|
|
819
868
|
resolved,
|
|
820
869
|
filter,
|
|
821
870
|
groupBy,
|
|
822
|
-
|
|
871
|
+
project,
|
|
823
872
|
colorFormat,
|
|
824
873
|
sortBy,
|
|
825
874
|
sortDir
|
|
@@ -920,70 +969,701 @@ function CopyButton$1({ value, label, variant = "icon", className }) {
|
|
|
920
969
|
});
|
|
921
970
|
}
|
|
922
971
|
//#endregion
|
|
923
|
-
//#region src/
|
|
972
|
+
//#region src/ColorTable.tsx
|
|
973
|
+
const BASE_LABEL = "base";
|
|
974
|
+
const COLUMN_COUNT = 6;
|
|
975
|
+
function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect, variants }) {
|
|
976
|
+
const project = useProject();
|
|
977
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
978
|
+
const colorFormat = useColorFormat();
|
|
979
|
+
const [query, setQuery] = useState("");
|
|
980
|
+
const [selectedByBase, setSelectedByBase] = useState({});
|
|
981
|
+
const [expandedByBase, setExpandedByBase] = useState(() => /* @__PURE__ */ new Set());
|
|
982
|
+
const defs = useMemo(() => buildVariantDefs(variants), [variants]);
|
|
983
|
+
const groups = useMemo(() => {
|
|
984
|
+
const sorted = sortTokens(Object.entries(resolved).filter(([path, token]) => {
|
|
985
|
+
if (token.$type !== "color") return false;
|
|
986
|
+
return globMatch(path, filter);
|
|
987
|
+
}), {
|
|
988
|
+
by: sortBy,
|
|
989
|
+
dir: sortDir
|
|
990
|
+
});
|
|
991
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
992
|
+
for (const [path, token] of sorted) {
|
|
993
|
+
const raw = token.$value;
|
|
994
|
+
const hex = resolveColorValue(path, raw, "hex", project);
|
|
995
|
+
const hsl = formatColor(raw, "hsl");
|
|
996
|
+
const oklch = formatColor(raw, "oklch");
|
|
997
|
+
const active = pickActiveFormat(raw, colorFormat, hex, hsl, oklch);
|
|
998
|
+
const match = matchVariant(path, defs.matchOrder);
|
|
999
|
+
const variant = {
|
|
1000
|
+
label: match?.label ?? BASE_LABEL,
|
|
1001
|
+
path,
|
|
1002
|
+
cssVar: resolveCssVar(path, project),
|
|
1003
|
+
value: active.value,
|
|
1004
|
+
outOfGamut: active.outOfGamut,
|
|
1005
|
+
hex: hex.value,
|
|
1006
|
+
hsl: hsl.value,
|
|
1007
|
+
oklch: oklch.value,
|
|
1008
|
+
...token.$description !== void 0 && { description: token.$description },
|
|
1009
|
+
...token.aliasOf !== void 0 && { aliasOf: token.aliasOf },
|
|
1010
|
+
...token.aliasChain !== void 0 && { aliasChain: token.aliasChain }
|
|
1011
|
+
};
|
|
1012
|
+
const basePath = match?.basePath ?? path;
|
|
1013
|
+
const existing = groupMap.get(basePath);
|
|
1014
|
+
if (existing) existing.variants.push(variant);
|
|
1015
|
+
else groupMap.set(basePath, {
|
|
1016
|
+
base: basePath,
|
|
1017
|
+
variants: [variant]
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
const out = [];
|
|
1021
|
+
for (const { base, variants: vs } of groupMap.values()) {
|
|
1022
|
+
vs.sort((a, b) => orderIndex(a.label, defs) - orderIndex(b.label, defs));
|
|
1023
|
+
const searchText = vs.map((v) => `${v.path} ${v.value}`).join(" ");
|
|
1024
|
+
out.push({
|
|
1025
|
+
base,
|
|
1026
|
+
variants: vs,
|
|
1027
|
+
searchText
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
return out;
|
|
1031
|
+
}, [
|
|
1032
|
+
resolved,
|
|
1033
|
+
filter,
|
|
1034
|
+
project,
|
|
1035
|
+
sortBy,
|
|
1036
|
+
sortDir,
|
|
1037
|
+
defs,
|
|
1038
|
+
colorFormat
|
|
1039
|
+
]);
|
|
1040
|
+
const visibleGroups = useMemo(() => {
|
|
1041
|
+
if (!searchable || query.trim() === "") return groups;
|
|
1042
|
+
return fuzzyFilter(groups, query, (g) => g.searchText);
|
|
1043
|
+
}, [
|
|
1044
|
+
groups,
|
|
1045
|
+
query,
|
|
1046
|
+
searchable
|
|
1047
|
+
]);
|
|
1048
|
+
const totalTokens = useMemo(() => groups.reduce((n, g) => n + g.variants.length, 0), [groups]);
|
|
1049
|
+
const toggleExpand = useCallback((base) => {
|
|
1050
|
+
setExpandedByBase((prev) => {
|
|
1051
|
+
const next = new Set(prev);
|
|
1052
|
+
if (next.has(base)) next.delete(base);
|
|
1053
|
+
else next.add(base);
|
|
1054
|
+
return next;
|
|
1055
|
+
});
|
|
1056
|
+
}, []);
|
|
1057
|
+
const selectVariant = useCallback((base, label) => {
|
|
1058
|
+
setSelectedByBase((prev) => ({
|
|
1059
|
+
...prev,
|
|
1060
|
+
[base]: label
|
|
1061
|
+
}));
|
|
1062
|
+
}, []);
|
|
1063
|
+
const matchSuffix = searchable && query.trim() !== "" ? ` · ${visibleGroups.length} matching "${query.trim()}"` : "";
|
|
1064
|
+
const captionText = caption ?? `${totalTokens} color${totalTokens === 1 ? "" : "s"} across ${groups.length} group${groups.length === 1 ? "" : "s"}${filter ? ` matching \`${filter}\`` : ""}${matchSuffix} · ${activeTheme}`;
|
|
1065
|
+
if (groups.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
1066
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
1067
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1068
|
+
className: "sb-block__empty",
|
|
1069
|
+
children: "No color tokens match this filter."
|
|
1070
|
+
})
|
|
1071
|
+
});
|
|
1072
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1073
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
1074
|
+
children: [searchable && /* @__PURE__ */ jsx("div", {
|
|
1075
|
+
className: "sb-color-table__search",
|
|
1076
|
+
children: /* @__PURE__ */ jsx("input", {
|
|
1077
|
+
type: "search",
|
|
1078
|
+
className: "sb-color-table__search-input",
|
|
1079
|
+
placeholder: "Search colors…",
|
|
1080
|
+
value: query,
|
|
1081
|
+
onChange: (e) => setQuery(e.target.value),
|
|
1082
|
+
"aria-label": "Fuzzy-search colors by path or value",
|
|
1083
|
+
"data-testid": "color-table-search"
|
|
1084
|
+
})
|
|
1085
|
+
}), /* @__PURE__ */ jsxs("table", {
|
|
1086
|
+
className: "sb-color-table__table",
|
|
1087
|
+
children: [
|
|
1088
|
+
/* @__PURE__ */ jsx("caption", {
|
|
1089
|
+
className: "sb-color-table__caption",
|
|
1090
|
+
children: captionText
|
|
1091
|
+
}),
|
|
1092
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
1093
|
+
/* @__PURE__ */ jsx("th", {
|
|
1094
|
+
className: "sb-color-table__th sb-color-table__th--swatch",
|
|
1095
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
1096
|
+
className: "sb-color-table__sr-only",
|
|
1097
|
+
children: "Swatch"
|
|
1098
|
+
})
|
|
1099
|
+
}),
|
|
1100
|
+
/* @__PURE__ */ jsx("th", {
|
|
1101
|
+
className: "sb-color-table__th sb-color-table__th--path",
|
|
1102
|
+
children: "Name"
|
|
1103
|
+
}),
|
|
1104
|
+
/* @__PURE__ */ jsx("th", {
|
|
1105
|
+
className: "sb-color-table__th",
|
|
1106
|
+
children: "Value"
|
|
1107
|
+
}),
|
|
1108
|
+
/* @__PURE__ */ jsx("th", {
|
|
1109
|
+
className: "sb-color-table__th",
|
|
1110
|
+
children: "CSS var"
|
|
1111
|
+
}),
|
|
1112
|
+
/* @__PURE__ */ jsx("th", {
|
|
1113
|
+
className: "sb-color-table__th",
|
|
1114
|
+
children: "Alias"
|
|
1115
|
+
}),
|
|
1116
|
+
/* @__PURE__ */ jsx("th", {
|
|
1117
|
+
className: "sb-color-table__th sb-color-table__th--expand",
|
|
1118
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
1119
|
+
className: "sb-color-table__sr-only",
|
|
1120
|
+
children: "Expand"
|
|
1121
|
+
})
|
|
1122
|
+
})
|
|
1123
|
+
] }) }),
|
|
1124
|
+
/* @__PURE__ */ jsxs("tbody", { children: [visibleGroups.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", {
|
|
1125
|
+
colSpan: COLUMN_COUNT,
|
|
1126
|
+
className: "sb-color-table__td sb-color-table__empty-row",
|
|
1127
|
+
children: [
|
|
1128
|
+
"No colors match \"",
|
|
1129
|
+
query.trim(),
|
|
1130
|
+
"\"."
|
|
1131
|
+
]
|
|
1132
|
+
}) }), visibleGroups.map((group) => /* @__PURE__ */ jsx(GroupRow, {
|
|
1133
|
+
group,
|
|
1134
|
+
selectedLabel: selectedByBase[group.base],
|
|
1135
|
+
expanded: expandedByBase.has(group.base),
|
|
1136
|
+
onToggleExpand: toggleExpand,
|
|
1137
|
+
onSelectVariant: selectVariant,
|
|
1138
|
+
...onSelect !== void 0 && { onSelect }
|
|
1139
|
+
}, group.base))] })
|
|
1140
|
+
]
|
|
1141
|
+
})]
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
function GroupRow({ group, selectedLabel, expanded, onToggleExpand, onSelectVariant, onSelect }) {
|
|
1145
|
+
const multi = group.variants.length > 1;
|
|
1146
|
+
const active = group.variants.find((v) => v.label === selectedLabel) ?? group.variants[0];
|
|
1147
|
+
const nameText = multi ? group.base : active.path;
|
|
1148
|
+
const handleRowActivate = () => {
|
|
1149
|
+
if (onSelect) onSelect(active.path);
|
|
1150
|
+
else onToggleExpand(group.base);
|
|
1151
|
+
};
|
|
1152
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("tr", {
|
|
1153
|
+
className: cx("sb-color-table__row", { "sb-color-table__row--expanded": expanded }),
|
|
1154
|
+
onClick: handleRowActivate,
|
|
1155
|
+
onKeyDown: (e) => {
|
|
1156
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
1157
|
+
e.preventDefault();
|
|
1158
|
+
handleRowActivate();
|
|
1159
|
+
}
|
|
1160
|
+
},
|
|
1161
|
+
tabIndex: 0,
|
|
1162
|
+
"aria-label": onSelect ? `Inspect ${active.path}` : expanded ? `Collapse ${group.base}` : `Expand ${group.base}`,
|
|
1163
|
+
"data-testid": "color-table-row",
|
|
1164
|
+
"data-path": active.path,
|
|
1165
|
+
"data-base": group.base,
|
|
1166
|
+
children: [
|
|
1167
|
+
/* @__PURE__ */ jsx("td", {
|
|
1168
|
+
className: "sb-color-table__td sb-color-table__swatch-cell",
|
|
1169
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
1170
|
+
className: "sb-color-table__swatch",
|
|
1171
|
+
style: { background: active.cssVar },
|
|
1172
|
+
"aria-hidden": true
|
|
1173
|
+
})
|
|
1174
|
+
}),
|
|
1175
|
+
/* @__PURE__ */ jsxs("td", {
|
|
1176
|
+
className: cx("sb-color-table__td", "sb-color-table__path"),
|
|
1177
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1178
|
+
className: "sb-color-table__path-text",
|
|
1179
|
+
children: nameText
|
|
1180
|
+
}), multi && /* @__PURE__ */ jsx("span", {
|
|
1181
|
+
className: "sb-color-table__variant-pills",
|
|
1182
|
+
onClick: (e) => e.stopPropagation(),
|
|
1183
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
1184
|
+
role: "presentation",
|
|
1185
|
+
children: group.variants.map((v) => /* @__PURE__ */ jsx("button", {
|
|
1186
|
+
type: "button",
|
|
1187
|
+
className: cx("sb-color-table__variant-pill", { "sb-color-table__variant-pill--active": v.label === active.label }),
|
|
1188
|
+
onClick: () => onSelectVariant(group.base, v.label),
|
|
1189
|
+
"aria-pressed": v.label === active.label,
|
|
1190
|
+
"data-testid": "color-table-variant",
|
|
1191
|
+
"data-variant": v.label,
|
|
1192
|
+
children: v.label
|
|
1193
|
+
}, v.label))
|
|
1194
|
+
})]
|
|
1195
|
+
}),
|
|
1196
|
+
/* @__PURE__ */ jsx(ValueCell, {
|
|
1197
|
+
value: active.value,
|
|
1198
|
+
label: `Copy value ${active.value}`,
|
|
1199
|
+
children: active.outOfGamut && /* @__PURE__ */ jsx("span", {
|
|
1200
|
+
title: "Out of sRGB gamut for this format",
|
|
1201
|
+
"aria-label": "out of gamut",
|
|
1202
|
+
className: "sb-color-table__gamut-warn",
|
|
1203
|
+
children: "⚠"
|
|
1204
|
+
})
|
|
1205
|
+
}),
|
|
1206
|
+
/* @__PURE__ */ jsx(ValueCell, {
|
|
1207
|
+
value: active.cssVar,
|
|
1208
|
+
label: `Copy CSS var ${active.cssVar}`
|
|
1209
|
+
}),
|
|
1210
|
+
/* @__PURE__ */ jsx("td", {
|
|
1211
|
+
className: "sb-color-table__td sb-color-table__alias",
|
|
1212
|
+
children: active.aliasOf ? /* @__PURE__ */ jsx("span", {
|
|
1213
|
+
className: "sb-color-table__alias-text",
|
|
1214
|
+
children: active.aliasOf
|
|
1215
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
1216
|
+
className: "sb-color-table__alias-empty",
|
|
1217
|
+
"aria-hidden": true,
|
|
1218
|
+
children: "—"
|
|
1219
|
+
})
|
|
1220
|
+
}),
|
|
1221
|
+
/* @__PURE__ */ jsx("td", {
|
|
1222
|
+
className: "sb-color-table__td sb-color-table__expand-cell",
|
|
1223
|
+
children: !onSelect && /* @__PURE__ */ jsx("span", {
|
|
1224
|
+
className: cx("sb-color-table__chevron", { "sb-color-table__chevron--expanded": expanded }),
|
|
1225
|
+
"aria-hidden": true,
|
|
1226
|
+
children: "▸"
|
|
1227
|
+
})
|
|
1228
|
+
})
|
|
1229
|
+
]
|
|
1230
|
+
}), expanded && !onSelect && /* @__PURE__ */ jsx("tr", {
|
|
1231
|
+
className: "sb-color-table__detail-row",
|
|
1232
|
+
"data-testid": "color-table-detail",
|
|
1233
|
+
children: /* @__PURE__ */ jsx("td", {
|
|
1234
|
+
colSpan: COLUMN_COUNT,
|
|
1235
|
+
className: "sb-color-table__td sb-color-table__detail-cell",
|
|
1236
|
+
children: /* @__PURE__ */ jsx(ExpandedDetail, {
|
|
1237
|
+
group,
|
|
1238
|
+
active
|
|
1239
|
+
})
|
|
1240
|
+
})
|
|
1241
|
+
})] });
|
|
1242
|
+
}
|
|
1243
|
+
function ExpandedDetail({ group, active }) {
|
|
1244
|
+
const hasDescription = active.description !== void 0 && active.description.length > 0;
|
|
1245
|
+
const chain = active.aliasChain && active.aliasChain.length > 0 ? active.aliasChain : void 0;
|
|
1246
|
+
const multi = group.variants.length > 1;
|
|
1247
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1248
|
+
className: "sb-color-table__detail",
|
|
1249
|
+
children: [
|
|
1250
|
+
hasDescription && /* @__PURE__ */ jsx("p", {
|
|
1251
|
+
className: "sb-color-table__description",
|
|
1252
|
+
children: active.description
|
|
1253
|
+
}),
|
|
1254
|
+
chain && /* @__PURE__ */ jsxs("p", {
|
|
1255
|
+
className: "sb-color-table__chain",
|
|
1256
|
+
children: [
|
|
1257
|
+
/* @__PURE__ */ jsx("span", {
|
|
1258
|
+
className: "sb-color-table__detail-label",
|
|
1259
|
+
children: "Alias chain:"
|
|
1260
|
+
}),
|
|
1261
|
+
" ",
|
|
1262
|
+
chain.join(" → ")
|
|
1263
|
+
]
|
|
1264
|
+
}),
|
|
1265
|
+
multi && /* @__PURE__ */ jsxs("div", {
|
|
1266
|
+
className: "sb-color-table__variant-grid",
|
|
1267
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1268
|
+
className: "sb-color-table__variant-grid-header",
|
|
1269
|
+
children: "All variants"
|
|
1270
|
+
}), /* @__PURE__ */ jsxs("table", {
|
|
1271
|
+
className: "sb-color-table__subtable",
|
|
1272
|
+
children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
|
|
1273
|
+
/* @__PURE__ */ jsx("th", {
|
|
1274
|
+
className: "sb-color-table__subth",
|
|
1275
|
+
children: "Variant"
|
|
1276
|
+
}),
|
|
1277
|
+
/* @__PURE__ */ jsx("th", {
|
|
1278
|
+
className: "sb-color-table__subth",
|
|
1279
|
+
children: "Path"
|
|
1280
|
+
}),
|
|
1281
|
+
/* @__PURE__ */ jsx("th", {
|
|
1282
|
+
className: "sb-color-table__subth",
|
|
1283
|
+
children: "HEX"
|
|
1284
|
+
}),
|
|
1285
|
+
/* @__PURE__ */ jsx("th", {
|
|
1286
|
+
className: "sb-color-table__subth",
|
|
1287
|
+
children: "HSL"
|
|
1288
|
+
}),
|
|
1289
|
+
/* @__PURE__ */ jsx("th", {
|
|
1290
|
+
className: "sb-color-table__subth",
|
|
1291
|
+
children: "OKLCH"
|
|
1292
|
+
})
|
|
1293
|
+
] }) }), /* @__PURE__ */ jsx("tbody", { children: group.variants.map((v) => /* @__PURE__ */ jsxs("tr", {
|
|
1294
|
+
className: cx({ "sb-color-table__subrow--active": v.label === active.label }),
|
|
1295
|
+
children: [
|
|
1296
|
+
/* @__PURE__ */ jsx("td", {
|
|
1297
|
+
className: "sb-color-table__subtd",
|
|
1298
|
+
children: v.label
|
|
1299
|
+
}),
|
|
1300
|
+
/* @__PURE__ */ jsx("td", {
|
|
1301
|
+
className: "sb-color-table__subtd sb-color-table__subtd--path",
|
|
1302
|
+
children: v.path
|
|
1303
|
+
}),
|
|
1304
|
+
/* @__PURE__ */ jsx("td", {
|
|
1305
|
+
className: "sb-color-table__subtd",
|
|
1306
|
+
children: v.hex
|
|
1307
|
+
}),
|
|
1308
|
+
/* @__PURE__ */ jsx("td", {
|
|
1309
|
+
className: "sb-color-table__subtd",
|
|
1310
|
+
children: v.hsl
|
|
1311
|
+
}),
|
|
1312
|
+
/* @__PURE__ */ jsx("td", {
|
|
1313
|
+
className: "sb-color-table__subtd",
|
|
1314
|
+
children: v.oklch
|
|
1315
|
+
})
|
|
1316
|
+
]
|
|
1317
|
+
}, v.label)) })]
|
|
1318
|
+
})]
|
|
1319
|
+
}),
|
|
1320
|
+
!hasDescription && !chain && !multi && /* @__PURE__ */ jsx("p", {
|
|
1321
|
+
className: "sb-color-table__detail-empty",
|
|
1322
|
+
children: "No description or alias chain authored for this token."
|
|
1323
|
+
})
|
|
1324
|
+
]
|
|
1325
|
+
});
|
|
1326
|
+
}
|
|
1327
|
+
function ValueCell({ value, label, children }) {
|
|
1328
|
+
return /* @__PURE__ */ jsxs("td", {
|
|
1329
|
+
className: "sb-color-table__td sb-color-table__value-cell",
|
|
1330
|
+
children: [
|
|
1331
|
+
/* @__PURE__ */ jsx("span", {
|
|
1332
|
+
className: "sb-color-table__value-text",
|
|
1333
|
+
title: value,
|
|
1334
|
+
children: value
|
|
1335
|
+
}),
|
|
1336
|
+
children,
|
|
1337
|
+
/* @__PURE__ */ jsx("span", {
|
|
1338
|
+
className: "sb-color-table__copy-wrap",
|
|
1339
|
+
onClick: (e) => e.stopPropagation(),
|
|
1340
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
1341
|
+
role: "presentation",
|
|
1342
|
+
children: /* @__PURE__ */ jsx(CopyButton$1, {
|
|
1343
|
+
value,
|
|
1344
|
+
label,
|
|
1345
|
+
className: "sb-color-table__copy"
|
|
1346
|
+
})
|
|
1347
|
+
})
|
|
1348
|
+
]
|
|
1349
|
+
});
|
|
1350
|
+
}
|
|
924
1351
|
/**
|
|
925
|
-
*
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
929
|
-
*
|
|
930
|
-
* - `color` → `formatColor(value, colorFormat)` — e.g. `#3b82f6`, `oklch(...)`, `raw` JSON.
|
|
931
|
-
* - `dimension|duration` → `value + unit` — e.g. `16px`, `200ms`.
|
|
932
|
-
* - `fontFamily` → string or array joined with `, `.
|
|
933
|
-
* - `fontWeight` → primitive.
|
|
934
|
-
* - `cubicBezier` → `cubic-bezier(a, b, c, d)`.
|
|
935
|
-
* - `strokeStyle` → primitive string, or `dashed · dashArray · lineCap` when it's the object shape.
|
|
936
|
-
* - `shadow` → one or more `offsetX offsetY blur spread color` layers joined with `, `.
|
|
937
|
-
* - `border` → `width style color`.
|
|
938
|
-
* - `transition` → `duration easing [delay]`.
|
|
939
|
-
* - `typography` → `family / size / line-height / weight`.
|
|
940
|
-
* - `gradient` → `stops joined with →` — compact representation, not a CSS gradient string (those live in GradientPalette's preview).
|
|
941
|
-
*
|
|
942
|
-
* Unknown object shapes fall through to truncated JSON.
|
|
1352
|
+
* Pick the value + gamut flag to display in the single Value column based
|
|
1353
|
+
* on the active color-format context. We pre-compute hex/hsl/oklch for the
|
|
1354
|
+
* expanded sub-table regardless; the extras (`rgb`, `raw`) take a fresh
|
|
1355
|
+
* `formatColor` pass. Keeps the hot path fast while staying honest about
|
|
1356
|
+
* out-of-gamut warnings per-format.
|
|
943
1357
|
*/
|
|
944
|
-
function
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
case "
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
case "
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
1358
|
+
function pickActiveFormat(raw, colorFormat, hex, hsl, oklch) {
|
|
1359
|
+
switch (colorFormat) {
|
|
1360
|
+
case "hex": return {
|
|
1361
|
+
value: hex.value,
|
|
1362
|
+
outOfGamut: hex.outOfGamut
|
|
1363
|
+
};
|
|
1364
|
+
case "hsl": return {
|
|
1365
|
+
value: hsl.value,
|
|
1366
|
+
outOfGamut: hsl.outOfGamut
|
|
1367
|
+
};
|
|
1368
|
+
case "oklch": return {
|
|
1369
|
+
value: oklch.value,
|
|
1370
|
+
outOfGamut: oklch.outOfGamut
|
|
1371
|
+
};
|
|
1372
|
+
default: {
|
|
1373
|
+
const extra = formatColor(raw, colorFormat);
|
|
1374
|
+
return {
|
|
1375
|
+
value: extra.value,
|
|
1376
|
+
outOfGamut: extra.outOfGamut
|
|
1377
|
+
};
|
|
1378
|
+
}
|
|
965
1379
|
}
|
|
966
1380
|
}
|
|
967
|
-
function
|
|
968
|
-
if (
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1381
|
+
function buildVariantDefs(variants) {
|
|
1382
|
+
if (!variants) return {
|
|
1383
|
+
matchOrder: [],
|
|
1384
|
+
displayOrder: []
|
|
1385
|
+
};
|
|
1386
|
+
const entries = [];
|
|
1387
|
+
const displayOrder = [];
|
|
1388
|
+
for (const [label, suffix] of Object.entries(variants)) {
|
|
1389
|
+
if (suffix.length === 0) continue;
|
|
1390
|
+
entries.push({
|
|
1391
|
+
label,
|
|
1392
|
+
suffix
|
|
1393
|
+
});
|
|
1394
|
+
displayOrder.push(label);
|
|
972
1395
|
}
|
|
973
|
-
return
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
if (Array.isArray(v)) return v.map(String).join(", ");
|
|
978
|
-
return formatUnknown(v);
|
|
1396
|
+
return {
|
|
1397
|
+
matchOrder: entries.toSorted((a, b) => b.suffix.length - a.suffix.length),
|
|
1398
|
+
displayOrder
|
|
1399
|
+
};
|
|
979
1400
|
}
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
1401
|
+
/**
|
|
1402
|
+
* Position of a label within a group — the `base` entry always sorts first,
|
|
1403
|
+
* then declared labels in the order the caller wrote them in the `variants`
|
|
1404
|
+
* prop. Unknown labels (shouldn't happen in practice) fall to the end.
|
|
1405
|
+
*/
|
|
1406
|
+
function orderIndex(label, defs) {
|
|
1407
|
+
if (label === BASE_LABEL) return -1;
|
|
1408
|
+
const idx = defs.displayOrder.indexOf(label);
|
|
1409
|
+
return idx >= 0 ? idx : Number.POSITIVE_INFINITY;
|
|
983
1410
|
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1411
|
+
/**
|
|
1412
|
+
* Resolve the variant label + base path for a token, if any. The leaf
|
|
1413
|
+
* (last dot-segment) must either equal the suffix outright (dot-segment
|
|
1414
|
+
* form: `hi.disabled` matches suffix `disabled`) or end in `-<suffix>`
|
|
1415
|
+
* (hyphen-tail form: `hi-d` matches `d`). The leading hyphen is required
|
|
1416
|
+
* for the tail form so suffix `0` can't hit `neutral-900` by character.
|
|
1417
|
+
*
|
|
1418
|
+
* Returned `basePath` is what gets used as the grouping key:
|
|
1419
|
+
* - Dot-segment match → parent path (drop the last dot-segment)
|
|
1420
|
+
* - Hyphen-tail match → same dot-depth, leaf with `-<suffix>` stripped
|
|
1421
|
+
*
|
|
1422
|
+
* Entries in `matchOrder` are pre-sorted longest-first, so `h-dark` wins
|
|
1423
|
+
* over `dark` for a path ending in `-h-dark`.
|
|
1424
|
+
*/
|
|
1425
|
+
function matchVariant(path, matchOrder) {
|
|
1426
|
+
if (matchOrder.length === 0) return void 0;
|
|
1427
|
+
const segments = path.split(".");
|
|
1428
|
+
const leaf = segments.at(-1) ?? path;
|
|
1429
|
+
for (const entry of matchOrder) {
|
|
1430
|
+
if (leaf === entry.suffix) {
|
|
1431
|
+
const parent = segments.slice(0, -1).join(".");
|
|
1432
|
+
if (parent.length === 0) continue;
|
|
1433
|
+
return {
|
|
1434
|
+
label: entry.label,
|
|
1435
|
+
basePath: parent
|
|
1436
|
+
};
|
|
1437
|
+
}
|
|
1438
|
+
const tailMarker = `-${entry.suffix}`;
|
|
1439
|
+
if (leaf.endsWith(tailMarker)) {
|
|
1440
|
+
const trimmed = leaf.slice(0, -tailMarker.length);
|
|
1441
|
+
if (trimmed.length === 0) continue;
|
|
1442
|
+
const copy = segments.slice(0, -1);
|
|
1443
|
+
copy.push(trimmed);
|
|
1444
|
+
return {
|
|
1445
|
+
label: entry.label,
|
|
1446
|
+
basePath: copy.join(".")
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
//#endregion
|
|
1452
|
+
//#region src/Diagnostics.tsx
|
|
1453
|
+
const severityLabel = {
|
|
1454
|
+
error: "ERROR",
|
|
1455
|
+
warn: "WARN",
|
|
1456
|
+
info: "INFO"
|
|
1457
|
+
};
|
|
1458
|
+
function summaryText(diagnostics) {
|
|
1459
|
+
if (diagnostics.length === 0) return "✔ OK · no diagnostics";
|
|
1460
|
+
const counts = {
|
|
1461
|
+
error: 0,
|
|
1462
|
+
warn: 0,
|
|
1463
|
+
info: 0
|
|
1464
|
+
};
|
|
1465
|
+
for (const d of diagnostics) counts[d.severity] += 1;
|
|
1466
|
+
const parts = [];
|
|
1467
|
+
if (counts.error > 0) parts.push(`✖ ${counts.error} error${counts.error === 1 ? "" : "s"}`);
|
|
1468
|
+
if (counts.warn > 0) parts.push(`⚠ ${counts.warn} warning${counts.warn === 1 ? "" : "s"}`);
|
|
1469
|
+
if (counts.info > 0) parts.push(`${counts.info} info`);
|
|
1470
|
+
return parts.join(" · ");
|
|
1471
|
+
}
|
|
1472
|
+
function diagnosticKey(d, i) {
|
|
1473
|
+
return `${d.severity}:${d.group}:${d.filename ?? ""}:${d.line ?? ""}:${d.message}:${i}`;
|
|
1474
|
+
}
|
|
1475
|
+
function summaryVariant(diagnostics) {
|
|
1476
|
+
if (diagnostics.length === 0) return "ok";
|
|
1477
|
+
if (diagnostics.some((d) => d.severity === "error")) return "error";
|
|
1478
|
+
if (diagnostics.some((d) => d.severity === "warn")) return "warn";
|
|
1479
|
+
return null;
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* Render the project's load diagnostics — parser errors, resolver warnings,
|
|
1483
|
+
* disabled-axes validation issues, etc. — as a collapsible list. Auto-opens
|
|
1484
|
+
* when the project carries errors or warnings; stays collapsed for clean
|
|
1485
|
+
* loads and info-only loads.
|
|
1486
|
+
*
|
|
1487
|
+
* Replaces the diagnostics section from the addon's (now-retired) Design
|
|
1488
|
+
* Tokens panel. Consumers compose it alongside TokenNavigator / TokenTable
|
|
1489
|
+
* on their own MDX pages.
|
|
1490
|
+
*/
|
|
1491
|
+
function Diagnostics({ caption } = {}) {
|
|
1492
|
+
const { activeTheme, cssVarPrefix, diagnostics } = useProject();
|
|
1493
|
+
const hasErrorsOrWarnings = diagnostics.some((d) => d.severity === "error" || d.severity === "warn");
|
|
1494
|
+
const headingText = caption ?? `Diagnostics · ${summaryText(diagnostics)}`;
|
|
1495
|
+
const variant = summaryVariant(diagnostics);
|
|
1496
|
+
return /* @__PURE__ */ jsx("div", {
|
|
1497
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
1498
|
+
"data-testid": "diagnostics",
|
|
1499
|
+
children: /* @__PURE__ */ jsxs("details", {
|
|
1500
|
+
open: hasErrorsOrWarnings,
|
|
1501
|
+
children: [/* @__PURE__ */ jsx("summary", {
|
|
1502
|
+
className: cx("sb-diagnostics__summary", variant && `sb-diagnostics__summary--${variant}`),
|
|
1503
|
+
children: headingText
|
|
1504
|
+
}), diagnostics.length > 0 && /* @__PURE__ */ jsx("ul", {
|
|
1505
|
+
className: "sb-diagnostics__list",
|
|
1506
|
+
children: diagnostics.map((d, i) => /* @__PURE__ */ jsxs("li", {
|
|
1507
|
+
className: "sb-diagnostics__row",
|
|
1508
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1509
|
+
className: cx("sb-diagnostics__label", { [`sb-diagnostics__label--${d.severity}`]: d.severity !== "info" }),
|
|
1510
|
+
children: severityLabel[d.severity]
|
|
1511
|
+
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children: d.message }), (d.group || d.filename) && /* @__PURE__ */ jsx("div", {
|
|
1512
|
+
className: "sb-diagnostics__meta",
|
|
1513
|
+
children: [
|
|
1514
|
+
d.group,
|
|
1515
|
+
d.filename,
|
|
1516
|
+
d.line ? `:${d.line}` : ""
|
|
1517
|
+
].filter(Boolean).join(" · ")
|
|
1518
|
+
})] })]
|
|
1519
|
+
}, diagnosticKey(d, i)))
|
|
1520
|
+
})]
|
|
1521
|
+
})
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
//#endregion
|
|
1525
|
+
//#region src/dimension-scale/DimensionBar.tsx
|
|
1526
|
+
const MAX_RENDER_PX$1 = 480;
|
|
1527
|
+
const styles$1 = {
|
|
1528
|
+
bar: {
|
|
1529
|
+
height: 14,
|
|
1530
|
+
background: "var(--swatchbook-accent-bg, #3b82f6)",
|
|
1531
|
+
borderRadius: 2,
|
|
1532
|
+
minWidth: 1
|
|
1533
|
+
},
|
|
1534
|
+
radiusSample: {
|
|
1535
|
+
width: 56,
|
|
1536
|
+
height: 56,
|
|
1537
|
+
background: "var(--swatchbook-accent-bg, #3b82f6)",
|
|
1538
|
+
border: BORDER_STRONG
|
|
1539
|
+
},
|
|
1540
|
+
sizeSample: {
|
|
1541
|
+
background: "var(--swatchbook-accent-bg, #3b82f6)",
|
|
1542
|
+
border: BORDER_STRONG,
|
|
1543
|
+
minWidth: 1,
|
|
1544
|
+
minHeight: 1
|
|
1545
|
+
}
|
|
1546
|
+
};
|
|
1547
|
+
/**
|
|
1548
|
+
* Convert a DTCG dimension `$value` (`{ value, unit }`) to pixels for the
|
|
1549
|
+
* purpose of deciding whether to cap the rendered bar. Returns `NaN` for
|
|
1550
|
+
* units we can't reasonably approximate (ex / ch / %), which the caller
|
|
1551
|
+
* treats as "render at cssVar but don't cap".
|
|
1552
|
+
*/
|
|
1553
|
+
function toPixels$1(raw) {
|
|
1554
|
+
if (raw == null || typeof raw !== "object") return NaN;
|
|
1555
|
+
const v = raw;
|
|
1556
|
+
if (typeof v.value !== "number" || typeof v.unit !== "string") return NaN;
|
|
1557
|
+
switch (v.unit) {
|
|
1558
|
+
case "px": return v.value;
|
|
1559
|
+
case "rem":
|
|
1560
|
+
case "em": return v.value * 16;
|
|
1561
|
+
default: return NaN;
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
function DimensionBar({ path, kind = "length" }) {
|
|
1565
|
+
const project = useProject();
|
|
1566
|
+
const { resolved } = project;
|
|
1567
|
+
const cssVar = resolveCssVar(path, project);
|
|
1568
|
+
const token = resolved[path];
|
|
1569
|
+
const pxValue = toPixels$1(token?.$value);
|
|
1570
|
+
const cappedValue = Number.isFinite(pxValue) && pxValue > MAX_RENDER_PX$1 ? `${MAX_RENDER_PX$1}px` : cssVar;
|
|
1571
|
+
switch (kind) {
|
|
1572
|
+
case "radius": return /* @__PURE__ */ jsx("div", {
|
|
1573
|
+
style: {
|
|
1574
|
+
...styles$1.radiusSample,
|
|
1575
|
+
borderRadius: cssVar
|
|
1576
|
+
},
|
|
1577
|
+
"aria-hidden": true
|
|
1578
|
+
});
|
|
1579
|
+
case "size": return /* @__PURE__ */ jsx("div", {
|
|
1580
|
+
style: {
|
|
1581
|
+
...styles$1.sizeSample,
|
|
1582
|
+
width: cappedValue,
|
|
1583
|
+
height: cappedValue
|
|
1584
|
+
},
|
|
1585
|
+
"aria-hidden": true
|
|
1586
|
+
});
|
|
1587
|
+
default: return /* @__PURE__ */ jsx("div", {
|
|
1588
|
+
style: {
|
|
1589
|
+
...styles$1.bar,
|
|
1590
|
+
width: cappedValue
|
|
1591
|
+
},
|
|
1592
|
+
"aria-hidden": true
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
//#endregion
|
|
1597
|
+
//#region src/internal/format-token-value.ts
|
|
1598
|
+
/**
|
|
1599
|
+
* Produce a single-line display string for any DTCG token `$value`,
|
|
1600
|
+
* respecting the active color format for color-typed tokens and the
|
|
1601
|
+
* color sub-values of composite types (border, shadow, gradient).
|
|
1602
|
+
*
|
|
1603
|
+
* Shape by type:
|
|
1604
|
+
* - `color` → `formatColor(value, colorFormat)` — e.g. `#3b82f6`, `oklch(...)`, `raw` JSON.
|
|
1605
|
+
* - `dimension|duration` → `value + unit` — e.g. `16px`, `200ms`.
|
|
1606
|
+
* - `fontFamily` → string or array joined with `, `.
|
|
1607
|
+
* - `fontWeight` → primitive.
|
|
1608
|
+
* - `cubicBezier` → `cubic-bezier(a, b, c, d)`.
|
|
1609
|
+
* - `strokeStyle` → primitive string, or `dashed · dashArray · lineCap` when it's the object shape.
|
|
1610
|
+
* - `shadow` → one or more `offsetX offsetY blur spread color` layers joined with `, `.
|
|
1611
|
+
* - `border` → `width style color`.
|
|
1612
|
+
* - `transition` → `duration easing [delay]`.
|
|
1613
|
+
* - `typography` → `family / size / line-height / weight`.
|
|
1614
|
+
* - `gradient` → `stops joined with →` — compact representation, not a CSS gradient string (those live in GradientPalette's preview).
|
|
1615
|
+
*
|
|
1616
|
+
* Unknown object shapes fall through to truncated JSON.
|
|
1617
|
+
*/
|
|
1618
|
+
function formatTokenValue(value, $type, colorFormat, listingEntry) {
|
|
1619
|
+
if (value == null) return "";
|
|
1620
|
+
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") return String(value);
|
|
1621
|
+
const preview = listingEntry?.previewValue;
|
|
1622
|
+
if (preview !== void 0) {
|
|
1623
|
+
const previewStr = typeof preview === "string" ? preview : String(preview);
|
|
1624
|
+
if ($type !== "color") return previewStr;
|
|
1625
|
+
if (colorFormat === "hex") return previewStr;
|
|
1626
|
+
}
|
|
1627
|
+
switch ($type) {
|
|
1628
|
+
case "color": return formatColor(value, colorFormat).value;
|
|
1629
|
+
case "dimension":
|
|
1630
|
+
case "duration": return formatDimension$1(value);
|
|
1631
|
+
case "fontFamily": return formatFontFamily$1(value);
|
|
1632
|
+
case "fontWeight":
|
|
1633
|
+
case "lineHeight":
|
|
1634
|
+
case "letterSpacing":
|
|
1635
|
+
case "opacity":
|
|
1636
|
+
case "number": return formatPrimitive$1(value);
|
|
1637
|
+
case "cubicBezier": return formatCubicBezier(value);
|
|
1638
|
+
case "strokeStyle": return formatStrokeStyle(value);
|
|
1639
|
+
case "shadow": return formatShadow(value, colorFormat);
|
|
1640
|
+
case "border": return formatBorder(value, colorFormat);
|
|
1641
|
+
case "transition": return formatTransition(value);
|
|
1642
|
+
case "typography": return formatTypography(value);
|
|
1643
|
+
case "gradient": return formatGradient(value, colorFormat);
|
|
1644
|
+
default: return formatUnknown(value);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
function formatDimension$1(v) {
|
|
1648
|
+
if (typeof v === "string" || typeof v === "number") return String(v);
|
|
1649
|
+
if (v && typeof v === "object") {
|
|
1650
|
+
const d = v;
|
|
1651
|
+
if (typeof d.value === "number" && typeof d.unit === "string") return `${d.value}${d.unit}`;
|
|
1652
|
+
}
|
|
1653
|
+
return formatUnknown(v);
|
|
1654
|
+
}
|
|
1655
|
+
function formatFontFamily$1(v) {
|
|
1656
|
+
if (typeof v === "string") return v;
|
|
1657
|
+
if (Array.isArray(v)) return v.map(String).join(", ");
|
|
1658
|
+
return formatUnknown(v);
|
|
1659
|
+
}
|
|
1660
|
+
function formatPrimitive$1(v) {
|
|
1661
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") return String(v);
|
|
1662
|
+
return formatUnknown(v);
|
|
1663
|
+
}
|
|
1664
|
+
function formatCubicBezier(v) {
|
|
1665
|
+
if (Array.isArray(v) && v.length === 4) return `cubic-bezier(${v.map((n) => typeof n === "number" ? n : 0).join(", ")})`;
|
|
1666
|
+
return formatUnknown(v);
|
|
987
1667
|
}
|
|
988
1668
|
function formatStrokeStyle(v) {
|
|
989
1669
|
if (typeof v === "string") return v;
|
|
@@ -1059,574 +1739,332 @@ function formatUnknown(v) {
|
|
|
1059
1739
|
}
|
|
1060
1740
|
}
|
|
1061
1741
|
//#endregion
|
|
1062
|
-
//#region src/
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
resolved: typedResolved,
|
|
1075
|
-
cssVarPrefix
|
|
1076
|
-
};
|
|
1742
|
+
//#region src/DimensionScale.tsx
|
|
1743
|
+
const MAX_RENDER_PX = 480;
|
|
1744
|
+
function toPixels(raw) {
|
|
1745
|
+
if (raw == null || typeof raw !== "object") return NaN;
|
|
1746
|
+
const v = raw;
|
|
1747
|
+
if (typeof v.value !== "number" || typeof v.unit !== "string") return NaN;
|
|
1748
|
+
switch (v.unit) {
|
|
1749
|
+
case "px": return v.value;
|
|
1750
|
+
case "rem":
|
|
1751
|
+
case "em": return v.value * 16;
|
|
1752
|
+
default: return NaN;
|
|
1753
|
+
}
|
|
1077
1754
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
const
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
};
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
className: "sb-token-detail__section-header",
|
|
1121
|
-
children: "Aliased by"
|
|
1122
|
-
}),
|
|
1123
|
-
/* @__PURE__ */ jsx("ul", {
|
|
1124
|
-
className: "sb-token-detail__aliased-by-list",
|
|
1125
|
-
children: tree.map((node) => /* @__PURE__ */ jsx(AliasedByRow, {
|
|
1126
|
-
node,
|
|
1127
|
-
depth: 0
|
|
1128
|
-
}, node.path))
|
|
1129
|
-
}),
|
|
1130
|
-
truncated && /* @__PURE__ */ jsxs("div", {
|
|
1131
|
-
className: "sb-token-detail__aliased-by-truncated",
|
|
1755
|
+
function DimensionScale({ filter, kind = "length", caption, sortBy = "value", sortDir = "asc" }) {
|
|
1756
|
+
const project = useProject();
|
|
1757
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
1758
|
+
const rows = useMemo(() => {
|
|
1759
|
+
return sortTokens(Object.entries(resolved).filter(([path, token]) => {
|
|
1760
|
+
if (token.$type !== "dimension") return false;
|
|
1761
|
+
return globMatch(path, filter);
|
|
1762
|
+
}), {
|
|
1763
|
+
by: sortBy,
|
|
1764
|
+
dir: sortDir
|
|
1765
|
+
}).map(([path, token]) => {
|
|
1766
|
+
const pxValue = toPixels(token.$value);
|
|
1767
|
+
return {
|
|
1768
|
+
path,
|
|
1769
|
+
cssVar: resolveCssVar(path, project),
|
|
1770
|
+
displayValue: formatTokenValue(token.$value, token.$type, "raw", project.listing[path]),
|
|
1771
|
+
pxValue,
|
|
1772
|
+
capped: Number.isFinite(pxValue) && pxValue > MAX_RENDER_PX
|
|
1773
|
+
};
|
|
1774
|
+
});
|
|
1775
|
+
}, [
|
|
1776
|
+
resolved,
|
|
1777
|
+
filter,
|
|
1778
|
+
project,
|
|
1779
|
+
sortBy,
|
|
1780
|
+
sortDir
|
|
1781
|
+
]);
|
|
1782
|
+
const captionText = caption ?? `${rows.length} dimension${rows.length === 1 ? "" : "s"}${filter ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
1783
|
+
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
1784
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
1785
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1786
|
+
className: "sb-block__empty",
|
|
1787
|
+
children: "No dimension tokens match this filter."
|
|
1788
|
+
})
|
|
1789
|
+
});
|
|
1790
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1791
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
1792
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1793
|
+
className: "sb-block__caption",
|
|
1794
|
+
children: captionText
|
|
1795
|
+
}), rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
1796
|
+
className: "sb-dimension-scale__row",
|
|
1132
1797
|
children: [
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1798
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1799
|
+
className: "sb-dimension-scale__meta",
|
|
1800
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1801
|
+
className: "sb-dimension-scale__path",
|
|
1802
|
+
children: row.path
|
|
1803
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1804
|
+
className: "sb-dimension-scale__specs",
|
|
1805
|
+
children: row.displayValue
|
|
1806
|
+
})]
|
|
1807
|
+
}),
|
|
1808
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1809
|
+
className: "sb-dimension-scale__visual-cell",
|
|
1810
|
+
children: [/* @__PURE__ */ jsx(DimensionBar, {
|
|
1811
|
+
path: row.path,
|
|
1812
|
+
kind
|
|
1813
|
+
}), row.capped && /* @__PURE__ */ jsxs("span", {
|
|
1814
|
+
className: "sb-dimension-scale__cap",
|
|
1815
|
+
children: [
|
|
1816
|
+
"capped at ",
|
|
1817
|
+
MAX_RENDER_PX,
|
|
1818
|
+
"px"
|
|
1819
|
+
]
|
|
1820
|
+
})]
|
|
1821
|
+
}),
|
|
1822
|
+
/* @__PURE__ */ jsx("span", {
|
|
1823
|
+
className: "sb-dimension-scale__css-var",
|
|
1824
|
+
children: row.cssVar
|
|
1825
|
+
})
|
|
1136
1826
|
]
|
|
1137
|
-
})
|
|
1138
|
-
|
|
1139
|
-
}
|
|
1140
|
-
function AliasedByRow({ node, depth }) {
|
|
1141
|
-
return /* @__PURE__ */ jsxs("li", { children: [/* @__PURE__ */ jsx("div", {
|
|
1142
|
-
className: "sb-token-detail__aliased-by-row",
|
|
1143
|
-
style: { paddingLeft: depth * 16 },
|
|
1144
|
-
children: /* @__PURE__ */ jsx("span", {
|
|
1145
|
-
className: "sb-token-detail__chain-node",
|
|
1146
|
-
children: node.path
|
|
1147
|
-
})
|
|
1148
|
-
}), node.children.length > 0 && /* @__PURE__ */ jsx("ul", {
|
|
1149
|
-
className: "sb-token-detail__aliased-by-list",
|
|
1150
|
-
children: node.children.map((child) => /* @__PURE__ */ jsx(AliasedByRow, {
|
|
1151
|
-
node: child,
|
|
1152
|
-
depth: depth + 1
|
|
1153
|
-
}, child.path))
|
|
1154
|
-
})] });
|
|
1155
|
-
}
|
|
1156
|
-
function buildAliasedByTree(rootPath, resolved) {
|
|
1157
|
-
const direct = resolved[rootPath]?.aliasedBy;
|
|
1158
|
-
if (!direct || direct.length === 0) return [];
|
|
1159
|
-
const visited = new Set([rootPath]);
|
|
1160
|
-
return sortPaths(direct).map((p) => walk(p, resolved, visited, 1));
|
|
1827
|
+
}, row.path))]
|
|
1828
|
+
});
|
|
1161
1829
|
}
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
const parents = resolved[path]?.aliasedBy;
|
|
1169
|
-
if (!parents || parents.length === 0) return {
|
|
1170
|
-
path,
|
|
1171
|
-
children: []
|
|
1172
|
-
};
|
|
1173
|
-
if (depth >= ALIASED_BY_DEPTH_CAP) return {
|
|
1174
|
-
path,
|
|
1175
|
-
children: [],
|
|
1176
|
-
truncated: true
|
|
1177
|
-
};
|
|
1178
|
-
return {
|
|
1179
|
-
path,
|
|
1180
|
-
children: sortPaths(parents).map((p) => walk(p, resolved, visited, depth + 1))
|
|
1181
|
-
};
|
|
1830
|
+
//#endregion
|
|
1831
|
+
//#region src/FontFamilySample.tsx
|
|
1832
|
+
function stackString(raw) {
|
|
1833
|
+
if (typeof raw === "string") return raw;
|
|
1834
|
+
if (Array.isArray(raw)) return raw.map(String).join(", ");
|
|
1835
|
+
return "";
|
|
1182
1836
|
}
|
|
1183
|
-
function
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
return
|
|
1837
|
+
function FontFamilySample({ filter, sample = "The quick brown fox jumps over the lazy dog.", caption, sortBy = "path", sortDir = "asc" }) {
|
|
1838
|
+
const project = useProject();
|
|
1839
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
1840
|
+
const rows = useMemo(() => {
|
|
1841
|
+
return sortTokens(Object.entries(resolved).filter(([path, token]) => {
|
|
1842
|
+
if (token.$type !== "fontFamily") return false;
|
|
1843
|
+
return globMatch(path, filter);
|
|
1844
|
+
}), {
|
|
1845
|
+
by: sortBy,
|
|
1846
|
+
dir: sortDir
|
|
1847
|
+
}).map(([path, token]) => ({
|
|
1848
|
+
path,
|
|
1849
|
+
cssVar: resolveCssVar(path, project),
|
|
1850
|
+
stack: stackString(token.$value)
|
|
1851
|
+
}));
|
|
1852
|
+
}, [
|
|
1853
|
+
resolved,
|
|
1854
|
+
filter,
|
|
1855
|
+
project,
|
|
1856
|
+
sortBy,
|
|
1857
|
+
sortDir
|
|
1858
|
+
]);
|
|
1859
|
+
const captionText = caption ?? `${rows.length} fontFamily token${rows.length === 1 ? "" : "s"}${filter && filter !== "fontFamily" ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
1860
|
+
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
1861
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
1862
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1863
|
+
className: "sb-block__empty",
|
|
1864
|
+
children: "No fontFamily tokens match this filter."
|
|
1865
|
+
})
|
|
1866
|
+
});
|
|
1867
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1868
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
1869
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1870
|
+
className: "sb-block__caption",
|
|
1871
|
+
children: captionText
|
|
1872
|
+
}), rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
1873
|
+
className: "sb-font-family-sample__row",
|
|
1874
|
+
children: [
|
|
1875
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1876
|
+
className: "sb-font-family-sample__meta",
|
|
1877
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1878
|
+
className: "sb-font-family-sample__path",
|
|
1879
|
+
children: row.path
|
|
1880
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1881
|
+
className: "sb-font-family-sample__stack",
|
|
1882
|
+
children: row.stack
|
|
1883
|
+
})]
|
|
1884
|
+
}),
|
|
1885
|
+
/* @__PURE__ */ jsx("div", {
|
|
1886
|
+
className: "sb-font-family-sample__sample",
|
|
1887
|
+
style: { fontFamily: row.cssVar },
|
|
1888
|
+
children: sample
|
|
1889
|
+
}),
|
|
1890
|
+
/* @__PURE__ */ jsx("span", {
|
|
1891
|
+
className: "sb-font-family-sample__css-var",
|
|
1892
|
+
children: row.cssVar
|
|
1893
|
+
})
|
|
1894
|
+
]
|
|
1895
|
+
}, row.path))]
|
|
1188
1896
|
});
|
|
1189
1897
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1898
|
+
//#endregion
|
|
1899
|
+
//#region src/FontWeightScale.tsx
|
|
1900
|
+
function toWeight(raw) {
|
|
1901
|
+
if (typeof raw === "number") return raw;
|
|
1902
|
+
if (typeof raw === "string") {
|
|
1903
|
+
const n = Number.parseInt(raw, 10);
|
|
1904
|
+
return Number.isFinite(n) ? n : NaN;
|
|
1194
1905
|
}
|
|
1195
|
-
return
|
|
1906
|
+
return NaN;
|
|
1196
1907
|
}
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
const
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1908
|
+
function FontWeightScale({ filter, sample = "Aa", caption, sortBy = "value", sortDir = "asc" }) {
|
|
1909
|
+
const project = useProject();
|
|
1910
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
1911
|
+
const rows = useMemo(() => {
|
|
1912
|
+
return sortTokens(Object.entries(resolved).filter(([path, token]) => {
|
|
1913
|
+
if (token.$type !== "fontWeight") return false;
|
|
1914
|
+
return globMatch(path, filter);
|
|
1915
|
+
}), {
|
|
1916
|
+
by: sortBy,
|
|
1917
|
+
dir: sortDir
|
|
1918
|
+
}).map(([path, token]) => ({
|
|
1919
|
+
path,
|
|
1920
|
+
cssVar: resolveCssVar(path, project),
|
|
1921
|
+
display: token.$value == null ? "" : String(token.$value),
|
|
1922
|
+
weight: toWeight(token.$value)
|
|
1923
|
+
}));
|
|
1211
1924
|
}, [
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
className: "sb-
|
|
1223
|
-
children: "
|
|
1224
|
-
})
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
isColor && /* @__PURE__ */ jsx("span", {
|
|
1234
|
-
className: "sb-token-detail__swatch",
|
|
1235
|
-
style: { background: cssVar },
|
|
1236
|
-
"aria-hidden": true
|
|
1237
|
-
}),
|
|
1238
|
-
value,
|
|
1239
|
-
/* @__PURE__ */ jsxs("span", {
|
|
1240
|
-
style: {
|
|
1241
|
-
opacity: .6,
|
|
1242
|
-
marginLeft: 8
|
|
1243
|
-
},
|
|
1244
|
-
children: [
|
|
1245
|
-
"same across all ",
|
|
1246
|
-
themes.length,
|
|
1247
|
-
" tuples"
|
|
1248
|
-
]
|
|
1249
|
-
})
|
|
1250
|
-
]
|
|
1251
|
-
})
|
|
1252
|
-
}) })
|
|
1253
|
-
})] });
|
|
1254
|
-
}
|
|
1255
|
-
if (variance.kind === "one-axis") {
|
|
1256
|
-
const axisName = variance.varyingAxes[0];
|
|
1257
|
-
if (!axisName) return /* @__PURE__ */ jsx(Fragment, {});
|
|
1258
|
-
const axis = axes.find((a) => a.name === axisName);
|
|
1259
|
-
if (!axis) return /* @__PURE__ */ jsx(Fragment, {});
|
|
1260
|
-
const contextValues = axis.contexts.map((ctx) => {
|
|
1261
|
-
const target = {
|
|
1262
|
-
...activeAxes,
|
|
1263
|
-
[axisName]: ctx
|
|
1264
|
-
};
|
|
1265
|
-
const name = themes.find((t) => {
|
|
1266
|
-
const input = t.input;
|
|
1267
|
-
return Object.keys(input).every((k) => input[k] === target[k]);
|
|
1268
|
-
})?.name ?? "";
|
|
1269
|
-
return {
|
|
1270
|
-
ctx,
|
|
1271
|
-
themeName: name,
|
|
1272
|
-
value: name ? formatFn(themesResolved[name]?.[path]) : "—"
|
|
1273
|
-
};
|
|
1274
|
-
});
|
|
1275
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs("div", {
|
|
1276
|
-
className: "sb-token-detail__section-header",
|
|
1277
|
-
children: ["Varies with ", axisName]
|
|
1278
|
-
}), /* @__PURE__ */ jsx("table", {
|
|
1279
|
-
className: "sb-token-detail__theme-table",
|
|
1280
|
-
"data-testid": "token-detail-values",
|
|
1281
|
-
children: /* @__PURE__ */ jsx("tbody", { children: contextValues.map((row) => /* @__PURE__ */ jsxs("tr", {
|
|
1282
|
-
className: "sb-token-detail__theme-row",
|
|
1283
|
-
"data-axis": axisName,
|
|
1284
|
-
"data-context": row.ctx,
|
|
1285
|
-
children: [/* @__PURE__ */ jsx("td", {
|
|
1286
|
-
className: "sb-token-detail__theme-cell",
|
|
1287
|
-
style: { width: "30%" },
|
|
1288
|
-
children: row.ctx
|
|
1289
|
-
}), /* @__PURE__ */ jsxs("td", {
|
|
1290
|
-
className: "sb-token-detail__theme-cell",
|
|
1291
|
-
children: [isColor && row.themeName && /* @__PURE__ */ jsx("span", {
|
|
1292
|
-
className: "sb-token-detail__swatch",
|
|
1293
|
-
style: { background: cssVar },
|
|
1294
|
-
[dataAttr(cssVarPrefix, "theme")]: row.themeName,
|
|
1295
|
-
"aria-hidden": true
|
|
1296
|
-
}), row.value]
|
|
1297
|
-
})]
|
|
1298
|
-
}, row.ctx)) })
|
|
1299
|
-
})] });
|
|
1300
|
-
}
|
|
1301
|
-
const [rowAxis, colAxis, ...extra] = variance.varyingAxes.map((name) => axes.find((a) => a.name === name)).filter((a) => Boolean(a)).toSorted((a, b) => b.contexts.length - a.contexts.length);
|
|
1302
|
-
if (!rowAxis || !colAxis) return /* @__PURE__ */ jsx(Fragment, {});
|
|
1303
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1304
|
-
/* @__PURE__ */ jsxs("div", {
|
|
1305
|
-
className: "sb-token-detail__section-header",
|
|
1306
|
-
children: ["Varies with ", variance.varyingAxes.join(" × ")]
|
|
1307
|
-
}),
|
|
1308
|
-
/* @__PURE__ */ jsxs("table", {
|
|
1309
|
-
className: "sb-token-detail__theme-table",
|
|
1310
|
-
"data-testid": "token-detail-values",
|
|
1311
|
-
children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", {
|
|
1312
|
-
className: "sb-token-detail__theme-row",
|
|
1313
|
-
children: [/* @__PURE__ */ jsxs("th", {
|
|
1314
|
-
className: "sb-token-detail__theme-cell",
|
|
1315
|
-
style: {
|
|
1316
|
-
textAlign: "left",
|
|
1317
|
-
opacity: .7
|
|
1318
|
-
},
|
|
1319
|
-
children: [
|
|
1320
|
-
rowAxis.name,
|
|
1321
|
-
" \\ ",
|
|
1322
|
-
colAxis.name
|
|
1323
|
-
]
|
|
1324
|
-
}), colAxis.contexts.map((col) => /* @__PURE__ */ jsx("th", {
|
|
1325
|
-
className: "sb-token-detail__theme-cell",
|
|
1326
|
-
style: {
|
|
1327
|
-
textAlign: "left",
|
|
1328
|
-
opacity: .7
|
|
1329
|
-
},
|
|
1330
|
-
children: col
|
|
1331
|
-
}, col))]
|
|
1332
|
-
}) }), /* @__PURE__ */ jsx("tbody", { children: rowAxis.contexts.map((row) => /* @__PURE__ */ jsxs("tr", {
|
|
1333
|
-
className: "sb-token-detail__theme-row",
|
|
1334
|
-
children: [/* @__PURE__ */ jsx("td", {
|
|
1335
|
-
className: "sb-token-detail__theme-cell",
|
|
1336
|
-
children: row
|
|
1337
|
-
}), colAxis.contexts.map((col) => {
|
|
1338
|
-
const name = tupleName(themes, {
|
|
1339
|
-
...activeAxes,
|
|
1340
|
-
[rowAxis.name]: row,
|
|
1341
|
-
[colAxis.name]: col
|
|
1342
|
-
});
|
|
1343
|
-
const value = name ? formatFn(themesResolved[name]?.[path]) : "—";
|
|
1344
|
-
return /* @__PURE__ */ jsxs("td", {
|
|
1345
|
-
className: "sb-token-detail__theme-cell",
|
|
1346
|
-
"data-row": row,
|
|
1347
|
-
"data-col": col,
|
|
1348
|
-
children: [isColor && name && /* @__PURE__ */ jsx("span", {
|
|
1349
|
-
className: "sb-token-detail__swatch",
|
|
1350
|
-
style: { background: cssVar },
|
|
1351
|
-
[dataAttr(cssVarPrefix, "theme")]: name,
|
|
1352
|
-
"aria-hidden": true
|
|
1353
|
-
}), value]
|
|
1354
|
-
}, col);
|
|
1355
|
-
})]
|
|
1356
|
-
}, row)) })]
|
|
1357
|
-
}),
|
|
1358
|
-
extra.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
1359
|
-
className: "sb-token-detail__aliased-by-truncated",
|
|
1360
|
-
style: { marginTop: 6 },
|
|
1925
|
+
resolved,
|
|
1926
|
+
filter,
|
|
1927
|
+
project,
|
|
1928
|
+
sortBy,
|
|
1929
|
+
sortDir
|
|
1930
|
+
]);
|
|
1931
|
+
const captionText = caption ?? `${rows.length} fontWeight token${rows.length === 1 ? "" : "s"}${filter && filter !== "fontWeight" ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
1932
|
+
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
1933
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
1934
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
1935
|
+
className: "sb-block__empty",
|
|
1936
|
+
children: "No fontWeight tokens match this filter."
|
|
1937
|
+
})
|
|
1938
|
+
});
|
|
1939
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1940
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
1941
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
1942
|
+
className: "sb-block__caption",
|
|
1943
|
+
children: captionText
|
|
1944
|
+
}), rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
1945
|
+
className: "sb-font-weight-scale__row",
|
|
1361
1946
|
children: [
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1947
|
+
/* @__PURE__ */ jsxs("div", {
|
|
1948
|
+
className: "sb-font-weight-scale__meta",
|
|
1949
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1950
|
+
className: "sb-font-weight-scale__path",
|
|
1951
|
+
children: row.path
|
|
1952
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
1953
|
+
className: "sb-font-weight-scale__value",
|
|
1954
|
+
children: row.display
|
|
1955
|
+
})]
|
|
1956
|
+
}),
|
|
1957
|
+
/* @__PURE__ */ jsx("div", {
|
|
1958
|
+
className: "sb-font-weight-scale__sample",
|
|
1959
|
+
style: { fontWeight: row.cssVar },
|
|
1960
|
+
children: sample
|
|
1961
|
+
}),
|
|
1962
|
+
/* @__PURE__ */ jsx("span", {
|
|
1963
|
+
className: "sb-font-weight-scale__css-var",
|
|
1964
|
+
children: row.cssVar
|
|
1965
|
+
})
|
|
1365
1966
|
]
|
|
1366
|
-
})
|
|
1367
|
-
|
|
1967
|
+
}, row.path))]
|
|
1968
|
+
});
|
|
1368
1969
|
}
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1970
|
+
//#endregion
|
|
1971
|
+
//#region src/GradientPalette.tsx
|
|
1972
|
+
function asStops(raw) {
|
|
1973
|
+
if (!Array.isArray(raw)) return [];
|
|
1974
|
+
return raw;
|
|
1372
1975
|
}
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1976
|
+
const pct = (n) => `${(n * 100).toFixed(3)}%`;
|
|
1977
|
+
function stopCssColor(stop) {
|
|
1978
|
+
const color = stop.color;
|
|
1979
|
+
if (!color || !Array.isArray(color.components) || color.components.length < 3) return "transparent";
|
|
1980
|
+
const [r, g, b] = color.components;
|
|
1981
|
+
if (r === void 0 || g === void 0 || b === void 0) return "transparent";
|
|
1982
|
+
const alpha = color.alpha ?? 1;
|
|
1983
|
+
return alpha === 1 ? `rgb(${pct(r)} ${pct(g)} ${pct(b)})` : `rgb(${pct(r)} ${pct(g)} ${pct(b)} / ${alpha})`;
|
|
1378
1984
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1985
|
+
function stopKey(path, stop, fallback) {
|
|
1986
|
+
return `${path}|${stop.position ?? fallback}|${stopCssColor(stop)}`;
|
|
1987
|
+
}
|
|
1988
|
+
function GradientPalette({ filter, caption, sortBy = "path", sortDir = "asc" }) {
|
|
1989
|
+
const project = useProject();
|
|
1990
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
1383
1991
|
const colorFormat = useColorFormat();
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1992
|
+
const rows = useMemo(() => {
|
|
1993
|
+
return sortTokens(Object.entries(resolved).filter(([path, token]) => {
|
|
1994
|
+
if (token.$type !== "gradient") return false;
|
|
1995
|
+
return globMatch(path, filter);
|
|
1996
|
+
}), {
|
|
1997
|
+
by: sortBy,
|
|
1998
|
+
dir: sortDir
|
|
1999
|
+
}).map(([path, token]) => ({
|
|
2000
|
+
path,
|
|
2001
|
+
cssVar: resolveCssVar(path, project),
|
|
2002
|
+
stops: asStops(token.$value)
|
|
2003
|
+
}));
|
|
2004
|
+
}, [
|
|
1389
2005
|
resolved,
|
|
1390
|
-
|
|
2006
|
+
filter,
|
|
2007
|
+
project,
|
|
2008
|
+
sortBy,
|
|
2009
|
+
sortDir
|
|
2010
|
+
]);
|
|
2011
|
+
const captionText = caption ?? `${rows.length} gradient${rows.length === 1 ? "" : "s"}${filter ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
2012
|
+
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
2013
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2014
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
2015
|
+
className: "sb-block__empty",
|
|
2016
|
+
children: "No gradient tokens match this filter."
|
|
2017
|
+
})
|
|
1391
2018
|
});
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
"width",
|
|
1438
|
-
formatDimensionValue(v["width"]),
|
|
1439
|
-
aliasFor("width")
|
|
1440
|
-
],
|
|
1441
|
-
[
|
|
1442
|
-
"style",
|
|
1443
|
-
formatPrimitive(v["style"]),
|
|
1444
|
-
aliasFor("style")
|
|
1445
|
-
]
|
|
1446
|
-
]);
|
|
1447
|
-
}
|
|
1448
|
-
if (type === "transition") {
|
|
1449
|
-
const v = rawValue;
|
|
1450
|
-
return renderKeyValueList([
|
|
1451
|
-
[
|
|
1452
|
-
"duration",
|
|
1453
|
-
formatDimensionValue(v["duration"]),
|
|
1454
|
-
aliasFor("duration")
|
|
1455
|
-
],
|
|
1456
|
-
[
|
|
1457
|
-
"timingFunction",
|
|
1458
|
-
formatPrimitive(v["timingFunction"]),
|
|
1459
|
-
aliasFor("timingFunction")
|
|
1460
|
-
],
|
|
1461
|
-
[
|
|
1462
|
-
"delay",
|
|
1463
|
-
formatDimensionValue(v["delay"]),
|
|
1464
|
-
aliasFor("delay")
|
|
2019
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2020
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2021
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2022
|
+
className: "sb-block__caption",
|
|
2023
|
+
children: captionText
|
|
2024
|
+
}), rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
2025
|
+
className: "sb-gradient-palette__row",
|
|
2026
|
+
children: [
|
|
2027
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2028
|
+
className: "sb-gradient-palette__meta",
|
|
2029
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2030
|
+
className: "sb-gradient-palette__path",
|
|
2031
|
+
children: row.path
|
|
2032
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
2033
|
+
className: "sb-gradient-palette__css-var",
|
|
2034
|
+
children: row.cssVar
|
|
2035
|
+
})]
|
|
2036
|
+
}),
|
|
2037
|
+
/* @__PURE__ */ jsx("div", {
|
|
2038
|
+
className: "sb-gradient-palette__sample",
|
|
2039
|
+
style: { background: `linear-gradient(to right, ${row.cssVar})` },
|
|
2040
|
+
"aria-hidden": true
|
|
2041
|
+
}),
|
|
2042
|
+
/* @__PURE__ */ jsx("div", {
|
|
2043
|
+
className: "sb-gradient-palette__stops",
|
|
2044
|
+
children: row.stops.map((stop, i) => /* @__PURE__ */ jsxs("div", {
|
|
2045
|
+
className: "sb-gradient-palette__stop-row",
|
|
2046
|
+
children: [
|
|
2047
|
+
/* @__PURE__ */ jsx("span", {
|
|
2048
|
+
className: "sb-gradient-palette__stop-swatch",
|
|
2049
|
+
style: { background: stopCssColor(stop) },
|
|
2050
|
+
"aria-hidden": true
|
|
2051
|
+
}),
|
|
2052
|
+
/* @__PURE__ */ jsx("span", { children: formatColor(stop.color, colorFormat).value }),
|
|
2053
|
+
/* @__PURE__ */ jsxs("span", {
|
|
2054
|
+
className: "sb-gradient-palette__stop-position",
|
|
2055
|
+
children: [
|
|
2056
|
+
"@ ",
|
|
2057
|
+
((stop.position ?? 0) * 100).toFixed(0),
|
|
2058
|
+
"%"
|
|
2059
|
+
]
|
|
2060
|
+
})
|
|
2061
|
+
]
|
|
2062
|
+
}, stopKey(row.path, stop, i)))
|
|
2063
|
+
})
|
|
1465
2064
|
]
|
|
1466
|
-
]
|
|
1467
|
-
}
|
|
1468
|
-
if (type === "shadow") {
|
|
1469
|
-
const layers = Array.isArray(rawValue) ? rawValue : [rawValue];
|
|
1470
|
-
const multi = layers.length > 1;
|
|
1471
|
-
const layerAliasFor = (i, key) => subValueChain(arrayAliases?.[i]?.[key], resolved);
|
|
1472
|
-
return /* @__PURE__ */ jsx("div", {
|
|
1473
|
-
className: "sb-token-detail__breakdown-section",
|
|
1474
|
-
children: layers.map((layer, i) => {
|
|
1475
|
-
const v = layer;
|
|
1476
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
1477
|
-
style: { display: "contents" },
|
|
1478
|
-
children: [
|
|
1479
|
-
multi && /* @__PURE__ */ jsxs("div", {
|
|
1480
|
-
className: "sb-token-detail__breakdown-layer-header",
|
|
1481
|
-
children: ["Layer ", i + 1]
|
|
1482
|
-
}),
|
|
1483
|
-
/* @__PURE__ */ jsx(KeyValueRow, {
|
|
1484
|
-
label: "color",
|
|
1485
|
-
value: formatColorSubValue(v["color"], colorFormat),
|
|
1486
|
-
alias: layerAliasFor(i, "color")
|
|
1487
|
-
}),
|
|
1488
|
-
/* @__PURE__ */ jsx(KeyValueRow, {
|
|
1489
|
-
label: "offsetX",
|
|
1490
|
-
value: formatDimensionValue(v["offsetX"]),
|
|
1491
|
-
alias: layerAliasFor(i, "offsetX")
|
|
1492
|
-
}),
|
|
1493
|
-
/* @__PURE__ */ jsx(KeyValueRow, {
|
|
1494
|
-
label: "offsetY",
|
|
1495
|
-
value: formatDimensionValue(v["offsetY"]),
|
|
1496
|
-
alias: layerAliasFor(i, "offsetY")
|
|
1497
|
-
}),
|
|
1498
|
-
/* @__PURE__ */ jsx(KeyValueRow, {
|
|
1499
|
-
label: "blur",
|
|
1500
|
-
value: formatDimensionValue(v["blur"]),
|
|
1501
|
-
alias: layerAliasFor(i, "blur")
|
|
1502
|
-
}),
|
|
1503
|
-
/* @__PURE__ */ jsx(KeyValueRow, {
|
|
1504
|
-
label: "spread",
|
|
1505
|
-
value: formatDimensionValue(v["spread"]),
|
|
1506
|
-
alias: layerAliasFor(i, "spread")
|
|
1507
|
-
}),
|
|
1508
|
-
"inset" in v && /* @__PURE__ */ jsx(KeyValueRow, {
|
|
1509
|
-
label: "inset",
|
|
1510
|
-
value: formatPrimitive(v["inset"]),
|
|
1511
|
-
alias: void 0
|
|
1512
|
-
})
|
|
1513
|
-
]
|
|
1514
|
-
}, shadowLayerKey(v, i));
|
|
1515
|
-
})
|
|
1516
|
-
});
|
|
1517
|
-
}
|
|
1518
|
-
if (type === "gradient") {
|
|
1519
|
-
const stops = Array.isArray(rawValue) ? rawValue : [];
|
|
1520
|
-
if (stops.length === 0) return null;
|
|
1521
|
-
const stopAliasFor = (i) => subValueChain(arrayAliases?.[i]?.["color"], resolved);
|
|
1522
|
-
return /* @__PURE__ */ jsx("div", {
|
|
1523
|
-
className: "sb-token-detail__breakdown-section",
|
|
1524
|
-
children: stops.map((stop, i) => {
|
|
1525
|
-
const v = stop;
|
|
1526
|
-
return /* @__PURE__ */ jsx(KeyValueRow, {
|
|
1527
|
-
label: `${((typeof v["position"] === "number" ? v["position"] : 0) * 100).toFixed(0)}%`,
|
|
1528
|
-
value: formatColorSubValue(v["color"], colorFormat),
|
|
1529
|
-
alias: stopAliasFor(i)
|
|
1530
|
-
}, gradientStopKey(v, i));
|
|
1531
|
-
})
|
|
1532
|
-
});
|
|
1533
|
-
}
|
|
1534
|
-
return null;
|
|
1535
|
-
}
|
|
1536
|
-
function renderKeyValueList(rows) {
|
|
1537
|
-
return /* @__PURE__ */ jsx("div", {
|
|
1538
|
-
className: "sb-token-detail__breakdown-section",
|
|
1539
|
-
children: rows.filter(([, v, alias]) => v !== null || alias && alias.length > 0).map(([k, v, alias]) => /* @__PURE__ */ jsx(KeyValueRow, {
|
|
1540
|
-
label: k,
|
|
1541
|
-
value: v ?? "",
|
|
1542
|
-
alias
|
|
1543
|
-
}, k))
|
|
2065
|
+
}, row.path))]
|
|
1544
2066
|
});
|
|
1545
2067
|
}
|
|
1546
|
-
function KeyValueRow({ label, value, alias }) {
|
|
1547
|
-
const hasAlias = alias && alias.length > 0;
|
|
1548
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
1549
|
-
className: "sb-token-detail__breakdown-key",
|
|
1550
|
-
children: label
|
|
1551
|
-
}), /* @__PURE__ */ jsxs("span", {
|
|
1552
|
-
className: "sb-token-detail__breakdown-value",
|
|
1553
|
-
children: [/* @__PURE__ */ jsx("span", { children: value ?? "—" }), hasAlias && /* @__PURE__ */ jsx("span", {
|
|
1554
|
-
className: "sb-token-detail__breakdown-alias",
|
|
1555
|
-
"data-testid": "breakdown-alias",
|
|
1556
|
-
children: alias.map((p, i) => /* @__PURE__ */ jsxs("span", {
|
|
1557
|
-
className: "sb-token-detail__breakdown-alias-step",
|
|
1558
|
-
children: [i > 0 && /* @__PURE__ */ jsx("span", {
|
|
1559
|
-
className: "sb-token-detail__arrow",
|
|
1560
|
-
children: "→"
|
|
1561
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
1562
|
-
className: "sb-token-detail__chain-node",
|
|
1563
|
-
children: p
|
|
1564
|
-
})]
|
|
1565
|
-
}, p))
|
|
1566
|
-
})]
|
|
1567
|
-
})] });
|
|
1568
|
-
}
|
|
1569
|
-
function formatPrimitive(v) {
|
|
1570
|
-
if (v == null) return null;
|
|
1571
|
-
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") return String(v);
|
|
1572
|
-
return JSON.stringify(v);
|
|
1573
|
-
}
|
|
1574
|
-
function formatFontFamily(v) {
|
|
1575
|
-
if (v == null) return null;
|
|
1576
|
-
if (typeof v === "string") return v;
|
|
1577
|
-
if (Array.isArray(v)) return v.map(String).join(", ");
|
|
1578
|
-
return JSON.stringify(v);
|
|
1579
|
-
}
|
|
1580
|
-
function formatDimensionValue(v) {
|
|
1581
|
-
if (v == null) return null;
|
|
1582
|
-
if (typeof v === "string" || typeof v === "number") return String(v);
|
|
1583
|
-
if (typeof v === "object") {
|
|
1584
|
-
const d = v;
|
|
1585
|
-
if (typeof d.value === "number" && typeof d.unit === "string") return `${d.value}${d.unit}`;
|
|
1586
|
-
}
|
|
1587
|
-
return JSON.stringify(v);
|
|
1588
|
-
}
|
|
1589
|
-
/**
|
|
1590
|
-
* Route sub-value colors through `formatColor` so they honor the active
|
|
1591
|
-
* color-format dropdown, just like the standalone `<ColorPalette />` and
|
|
1592
|
-
* `<TokenDetail />` top-line do. Returns `null` for a missing field so
|
|
1593
|
-
* the key/value row drops out entirely.
|
|
1594
|
-
*/
|
|
1595
|
-
function formatColorSubValue(v, format) {
|
|
1596
|
-
if (v == null) return null;
|
|
1597
|
-
return formatColor(v, format).value;
|
|
1598
|
-
}
|
|
1599
|
-
function pickObjectAliases(v) {
|
|
1600
|
-
if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
|
|
1601
|
-
return v;
|
|
1602
|
-
}
|
|
1603
|
-
function pickArrayAliases(v) {
|
|
1604
|
-
if (!Array.isArray(v)) return void 0;
|
|
1605
|
-
return v;
|
|
1606
|
-
}
|
|
1607
|
-
/**
|
|
1608
|
-
* Walk the alias chain starting from an immediate sub-value alias target.
|
|
1609
|
-
* `aliasTarget` is the path the sub-value directly references; the target
|
|
1610
|
-
* token's own `aliasChain` continues the walk to the primitive.
|
|
1611
|
-
*/
|
|
1612
|
-
function subValueChain(aliasTarget, resolved) {
|
|
1613
|
-
if (!aliasTarget) return void 0;
|
|
1614
|
-
const tail = (resolved?.[aliasTarget])?.aliasChain;
|
|
1615
|
-
return tail && tail.length > 0 ? [aliasTarget, ...tail] : [aliasTarget];
|
|
1616
|
-
}
|
|
1617
|
-
function shadowLayerKey(layer, fallback) {
|
|
1618
|
-
return `shadow|${[
|
|
1619
|
-
layer["color"],
|
|
1620
|
-
layer["offsetX"],
|
|
1621
|
-
layer["offsetY"],
|
|
1622
|
-
layer["blur"],
|
|
1623
|
-
layer["spread"],
|
|
1624
|
-
layer["inset"]
|
|
1625
|
-
].map((p) => p === void 0 ? "" : JSON.stringify(p)).join("|")}|${fallback}`;
|
|
1626
|
-
}
|
|
1627
|
-
function gradientStopKey(stop, fallback) {
|
|
1628
|
-
return `stop|${stop["position"] ?? fallback}|${JSON.stringify(stop["color"])}`;
|
|
1629
|
-
}
|
|
1630
2068
|
//#endregion
|
|
1631
2069
|
//#region src/internal/prefers-reduced-motion.ts
|
|
1632
2070
|
/**
|
|
@@ -1646,1619 +2084,1466 @@ function usePrefersReducedMotion() {
|
|
|
1646
2084
|
return reduced;
|
|
1647
2085
|
}
|
|
1648
2086
|
//#endregion
|
|
1649
|
-
//#region src/
|
|
1650
|
-
const
|
|
1651
|
-
const
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
"aria-hidden": true
|
|
1689
|
-
});
|
|
1690
|
-
if (type === "border") return /* @__PURE__ */ jsx("div", {
|
|
1691
|
-
className: "sb-token-detail__border-sample",
|
|
1692
|
-
style: { border: cssVar },
|
|
1693
|
-
"aria-hidden": true
|
|
1694
|
-
});
|
|
1695
|
-
if (type === "transition") return /* @__PURE__ */ jsx(TransitionSample, { transition: cssVar });
|
|
1696
|
-
if (type === "dimension") return /* @__PURE__ */ jsx("div", {
|
|
1697
|
-
className: "sb-token-detail__dimension-track",
|
|
1698
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
1699
|
-
className: "sb-token-detail__dimension-bar",
|
|
1700
|
-
style: { width: cssVar },
|
|
1701
|
-
"aria-hidden": true
|
|
1702
|
-
})
|
|
1703
|
-
});
|
|
1704
|
-
if (type === "duration") return /* @__PURE__ */ jsx(TransitionSample, { transition: `left ${cssVar} ease` });
|
|
1705
|
-
if (type === "fontFamily") return /* @__PURE__ */ jsx("div", {
|
|
1706
|
-
className: "sb-token-detail__font-family-sample",
|
|
1707
|
-
style: { fontFamily: cssVar },
|
|
1708
|
-
children: PANGRAM
|
|
1709
|
-
});
|
|
1710
|
-
if (type === "fontWeight") return /* @__PURE__ */ jsx("div", {
|
|
1711
|
-
className: "sb-token-detail__font-weight-sample",
|
|
1712
|
-
style: { fontWeight: cssVar },
|
|
1713
|
-
children: "Aa"
|
|
1714
|
-
});
|
|
1715
|
-
if (type === "cubicBezier") return /* @__PURE__ */ jsx(TransitionSample, { transition: `left 800ms ${cssVar}` });
|
|
1716
|
-
if (type === "gradient") return /* @__PURE__ */ jsx("div", {
|
|
1717
|
-
className: "sb-token-detail__gradient-sample",
|
|
1718
|
-
style: { background: `linear-gradient(to right, ${cssVar})` },
|
|
1719
|
-
"aria-hidden": true
|
|
1720
|
-
});
|
|
1721
|
-
if (type === "strokeStyle") return /* @__PURE__ */ jsx(StrokeStylePreview, { value: rawValue });
|
|
1722
|
-
if (type === "color") return /* @__PURE__ */ jsxs("div", {
|
|
1723
|
-
className: "sb-token-detail__color-swatch-row",
|
|
1724
|
-
"aria-hidden": true,
|
|
1725
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
1726
|
-
className: "sb-token-detail__color-swatch-light",
|
|
1727
|
-
style: { background: cssVar }
|
|
1728
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
1729
|
-
className: "sb-token-detail__color-swatch-dark",
|
|
1730
|
-
style: { background: cssVar }
|
|
1731
|
-
})]
|
|
1732
|
-
});
|
|
2087
|
+
//#region src/motion-preview/MotionSample.tsx
|
|
2088
|
+
const DEFAULT_DURATION_MS = 300;
|
|
2089
|
+
const DEFAULT_EASING = "cubic-bezier(0.2, 0, 0, 1)";
|
|
2090
|
+
const styles = {
|
|
2091
|
+
track: {
|
|
2092
|
+
position: "relative",
|
|
2093
|
+
height: 36,
|
|
2094
|
+
background: SURFACE_MUTED,
|
|
2095
|
+
borderRadius: 18,
|
|
2096
|
+
overflow: "hidden"
|
|
2097
|
+
},
|
|
2098
|
+
ball: {
|
|
2099
|
+
position: "absolute",
|
|
2100
|
+
top: "50%",
|
|
2101
|
+
width: 28,
|
|
2102
|
+
height: 28,
|
|
2103
|
+
marginTop: -14,
|
|
2104
|
+
borderRadius: "50%",
|
|
2105
|
+
background: "var(--swatchbook-accent-bg, #3b82f6)"
|
|
2106
|
+
},
|
|
2107
|
+
reducedMotion: {
|
|
2108
|
+
fontSize: 11,
|
|
2109
|
+
color: TEXT_MUTED,
|
|
2110
|
+
fontStyle: "italic"
|
|
2111
|
+
}
|
|
2112
|
+
};
|
|
2113
|
+
function extractDurationMs(raw) {
|
|
2114
|
+
if (raw == null) return NaN;
|
|
2115
|
+
if (typeof raw === "object") {
|
|
2116
|
+
const v = raw;
|
|
2117
|
+
if (typeof v.value === "number" && typeof v.unit === "string") {
|
|
2118
|
+
if (v.unit === "ms") return v.value;
|
|
2119
|
+
if (v.unit === "s") return v.value * 1e3;
|
|
2120
|
+
}
|
|
2121
|
+
}
|
|
2122
|
+
return NaN;
|
|
2123
|
+
}
|
|
2124
|
+
function extractCubicBezier(raw) {
|
|
2125
|
+
if (Array.isArray(raw) && raw.length === 4 && raw.every((n) => typeof n === "number")) return `cubic-bezier(${raw.map((n) => Number(n).toFixed(3)).join(", ")})`;
|
|
1733
2126
|
return null;
|
|
1734
2127
|
}
|
|
1735
|
-
function
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
className: "sb-token-detail__stroke-style-fallback",
|
|
1746
|
-
children: "Object-form strokeStyle with no resolvable dashArray."
|
|
1747
|
-
});
|
|
1748
|
-
const cap = typeof v.lineCap === "string" ? v.lineCap : "butt";
|
|
1749
|
-
return /* @__PURE__ */ jsx("svg", {
|
|
1750
|
-
className: "sb-token-detail__stroke-style-svg",
|
|
1751
|
-
viewBox: "0 0 220 24",
|
|
1752
|
-
preserveAspectRatio: "none",
|
|
1753
|
-
"aria-hidden": true,
|
|
1754
|
-
children: /* @__PURE__ */ jsx("line", {
|
|
1755
|
-
x1: "4",
|
|
1756
|
-
y1: "12",
|
|
1757
|
-
x2: "216",
|
|
1758
|
-
y2: "12",
|
|
1759
|
-
stroke: "currentColor",
|
|
1760
|
-
strokeWidth: "4",
|
|
1761
|
-
strokeDasharray: lengths.join(" "),
|
|
1762
|
-
strokeLinecap: cap
|
|
1763
|
-
})
|
|
1764
|
-
});
|
|
2128
|
+
function asDuration(raw, themeTokens, fallback) {
|
|
2129
|
+
const direct = extractDurationMs(raw);
|
|
2130
|
+
if (Number.isFinite(direct)) return direct;
|
|
2131
|
+
if (typeof raw === "string") {
|
|
2132
|
+
const match = raw.match(/^\{([^}]+)\}$/);
|
|
2133
|
+
if (match && match[1]) {
|
|
2134
|
+
const referenced = themeTokens[match[1]];
|
|
2135
|
+
const resolved = extractDurationMs(referenced?.$value);
|
|
2136
|
+
if (Number.isFinite(resolved)) return resolved;
|
|
2137
|
+
}
|
|
1765
2138
|
}
|
|
1766
|
-
return
|
|
1767
|
-
className: "sb-token-detail__stroke-style-fallback",
|
|
1768
|
-
children: "strokeStyle value could not be previewed."
|
|
1769
|
-
});
|
|
2139
|
+
return fallback;
|
|
1770
2140
|
}
|
|
1771
|
-
function
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
const e = entry;
|
|
1781
|
-
if (typeof e.value === "number") out.push(e.value);
|
|
2141
|
+
function asEasing(raw, themeTokens, fallback) {
|
|
2142
|
+
const direct = extractCubicBezier(raw);
|
|
2143
|
+
if (direct) return direct;
|
|
2144
|
+
if (typeof raw === "string") {
|
|
2145
|
+
const match = raw.match(/^\{([^}]+)\}$/);
|
|
2146
|
+
if (match && match[1]) {
|
|
2147
|
+
const referenced = themeTokens[match[1]];
|
|
2148
|
+
const resolved = extractCubicBezier(referenced?.$value);
|
|
2149
|
+
if (resolved) return resolved;
|
|
1782
2150
|
}
|
|
1783
2151
|
}
|
|
1784
|
-
return
|
|
2152
|
+
return fallback;
|
|
1785
2153
|
}
|
|
1786
|
-
function
|
|
1787
|
-
|
|
2154
|
+
function resolveMotionSpec(token, themeTokens) {
|
|
2155
|
+
if (!token) return null;
|
|
2156
|
+
const type = token.$type;
|
|
2157
|
+
if (type === "transition") {
|
|
2158
|
+
const v = token.$value ?? {};
|
|
2159
|
+
return {
|
|
2160
|
+
durationMs: asDuration(v.duration, themeTokens, DEFAULT_DURATION_MS),
|
|
2161
|
+
easing: asEasing(v.timingFunction, themeTokens, DEFAULT_EASING)
|
|
2162
|
+
};
|
|
2163
|
+
}
|
|
2164
|
+
if (type === "duration") {
|
|
2165
|
+
const durationMs = extractDurationMs(token.$value);
|
|
2166
|
+
if (!Number.isFinite(durationMs)) return null;
|
|
2167
|
+
return {
|
|
2168
|
+
durationMs,
|
|
2169
|
+
easing: DEFAULT_EASING
|
|
2170
|
+
};
|
|
2171
|
+
}
|
|
2172
|
+
if (type === "cubicBezier") {
|
|
2173
|
+
const easing = extractCubicBezier(token.$value);
|
|
2174
|
+
if (!easing) return null;
|
|
2175
|
+
return {
|
|
2176
|
+
durationMs: DEFAULT_DURATION_MS,
|
|
2177
|
+
easing
|
|
2178
|
+
};
|
|
2179
|
+
}
|
|
2180
|
+
return null;
|
|
2181
|
+
}
|
|
2182
|
+
function MotionSample({ path, speed = 1, runKey = 0 }) {
|
|
2183
|
+
const { resolved } = useProject();
|
|
2184
|
+
const reducedMotion = usePrefersReducedMotion();
|
|
2185
|
+
const spec = useMemo(() => resolveMotionSpec(resolved[path], resolved), [resolved, path]);
|
|
2186
|
+
const durationMs = spec?.durationMs ?? DEFAULT_DURATION_MS;
|
|
2187
|
+
const easing = spec?.easing ?? DEFAULT_EASING;
|
|
2188
|
+
const scaledDuration = Math.max(1, durationMs / speed);
|
|
1788
2189
|
const [phase, setPhase] = useState(0);
|
|
1789
2190
|
useEffect(() => {
|
|
1790
|
-
if (
|
|
2191
|
+
if (reducedMotion) return;
|
|
2192
|
+
setPhase(0);
|
|
1791
2193
|
const id = requestAnimationFrame(() => setPhase(1));
|
|
1792
2194
|
const loop = window.setInterval(() => {
|
|
1793
2195
|
setPhase((p) => p === 0 ? 1 : 0);
|
|
1794
|
-
},
|
|
2196
|
+
}, scaledDuration * 2);
|
|
1795
2197
|
return () => {
|
|
1796
2198
|
cancelAnimationFrame(id);
|
|
1797
2199
|
window.clearInterval(loop);
|
|
1798
2200
|
};
|
|
1799
|
-
}, [
|
|
1800
|
-
|
|
1801
|
-
|
|
2201
|
+
}, [
|
|
2202
|
+
scaledDuration,
|
|
2203
|
+
runKey,
|
|
2204
|
+
reducedMotion
|
|
2205
|
+
]);
|
|
2206
|
+
if (reducedMotion) return /* @__PURE__ */ jsx("div", {
|
|
2207
|
+
style: styles.reducedMotion,
|
|
1802
2208
|
children: "Animation suppressed by `prefers-reduced-motion: reduce`."
|
|
1803
2209
|
});
|
|
1804
2210
|
return /* @__PURE__ */ jsx("div", {
|
|
1805
|
-
|
|
2211
|
+
style: styles.track,
|
|
1806
2212
|
children: /* @__PURE__ */ jsx("div", {
|
|
1807
|
-
className: "sb-token-detail__motion-ball",
|
|
1808
2213
|
style: {
|
|
1809
|
-
|
|
1810
|
-
|
|
2214
|
+
...styles.ball,
|
|
2215
|
+
left: phase === 1 ? "calc(100% - 32px)" : "4px",
|
|
2216
|
+
transition: `left ${scaledDuration}ms ${easing}`
|
|
1811
2217
|
},
|
|
1812
2218
|
"aria-hidden": true
|
|
1813
2219
|
})
|
|
1814
2220
|
});
|
|
1815
2221
|
}
|
|
1816
2222
|
//#endregion
|
|
1817
|
-
//#region src/
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
}
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
}),
|
|
1831
|
-
/* @__PURE__ */ jsx(OutputRow, {
|
|
1832
|
-
label: "Path",
|
|
1833
|
-
value: path,
|
|
1834
|
-
testId: "consumer-output-path"
|
|
1835
|
-
}),
|
|
1836
|
-
/* @__PURE__ */ jsx(OutputRow, {
|
|
1837
|
-
label: "CSS",
|
|
1838
|
-
value: cssVar,
|
|
1839
|
-
testId: "consumer-output-css"
|
|
1840
|
-
})
|
|
1841
|
-
] });
|
|
2223
|
+
//#region src/MotionPreview.tsx
|
|
2224
|
+
const SPEEDS = [
|
|
2225
|
+
.25,
|
|
2226
|
+
.5,
|
|
2227
|
+
1,
|
|
2228
|
+
2
|
|
2229
|
+
];
|
|
2230
|
+
function formatSpec(row) {
|
|
2231
|
+
switch (row.kind) {
|
|
2232
|
+
case "transition": return `transition · ${Math.round(row.durationMs)}ms · ${row.easing}`;
|
|
2233
|
+
case "duration": return `duration · ${Math.round(row.durationMs)}ms`;
|
|
2234
|
+
case "cubicBezier": return `cubicBezier · ${row.easing}`;
|
|
2235
|
+
}
|
|
1842
2236
|
}
|
|
1843
|
-
function
|
|
2237
|
+
function MotionPreview({ filter, caption }) {
|
|
2238
|
+
const project = useProject();
|
|
2239
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
2240
|
+
const [speed, setSpeed] = useState(1);
|
|
2241
|
+
const [run, setRun] = useState(0);
|
|
2242
|
+
const reducedMotion = usePrefersReducedMotion();
|
|
2243
|
+
const rows = useMemo(() => {
|
|
2244
|
+
const collected = [];
|
|
2245
|
+
for (const [path, token] of Object.entries(resolved)) {
|
|
2246
|
+
if (filter && !globMatch(path, filter)) continue;
|
|
2247
|
+
if (!filter && ![
|
|
2248
|
+
"transition",
|
|
2249
|
+
"duration",
|
|
2250
|
+
"cubicBezier"
|
|
2251
|
+
].includes(token.$type ?? "")) continue;
|
|
2252
|
+
const kind = token.$type;
|
|
2253
|
+
if (!kind) continue;
|
|
2254
|
+
const spec = resolveMotionSpec(token, resolved);
|
|
2255
|
+
if (!spec) continue;
|
|
2256
|
+
collected.push({
|
|
2257
|
+
path,
|
|
2258
|
+
cssVar: resolveCssVar(path, project),
|
|
2259
|
+
durationMs: spec.durationMs,
|
|
2260
|
+
easing: spec.easing,
|
|
2261
|
+
kind
|
|
2262
|
+
});
|
|
2263
|
+
}
|
|
2264
|
+
collected.sort((a, b) => {
|
|
2265
|
+
if (a.kind !== b.kind) return a.kind.localeCompare(b.kind);
|
|
2266
|
+
return a.path.localeCompare(b.path, void 0, { numeric: true });
|
|
2267
|
+
});
|
|
2268
|
+
return collected;
|
|
2269
|
+
}, [
|
|
2270
|
+
resolved,
|
|
2271
|
+
filter,
|
|
2272
|
+
project
|
|
2273
|
+
]);
|
|
2274
|
+
const captionText = caption ?? `${rows.length} motion token${rows.length === 1 ? "" : "s"}${filter ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
2275
|
+
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
2276
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2277
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
2278
|
+
className: "sb-block__empty",
|
|
2279
|
+
children: "No motion tokens match this filter."
|
|
2280
|
+
})
|
|
2281
|
+
});
|
|
1844
2282
|
return /* @__PURE__ */ jsxs("div", {
|
|
1845
|
-
|
|
2283
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
1846
2284
|
children: [
|
|
1847
|
-
/* @__PURE__ */ jsx("
|
|
1848
|
-
className: "sb-
|
|
1849
|
-
children:
|
|
2285
|
+
/* @__PURE__ */ jsx("div", {
|
|
2286
|
+
className: "sb-block__caption",
|
|
2287
|
+
children: captionText
|
|
1850
2288
|
}),
|
|
1851
|
-
/* @__PURE__ */
|
|
1852
|
-
className: "sb-
|
|
1853
|
-
|
|
1854
|
-
|
|
2289
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2290
|
+
className: "sb-motion-preview__controls",
|
|
2291
|
+
children: [
|
|
2292
|
+
/* @__PURE__ */ jsx("span", {
|
|
2293
|
+
className: "sb-motion-preview__control-label",
|
|
2294
|
+
children: "Speed"
|
|
2295
|
+
}),
|
|
2296
|
+
SPEEDS.map((s) => /* @__PURE__ */ jsxs("button", {
|
|
2297
|
+
type: "button",
|
|
2298
|
+
className: cx("sb-motion-preview__speed-btn", { "sb-motion-preview__speed-btn--active": s === speed }),
|
|
2299
|
+
onClick: () => setSpeed(s),
|
|
2300
|
+
children: [s, "×"]
|
|
2301
|
+
}, s)),
|
|
2302
|
+
/* @__PURE__ */ jsx("button", {
|
|
2303
|
+
type: "button",
|
|
2304
|
+
className: "sb-motion-preview__replay-btn",
|
|
2305
|
+
onClick: () => setRun((n) => n + 1),
|
|
2306
|
+
disabled: reducedMotion,
|
|
2307
|
+
title: reducedMotion ? "Disabled by prefers-reduced-motion" : "Replay all",
|
|
2308
|
+
children: "↻ Replay"
|
|
2309
|
+
})
|
|
2310
|
+
]
|
|
1855
2311
|
}),
|
|
1856
|
-
/* @__PURE__ */
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
2312
|
+
rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
2313
|
+
className: "sb-motion-preview__row",
|
|
2314
|
+
children: [
|
|
2315
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2316
|
+
className: "sb-motion-preview__meta",
|
|
2317
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2318
|
+
className: "sb-motion-preview__path",
|
|
2319
|
+
children: row.path
|
|
2320
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
2321
|
+
className: "sb-motion-preview__specs",
|
|
2322
|
+
children: formatSpec(row)
|
|
2323
|
+
})]
|
|
2324
|
+
}),
|
|
2325
|
+
/* @__PURE__ */ jsx(MotionSample, {
|
|
2326
|
+
path: row.path,
|
|
2327
|
+
speed,
|
|
2328
|
+
runKey: run
|
|
2329
|
+
}),
|
|
2330
|
+
/* @__PURE__ */ jsx("span", {
|
|
2331
|
+
className: "sb-motion-preview__css-var",
|
|
2332
|
+
children: row.cssVar
|
|
2333
|
+
})
|
|
2334
|
+
]
|
|
2335
|
+
}, row.path))
|
|
1860
2336
|
]
|
|
1861
2337
|
});
|
|
1862
2338
|
}
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
2339
|
+
//#endregion
|
|
2340
|
+
//#region src/provider.tsx
|
|
2341
|
+
/**
|
|
2342
|
+
* Wraps a tree of blocks with the token data they need to render.
|
|
2343
|
+
*
|
|
2344
|
+
* The Storybook addon's preview decorator mounts this automatically, so
|
|
2345
|
+
* story/MDX authors typically never see it. Outside Storybook — unit
|
|
2346
|
+
* tests, custom React apps, non-Storybook doc sites — consumers construct
|
|
2347
|
+
* a {@link ProjectSnapshot} (often imported from a JSON file) and wrap
|
|
2348
|
+
* their blocks in this provider.
|
|
2349
|
+
*/
|
|
2350
|
+
function SwatchbookProvider({ value, children }) {
|
|
2351
|
+
return /* @__PURE__ */ jsx(SwatchbookContext.Provider, {
|
|
2352
|
+
value,
|
|
2353
|
+
children
|
|
1877
2354
|
});
|
|
1878
2355
|
}
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
}
|
|
2356
|
+
/**
|
|
2357
|
+
* Read the current {@link ProjectSnapshot}. Throws if called outside a
|
|
2358
|
+
* {@link SwatchbookProvider}; blocks that need to fall back to the
|
|
2359
|
+
* virtual module go through the internal `useProject()` hook instead.
|
|
2360
|
+
*/
|
|
2361
|
+
function useSwatchbookData() {
|
|
2362
|
+
const value = useOptionalSwatchbookData();
|
|
2363
|
+
if (!value) throw new Error("[swatchbook-blocks] useSwatchbookData() called outside <SwatchbookProvider>. Wrap your tree in <SwatchbookProvider value={snapshot}> or render inside a Storybook story.");
|
|
2364
|
+
return value;
|
|
1887
2365
|
}
|
|
1888
2366
|
//#endregion
|
|
1889
|
-
//#region src/
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
2367
|
+
//#region src/shadow-preview/ShadowSample.tsx
|
|
2368
|
+
const sampleStyle = {
|
|
2369
|
+
width: 120,
|
|
2370
|
+
height: 56,
|
|
2371
|
+
background: SURFACE_RAISED,
|
|
2372
|
+
border: BORDER_FAINT,
|
|
2373
|
+
borderRadius: 6
|
|
2374
|
+
};
|
|
2375
|
+
function ShadowSample({ path }) {
|
|
2376
|
+
const cssVar = resolveCssVar(path, useProject());
|
|
2377
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2378
|
+
style: {
|
|
2379
|
+
...sampleStyle,
|
|
2380
|
+
boxShadow: cssVar
|
|
2381
|
+
},
|
|
2382
|
+
"aria-hidden": true
|
|
1901
2383
|
});
|
|
1902
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1903
|
-
/* @__PURE__ */ jsx("h3", {
|
|
1904
|
-
className: "sb-token-detail__heading",
|
|
1905
|
-
children: heading ?? path
|
|
1906
|
-
}),
|
|
1907
|
-
/* @__PURE__ */ jsxs("div", {
|
|
1908
|
-
className: "sb-token-detail__subline",
|
|
1909
|
-
children: [token.$type && /* @__PURE__ */ jsx("span", {
|
|
1910
|
-
className: "sb-token-detail__type-pill",
|
|
1911
|
-
children: token.$type
|
|
1912
|
-
}), /* @__PURE__ */ jsx("span", { children: cssVar })]
|
|
1913
|
-
}),
|
|
1914
|
-
token.$description && /* @__PURE__ */ jsx("p", {
|
|
1915
|
-
className: "sb-token-detail__description",
|
|
1916
|
-
children: token.$description
|
|
1917
|
-
})
|
|
1918
|
-
] });
|
|
1919
2384
|
}
|
|
1920
2385
|
//#endregion
|
|
1921
|
-
//#region src/
|
|
1922
|
-
function
|
|
1923
|
-
|
|
1924
|
-
if (
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
}
|
|
1930
|
-
|
|
1931
|
-
children: [/* @__PURE__ */ jsx("code", {
|
|
1932
|
-
className: "sb-token-detail__snippet",
|
|
1933
|
-
children: snippet
|
|
1934
|
-
}), /* @__PURE__ */ jsx(CopyButton$1, {
|
|
1935
|
-
value: snippet,
|
|
1936
|
-
label: `Copy usage snippet ${snippet}`
|
|
1937
|
-
})]
|
|
1938
|
-
})] });
|
|
2386
|
+
//#region src/ShadowPreview.tsx
|
|
2387
|
+
function formatDimension(raw) {
|
|
2388
|
+
if (raw == null) return "—";
|
|
2389
|
+
if (typeof raw === "number") return String(raw);
|
|
2390
|
+
if (typeof raw === "string") return raw;
|
|
2391
|
+
if (typeof raw === "object") {
|
|
2392
|
+
const v = raw;
|
|
2393
|
+
if (typeof v.value === "number" && typeof v.unit === "string") return `${v.value}${v.unit}`;
|
|
2394
|
+
}
|
|
2395
|
+
return JSON.stringify(raw);
|
|
1939
2396
|
}
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
2397
|
+
function formatSubColor(raw, format) {
|
|
2398
|
+
if (raw == null) return "—";
|
|
2399
|
+
return formatColor(raw, format).value;
|
|
2400
|
+
}
|
|
2401
|
+
function asLayers(raw) {
|
|
2402
|
+
if (Array.isArray(raw)) return raw;
|
|
2403
|
+
if (raw && typeof raw === "object") return [raw];
|
|
2404
|
+
return [];
|
|
2405
|
+
}
|
|
2406
|
+
function layerKey(path, layer, fallback) {
|
|
2407
|
+
return `${path}|${`${formatDimension(layer.offsetX)},${formatDimension(layer.offsetY)}`}|${formatDimension(layer.blur)}|${formatDimension(layer.spread)}|${fallback}`;
|
|
2408
|
+
}
|
|
2409
|
+
function ShadowPreview({ filter, caption, sortBy = "path", sortDir = "asc" }) {
|
|
2410
|
+
const project = useProject();
|
|
2411
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
1944
2412
|
const colorFormat = useColorFormat();
|
|
1945
|
-
const
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
2413
|
+
const rows = useMemo(() => {
|
|
2414
|
+
return sortTokens(Object.entries(resolved).filter(([path, token]) => {
|
|
2415
|
+
if (token.$type !== "shadow") return false;
|
|
2416
|
+
return globMatch(path, filter);
|
|
2417
|
+
}), {
|
|
2418
|
+
by: sortBy,
|
|
2419
|
+
dir: sortDir
|
|
2420
|
+
}).map(([path, token]) => ({
|
|
2421
|
+
path,
|
|
2422
|
+
cssVar: resolveCssVar(path, project),
|
|
2423
|
+
layers: asLayers(token.$value)
|
|
2424
|
+
}));
|
|
2425
|
+
}, [
|
|
2426
|
+
resolved,
|
|
2427
|
+
filter,
|
|
2428
|
+
project,
|
|
2429
|
+
sortBy,
|
|
2430
|
+
sortDir
|
|
2431
|
+
]);
|
|
2432
|
+
const captionText = caption ?? `${rows.length} shadow${rows.length === 1 ? "" : "s"}${filter ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
2433
|
+
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
2434
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2435
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
2436
|
+
className: "sb-block__empty",
|
|
2437
|
+
children: "No shadow tokens match this filter."
|
|
2438
|
+
})
|
|
2439
|
+
});
|
|
2440
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2441
|
+
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2442
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2443
|
+
className: "sb-block__caption",
|
|
2444
|
+
children: captionText
|
|
2445
|
+
}), rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
2446
|
+
className: "sb-shadow-preview__row",
|
|
2447
|
+
children: [
|
|
2448
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2449
|
+
className: "sb-shadow-preview__meta",
|
|
2450
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2451
|
+
className: "sb-shadow-preview__path",
|
|
2452
|
+
children: row.path
|
|
2453
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
2454
|
+
className: "sb-shadow-preview__css-var",
|
|
2455
|
+
children: row.cssVar
|
|
2456
|
+
})]
|
|
2457
|
+
}),
|
|
2458
|
+
/* @__PURE__ */ jsx("div", {
|
|
2459
|
+
className: "sb-shadow-preview__sample-cell",
|
|
2460
|
+
children: /* @__PURE__ */ jsx(ShadowSample, { path: row.path })
|
|
2461
|
+
}),
|
|
2462
|
+
/* @__PURE__ */ jsx("div", {
|
|
2463
|
+
className: "sb-shadow-preview__breakdown",
|
|
2464
|
+
children: row.layers.length === 1 ? renderLayer(row.layers[0], colorFormat) : row.layers.map((layer, i) => /* @__PURE__ */ jsx(Layer, {
|
|
2465
|
+
layer,
|
|
2466
|
+
index: i,
|
|
2467
|
+
total: row.layers.length,
|
|
2468
|
+
colorFormat
|
|
2469
|
+
}, layerKey(row.path, layer, i)))
|
|
2470
|
+
})
|
|
2471
|
+
]
|
|
2472
|
+
}, row.path))]
|
|
2473
|
+
});
|
|
2474
|
+
}
|
|
2475
|
+
function renderLayer(layer, format) {
|
|
2476
|
+
if (!layer) return [];
|
|
2477
|
+
const entries = [
|
|
2478
|
+
["offset", `${formatDimension(layer.offsetX)} ${formatDimension(layer.offsetY)}`],
|
|
2479
|
+
["blur", formatDimension(layer.blur)],
|
|
2480
|
+
["spread", formatDimension(layer.spread)],
|
|
2481
|
+
["color", formatSubColor(layer.color, format)]
|
|
2482
|
+
];
|
|
2483
|
+
if (layer.inset) entries.push(["inset", String(layer.inset)]);
|
|
2484
|
+
return entries.flatMap(([k, v]) => [/* @__PURE__ */ jsx("span", {
|
|
2485
|
+
className: "sb-shadow-preview__breakdown-key",
|
|
2486
|
+
children: k
|
|
2487
|
+
}, `k-${k}`), /* @__PURE__ */ jsx("span", { children: v }, `v-${k}`)]);
|
|
2488
|
+
}
|
|
2489
|
+
function Layer({ layer, index, total, colorFormat }) {
|
|
2490
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2491
|
+
className: "sb-shadow-preview__layer",
|
|
2492
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
2493
|
+
className: "sb-shadow-preview__layer-header",
|
|
1951
2494
|
children: [
|
|
1952
|
-
"
|
|
1953
|
-
|
|
1954
|
-
"
|
|
1955
|
-
|
|
1956
|
-
"."
|
|
2495
|
+
"layer ",
|
|
2496
|
+
index + 1,
|
|
2497
|
+
" of ",
|
|
2498
|
+
total
|
|
1957
2499
|
]
|
|
1958
|
-
})
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
const value = formatTokenValue(token.$value, token.$type, colorFormat);
|
|
1963
|
-
const outOfGamut = gamut?.outOfGamut ?? false;
|
|
1964
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
1965
|
-
...theme,
|
|
1966
|
-
className: cx(theme["className"], "sb-token-detail"),
|
|
1967
|
-
children: [
|
|
1968
|
-
/* @__PURE__ */ jsx(TokenHeader, {
|
|
1969
|
-
path,
|
|
1970
|
-
...heading !== void 0 && { heading }
|
|
1971
|
-
}),
|
|
1972
|
-
/* @__PURE__ */ jsxs("div", {
|
|
1973
|
-
className: "sb-token-detail__section-header",
|
|
1974
|
-
children: ["Resolved value · ", activeTheme]
|
|
1975
|
-
}),
|
|
1976
|
-
/* @__PURE__ */ jsx(CompositePreview, { path }),
|
|
1977
|
-
/* @__PURE__ */ jsx(CompositeBreakdown, { path }),
|
|
1978
|
-
/* @__PURE__ */ jsxs("div", {
|
|
1979
|
-
className: "sb-token-detail__chain",
|
|
1980
|
-
children: [
|
|
1981
|
-
isColor && /* @__PURE__ */ jsx("span", {
|
|
1982
|
-
className: "sb-token-detail__swatch",
|
|
1983
|
-
style: { background: cssVar },
|
|
1984
|
-
"aria-hidden": true
|
|
1985
|
-
}),
|
|
1986
|
-
/* @__PURE__ */ jsx("span", { children: value }),
|
|
1987
|
-
outOfGamut && /* @__PURE__ */ jsx("span", {
|
|
1988
|
-
title: "Out of sRGB gamut for this format",
|
|
1989
|
-
"aria-label": "out of gamut",
|
|
1990
|
-
style: { marginLeft: 6 },
|
|
1991
|
-
children: "⚠"
|
|
1992
|
-
}),
|
|
1993
|
-
/* @__PURE__ */ jsx(CopyButton$1, {
|
|
1994
|
-
value,
|
|
1995
|
-
label: `Copy value ${value}`
|
|
1996
|
-
})
|
|
1997
|
-
]
|
|
1998
|
-
}),
|
|
1999
|
-
/* @__PURE__ */ jsx(AliasChain, { path }),
|
|
2000
|
-
/* @__PURE__ */ jsx(AliasedBy, { path }),
|
|
2001
|
-
/* @__PURE__ */ jsx(TokenUsageSnippet, { path }),
|
|
2002
|
-
/* @__PURE__ */ jsx(ConsumerOutput, { path }),
|
|
2003
|
-
/* @__PURE__ */ jsx(AxisVariance, { path })
|
|
2004
|
-
]
|
|
2500
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2501
|
+
className: cx("sb-shadow-preview__breakdown", "sb-shadow-preview__layer-breakdown"),
|
|
2502
|
+
children: renderLayer(layer, colorFormat)
|
|
2503
|
+
})]
|
|
2005
2504
|
});
|
|
2006
2505
|
}
|
|
2007
2506
|
//#endregion
|
|
2008
|
-
//#region src/
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
2023
|
-
className: "sb-detail-overlay__panel",
|
|
2024
|
-
onClick: (e) => e.stopPropagation(),
|
|
2025
|
-
role: "dialog",
|
|
2026
|
-
"aria-modal": "true",
|
|
2027
|
-
"aria-label": `Token detail for ${path}`,
|
|
2028
|
-
children: [/* @__PURE__ */ jsx("button", {
|
|
2029
|
-
type: "button",
|
|
2030
|
-
className: "sb-detail-overlay__close",
|
|
2031
|
-
onClick: onClose,
|
|
2032
|
-
"aria-label": "Close",
|
|
2033
|
-
"data-testid": `${testId}-close`,
|
|
2034
|
-
children: "×"
|
|
2035
|
-
}), /* @__PURE__ */ jsx(TokenDetail, { path })]
|
|
2036
|
-
})
|
|
2037
|
-
});
|
|
2507
|
+
//#region src/StrokeStyleSample.tsx
|
|
2508
|
+
const STRING_STYLES = new Set([
|
|
2509
|
+
"solid",
|
|
2510
|
+
"dashed",
|
|
2511
|
+
"dotted",
|
|
2512
|
+
"double",
|
|
2513
|
+
"groove",
|
|
2514
|
+
"ridge",
|
|
2515
|
+
"outset",
|
|
2516
|
+
"inset"
|
|
2517
|
+
]);
|
|
2518
|
+
function extractCssStyle(value) {
|
|
2519
|
+
if (typeof value === "string" && STRING_STYLES.has(value)) return value;
|
|
2520
|
+
return null;
|
|
2038
2521
|
}
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
const { resolved, activeTheme, cssVarPrefix } = useProject();
|
|
2043
|
-
const [selectedPath, setSelectedPath] = useState(null);
|
|
2044
|
-
const [query, setQuery] = useState("");
|
|
2045
|
-
const variantIndex = useMemo(() => buildVariantIndex(variants), [variants]);
|
|
2522
|
+
function StrokeStyleSample({ filter, caption, sortBy = "path", sortDir = "asc" }) {
|
|
2523
|
+
const project = useProject();
|
|
2524
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
2046
2525
|
const rows = useMemo(() => {
|
|
2047
2526
|
return sortTokens(Object.entries(resolved).filter(([path, token]) => {
|
|
2048
|
-
if (token.$type !== "
|
|
2527
|
+
if (token.$type !== "strokeStyle") return false;
|
|
2049
2528
|
return globMatch(path, filter);
|
|
2050
2529
|
}), {
|
|
2051
2530
|
by: sortBy,
|
|
2052
2531
|
dir: sortDir
|
|
2053
|
-
}).map(([path, token]) => {
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
return {
|
|
2060
|
-
path,
|
|
2061
|
-
cssVar: makeCssVar(path, cssVarPrefix),
|
|
2062
|
-
hex: hex.value,
|
|
2063
|
-
hsl: hsl.value,
|
|
2064
|
-
oklch: oklch.value,
|
|
2065
|
-
hexOutOfGamut: hex.outOfGamut,
|
|
2066
|
-
...token.aliasOf !== void 0 && { aliasOf: token.aliasOf },
|
|
2067
|
-
...variant !== void 0 && { variant }
|
|
2068
|
-
};
|
|
2069
|
-
});
|
|
2532
|
+
}).map(([path, token]) => ({
|
|
2533
|
+
path,
|
|
2534
|
+
cssVar: resolveCssVar(path, project),
|
|
2535
|
+
displayValue: formatTokenValue(token.$value, token.$type, "raw", project.listing[path]),
|
|
2536
|
+
cssStyle: extractCssStyle(token.$value)
|
|
2537
|
+
}));
|
|
2070
2538
|
}, [
|
|
2071
2539
|
resolved,
|
|
2072
2540
|
filter,
|
|
2073
|
-
|
|
2541
|
+
project,
|
|
2074
2542
|
sortBy,
|
|
2075
|
-
sortDir
|
|
2076
|
-
variantIndex
|
|
2077
|
-
]);
|
|
2078
|
-
const visibleRows = useMemo(() => {
|
|
2079
|
-
if (!searchable || query.trim() === "") return rows;
|
|
2080
|
-
return fuzzyFilter(rows, query, (r) => `${r.path} ${r.hex} ${r.hsl} ${r.oklch}`);
|
|
2081
|
-
}, [
|
|
2082
|
-
rows,
|
|
2083
|
-
query,
|
|
2084
|
-
searchable
|
|
2543
|
+
sortDir
|
|
2085
2544
|
]);
|
|
2086
|
-
const
|
|
2087
|
-
if (onSelect) onSelect(path);
|
|
2088
|
-
else setSelectedPath(path);
|
|
2089
|
-
}, [onSelect]);
|
|
2090
|
-
const matchSuffix = searchable && query.trim() !== "" ? ` · ${visibleRows.length} matching "${query.trim()}"` : "";
|
|
2091
|
-
const captionText = caption ?? `${rows.length} color${rows.length === 1 ? "" : "s"}${filter ? ` matching \`${filter}\`` : ""}${matchSuffix} · ${activeTheme}`;
|
|
2545
|
+
const captionText = caption ?? `${rows.length} strokeStyle token${rows.length === 1 ? "" : "s"}${filter && filter !== "strokeStyle" ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
2092
2546
|
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
2093
2547
|
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2094
2548
|
children: /* @__PURE__ */ jsx("div", {
|
|
2095
2549
|
className: "sb-block__empty",
|
|
2096
|
-
children: "No
|
|
2550
|
+
children: "No strokeStyle tokens match this filter."
|
|
2097
2551
|
})
|
|
2098
2552
|
});
|
|
2099
2553
|
return /* @__PURE__ */ jsxs("div", {
|
|
2100
2554
|
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2101
|
-
children: [
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
}),
|
|
2129
|
-
/* @__PURE__ */ jsx("th", {
|
|
2130
|
-
className: "sb-color-table__th sb-color-table__th--path",
|
|
2131
|
-
children: "Name"
|
|
2132
|
-
}),
|
|
2133
|
-
/* @__PURE__ */ jsx("th", {
|
|
2134
|
-
className: "sb-color-table__th",
|
|
2135
|
-
children: "HEX"
|
|
2136
|
-
}),
|
|
2137
|
-
/* @__PURE__ */ jsx("th", {
|
|
2138
|
-
className: "sb-color-table__th",
|
|
2139
|
-
children: "HSL"
|
|
2140
|
-
}),
|
|
2141
|
-
/* @__PURE__ */ jsx("th", {
|
|
2142
|
-
className: "sb-color-table__th",
|
|
2143
|
-
children: "OKLCH"
|
|
2144
|
-
}),
|
|
2145
|
-
/* @__PURE__ */ jsx("th", {
|
|
2146
|
-
className: "sb-color-table__th",
|
|
2147
|
-
children: "CSS var"
|
|
2148
|
-
}),
|
|
2149
|
-
/* @__PURE__ */ jsx("th", {
|
|
2150
|
-
className: "sb-color-table__th",
|
|
2151
|
-
children: "Alias"
|
|
2152
|
-
})
|
|
2153
|
-
] }) }),
|
|
2154
|
-
/* @__PURE__ */ jsxs("tbody", { children: [visibleRows.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsxs("td", {
|
|
2155
|
-
colSpan: 7,
|
|
2156
|
-
className: "sb-color-table__td sb-color-table__empty-row",
|
|
2157
|
-
children: [
|
|
2158
|
-
"No colors match \"",
|
|
2159
|
-
query.trim(),
|
|
2160
|
-
"\"."
|
|
2161
|
-
]
|
|
2162
|
-
}) }), visibleRows.map((row) => /* @__PURE__ */ jsxs("tr", {
|
|
2163
|
-
className: "sb-color-table__row",
|
|
2164
|
-
onClick: () => handleRowClick(row.path),
|
|
2165
|
-
onKeyDown: (e) => {
|
|
2166
|
-
if (e.key === "Enter" || e.key === " ") {
|
|
2167
|
-
e.preventDefault();
|
|
2168
|
-
handleRowClick(row.path);
|
|
2169
|
-
}
|
|
2170
|
-
},
|
|
2171
|
-
tabIndex: 0,
|
|
2172
|
-
"aria-label": `Inspect ${row.path}`,
|
|
2173
|
-
"data-testid": "color-table-row",
|
|
2174
|
-
"data-path": row.path,
|
|
2175
|
-
children: [
|
|
2176
|
-
/* @__PURE__ */ jsx("td", {
|
|
2177
|
-
className: "sb-color-table__td sb-color-table__swatch-cell",
|
|
2178
|
-
children: /* @__PURE__ */ jsx("span", {
|
|
2179
|
-
className: "sb-color-table__swatch",
|
|
2180
|
-
style: { background: row.cssVar },
|
|
2181
|
-
"aria-hidden": true
|
|
2182
|
-
})
|
|
2183
|
-
}),
|
|
2184
|
-
/* @__PURE__ */ jsxs("td", {
|
|
2185
|
-
className: cx("sb-color-table__td", "sb-color-table__path"),
|
|
2186
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
2187
|
-
className: "sb-color-table__path-text",
|
|
2188
|
-
children: row.path
|
|
2189
|
-
}), row.variant !== void 0 && /* @__PURE__ */ jsx("span", {
|
|
2190
|
-
className: "sb-color-table__variant-pill",
|
|
2191
|
-
"data-variant": row.variant,
|
|
2192
|
-
"data-testid": "color-table-variant",
|
|
2193
|
-
children: row.variant
|
|
2194
|
-
})]
|
|
2195
|
-
}),
|
|
2196
|
-
/* @__PURE__ */ jsx(ValueCell, {
|
|
2197
|
-
value: row.hex,
|
|
2198
|
-
label: `Copy HEX ${row.hex}`,
|
|
2199
|
-
children: row.hexOutOfGamut && /* @__PURE__ */ jsx("span", {
|
|
2200
|
-
title: "Out of sRGB gamut",
|
|
2201
|
-
"aria-label": "out of gamut",
|
|
2202
|
-
className: "sb-color-table__gamut-warn",
|
|
2203
|
-
children: "⚠"
|
|
2204
|
-
})
|
|
2205
|
-
}),
|
|
2206
|
-
/* @__PURE__ */ jsx(ValueCell, {
|
|
2207
|
-
value: row.hsl,
|
|
2208
|
-
label: `Copy HSL ${row.hsl}`
|
|
2209
|
-
}),
|
|
2210
|
-
/* @__PURE__ */ jsx(ValueCell, {
|
|
2211
|
-
value: row.oklch,
|
|
2212
|
-
label: `Copy OKLCH ${row.oklch}`
|
|
2213
|
-
}),
|
|
2214
|
-
/* @__PURE__ */ jsx(ValueCell, {
|
|
2215
|
-
value: row.cssVar,
|
|
2216
|
-
label: `Copy CSS var ${row.cssVar}`
|
|
2217
|
-
}),
|
|
2218
|
-
/* @__PURE__ */ jsx("td", {
|
|
2219
|
-
className: "sb-color-table__td sb-color-table__alias",
|
|
2220
|
-
children: row.aliasOf ? /* @__PURE__ */ jsx("span", {
|
|
2221
|
-
className: "sb-color-table__alias-text",
|
|
2222
|
-
children: row.aliasOf
|
|
2223
|
-
}) : /* @__PURE__ */ jsx("span", {
|
|
2224
|
-
className: "sb-color-table__alias-empty",
|
|
2225
|
-
"aria-hidden": true,
|
|
2226
|
-
children: "—"
|
|
2227
|
-
})
|
|
2228
|
-
})
|
|
2229
|
-
]
|
|
2230
|
-
}, row.path))] })
|
|
2231
|
-
]
|
|
2232
|
-
}),
|
|
2233
|
-
selectedPath !== null && /* @__PURE__ */ jsx(DetailOverlay, {
|
|
2234
|
-
path: selectedPath,
|
|
2235
|
-
onClose: () => setSelectedPath(null),
|
|
2236
|
-
testId: "color-table-overlay"
|
|
2237
|
-
})
|
|
2238
|
-
]
|
|
2239
|
-
});
|
|
2240
|
-
}
|
|
2241
|
-
function ValueCell({ value, label, children }) {
|
|
2242
|
-
return /* @__PURE__ */ jsxs("td", {
|
|
2243
|
-
className: "sb-color-table__td sb-color-table__value-cell",
|
|
2244
|
-
children: [
|
|
2245
|
-
/* @__PURE__ */ jsx("span", {
|
|
2246
|
-
className: "sb-color-table__value-text",
|
|
2247
|
-
title: value,
|
|
2248
|
-
children: value
|
|
2249
|
-
}),
|
|
2250
|
-
children,
|
|
2251
|
-
/* @__PURE__ */ jsx("span", {
|
|
2252
|
-
className: "sb-color-table__copy-wrap",
|
|
2253
|
-
onClick: (e) => e.stopPropagation(),
|
|
2254
|
-
onKeyDown: (e) => e.stopPropagation(),
|
|
2255
|
-
role: "presentation",
|
|
2256
|
-
children: /* @__PURE__ */ jsx(CopyButton$1, {
|
|
2257
|
-
value,
|
|
2258
|
-
label,
|
|
2259
|
-
className: "sb-color-table__copy"
|
|
2555
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2556
|
+
className: "sb-block__caption",
|
|
2557
|
+
children: captionText
|
|
2558
|
+
}), rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
2559
|
+
className: "sb-stroke-style-sample__row",
|
|
2560
|
+
children: [
|
|
2561
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2562
|
+
className: "sb-stroke-style-sample__meta",
|
|
2563
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2564
|
+
className: "sb-stroke-style-sample__path",
|
|
2565
|
+
children: row.path
|
|
2566
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
2567
|
+
className: "sb-stroke-style-sample__value",
|
|
2568
|
+
children: row.displayValue
|
|
2569
|
+
})]
|
|
2570
|
+
}),
|
|
2571
|
+
row.cssStyle ? /* @__PURE__ */ jsx("div", {
|
|
2572
|
+
className: "sb-stroke-style-sample__line",
|
|
2573
|
+
style: { borderTopStyle: row.cssStyle },
|
|
2574
|
+
"aria-hidden": true
|
|
2575
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
2576
|
+
className: "sb-stroke-style-sample__object-fallback",
|
|
2577
|
+
children: "Object-form (dashArray + lineCap) — no pure CSS `border-style` equivalent."
|
|
2578
|
+
}),
|
|
2579
|
+
/* @__PURE__ */ jsx("span", {
|
|
2580
|
+
className: "sb-stroke-style-sample__css-var",
|
|
2581
|
+
children: row.cssVar
|
|
2260
2582
|
})
|
|
2261
|
-
|
|
2262
|
-
]
|
|
2583
|
+
]
|
|
2584
|
+
}, row.path))]
|
|
2263
2585
|
});
|
|
2264
2586
|
}
|
|
2265
|
-
/**
|
|
2266
|
-
* Pre-sort the variants map by descending suffix length so the first
|
|
2267
|
-
* `endsWith` hit during matching is always the longest. Empty suffixes are
|
|
2268
|
-
* dropped — they'd match every path and make the feature meaningless.
|
|
2269
|
-
*/
|
|
2270
|
-
function buildVariantIndex(variants) {
|
|
2271
|
-
if (!variants) return [];
|
|
2272
|
-
const entries = [];
|
|
2273
|
-
for (const [label, suffix] of Object.entries(variants)) {
|
|
2274
|
-
if (suffix.length === 0) continue;
|
|
2275
|
-
entries.push({
|
|
2276
|
-
label,
|
|
2277
|
-
suffix
|
|
2278
|
-
});
|
|
2279
|
-
}
|
|
2280
|
-
entries.sort((a, b) => b.suffix.length - a.suffix.length);
|
|
2281
|
-
return entries;
|
|
2282
|
-
}
|
|
2283
|
-
/**
|
|
2284
|
-
* Resolve the variant label for a token path, if any. The leaf (last
|
|
2285
|
-
* dot-segment) must either equal the suffix outright (`hi.disabled`
|
|
2286
|
-
* matches suffix `disabled`) or end in `-<suffix>` (`hi-d` matches `d`).
|
|
2287
|
-
* The leading hyphen is required for the tail form, so suffix `h` matches
|
|
2288
|
-
* `hi-h` but not `highlight` or `neutral-900` — the whole trailing token
|
|
2289
|
-
* has to be the suffix, not a character within it. Entries are tried
|
|
2290
|
-
* longest-first, so `h-dark` wins over `dark` when both are configured
|
|
2291
|
-
* and the path ends in `-h-dark`.
|
|
2292
|
-
*/
|
|
2293
|
-
function matchVariant(path, variantIndex) {
|
|
2294
|
-
if (variantIndex.length === 0) return void 0;
|
|
2295
|
-
const leaf = path.split(".").at(-1) ?? path;
|
|
2296
|
-
for (const entry of variantIndex) if (leaf === entry.suffix || leaf.endsWith(`-${entry.suffix}`)) return entry.label;
|
|
2297
|
-
}
|
|
2298
2587
|
//#endregion
|
|
2299
|
-
//#region src/
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2588
|
+
//#region src/token-detail/internal.ts
|
|
2589
|
+
function useTokenDetailData(path) {
|
|
2590
|
+
const project = useProject();
|
|
2591
|
+
const { activeTheme, activeAxes, axes, themes, themesResolved, resolved, cssVarPrefix } = project;
|
|
2592
|
+
const typedResolved = resolved;
|
|
2593
|
+
return {
|
|
2594
|
+
token: typedResolved[path],
|
|
2595
|
+
cssVar: resolveCssVar(path, project),
|
|
2596
|
+
activeTheme,
|
|
2597
|
+
activeAxes,
|
|
2598
|
+
axes,
|
|
2599
|
+
themes,
|
|
2600
|
+
themesResolved,
|
|
2601
|
+
resolved: typedResolved,
|
|
2602
|
+
cssVarPrefix
|
|
2311
2603
|
};
|
|
2312
|
-
for (const d of diagnostics) counts[d.severity] += 1;
|
|
2313
|
-
const parts = [];
|
|
2314
|
-
if (counts.error > 0) parts.push(`✖ ${counts.error} error${counts.error === 1 ? "" : "s"}`);
|
|
2315
|
-
if (counts.warn > 0) parts.push(`⚠ ${counts.warn} warning${counts.warn === 1 ? "" : "s"}`);
|
|
2316
|
-
if (counts.info > 0) parts.push(`${counts.info} info`);
|
|
2317
|
-
return parts.join(" · ");
|
|
2318
|
-
}
|
|
2319
|
-
function diagnosticKey(d, i) {
|
|
2320
|
-
return `${d.severity}:${d.group}:${d.filename ?? ""}:${d.line ?? ""}:${d.message}:${i}`;
|
|
2321
|
-
}
|
|
2322
|
-
function summaryVariant(diagnostics) {
|
|
2323
|
-
if (diagnostics.length === 0) return "ok";
|
|
2324
|
-
if (diagnostics.some((d) => d.severity === "error")) return "error";
|
|
2325
|
-
if (diagnostics.some((d) => d.severity === "warn")) return "warn";
|
|
2326
|
-
return null;
|
|
2327
2604
|
}
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
className: "sb-diagnostics__list",
|
|
2353
|
-
children: diagnostics.map((d, i) => /* @__PURE__ */ jsxs("li", {
|
|
2354
|
-
className: "sb-diagnostics__row",
|
|
2355
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
2356
|
-
className: cx("sb-diagnostics__label", { [`sb-diagnostics__label--${d.severity}`]: d.severity !== "info" }),
|
|
2357
|
-
children: severityLabel[d.severity]
|
|
2358
|
-
}), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("div", { children: d.message }), (d.group || d.filename) && /* @__PURE__ */ jsx("div", {
|
|
2359
|
-
className: "sb-diagnostics__meta",
|
|
2360
|
-
children: [
|
|
2361
|
-
d.group,
|
|
2362
|
-
d.filename,
|
|
2363
|
-
d.line ? `:${d.line}` : ""
|
|
2364
|
-
].filter(Boolean).join(" · ")
|
|
2365
|
-
})] })]
|
|
2366
|
-
}, diagnosticKey(d, i)))
|
|
2605
|
+
//#endregion
|
|
2606
|
+
//#region src/token-detail/AliasChain.tsx
|
|
2607
|
+
function AliasChain({ path }) {
|
|
2608
|
+
const { token } = useTokenDetailData(path);
|
|
2609
|
+
const chain = useMemo(() => {
|
|
2610
|
+
if (!token) return [];
|
|
2611
|
+
if (Array.isArray(token.aliasChain) && token.aliasChain.length > 0) return [path, ...token.aliasChain];
|
|
2612
|
+
if (typeof token.aliasOf === "string") return [path, token.aliasOf];
|
|
2613
|
+
return [path];
|
|
2614
|
+
}, [token, path]);
|
|
2615
|
+
if (chain.length <= 1) return null;
|
|
2616
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
2617
|
+
className: "sb-token-detail__section-header",
|
|
2618
|
+
children: "Alias chain"
|
|
2619
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2620
|
+
className: "sb-token-detail__chain",
|
|
2621
|
+
children: chain.map((step, i) => /* @__PURE__ */ jsxs("span", {
|
|
2622
|
+
className: "sb-token-detail__chain",
|
|
2623
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
2624
|
+
className: "sb-token-detail__chain-node",
|
|
2625
|
+
children: step
|
|
2626
|
+
}), i < chain.length - 1 && /* @__PURE__ */ jsx("span", {
|
|
2627
|
+
className: "sb-token-detail__arrow",
|
|
2628
|
+
children: "→"
|
|
2367
2629
|
})]
|
|
2368
|
-
})
|
|
2369
|
-
});
|
|
2630
|
+
}, step))
|
|
2631
|
+
})] });
|
|
2370
2632
|
}
|
|
2371
2633
|
//#endregion
|
|
2372
|
-
//#region src/
|
|
2373
|
-
const
|
|
2374
|
-
const
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
background: "var(--swatchbook-accent-bg, #3b82f6)",
|
|
2378
|
-
borderRadius: 2,
|
|
2379
|
-
minWidth: 1
|
|
2380
|
-
},
|
|
2381
|
-
radiusSample: {
|
|
2382
|
-
width: 56,
|
|
2383
|
-
height: 56,
|
|
2384
|
-
background: "var(--swatchbook-accent-bg, #3b82f6)",
|
|
2385
|
-
border: BORDER_STRONG
|
|
2386
|
-
},
|
|
2387
|
-
sizeSample: {
|
|
2388
|
-
background: "var(--swatchbook-accent-bg, #3b82f6)",
|
|
2389
|
-
border: BORDER_STRONG,
|
|
2390
|
-
minWidth: 1,
|
|
2391
|
-
minHeight: 1
|
|
2392
|
-
}
|
|
2634
|
+
//#region src/token-detail/AliasedBy.tsx
|
|
2635
|
+
const ALIASED_BY_DEPTH_CAP = 6;
|
|
2636
|
+
const GROUP_RANK = {
|
|
2637
|
+
ref: 0,
|
|
2638
|
+
sys: 1
|
|
2393
2639
|
};
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
*/
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2640
|
+
function AliasedBy({ path }) {
|
|
2641
|
+
const { resolved } = useTokenDetailData(path);
|
|
2642
|
+
const tree = useMemo(() => buildAliasedByTree(path, resolved), [path, resolved]);
|
|
2643
|
+
const truncated = useMemo(() => treeHasTruncation(tree), [tree]);
|
|
2644
|
+
if (tree.length === 0) return null;
|
|
2645
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
2646
|
+
/* @__PURE__ */ jsx("div", {
|
|
2647
|
+
className: "sb-token-detail__section-header",
|
|
2648
|
+
children: "Aliased by"
|
|
2649
|
+
}),
|
|
2650
|
+
/* @__PURE__ */ jsx("ul", {
|
|
2651
|
+
className: "sb-token-detail__aliased-by-list",
|
|
2652
|
+
children: tree.map((node) => /* @__PURE__ */ jsx(AliasedByRow, {
|
|
2653
|
+
node,
|
|
2654
|
+
depth: 0
|
|
2655
|
+
}, node.path))
|
|
2656
|
+
}),
|
|
2657
|
+
truncated && /* @__PURE__ */ jsxs("div", {
|
|
2658
|
+
className: "sb-token-detail__aliased-by-truncated",
|
|
2659
|
+
children: [
|
|
2660
|
+
"Further descendants truncated at depth ",
|
|
2661
|
+
ALIASED_BY_DEPTH_CAP,
|
|
2662
|
+
"."
|
|
2663
|
+
]
|
|
2664
|
+
})
|
|
2665
|
+
] });
|
|
2410
2666
|
}
|
|
2411
|
-
function
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
})
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2667
|
+
function AliasedByRow({ node, depth }) {
|
|
2668
|
+
return /* @__PURE__ */ jsxs("li", { children: [/* @__PURE__ */ jsx("div", {
|
|
2669
|
+
className: "sb-token-detail__aliased-by-row",
|
|
2670
|
+
style: { paddingLeft: depth * 16 },
|
|
2671
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
2672
|
+
className: "sb-token-detail__chain-node",
|
|
2673
|
+
children: node.path
|
|
2674
|
+
})
|
|
2675
|
+
}), node.children.length > 0 && /* @__PURE__ */ jsx("ul", {
|
|
2676
|
+
className: "sb-token-detail__aliased-by-list",
|
|
2677
|
+
children: node.children.map((child) => /* @__PURE__ */ jsx(AliasedByRow, {
|
|
2678
|
+
node: child,
|
|
2679
|
+
depth: depth + 1
|
|
2680
|
+
}, child.path))
|
|
2681
|
+
})] });
|
|
2682
|
+
}
|
|
2683
|
+
function buildAliasedByTree(rootPath, resolved) {
|
|
2684
|
+
const direct = resolved[rootPath]?.aliasedBy;
|
|
2685
|
+
if (!direct || direct.length === 0) return [];
|
|
2686
|
+
const visited = new Set([rootPath]);
|
|
2687
|
+
return sortPaths(direct).map((p) => walk(p, resolved, visited, 1));
|
|
2688
|
+
}
|
|
2689
|
+
function walk(path, resolved, visited, depth) {
|
|
2690
|
+
if (visited.has(path)) return {
|
|
2691
|
+
path,
|
|
2692
|
+
children: []
|
|
2693
|
+
};
|
|
2694
|
+
visited.add(path);
|
|
2695
|
+
const parents = resolved[path]?.aliasedBy;
|
|
2696
|
+
if (!parents || parents.length === 0) return {
|
|
2697
|
+
path,
|
|
2698
|
+
children: []
|
|
2699
|
+
};
|
|
2700
|
+
if (depth >= ALIASED_BY_DEPTH_CAP) return {
|
|
2701
|
+
path,
|
|
2702
|
+
children: [],
|
|
2703
|
+
truncated: true
|
|
2704
|
+
};
|
|
2705
|
+
return {
|
|
2706
|
+
path,
|
|
2707
|
+
children: sortPaths(parents).map((p) => walk(p, resolved, visited, depth + 1))
|
|
2708
|
+
};
|
|
2709
|
+
}
|
|
2710
|
+
function sortPaths(paths) {
|
|
2711
|
+
return paths.toSorted((a, b) => {
|
|
2712
|
+
const ra = GROUP_RANK[a.split(".")[0] ?? ""] ?? 2;
|
|
2713
|
+
const rb = GROUP_RANK[b.split(".")[0] ?? ""] ?? 2;
|
|
2714
|
+
return ra !== rb ? ra - rb : a.localeCompare(b, void 0, { numeric: true });
|
|
2715
|
+
});
|
|
2716
|
+
}
|
|
2717
|
+
function treeHasTruncation(nodes) {
|
|
2718
|
+
for (const n of nodes) {
|
|
2719
|
+
if (n.truncated) return true;
|
|
2720
|
+
if (treeHasTruncation(n.children)) return true;
|
|
2440
2721
|
}
|
|
2722
|
+
return false;
|
|
2441
2723
|
}
|
|
2442
2724
|
//#endregion
|
|
2443
|
-
//#region src/
|
|
2444
|
-
|
|
2445
|
-
|
|
2446
|
-
|
|
2447
|
-
const
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2453
|
-
|
|
2725
|
+
//#region src/token-detail/AxisVariance.tsx
|
|
2726
|
+
function AxisVariance({ path }) {
|
|
2727
|
+
const { token, cssVar, axes, themes, themesResolved, activeAxes, cssVarPrefix } = useTokenDetailData(path);
|
|
2728
|
+
const colorFormat = useColorFormat();
|
|
2729
|
+
const tokenType = token?.$type;
|
|
2730
|
+
const isColor = tokenType === "color";
|
|
2731
|
+
const formatFn = (t) => valueFor(t, tokenType, colorFormat);
|
|
2732
|
+
const variance = useMemo(() => {
|
|
2733
|
+
const result = analyzeAxisVariance(path, axes, themes, themesResolved);
|
|
2734
|
+
return {
|
|
2735
|
+
kind: result.kind === "constant" ? "constant" : result.kind === "single" ? "one-axis" : "multi-axis",
|
|
2736
|
+
varyingAxes: result.varyingAxes
|
|
2737
|
+
};
|
|
2738
|
+
}, [
|
|
2739
|
+
path,
|
|
2740
|
+
axes,
|
|
2741
|
+
themes,
|
|
2742
|
+
themesResolved
|
|
2743
|
+
]);
|
|
2744
|
+
if (themes.length === 0) return /* @__PURE__ */ jsx(Fragment$1, {});
|
|
2745
|
+
if (variance.kind === "constant") {
|
|
2746
|
+
const anyTheme = themes[0];
|
|
2747
|
+
const value = anyTheme ? formatFn(themesResolved[anyTheme.name]?.[path]) : "—";
|
|
2748
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
2749
|
+
className: "sb-token-detail__section-header",
|
|
2750
|
+
children: "Values across axes"
|
|
2751
|
+
}), /* @__PURE__ */ jsx("table", {
|
|
2752
|
+
className: "sb-token-detail__theme-table",
|
|
2753
|
+
"data-testid": "token-detail-values",
|
|
2754
|
+
children: /* @__PURE__ */ jsx("tbody", { children: /* @__PURE__ */ jsx("tr", {
|
|
2755
|
+
className: "sb-token-detail__theme-row",
|
|
2756
|
+
children: /* @__PURE__ */ jsxs("td", {
|
|
2757
|
+
className: "sb-token-detail__theme-cell",
|
|
2758
|
+
"data-testid": "token-detail-constant",
|
|
2759
|
+
children: [
|
|
2760
|
+
isColor && /* @__PURE__ */ jsx("span", {
|
|
2761
|
+
className: "sb-token-detail__swatch",
|
|
2762
|
+
style: { background: cssVar },
|
|
2763
|
+
"aria-hidden": true
|
|
2764
|
+
}),
|
|
2765
|
+
value,
|
|
2766
|
+
/* @__PURE__ */ jsxs("span", {
|
|
2767
|
+
style: {
|
|
2768
|
+
opacity: .6,
|
|
2769
|
+
marginLeft: 8
|
|
2770
|
+
},
|
|
2771
|
+
children: [
|
|
2772
|
+
"same across all ",
|
|
2773
|
+
themes.length,
|
|
2774
|
+
" tuples"
|
|
2775
|
+
]
|
|
2776
|
+
})
|
|
2777
|
+
]
|
|
2778
|
+
})
|
|
2779
|
+
}) })
|
|
2780
|
+
})] });
|
|
2454
2781
|
}
|
|
2455
|
-
|
|
2456
|
-
|
|
2457
|
-
|
|
2458
|
-
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2782
|
+
if (variance.kind === "one-axis") {
|
|
2783
|
+
const axisName = variance.varyingAxes[0];
|
|
2784
|
+
if (!axisName) return /* @__PURE__ */ jsx(Fragment$1, {});
|
|
2785
|
+
const axis = axes.find((a) => a.name === axisName);
|
|
2786
|
+
if (!axis) return /* @__PURE__ */ jsx(Fragment$1, {});
|
|
2787
|
+
const contextValues = axis.contexts.map((ctx) => {
|
|
2788
|
+
const target = {
|
|
2789
|
+
...activeAxes,
|
|
2790
|
+
[axisName]: ctx
|
|
2791
|
+
};
|
|
2792
|
+
const name = themes.find((t) => {
|
|
2793
|
+
const input = t.input;
|
|
2794
|
+
return Object.keys(input).every((k) => input[k] === target[k]);
|
|
2795
|
+
})?.name ?? "";
|
|
2467
2796
|
return {
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
pxValue,
|
|
2472
|
-
capped: Number.isFinite(pxValue) && pxValue > MAX_RENDER_PX
|
|
2797
|
+
ctx,
|
|
2798
|
+
themeName: name,
|
|
2799
|
+
value: name ? formatFn(themesResolved[name]?.[path]) : "—"
|
|
2473
2800
|
};
|
|
2474
2801
|
});
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2802
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
|
|
2803
|
+
className: "sb-token-detail__section-header",
|
|
2804
|
+
children: ["Varies with ", axisName]
|
|
2805
|
+
}), /* @__PURE__ */ jsx("table", {
|
|
2806
|
+
className: "sb-token-detail__theme-table",
|
|
2807
|
+
"data-testid": "token-detail-values",
|
|
2808
|
+
children: /* @__PURE__ */ jsx("tbody", { children: contextValues.map((row) => /* @__PURE__ */ jsxs("tr", {
|
|
2809
|
+
className: "sb-token-detail__theme-row",
|
|
2810
|
+
"data-axis": axisName,
|
|
2811
|
+
"data-context": row.ctx,
|
|
2812
|
+
children: [/* @__PURE__ */ jsx("td", {
|
|
2813
|
+
className: "sb-token-detail__theme-cell",
|
|
2814
|
+
style: { width: "30%" },
|
|
2815
|
+
children: row.ctx
|
|
2816
|
+
}), /* @__PURE__ */ jsxs("td", {
|
|
2817
|
+
className: "sb-token-detail__theme-cell",
|
|
2818
|
+
children: [isColor && row.themeName && /* @__PURE__ */ jsx("span", {
|
|
2819
|
+
className: "sb-token-detail__swatch",
|
|
2820
|
+
style: { background: cssVar },
|
|
2821
|
+
[dataAttr(cssVarPrefix, "theme")]: row.themeName,
|
|
2822
|
+
"aria-hidden": true
|
|
2823
|
+
}), row.value]
|
|
2824
|
+
})]
|
|
2825
|
+
}, row.ctx)) })
|
|
2826
|
+
})] });
|
|
2827
|
+
}
|
|
2828
|
+
const [rowAxis, colAxis, ...extra] = variance.varyingAxes.map((name) => axes.find((a) => a.name === name)).filter((a) => Boolean(a)).toSorted((a, b) => b.contexts.length - a.contexts.length);
|
|
2829
|
+
if (!rowAxis || !colAxis) return /* @__PURE__ */ jsx(Fragment$1, {});
|
|
2830
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
2831
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2832
|
+
className: "sb-token-detail__section-header",
|
|
2833
|
+
children: ["Varies with ", variance.varyingAxes.join(" × ")]
|
|
2834
|
+
}),
|
|
2835
|
+
/* @__PURE__ */ jsxs("table", {
|
|
2836
|
+
className: "sb-token-detail__theme-table",
|
|
2837
|
+
"data-testid": "token-detail-values",
|
|
2838
|
+
children: [/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", {
|
|
2839
|
+
className: "sb-token-detail__theme-row",
|
|
2840
|
+
children: [/* @__PURE__ */ jsxs("th", {
|
|
2841
|
+
className: "sb-token-detail__theme-cell",
|
|
2842
|
+
style: {
|
|
2843
|
+
textAlign: "left",
|
|
2844
|
+
opacity: .7
|
|
2845
|
+
},
|
|
2846
|
+
children: [
|
|
2847
|
+
rowAxis.name,
|
|
2848
|
+
" \\ ",
|
|
2849
|
+
colAxis.name
|
|
2850
|
+
]
|
|
2851
|
+
}), colAxis.contexts.map((col) => /* @__PURE__ */ jsx("th", {
|
|
2852
|
+
className: "sb-token-detail__theme-cell",
|
|
2853
|
+
style: {
|
|
2854
|
+
textAlign: "left",
|
|
2855
|
+
opacity: .7
|
|
2856
|
+
},
|
|
2857
|
+
children: col
|
|
2858
|
+
}, col))]
|
|
2859
|
+
}) }), /* @__PURE__ */ jsx("tbody", { children: rowAxis.contexts.map((row) => /* @__PURE__ */ jsxs("tr", {
|
|
2860
|
+
className: "sb-token-detail__theme-row",
|
|
2861
|
+
children: [/* @__PURE__ */ jsx("td", {
|
|
2862
|
+
className: "sb-token-detail__theme-cell",
|
|
2863
|
+
children: row
|
|
2864
|
+
}), colAxis.contexts.map((col) => {
|
|
2865
|
+
const name = tupleName(themes, {
|
|
2866
|
+
...activeAxes,
|
|
2867
|
+
[rowAxis.name]: row,
|
|
2868
|
+
[colAxis.name]: col
|
|
2869
|
+
});
|
|
2870
|
+
const value = name ? formatFn(themesResolved[name]?.[path]) : "—";
|
|
2871
|
+
return /* @__PURE__ */ jsxs("td", {
|
|
2872
|
+
className: "sb-token-detail__theme-cell",
|
|
2873
|
+
"data-row": row,
|
|
2874
|
+
"data-col": col,
|
|
2875
|
+
children: [isColor && name && /* @__PURE__ */ jsx("span", {
|
|
2876
|
+
className: "sb-token-detail__swatch",
|
|
2877
|
+
style: { background: cssVar },
|
|
2878
|
+
[dataAttr(cssVarPrefix, "theme")]: name,
|
|
2879
|
+
"aria-hidden": true
|
|
2880
|
+
}), value]
|
|
2881
|
+
}, col);
|
|
2882
|
+
})]
|
|
2883
|
+
}, row)) })]
|
|
2884
|
+
}),
|
|
2885
|
+
extra.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
2886
|
+
className: "sb-token-detail__aliased-by-truncated",
|
|
2887
|
+
style: { marginTop: 6 },
|
|
2888
|
+
children: [
|
|
2889
|
+
"Values also vary with ",
|
|
2890
|
+
extra.map((a) => a.name).join(", "),
|
|
2891
|
+
"; matrix shows the slice for the active selection."
|
|
2526
2892
|
]
|
|
2527
|
-
}
|
|
2528
|
-
});
|
|
2893
|
+
})
|
|
2894
|
+
] });
|
|
2529
2895
|
}
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
if (typeof raw === "string") return raw;
|
|
2534
|
-
if (Array.isArray(raw)) return raw.map(String).join(", ");
|
|
2535
|
-
return "";
|
|
2896
|
+
function valueFor(token, $type, format) {
|
|
2897
|
+
if (!token) return "—";
|
|
2898
|
+
return formatTokenValue(token.$value, $type, format);
|
|
2536
2899
|
}
|
|
2537
|
-
function
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
return
|
|
2541
|
-
|
|
2542
|
-
return globMatch(path, filter);
|
|
2543
|
-
}), {
|
|
2544
|
-
by: sortBy,
|
|
2545
|
-
dir: sortDir
|
|
2546
|
-
}).map(([path, token]) => ({
|
|
2547
|
-
path,
|
|
2548
|
-
cssVar: makeCssVar(path, cssVarPrefix),
|
|
2549
|
-
stack: stackString(token.$value)
|
|
2550
|
-
}));
|
|
2551
|
-
}, [
|
|
2552
|
-
resolved,
|
|
2553
|
-
filter,
|
|
2554
|
-
cssVarPrefix,
|
|
2555
|
-
sortBy,
|
|
2556
|
-
sortDir
|
|
2557
|
-
]);
|
|
2558
|
-
const captionText = caption ?? `${rows.length} fontFamily token${rows.length === 1 ? "" : "s"}${filter && filter !== "fontFamily" ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
2559
|
-
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
2560
|
-
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2561
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
2562
|
-
className: "sb-block__empty",
|
|
2563
|
-
children: "No fontFamily tokens match this filter."
|
|
2564
|
-
})
|
|
2565
|
-
});
|
|
2566
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
2567
|
-
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2568
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
2569
|
-
className: "sb-block__caption",
|
|
2570
|
-
children: captionText
|
|
2571
|
-
}), rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
2572
|
-
className: "sb-font-family-sample__row",
|
|
2573
|
-
children: [
|
|
2574
|
-
/* @__PURE__ */ jsxs("div", {
|
|
2575
|
-
className: "sb-font-family-sample__meta",
|
|
2576
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
2577
|
-
className: "sb-font-family-sample__path",
|
|
2578
|
-
children: row.path
|
|
2579
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
2580
|
-
className: "sb-font-family-sample__stack",
|
|
2581
|
-
children: row.stack
|
|
2582
|
-
})]
|
|
2583
|
-
}),
|
|
2584
|
-
/* @__PURE__ */ jsx("div", {
|
|
2585
|
-
className: "sb-font-family-sample__sample",
|
|
2586
|
-
style: { fontFamily: row.cssVar },
|
|
2587
|
-
children: sample
|
|
2588
|
-
}),
|
|
2589
|
-
/* @__PURE__ */ jsx("span", {
|
|
2590
|
-
className: "sb-font-family-sample__css-var",
|
|
2591
|
-
children: row.cssVar
|
|
2592
|
-
})
|
|
2593
|
-
]
|
|
2594
|
-
}, row.path))]
|
|
2595
|
-
});
|
|
2900
|
+
function tupleName(themes, tuple) {
|
|
2901
|
+
return themes.find((t) => {
|
|
2902
|
+
const input = t.input;
|
|
2903
|
+
return Object.keys(input).every((k) => input[k] === tuple[k]);
|
|
2904
|
+
})?.name;
|
|
2596
2905
|
}
|
|
2597
2906
|
//#endregion
|
|
2598
|
-
//#region src/
|
|
2599
|
-
function
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
function FontWeightScale({ filter, sample = "Aa", caption, sortBy = "value", sortDir = "asc" }) {
|
|
2608
|
-
const { resolved, activeTheme, cssVarPrefix } = useProject();
|
|
2609
|
-
const rows = useMemo(() => {
|
|
2610
|
-
return sortTokens(Object.entries(resolved).filter(([path, token]) => {
|
|
2611
|
-
if (token.$type !== "fontWeight") return false;
|
|
2612
|
-
return globMatch(path, filter);
|
|
2613
|
-
}), {
|
|
2614
|
-
by: sortBy,
|
|
2615
|
-
dir: sortDir
|
|
2616
|
-
}).map(([path, token]) => ({
|
|
2617
|
-
path,
|
|
2618
|
-
cssVar: makeCssVar(path, cssVarPrefix),
|
|
2619
|
-
display: token.$value == null ? "" : String(token.$value),
|
|
2620
|
-
weight: toWeight(token.$value)
|
|
2621
|
-
}));
|
|
2622
|
-
}, [
|
|
2907
|
+
//#region src/token-detail/CompositeBreakdown.tsx
|
|
2908
|
+
function CompositeBreakdown({ path }) {
|
|
2909
|
+
const { token, resolved } = useTokenDetailData(path);
|
|
2910
|
+
const colorFormat = useColorFormat();
|
|
2911
|
+
if (!token) return null;
|
|
2912
|
+
return /* @__PURE__ */ jsx(CompositeBreakdownContent, {
|
|
2913
|
+
type: token.$type,
|
|
2914
|
+
rawValue: token.$value,
|
|
2915
|
+
partialAliasOf: token.partialAliasOf,
|
|
2623
2916
|
resolved,
|
|
2624
|
-
|
|
2625
|
-
cssVarPrefix,
|
|
2626
|
-
sortBy,
|
|
2627
|
-
sortDir
|
|
2628
|
-
]);
|
|
2629
|
-
const captionText = caption ?? `${rows.length} fontWeight token${rows.length === 1 ? "" : "s"}${filter && filter !== "fontWeight" ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
2630
|
-
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
2631
|
-
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2632
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
2633
|
-
className: "sb-block__empty",
|
|
2634
|
-
children: "No fontWeight tokens match this filter."
|
|
2635
|
-
})
|
|
2917
|
+
colorFormat
|
|
2636
2918
|
});
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2919
|
+
}
|
|
2920
|
+
function CompositeBreakdownContent({ type, rawValue, partialAliasOf, resolved, colorFormat }) {
|
|
2921
|
+
if (!rawValue || typeof rawValue !== "object") return null;
|
|
2922
|
+
const objectAliases = pickObjectAliases(partialAliasOf);
|
|
2923
|
+
const arrayAliases = pickArrayAliases(partialAliasOf);
|
|
2924
|
+
const aliasFor = (key) => subValueChain(objectAliases?.[key], resolved);
|
|
2925
|
+
if (type === "typography") {
|
|
2926
|
+
const v = rawValue;
|
|
2927
|
+
return renderKeyValueList([
|
|
2928
|
+
[
|
|
2929
|
+
"fontFamily",
|
|
2930
|
+
formatFontFamily(v["fontFamily"]),
|
|
2931
|
+
aliasFor("fontFamily")
|
|
2932
|
+
],
|
|
2933
|
+
[
|
|
2934
|
+
"fontSize",
|
|
2935
|
+
formatDimensionValue(v["fontSize"]),
|
|
2936
|
+
aliasFor("fontSize")
|
|
2937
|
+
],
|
|
2938
|
+
[
|
|
2939
|
+
"fontWeight",
|
|
2940
|
+
formatPrimitive(v["fontWeight"]),
|
|
2941
|
+
aliasFor("fontWeight")
|
|
2942
|
+
],
|
|
2943
|
+
[
|
|
2944
|
+
"lineHeight",
|
|
2945
|
+
formatPrimitive(v["lineHeight"]),
|
|
2946
|
+
aliasFor("lineHeight")
|
|
2947
|
+
],
|
|
2948
|
+
[
|
|
2949
|
+
"letterSpacing",
|
|
2950
|
+
formatDimensionValue(v["letterSpacing"]),
|
|
2951
|
+
aliasFor("letterSpacing")
|
|
2664
2952
|
]
|
|
2665
|
-
|
|
2666
|
-
}
|
|
2953
|
+
]);
|
|
2954
|
+
}
|
|
2955
|
+
if (type === "border") {
|
|
2956
|
+
const v = rawValue;
|
|
2957
|
+
return renderKeyValueList([
|
|
2958
|
+
[
|
|
2959
|
+
"color",
|
|
2960
|
+
formatColorSubValue(v["color"], colorFormat),
|
|
2961
|
+
aliasFor("color")
|
|
2962
|
+
],
|
|
2963
|
+
[
|
|
2964
|
+
"width",
|
|
2965
|
+
formatDimensionValue(v["width"]),
|
|
2966
|
+
aliasFor("width")
|
|
2967
|
+
],
|
|
2968
|
+
[
|
|
2969
|
+
"style",
|
|
2970
|
+
formatPrimitive(v["style"]),
|
|
2971
|
+
aliasFor("style")
|
|
2972
|
+
]
|
|
2973
|
+
]);
|
|
2974
|
+
}
|
|
2975
|
+
if (type === "transition") {
|
|
2976
|
+
const v = rawValue;
|
|
2977
|
+
return renderKeyValueList([
|
|
2978
|
+
[
|
|
2979
|
+
"duration",
|
|
2980
|
+
formatDimensionValue(v["duration"]),
|
|
2981
|
+
aliasFor("duration")
|
|
2982
|
+
],
|
|
2983
|
+
[
|
|
2984
|
+
"timingFunction",
|
|
2985
|
+
formatPrimitive(v["timingFunction"]),
|
|
2986
|
+
aliasFor("timingFunction")
|
|
2987
|
+
],
|
|
2988
|
+
[
|
|
2989
|
+
"delay",
|
|
2990
|
+
formatDimensionValue(v["delay"]),
|
|
2991
|
+
aliasFor("delay")
|
|
2992
|
+
]
|
|
2993
|
+
]);
|
|
2994
|
+
}
|
|
2995
|
+
if (type === "shadow") {
|
|
2996
|
+
const layers = Array.isArray(rawValue) ? rawValue : [rawValue];
|
|
2997
|
+
const multi = layers.length > 1;
|
|
2998
|
+
const layerAliasFor = (i, key) => subValueChain(arrayAliases?.[i]?.[key], resolved);
|
|
2999
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3000
|
+
className: "sb-token-detail__breakdown-section",
|
|
3001
|
+
children: layers.map((layer, i) => {
|
|
3002
|
+
const v = layer;
|
|
3003
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3004
|
+
style: { display: "contents" },
|
|
3005
|
+
children: [
|
|
3006
|
+
multi && /* @__PURE__ */ jsxs("div", {
|
|
3007
|
+
className: "sb-token-detail__breakdown-layer-header",
|
|
3008
|
+
children: ["Layer ", i + 1]
|
|
3009
|
+
}),
|
|
3010
|
+
/* @__PURE__ */ jsx(KeyValueRow, {
|
|
3011
|
+
label: "color",
|
|
3012
|
+
value: formatColorSubValue(v["color"], colorFormat),
|
|
3013
|
+
alias: layerAliasFor(i, "color")
|
|
3014
|
+
}),
|
|
3015
|
+
/* @__PURE__ */ jsx(KeyValueRow, {
|
|
3016
|
+
label: "offsetX",
|
|
3017
|
+
value: formatDimensionValue(v["offsetX"]),
|
|
3018
|
+
alias: layerAliasFor(i, "offsetX")
|
|
3019
|
+
}),
|
|
3020
|
+
/* @__PURE__ */ jsx(KeyValueRow, {
|
|
3021
|
+
label: "offsetY",
|
|
3022
|
+
value: formatDimensionValue(v["offsetY"]),
|
|
3023
|
+
alias: layerAliasFor(i, "offsetY")
|
|
3024
|
+
}),
|
|
3025
|
+
/* @__PURE__ */ jsx(KeyValueRow, {
|
|
3026
|
+
label: "blur",
|
|
3027
|
+
value: formatDimensionValue(v["blur"]),
|
|
3028
|
+
alias: layerAliasFor(i, "blur")
|
|
3029
|
+
}),
|
|
3030
|
+
/* @__PURE__ */ jsx(KeyValueRow, {
|
|
3031
|
+
label: "spread",
|
|
3032
|
+
value: formatDimensionValue(v["spread"]),
|
|
3033
|
+
alias: layerAliasFor(i, "spread")
|
|
3034
|
+
}),
|
|
3035
|
+
"inset" in v && /* @__PURE__ */ jsx(KeyValueRow, {
|
|
3036
|
+
label: "inset",
|
|
3037
|
+
value: formatPrimitive(v["inset"]),
|
|
3038
|
+
alias: void 0
|
|
3039
|
+
})
|
|
3040
|
+
]
|
|
3041
|
+
}, shadowLayerKey(v, i));
|
|
3042
|
+
})
|
|
3043
|
+
});
|
|
3044
|
+
}
|
|
3045
|
+
if (type === "gradient") {
|
|
3046
|
+
const stops = Array.isArray(rawValue) ? rawValue : [];
|
|
3047
|
+
if (stops.length === 0) return null;
|
|
3048
|
+
const stopAliasFor = (i) => subValueChain(arrayAliases?.[i]?.["color"], resolved);
|
|
3049
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3050
|
+
className: "sb-token-detail__breakdown-section",
|
|
3051
|
+
children: stops.map((stop, i) => {
|
|
3052
|
+
const v = stop;
|
|
3053
|
+
return /* @__PURE__ */ jsx(KeyValueRow, {
|
|
3054
|
+
label: `${((typeof v["position"] === "number" ? v["position"] : 0) * 100).toFixed(0)}%`,
|
|
3055
|
+
value: formatColorSubValue(v["color"], colorFormat),
|
|
3056
|
+
alias: stopAliasFor(i)
|
|
3057
|
+
}, gradientStopKey(v, i));
|
|
3058
|
+
})
|
|
3059
|
+
});
|
|
3060
|
+
}
|
|
3061
|
+
return null;
|
|
2667
3062
|
}
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
3063
|
+
function renderKeyValueList(rows) {
|
|
3064
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3065
|
+
className: "sb-token-detail__breakdown-section",
|
|
3066
|
+
children: rows.filter(([, v, alias]) => v !== null || alias && alias.length > 0).map(([k, v, alias]) => /* @__PURE__ */ jsx(KeyValueRow, {
|
|
3067
|
+
label: k,
|
|
3068
|
+
value: v ?? "",
|
|
3069
|
+
alias
|
|
3070
|
+
}, k))
|
|
3071
|
+
});
|
|
2673
3072
|
}
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
3073
|
+
function KeyValueRow({ label, value, alias }) {
|
|
3074
|
+
const hasAlias = alias && alias.length > 0;
|
|
3075
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("span", {
|
|
3076
|
+
className: "sb-token-detail__breakdown-key",
|
|
3077
|
+
children: label
|
|
3078
|
+
}), /* @__PURE__ */ jsxs("span", {
|
|
3079
|
+
className: "sb-token-detail__breakdown-value",
|
|
3080
|
+
children: [/* @__PURE__ */ jsx("span", { children: value ?? "—" }), hasAlias && /* @__PURE__ */ jsx("span", {
|
|
3081
|
+
className: "sb-token-detail__breakdown-alias",
|
|
3082
|
+
"data-testid": "breakdown-alias",
|
|
3083
|
+
children: alias.map((p, i) => /* @__PURE__ */ jsxs("span", {
|
|
3084
|
+
className: "sb-token-detail__breakdown-alias-step",
|
|
3085
|
+
children: [i > 0 && /* @__PURE__ */ jsx("span", {
|
|
3086
|
+
className: "sb-token-detail__arrow",
|
|
3087
|
+
children: "→"
|
|
3088
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
3089
|
+
className: "sb-token-detail__chain-node",
|
|
3090
|
+
children: p
|
|
3091
|
+
})]
|
|
3092
|
+
}, p))
|
|
3093
|
+
})]
|
|
3094
|
+
})] });
|
|
2682
3095
|
}
|
|
2683
|
-
function
|
|
2684
|
-
|
|
3096
|
+
function formatPrimitive(v) {
|
|
3097
|
+
if (v == null) return null;
|
|
3098
|
+
if (typeof v === "string" || typeof v === "number" || typeof v === "boolean") return String(v);
|
|
3099
|
+
return JSON.stringify(v);
|
|
2685
3100
|
}
|
|
2686
|
-
function
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
if (token.$type !== "gradient") return false;
|
|
2692
|
-
return globMatch(path, filter);
|
|
2693
|
-
}), {
|
|
2694
|
-
by: sortBy,
|
|
2695
|
-
dir: sortDir
|
|
2696
|
-
}).map(([path, token]) => ({
|
|
2697
|
-
path,
|
|
2698
|
-
cssVar: makeCssVar(path, cssVarPrefix),
|
|
2699
|
-
stops: asStops(token.$value)
|
|
2700
|
-
}));
|
|
2701
|
-
}, [
|
|
2702
|
-
resolved,
|
|
2703
|
-
filter,
|
|
2704
|
-
cssVarPrefix,
|
|
2705
|
-
sortBy,
|
|
2706
|
-
sortDir
|
|
2707
|
-
]);
|
|
2708
|
-
const captionText = caption ?? `${rows.length} gradient${rows.length === 1 ? "" : "s"}${filter ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
2709
|
-
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
2710
|
-
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2711
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
2712
|
-
className: "sb-block__empty",
|
|
2713
|
-
children: "No gradient tokens match this filter."
|
|
2714
|
-
})
|
|
2715
|
-
});
|
|
2716
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
2717
|
-
...themeAttrs(cssVarPrefix, activeTheme),
|
|
2718
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
2719
|
-
className: "sb-block__caption",
|
|
2720
|
-
children: captionText
|
|
2721
|
-
}), rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
2722
|
-
className: "sb-gradient-palette__row",
|
|
2723
|
-
children: [
|
|
2724
|
-
/* @__PURE__ */ jsxs("div", {
|
|
2725
|
-
className: "sb-gradient-palette__meta",
|
|
2726
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
2727
|
-
className: "sb-gradient-palette__path",
|
|
2728
|
-
children: row.path
|
|
2729
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
2730
|
-
className: "sb-gradient-palette__css-var",
|
|
2731
|
-
children: row.cssVar
|
|
2732
|
-
})]
|
|
2733
|
-
}),
|
|
2734
|
-
/* @__PURE__ */ jsx("div", {
|
|
2735
|
-
className: "sb-gradient-palette__sample",
|
|
2736
|
-
style: { background: `linear-gradient(to right, ${row.cssVar})` },
|
|
2737
|
-
"aria-hidden": true
|
|
2738
|
-
}),
|
|
2739
|
-
/* @__PURE__ */ jsx("div", {
|
|
2740
|
-
className: "sb-gradient-palette__stops",
|
|
2741
|
-
children: row.stops.map((stop, i) => /* @__PURE__ */ jsxs("div", {
|
|
2742
|
-
className: "sb-gradient-palette__stop-row",
|
|
2743
|
-
children: [
|
|
2744
|
-
/* @__PURE__ */ jsx("span", {
|
|
2745
|
-
className: "sb-gradient-palette__stop-swatch",
|
|
2746
|
-
style: { background: stopCssColor(stop) },
|
|
2747
|
-
"aria-hidden": true
|
|
2748
|
-
}),
|
|
2749
|
-
/* @__PURE__ */ jsx("span", { children: formatColor(stop.color, colorFormat).value }),
|
|
2750
|
-
/* @__PURE__ */ jsxs("span", {
|
|
2751
|
-
className: "sb-gradient-palette__stop-position",
|
|
2752
|
-
children: [
|
|
2753
|
-
"@ ",
|
|
2754
|
-
((stop.position ?? 0) * 100).toFixed(0),
|
|
2755
|
-
"%"
|
|
2756
|
-
]
|
|
2757
|
-
})
|
|
2758
|
-
]
|
|
2759
|
-
}, stopKey(row.path, stop, i)))
|
|
2760
|
-
})
|
|
2761
|
-
]
|
|
2762
|
-
}, row.path))]
|
|
2763
|
-
});
|
|
3101
|
+
function formatFontFamily(v) {
|
|
3102
|
+
if (v == null) return null;
|
|
3103
|
+
if (typeof v === "string") return v;
|
|
3104
|
+
if (Array.isArray(v)) return v.map(String).join(", ");
|
|
3105
|
+
return JSON.stringify(v);
|
|
2764
3106
|
}
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
const
|
|
2770
|
-
|
|
2771
|
-
position: "relative",
|
|
2772
|
-
height: 36,
|
|
2773
|
-
background: SURFACE_MUTED,
|
|
2774
|
-
borderRadius: 18,
|
|
2775
|
-
overflow: "hidden"
|
|
2776
|
-
},
|
|
2777
|
-
ball: {
|
|
2778
|
-
position: "absolute",
|
|
2779
|
-
top: "50%",
|
|
2780
|
-
width: 28,
|
|
2781
|
-
height: 28,
|
|
2782
|
-
marginTop: -14,
|
|
2783
|
-
borderRadius: "50%",
|
|
2784
|
-
background: "var(--swatchbook-accent-bg, #3b82f6)"
|
|
2785
|
-
},
|
|
2786
|
-
reducedMotion: {
|
|
2787
|
-
fontSize: 11,
|
|
2788
|
-
color: TEXT_MUTED,
|
|
2789
|
-
fontStyle: "italic"
|
|
2790
|
-
}
|
|
2791
|
-
};
|
|
2792
|
-
function extractDurationMs(raw) {
|
|
2793
|
-
if (raw == null) return NaN;
|
|
2794
|
-
if (typeof raw === "object") {
|
|
2795
|
-
const v = raw;
|
|
2796
|
-
if (typeof v.value === "number" && typeof v.unit === "string") {
|
|
2797
|
-
if (v.unit === "ms") return v.value;
|
|
2798
|
-
if (v.unit === "s") return v.value * 1e3;
|
|
2799
|
-
}
|
|
3107
|
+
function formatDimensionValue(v) {
|
|
3108
|
+
if (v == null) return null;
|
|
3109
|
+
if (typeof v === "string" || typeof v === "number") return String(v);
|
|
3110
|
+
if (typeof v === "object") {
|
|
3111
|
+
const d = v;
|
|
3112
|
+
if (typeof d.value === "number" && typeof d.unit === "string") return `${d.value}${d.unit}`;
|
|
2800
3113
|
}
|
|
2801
|
-
return
|
|
3114
|
+
return JSON.stringify(v);
|
|
2802
3115
|
}
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
3116
|
+
/**
|
|
3117
|
+
* Route sub-value colors through `formatColor` so they honor the active
|
|
3118
|
+
* color-format dropdown, just like the standalone `<ColorPalette />` and
|
|
3119
|
+
* `<TokenDetail />` top-line do. Returns `null` for a missing field so
|
|
3120
|
+
* the key/value row drops out entirely.
|
|
3121
|
+
*/
|
|
3122
|
+
function formatColorSubValue(v, format) {
|
|
3123
|
+
if (v == null) return null;
|
|
3124
|
+
return formatColor(v, format).value;
|
|
2806
3125
|
}
|
|
2807
|
-
function
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
3126
|
+
function pickObjectAliases(v) {
|
|
3127
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return void 0;
|
|
3128
|
+
return v;
|
|
3129
|
+
}
|
|
3130
|
+
function pickArrayAliases(v) {
|
|
3131
|
+
if (!Array.isArray(v)) return void 0;
|
|
3132
|
+
return v;
|
|
3133
|
+
}
|
|
3134
|
+
/**
|
|
3135
|
+
* Walk the alias chain starting from an immediate sub-value alias target.
|
|
3136
|
+
* `aliasTarget` is the path the sub-value directly references; the target
|
|
3137
|
+
* token's own `aliasChain` continues the walk to the primitive.
|
|
3138
|
+
*/
|
|
3139
|
+
function subValueChain(aliasTarget, resolved) {
|
|
3140
|
+
if (!aliasTarget) return void 0;
|
|
3141
|
+
const tail = (resolved?.[aliasTarget])?.aliasChain;
|
|
3142
|
+
return tail && tail.length > 0 ? [aliasTarget, ...tail] : [aliasTarget];
|
|
3143
|
+
}
|
|
3144
|
+
function shadowLayerKey(layer, fallback) {
|
|
3145
|
+
return `shadow|${[
|
|
3146
|
+
layer["color"],
|
|
3147
|
+
layer["offsetX"],
|
|
3148
|
+
layer["offsetY"],
|
|
3149
|
+
layer["blur"],
|
|
3150
|
+
layer["spread"],
|
|
3151
|
+
layer["inset"]
|
|
3152
|
+
].map((p) => p === void 0 ? "" : JSON.stringify(p)).join("|")}|${fallback}`;
|
|
2819
3153
|
}
|
|
2820
|
-
function
|
|
2821
|
-
|
|
2822
|
-
if (direct) return direct;
|
|
2823
|
-
if (typeof raw === "string") {
|
|
2824
|
-
const match = raw.match(/^\{([^}]+)\}$/);
|
|
2825
|
-
if (match && match[1]) {
|
|
2826
|
-
const referenced = themeTokens[match[1]];
|
|
2827
|
-
const resolved = extractCubicBezier(referenced?.$value);
|
|
2828
|
-
if (resolved) return resolved;
|
|
2829
|
-
}
|
|
2830
|
-
}
|
|
2831
|
-
return fallback;
|
|
3154
|
+
function gradientStopKey(stop, fallback) {
|
|
3155
|
+
return `stop|${stop["position"] ?? fallback}|${JSON.stringify(stop["color"])}`;
|
|
2832
3156
|
}
|
|
2833
|
-
|
|
3157
|
+
//#endregion
|
|
3158
|
+
//#region src/token-detail/CompositePreview.tsx
|
|
3159
|
+
const PANGRAM = "Sphinx of black quartz, judge my vow.";
|
|
3160
|
+
const STROKE_STYLE_STRINGS = new Set([
|
|
3161
|
+
"solid",
|
|
3162
|
+
"dashed",
|
|
3163
|
+
"dotted",
|
|
3164
|
+
"double",
|
|
3165
|
+
"groove",
|
|
3166
|
+
"ridge",
|
|
3167
|
+
"outset",
|
|
3168
|
+
"inset"
|
|
3169
|
+
]);
|
|
3170
|
+
function CompositePreview({ path }) {
|
|
3171
|
+
const { token, cssVar } = useTokenDetailData(path);
|
|
2834
3172
|
if (!token) return null;
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
durationMs: asDuration(v.duration, themeTokens, DEFAULT_DURATION_MS),
|
|
2840
|
-
easing: asEasing(v.timingFunction, themeTokens, DEFAULT_EASING)
|
|
2841
|
-
};
|
|
2842
|
-
}
|
|
2843
|
-
if (type === "duration") {
|
|
2844
|
-
const durationMs = extractDurationMs(token.$value);
|
|
2845
|
-
if (!Number.isFinite(durationMs)) return null;
|
|
2846
|
-
return {
|
|
2847
|
-
durationMs,
|
|
2848
|
-
easing: DEFAULT_EASING
|
|
2849
|
-
};
|
|
2850
|
-
}
|
|
2851
|
-
if (type === "cubicBezier") {
|
|
2852
|
-
const easing = extractCubicBezier(token.$value);
|
|
2853
|
-
if (!easing) return null;
|
|
2854
|
-
return {
|
|
2855
|
-
durationMs: DEFAULT_DURATION_MS,
|
|
2856
|
-
easing
|
|
2857
|
-
};
|
|
2858
|
-
}
|
|
2859
|
-
return null;
|
|
2860
|
-
}
|
|
2861
|
-
function MotionSample({ path, speed = 1, runKey = 0 }) {
|
|
2862
|
-
const { resolved } = useProject();
|
|
2863
|
-
const reducedMotion = usePrefersReducedMotion();
|
|
2864
|
-
const spec = useMemo(() => resolveMotionSpec(resolved[path], resolved), [resolved, path]);
|
|
2865
|
-
const durationMs = spec?.durationMs ?? DEFAULT_DURATION_MS;
|
|
2866
|
-
const easing = spec?.easing ?? DEFAULT_EASING;
|
|
2867
|
-
const scaledDuration = Math.max(1, durationMs / speed);
|
|
2868
|
-
const [phase, setPhase] = useState(0);
|
|
2869
|
-
useEffect(() => {
|
|
2870
|
-
if (reducedMotion) return;
|
|
2871
|
-
setPhase(0);
|
|
2872
|
-
const id = requestAnimationFrame(() => setPhase(1));
|
|
2873
|
-
const loop = window.setInterval(() => {
|
|
2874
|
-
setPhase((p) => p === 0 ? 1 : 0);
|
|
2875
|
-
}, scaledDuration * 2);
|
|
2876
|
-
return () => {
|
|
2877
|
-
cancelAnimationFrame(id);
|
|
2878
|
-
window.clearInterval(loop);
|
|
2879
|
-
};
|
|
2880
|
-
}, [
|
|
2881
|
-
scaledDuration,
|
|
2882
|
-
runKey,
|
|
2883
|
-
reducedMotion
|
|
2884
|
-
]);
|
|
2885
|
-
if (reducedMotion) return /* @__PURE__ */ jsx("div", {
|
|
2886
|
-
style: styles.reducedMotion,
|
|
2887
|
-
children: "Animation suppressed by `prefers-reduced-motion: reduce`."
|
|
3173
|
+
return /* @__PURE__ */ jsx(CompositePreviewContent, {
|
|
3174
|
+
type: token.$type,
|
|
3175
|
+
cssVar,
|
|
3176
|
+
rawValue: token.$value
|
|
2888
3177
|
});
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
3178
|
+
}
|
|
3179
|
+
function CompositePreviewContent({ type, cssVar, rawValue }) {
|
|
3180
|
+
if (type === "typography") {
|
|
3181
|
+
const base = cssVar.replace(/^var\(/, "").replace(/\)$/, "");
|
|
3182
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3183
|
+
className: "sb-token-detail__typography-sample",
|
|
2892
3184
|
style: {
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
3185
|
+
fontFamily: `var(${base}-font-family)`,
|
|
3186
|
+
fontSize: `var(${base}-font-size)`,
|
|
3187
|
+
fontWeight: `var(${base}-font-weight)`,
|
|
3188
|
+
lineHeight: `var(${base}-line-height)`,
|
|
3189
|
+
letterSpacing: `var(${base}-letter-spacing)`
|
|
2896
3190
|
},
|
|
2897
|
-
|
|
2898
|
-
})
|
|
2899
|
-
});
|
|
2900
|
-
}
|
|
2901
|
-
//#endregion
|
|
2902
|
-
//#region src/MotionPreview.tsx
|
|
2903
|
-
const SPEEDS = [
|
|
2904
|
-
.25,
|
|
2905
|
-
.5,
|
|
2906
|
-
1,
|
|
2907
|
-
2
|
|
2908
|
-
];
|
|
2909
|
-
function formatSpec(row) {
|
|
2910
|
-
switch (row.kind) {
|
|
2911
|
-
case "transition": return `transition · ${Math.round(row.durationMs)}ms · ${row.easing}`;
|
|
2912
|
-
case "duration": return `duration · ${Math.round(row.durationMs)}ms`;
|
|
2913
|
-
case "cubicBezier": return `cubicBezier · ${row.easing}`;
|
|
2914
|
-
}
|
|
2915
|
-
}
|
|
2916
|
-
function MotionPreview({ filter, caption }) {
|
|
2917
|
-
const { resolved, activeTheme, cssVarPrefix } = useProject();
|
|
2918
|
-
const [speed, setSpeed] = useState(1);
|
|
2919
|
-
const [run, setRun] = useState(0);
|
|
2920
|
-
const reducedMotion = usePrefersReducedMotion();
|
|
2921
|
-
const rows = useMemo(() => {
|
|
2922
|
-
const collected = [];
|
|
2923
|
-
for (const [path, token] of Object.entries(resolved)) {
|
|
2924
|
-
if (filter && !globMatch(path, filter)) continue;
|
|
2925
|
-
if (!filter && ![
|
|
2926
|
-
"transition",
|
|
2927
|
-
"duration",
|
|
2928
|
-
"cubicBezier"
|
|
2929
|
-
].includes(token.$type ?? "")) continue;
|
|
2930
|
-
const kind = token.$type;
|
|
2931
|
-
if (!kind) continue;
|
|
2932
|
-
const spec = resolveMotionSpec(token, resolved);
|
|
2933
|
-
if (!spec) continue;
|
|
2934
|
-
collected.push({
|
|
2935
|
-
path,
|
|
2936
|
-
cssVar: makeCssVar(path, cssVarPrefix),
|
|
2937
|
-
durationMs: spec.durationMs,
|
|
2938
|
-
easing: spec.easing,
|
|
2939
|
-
kind
|
|
2940
|
-
});
|
|
2941
|
-
}
|
|
2942
|
-
collected.sort((a, b) => {
|
|
2943
|
-
if (a.kind !== b.kind) return a.kind.localeCompare(b.kind);
|
|
2944
|
-
return a.path.localeCompare(b.path, void 0, { numeric: true });
|
|
3191
|
+
children: PANGRAM
|
|
2945
3192
|
});
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2952
|
-
|
|
2953
|
-
|
|
2954
|
-
|
|
3193
|
+
}
|
|
3194
|
+
if (type === "shadow") return /* @__PURE__ */ jsx("div", {
|
|
3195
|
+
className: "sb-token-detail__shadow-sample",
|
|
3196
|
+
style: { boxShadow: cssVar },
|
|
3197
|
+
"aria-hidden": true
|
|
3198
|
+
});
|
|
3199
|
+
if (type === "border") return /* @__PURE__ */ jsx("div", {
|
|
3200
|
+
className: "sb-token-detail__border-sample",
|
|
3201
|
+
style: { border: cssVar },
|
|
3202
|
+
"aria-hidden": true
|
|
3203
|
+
});
|
|
3204
|
+
if (type === "transition") return /* @__PURE__ */ jsx(TransitionSample, { transition: cssVar });
|
|
3205
|
+
if (type === "dimension") return /* @__PURE__ */ jsx("div", {
|
|
3206
|
+
className: "sb-token-detail__dimension-track",
|
|
2955
3207
|
children: /* @__PURE__ */ jsx("div", {
|
|
2956
|
-
className: "sb-
|
|
2957
|
-
|
|
3208
|
+
className: "sb-token-detail__dimension-bar",
|
|
3209
|
+
style: { width: cssVar },
|
|
3210
|
+
"aria-hidden": true
|
|
2958
3211
|
})
|
|
2959
3212
|
});
|
|
2960
|
-
return /* @__PURE__ */
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
|
|
2965
|
-
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
|
|
2975
|
-
|
|
2976
|
-
className: cx("sb-motion-preview__speed-btn", { "sb-motion-preview__speed-btn--active": s === speed }),
|
|
2977
|
-
onClick: () => setSpeed(s),
|
|
2978
|
-
children: [s, "×"]
|
|
2979
|
-
}, s)),
|
|
2980
|
-
/* @__PURE__ */ jsx("button", {
|
|
2981
|
-
type: "button",
|
|
2982
|
-
className: "sb-motion-preview__replay-btn",
|
|
2983
|
-
onClick: () => setRun((n) => n + 1),
|
|
2984
|
-
disabled: reducedMotion,
|
|
2985
|
-
title: reducedMotion ? "Disabled by prefers-reduced-motion" : "Replay all",
|
|
2986
|
-
children: "↻ Replay"
|
|
2987
|
-
})
|
|
2988
|
-
]
|
|
2989
|
-
}),
|
|
2990
|
-
rows.map((row) => /* @__PURE__ */ jsxs("div", {
|
|
2991
|
-
className: "sb-motion-preview__row",
|
|
2992
|
-
children: [
|
|
2993
|
-
/* @__PURE__ */ jsxs("div", {
|
|
2994
|
-
className: "sb-motion-preview__meta",
|
|
2995
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
2996
|
-
className: "sb-motion-preview__path",
|
|
2997
|
-
children: row.path
|
|
2998
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
2999
|
-
className: "sb-motion-preview__specs",
|
|
3000
|
-
children: formatSpec(row)
|
|
3001
|
-
})]
|
|
3002
|
-
}),
|
|
3003
|
-
/* @__PURE__ */ jsx(MotionSample, {
|
|
3004
|
-
path: row.path,
|
|
3005
|
-
speed,
|
|
3006
|
-
runKey: run
|
|
3007
|
-
}),
|
|
3008
|
-
/* @__PURE__ */ jsx("span", {
|
|
3009
|
-
className: "sb-motion-preview__css-var",
|
|
3010
|
-
children: row.cssVar
|
|
3011
|
-
})
|
|
3012
|
-
]
|
|
3013
|
-
}, row.path))
|
|
3014
|
-
]
|
|
3213
|
+
if (type === "duration") return /* @__PURE__ */ jsx(TransitionSample, { transition: `left ${cssVar} ease` });
|
|
3214
|
+
if (type === "fontFamily") return /* @__PURE__ */ jsx("div", {
|
|
3215
|
+
className: "sb-token-detail__font-family-sample",
|
|
3216
|
+
style: { fontFamily: cssVar },
|
|
3217
|
+
children: PANGRAM
|
|
3218
|
+
});
|
|
3219
|
+
if (type === "fontWeight") return /* @__PURE__ */ jsx("div", {
|
|
3220
|
+
className: "sb-token-detail__font-weight-sample",
|
|
3221
|
+
style: { fontWeight: cssVar },
|
|
3222
|
+
children: "Aa"
|
|
3223
|
+
});
|
|
3224
|
+
if (type === "cubicBezier") return /* @__PURE__ */ jsx(TransitionSample, { transition: `left 800ms ${cssVar}` });
|
|
3225
|
+
if (type === "gradient") return /* @__PURE__ */ jsx("div", {
|
|
3226
|
+
className: "sb-token-detail__gradient-sample",
|
|
3227
|
+
style: { background: `linear-gradient(to right, ${cssVar})` },
|
|
3228
|
+
"aria-hidden": true
|
|
3015
3229
|
});
|
|
3016
|
-
}
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
*/
|
|
3028
|
-
function SwatchbookProvider({ value, children }) {
|
|
3029
|
-
return /* @__PURE__ */ jsx(SwatchbookContext.Provider, {
|
|
3030
|
-
value,
|
|
3031
|
-
children
|
|
3230
|
+
if (type === "strokeStyle") return /* @__PURE__ */ jsx(StrokeStylePreview, { value: rawValue });
|
|
3231
|
+
if (type === "color") return /* @__PURE__ */ jsxs("div", {
|
|
3232
|
+
className: "sb-token-detail__color-swatch-row",
|
|
3233
|
+
"aria-hidden": true,
|
|
3234
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
3235
|
+
className: "sb-token-detail__color-swatch-light",
|
|
3236
|
+
style: { background: cssVar }
|
|
3237
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
3238
|
+
className: "sb-token-detail__color-swatch-dark",
|
|
3239
|
+
style: { background: cssVar }
|
|
3240
|
+
})]
|
|
3032
3241
|
});
|
|
3242
|
+
return null;
|
|
3033
3243
|
}
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
*/
|
|
3039
|
-
function useSwatchbookData() {
|
|
3040
|
-
const value = useOptionalSwatchbookData();
|
|
3041
|
-
if (!value) throw new Error("[swatchbook-blocks] useSwatchbookData() called outside <SwatchbookProvider>. Wrap your tree in <SwatchbookProvider value={snapshot}> or render inside a Storybook story.");
|
|
3042
|
-
return value;
|
|
3043
|
-
}
|
|
3044
|
-
//#endregion
|
|
3045
|
-
//#region src/shadow-preview/ShadowSample.tsx
|
|
3046
|
-
const sampleStyle = {
|
|
3047
|
-
width: 120,
|
|
3048
|
-
height: 56,
|
|
3049
|
-
background: SURFACE_RAISED,
|
|
3050
|
-
border: BORDER_FAINT,
|
|
3051
|
-
borderRadius: 6
|
|
3052
|
-
};
|
|
3053
|
-
function ShadowSample({ path }) {
|
|
3054
|
-
const { cssVarPrefix } = useProject();
|
|
3055
|
-
const cssVar = makeCssVar(path, cssVarPrefix);
|
|
3056
|
-
return /* @__PURE__ */ jsx("div", {
|
|
3057
|
-
style: {
|
|
3058
|
-
...sampleStyle,
|
|
3059
|
-
boxShadow: cssVar
|
|
3060
|
-
},
|
|
3244
|
+
function StrokeStylePreview({ value }) {
|
|
3245
|
+
if (typeof value === "string" && STROKE_STYLE_STRINGS.has(value)) return /* @__PURE__ */ jsx("div", {
|
|
3246
|
+
className: "sb-token-detail__stroke-style-line",
|
|
3247
|
+
style: { borderTopStyle: value },
|
|
3061
3248
|
"aria-hidden": true
|
|
3062
3249
|
});
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3071
|
-
|
|
3072
|
-
|
|
3250
|
+
if (value && typeof value === "object" && "dashArray" in value) {
|
|
3251
|
+
const v = value;
|
|
3252
|
+
const lengths = asDashLengths(v.dashArray);
|
|
3253
|
+
if (lengths.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
3254
|
+
className: "sb-token-detail__stroke-style-fallback",
|
|
3255
|
+
children: "Object-form strokeStyle with no resolvable dashArray."
|
|
3256
|
+
});
|
|
3257
|
+
const cap = typeof v.lineCap === "string" ? v.lineCap : "butt";
|
|
3258
|
+
return /* @__PURE__ */ jsx("svg", {
|
|
3259
|
+
className: "sb-token-detail__stroke-style-svg",
|
|
3260
|
+
viewBox: "0 0 220 24",
|
|
3261
|
+
preserveAspectRatio: "none",
|
|
3262
|
+
"aria-hidden": true,
|
|
3263
|
+
children: /* @__PURE__ */ jsx("line", {
|
|
3264
|
+
x1: "4",
|
|
3265
|
+
y1: "12",
|
|
3266
|
+
x2: "216",
|
|
3267
|
+
y2: "12",
|
|
3268
|
+
stroke: "currentColor",
|
|
3269
|
+
strokeWidth: "4",
|
|
3270
|
+
strokeDasharray: lengths.join(" "),
|
|
3271
|
+
strokeLinecap: cap
|
|
3272
|
+
})
|
|
3273
|
+
});
|
|
3073
3274
|
}
|
|
3074
|
-
return
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
return formatColor(raw, format).value;
|
|
3079
|
-
}
|
|
3080
|
-
function asLayers(raw) {
|
|
3081
|
-
if (Array.isArray(raw)) return raw;
|
|
3082
|
-
if (raw && typeof raw === "object") return [raw];
|
|
3083
|
-
return [];
|
|
3275
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3276
|
+
className: "sb-token-detail__stroke-style-fallback",
|
|
3277
|
+
children: "strokeStyle value could not be previewed."
|
|
3278
|
+
});
|
|
3084
3279
|
}
|
|
3085
|
-
function
|
|
3086
|
-
|
|
3280
|
+
function asDashLengths(raw) {
|
|
3281
|
+
if (!Array.isArray(raw)) return [];
|
|
3282
|
+
const out = [];
|
|
3283
|
+
for (const entry of raw) {
|
|
3284
|
+
if (typeof entry === "number") {
|
|
3285
|
+
out.push(entry);
|
|
3286
|
+
continue;
|
|
3287
|
+
}
|
|
3288
|
+
if (entry && typeof entry === "object") {
|
|
3289
|
+
const e = entry;
|
|
3290
|
+
if (typeof e.value === "number") out.push(e.value);
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
return out;
|
|
3087
3294
|
}
|
|
3088
|
-
function
|
|
3089
|
-
const
|
|
3090
|
-
const
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
sortDir
|
|
3109
|
-
]);
|
|
3110
|
-
const captionText = caption ?? `${rows.length} shadow${rows.length === 1 ? "" : "s"}${filter ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
3111
|
-
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
3112
|
-
...themeAttrs(cssVarPrefix, activeTheme),
|
|
3295
|
+
function TransitionSample({ transition }) {
|
|
3296
|
+
const reduced = usePrefersReducedMotion();
|
|
3297
|
+
const [phase, setPhase] = useState(0);
|
|
3298
|
+
useEffect(() => {
|
|
3299
|
+
if (reduced) return;
|
|
3300
|
+
const id = requestAnimationFrame(() => setPhase(1));
|
|
3301
|
+
const loop = window.setInterval(() => {
|
|
3302
|
+
setPhase((p) => p === 0 ? 1 : 0);
|
|
3303
|
+
}, 1200);
|
|
3304
|
+
return () => {
|
|
3305
|
+
cancelAnimationFrame(id);
|
|
3306
|
+
window.clearInterval(loop);
|
|
3307
|
+
};
|
|
3308
|
+
}, [reduced]);
|
|
3309
|
+
if (reduced) return /* @__PURE__ */ jsx("div", {
|
|
3310
|
+
className: "sb-token-detail__reduced-motion",
|
|
3311
|
+
children: "Animation suppressed by `prefers-reduced-motion: reduce`."
|
|
3312
|
+
});
|
|
3313
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3314
|
+
className: "sb-token-detail__motion-track",
|
|
3113
3315
|
children: /* @__PURE__ */ jsx("div", {
|
|
3114
|
-
className: "sb-
|
|
3115
|
-
|
|
3316
|
+
className: "sb-token-detail__motion-ball",
|
|
3317
|
+
style: {
|
|
3318
|
+
left: phase === 1 ? "calc(100% - 28px)" : "4px",
|
|
3319
|
+
transition
|
|
3320
|
+
},
|
|
3321
|
+
"aria-hidden": true
|
|
3116
3322
|
})
|
|
3117
3323
|
});
|
|
3324
|
+
}
|
|
3325
|
+
//#endregion
|
|
3326
|
+
//#region src/token-detail/ConsumerOutput.tsx
|
|
3327
|
+
function ConsumerOutput({ path }) {
|
|
3328
|
+
const { token, cssVar, activeAxes } = useTokenDetailData(path);
|
|
3329
|
+
if (!token) return null;
|
|
3330
|
+
const tupleLabel = Object.entries(activeAxes).map(([k, v]) => `${k}=${v}`).join(", ");
|
|
3331
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
3332
|
+
/* @__PURE__ */ jsx("div", {
|
|
3333
|
+
className: "sb-token-detail__section-header",
|
|
3334
|
+
children: "Consumer output"
|
|
3335
|
+
}),
|
|
3336
|
+
tupleLabel && /* @__PURE__ */ jsxs("div", {
|
|
3337
|
+
className: "sb-token-detail__tuple-indicator",
|
|
3338
|
+
children: ["Active tuple: ", /* @__PURE__ */ jsx("strong", { children: tupleLabel })]
|
|
3339
|
+
}),
|
|
3340
|
+
/* @__PURE__ */ jsx(OutputRow, {
|
|
3341
|
+
label: "Path",
|
|
3342
|
+
value: path,
|
|
3343
|
+
testId: "consumer-output-path"
|
|
3344
|
+
}),
|
|
3345
|
+
/* @__PURE__ */ jsx(OutputRow, {
|
|
3346
|
+
label: "CSS",
|
|
3347
|
+
value: cssVar,
|
|
3348
|
+
testId: "consumer-output-css"
|
|
3349
|
+
})
|
|
3350
|
+
] });
|
|
3351
|
+
}
|
|
3352
|
+
function OutputRow({ label, value, testId }) {
|
|
3118
3353
|
return /* @__PURE__ */ jsxs("div", {
|
|
3119
|
-
|
|
3120
|
-
children: [
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3354
|
+
className: "sb-token-detail__consumer-row",
|
|
3355
|
+
children: [
|
|
3356
|
+
/* @__PURE__ */ jsx("span", {
|
|
3357
|
+
className: "sb-token-detail__consumer-row-label",
|
|
3358
|
+
children: label
|
|
3359
|
+
}),
|
|
3360
|
+
/* @__PURE__ */ jsx("code", {
|
|
3361
|
+
className: "sb-token-detail__consumer-row-value",
|
|
3362
|
+
"data-testid": testId,
|
|
3363
|
+
children: value
|
|
3364
|
+
}),
|
|
3365
|
+
/* @__PURE__ */ jsx(CopyButton, {
|
|
3366
|
+
text: value,
|
|
3367
|
+
testId: `${testId}-copy`
|
|
3368
|
+
})
|
|
3369
|
+
]
|
|
3370
|
+
});
|
|
3371
|
+
}
|
|
3372
|
+
function CopyButton({ text, testId }) {
|
|
3373
|
+
const [copied, setCopied] = useState(false);
|
|
3374
|
+
return /* @__PURE__ */ jsx("button", {
|
|
3375
|
+
type: "button",
|
|
3376
|
+
className: "sb-token-detail__consumer-row-copy",
|
|
3377
|
+
"data-testid": testId,
|
|
3378
|
+
onClick: () => {
|
|
3379
|
+
copyToClipboard(text).then((ok) => {
|
|
3380
|
+
if (!ok) return;
|
|
3381
|
+
setCopied(true);
|
|
3382
|
+
window.setTimeout(() => setCopied(false), 1200);
|
|
3383
|
+
});
|
|
3384
|
+
},
|
|
3385
|
+
children: copied ? "Copied" : "Copy"
|
|
3151
3386
|
});
|
|
3152
3387
|
}
|
|
3153
|
-
function
|
|
3154
|
-
if (!
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
if (layer.inset) entries.push(["inset", String(layer.inset)]);
|
|
3162
|
-
return entries.flatMap(([k, v]) => [/* @__PURE__ */ jsx("span", {
|
|
3163
|
-
className: "sb-shadow-preview__breakdown-key",
|
|
3164
|
-
children: k
|
|
3165
|
-
}, `k-${k}`), /* @__PURE__ */ jsx("span", { children: v }, `v-${k}`)]);
|
|
3388
|
+
async function copyToClipboard(text) {
|
|
3389
|
+
if (typeof navigator === "undefined" || !navigator.clipboard) return false;
|
|
3390
|
+
try {
|
|
3391
|
+
await navigator.clipboard.writeText(text);
|
|
3392
|
+
return true;
|
|
3393
|
+
} catch {
|
|
3394
|
+
return false;
|
|
3395
|
+
}
|
|
3166
3396
|
}
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
children: renderLayer(layer, colorFormat)
|
|
3181
|
-
})]
|
|
3397
|
+
//#endregion
|
|
3398
|
+
//#region src/token-detail/TokenHeader.tsx
|
|
3399
|
+
function TokenHeader({ path, heading }) {
|
|
3400
|
+
const { token, cssVar, activeTheme } = useTokenDetailData(path);
|
|
3401
|
+
if (!token) return /* @__PURE__ */ jsxs("div", {
|
|
3402
|
+
className: "sb-token-detail__missing",
|
|
3403
|
+
children: [
|
|
3404
|
+
"Token ",
|
|
3405
|
+
/* @__PURE__ */ jsx("code", { children: path }),
|
|
3406
|
+
" not found in theme ",
|
|
3407
|
+
/* @__PURE__ */ jsx("strong", { children: activeTheme }),
|
|
3408
|
+
"."
|
|
3409
|
+
]
|
|
3182
3410
|
});
|
|
3411
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
3412
|
+
/* @__PURE__ */ jsx("h3", {
|
|
3413
|
+
className: "sb-token-detail__heading",
|
|
3414
|
+
children: heading ?? path
|
|
3415
|
+
}),
|
|
3416
|
+
/* @__PURE__ */ jsxs("div", {
|
|
3417
|
+
className: "sb-token-detail__subline",
|
|
3418
|
+
children: [token.$type && /* @__PURE__ */ jsx("span", {
|
|
3419
|
+
className: "sb-token-detail__type-pill",
|
|
3420
|
+
children: token.$type
|
|
3421
|
+
}), /* @__PURE__ */ jsx("span", { children: cssVar })]
|
|
3422
|
+
}),
|
|
3423
|
+
token.$description && /* @__PURE__ */ jsx("p", {
|
|
3424
|
+
className: "sb-token-detail__description",
|
|
3425
|
+
children: token.$description
|
|
3426
|
+
})
|
|
3427
|
+
] });
|
|
3183
3428
|
}
|
|
3184
3429
|
//#endregion
|
|
3185
|
-
//#region src/
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
"
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
"
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3430
|
+
//#region src/token-detail/TokenUsageSnippet.tsx
|
|
3431
|
+
function TokenUsageSnippet({ path }) {
|
|
3432
|
+
const { token, cssVar } = useTokenDetailData(path);
|
|
3433
|
+
if (!token) return null;
|
|
3434
|
+
const snippet = `color: ${cssVar};`;
|
|
3435
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("div", {
|
|
3436
|
+
className: "sb-token-detail__section-header",
|
|
3437
|
+
children: "Usage"
|
|
3438
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
3439
|
+
className: "sb-token-detail__snippet-row",
|
|
3440
|
+
children: [/* @__PURE__ */ jsx("code", {
|
|
3441
|
+
className: "sb-token-detail__snippet",
|
|
3442
|
+
children: snippet
|
|
3443
|
+
}), /* @__PURE__ */ jsx(CopyButton$1, {
|
|
3444
|
+
value: snippet,
|
|
3445
|
+
label: `Copy usage snippet ${snippet}`
|
|
3446
|
+
})]
|
|
3447
|
+
})] });
|
|
3199
3448
|
}
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
cssVarPrefix,
|
|
3219
|
-
sortBy,
|
|
3220
|
-
sortDir
|
|
3221
|
-
]);
|
|
3222
|
-
const captionText = caption ?? `${rows.length} strokeStyle token${rows.length === 1 ? "" : "s"}${filter && filter !== "strokeStyle" ? ` matching \`${filter}\`` : ""} · ${activeTheme}`;
|
|
3223
|
-
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
3224
|
-
...themeAttrs(cssVarPrefix, activeTheme),
|
|
3225
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
3226
|
-
className: "sb-block__empty",
|
|
3227
|
-
children: "No strokeStyle tokens match this filter."
|
|
3449
|
+
//#endregion
|
|
3450
|
+
//#region src/TokenDetail.tsx
|
|
3451
|
+
function TokenDetail({ path, heading }) {
|
|
3452
|
+
const { token, cssVar, activeTheme, cssVarPrefix } = useTokenDetailData(path);
|
|
3453
|
+
const colorFormat = useColorFormat();
|
|
3454
|
+
const theme = themeAttrs(cssVarPrefix, activeTheme);
|
|
3455
|
+
if (!token) return /* @__PURE__ */ jsx("div", {
|
|
3456
|
+
...theme,
|
|
3457
|
+
className: cx(theme["className"], "sb-token-detail"),
|
|
3458
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
3459
|
+
className: "sb-token-detail__missing",
|
|
3460
|
+
children: [
|
|
3461
|
+
"Token ",
|
|
3462
|
+
/* @__PURE__ */ jsx("code", { children: path }),
|
|
3463
|
+
" not found in theme ",
|
|
3464
|
+
/* @__PURE__ */ jsx("strong", { children: activeTheme }),
|
|
3465
|
+
"."
|
|
3466
|
+
]
|
|
3228
3467
|
})
|
|
3229
3468
|
});
|
|
3469
|
+
const { listing } = useProject();
|
|
3470
|
+
const isColor = token.$type === "color";
|
|
3471
|
+
const gamut = isColor ? formatColor(token.$value, colorFormat) : null;
|
|
3472
|
+
const value = formatTokenValue(token.$value, token.$type, colorFormat, listing[path]);
|
|
3473
|
+
const outOfGamut = gamut?.outOfGamut ?? false;
|
|
3230
3474
|
return /* @__PURE__ */ jsxs("div", {
|
|
3231
|
-
...
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3475
|
+
...theme,
|
|
3476
|
+
className: cx(theme["className"], "sb-token-detail"),
|
|
3477
|
+
children: [
|
|
3478
|
+
/* @__PURE__ */ jsx(TokenHeader, {
|
|
3479
|
+
path,
|
|
3480
|
+
...heading !== void 0 && { heading }
|
|
3481
|
+
}),
|
|
3482
|
+
/* @__PURE__ */ jsxs("div", {
|
|
3483
|
+
className: "sb-token-detail__section-header",
|
|
3484
|
+
children: ["Resolved value · ", activeTheme]
|
|
3485
|
+
}),
|
|
3486
|
+
/* @__PURE__ */ jsx(CompositePreview, { path }),
|
|
3487
|
+
/* @__PURE__ */ jsx(CompositeBreakdown, { path }),
|
|
3488
|
+
/* @__PURE__ */ jsxs("div", {
|
|
3489
|
+
className: "sb-token-detail__chain",
|
|
3490
|
+
children: [
|
|
3491
|
+
isColor && /* @__PURE__ */ jsx("span", {
|
|
3492
|
+
className: "sb-token-detail__swatch",
|
|
3493
|
+
style: { background: cssVar },
|
|
3494
|
+
"aria-hidden": true
|
|
3495
|
+
}),
|
|
3496
|
+
/* @__PURE__ */ jsx("span", { children: value }),
|
|
3497
|
+
outOfGamut && /* @__PURE__ */ jsx("span", {
|
|
3498
|
+
title: "Out of sRGB gamut for this format",
|
|
3499
|
+
"aria-label": "out of gamut",
|
|
3500
|
+
style: { marginLeft: 6 },
|
|
3501
|
+
children: "⚠"
|
|
3502
|
+
}),
|
|
3503
|
+
/* @__PURE__ */ jsx(CopyButton$1, {
|
|
3504
|
+
value,
|
|
3505
|
+
label: `Copy value ${value}`
|
|
3506
|
+
})
|
|
3507
|
+
]
|
|
3508
|
+
}),
|
|
3509
|
+
/* @__PURE__ */ jsx(AliasChain, { path }),
|
|
3510
|
+
/* @__PURE__ */ jsx(AliasedBy, { path }),
|
|
3511
|
+
/* @__PURE__ */ jsx(TokenUsageSnippet, { path }),
|
|
3512
|
+
/* @__PURE__ */ jsx(ConsumerOutput, { path }),
|
|
3513
|
+
/* @__PURE__ */ jsx(AxisVariance, { path })
|
|
3514
|
+
]
|
|
3515
|
+
});
|
|
3516
|
+
}
|
|
3517
|
+
//#endregion
|
|
3518
|
+
//#region src/internal/DetailOverlay.tsx
|
|
3519
|
+
function DetailOverlay({ path, onClose, testId = "swatchbook-overlay" }) {
|
|
3520
|
+
useEffect(() => {
|
|
3521
|
+
const onKey = (e) => {
|
|
3522
|
+
if (e.key === "Escape") onClose();
|
|
3523
|
+
};
|
|
3524
|
+
window.addEventListener("keydown", onKey);
|
|
3525
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
3526
|
+
}, [onClose]);
|
|
3527
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3528
|
+
className: "sb-detail-overlay__backdrop",
|
|
3529
|
+
onClick: onClose,
|
|
3530
|
+
role: "presentation",
|
|
3531
|
+
"data-testid": testId,
|
|
3532
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
3533
|
+
className: "sb-detail-overlay__panel",
|
|
3534
|
+
onClick: (e) => e.stopPropagation(),
|
|
3535
|
+
role: "dialog",
|
|
3536
|
+
"aria-modal": "true",
|
|
3537
|
+
"aria-label": `Token detail for ${path}`,
|
|
3538
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
3539
|
+
type: "button",
|
|
3540
|
+
className: "sb-detail-overlay__close",
|
|
3541
|
+
onClick: onClose,
|
|
3542
|
+
"aria-label": "Close",
|
|
3543
|
+
"data-testid": `${testId}-close`,
|
|
3544
|
+
children: "×"
|
|
3545
|
+
}), /* @__PURE__ */ jsx(TokenDetail, { path })]
|
|
3546
|
+
})
|
|
3262
3547
|
});
|
|
3263
3548
|
}
|
|
3264
3549
|
//#endregion
|
|
@@ -3567,16 +3852,16 @@ function LeafRow({ node, onLeafClick }) {
|
|
|
3567
3852
|
});
|
|
3568
3853
|
}
|
|
3569
3854
|
function LeafPreview({ path, token }) {
|
|
3570
|
-
const
|
|
3855
|
+
const project = useProject();
|
|
3571
3856
|
const colorFormat = useColorFormat();
|
|
3572
3857
|
const type = token.$type;
|
|
3573
3858
|
if (type === "color") {
|
|
3574
|
-
const cssVar =
|
|
3859
|
+
const cssVar = resolveCssVar(path, project);
|
|
3575
3860
|
return /* @__PURE__ */ jsxs("span", {
|
|
3576
3861
|
className: "sb-token-navigator__preview-box",
|
|
3577
3862
|
children: [/* @__PURE__ */ jsx("span", {
|
|
3578
3863
|
className: "sb-token-navigator__value",
|
|
3579
|
-
children: formatTokenValue(token.$value, type, colorFormat)
|
|
3864
|
+
children: formatTokenValue(token.$value, type, colorFormat, project.listing[path])
|
|
3580
3865
|
}), /* @__PURE__ */ jsx("span", {
|
|
3581
3866
|
className: "sb-token-navigator__color-swatch",
|
|
3582
3867
|
style: { background: cssVar },
|
|
@@ -3588,7 +3873,7 @@ function LeafPreview({ path, token }) {
|
|
|
3588
3873
|
className: "sb-token-navigator__preview-box",
|
|
3589
3874
|
children: [/* @__PURE__ */ jsx("span", {
|
|
3590
3875
|
className: "sb-token-navigator__value",
|
|
3591
|
-
children: formatTokenValue(token.$value, type, colorFormat)
|
|
3876
|
+
children: formatTokenValue(token.$value, type, colorFormat, project.listing[path])
|
|
3592
3877
|
}), /* @__PURE__ */ jsx("span", {
|
|
3593
3878
|
className: "sb-token-navigator__preview-dimension",
|
|
3594
3879
|
children: /* @__PURE__ */ jsx(DimensionBar, {
|
|
@@ -3622,14 +3907,15 @@ function LeafPreview({ path, token }) {
|
|
|
3622
3907
|
className: "sb-token-navigator__preview-box",
|
|
3623
3908
|
children: /* @__PURE__ */ jsx("span", {
|
|
3624
3909
|
className: "sb-token-navigator__value",
|
|
3625
|
-
children: formatTokenValue(token.$value, type, colorFormat)
|
|
3910
|
+
children: formatTokenValue(token.$value, type, colorFormat, project.listing[path])
|
|
3626
3911
|
})
|
|
3627
3912
|
});
|
|
3628
3913
|
}
|
|
3629
3914
|
//#endregion
|
|
3630
3915
|
//#region src/TokenTable.tsx
|
|
3631
3916
|
function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect }) {
|
|
3632
|
-
const
|
|
3917
|
+
const project = useProject();
|
|
3918
|
+
const { resolved, activeTheme, cssVarPrefix } = project;
|
|
3633
3919
|
const colorFormat = useColorFormat();
|
|
3634
3920
|
const [selectedPath, setSelectedPath] = useState(null);
|
|
3635
3921
|
const [query, setQuery] = useState("");
|
|
@@ -3643,13 +3929,13 @@ function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", s
|
|
|
3643
3929
|
dir: sortDir
|
|
3644
3930
|
}).map(([path, token]) => {
|
|
3645
3931
|
const isColor = token.$type === "color";
|
|
3646
|
-
const color = isColor ?
|
|
3932
|
+
const color = isColor ? resolveColorValue(path, token.$value, colorFormat, project) : null;
|
|
3647
3933
|
return {
|
|
3648
3934
|
path,
|
|
3649
3935
|
type: token.$type ?? "",
|
|
3650
|
-
value: formatTokenValue(token.$value, token.$type, colorFormat),
|
|
3936
|
+
value: formatTokenValue(token.$value, token.$type, colorFormat, project.listing[path]),
|
|
3651
3937
|
outOfGamut: color?.outOfGamut ?? false,
|
|
3652
|
-
cssVar:
|
|
3938
|
+
cssVar: resolveCssVar(path, project),
|
|
3653
3939
|
isColor
|
|
3654
3940
|
};
|
|
3655
3941
|
});
|
|
@@ -3657,7 +3943,7 @@ function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", s
|
|
|
3657
3943
|
resolved,
|
|
3658
3944
|
filter,
|
|
3659
3945
|
type,
|
|
3660
|
-
|
|
3946
|
+
project,
|
|
3661
3947
|
colorFormat,
|
|
3662
3948
|
sortBy,
|
|
3663
3949
|
sortDir
|