@unpunnyfuns/swatchbook-addon 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as preview_exports } from "./preview-
|
|
1
|
+
import { i as preview_exports } from "./preview-BelQcfkL.mjs";
|
|
2
2
|
import { a as GLOBAL_KEY, c as PARAM_KEY, f as VIRTUAL_MODULE_ID, n as AXES_GLOBAL_KEY, t as ADDON_ID } from "./constants-1plfdgh7.mjs";
|
|
3
3
|
import { definePreviewAddon } from "storybook/internal/csf";
|
|
4
4
|
//#region src/index.ts
|
|
@@ -234,7 +234,46 @@ const initialGlobals = {
|
|
|
234
234
|
[AXES_GLOBAL_KEY]: buildInitialAxes(),
|
|
235
235
|
[COLOR_FORMAT_GLOBAL_KEY]: "hex"
|
|
236
236
|
};
|
|
237
|
+
/**
|
|
238
|
+
* Module-level channel subscription: writes the active tuple's attributes
|
|
239
|
+
* onto `<html>` regardless of whether a story decorator is rendering.
|
|
240
|
+
*
|
|
241
|
+
* The {@link themedDecorator} already sets these inside story renders, but
|
|
242
|
+
* it never runs on MDX docs pages that embed blocks without `<Story />`.
|
|
243
|
+
* Without attrs on an ancestor, the per-tuple CSS selectors
|
|
244
|
+
* (`[data-mode="Dark"][data-brand="…"]`) don't match and everything falls
|
|
245
|
+
* back to the `:root` default tuple — so colors stay defaults even after
|
|
246
|
+
* the toolbar switches axes. Subscribing globally fixes MDX docs at the
|
|
247
|
+
* cost of one idempotent redundant write per story render.
|
|
248
|
+
*/
|
|
249
|
+
function installGlobalAxisApplier() {
|
|
250
|
+
if (typeof document === "undefined") return;
|
|
251
|
+
const channel = addons.getChannel();
|
|
252
|
+
/**
|
|
253
|
+
* Inject the stylesheet and emit the init payload once on module load so
|
|
254
|
+
* the manager's toolbar populates and CSS vars are available even when no
|
|
255
|
+
* story/decorator ever runs (bare MDX docs pages). Without these, the
|
|
256
|
+
* toolbar sits in its disabled "loading…" state and nothing is styled.
|
|
257
|
+
*/
|
|
258
|
+
ensureStylesheet();
|
|
259
|
+
broadcastInit();
|
|
260
|
+
const apply = (globals) => {
|
|
261
|
+
ensureStylesheet();
|
|
262
|
+
const tuple = resolveTuple(globals, {});
|
|
263
|
+
setRootAxes(themes.find((t) => {
|
|
264
|
+
const input = t.input;
|
|
265
|
+
return Object.keys(input).every((k) => input[k] === tuple[k]);
|
|
266
|
+
})?.name ?? defaultTheme ?? themes[0]?.name ?? "Light", tuple);
|
|
267
|
+
};
|
|
268
|
+
const onGlobals = (payload) => {
|
|
269
|
+
if (payload.globals) apply(payload.globals);
|
|
270
|
+
};
|
|
271
|
+
channel.on("globalsUpdated", onGlobals);
|
|
272
|
+
channel.on("setGlobals", onGlobals);
|
|
273
|
+
channel.on("updateGlobals", onGlobals);
|
|
274
|
+
}
|
|
275
|
+
installGlobalAxisApplier();
|
|
237
276
|
//#endregion
|
|
238
277
|
export { preview_exports as i, globalTypes as n, initialGlobals as r, decorators as t };
|
|
239
278
|
|
|
240
|
-
//# sourceMappingURL=preview-
|
|
279
|
+
//# sourceMappingURL=preview-BelQcfkL.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview-DcMFt0cD.mjs","names":["virtualAxes","virtualDisabledAxes","virtualPresets"],"sources":["../src/preview.tsx"],"sourcesContent":["import type { Decorator, Preview } from '@storybook/react-vite';\nimport { useEffect, useMemo } from 'react';\nimport { addons } from 'storybook/preview-api';\nimport {\n axes as virtualAxes,\n css,\n cssVarPrefix,\n defaultTheme,\n diagnostics,\n disabledAxes as virtualDisabledAxes,\n presets as virtualPresets,\n themes,\n themesResolved,\n} from 'virtual:swatchbook/tokens';\nimport {\n AxesContext,\n COLOR_FORMATS,\n type ColorFormat,\n ColorFormatContext,\n type ProjectSnapshot,\n SwatchbookContext,\n ThemeContext,\n} from '@unpunnyfuns/swatchbook-blocks';\nimport {\n AXES_GLOBAL_KEY,\n COLOR_FORMAT_GLOBAL_KEY,\n DATA_THEME_ATTR,\n GLOBAL_KEY,\n INIT_EVENT,\n PARAM_KEY,\n STYLE_ELEMENT_ID,\n} from '#/constants.ts';\n\n/** CSS var name with the active prefix applied. */\nfunction v(name: string): string {\n return cssVarPrefix ? `--${cssVarPrefix}-${name}` : `--${name}`;\n}\n\n/**\n * Inject the per-theme stylesheet plus a tiny `html, body { ... }` block so\n * the iframe's own chrome (outside any decorator wrapper — Docs mode,\n * autodocs, empty gutters) also picks up the active theme.\n */\nfunction ensureStylesheet(): void {\n if (typeof document === 'undefined') return;\n const bodyRules = `\nhtml, body {\n background: var(${v('color-sys-surface-default')}, Canvas);\n color: var(${v('color-sys-text-default')}, CanvasText);\n margin: 0;\n}\n`;\n const text = `${css}\\n${bodyRules}`;\n let style = document.getElementById(STYLE_ELEMENT_ID) as HTMLStyleElement | null;\n if (!style) {\n style = document.createElement('style');\n style.id = STYLE_ELEMENT_ID;\n document.head.appendChild(style);\n }\n if (style.textContent !== text) style.textContent = text;\n}\n\n/**\n * Write the composed permutation ID to `data-theme` plus one\n * `data-<axis>=<context>` per axis. The composed ID stays for CSS\n * emission's current `[data-theme=\"…\"]` selectors (retires in #135);\n * per-axis attributes are what upcoming toolbar + panel work will key on.\n */\nfunction setRootAxes(themeName: string, tuple: Readonly<Record<string, string>>): void {\n if (typeof document === 'undefined') return;\n const root = document.documentElement;\n root.setAttribute(DATA_THEME_ATTR, themeName);\n for (const axis of virtualAxes) {\n const value = tuple[axis.name];\n if (value === undefined) {\n root.removeAttribute(`data-${axis.name}`);\n } else {\n root.setAttribute(`data-${axis.name}`, value);\n }\n }\n /**\n * Disabled axes aren't in `virtualAxes`, but CSS may still reference their\n * pinned value on compound selectors in extension code. Read the value\n * from any surviving theme's `input` — every theme that survived filtering\n * carries the same pinned context for each disabled axis.\n */\n const pinnedSample = themes[0]?.input;\n if (pinnedSample) {\n for (const name of virtualDisabledAxes) {\n const value = pinnedSample[name];\n if (value !== undefined) root.setAttribute(`data-${name}`, value);\n }\n }\n}\n\n/**\n * Emit the full virtual-module payload to the manager over Storybook's\n * channel so the toolbar + panel (which run in the manager bundle and\n * can't import our virtual module) can render from it.\n */\nfunction broadcastInit(): void {\n const channel = addons.getChannel();\n channel.emit(INIT_EVENT, {\n axes: virtualAxes,\n disabledAxes: virtualDisabledAxes,\n presets: virtualPresets,\n themes,\n defaultTheme,\n themesResolved,\n diagnostics,\n cssVarPrefix,\n });\n}\n\n/** Axis-default tuple, used as the baseline before overrides. */\nfunction defaultTuple(): Record<string, string> {\n const out: Record<string, string> = {};\n for (const axis of virtualAxes) out[axis.name] = axis.default;\n return out;\n}\n\n/** Look up a `Theme.input` by composed name. Returns `undefined` if no theme matches. */\nfunction tupleForName(name: string): Record<string, string> | undefined {\n const match = themes.find((t) => t.name === name);\n return match?.input;\n}\n\n/**\n * Merge a partial tuple onto the axis defaults, dropping keys for axes that\n * don't exist and silently falling back to the default for contexts that\n * aren't listed on the axis.\n */\nfunction normalizeTuple(partial: Readonly<Record<string, string>>): Record<string, string> {\n const out = defaultTuple();\n for (const axis of virtualAxes) {\n const candidate = partial[axis.name];\n if (candidate !== undefined && axis.contexts.includes(candidate)) {\n out[axis.name] = candidate;\n }\n }\n return out;\n}\n\n/**\n * Resolve the active tuple from all four input channels, in priority order:\n * 1. `parameters.swatchbook.axes` — per-story tuple.\n * 2. `parameters.swatchbook.theme` — per-story composed name (legacy).\n * 3. `globals.swatchbookAxes` — toolbar-set tuple.\n * 4. `globals.swatchbookTheme` — toolbar-set composed name.\n * 5. virtual module default.\n */\nfunction resolveTuple(\n globals: Record<string, unknown>,\n parameters: Record<string, Record<string, unknown>>,\n): Record<string, string> {\n const param = parameters[PARAM_KEY];\n const paramAxes = param?.['axes'];\n if (paramAxes && typeof paramAxes === 'object') {\n return normalizeTuple(paramAxes as Record<string, string>);\n }\n const paramTheme = param?.['theme'];\n if (typeof paramTheme === 'string') {\n const hit = tupleForName(paramTheme);\n if (hit) return normalizeTuple(hit);\n }\n const globalAxes = globals[AXES_GLOBAL_KEY];\n if (globalAxes && typeof globalAxes === 'object') {\n return normalizeTuple(globalAxes as Record<string, string>);\n }\n const globalTheme = globals[GLOBAL_KEY];\n if (typeof globalTheme === 'string') {\n const hit = tupleForName(globalTheme);\n if (hit) return normalizeTuple(hit);\n }\n return defaultTuple();\n}\n\nfunction resolveColorFormat(globals: Record<string, unknown>): ColorFormat {\n const raw = globals[COLOR_FORMAT_GLOBAL_KEY];\n if (typeof raw === 'string' && (COLOR_FORMATS as readonly string[]).includes(raw)) {\n return raw as ColorFormat;\n }\n return 'hex';\n}\n\nconst themedDecorator: Decorator = (Story, context) => {\n const tuple = useMemo(\n () =>\n resolveTuple(\n context.globals as Record<string, unknown>,\n context.parameters as Record<string, Record<string, unknown>>,\n ),\n [context.globals, context.parameters],\n );\n const colorFormat = useMemo(\n () => resolveColorFormat(context.globals as Record<string, unknown>),\n [context.globals],\n );\n const themeName = useMemo(() => {\n const match = themes.find((t) => {\n const input = t.input as Record<string, string>;\n return Object.keys(input).every((k) => input[k] === tuple[k]);\n });\n return match?.name ?? defaultTheme ?? themes[0]?.name ?? 'Light';\n }, [tuple]);\n\n useEffect(() => {\n ensureStylesheet();\n broadcastInit();\n }, []);\n\n useEffect(() => {\n setRootAxes(themeName, tuple);\n }, [themeName, tuple]);\n\n const wrapperAttrs: Record<string, string> = { [DATA_THEME_ATTR]: themeName };\n for (const axis of virtualAxes) {\n const value = tuple[axis.name];\n if (value !== undefined) wrapperAttrs[`data-${axis.name}`] = value;\n }\n const pinnedSample = themes[0]?.input;\n if (pinnedSample) {\n for (const name of virtualDisabledAxes) {\n const value = pinnedSample[name];\n if (value !== undefined) wrapperAttrs[`data-${name}`] = value;\n }\n }\n\n const snapshot = useMemo<ProjectSnapshot>(\n () => ({\n axes: virtualAxes,\n disabledAxes: virtualDisabledAxes,\n presets: virtualPresets,\n themes,\n themesResolved,\n activeTheme: themeName,\n activeAxes: tuple,\n cssVarPrefix,\n diagnostics,\n css,\n }),\n [themeName, tuple],\n );\n\n return (\n <SwatchbookContext.Provider value={snapshot}>\n <ThemeContext.Provider value={themeName}>\n <AxesContext.Provider value={tuple}>\n <ColorFormatContext.Provider value={colorFormat}>\n <div\n {...wrapperAttrs}\n style={{\n padding: '1rem',\n minHeight: '100%',\n }}\n >\n <Story />\n </div>\n </ColorFormatContext.Provider>\n </AxesContext.Provider>\n </ThemeContext.Provider>\n </SwatchbookContext.Provider>\n );\n};\n\n/**\n * Named exports consumed by `definePreviewAddon(previewExports)` in the\n * addon's CSF Next factory (`src/index.ts`).\n */\nexport const decorators: NonNullable<Preview['decorators']> = [themedDecorator];\n\nexport const globalTypes: NonNullable<Preview['globalTypes']> = {\n [GLOBAL_KEY]: {\n name: 'Theme',\n description: 'Active swatchbook theme (composed permutation ID).',\n },\n [AXES_GLOBAL_KEY]: {\n name: 'Axes',\n description: 'Per-axis context selection. Takes precedence over the composed theme name.',\n },\n [COLOR_FORMAT_GLOBAL_KEY]: {\n name: 'Color format',\n description: 'Display format for color tokens in blocks. Emitted CSS is unaffected.',\n },\n};\n\nfunction buildInitialAxes(): Record<string, string> {\n const out: Record<string, string> = {};\n for (const axis of virtualAxes) out[axis.name] = axis.default;\n return out;\n}\n\nexport const initialGlobals: NonNullable<Preview['initialGlobals']> = {\n [GLOBAL_KEY]: defaultTheme ?? themes[0]?.name ?? 'Light',\n [AXES_GLOBAL_KEY]: buildInitialAxes(),\n [COLOR_FORMAT_GLOBAL_KEY]: 'hex',\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"preview-BelQcfkL.mjs","names":["virtualAxes","virtualDisabledAxes","virtualPresets"],"sources":["../src/preview.tsx"],"sourcesContent":["import type { Decorator, Preview } from '@storybook/react-vite';\nimport { useEffect, useMemo } from 'react';\nimport { addons } from 'storybook/preview-api';\nimport {\n axes as virtualAxes,\n css,\n cssVarPrefix,\n defaultTheme,\n diagnostics,\n disabledAxes as virtualDisabledAxes,\n presets as virtualPresets,\n themes,\n themesResolved,\n} from 'virtual:swatchbook/tokens';\nimport {\n AxesContext,\n COLOR_FORMATS,\n type ColorFormat,\n ColorFormatContext,\n type ProjectSnapshot,\n SwatchbookContext,\n ThemeContext,\n} from '@unpunnyfuns/swatchbook-blocks';\nimport {\n AXES_GLOBAL_KEY,\n COLOR_FORMAT_GLOBAL_KEY,\n DATA_THEME_ATTR,\n GLOBAL_KEY,\n INIT_EVENT,\n PARAM_KEY,\n STYLE_ELEMENT_ID,\n} from '#/constants.ts';\n\n/** CSS var name with the active prefix applied. */\nfunction v(name: string): string {\n return cssVarPrefix ? `--${cssVarPrefix}-${name}` : `--${name}`;\n}\n\n/**\n * Inject the per-theme stylesheet plus a tiny `html, body { ... }` block so\n * the iframe's own chrome (outside any decorator wrapper — Docs mode,\n * autodocs, empty gutters) also picks up the active theme.\n */\nfunction ensureStylesheet(): void {\n if (typeof document === 'undefined') return;\n const bodyRules = `\nhtml, body {\n background: var(${v('color-sys-surface-default')}, Canvas);\n color: var(${v('color-sys-text-default')}, CanvasText);\n margin: 0;\n}\n`;\n const text = `${css}\\n${bodyRules}`;\n let style = document.getElementById(STYLE_ELEMENT_ID) as HTMLStyleElement | null;\n if (!style) {\n style = document.createElement('style');\n style.id = STYLE_ELEMENT_ID;\n document.head.appendChild(style);\n }\n if (style.textContent !== text) style.textContent = text;\n}\n\n/**\n * Write the composed permutation ID to `data-theme` plus one\n * `data-<axis>=<context>` per axis. The composed ID stays for CSS\n * emission's current `[data-theme=\"…\"]` selectors (retires in #135);\n * per-axis attributes are what upcoming toolbar + panel work will key on.\n */\nfunction setRootAxes(themeName: string, tuple: Readonly<Record<string, string>>): void {\n if (typeof document === 'undefined') return;\n const root = document.documentElement;\n root.setAttribute(DATA_THEME_ATTR, themeName);\n for (const axis of virtualAxes) {\n const value = tuple[axis.name];\n if (value === undefined) {\n root.removeAttribute(`data-${axis.name}`);\n } else {\n root.setAttribute(`data-${axis.name}`, value);\n }\n }\n /**\n * Disabled axes aren't in `virtualAxes`, but CSS may still reference their\n * pinned value on compound selectors in extension code. Read the value\n * from any surviving theme's `input` — every theme that survived filtering\n * carries the same pinned context for each disabled axis.\n */\n const pinnedSample = themes[0]?.input;\n if (pinnedSample) {\n for (const name of virtualDisabledAxes) {\n const value = pinnedSample[name];\n if (value !== undefined) root.setAttribute(`data-${name}`, value);\n }\n }\n}\n\n/**\n * Emit the full virtual-module payload to the manager over Storybook's\n * channel so the toolbar + panel (which run in the manager bundle and\n * can't import our virtual module) can render from it.\n */\nfunction broadcastInit(): void {\n const channel = addons.getChannel();\n channel.emit(INIT_EVENT, {\n axes: virtualAxes,\n disabledAxes: virtualDisabledAxes,\n presets: virtualPresets,\n themes,\n defaultTheme,\n themesResolved,\n diagnostics,\n cssVarPrefix,\n });\n}\n\n/** Axis-default tuple, used as the baseline before overrides. */\nfunction defaultTuple(): Record<string, string> {\n const out: Record<string, string> = {};\n for (const axis of virtualAxes) out[axis.name] = axis.default;\n return out;\n}\n\n/** Look up a `Theme.input` by composed name. Returns `undefined` if no theme matches. */\nfunction tupleForName(name: string): Record<string, string> | undefined {\n const match = themes.find((t) => t.name === name);\n return match?.input;\n}\n\n/**\n * Merge a partial tuple onto the axis defaults, dropping keys for axes that\n * don't exist and silently falling back to the default for contexts that\n * aren't listed on the axis.\n */\nfunction normalizeTuple(partial: Readonly<Record<string, string>>): Record<string, string> {\n const out = defaultTuple();\n for (const axis of virtualAxes) {\n const candidate = partial[axis.name];\n if (candidate !== undefined && axis.contexts.includes(candidate)) {\n out[axis.name] = candidate;\n }\n }\n return out;\n}\n\n/**\n * Resolve the active tuple from all four input channels, in priority order:\n * 1. `parameters.swatchbook.axes` — per-story tuple.\n * 2. `parameters.swatchbook.theme` — per-story composed name (legacy).\n * 3. `globals.swatchbookAxes` — toolbar-set tuple.\n * 4. `globals.swatchbookTheme` — toolbar-set composed name.\n * 5. virtual module default.\n */\nfunction resolveTuple(\n globals: Record<string, unknown>,\n parameters: Record<string, Record<string, unknown>>,\n): Record<string, string> {\n const param = parameters[PARAM_KEY];\n const paramAxes = param?.['axes'];\n if (paramAxes && typeof paramAxes === 'object') {\n return normalizeTuple(paramAxes as Record<string, string>);\n }\n const paramTheme = param?.['theme'];\n if (typeof paramTheme === 'string') {\n const hit = tupleForName(paramTheme);\n if (hit) return normalizeTuple(hit);\n }\n const globalAxes = globals[AXES_GLOBAL_KEY];\n if (globalAxes && typeof globalAxes === 'object') {\n return normalizeTuple(globalAxes as Record<string, string>);\n }\n const globalTheme = globals[GLOBAL_KEY];\n if (typeof globalTheme === 'string') {\n const hit = tupleForName(globalTheme);\n if (hit) return normalizeTuple(hit);\n }\n return defaultTuple();\n}\n\nfunction resolveColorFormat(globals: Record<string, unknown>): ColorFormat {\n const raw = globals[COLOR_FORMAT_GLOBAL_KEY];\n if (typeof raw === 'string' && (COLOR_FORMATS as readonly string[]).includes(raw)) {\n return raw as ColorFormat;\n }\n return 'hex';\n}\n\nconst themedDecorator: Decorator = (Story, context) => {\n const tuple = useMemo(\n () =>\n resolveTuple(\n context.globals as Record<string, unknown>,\n context.parameters as Record<string, Record<string, unknown>>,\n ),\n [context.globals, context.parameters],\n );\n const colorFormat = useMemo(\n () => resolveColorFormat(context.globals as Record<string, unknown>),\n [context.globals],\n );\n const themeName = useMemo(() => {\n const match = themes.find((t) => {\n const input = t.input as Record<string, string>;\n return Object.keys(input).every((k) => input[k] === tuple[k]);\n });\n return match?.name ?? defaultTheme ?? themes[0]?.name ?? 'Light';\n }, [tuple]);\n\n useEffect(() => {\n ensureStylesheet();\n broadcastInit();\n }, []);\n\n useEffect(() => {\n setRootAxes(themeName, tuple);\n }, [themeName, tuple]);\n\n const wrapperAttrs: Record<string, string> = { [DATA_THEME_ATTR]: themeName };\n for (const axis of virtualAxes) {\n const value = tuple[axis.name];\n if (value !== undefined) wrapperAttrs[`data-${axis.name}`] = value;\n }\n const pinnedSample = themes[0]?.input;\n if (pinnedSample) {\n for (const name of virtualDisabledAxes) {\n const value = pinnedSample[name];\n if (value !== undefined) wrapperAttrs[`data-${name}`] = value;\n }\n }\n\n const snapshot = useMemo<ProjectSnapshot>(\n () => ({\n axes: virtualAxes,\n disabledAxes: virtualDisabledAxes,\n presets: virtualPresets,\n themes,\n themesResolved,\n activeTheme: themeName,\n activeAxes: tuple,\n cssVarPrefix,\n diagnostics,\n css,\n }),\n [themeName, tuple],\n );\n\n return (\n <SwatchbookContext.Provider value={snapshot}>\n <ThemeContext.Provider value={themeName}>\n <AxesContext.Provider value={tuple}>\n <ColorFormatContext.Provider value={colorFormat}>\n <div\n {...wrapperAttrs}\n style={{\n padding: '1rem',\n minHeight: '100%',\n }}\n >\n <Story />\n </div>\n </ColorFormatContext.Provider>\n </AxesContext.Provider>\n </ThemeContext.Provider>\n </SwatchbookContext.Provider>\n );\n};\n\n/**\n * Named exports consumed by `definePreviewAddon(previewExports)` in the\n * addon's CSF Next factory (`src/index.ts`).\n */\nexport const decorators: NonNullable<Preview['decorators']> = [themedDecorator];\n\nexport const globalTypes: NonNullable<Preview['globalTypes']> = {\n [GLOBAL_KEY]: {\n name: 'Theme',\n description: 'Active swatchbook theme (composed permutation ID).',\n },\n [AXES_GLOBAL_KEY]: {\n name: 'Axes',\n description: 'Per-axis context selection. Takes precedence over the composed theme name.',\n },\n [COLOR_FORMAT_GLOBAL_KEY]: {\n name: 'Color format',\n description: 'Display format for color tokens in blocks. Emitted CSS is unaffected.',\n },\n};\n\nfunction buildInitialAxes(): Record<string, string> {\n const out: Record<string, string> = {};\n for (const axis of virtualAxes) out[axis.name] = axis.default;\n return out;\n}\n\nexport const initialGlobals: NonNullable<Preview['initialGlobals']> = {\n [GLOBAL_KEY]: defaultTheme ?? themes[0]?.name ?? 'Light',\n [AXES_GLOBAL_KEY]: buildInitialAxes(),\n [COLOR_FORMAT_GLOBAL_KEY]: 'hex',\n};\n\n/**\n * Module-level channel subscription: writes the active tuple's attributes\n * onto `<html>` regardless of whether a story decorator is rendering.\n *\n * The {@link themedDecorator} already sets these inside story renders, but\n * it never runs on MDX docs pages that embed blocks without `<Story />`.\n * Without attrs on an ancestor, the per-tuple CSS selectors\n * (`[data-mode=\"Dark\"][data-brand=\"…\"]`) don't match and everything falls\n * back to the `:root` default tuple — so colors stay defaults even after\n * the toolbar switches axes. Subscribing globally fixes MDX docs at the\n * cost of one idempotent redundant write per story render.\n */\nfunction installGlobalAxisApplier(): void {\n if (typeof document === 'undefined') return;\n const channel = addons.getChannel();\n /**\n * Inject the stylesheet and emit the init payload once on module load so\n * the manager's toolbar populates and CSS vars are available even when no\n * story/decorator ever runs (bare MDX docs pages). Without these, the\n * toolbar sits in its disabled \"loading…\" state and nothing is styled.\n */\n ensureStylesheet();\n broadcastInit();\n const apply = (globals: Record<string, unknown>): void => {\n ensureStylesheet();\n const tuple = resolveTuple(globals, {});\n const match = themes.find((t) => {\n const input = t.input as Record<string, string>;\n return Object.keys(input).every((k) => input[k] === tuple[k]);\n });\n const themeName = match?.name ?? defaultTheme ?? themes[0]?.name ?? 'Light';\n setRootAxes(themeName, tuple);\n };\n const onGlobals = (payload: { globals?: Record<string, unknown> }): void => {\n if (payload.globals) apply(payload.globals);\n };\n channel.on('globalsUpdated', onGlobals);\n channel.on('setGlobals', onGlobals);\n channel.on('updateGlobals', onGlobals);\n}\n\ninstallGlobalAxisApplier();\n"],"mappings":"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"}
|
package/dist/preview.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as globalTypes, r as initialGlobals, t as decorators } from "./preview-
|
|
1
|
+
import { n as globalTypes, r as initialGlobals, t as decorators } from "./preview-BelQcfkL.mjs";
|
|
2
2
|
export { decorators, globalTypes, initialGlobals };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unpunnyfuns/swatchbook-addon",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Storybook addon for DTCG design tokens — toolbar, panel, and useToken hook.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "unpunnyfuns <unpunnyfuns@gmail.com>",
|
|
@@ -67,8 +67,8 @@
|
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"jiti": "^2.4.0",
|
|
70
|
-
"@unpunnyfuns/swatchbook-blocks": "0.1.
|
|
71
|
-
"@unpunnyfuns/swatchbook-core": "0.1.
|
|
70
|
+
"@unpunnyfuns/swatchbook-blocks": "0.1.3",
|
|
71
|
+
"@unpunnyfuns/swatchbook-core": "0.1.3"
|
|
72
72
|
},
|
|
73
73
|
"peerDependencies": {
|
|
74
74
|
"react": ">=18",
|