@symbo.ls/brender 3.5.0 → 3.6.1

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.
@@ -30,9 +30,11 @@ __export(render_exports, {
30
30
  render: () => render,
31
31
  renderElement: () => renderElement,
32
32
  renderPage: () => renderPage,
33
- renderRoute: () => renderRoute
33
+ renderRoute: () => renderRoute,
34
+ resetGlobalCSSCache: () => resetGlobalCSSCache
34
35
  });
35
36
  module.exports = __toCommonJS(render_exports);
37
+ var import_path = require("path");
36
38
  var import_env = require("./env.js");
37
39
  var import_keys = require("./keys.js");
38
40
  var import_metadata = require("./metadata.js");
@@ -61,7 +63,13 @@ const UIKIT_STUBS = {
61
63
  Img: {
62
64
  tag: "img",
63
65
  attr: {
64
- src: (el) => el.props?.src,
66
+ src: (el) => {
67
+ let src = el.props?.src;
68
+ if (typeof src === "string" && src.includes("{{")) {
69
+ src = el.call("replaceLiteralsWithObjectFields", src, el.state);
70
+ }
71
+ return src;
72
+ },
65
73
  alt: (el) => el.props?.alt,
66
74
  loading: (el) => el.props?.loading
67
75
  }
@@ -86,7 +94,15 @@ const UIKIT_STUBS = {
86
94
  H3: { tag: "h3" },
87
95
  H4: { tag: "h4" },
88
96
  H5: { tag: "h5" },
89
- H6: { tag: "h6" }
97
+ H6: { tag: "h6" },
98
+ Svg: {
99
+ tag: "svg",
100
+ attr: {
101
+ xmlns: "http://www.w3.org/2000/svg",
102
+ "xmlns:xlink": "http://www.w3.org/1999/xlink"
103
+ }
104
+ },
105
+ Text: { tag: "span" }
90
106
  };
91
107
  const render = async (data, options = {}) => {
92
108
  const { route = "/", state: stateOverrides, context: contextOverrides } = options;
@@ -127,16 +143,186 @@ const renderElement = async (elementDef, options = {}) => {
127
143
  const { window, document } = (0, import_env.createEnv)();
128
144
  const body = document.body;
129
145
  const { create } = await import("@domql/element");
146
+ const domqlUtils = await import("@domql/utils");
130
147
  const components = { ...UIKIT_STUBS, ...context.components || {} };
148
+ const utils = {
149
+ ...domqlUtils,
150
+ ...context.utils || {},
151
+ ...context.functions || {}
152
+ };
131
153
  (0, import_keys.resetKeys)();
132
- const element = create(elementDef, { node: body }, "root", {
133
- context: { document, window, ...context, components }
134
- });
154
+ let element;
155
+ try {
156
+ element = create(elementDef, { node: body }, "root", {
157
+ context: { document, window, ...context, components, utils }
158
+ });
159
+ } catch (err) {
160
+ }
135
161
  (0, import_keys.assignKeys)(body);
136
- const registry = (0, import_keys.mapKeysToElements)(element);
137
- const html = body.innerHTML;
162
+ const registry = element ? (0, import_keys.mapKeysToElements)(element) : {};
163
+ const html = fixSvgContent(body.innerHTML);
138
164
  return { html, registry, element };
139
165
  };
166
+ const fixSvgContent = (html) => {
167
+ return html.replace(
168
+ /(<svg\b[^>]*>)([\s\S]*?)(<\/svg>)/gi,
169
+ (match, open, content, close) => {
170
+ if (content.includes("&lt;")) {
171
+ const unescaped = content.replace(/&lt;/g, "<").replace(/&gt;/g, ">").replace(/&amp;/g, "&").replace(/&quot;/g, '"').replace(/&#39;/g, "'");
172
+ return open + unescaped + close;
173
+ }
174
+ return match;
175
+ }
176
+ );
177
+ };
178
+ let _cachedGlobalCSS = null;
179
+ const generateGlobalCSS = async (ds, config) => {
180
+ if (_cachedGlobalCSS) return _cachedGlobalCSS;
181
+ try {
182
+ const { existsSync, writeFileSync, unlinkSync } = await import("fs");
183
+ const { tmpdir } = await import("os");
184
+ const { randomBytes } = await import("crypto");
185
+ const esbuild = await import("esbuild");
186
+ const dsJson = JSON.stringify(ds || {});
187
+ const cfgJson = JSON.stringify(config || {});
188
+ const tmpEntry = (0, import_path.join)(tmpdir(), `br_global_${randomBytes(6).toString("hex")}.mjs`);
189
+ const tmpOut = (0, import_path.join)(tmpdir(), `br_global_${randomBytes(6).toString("hex")}_out.mjs`);
190
+ writeFileSync(tmpEntry, `
191
+ import { set, getActiveConfig, getFontFaceString } from '@symbo.ls/scratch'
192
+ import { DEFAULT_CONFIG } from '@symbo.ls/default-config'
193
+
194
+ const ds = ${dsJson}
195
+ const cfg = ${cfgJson}
196
+
197
+ // Merge with defaults (same as initEmotion)
198
+ const merged = {}
199
+ for (const k in DEFAULT_CONFIG) merged[k] = DEFAULT_CONFIG[k]
200
+ for (const k in ds) {
201
+ if (typeof ds[k] === 'object' && !Array.isArray(ds[k]) && typeof merged[k] === 'object' && !Array.isArray(merged[k])) {
202
+ merged[k] = { ...merged[k], ...ds[k] }
203
+ } else {
204
+ merged[k] = ds[k]
205
+ }
206
+ }
207
+
208
+ const conf = set({
209
+ useReset: true,
210
+ useVariable: true,
211
+ useFontImport: true,
212
+ useDocumentTheme: true,
213
+ useDefaultConfig: true,
214
+ globalTheme: 'auto',
215
+ ...merged,
216
+ ...cfg
217
+ }, { newConfig: {} })
218
+
219
+ const result = {
220
+ CSS_VARS: conf.CSS_VARS || {},
221
+ CSS_MEDIA_VARS: conf.CSS_MEDIA_VARS || {},
222
+ RESET: conf.RESET || conf.reset || {},
223
+ ANIMATION: conf.animation || conf.ANIMATION || {}
224
+ }
225
+ // Export as globalThis so we can read it
226
+ globalThis.__BR_GLOBAL_CSS__ = result
227
+ export default result
228
+ `);
229
+ const brenderDir = new URL(".", import_meta.url).pathname;
230
+ const monorepoRoot = (0, import_path.resolve)(brenderDir, "../..");
231
+ const workspacePlugin = {
232
+ name: "workspace-resolve",
233
+ setup(build) {
234
+ build.onResolve({ filter: /^@symbo\.ls\// }, (args) => {
235
+ const pkg = args.path.replace("@symbo.ls/", "");
236
+ for (const dir of ["packages", "plugins"]) {
237
+ const src = (0, import_path.resolve)(monorepoRoot, dir, pkg, "src", "index.js");
238
+ if (existsSync(src)) return { path: src };
239
+ const dist = (0, import_path.resolve)(monorepoRoot, dir, pkg, "index.js");
240
+ if (existsSync(dist)) return { path: dist };
241
+ }
242
+ const blank = (0, import_path.resolve)(monorepoRoot, "packages", "default-config", "blank", "index.js");
243
+ if (pkg === "default-config" && existsSync(blank)) return { path: blank };
244
+ });
245
+ build.onResolve({ filter: /^@domql\// }, (args) => {
246
+ const pkg = args.path.replace("@domql/", "");
247
+ const src = (0, import_path.resolve)(monorepoRoot, "packages", "domql", "packages", pkg, "src", "index.js");
248
+ if (existsSync(src)) return { path: src };
249
+ });
250
+ }
251
+ };
252
+ await esbuild.build({
253
+ entryPoints: [tmpEntry],
254
+ bundle: true,
255
+ format: "esm",
256
+ platform: "node",
257
+ outfile: tmpOut,
258
+ write: true,
259
+ logLevel: "silent",
260
+ plugins: [workspacePlugin],
261
+ external: ["fs", "path", "os", "crypto", "url", "http", "https", "stream", "util", "events", "buffer", "child_process", "worker_threads", "net", "tls", "dns", "dgram", "zlib", "assert", "querystring", "string_decoder", "readline", "perf_hooks", "async_hooks", "v8", "vm", "cluster", "inspector", "module", "process", "tty", "color-contrast-checker"]
262
+ });
263
+ const mod = await import(`file://${tmpOut}`);
264
+ const data = mod.default || {};
265
+ try {
266
+ unlinkSync(tmpEntry);
267
+ } catch {
268
+ }
269
+ try {
270
+ unlinkSync(tmpOut);
271
+ } catch {
272
+ }
273
+ const cssVars = data.CSS_VARS || {};
274
+ const cssMediaVars = data.CSS_MEDIA_VARS || {};
275
+ const reset = data.RESET || {};
276
+ const animations = data.ANIMATION || {};
277
+ const varDecls = Object.entries(cssVars).map(([k, v]) => ` ${k}: ${v}`).join(";\n");
278
+ let rootRule = varDecls ? `:root {
279
+ ${varDecls};
280
+ }` : "";
281
+ const themeVarRules = Object.entries(cssMediaVars).map(([key, vars]) => {
282
+ const decls = Object.entries(vars).map(([k, v]) => ` ${k}: ${v}`).join(";\n");
283
+ if (!decls) return "";
284
+ if (key.startsWith("@media")) {
285
+ return `${key} {
286
+ :root:not([data-theme]) {
287
+ ${decls};
288
+ }
289
+ }`;
290
+ }
291
+ return `${key} {
292
+ ${decls};
293
+ }`;
294
+ }).filter(Boolean).join("\n\n");
295
+ if (themeVarRules) rootRule += "\n\n" + themeVarRules;
296
+ const resetRules = generateResetCSS(reset);
297
+ const keyframeRules = [];
298
+ for (const name in animations) {
299
+ const frames = animations[name];
300
+ if (!frames || typeof frames !== "object") continue;
301
+ const frameRules = Object.entries(frames).map(([step, p]) => {
302
+ if (typeof p !== "object") return "";
303
+ const decls = Object.entries(p).map(([k, v]) => `${camelToKebab(k)}: ${v}`).join("; ");
304
+ return ` ${step} { ${decls}; }`;
305
+ }).join("\n");
306
+ keyframeRules.push(`@keyframes ${name} {
307
+ ${frameRules}
308
+ }`);
309
+ }
310
+ _cachedGlobalCSS = {
311
+ rootRule,
312
+ resetRules,
313
+ fontFaceCSS: "",
314
+ keyframeRules: keyframeRules.join("\n")
315
+ };
316
+ return _cachedGlobalCSS;
317
+ } catch (err) {
318
+ console.warn("generateGlobalCSS failed:", err.message, err.stack);
319
+ _cachedGlobalCSS = { rootRule: "", resetRules: "", fontFaceCSS: "", keyframeRules: "" };
320
+ return _cachedGlobalCSS;
321
+ }
322
+ };
323
+ const resetGlobalCSSCache = () => {
324
+ _cachedGlobalCSS = null;
325
+ };
140
326
  const renderRoute = async (data, options = {}) => {
141
327
  const { route = "/" } = options;
142
328
  const ds = data.designSystem || {};
@@ -166,38 +352,202 @@ const renderRoute = async (data, options = {}) => {
166
352
  emotion: emotionInstance,
167
353
  designSystem: ds
168
354
  });
355
+ const globalCSS = await generateGlobalCSS(ds, data.config || data.settings);
169
356
  return {
170
357
  html: cssDoc.body.innerHTML,
171
358
  css: extractCSS(result.element, ds),
172
- resetCss: generateResetCSS(ds.reset),
359
+ globalCSS,
360
+ resetCss: globalCSS.resetRules || generateResetCSS(ds.reset),
173
361
  fontLinks: generateFontLinks(ds),
174
362
  metadata: (0, import_metadata.extractMetadata)(data, route),
175
363
  brKeyCount: Object.keys(result.registry).length
176
364
  };
177
365
  };
178
366
  const renderPage = async (data, route = "/", options = {}) => {
179
- const { lang = "en", themeColor } = options;
367
+ const { lang = "en", themeColor, isr } = options;
180
368
  const result = await renderRoute(data, { route });
181
369
  if (!result) return null;
182
370
  const metadata = { ...result.metadata };
183
371
  if (themeColor) metadata["theme-color"] = themeColor;
184
372
  const headTags = (0, import_metadata.generateHeadHtml)(metadata);
373
+ const globalCSS = result.globalCSS || {};
374
+ let isrBody = "";
375
+ if (isr && isr.clientScript) {
376
+ const depth = route === "/" ? 0 : route.replace(/^\/|\/$/g, "").split("/").length;
377
+ const prefix = depth > 0 ? "../".repeat(depth) : "./";
378
+ isrBody = `<script type="module">
379
+ {
380
+ const brEls = document.querySelectorAll('body > :not(script):not(style)')
381
+ const observer = new MutationObserver((mutations) => {
382
+ for (const m of mutations) {
383
+ for (const node of m.addedNodes) {
384
+ if (node.nodeType === 1 && node.tagName !== 'SCRIPT' && node.tagName !== 'STYLE' && !node.hasAttribute('data-br')) {
385
+ brEls.forEach(el => { if (el.hasAttribute('data-br') || el.querySelector('[data-br]')) el.remove() })
386
+ observer.disconnect()
387
+ return
388
+ }
389
+ }
390
+ }
391
+ })
392
+ observer.observe(document.body, { childList: true })
393
+ }
394
+ <\/script>
395
+ <script type="module" src="${prefix}${isr.clientScript}"><\/script>`;
396
+ }
185
397
  const html = `<!DOCTYPE html>
186
398
  <html lang="${lang}">
187
399
  <head>
188
400
  ${headTags}
189
401
  ${result.fontLinks}
190
- <style>${result.resetCss}</style>
402
+ ${globalCSS.fontFaceCSS ? `<style>${globalCSS.fontFaceCSS}</style>` : ""}
403
+ <style>
404
+ ${globalCSS.rootRule || ""}
405
+ ${result.resetCss}
406
+ ${globalCSS.keyframeRules || ""}
407
+ </style>
191
408
  <style data-emotion="smbls">
192
409
  ${result.css}
193
410
  </style>
194
411
  </head>
195
412
  <body>
196
413
  ${result.html}
414
+ ${isrBody}
197
415
  </body>
198
416
  </html>`;
199
417
  return { html, route, brKeyCount: result.brKeyCount };
200
418
  };
419
+ const LETTER_TO_INDEX = {
420
+ U: -6,
421
+ V: -5,
422
+ W: -4,
423
+ X: -3,
424
+ Y: -2,
425
+ Z: -1,
426
+ A: 0,
427
+ B: 1,
428
+ C: 2,
429
+ D: 3,
430
+ E: 4,
431
+ F: 5,
432
+ G: 6,
433
+ H: 7,
434
+ I: 8,
435
+ J: 9,
436
+ K: 10,
437
+ L: 11,
438
+ M: 12,
439
+ N: 13,
440
+ O: 14,
441
+ P: 15
442
+ };
443
+ const SPACING_PROPS = /* @__PURE__ */ new Set([
444
+ "padding",
445
+ "paddingTop",
446
+ "paddingRight",
447
+ "paddingBottom",
448
+ "paddingLeft",
449
+ "paddingBlock",
450
+ "paddingInline",
451
+ "paddingBlockStart",
452
+ "paddingBlockEnd",
453
+ "paddingInlineStart",
454
+ "paddingInlineEnd",
455
+ "margin",
456
+ "marginTop",
457
+ "marginRight",
458
+ "marginBottom",
459
+ "marginLeft",
460
+ "marginBlock",
461
+ "marginInline",
462
+ "marginBlockStart",
463
+ "marginBlockEnd",
464
+ "marginInlineStart",
465
+ "marginInlineEnd",
466
+ "gap",
467
+ "rowGap",
468
+ "columnGap",
469
+ "top",
470
+ "right",
471
+ "bottom",
472
+ "left",
473
+ "width",
474
+ "height",
475
+ "minWidth",
476
+ "maxWidth",
477
+ "minHeight",
478
+ "maxHeight",
479
+ "flexBasis",
480
+ "fontSize",
481
+ "lineHeight",
482
+ "letterSpacing",
483
+ "borderWidth",
484
+ "borderRadius",
485
+ "outlineWidth",
486
+ "outlineOffset",
487
+ "inset",
488
+ "insetBlock",
489
+ "insetInline",
490
+ "boxSize",
491
+ "round"
492
+ ]);
493
+ const resolveSpacingToken = (token, spacingConfig) => {
494
+ if (!token || typeof token !== "string") return null;
495
+ if (!spacingConfig) return null;
496
+ const base = spacingConfig.base || 16;
497
+ const ratio = spacingConfig.ratio || 1.618;
498
+ const unit = spacingConfig.unit || "px";
499
+ const hasSubSequence = spacingConfig.subSequence !== false;
500
+ if (token.includes(" ")) {
501
+ const parts = token.split(" ").map((part) => {
502
+ if (part === "-" || part === "") return part;
503
+ return resolveSpacingToken(part, spacingConfig) || part;
504
+ });
505
+ return parts.join(" ");
506
+ }
507
+ if (/^(none|auto|inherit|initial|unset|0)$/i.test(token)) return null;
508
+ if (/\d+(px|em|rem|%|vh|vw|vmin|vmax|ch|ex|cm|mm|in|pt|pc|fr|s|ms)$/i.test(token)) return null;
509
+ if (/^(#|rgb|hsl|var\()/i.test(token)) return null;
510
+ const isNegative = token.startsWith("-");
511
+ const abs = isNegative ? token.slice(1) : token;
512
+ const m = abs.match(/^([A-Z])(\d)?$/i);
513
+ if (!m) return null;
514
+ const letter = m[1].toUpperCase();
515
+ const subStep = m[2] ? parseInt(m[2]) : 0;
516
+ const idx = LETTER_TO_INDEX[letter];
517
+ if (idx === void 0) return null;
518
+ let value = base * Math.pow(ratio, idx);
519
+ if (subStep > 0 && hasSubSequence) {
520
+ const next = base * Math.pow(ratio, idx + 1);
521
+ const diff = next - value;
522
+ const subRatio = diff / ratio;
523
+ const first = next - subRatio;
524
+ const second = value + subRatio;
525
+ const middle = (first + second) / 2;
526
+ const subs = ~~next - ~~value > 16 ? [first, middle, second] : [first, second];
527
+ if (subStep <= subs.length) {
528
+ value = subs[subStep - 1];
529
+ }
530
+ }
531
+ const rounded = Math.round(value * 100) / 100;
532
+ const sign = isNegative ? "-" : "";
533
+ return `${sign}${rounded}${unit}`;
534
+ };
535
+ const SPACING_PROPS_KEBAB = new Set(
536
+ [...SPACING_PROPS].map((k) => k.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()))
537
+ );
538
+ const resolveDSValue = (key, val, ds) => {
539
+ if (typeof val !== "string") return val;
540
+ if (CSS_COLOR_PROPS.has(key)) {
541
+ const colorMap = ds?.color || {};
542
+ if (colorMap[val]) return colorMap[val];
543
+ }
544
+ if (SPACING_PROPS.has(key) || SPACING_PROPS_KEBAB.has(key)) {
545
+ const spacing = ds?.spacing || {};
546
+ const resolved = resolveSpacingToken(val, spacing);
547
+ if (resolved) return resolved;
548
+ }
549
+ return val;
550
+ };
201
551
  const CSS_COLOR_PROPS = /* @__PURE__ */ new Set([
202
552
  "color",
203
553
  "background",
@@ -237,7 +587,11 @@ const NON_CSS_PROPS = /* @__PURE__ */ new Set([
237
587
  "autofocus",
238
588
  "theme",
239
589
  "__element",
240
- "update"
590
+ "update",
591
+ "childrenAs",
592
+ "childExtends",
593
+ "childProps",
594
+ "children"
241
595
  ]);
242
596
  const camelToKebab = (str) => str.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
243
597
  const resolveShorthand = (key, val) => {
@@ -253,11 +607,15 @@ const resolveShorthand = (key, val) => {
253
607
  }
254
608
  if ((key === "align" || key === "flexAlign") && typeof val === "string") {
255
609
  const [alignItems, justifyContent] = val.split(" ");
256
- return { display: "flex", "align-items": alignItems, "justify-content": justifyContent };
610
+ const result = { display: "flex", "align-items": alignItems };
611
+ if (justifyContent) result["justify-content"] = justifyContent;
612
+ return result;
257
613
  }
258
614
  if (key === "gridAlign" && typeof val === "string") {
259
615
  const [alignItems, justifyContent] = val.split(" ");
260
- return { display: "grid", "align-items": alignItems, "justify-content": justifyContent };
616
+ const result = { display: "grid", "align-items": alignItems };
617
+ if (justifyContent) result["justify-content"] = justifyContent;
618
+ return result;
261
619
  }
262
620
  if (key === "flexFlow" && typeof val === "string") {
263
621
  let [direction, wrap] = (val || "row").split(" ");
@@ -268,6 +626,9 @@ const resolveShorthand = (key, val) => {
268
626
  if (key === "flexWrap") {
269
627
  return { display: "flex", "flex-wrap": val };
270
628
  }
629
+ if (key === "backgroundImage" && typeof val === "string" && !val.startsWith("url(") && !val.startsWith("linear-gradient") && !val.startsWith("radial-gradient") && !val.startsWith("none")) {
630
+ return { "background-image": `url(${val})` };
631
+ }
271
632
  if (key === "round" || key === "borderRadius" && val) {
272
633
  return { "border-radius": typeof val === "number" ? val + "px" : val };
273
634
  }
@@ -299,21 +660,23 @@ const resolveShorthand = (key, val) => {
299
660
  if (key === "rowStart") return { "grid-row-start": val };
300
661
  return null;
301
662
  };
302
- const resolveInnerProps = (obj, colorMap) => {
663
+ const resolveInnerProps = (obj, ds) => {
303
664
  const result = {};
304
665
  for (const k in obj) {
305
666
  const v = obj[k];
306
667
  const expanded = resolveShorthand(k, v);
307
668
  if (expanded) {
308
- Object.assign(result, expanded);
669
+ for (const ek in expanded) {
670
+ result[ek] = resolveDSValue(ek, expanded[ek], ds);
671
+ }
309
672
  continue;
310
673
  }
311
674
  if (typeof v !== "string" && typeof v !== "number") continue;
312
- result[camelToKebab(k)] = CSS_COLOR_PROPS.has(k) && colorMap[v] ? colorMap[v] : v;
675
+ result[camelToKebab(k)] = resolveDSValue(k, v, ds);
313
676
  }
314
677
  return result;
315
678
  };
316
- const buildCSSFromProps = (props, colorMap, mediaMap) => {
679
+ const buildCSSFromProps = (props, ds, mediaMap) => {
317
680
  const base = {};
318
681
  const mediaRules = {};
319
682
  const pseudoRules = {};
@@ -322,13 +685,13 @@ const buildCSSFromProps = (props, colorMap, mediaMap) => {
322
685
  if (key.charCodeAt(0) === 64 && typeof val === "object") {
323
686
  const bp = mediaMap?.[key.slice(1)];
324
687
  if (bp) {
325
- const inner = resolveInnerProps(val, colorMap);
688
+ const inner = resolveInnerProps(val, ds);
326
689
  if (Object.keys(inner).length) mediaRules[bp] = inner;
327
690
  }
328
691
  continue;
329
692
  }
330
693
  if (key.charCodeAt(0) === 58 && typeof val === "object") {
331
- const inner = resolveInnerProps(val, colorMap);
694
+ const inner = resolveInnerProps(val, ds);
332
695
  if (Object.keys(inner).length) pseudoRules[key] = inner;
333
696
  continue;
334
697
  }
@@ -337,10 +700,12 @@ const buildCSSFromProps = (props, colorMap, mediaMap) => {
337
700
  if (NON_CSS_PROPS.has(key)) continue;
338
701
  const expanded = resolveShorthand(key, val);
339
702
  if (expanded) {
340
- Object.assign(base, expanded);
703
+ for (const ek in expanded) {
704
+ base[ek] = resolveDSValue(ek, expanded[ek], ds);
705
+ }
341
706
  continue;
342
707
  }
343
- base[camelToKebab(key)] = CSS_COLOR_PROPS.has(key) && colorMap[val] ? colorMap[val] : val;
708
+ base[camelToKebab(key)] = resolveDSValue(key, val, ds);
344
709
  }
345
710
  return { base, mediaRules, pseudoRules };
346
711
  };
@@ -375,8 +740,35 @@ const getExtendsCSS = (el) => {
375
740
  }
376
741
  return null;
377
742
  };
743
+ const resolveElementProps = (el) => {
744
+ const { props } = el;
745
+ if (!props) return props;
746
+ let resolved;
747
+ for (const key in props) {
748
+ if (typeof props[key] !== "function") continue;
749
+ if (NON_CSS_PROPS.has(key)) continue;
750
+ if (key.charCodeAt(0) >= 65 && key.charCodeAt(0) <= 90) continue;
751
+ if (key.startsWith("on")) continue;
752
+ if (!resolved) resolved = { ...props };
753
+ let result;
754
+ try {
755
+ result = props[key](el, el.state || {});
756
+ } catch {
757
+ try {
758
+ const mockState = { root: {}, ...el.state || {} };
759
+ result = props[key](el, mockState);
760
+ } catch {
761
+ }
762
+ }
763
+ if (result !== void 0 && result !== null && result !== false) {
764
+ resolved[key] = result;
765
+ } else {
766
+ delete resolved[key];
767
+ }
768
+ }
769
+ return resolved || props;
770
+ };
378
771
  const extractCSS = (element, ds) => {
379
- const colorMap = ds?.color || {};
380
772
  const mediaMap = ds?.media || {};
381
773
  const animations = ds?.animation || {};
382
774
  const rules = [];
@@ -384,12 +776,12 @@ const extractCSS = (element, ds) => {
384
776
  const usedAnimations = /* @__PURE__ */ new Set();
385
777
  const walk = (el) => {
386
778
  if (!el || !el.__ref) return;
387
- const { props } = el;
779
+ const props = resolveElementProps(el);
388
780
  if (props && el.node) {
389
781
  const cls = el.node.getAttribute?.("class");
390
782
  if (cls && !seen.has(cls)) {
391
783
  seen.add(cls);
392
- const cssResult = buildCSSFromProps(props, colorMap, mediaMap);
784
+ const cssResult = buildCSSFromProps(props, ds, mediaMap);
393
785
  const extsCss = getExtendsCSS(el);
394
786
  if (extsCss) {
395
787
  for (const [k, v] of Object.entries(extsCss)) {
@@ -406,7 +798,7 @@ const extractCSS = (element, ds) => {
406
798
  }
407
799
  }
408
800
  }
409
- if (el.__ref.__children) {
801
+ if (el.__ref?.__children) {
410
802
  for (const ck of el.__ref.__children) {
411
803
  if (el[ck]?.__ref) walk(el[ck]);
412
804
  }
@@ -430,8 +822,21 @@ const generateResetCSS = (reset) => {
430
822
  if (!reset) return "";
431
823
  const rules = [];
432
824
  for (const [selector, props] of Object.entries(reset)) {
433
- const decls = Object.entries(props).map(([k, v]) => `${camelToKebab(k)}: ${v}`).join("; ");
434
- if (decls) rules.push(`${selector} { ${decls}; }`);
825
+ if (!props || typeof props !== "object") continue;
826
+ const baseDecls = [];
827
+ const mediaRules = [];
828
+ for (const [k, v] of Object.entries(props)) {
829
+ if (typeof v === "object" && v !== null) {
830
+ if (k.startsWith("@media") || k.startsWith("@")) {
831
+ const inner = Object.entries(v).filter(([, iv]) => typeof iv !== "object").map(([ik, iv]) => `${camelToKebab(ik)}: ${iv}`).join("; ");
832
+ if (inner) mediaRules.push(`${k} { ${selector} { ${inner}; } }`);
833
+ }
834
+ continue;
835
+ }
836
+ baseDecls.push(`${camelToKebab(k)}: ${v}`);
837
+ }
838
+ if (baseDecls.length) rules.push(`${selector} { ${baseDecls.join("; ")}; }`);
839
+ rules.push(...mediaRules);
435
840
  }
436
841
  return rules.join("\n");
437
842
  };
@@ -440,6 +845,7 @@ const generateFontLinks = (ds) => {
440
845
  const families = ds.font_family || ds.fontFamily || {};
441
846
  const fontNames = /* @__PURE__ */ new Set();
442
847
  for (const val of Object.values(families)) {
848
+ if (typeof val !== "string") continue;
443
849
  const match = val.match(/'([^']+)'/);
444
850
  if (match) fontNames.add(match[1]);
445
851
  }
@@ -0,0 +1,41 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var sitemap_exports = {};
19
+ __export(sitemap_exports, {
20
+ generateSitemap: () => generateSitemap
21
+ });
22
+ module.exports = __toCommonJS(sitemap_exports);
23
+ function generateSitemap(baseUrl, routes) {
24
+ const urls = Object.entries(routes).map(([path, config]) => {
25
+ const metadata = config.metadata || {};
26
+ const canonical = metadata.canonical || `${baseUrl}${path === "/" ? "" : path}`;
27
+ return `
28
+ <url>
29
+ <loc>${canonical}</loc>
30
+ <lastmod>${(/* @__PURE__ */ new Date()).toISOString()}</lastmod>
31
+ <changefreq>weekly</changefreq>
32
+ <priority>${path === "/" ? "1.0" : "0.8"}</priority>
33
+ </url>`;
34
+ });
35
+ return `<?xml version="1.0" encoding="UTF-8"?>
36
+ <urlset
37
+ xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
38
+ xmlns:xhtml="http://www.w3.org/1999/xhtml">
39
+ ${urls.join("\n")}
40
+ </urlset>`;
41
+ }