@unpunnyfuns/swatchbook-blocks 0.62.2 → 0.62.4
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 +17 -3
- package/dist/index.mjs +89 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.d.mts
CHANGED
|
@@ -271,6 +271,8 @@ interface ColorTableProps {
|
|
|
271
271
|
* own row.
|
|
272
272
|
*/
|
|
273
273
|
variants?: Record<string, string>;
|
|
274
|
+
/** Disambiguates persisted UI state for two identical-prop tables on a page. */
|
|
275
|
+
id?: string;
|
|
274
276
|
}
|
|
275
277
|
declare function ColorTable({
|
|
276
278
|
filter,
|
|
@@ -279,7 +281,8 @@ declare function ColorTable({
|
|
|
279
281
|
sortDir,
|
|
280
282
|
searchable,
|
|
281
283
|
onSelect,
|
|
282
|
-
variants
|
|
284
|
+
variants,
|
|
285
|
+
id
|
|
283
286
|
}: ColorTableProps): ReactElement;
|
|
284
287
|
//#endregion
|
|
285
288
|
//#region src/Diagnostics.d.ts
|
|
@@ -789,13 +792,21 @@ interface TokenNavigatorProps {
|
|
|
789
792
|
* the follow-up UI.
|
|
790
793
|
*/
|
|
791
794
|
onSelect?(path: string): void;
|
|
795
|
+
/**
|
|
796
|
+
* Disambiguates persisted UI state (expand/collapse, selection, search)
|
|
797
|
+
* when two navigators with otherwise-identical props sit on the same docs
|
|
798
|
+
* page. Only needed in that case; the state key is derived from the other
|
|
799
|
+
* props otherwise.
|
|
800
|
+
*/
|
|
801
|
+
id?: string;
|
|
792
802
|
}
|
|
793
803
|
declare function TokenNavigator({
|
|
794
804
|
root,
|
|
795
805
|
type,
|
|
796
806
|
initiallyExpanded,
|
|
797
807
|
searchable,
|
|
798
|
-
onSelect
|
|
808
|
+
onSelect,
|
|
809
|
+
id
|
|
799
810
|
}: TokenNavigatorProps): ReactElement;
|
|
800
811
|
//#endregion
|
|
801
812
|
//#region src/TokenTable.d.ts
|
|
@@ -836,6 +847,8 @@ interface TokenTableProps {
|
|
|
836
847
|
* follow-up UI (inline panel, drill-down route, …).
|
|
837
848
|
*/
|
|
838
849
|
onSelect?(path: string): void;
|
|
850
|
+
/** Disambiguates persisted UI state for two identical-prop tables on a page. */
|
|
851
|
+
id?: string;
|
|
839
852
|
}
|
|
840
853
|
declare function TokenTable({
|
|
841
854
|
filter,
|
|
@@ -844,7 +857,8 @@ declare function TokenTable({
|
|
|
844
857
|
sortBy,
|
|
845
858
|
sortDir,
|
|
846
859
|
searchable,
|
|
847
|
-
onSelect
|
|
860
|
+
onSelect,
|
|
861
|
+
id
|
|
848
862
|
}: TokenTableProps): ReactElement;
|
|
849
863
|
//#endregion
|
|
850
864
|
//#region src/TypographyScale.d.ts
|
package/dist/index.mjs
CHANGED
|
@@ -809,16 +809,73 @@ function CopyButton$1({ value, label, variant = "icon", className }) {
|
|
|
809
809
|
})] });
|
|
810
810
|
}
|
|
811
811
|
//#endregion
|
|
812
|
+
//#region src/internal/persistent-state.ts
|
|
813
|
+
/**
|
|
814
|
+
* Block UI state that survives a docs-mode remount.
|
|
815
|
+
*
|
|
816
|
+
* In MDX docs mode Storybook re-renders the docs container on every
|
|
817
|
+
* `updateGlobals` (axis flip), which unmounts and remounts the embedded
|
|
818
|
+
* blocks — destroying any plain `useState` (expand/collapse, selection,
|
|
819
|
+
* search). This is the same problem `channel-globals` solves for the
|
|
820
|
+
* globals: lift the value out of React into module state so it persists
|
|
821
|
+
* across the remount, and re-seed component state from it on mount.
|
|
822
|
+
*
|
|
823
|
+
* `usePersistedState` is a drop-in `useState` whose value is mirrored to a
|
|
824
|
+
* module-level store under a caller-supplied key, and read back from it on
|
|
825
|
+
* (re)mount. `useBlockKey` builds a stable key scoped to the current docs
|
|
826
|
+
* page + block identity so two pages (or two distinct blocks) don't share
|
|
827
|
+
* an entry.
|
|
828
|
+
*/
|
|
829
|
+
const store = /* @__PURE__ */ new Map();
|
|
830
|
+
function pageScope() {
|
|
831
|
+
if (typeof window === "undefined") return "";
|
|
832
|
+
try {
|
|
833
|
+
return new URLSearchParams(window.location.search).get("id") ?? window.location.pathname;
|
|
834
|
+
} catch {
|
|
835
|
+
return "";
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
const SEP = "";
|
|
839
|
+
/**
|
|
840
|
+
* Build a stable persistence key for a block's UI state: docs page + block
|
|
841
|
+
* type + the props that distinguish one instance from another (and an
|
|
842
|
+
* optional explicit `id` for identical-prop siblings on the same page).
|
|
843
|
+
*/
|
|
844
|
+
function useBlockKey(blockType, parts) {
|
|
845
|
+
const partsKey = parts.map((p) => p === void 0 ? "" : String(p)).join(SEP);
|
|
846
|
+
return useMemo(() => `${pageScope()}${SEP}${blockType}${SEP}${partsKey}`, [blockType, partsKey]);
|
|
847
|
+
}
|
|
848
|
+
/**
|
|
849
|
+
* `useState`, but the value persists across remounts under `key`. `initial`
|
|
850
|
+
* may be a value or a lazy initializer (used only on the first mount when the
|
|
851
|
+
* store has no entry yet — never an actual `T` that's a function here).
|
|
852
|
+
*/
|
|
853
|
+
function usePersistedState(key, initial) {
|
|
854
|
+
const [value, setValue] = useState(() => {
|
|
855
|
+
if (store.has(key)) return store.get(key);
|
|
856
|
+
return typeof initial === "function" ? initial() : initial;
|
|
857
|
+
});
|
|
858
|
+
useEffect(() => {
|
|
859
|
+
store.set(key, value);
|
|
860
|
+
}, [key, value]);
|
|
861
|
+
return [value, setValue];
|
|
862
|
+
}
|
|
863
|
+
//#endregion
|
|
812
864
|
//#region src/ColorTable.tsx
|
|
813
865
|
const BASE_LABEL = "base";
|
|
814
866
|
const COLUMN_COUNT = 6;
|
|
815
|
-
function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect, variants }) {
|
|
867
|
+
function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect, variants, id }) {
|
|
816
868
|
const { resolved, activeTheme, activeAxes, cssVarPrefix, listing } = useProject();
|
|
817
869
|
const colorFormat = useColorFormat();
|
|
818
|
-
const
|
|
870
|
+
const blockKey = useBlockKey("ColorTable", [
|
|
871
|
+
filter,
|
|
872
|
+
caption,
|
|
873
|
+
id
|
|
874
|
+
]);
|
|
875
|
+
const [query, setQuery] = usePersistedState(`${blockKey}::query`, "");
|
|
819
876
|
const deferredQuery = useDeferredValue(query);
|
|
820
|
-
const [selectedByBase, setSelectedByBase] =
|
|
821
|
-
const [expandedByBase, setExpandedByBase] =
|
|
877
|
+
const [selectedByBase, setSelectedByBase] = usePersistedState(`${blockKey}::selected`, {});
|
|
878
|
+
const [expandedByBase, setExpandedByBase] = usePersistedState(`${blockKey}::expanded`, () => /* @__PURE__ */ new Set());
|
|
822
879
|
const defs = useMemo(() => buildVariantDefs(variants), [variants]);
|
|
823
880
|
const groups = useMemo(() => {
|
|
824
881
|
const projectFields = {
|
|
@@ -898,13 +955,13 @@ function ColorTable({ filter, caption, sortBy = "path", sortDir = "asc", searcha
|
|
|
898
955
|
else next.add(base);
|
|
899
956
|
return next;
|
|
900
957
|
});
|
|
901
|
-
}, []);
|
|
958
|
+
}, [setExpandedByBase]);
|
|
902
959
|
const selectVariant = useCallback((base, label) => {
|
|
903
960
|
setSelectedByBase((prev) => ({
|
|
904
961
|
...prev,
|
|
905
962
|
[base]: label
|
|
906
963
|
}));
|
|
907
|
-
}, []);
|
|
964
|
+
}, [setSelectedByBase]);
|
|
908
965
|
const matchSuffix = searchable && query.trim() !== "" ? ` · ${visibleGroups.length} matching "${query.trim()}"` : "";
|
|
909
966
|
const captionText = caption ?? `${totalTokens} color${totalTokens === 1 ? "" : "s"} across ${groups.length} group${groups.length === 1 ? "" : "s"}${filter ? ` matching \`${filter}\`` : ""}${matchSuffix} · ${activeTheme}`;
|
|
910
967
|
if (groups.length === 0) return /* @__PURE__ */ jsx("div", {
|
|
@@ -3639,8 +3696,13 @@ function pruneTreeForMatches(nodes, matches, expandOut) {
|
|
|
3639
3696
|
}
|
|
3640
3697
|
return out;
|
|
3641
3698
|
}
|
|
3642
|
-
function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true, onSelect }) {
|
|
3699
|
+
function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true, onSelect, id }) {
|
|
3643
3700
|
const { resolved, activeTheme, activeAxes, cssVarPrefix } = useProject();
|
|
3701
|
+
const blockKey = useBlockKey("TokenNavigator", [
|
|
3702
|
+
root,
|
|
3703
|
+
type === void 0 ? "" : typeof type === "string" ? type : type.join(","),
|
|
3704
|
+
id
|
|
3705
|
+
]);
|
|
3644
3706
|
const typeFilter = useMemo(() => {
|
|
3645
3707
|
if (type === void 0) return void 0;
|
|
3646
3708
|
return new Set(Array.isArray(type) ? type : [type]);
|
|
@@ -3655,15 +3717,19 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
|
|
|
3655
3717
|
collectInitialExpanded(tree, initiallyExpanded, out);
|
|
3656
3718
|
return out;
|
|
3657
3719
|
}, [tree, initiallyExpanded]);
|
|
3658
|
-
const [expanded, setExpanded] =
|
|
3720
|
+
const [expanded, setExpanded] = usePersistedState(`${blockKey}::expanded`, initialExpanded);
|
|
3659
3721
|
const initiallyExpandedRef = useRef(initiallyExpanded);
|
|
3660
3722
|
useEffect(() => {
|
|
3661
3723
|
if (initiallyExpandedRef.current === initiallyExpanded) return;
|
|
3662
3724
|
initiallyExpandedRef.current = initiallyExpanded;
|
|
3663
3725
|
setExpanded(initialExpanded);
|
|
3664
|
-
}, [
|
|
3665
|
-
|
|
3666
|
-
|
|
3726
|
+
}, [
|
|
3727
|
+
initiallyExpanded,
|
|
3728
|
+
initialExpanded,
|
|
3729
|
+
setExpanded
|
|
3730
|
+
]);
|
|
3731
|
+
const [selectedPath, setSelectedPath] = usePersistedState(`${blockKey}::selected`, null);
|
|
3732
|
+
const [query, setQuery] = usePersistedState(`${blockKey}::query`, "");
|
|
3667
3733
|
const deferredQuery = useDeferredValue(query);
|
|
3668
3734
|
const { visibleTree, searchExpanded } = useMemo(() => {
|
|
3669
3735
|
if (!searchable || deferredQuery.trim() === "") return {
|
|
@@ -3696,11 +3762,11 @@ function TokenNavigator({ root, type, initiallyExpanded = 1, searchable = true,
|
|
|
3696
3762
|
else next.add(path);
|
|
3697
3763
|
return next;
|
|
3698
3764
|
});
|
|
3699
|
-
}, []);
|
|
3765
|
+
}, [setExpanded]);
|
|
3700
3766
|
const handleLeafClick = useCallback((path) => {
|
|
3701
3767
|
if (onSelect) onSelect(path);
|
|
3702
3768
|
else setSelectedPath(path);
|
|
3703
|
-
}, [onSelect]);
|
|
3769
|
+
}, [onSelect, setSelectedPath]);
|
|
3704
3770
|
const [storedFocus, setStoredFocus] = useState(null);
|
|
3705
3771
|
const treeItemRefs = useRef(/* @__PURE__ */ new Map());
|
|
3706
3772
|
const registerTreeItem = useCallback((path) => (el) => {
|
|
@@ -4055,11 +4121,17 @@ const LeafPreview = memo(function LeafPreview({ path, token }) {
|
|
|
4055
4121
|
});
|
|
4056
4122
|
//#endregion
|
|
4057
4123
|
//#region src/TokenTable.tsx
|
|
4058
|
-
function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect }) {
|
|
4124
|
+
function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", searchable = true, onSelect, id }) {
|
|
4059
4125
|
const { resolved, activeTheme, activeAxes, cssVarPrefix, listing } = useProject();
|
|
4060
4126
|
const colorFormat = useColorFormat();
|
|
4061
|
-
const
|
|
4062
|
-
|
|
4127
|
+
const blockKey = useBlockKey("TokenTable", [
|
|
4128
|
+
filter,
|
|
4129
|
+
type,
|
|
4130
|
+
caption,
|
|
4131
|
+
id
|
|
4132
|
+
]);
|
|
4133
|
+
const [selectedPath, setSelectedPath] = usePersistedState(`${blockKey}::selected`, null);
|
|
4134
|
+
const [query, setQuery] = usePersistedState(`${blockKey}::query`, "");
|
|
4063
4135
|
const deferredQuery = useDeferredValue(query);
|
|
4064
4136
|
const rows = useMemo(() => {
|
|
4065
4137
|
const projectFields = {
|
|
@@ -4106,7 +4178,7 @@ function TokenTable({ filter, type, caption, sortBy = "path", sortDir = "asc", s
|
|
|
4106
4178
|
const handleRowClick = useCallback((path) => {
|
|
4107
4179
|
if (onSelect) onSelect(path);
|
|
4108
4180
|
else setSelectedPath(path);
|
|
4109
|
-
}, [onSelect]);
|
|
4181
|
+
}, [onSelect, setSelectedPath]);
|
|
4110
4182
|
const matchSuffix = searchable && query.trim() !== "" ? ` · ${visibleRows.length} matching "${query.trim()}"` : "";
|
|
4111
4183
|
const captionText = caption ?? `${rows.length} token${rows.length === 1 ? "" : "s"}${filter ? ` matching \`${filter}\`` : ""}${type ? ` · $type=${type}` : ""}${matchSuffix} · ${activeTheme}`;
|
|
4112
4184
|
if (rows.length === 0) return /* @__PURE__ */ jsx("div", {
|