meno-core 1.0.45 → 1.0.46

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.
Files changed (56) hide show
  1. package/build-astro.ts +214 -63
  2. package/dist/bin/cli.js +2 -2
  3. package/dist/build-static.js +7 -7
  4. package/dist/chunks/{chunk-NZTSJS5C.js → chunk-2QK6U5UK.js} +3 -2
  5. package/dist/chunks/{chunk-NZTSJS5C.js.map → chunk-2QK6U5UK.js.map} +2 -2
  6. package/dist/chunks/{chunk-BZQKEJQY.js → chunk-77ZB6353.js} +29 -18
  7. package/dist/chunks/chunk-77ZB6353.js.map +7 -0
  8. package/dist/chunks/{chunk-TVH3TC2T.js → chunk-C6U5T5S5.js} +6 -6
  9. package/dist/chunks/{chunk-5ZASE4IG.js → chunk-FED5MME6.js} +234 -11
  10. package/dist/chunks/{chunk-5ZASE4IG.js.map → chunk-FED5MME6.js.map} +3 -3
  11. package/dist/chunks/{chunk-5Z5VQRTJ.js → chunk-I7YIGZXT.js} +4 -4
  12. package/dist/chunks/{chunk-5Z5VQRTJ.js.map → chunk-I7YIGZXT.js.map} +2 -2
  13. package/dist/chunks/{chunk-OUNJ76QM.js → chunk-ORN7S4AP.js} +5 -5
  14. package/dist/chunks/{chunk-GYF3ABI3.js → chunk-UUA5LEWF.js} +3 -3
  15. package/dist/chunks/{chunk-GYF3ABI3.js.map → chunk-UUA5LEWF.js.map} +2 -2
  16. package/dist/chunks/{chunk-WQSG5WHC.js → chunk-ZTKHJQ2Z.js} +2 -2
  17. package/dist/chunks/{chunk-F7MA62WG.js → chunk-ZWYDT3QJ.js} +3 -3
  18. package/dist/chunks/{configService-6KTT6GRT.js → configService-DYCUEURL.js} +3 -3
  19. package/dist/chunks/{constants-L5IKLB6U.js → constants-GWBAD66U.js} +2 -2
  20. package/dist/entries/server-router.js +7 -7
  21. package/dist/lib/client/index.js +4 -4
  22. package/dist/lib/server/index.js +586 -142
  23. package/dist/lib/server/index.js.map +3 -3
  24. package/dist/lib/shared/index.js +7 -3
  25. package/dist/lib/shared/index.js.map +2 -2
  26. package/dist/lib/test-utils/index.js +1 -1
  27. package/lib/client/templateEngine.test.ts +64 -0
  28. package/lib/server/astro/astroEmitHelpers.ts +18 -0
  29. package/lib/server/astro/cmsPageEmitter.ts +31 -1
  30. package/lib/server/astro/componentEmitter.test.ts +59 -0
  31. package/lib/server/astro/componentEmitter.ts +43 -10
  32. package/lib/server/astro/cssCollector.ts +58 -11
  33. package/lib/server/astro/nodeToAstro.test.ts +397 -5
  34. package/lib/server/astro/nodeToAstro.ts +478 -63
  35. package/lib/server/astro/pageEmitter.ts +31 -1
  36. package/lib/server/astro/tailwindMapper.test.ts +119 -0
  37. package/lib/server/astro/tailwindMapper.ts +67 -1
  38. package/lib/server/runtime/httpServer.ts +12 -4
  39. package/lib/server/ssr/htmlGenerator.ts +1 -1
  40. package/lib/server/ssr/jsCollector.ts +2 -2
  41. package/lib/server/ssr/ssrRenderer.test.ts +32 -0
  42. package/lib/server/ssr/ssrRenderer.ts +26 -11
  43. package/lib/shared/constants.ts +1 -0
  44. package/lib/shared/cssGeneration.test.ts +109 -3
  45. package/lib/shared/cssGeneration.ts +98 -13
  46. package/lib/shared/cssNamedColors.ts +47 -0
  47. package/lib/shared/cssProperties.ts +2 -2
  48. package/lib/shared/index.ts +1 -0
  49. package/package.json +1 -1
  50. package/dist/chunks/chunk-BZQKEJQY.js.map +0 -7
  51. /package/dist/chunks/{chunk-TVH3TC2T.js.map → chunk-C6U5T5S5.js.map} +0 -0
  52. /package/dist/chunks/{chunk-OUNJ76QM.js.map → chunk-ORN7S4AP.js.map} +0 -0
  53. /package/dist/chunks/{chunk-WQSG5WHC.js.map → chunk-ZTKHJQ2Z.js.map} +0 -0
  54. /package/dist/chunks/{chunk-F7MA62WG.js.map → chunk-ZWYDT3QJ.js.map} +0 -0
  55. /package/dist/chunks/{configService-6KTT6GRT.js.map → configService-DYCUEURL.js.map} +0 -0
  56. /package/dist/chunks/{constants-L5IKLB6U.js.map → constants-GWBAD66U.js.map} +0 -0
@@ -10,6 +10,7 @@ import { nodeToAstro, type AstroEmitContext } from './nodeToAstro';
10
10
  import { transformCMSTemplate } from './templateTransformer';
11
11
  import type { ImageMetadataMap } from '../ssr/imageMetadata';
12
12
  import type { SlugMap } from '../../shared/slugTranslator';
13
+ import type { ResponsiveScales } from '../../shared/responsiveScaling';
13
14
 
14
15
  // ---------------------------------------------------------------------------
15
16
  // Types
@@ -46,6 +47,8 @@ export interface CMSPageEmitOptions {
46
47
  pageName: string;
47
48
  /** Breakpoint config for responsive Tailwind classes */
48
49
  breakpoints?: BreakpointConfig;
50
+ /** Responsive scales config for auto-scaling at breakpoints */
51
+ responsiveScales?: ResponsiveScales;
49
52
  /** Image metadata map for responsive image generation */
50
53
  imageMetadataMap?: ImageMetadataMap;
51
54
  /** Internationalization config */
@@ -56,6 +59,12 @@ export interface CMSPageEmitOptions {
56
59
  slugMappings?: SlugMap[];
57
60
  /** Image format: 'webp' uses plain <img>, 'avif' uses <picture> */
58
61
  imageFormat?: 'webp' | 'avif';
62
+ /**
63
+ * Raw-HTML slice → processed HTML captured during the template's SSR pass.
64
+ * Ensures `<Fragment set:html>` matches SSR output for rich-text content
65
+ * (image rewriting, component expansion, link localization).
66
+ */
67
+ processedRawHtml?: Map<string, string>;
59
68
  }
60
69
 
61
70
  // ---------------------------------------------------------------------------
@@ -63,7 +72,12 @@ export interface CMSPageEmitOptions {
63
72
  // ---------------------------------------------------------------------------
64
73
 
65
74
  function escapeTemplateLiteral(s: string): string {
66
- return s.replace(/\\/g, '\\\\').replace(/`/g, '\\`').replace(/\$\{/g, '\\${');
75
+ return s
76
+ .replace(/\\/g, '\\\\')
77
+ .replace(/`/g, '\\`')
78
+ .replace(/\$\{/g, '\\${')
79
+ .replace(/\u2028/g, '\\u2028')
80
+ .replace(/\u2029/g, '\\u2029');
67
81
  }
68
82
 
69
83
  function escapeJSX(s: string): string {
@@ -247,10 +261,12 @@ export function emitCMSPage(options: CMSPageEmitOptions): string {
247
261
  ssrFallbacks,
248
262
  pageName,
249
263
  breakpoints: breakpointsOpt,
264
+ responsiveScales,
250
265
  imageMetadataMap,
251
266
  i18nConfig,
252
267
  isMultiLocale,
253
268
  slugMappings,
269
+ processedRawHtml,
254
270
  } = options;
255
271
 
256
272
  const breakpoints = breakpointsOpt ?? DEFAULT_BREAKPOINTS;
@@ -289,6 +305,7 @@ export function emitCMSPage(options: CMSPageEmitOptions): string {
289
305
  fileType: 'page',
290
306
  fileName: pageName,
291
307
  breakpoints,
308
+ responsiveScales,
292
309
  imageMetadataMap,
293
310
  locale,
294
311
  cmsMode: true,
@@ -298,6 +315,9 @@ export function emitCMSPage(options: CMSPageEmitOptions): string {
298
315
  slugMappings,
299
316
  i18nDefaultLocale: i18nConfig.defaultLocale,
300
317
  imageFormat: options.imageFormat,
318
+ processedRawHtml,
319
+ imageImports: new Map<string, string>(),
320
+ fileDepth,
301
321
  };
302
322
 
303
323
  // Emit the template body
@@ -308,6 +328,16 @@ export function emitCMSPage(options: CMSPageEmitOptions): string {
308
328
  importLines.push(`import { getCollection } from 'astro:content';`);
309
329
  importLines.push(`import BaseLayout from '${layoutImportPath}';`);
310
330
 
331
+ // Static image imports (astro:assets <Picture>). Map size is the single
332
+ // source of truth — a separate boolean would be lost by child-ctx spreads.
333
+ if (ctx.imageImports && ctx.imageImports.size > 0) {
334
+ importLines.push(`import { Picture } from 'astro:assets';`);
335
+ const sortedImages = Array.from(ctx.imageImports.entries()).sort(([a], [b]) => a.localeCompare(b));
336
+ for (const [varName, importPath] of sortedImages) {
337
+ importLines.push(`import ${varName} from '${importPath}';`);
338
+ }
339
+ }
340
+
311
341
  // Sort component imports alphabetically
312
342
  const componentImports = Array.from(ctx.imports).sort();
313
343
  for (const comp of componentImports) {
@@ -0,0 +1,59 @@
1
+ import { describe, test, expect } from 'bun:test';
2
+ import { emitAstroComponent } from './componentEmitter';
3
+ import type { ComponentDefinition } from '../../shared/types';
4
+
5
+ function makeComponent(overrides: Partial<ComponentDefinition['component']> = {}): ComponentDefinition {
6
+ return {
7
+ component: {
8
+ interface: {},
9
+ structure: { type: 'node', tag: 'div', children: [] } as unknown as ComponentDefinition['component']['structure'],
10
+ ...overrides,
11
+ },
12
+ };
13
+ }
14
+
15
+ describe('emitAstroComponent — RAW_HTML_PREFIX stripping', () => {
16
+ test('strips marker from rich-text string default in frontmatter', () => {
17
+ const def = makeComponent({
18
+ interface: {
19
+ text2: {
20
+ type: 'rich-text',
21
+ default: '<!--MENO_RAW_HTML-->SEO<br>Audit Blueprint',
22
+ } as unknown as import('../../shared/types').PropDefinition,
23
+ },
24
+ });
25
+ const out = emitAstroComponent('SeoAudit', def, {});
26
+ expect(out).not.toContain('MENO_RAW_HTML');
27
+ expect(out).toContain('text2 = "SEO<br>Audit Blueprint"');
28
+ });
29
+
30
+ test('strips marker from i18n default values', () => {
31
+ const def = makeComponent({
32
+ interface: {
33
+ text2: {
34
+ type: 'rich-text',
35
+ default: {
36
+ _i18n: true,
37
+ en: '<!--MENO_RAW_HTML-->SEO<br>Audit Blueprint',
38
+ pl: '<!--MENO_RAW_HTML-->Audyt SEO',
39
+ },
40
+ } as unknown as import('../../shared/types').PropDefinition,
41
+ },
42
+ });
43
+ const out = emitAstroComponent('SeoAudit', def, {});
44
+ expect(out).not.toContain('MENO_RAW_HTML');
45
+ });
46
+
47
+ test('leaves non-rich-text string defaults unchanged', () => {
48
+ const def = makeComponent({
49
+ interface: {
50
+ title: {
51
+ type: 'string',
52
+ default: 'Hello world',
53
+ } as unknown as import('../../shared/types').PropDefinition,
54
+ },
55
+ });
56
+ const out = emitAstroComponent('Heading', def, {});
57
+ expect(out).toContain('title = "Hello world"');
58
+ });
59
+ });
@@ -12,6 +12,8 @@ import type { BasePropDefinition, ListPropDefinition, LinkPropValue } from '../.
12
12
  import type { BreakpointConfig } from '../../shared/breakpoints';
13
13
  import { DEFAULT_BREAKPOINTS } from '../../shared/breakpoints';
14
14
  import { nodeToAstro, type AstroEmitContext } from './nodeToAstro';
15
+ import type { ResponsiveScales } from '../../shared/responsiveScaling';
16
+ import { stripRawHtmlPrefixDeep } from './astroEmitHelpers';
15
17
 
16
18
  // ---------------------------------------------------------------------------
17
19
  // Helpers
@@ -49,7 +51,7 @@ function propDefToTSType(def: PropDefinition): string {
49
51
  */
50
52
  function formatDefault(def: PropDefinition): string | null {
51
53
  if (!('default' in def) || def.default === undefined) return null;
52
- const val = def.default;
54
+ const val = stripRawHtmlPrefixDeep(def.default);
53
55
 
54
56
  if (typeof val === 'string') return JSON.stringify(val);
55
57
  if (typeof val === 'number' || typeof val === 'boolean') return String(val);
@@ -129,7 +131,8 @@ export function emitAstroComponent(
129
131
  def: ComponentDefinition,
130
132
  allComponents: Record<string, ComponentDefinition>,
131
133
  breakpoints: BreakpointConfig = DEFAULT_BREAKPOINTS,
132
- defaultLocale: string = 'en'
134
+ defaultLocale: string = 'en',
135
+ responsiveScales?: ResponsiveScales
133
136
  ): string {
134
137
  const comp = def.component;
135
138
  const propDefs = comp.interface || {};
@@ -152,7 +155,10 @@ export function emitAstroComponent(
152
155
  fileType: 'component',
153
156
  fileName: name,
154
157
  breakpoints,
158
+ responsiveScales,
155
159
  defaultLocale,
160
+ imageImports: new Map<string, string>(),
161
+ fileDepth: 0, // components live at src/components/
156
162
  };
157
163
 
158
164
  // Emit the template body
@@ -162,7 +168,14 @@ export function emitAstroComponent(
162
168
  templateBody = mergeClassNameOntoRoot(templateBody);
163
169
 
164
170
  // Build frontmatter (includes class prop for instance style support)
165
- const frontmatter = buildFrontmatter(name, propDefs, ctx.imports, ctx.dynamicTags, ctx.needsI18nResolver ? defaultLocale : undefined);
171
+ const frontmatter = buildFrontmatter(
172
+ name,
173
+ propDefs,
174
+ ctx.imports,
175
+ ctx.dynamicTags,
176
+ ctx.needsI18nResolver ? defaultLocale : undefined,
177
+ ctx.imageImports
178
+ );
166
179
 
167
180
  // Build style/script sections
168
181
  const styleSection = comp.css ? `\n<style>\n${comp.css}\n</style>\n` : '';
@@ -181,7 +194,8 @@ function buildFrontmatter(
181
194
  propDefs: Record<string, PropDefinition>,
182
195
  imports: Set<string>,
183
196
  dynamicTags?: Map<string, string>,
184
- i18nDefaultLocale?: string
197
+ i18nDefaultLocale?: string,
198
+ imageImports?: Map<string, string>
185
199
  ): string {
186
200
  const lines: string[] = [];
187
201
 
@@ -190,6 +204,16 @@ function buildFrontmatter(
190
204
  lines.push(`import ${imp} from './${imp}.astro';`);
191
205
  }
192
206
 
207
+ // Static image imports (astro:assets <Picture>). Map size is the single
208
+ // source of truth — a separate boolean would be lost by child-ctx spreads.
209
+ if (imageImports && imageImports.size > 0) {
210
+ lines.push(`import { Picture } from 'astro:assets';`);
211
+ const sortedImages = Array.from(imageImports.entries()).sort(([a], [b]) => a.localeCompare(b));
212
+ for (const [varName, importPath] of sortedImages) {
213
+ lines.push(`import ${varName} from '${importPath}';`);
214
+ }
215
+ }
216
+
193
217
  if (lines.length > 0) lines.push('');
194
218
 
195
219
  const propEntries = Object.entries(propDefs);
@@ -314,16 +338,25 @@ function transformDefineVarsJS(js: string, varNames: string[]): string {
314
338
 
315
339
  /**
316
340
  * Build the script section with proper el/props initialization.
317
- * - defineVars components: use Astro's define:vars to pass props into inline script
318
- * - other components: use is:inline to avoid module bundling
319
- * Both cases use document.currentScript.previousElementSibling to get el.
341
+ * Captures el immediately via document.currentScript.previousElementSibling,
342
+ * then defers actual JS execution until DOMContentLoaded so that external
343
+ * libraries (e.g. Swiper loaded with defer) are available.
320
344
  */
321
345
  function buildScriptSection(
322
346
  js: string,
323
347
  comp: StructuredComponentDefinition,
324
348
  propDefs: Record<string, PropDefinition>
325
349
  ): string {
326
- const elInit = 'const el = document.currentScript.previousElementSibling;';
350
+ // Capture el immediately (document.currentScript is only valid during script execution)
351
+ // but defer the component init until DOMContentLoaded so deferred libraries are ready
352
+ // Remove whitespace-only text nodes so Astro's formatted HTML matches SSR's minified output.
353
+ // Without this, scripts that use firstChild/childNodes pick up whitespace between elements.
354
+ const cleanTextNodes = `(function _w(n){var c=n.firstChild,x;while(c){x=c.nextSibling;if(c.nodeType===3){if(!c.textContent.trim())n.removeChild(c)}else if(c.nodeType===1)_w(c);c=x}})(el);`;
355
+
356
+ const deferWrapper = (innerJS: string) =>
357
+ `var el = document.currentScript.previousElementSibling;\n` +
358
+ `function __init__() {\n${cleanTextNodes}\n${innerJS}\n}\n` +
359
+ `if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', __init__); } else { __init__(); }`;
327
360
 
328
361
  if (comp.defineVars) {
329
362
  const vars = comp.defineVars === true
@@ -333,9 +366,9 @@ function buildScriptSection(
333
366
  if (vars.length > 0) {
334
367
  const transformedJS = transformDefineVarsJS(js, vars);
335
368
  const defineVarsObj = `{ ${vars.join(', ')} }`;
336
- return `\n<script define:vars={${defineVarsObj}}>\n${elInit}\n${transformedJS}\n</script>\n`;
369
+ return `\n<script define:vars={${defineVarsObj}}>\n(function(){\n${deferWrapper(transformedJS)}\n})();\n</script>\n`;
337
370
  }
338
371
  }
339
372
 
340
- return `\n<script is:inline>\n${elInit}\n${js}\n</script>\n`;
373
+ return `\n<script is:inline>\n(function(){\n${deferWrapper(js)}\n})();\n</script>\n`;
341
374
  }
@@ -14,6 +14,8 @@ import type {
14
14
  import type { BreakpointConfig } from '../../shared/breakpoints';
15
15
  import { DEFAULT_BREAKPOINTS } from '../../shared/breakpoints';
16
16
  import { propertyToTailwind } from './tailwindMapper';
17
+ import type { ResponsiveScales, CSSPropertyType } from '../../shared/responsiveScaling';
18
+ import { getScaleMultiplier, scalePropertyValue } from '../../shared/responsiveScaling';
17
19
 
18
20
  // ---------------------------------------------------------------------------
19
21
  // Helpers
@@ -40,7 +42,8 @@ function isResponsiveStyle(
40
42
  function collectFromStyle(
41
43
  style: StyleObject | ResponsiveStyleObject | undefined,
42
44
  classes: Set<string>,
43
- breakpoints: BreakpointConfig
45
+ breakpoints: BreakpointConfig,
46
+ responsiveScales?: ResponsiveScales
44
47
  ): void {
45
48
  if (!style) return;
46
49
 
@@ -48,24 +51,46 @@ function collectFromStyle(
48
51
  for (const [bp, bpStyle] of Object.entries(style)) {
49
52
  if (!bpStyle) continue;
50
53
  let prefix = '';
54
+ let bpName: string | undefined;
51
55
  if (bp !== 'base') {
52
56
  const bpValue = breakpoints[bp]?.breakpoint;
53
57
  if (bpValue) {
54
58
  prefix = `max-[${bpValue}px]:`;
59
+ bpName = bp;
55
60
  }
56
61
  }
57
- collectFromFlatStyle(bpStyle, prefix, classes);
62
+ collectFromFlatStyle(bpStyle, prefix, classes, breakpoints, responsiveScales, bpName);
58
63
  }
59
64
  } else {
60
- collectFromFlatStyle(style, '', classes);
65
+ collectFromFlatStyle(style, '', classes, breakpoints, responsiveScales);
61
66
  }
62
67
  }
63
68
 
64
69
  function collectFromFlatStyle(
65
70
  style: StyleObject,
66
71
  prefix: string,
67
- classes: Set<string>
72
+ classes: Set<string>,
73
+ breakpoints: BreakpointConfig,
74
+ responsiveScales?: ResponsiveScales,
75
+ sourceBreakpoint?: string
68
76
  ): void {
77
+ // Only auto-scale when mapping value lives in the base branch (or a flat
78
+ // top-level style). Mappings inside an explicit breakpoint branch already
79
+ // describe the override the author wants — don't re-scale them.
80
+ const shouldAutoScale =
81
+ responsiveScales?.enabled === true && sourceBreakpoint === undefined;
82
+
83
+ const scaleBreakpoints = shouldAutoScale
84
+ ? Object.entries(breakpoints)
85
+ .map(([name, cfg]) => ({ name, value: cfg?.breakpoint }))
86
+ .filter((bp): bp is { name: string; value: number } =>
87
+ typeof bp.value === 'number' && bp.value > 0
88
+ )
89
+ .sort((a, b) => b.value - a.value)
90
+ : [];
91
+
92
+ const baseRef = responsiveScales?.baseReference ?? 16;
93
+
69
94
  for (const [property, value] of Object.entries(style)) {
70
95
  if (!isStyleMapping(value)) continue;
71
96
 
@@ -75,6 +100,26 @@ function collectFromFlatStyle(
75
100
  if (twClass) {
76
101
  classes.add(prefix ? `${prefix}${twClass}` : twClass);
77
102
  }
103
+
104
+ // Safelist auto-scaled `max-[Npx]:` variants so Tailwind generates
105
+ // CSS for each breakpoint-scaled class the runtime might produce.
106
+ if (shouldAutoScale && responsiveScales) {
107
+ const strValue = String(cssValue);
108
+ if (strValue === '') continue;
109
+ for (const { name: bpName, value: bpPixels } of scaleBreakpoints) {
110
+ const scale = getScaleMultiplier(
111
+ responsiveScales,
112
+ property as CSSPropertyType,
113
+ bpName
114
+ );
115
+ if (scale == null) continue;
116
+ const scaledValue = scalePropertyValue(strValue, baseRef, scale);
117
+ if (scaledValue == null || scaledValue === strValue) continue;
118
+ const scaledClass = propertyToTailwind(property, scaledValue);
119
+ if (!scaledClass) continue;
120
+ classes.add(`max-[${bpPixels}px]:${scaledClass}`);
121
+ }
122
+ }
78
123
  }
79
124
  }
80
125
  }
@@ -85,27 +130,28 @@ function collectFromFlatStyle(
85
130
  function walkNode(
86
131
  node: ComponentNode | ComponentNode[] | string | number | null | undefined,
87
132
  classes: Set<string>,
88
- breakpoints: BreakpointConfig
133
+ breakpoints: BreakpointConfig,
134
+ responsiveScales?: ResponsiveScales
89
135
  ): void {
90
136
  if (!node || typeof node === 'string' || typeof node === 'number') return;
91
137
 
92
138
  if (Array.isArray(node)) {
93
139
  for (const child of node) {
94
- walkNode(child, classes, breakpoints);
140
+ walkNode(child, classes, breakpoints, responsiveScales);
95
141
  }
96
142
  return;
97
143
  }
98
144
 
99
145
  // Collect from style
100
146
  if ('style' in node && node.style) {
101
- collectFromStyle(node.style as StyleObject | ResponsiveStyleObject, classes, breakpoints);
147
+ collectFromStyle(node.style as StyleObject | ResponsiveStyleObject, classes, breakpoints, responsiveScales);
102
148
  }
103
149
 
104
150
  // Collect from interactive styles
105
151
  if ('interactiveStyles' in node && Array.isArray((node as any).interactiveStyles)) {
106
152
  for (const rule of (node as any).interactiveStyles) {
107
153
  if (rule.style) {
108
- collectFromStyle(rule.style, classes, breakpoints);
154
+ collectFromStyle(rule.style, classes, breakpoints, responsiveScales);
109
155
  }
110
156
  }
111
157
  }
@@ -114,7 +160,7 @@ function walkNode(
114
160
  if ('children' in node && node.children) {
115
161
  if (Array.isArray(node.children)) {
116
162
  for (const child of node.children) {
117
- walkNode(child as ComponentNode, classes, breakpoints);
163
+ walkNode(child as ComponentNode, classes, breakpoints, responsiveScales);
118
164
  }
119
165
  }
120
166
  }
@@ -132,14 +178,15 @@ function walkNode(
132
178
  */
133
179
  export function collectAllMappingClasses(
134
180
  componentDefs: Record<string, ComponentDefinition>,
135
- breakpoints: BreakpointConfig = DEFAULT_BREAKPOINTS
181
+ breakpoints: BreakpointConfig = DEFAULT_BREAKPOINTS,
182
+ responsiveScales?: ResponsiveScales
136
183
  ): Set<string> {
137
184
  const classes = new Set<string>();
138
185
 
139
186
  for (const def of Object.values(componentDefs)) {
140
187
  const structure = def.component?.structure;
141
188
  if (structure) {
142
- walkNode(structure, classes, breakpoints);
189
+ walkNode(structure, classes, breakpoints, responsiveScales);
143
190
  }
144
191
  }
145
192