@unpunnyfuns/swatchbook-integrations 0.60.8 → 0.61.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.
@@ -12,17 +12,19 @@ interface CssInJsIntegrationOptions {
12
12
  }
13
13
  /**
14
14
  * Preview-only CSS-in-JS integration for swatchbook's Storybook addon.
15
- * Contributes a virtual JS module that exports a nested accessor
16
- * mirroring the project's token tree every leaf is a `var(...)`
17
- * reference carrying the project's `cssVarPrefix`. Lets stories import
18
- * `{ theme }` the same way their production components do, but backed
19
- * by swatchbook's runtime-switchable cascade rather than a concrete
20
- * theme object. Not a replacement for the consumer's production
21
- * CSS-in-JS emit step.
15
+ * Contributes a virtual JS module exporting a nested accessor that mirrors
16
+ * the project's token tree, every leaf a `var(--<cssVarPrefix>-*)` reference.
17
+ * Stories import `{ theme }` the way their production components do, but
18
+ * backed by swatchbook's runtime-switchable cascade rather than a concrete
19
+ * theme object.
22
20
  *
23
- * Swatchbook's toolbar still does the flipping via compound `data-*`
24
- * attributes; the accessor's values don't change across tuples because
25
- * the cascade resolves the var.
21
+ * The accessor is stable across tuples: its values are `var(...)` refs, so
22
+ * the toolbar's `data-*` axis flips repaint through the cascade without
23
+ * rebuilding the object. Consumers wire it into a provider once.
24
+ *
25
+ * Not a transform step. Consumers needing resolved-value permutations
26
+ * (MUI `createTheme`, Vuetify factories) are out of scope — that's the
27
+ * production CSS-in-JS emit, not this preview shim.
26
28
  *
27
29
  * ```ts
28
30
  * // .storybook/main.ts
@@ -49,12 +51,6 @@ interface CssInJsIntegrationOptions {
49
51
  * // direct ref
50
52
  * const bg = color.surface.default; // -> "var(--sb-color-surface-default)"
51
53
  * ```
52
- *
53
- * The theme object is stable across tuples — consumers wire it into a
54
- * provider *once*; runtime switching happens entirely through CSS cascade
55
- * when swatchbook's toolbar toggles `data-<prefix>-<axis>` on `<html>`.
56
- * Consumers who need resolved-value permutations (MUI `createTheme`, Vuetify
57
- * factories) are not covered — that's a different emission story.
58
54
  */
59
55
  declare function cssInJsIntegration(options?: CssInJsIntegrationOptions): SwatchbookIntegration;
60
56
  //#endregion
@@ -2,17 +2,19 @@ import { listPaths } from "@unpunnyfuns/swatchbook-core/graph";
2
2
  //#region src/css-in-js.ts
3
3
  /**
4
4
  * Preview-only CSS-in-JS integration for swatchbook's Storybook addon.
5
- * Contributes a virtual JS module that exports a nested accessor
6
- * mirroring the project's token tree every leaf is a `var(...)`
7
- * reference carrying the project's `cssVarPrefix`. Lets stories import
8
- * `{ theme }` the same way their production components do, but backed
9
- * by swatchbook's runtime-switchable cascade rather than a concrete
10
- * theme object. Not a replacement for the consumer's production
11
- * CSS-in-JS emit step.
5
+ * Contributes a virtual JS module exporting a nested accessor that mirrors
6
+ * the project's token tree, every leaf a `var(--<cssVarPrefix>-*)` reference.
7
+ * Stories import `{ theme }` the way their production components do, but
8
+ * backed by swatchbook's runtime-switchable cascade rather than a concrete
9
+ * theme object.
12
10
  *
13
- * Swatchbook's toolbar still does the flipping via compound `data-*`
14
- * attributes; the accessor's values don't change across tuples because
15
- * the cascade resolves the var.
11
+ * The accessor is stable across tuples: its values are `var(...)` refs, so
12
+ * the toolbar's `data-*` axis flips repaint through the cascade without
13
+ * rebuilding the object. Consumers wire it into a provider once.
14
+ *
15
+ * Not a transform step. Consumers needing resolved-value permutations
16
+ * (MUI `createTheme`, Vuetify factories) are out of scope — that's the
17
+ * production CSS-in-JS emit, not this preview shim.
16
18
  *
17
19
  * ```ts
18
20
  * // .storybook/main.ts
@@ -39,12 +41,6 @@ import { listPaths } from "@unpunnyfuns/swatchbook-core/graph";
39
41
  * // direct ref
40
42
  * const bg = color.surface.default; // -> "var(--sb-color-surface-default)"
41
43
  * ```
42
- *
43
- * The theme object is stable across tuples — consumers wire it into a
44
- * provider *once*; runtime switching happens entirely through CSS cascade
45
- * when swatchbook's toolbar toggles `data-<prefix>-<axis>` on `<html>`.
46
- * Consumers who need resolved-value permutations (MUI `createTheme`, Vuetify
47
- * factories) are not covered — that's a different emission story.
48
44
  */
49
45
  function cssInJsIntegration(options = {}) {
50
46
  return {
@@ -75,13 +71,6 @@ function renderTheme(project) {
75
71
  function collectPaths(project) {
76
72
  return [...listPaths(project.tokenGraph)];
77
73
  }
78
- /**
79
- * Build a nested object tree from a sorted path list. Leaves hold the
80
- * emitted value from `leafFor(path)`. Leaf/branch collisions (a shorter
81
- * path emits a leaf while a longer path wants to nest under the same
82
- * key) are resolved by keeping the leaf — realistic DTCG trees don't
83
- * hit this, but the explicit behaviour beats silent UB.
84
- */
85
74
  function buildTree(sortedPaths, leafFor) {
86
75
  const root = {};
87
76
  for (const path of sortedPaths) {
@@ -108,17 +97,11 @@ function renderNode(node, depth) {
108
97
  const closing = " ".repeat(depth - 1);
109
98
  return `{\n${Object.keys(node).toSorted().map((key) => `${indent}${safeKey(key)}: ${renderNode(node[key], depth + 1)}`).join(",\n")},\n${closing}}`;
110
99
  }
111
- /**
112
- * Bare identifier (or canonical non-leading-zero integer literal) if
113
- * safe; quoted string otherwise. Leading-zero numerics like `"050"`
114
- * stay quoted because bare `050` is an octal under strict mode.
115
- */
116
100
  function safeKey(key) {
117
101
  if (/^[A-Za-z_$][\w$]*$/.test(key)) return key;
118
102
  if (/^(0|[1-9]\d*)$/.test(key)) return key;
119
103
  return JSON.stringify(key);
120
104
  }
121
- /** Top-level exports must be valid JS identifiers. */
122
105
  function safeIdent(key) {
123
106
  return /^[A-Za-z_$][\w$]*$/.test(key) ? key : `_${key.replaceAll(/[^\w$]/g, "_")}`;
124
107
  }
@@ -1 +1 @@
1
- {"version":3,"file":"css-in-js.mjs","names":[],"sources":["../src/css-in-js.ts"],"sourcesContent":["import type { Project, SwatchbookIntegration } from '@unpunnyfuns/swatchbook-core';\nimport { listPaths } from '@unpunnyfuns/swatchbook-core/graph';\n\nexport interface CssInJsIntegrationOptions {\n /**\n * Virtual module ID the addon serves. Default:\n * `'virtual:swatchbook/theme'`. Consumers import this string from\n * their preview (or stories) to receive a typed accessor object whose\n * leaves are `var(--<cssVarPrefix>-*)` references.\n */\n virtualId?: string;\n}\n\n/**\n * Preview-only CSS-in-JS integration for swatchbook's Storybook addon.\n * Contributes a virtual JS module that exports a nested accessor\n * mirroring the project's token tree every leaf is a `var(...)`\n * reference carrying the project's `cssVarPrefix`. Lets stories import\n * `{ theme }` the same way their production components do, but backed\n * by swatchbook's runtime-switchable cascade rather than a concrete\n * theme object. Not a replacement for the consumer's production\n * CSS-in-JS emit step.\n *\n * Swatchbook's toolbar still does the flipping via compound `data-*`\n * attributes; the accessor's values don't change across tuples because\n * the cascade resolves the var.\n *\n * ```ts\n * // .storybook/main.ts\n * import cssInJsIntegration from '@unpunnyfuns/swatchbook-integrations/css-in-js';\n *\n * export default defineMain({\n * addons: [\n * {\n * name: '@unpunnyfuns/swatchbook-addon',\n * options: {\n * configPath: '../swatchbook.config.ts',\n * integrations: [cssInJsIntegration()],\n * },\n * },\n * ],\n * });\n *\n * // Any story / component\n * import { theme, color, space } from 'virtual:swatchbook/theme';\n *\n * // styled-components / emotion\n * <ThemeProvider theme={theme}>...</ThemeProvider>\n *\n * // direct ref\n * const bg = color.surface.default; // -> \"var(--sb-color-surface-default)\"\n * ```\n *\n * The theme object is stable across tuples — consumers wire it into a\n * provider *once*; runtime switching happens entirely through CSS cascade\n * when swatchbook's toolbar toggles `data-<prefix>-<axis>` on `<html>`.\n * Consumers who need resolved-value permutations (MUI `createTheme`, Vuetify\n * factories) are not covered — that's a different emission story.\n */\nexport default function cssInJsIntegration(\n options: CssInJsIntegrationOptions = {},\n): SwatchbookIntegration {\n const virtualId = options.virtualId ?? 'virtual:swatchbook/theme';\n return {\n name: 'css-in-js',\n virtualModule: {\n virtualId,\n render: renderTheme,\n },\n };\n}\n\nfunction renderTheme(project: Project): string {\n const prefix = project.config.cssVarPrefix ?? '';\n const varPrefix = prefix ? `${prefix}-` : '';\n const paths = collectPaths(project);\n const tree = buildTree(paths, (path) => `var(--${varPrefix}${path.replaceAll('.', '-')})`);\n\n const groupNames = Object.keys(tree).toSorted();\n const groupExports = groupNames.map(\n (name) => `export const ${safeIdent(name)} = ${renderNode(tree[name]!, 1)};`,\n );\n const aggregate = `export const theme = { ${groupNames.map(safeIdent).join(', ')} };`;\n\n return [\n '/* Synthesized by @unpunnyfuns/swatchbook-integrations/css-in-js for preview.',\n ' * Served via `virtual:swatchbook/theme` — rebuilt on token changes. */',\n '',\n ...groupExports,\n '',\n aggregate,\n '',\n ].join('\\n');\n}\n\nfunction collectPaths(project: Project): string[] {\n // listPaths already returns a sorted array; copy it to a mutable string[].\n return [...listPaths(project.tokenGraph)];\n}\n\ninterface TreeNode {\n [key: string]: TreeNode | string;\n}\n\n/**\n * Build a nested object tree from a sorted path list. Leaves hold the\n * emitted value from `leafFor(path)`. Leaf/branch collisions (a shorter\n * path emits a leaf while a longer path wants to nest under the same\n * key) are resolved by keeping the leaf — realistic DTCG trees don't\n * hit this, but the explicit behaviour beats silent UB.\n */\nfunction buildTree(sortedPaths: readonly string[], leafFor: (path: string) => string): TreeNode {\n const root: TreeNode = {};\n for (const path of sortedPaths) {\n const segments = path.split('.');\n let node = root;\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i]!;\n const existing = node[seg];\n if (typeof existing === 'string') break;\n if (existing === undefined) {\n const next: TreeNode = {};\n node[seg] = next;\n node = next;\n } else {\n node = existing;\n }\n }\n const leafKey = segments.at(-1)!;\n if (node[leafKey] === undefined) node[leafKey] = leafFor(path);\n }\n return root;\n}\n\nfunction renderNode(node: TreeNode | string, depth: number): string {\n if (typeof node === 'string') return JSON.stringify(node);\n const indent = ' '.repeat(depth);\n const closing = ' '.repeat(depth - 1);\n const entries = Object.keys(node)\n .toSorted()\n .map((key) => `${indent}${safeKey(key)}: ${renderNode(node[key]!, depth + 1)}`);\n return `{\\n${entries.join(',\\n')},\\n${closing}}`;\n}\n\n/**\n * Bare identifier (or canonical non-leading-zero integer literal) if\n * safe; quoted string otherwise. Leading-zero numerics like `\"050\"`\n * stay quoted because bare `050` is an octal under strict mode.\n */\nfunction safeKey(key: string): string {\n if (/^[A-Za-z_$][\\w$]*$/.test(key)) return key;\n if (/^(0|[1-9]\\d*)$/.test(key)) return key;\n return JSON.stringify(key);\n}\n\n/** Top-level exports must be valid JS identifiers. */\nfunction safeIdent(key: string): string {\n return /^[A-Za-z_$][\\w$]*$/.test(key) ? key : `_${key.replaceAll(/[^\\w$]/g, '_')}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,SAAwB,mBACtB,UAAqC,EAAE,EAChB;AAEvB,QAAO;EACL,MAAM;EACN,eAAe;GACb,WAJc,QAAQ,aAAa;GAKnC,QAAQ;GACT;EACF;;AAGH,SAAS,YAAY,SAA0B;CAC7C,MAAM,SAAS,QAAQ,OAAO,gBAAgB;CAC9C,MAAM,YAAY,SAAS,GAAG,OAAO,KAAK;CAE1C,MAAM,OAAO,UADC,aAAa,QAAQ,GACJ,SAAS,SAAS,YAAY,KAAK,WAAW,KAAK,IAAI,CAAC,GAAG;CAE1F,MAAM,aAAa,OAAO,KAAK,KAAK,CAAC,UAAU;CAC/C,MAAM,eAAe,WAAW,KAC7B,SAAS,gBAAgB,UAAU,KAAK,CAAC,KAAK,WAAW,KAAK,OAAQ,EAAE,CAAC,GAC3E;CACD,MAAM,YAAY,0BAA0B,WAAW,IAAI,UAAU,CAAC,KAAK,KAAK,CAAC;AAEjF,QAAO;EACL;EACA;EACA;EACA,GAAG;EACH;EACA;EACA;EACD,CAAC,KAAK,KAAK;;AAGd,SAAS,aAAa,SAA4B;AAEhD,QAAO,CAAC,GAAG,UAAU,QAAQ,WAAW,CAAC;;;;;;;;;AAc3C,SAAS,UAAU,aAAgC,SAA6C;CAC9F,MAAM,OAAiB,EAAE;AACzB,MAAK,MAAM,QAAQ,aAAa;EAC9B,MAAM,WAAW,KAAK,MAAM,IAAI;EAChC,IAAI,OAAO;AACX,OAAK,IAAI,IAAI,GAAG,IAAI,SAAS,SAAS,GAAG,KAAK;GAC5C,MAAM,MAAM,SAAS;GACrB,MAAM,WAAW,KAAK;AACtB,OAAI,OAAO,aAAa,SAAU;AAClC,OAAI,aAAa,KAAA,GAAW;IAC1B,MAAM,OAAiB,EAAE;AACzB,SAAK,OAAO;AACZ,WAAO;SAEP,QAAO;;EAGX,MAAM,UAAU,SAAS,GAAG,GAAG;AAC/B,MAAI,KAAK,aAAa,KAAA,EAAW,MAAK,WAAW,QAAQ,KAAK;;AAEhE,QAAO;;AAGT,SAAS,WAAW,MAAyB,OAAuB;AAClE,KAAI,OAAO,SAAS,SAAU,QAAO,KAAK,UAAU,KAAK;CACzD,MAAM,SAAS,KAAK,OAAO,MAAM;CACjC,MAAM,UAAU,KAAK,OAAO,QAAQ,EAAE;AAItC,QAAO,MAHS,OAAO,KAAK,KAAK,CAC9B,UAAU,CACV,KAAK,QAAQ,GAAG,SAAS,QAAQ,IAAI,CAAC,IAAI,WAAW,KAAK,MAAO,QAAQ,EAAE,GAAG,CAC5D,KAAK,MAAM,CAAC,KAAK,QAAQ;;;;;;;AAQhD,SAAS,QAAQ,KAAqB;AACpC,KAAI,qBAAqB,KAAK,IAAI,CAAE,QAAO;AAC3C,KAAI,iBAAiB,KAAK,IAAI,CAAE,QAAO;AACvC,QAAO,KAAK,UAAU,IAAI;;;AAI5B,SAAS,UAAU,KAAqB;AACtC,QAAO,qBAAqB,KAAK,IAAI,GAAG,MAAM,IAAI,IAAI,WAAW,WAAW,IAAI"}
1
+ {"version":3,"file":"css-in-js.mjs","names":[],"sources":["../src/css-in-js.ts"],"sourcesContent":["import type { Project, SwatchbookIntegration } from '@unpunnyfuns/swatchbook-core';\nimport { listPaths } from '@unpunnyfuns/swatchbook-core/graph';\n\nexport interface CssInJsIntegrationOptions {\n /**\n * Virtual module ID the addon serves. Default:\n * `'virtual:swatchbook/theme'`. Consumers import this string from\n * their preview (or stories) to receive a typed accessor object whose\n * leaves are `var(--<cssVarPrefix>-*)` references.\n */\n virtualId?: string;\n}\n\n/**\n * Preview-only CSS-in-JS integration for swatchbook's Storybook addon.\n * Contributes a virtual JS module exporting a nested accessor that mirrors\n * the project's token tree, every leaf a `var(--<cssVarPrefix>-*)` reference.\n * Stories import `{ theme }` the way their production components do, but\n * backed by swatchbook's runtime-switchable cascade rather than a concrete\n * theme object.\n *\n * The accessor is stable across tuples: its values are `var(...)` refs, so\n * the toolbar's `data-*` axis flips repaint through the cascade without\n * rebuilding the object. Consumers wire it into a provider once.\n *\n * Not a transform step. Consumers needing resolved-value permutations\n * (MUI `createTheme`, Vuetify factories) are out of scope — that's the\n * production CSS-in-JS emit, not this preview shim.\n *\n * ```ts\n * // .storybook/main.ts\n * import cssInJsIntegration from '@unpunnyfuns/swatchbook-integrations/css-in-js';\n *\n * export default defineMain({\n * addons: [\n * {\n * name: '@unpunnyfuns/swatchbook-addon',\n * options: {\n * configPath: '../swatchbook.config.ts',\n * integrations: [cssInJsIntegration()],\n * },\n * },\n * ],\n * });\n *\n * // Any story / component\n * import { theme, color, space } from 'virtual:swatchbook/theme';\n *\n * // styled-components / emotion\n * <ThemeProvider theme={theme}>...</ThemeProvider>\n *\n * // direct ref\n * const bg = color.surface.default; // -> \"var(--sb-color-surface-default)\"\n * ```\n */\nexport default function cssInJsIntegration(\n options: CssInJsIntegrationOptions = {},\n): SwatchbookIntegration {\n const virtualId = options.virtualId ?? 'virtual:swatchbook/theme';\n return {\n name: 'css-in-js',\n virtualModule: {\n virtualId,\n render: renderTheme,\n },\n };\n}\n\n// Render the virtual module source: one accessor export per top-level group,\n// plus the aggregate `theme`.\nfunction renderTheme(project: Project): string {\n const prefix = project.config.cssVarPrefix ?? '';\n const varPrefix = prefix ? `${prefix}-` : '';\n const paths = collectPaths(project);\n const tree = buildTree(paths, (path) => `var(--${varPrefix}${path.replaceAll('.', '-')})`);\n\n const groupNames = Object.keys(tree).toSorted();\n const groupExports = groupNames.map(\n (name) => `export const ${safeIdent(name)} = ${renderNode(tree[name]!, 1)};`,\n );\n const aggregate = `export const theme = { ${groupNames.map(safeIdent).join(', ')} };`;\n\n return [\n '/* Synthesized by @unpunnyfuns/swatchbook-integrations/css-in-js for preview.',\n ' * Served via `virtual:swatchbook/theme` — rebuilt on token changes. */',\n '',\n ...groupExports,\n '',\n aggregate,\n '',\n ].join('\\n');\n}\n\nfunction collectPaths(project: Project): string[] {\n // Mutable copy; listPaths returns a readonly array.\n return [...listPaths(project.tokenGraph)];\n}\n\ninterface TreeNode {\n [key: string]: TreeNode | string;\n}\n\n// Build a nested object tree from a sorted path list; leaves hold leafFor(path).\n// On a leaf/branch collision (a short path's leaf shares a key a longer path\n// wants to nest under) the leaf wins real DTCG trees don't hit this, but\n// explicit beats silent UB.\nfunction buildTree(sortedPaths: readonly string[], leafFor: (path: string) => string): TreeNode {\n const root: TreeNode = {};\n for (const path of sortedPaths) {\n const segments = path.split('.');\n let node = root;\n for (let i = 0; i < segments.length - 1; i++) {\n const seg = segments[i]!;\n const existing = node[seg];\n if (typeof existing === 'string') break;\n if (existing === undefined) {\n const next: TreeNode = {};\n node[seg] = next;\n node = next;\n } else {\n node = existing;\n }\n }\n const leafKey = segments.at(-1)!;\n if (node[leafKey] === undefined) node[leafKey] = leafFor(path);\n }\n return root;\n}\n\nfunction renderNode(node: TreeNode | string, depth: number): string {\n if (typeof node === 'string') return JSON.stringify(node);\n const indent = ' '.repeat(depth);\n const closing = ' '.repeat(depth - 1);\n const entries = Object.keys(node)\n .toSorted()\n .map((key) => `${indent}${safeKey(key)}: ${renderNode(node[key]!, depth + 1)}`);\n return `{\\n${entries.join(',\\n')},\\n${closing}}`;\n}\n\n// Bare identifier or canonical integer literal when safe, quoted otherwise.\n// Leading-zero numerics like \"050\" stay quoted bare 050 is octal in strict mode.\nfunction safeKey(key: string): string {\n if (/^[A-Za-z_$][\\w$]*$/.test(key)) return key;\n if (/^(0|[1-9]\\d*)$/.test(key)) return key;\n return JSON.stringify(key);\n}\n\n// Top-level exports must be valid JS identifiers.\nfunction safeIdent(key: string): string {\n return /^[A-Za-z_$][\\w$]*$/.test(key) ? key : `_${key.replaceAll(/[^\\w$]/g, '_')}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuDA,SAAwB,mBACtB,UAAqC,EAAE,EAChB;AAEvB,QAAO;EACL,MAAM;EACN,eAAe;GACb,WAJc,QAAQ,aAAa;GAKnC,QAAQ;GACT;EACF;;AAKH,SAAS,YAAY,SAA0B;CAC7C,MAAM,SAAS,QAAQ,OAAO,gBAAgB;CAC9C,MAAM,YAAY,SAAS,GAAG,OAAO,KAAK;CAE1C,MAAM,OAAO,UADC,aAAa,QAAQ,GACJ,SAAS,SAAS,YAAY,KAAK,WAAW,KAAK,IAAI,CAAC,GAAG;CAE1F,MAAM,aAAa,OAAO,KAAK,KAAK,CAAC,UAAU;CAC/C,MAAM,eAAe,WAAW,KAC7B,SAAS,gBAAgB,UAAU,KAAK,CAAC,KAAK,WAAW,KAAK,OAAQ,EAAE,CAAC,GAC3E;CACD,MAAM,YAAY,0BAA0B,WAAW,IAAI,UAAU,CAAC,KAAK,KAAK,CAAC;AAEjF,QAAO;EACL;EACA;EACA;EACA,GAAG;EACH;EACA;EACA;EACD,CAAC,KAAK,KAAK;;AAGd,SAAS,aAAa,SAA4B;AAEhD,QAAO,CAAC,GAAG,UAAU,QAAQ,WAAW,CAAC;;AAW3C,SAAS,UAAU,aAAgC,SAA6C;CAC9F,MAAM,OAAiB,EAAE;AACzB,MAAK,MAAM,QAAQ,aAAa;EAC9B,MAAM,WAAW,KAAK,MAAM,IAAI;EAChC,IAAI,OAAO;AACX,OAAK,IAAI,IAAI,GAAG,IAAI,SAAS,SAAS,GAAG,KAAK;GAC5C,MAAM,MAAM,SAAS;GACrB,MAAM,WAAW,KAAK;AACtB,OAAI,OAAO,aAAa,SAAU;AAClC,OAAI,aAAa,KAAA,GAAW;IAC1B,MAAM,OAAiB,EAAE;AACzB,SAAK,OAAO;AACZ,WAAO;SAEP,QAAO;;EAGX,MAAM,UAAU,SAAS,GAAG,GAAG;AAC/B,MAAI,KAAK,aAAa,KAAA,EAAW,MAAK,WAAW,QAAQ,KAAK;;AAEhE,QAAO;;AAGT,SAAS,WAAW,MAAyB,OAAuB;AAClE,KAAI,OAAO,SAAS,SAAU,QAAO,KAAK,UAAU,KAAK;CACzD,MAAM,SAAS,KAAK,OAAO,MAAM;CACjC,MAAM,UAAU,KAAK,OAAO,QAAQ,EAAE;AAItC,QAAO,MAHS,OAAO,KAAK,KAAK,CAC9B,UAAU,CACV,KAAK,QAAQ,GAAG,SAAS,QAAQ,IAAI,CAAC,IAAI,WAAW,KAAK,MAAO,QAAQ,EAAE,GAAG,CAC5D,KAAK,MAAM,CAAC,KAAK,QAAQ;;AAKhD,SAAS,QAAQ,KAAqB;AACpC,KAAI,qBAAqB,KAAK,IAAI,CAAE,QAAO;AAC3C,KAAI,iBAAiB,KAAK,IAAI,CAAE,QAAO;AACvC,QAAO,KAAK,UAAU,IAAI;;AAI5B,SAAS,UAAU,KAAqB;AACtC,QAAO,qBAAqB,KAAK,IAAI,GAAG,MAAM,IAAI,IAAI,WAAW,WAAW,IAAI"}
package/dist/tailwind.mjs CHANGED
@@ -48,15 +48,14 @@ function tailwindIntegration(options = {}) {
48
48
  }
49
49
  function renderTailwindTheme(project, roles) {
50
50
  const prefix = project.config.cssVarPrefix ?? "";
51
- const sourcePrefix = prefix ? `${prefix}-` : "";
52
- const scopePrefix = prefix ? `${prefix}-` : "";
51
+ const varPrefix = prefix ? `${prefix}-` : "";
53
52
  const entries = [];
54
53
  for (const [scale, names] of Object.entries(roles)) {
55
54
  if (names.length === 0) continue;
56
55
  entries.push(` /* ${scale} */`);
57
56
  for (const [themeKey, sourcePath] of names) {
58
- const sourceVar = `--${sourcePrefix}${sourcePath.replaceAll(".", "-")}`;
59
- const themeVar = `--${scale}-${scopePrefix}${themeKey}`;
57
+ const sourceVar = `--${varPrefix}${sourcePath.replaceAll(".", "-")}`;
58
+ const themeVar = `--${scale}-${varPrefix}${themeKey}`;
60
59
  entries.push(` ${themeVar}: var(${sourceVar});`);
61
60
  }
62
61
  entries.push("");
@@ -73,24 +72,6 @@ function renderTailwindTheme(project, roles) {
73
72
  ""
74
73
  ].join("\n");
75
74
  }
76
- /**
77
- * Walk the project's default-theme token graph and classify each entry
78
- * into a Tailwind scale based on its `$type` + path. Returns a role map
79
- * shaped the same as a user-supplied `roles` option.
80
- *
81
- * Scale assignment:
82
- * - `$type: 'color'` → `color`, role = path minus `color.` prefix
83
- * - `$type: 'dimension'` → `spacing` (default), `radius` (if path starts with
84
- * `radius.`, `borderRadius.`, or `border-radius.`), or nothing (skipped)
85
- * for dimensions that look like font sizes (`font.size.*`, `text.*`), since
86
- * Tailwind's `--text-*` scale needs size + line-height pairs this preview
87
- * integration doesn't synthesize
88
- * - `$type: 'shadow'` → `shadow`, role = path minus `shadow.` prefix
89
- * - `$type: 'fontFamily'` → `font`, role = path minus `font.` / `font.family.` / `fontFamily.` prefix
90
- *
91
- * Other `$type`s are skipped — they don't have a natural single-value
92
- * Tailwind utility and would produce broken output.
93
- */
94
75
  function deriveRoles(project) {
95
76
  const scales = {
96
77
  color: [],
@@ -1 +1 @@
1
- {"version":3,"file":"tailwind.mjs","names":[],"sources":["../src/tailwind.ts"],"sourcesContent":["import type { Project, SwatchbookIntegration } from '@unpunnyfuns/swatchbook-core';\n\nexport interface TailwindIntegrationOptions {\n /**\n * Virtual module ID the addon serves. Storybook users import this\n * string from their preview to receive the rendered `@theme` block.\n * Default: `'virtual:swatchbook/tailwind.css'`.\n */\n virtualId?: string;\n /**\n * Override the auto-derived role map. Keys are Tailwind scale names\n * (`color`, `spacing`, `radius`, `shadow`, `font`); values are ordered\n * `[tailwindEntryName, dtcgPath]` pairs. Supplied map **replaces** the\n * derived one — pass your own to pin exact entries, restrict the\n * universe of emitted utilities, or name scales the derivation doesn't\n * cover.\n *\n * Omit to let the integration derive a role map from the project at\n * render time: every `color` token lands under the `color` scale,\n * every `dimension` token under `spacing` / `radius` based on its\n * path prefix, every `shadow` under `shadow`, every `fontFamily` under\n * `font`. Works for any DTCG project without a configuration step.\n */\n roles?: Readonly<Record<string, readonly (readonly [string, string])[]>>;\n}\n\ntype RoleMap = Readonly<Record<string, readonly (readonly [string, string])[]>>;\n\n/**\n * Preview-only Tailwind v4 integration for the swatchbook Storybook\n * addon. Contributes a virtual CSS module whose `@theme` block aliases\n * Tailwind utility scales to the project's DTCG tokens via\n * `var(--<cssVarPrefix>-*)` references, so stories authored with\n * utility classes render correctly inside Storybook and react to the\n * toolbar's axis flips. This is not a replacement for the consumer's\n * production Tailwind build.\n *\n * Every entry is nested under the project's own `cssVarPrefix` so it\n * never collides with Tailwind's shipped scales: with\n * `cssVarPrefix: 'sb'` you get `--color-sb-surface-default`,\n * `--spacing-sb-md`, etc., generating utilities `bg-sb-surface-default`\n * and `p-sb-md` that coexist with `bg-red-500` / `p-4` / `max-w-md`.\n *\n * ```ts\n * // .storybook/main.ts\n * import tailwindIntegration from '@unpunnyfuns/swatchbook-integrations/tailwind';\n *\n * export default defineMain({\n * addons: [\n * {\n * name: '@unpunnyfuns/swatchbook-addon',\n * options: {\n * configPath: '../swatchbook.config.ts',\n * integrations: [tailwindIntegration()],\n * },\n * },\n * ],\n * });\n *\n * // .storybook/preview.tsx\n * import 'virtual:swatchbook/tailwind.css';\n * ```\n */\nexport default function tailwindIntegration(\n options: TailwindIntegrationOptions = {},\n): SwatchbookIntegration {\n const virtualId = options.virtualId ?? 'virtual:swatchbook/tailwind.css';\n const userRoles = options.roles;\n\n return {\n name: 'tailwind',\n virtualModule: {\n virtualId,\n render: (project) => renderTailwindTheme(project, userRoles ?? deriveRoles(project)),\n // Tailwind's `@theme` block is a global stylesheet — exactly the\n // kind of payload the addon should auto-inject into the preview,\n // so consumers don't hand-write a second `import` line after\n // plugging the integration in.\n autoInject: true,\n },\n };\n}\n\nfunction renderTailwindTheme(project: Project, roles: RoleMap): string {\n const prefix = project.config.cssVarPrefix ?? '';\n const sourcePrefix = prefix ? `${prefix}-` : '';\n const scopePrefix = prefix ? `${prefix}-` : '';\n\n const entries: string[] = [];\n for (const [scale, names] of Object.entries(roles)) {\n if (names.length === 0) continue;\n entries.push(` /* ${scale} */`);\n for (const [themeKey, sourcePath] of names) {\n const sourceVar = `--${sourcePrefix}${sourcePath.replaceAll('.', '-')}`;\n const themeVar = `--${scale}-${scopePrefix}${themeKey}`;\n entries.push(` ${themeVar}: var(${sourceVar});`);\n }\n entries.push('');\n }\n while (entries.length > 0 && entries.at(-1) === '') entries.pop();\n\n return [\n '/* Synthesized by @unpunnyfuns/swatchbook-integrations/tailwind for preview.',\n ' * Served via `virtual:swatchbook/tailwind.css` — rebuilt on token changes. */',\n \"@import 'tailwindcss';\",\n '',\n '@theme {',\n ...entries,\n '}',\n '',\n ].join('\\n');\n}\n\n/**\n * Walk the project's default-theme token graph and classify each entry\n * into a Tailwind scale based on its `$type` + path. Returns a role map\n * shaped the same as a user-supplied `roles` option.\n *\n * Scale assignment:\n * - `$type: 'color'` → `color`, role = path minus `color.` prefix\n * - `$type: 'dimension'` → `spacing` (default), `radius` (if path starts with\n * `radius.`, `borderRadius.`, or `border-radius.`), or nothing (skipped)\n * for dimensions that look like font sizes (`font.size.*`, `text.*`), since\n * Tailwind's `--text-*` scale needs size + line-height pairs this preview\n * integration doesn't synthesize\n * - `$type: 'shadow'` → `shadow`, role = path minus `shadow.` prefix\n * - `$type: 'fontFamily'` → `font`, role = path minus `font.` / `font.family.` / `fontFamily.` prefix\n *\n * Other `$type`s are skipped — they don't have a natural single-value\n * Tailwind utility and would produce broken output.\n */\nfunction deriveRoles(project: Project): RoleMap {\n const scales: Record<string, [string, string][]> = {\n color: [],\n spacing: [],\n radius: [],\n shadow: [],\n font: [],\n };\n\n for (const [path, token] of Object.entries(project.defaultTokens)) {\n const classification = classify(path, token.$type);\n if (!classification) continue;\n const { scale, role } = classification;\n if (!role) continue;\n scales[scale]?.push([role, path]);\n }\n\n const out: Record<string, readonly (readonly [string, string])[]> = {};\n for (const [scale, entries] of Object.entries(scales)) {\n if (entries.length === 0) continue;\n entries.sort(([a], [b]) => a.localeCompare(b, 'en'));\n out[scale] = entries;\n }\n return out;\n}\n\nconst SPACING_ROOTS = ['space', 'spacing'] as const;\nconst RADIUS_ROOTS = ['radius', 'borderRadius', 'border-radius'] as const;\nconst FONT_PREFIXES = ['font.family.', 'fontFamily.', 'font.'] as const;\n\nfunction classify(path: string, type: string | undefined): { scale: string; role: string } | null {\n switch (type) {\n case 'color':\n return { scale: 'color', role: stripPrefix(path, 'color.') };\n case 'shadow':\n return { scale: 'shadow', role: stripPrefix(path, 'shadow.') };\n case 'fontFamily': {\n for (const prefix of FONT_PREFIXES) {\n if (path.startsWith(prefix)) {\n return { scale: 'font', role: pathToRole(path.slice(prefix.length)) };\n }\n }\n return { scale: 'font', role: pathToRole(path) };\n }\n case 'dimension': {\n const head = path.split('.', 1)[0] ?? '';\n if ((RADIUS_ROOTS as readonly string[]).includes(head)) {\n return { scale: 'radius', role: pathToRole(path.slice(head.length + 1)) };\n }\n if ((SPACING_ROOTS as readonly string[]).includes(head)) {\n return { scale: 'spacing', role: pathToRole(path.slice(head.length + 1)) };\n }\n // Font-size-ish dimensions are skipped — Tailwind's `--text-*` entries\n // expect a size+line-height pair that this integration doesn't build.\n if (head === 'font' && /size|text/i.test(path)) return null;\n if (head === 'text') return null;\n // Default-bucket any other dimension under spacing — safer than guessing.\n return { scale: 'spacing', role: pathToRole(path) };\n }\n default:\n return null;\n }\n}\n\nfunction stripPrefix(path: string, prefix: string): string {\n return pathToRole(path.startsWith(prefix) ? path.slice(prefix.length) : path);\n}\n\nfunction pathToRole(remainder: string): string {\n return remainder.replaceAll('.', '-');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tailwind.mjs","names":[],"sources":["../src/tailwind.ts"],"sourcesContent":["import type { Project, SwatchbookIntegration } from '@unpunnyfuns/swatchbook-core';\n\nexport interface TailwindIntegrationOptions {\n /**\n * Virtual module ID the addon serves. Storybook users import this\n * string from their preview to receive the rendered `@theme` block.\n * Default: `'virtual:swatchbook/tailwind.css'`.\n */\n virtualId?: string;\n /**\n * Override the auto-derived role map. Keys are Tailwind scale names\n * (`color`, `spacing`, `radius`, `shadow`, `font`); values are ordered\n * `[tailwindEntryName, dtcgPath]` pairs. Supplied map **replaces** the\n * derived one — pass your own to pin exact entries, restrict the\n * universe of emitted utilities, or name scales the derivation doesn't\n * cover.\n *\n * Omit to let the integration derive a role map from the project at\n * render time: every `color` token lands under the `color` scale,\n * every `dimension` token under `spacing` / `radius` based on its\n * path prefix, every `shadow` under `shadow`, every `fontFamily` under\n * `font`. Works for any DTCG project without a configuration step.\n */\n roles?: Readonly<Record<string, readonly (readonly [string, string])[]>>;\n}\n\ntype RoleMap = Readonly<Record<string, readonly (readonly [string, string])[]>>;\n\n/**\n * Preview-only Tailwind v4 integration for the swatchbook Storybook\n * addon. Contributes a virtual CSS module whose `@theme` block aliases\n * Tailwind utility scales to the project's DTCG tokens via\n * `var(--<cssVarPrefix>-*)` references, so stories authored with\n * utility classes render correctly inside Storybook and react to the\n * toolbar's axis flips. This is not a replacement for the consumer's\n * production Tailwind build.\n *\n * Every entry is nested under the project's own `cssVarPrefix` so it\n * never collides with Tailwind's shipped scales: with\n * `cssVarPrefix: 'sb'` you get `--color-sb-surface-default`,\n * `--spacing-sb-md`, etc., generating utilities `bg-sb-surface-default`\n * and `p-sb-md` that coexist with `bg-red-500` / `p-4` / `max-w-md`.\n *\n * ```ts\n * // .storybook/main.ts\n * import tailwindIntegration from '@unpunnyfuns/swatchbook-integrations/tailwind';\n *\n * export default defineMain({\n * addons: [\n * {\n * name: '@unpunnyfuns/swatchbook-addon',\n * options: {\n * configPath: '../swatchbook.config.ts',\n * integrations: [tailwindIntegration()],\n * },\n * },\n * ],\n * });\n *\n * // .storybook/preview.tsx\n * import 'virtual:swatchbook/tailwind.css';\n * ```\n */\nexport default function tailwindIntegration(\n options: TailwindIntegrationOptions = {},\n): SwatchbookIntegration {\n const virtualId = options.virtualId ?? 'virtual:swatchbook/tailwind.css';\n const userRoles = options.roles;\n\n return {\n name: 'tailwind',\n virtualModule: {\n virtualId,\n render: (project) => renderTailwindTheme(project, userRoles ?? deriveRoles(project)),\n // Tailwind's `@theme` block is a global stylesheet — exactly the\n // kind of payload the addon should auto-inject into the preview,\n // so consumers don't hand-write a second `import` line after\n // plugging the integration in.\n autoInject: true,\n },\n };\n}\n\nfunction renderTailwindTheme(project: Project, roles: RoleMap): string {\n const prefix = project.config.cssVarPrefix ?? '';\n const varPrefix = prefix ? `${prefix}-` : '';\n\n const entries: string[] = [];\n for (const [scale, names] of Object.entries(roles)) {\n if (names.length === 0) continue;\n entries.push(` /* ${scale} */`);\n for (const [themeKey, sourcePath] of names) {\n const sourceVar = `--${varPrefix}${sourcePath.replaceAll('.', '-')}`;\n const themeVar = `--${scale}-${varPrefix}${themeKey}`;\n entries.push(` ${themeVar}: var(${sourceVar});`);\n }\n entries.push('');\n }\n while (entries.length > 0 && entries.at(-1) === '') entries.pop();\n\n return [\n '/* Synthesized by @unpunnyfuns/swatchbook-integrations/tailwind for preview.',\n ' * Served via `virtual:swatchbook/tailwind.css` — rebuilt on token changes. */',\n \"@import 'tailwindcss';\",\n '',\n '@theme {',\n ...entries,\n '}',\n '',\n ].join('\\n');\n}\n\n// Classify each default-theme token into a Tailwind scale, dropping empty\n// scales. Returns the same shape as the `roles` option; per-token rules and\n// skip reasons live in classify().\nfunction deriveRoles(project: Project): RoleMap {\n const scales: Record<string, [string, string][]> = {\n color: [],\n spacing: [],\n radius: [],\n shadow: [],\n font: [],\n };\n\n for (const [path, token] of Object.entries(project.defaultTokens)) {\n const classification = classify(path, token.$type);\n if (!classification) continue;\n const { scale, role } = classification;\n if (!role) continue;\n scales[scale]?.push([role, path]);\n }\n\n const out: Record<string, readonly (readonly [string, string])[]> = {};\n for (const [scale, entries] of Object.entries(scales)) {\n if (entries.length === 0) continue;\n entries.sort(([a], [b]) => a.localeCompare(b, 'en'));\n out[scale] = entries;\n }\n return out;\n}\n\nconst SPACING_ROOTS = ['space', 'spacing'] as const;\nconst RADIUS_ROOTS = ['radius', 'borderRadius', 'border-radius'] as const;\nconst FONT_PREFIXES = ['font.family.', 'fontFamily.', 'font.'] as const;\n\n// Map one token's $type + path to its Tailwind { scale, role }, or null to skip.\nfunction classify(path: string, type: string | undefined): { scale: string; role: string } | null {\n switch (type) {\n case 'color':\n return { scale: 'color', role: stripPrefix(path, 'color.') };\n case 'shadow':\n return { scale: 'shadow', role: stripPrefix(path, 'shadow.') };\n case 'fontFamily': {\n for (const prefix of FONT_PREFIXES) {\n if (path.startsWith(prefix)) {\n return { scale: 'font', role: pathToRole(path.slice(prefix.length)) };\n }\n }\n return { scale: 'font', role: pathToRole(path) };\n }\n case 'dimension': {\n const head = path.split('.', 1)[0] ?? '';\n if ((RADIUS_ROOTS as readonly string[]).includes(head)) {\n return { scale: 'radius', role: pathToRole(path.slice(head.length + 1)) };\n }\n if ((SPACING_ROOTS as readonly string[]).includes(head)) {\n return { scale: 'spacing', role: pathToRole(path.slice(head.length + 1)) };\n }\n // Font-size-ish dimensions are skipped — Tailwind's `--text-*` entries\n // expect a size+line-height pair that this integration doesn't build.\n if (head === 'font' && /size|text/i.test(path)) return null;\n if (head === 'text') return null;\n // Default-bucket any other dimension under spacing — safer than guessing.\n return { scale: 'spacing', role: pathToRole(path) };\n }\n default:\n return null;\n }\n}\n\nfunction stripPrefix(path: string, prefix: string): string {\n return pathToRole(path.startsWith(prefix) ? path.slice(prefix.length) : path);\n}\n\nfunction pathToRole(remainder: string): string {\n return remainder.replaceAll('.', '-');\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unpunnyfuns/swatchbook-integrations",
3
- "version": "0.60.8",
3
+ "version": "0.61.0",
4
4
  "description": "Display-side integrations for the swatchbook Storybook addon. Each subpath (./tailwind, …) exports a factory that plugs into the addon's options as a SwatchbookIntegration.",
5
5
  "license": "MIT",
6
6
  "author": "unpunnyfuns <unpunnyfuns@gmail.com>",
@@ -44,13 +44,13 @@
44
44
  "access": "public"
45
45
  },
46
46
  "dependencies": {
47
- "@unpunnyfuns/swatchbook-core": "0.60.8"
47
+ "@unpunnyfuns/swatchbook-core": "0.61.0"
48
48
  },
49
49
  "devDependencies": {
50
50
  "@types/node": "^25.6.0",
51
51
  "tsdown": "^0.21.9",
52
52
  "typescript": "^6.0.0",
53
- "vitest": "^4.1.4",
53
+ "vitest": "^4.1.7",
54
54
  "@unpunnyfuns/swatchbook-tokens": "0.0.0"
55
55
  },
56
56
  "scripts": {