@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.
- package/README.md +18 -2
- package/dist/cjs/env.js +23 -0
- package/dist/cjs/index.js +4 -1
- package/dist/cjs/load.js +62 -16
- package/dist/cjs/metadata.js +5 -81
- package/dist/cjs/render.js +434 -28
- package/dist/cjs/sitemap.js +41 -0
- package/dist/esm/env.js +23 -0
- package/dist/esm/index.js +4 -1
- package/dist/esm/load.js +52 -16
- package/dist/esm/metadata.js +4 -80
- package/dist/esm/render.js +434 -28
- package/dist/esm/sitemap.js +22 -0
- package/env.js +17 -0
- package/index.js +5 -2
- package/load.js +58 -19
- package/metadata.js +3 -115
- package/package.json +10 -9
- package/render.js +481 -29
- package/sitemap.js +28 -0
package/dist/cjs/render.js
CHANGED
|
@@ -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) =>
|
|
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
|
-
|
|
133
|
-
|
|
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("<")) {
|
|
171
|
+
const unescaped = content.replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&").replace(/"/g, '"').replace(/'/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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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)] =
|
|
675
|
+
result[camelToKebab(k)] = resolveDSValue(k, v, ds);
|
|
313
676
|
}
|
|
314
677
|
return result;
|
|
315
678
|
};
|
|
316
|
-
const buildCSSFromProps = (props,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
703
|
+
for (const ek in expanded) {
|
|
704
|
+
base[ek] = resolveDSValue(ek, expanded[ek], ds);
|
|
705
|
+
}
|
|
341
706
|
continue;
|
|
342
707
|
}
|
|
343
|
-
base[camelToKebab(key)] =
|
|
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
|
|
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,
|
|
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
|
|
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
|
-
|
|
434
|
-
|
|
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
|
+
}
|