@domql/brender 3.2.7
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 +282 -0
- package/dist/cjs/env.js +57 -0
- package/dist/cjs/hydrate.js +472 -0
- package/dist/cjs/index.js +58 -0
- package/dist/cjs/keys.js +62 -0
- package/dist/cjs/load.js +82 -0
- package/dist/cjs/metadata.js +102 -0
- package/dist/cjs/render.js +341 -0
- package/dist/esm/env.js +38 -0
- package/dist/esm/hydrate.js +453 -0
- package/dist/esm/index.js +39 -0
- package/dist/esm/keys.js +43 -0
- package/dist/esm/load.js +63 -0
- package/dist/esm/metadata.js +83 -0
- package/dist/esm/render.js +311 -0
- package/env.js +43 -0
- package/hydrate.js +388 -0
- package/index.js +40 -0
- package/keys.js +54 -0
- package/load.js +81 -0
- package/metadata.js +117 -0
- package/package.json +48 -0
- package/render.js +386 -0
|
@@ -0,0 +1,102 @@
|
|
|
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 metadata_exports = {};
|
|
19
|
+
__export(metadata_exports, {
|
|
20
|
+
extractMetadata: () => extractMetadata,
|
|
21
|
+
generateHeadHtml: () => generateHeadHtml
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(metadata_exports);
|
|
24
|
+
const extractMetadata = (data, route = "/") => {
|
|
25
|
+
const pages = data.pages || {};
|
|
26
|
+
const page = pages[route];
|
|
27
|
+
let metadata = {};
|
|
28
|
+
if (data.integrations?.seo) {
|
|
29
|
+
metadata = { ...data.integrations.seo };
|
|
30
|
+
}
|
|
31
|
+
if (page) {
|
|
32
|
+
const pageMeta = page.metadata || page.helmet || {};
|
|
33
|
+
metadata = { ...metadata, ...pageMeta };
|
|
34
|
+
if (!metadata.title && page.state?.title) {
|
|
35
|
+
metadata.title = page.state.title;
|
|
36
|
+
}
|
|
37
|
+
if (!metadata.description && page.state?.description) {
|
|
38
|
+
metadata.description = page.state.description;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
if (!metadata.title) {
|
|
42
|
+
metadata.title = data.name || "Symbols";
|
|
43
|
+
}
|
|
44
|
+
return metadata;
|
|
45
|
+
};
|
|
46
|
+
const generateHeadHtml = (metadata) => {
|
|
47
|
+
const esc = (text) => {
|
|
48
|
+
if (text === null || text === void 0) return "";
|
|
49
|
+
const map = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
50
|
+
return text.toString().replace(/[&<>"']/g, (m) => map[m]);
|
|
51
|
+
};
|
|
52
|
+
const tags = [
|
|
53
|
+
'<meta charset="UTF-8">',
|
|
54
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">'
|
|
55
|
+
];
|
|
56
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
57
|
+
if (!value && value !== 0 && value !== false) continue;
|
|
58
|
+
if (key === "title") {
|
|
59
|
+
tags.push(`<title>${esc(value)}</title>`);
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (key === "canonical") {
|
|
63
|
+
tags.push(`<link rel="canonical" href="${esc(value)}">`);
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (key === "alternate" && Array.isArray(value)) {
|
|
67
|
+
value.forEach((alt) => {
|
|
68
|
+
if (typeof alt === "object") {
|
|
69
|
+
const attrs = Object.entries(alt).map(([k, v]) => `${k}="${esc(v)}"`).join(" ");
|
|
70
|
+
tags.push(`<link rel="alternate" ${attrs}>`);
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
const propertyPrefixes = ["og:", "article:", "product:", "fb:", "profile:", "book:", "business:", "music:", "video:"];
|
|
76
|
+
const namePrefixes = ["twitter:", "DC:", "DCTERMS:"];
|
|
77
|
+
const isProperty = propertyPrefixes.some((p) => key.startsWith(p));
|
|
78
|
+
const isName = namePrefixes.some((p) => key.startsWith(p));
|
|
79
|
+
if (key.startsWith("http-equiv:")) {
|
|
80
|
+
const httpKey = key.replace("http-equiv:", "");
|
|
81
|
+
tags.push(`<meta http-equiv="${esc(httpKey)}" content="${esc(value)}">`);
|
|
82
|
+
} else if (key.startsWith("itemprop:")) {
|
|
83
|
+
const itemKey = key.replace("itemprop:", "");
|
|
84
|
+
tags.push(`<meta itemprop="${esc(itemKey)}" content="${esc(value)}">`);
|
|
85
|
+
} else if (isProperty) {
|
|
86
|
+
if (Array.isArray(value)) {
|
|
87
|
+
value.forEach((v) => tags.push(`<meta property="${esc(key)}" content="${esc(v)}">`));
|
|
88
|
+
} else {
|
|
89
|
+
tags.push(`<meta property="${esc(key)}" content="${esc(value)}">`);
|
|
90
|
+
}
|
|
91
|
+
} else if (isName) {
|
|
92
|
+
tags.push(`<meta name="${esc(key)}" content="${esc(value)}">`);
|
|
93
|
+
} else if (key !== "favicon" && key !== "favicons") {
|
|
94
|
+
if (Array.isArray(value)) {
|
|
95
|
+
value.forEach((v) => tags.push(`<meta name="${esc(key)}" content="${esc(v)}">`));
|
|
96
|
+
} else if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
|
|
97
|
+
tags.push(`<meta name="${esc(key)}" content="${esc(value)}">`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return tags.join("\n");
|
|
102
|
+
};
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var render_exports = {};
|
|
29
|
+
__export(render_exports, {
|
|
30
|
+
render: () => render,
|
|
31
|
+
renderElement: () => renderElement,
|
|
32
|
+
renderPage: () => renderPage,
|
|
33
|
+
renderRoute: () => renderRoute
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(render_exports);
|
|
36
|
+
var import_env = require("./env.js");
|
|
37
|
+
var import_keys = require("./keys.js");
|
|
38
|
+
var import_metadata = require("./metadata.js");
|
|
39
|
+
var import_hydrate = require("./hydrate.js");
|
|
40
|
+
var import_linkedom = require("linkedom");
|
|
41
|
+
const import_meta = {};
|
|
42
|
+
const render = async (data, options = {}) => {
|
|
43
|
+
const { route = "/", state: stateOverrides, context: contextOverrides } = options;
|
|
44
|
+
const { window, document } = (0, import_env.createEnv)();
|
|
45
|
+
const body = document.body;
|
|
46
|
+
window.location.pathname = route;
|
|
47
|
+
const smblsSrc = new URL("../../packages/smbls/src/createDomql.js", import_meta.url);
|
|
48
|
+
const { createDomqlElement } = await import(smblsSrc.href);
|
|
49
|
+
const app = data.app || {};
|
|
50
|
+
const ctx = {
|
|
51
|
+
state: { ...data.state, ...stateOverrides || {} },
|
|
52
|
+
dependencies: data.dependencies || {},
|
|
53
|
+
components: data.components || {},
|
|
54
|
+
snippets: data.snippets || {},
|
|
55
|
+
pages: data.pages || {},
|
|
56
|
+
functions: data.functions || {},
|
|
57
|
+
methods: data.methods || {},
|
|
58
|
+
designSystem: data.designSystem || {},
|
|
59
|
+
files: data.files || {},
|
|
60
|
+
...data.config || data.settings || {},
|
|
61
|
+
// Virtual DOM environment
|
|
62
|
+
document,
|
|
63
|
+
window,
|
|
64
|
+
parent: { node: body },
|
|
65
|
+
// Caller overrides
|
|
66
|
+
...contextOverrides || {}
|
|
67
|
+
};
|
|
68
|
+
(0, import_keys.resetKeys)();
|
|
69
|
+
const element = await createDomqlElement(app, ctx);
|
|
70
|
+
(0, import_keys.assignKeys)(body);
|
|
71
|
+
const registry = (0, import_keys.mapKeysToElements)(element);
|
|
72
|
+
const metadata = (0, import_metadata.extractMetadata)(data, route);
|
|
73
|
+
const html = body.innerHTML;
|
|
74
|
+
return { html, metadata, registry, element };
|
|
75
|
+
};
|
|
76
|
+
const renderElement = async (elementDef, options = {}) => {
|
|
77
|
+
const { context = {} } = options;
|
|
78
|
+
const { window, document } = (0, import_env.createEnv)();
|
|
79
|
+
const body = document.body;
|
|
80
|
+
const { create } = await import("@domql/element");
|
|
81
|
+
(0, import_keys.resetKeys)();
|
|
82
|
+
const element = create(elementDef, { node: body }, "root", {
|
|
83
|
+
context: { document, window, ...context }
|
|
84
|
+
});
|
|
85
|
+
(0, import_keys.assignKeys)(body);
|
|
86
|
+
const registry = (0, import_keys.mapKeysToElements)(element);
|
|
87
|
+
const html = body.innerHTML;
|
|
88
|
+
return { html, registry, element };
|
|
89
|
+
};
|
|
90
|
+
const renderRoute = async (data, options = {}) => {
|
|
91
|
+
const { route = "/" } = options;
|
|
92
|
+
const ds = data.designSystem || {};
|
|
93
|
+
const pageDef = (data.pages || {})[route];
|
|
94
|
+
if (!pageDef) return null;
|
|
95
|
+
const result = await renderElement(pageDef, {
|
|
96
|
+
context: {
|
|
97
|
+
components: data.components || {},
|
|
98
|
+
snippets: data.snippets || {},
|
|
99
|
+
designSystem: ds,
|
|
100
|
+
state: data.state || {},
|
|
101
|
+
functions: data.functions || {},
|
|
102
|
+
methods: data.methods || {}
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
const { document: cssDoc } = (0, import_linkedom.parseHTML)(`<html><head></head><body>${result.html}</body></html>`);
|
|
106
|
+
let emotionInstance;
|
|
107
|
+
try {
|
|
108
|
+
const { default: createInstance } = await import("@emotion/css/create-instance");
|
|
109
|
+
emotionInstance = createInstance({ key: "smbls", container: cssDoc.head });
|
|
110
|
+
} catch {
|
|
111
|
+
}
|
|
112
|
+
(0, import_hydrate.hydrate)(result.element, {
|
|
113
|
+
root: cssDoc.body,
|
|
114
|
+
renderEvents: false,
|
|
115
|
+
events: false,
|
|
116
|
+
emotion: emotionInstance,
|
|
117
|
+
designSystem: ds
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
html: cssDoc.body.innerHTML,
|
|
121
|
+
css: extractCSS(result.element, ds),
|
|
122
|
+
resetCss: generateResetCSS(ds.reset),
|
|
123
|
+
fontLinks: generateFontLinks(ds),
|
|
124
|
+
metadata: (0, import_metadata.extractMetadata)(data, route),
|
|
125
|
+
brKeyCount: Object.keys(result.registry).length
|
|
126
|
+
};
|
|
127
|
+
};
|
|
128
|
+
const renderPage = async (data, route = "/", options = {}) => {
|
|
129
|
+
const { lang = "en", themeColor } = options;
|
|
130
|
+
const result = await renderRoute(data, { route });
|
|
131
|
+
if (!result) return null;
|
|
132
|
+
const metadata = { ...result.metadata };
|
|
133
|
+
if (themeColor) metadata["theme-color"] = themeColor;
|
|
134
|
+
const headTags = (0, import_metadata.generateHeadHtml)(metadata);
|
|
135
|
+
const html = `<!DOCTYPE html>
|
|
136
|
+
<html lang="${lang}">
|
|
137
|
+
<head>
|
|
138
|
+
${headTags}
|
|
139
|
+
${result.fontLinks}
|
|
140
|
+
<style>${result.resetCss}</style>
|
|
141
|
+
<style data-emotion="smbls">
|
|
142
|
+
${result.css}
|
|
143
|
+
</style>
|
|
144
|
+
</head>
|
|
145
|
+
<body>
|
|
146
|
+
${result.html}
|
|
147
|
+
</body>
|
|
148
|
+
</html>`;
|
|
149
|
+
return { html, route, brKeyCount: result.brKeyCount };
|
|
150
|
+
};
|
|
151
|
+
const CSS_COLOR_PROPS = /* @__PURE__ */ new Set([
|
|
152
|
+
"color",
|
|
153
|
+
"background",
|
|
154
|
+
"backgroundColor",
|
|
155
|
+
"borderColor",
|
|
156
|
+
"borderTopColor",
|
|
157
|
+
"borderRightColor",
|
|
158
|
+
"borderBottomColor",
|
|
159
|
+
"borderLeftColor",
|
|
160
|
+
"outlineColor",
|
|
161
|
+
"fill",
|
|
162
|
+
"stroke"
|
|
163
|
+
]);
|
|
164
|
+
const NON_CSS_PROPS = /* @__PURE__ */ new Set([
|
|
165
|
+
"href",
|
|
166
|
+
"src",
|
|
167
|
+
"alt",
|
|
168
|
+
"title",
|
|
169
|
+
"id",
|
|
170
|
+
"name",
|
|
171
|
+
"type",
|
|
172
|
+
"value",
|
|
173
|
+
"placeholder",
|
|
174
|
+
"target",
|
|
175
|
+
"rel",
|
|
176
|
+
"loading",
|
|
177
|
+
"srcset",
|
|
178
|
+
"sizes",
|
|
179
|
+
"media",
|
|
180
|
+
"role",
|
|
181
|
+
"tabindex",
|
|
182
|
+
"for",
|
|
183
|
+
"action",
|
|
184
|
+
"method",
|
|
185
|
+
"enctype",
|
|
186
|
+
"autocomplete",
|
|
187
|
+
"autofocus",
|
|
188
|
+
"theme",
|
|
189
|
+
"__element",
|
|
190
|
+
"update"
|
|
191
|
+
]);
|
|
192
|
+
const camelToKebab = (str) => str.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
|
193
|
+
const resolveShorthand = (key, val) => {
|
|
194
|
+
if (key === "flexAlign" && typeof val === "string") {
|
|
195
|
+
const [alignItems, justifyContent] = val.split(" ");
|
|
196
|
+
return { display: "flex", "align-items": alignItems, "justify-content": justifyContent };
|
|
197
|
+
}
|
|
198
|
+
if (key === "gridAlign" && typeof val === "string") {
|
|
199
|
+
const [alignItems, justifyContent] = val.split(" ");
|
|
200
|
+
return { display: "grid", "align-items": alignItems, "justify-content": justifyContent };
|
|
201
|
+
}
|
|
202
|
+
if (key === "round" && val) {
|
|
203
|
+
return { "border-radius": typeof val === "number" ? val + "px" : val };
|
|
204
|
+
}
|
|
205
|
+
if (key === "boxSize" && val) {
|
|
206
|
+
return { width: val, height: val };
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
};
|
|
210
|
+
const resolveInnerProps = (obj, colorMap) => {
|
|
211
|
+
const result = {};
|
|
212
|
+
for (const k in obj) {
|
|
213
|
+
const v = obj[k];
|
|
214
|
+
const expanded = resolveShorthand(k, v);
|
|
215
|
+
if (expanded) {
|
|
216
|
+
Object.assign(result, expanded);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
if (typeof v !== "string" && typeof v !== "number") continue;
|
|
220
|
+
result[camelToKebab(k)] = CSS_COLOR_PROPS.has(k) && colorMap[v] ? colorMap[v] : v;
|
|
221
|
+
}
|
|
222
|
+
return result;
|
|
223
|
+
};
|
|
224
|
+
const buildCSSFromProps = (props, colorMap, mediaMap) => {
|
|
225
|
+
const base = {};
|
|
226
|
+
const mediaRules = {};
|
|
227
|
+
const pseudoRules = {};
|
|
228
|
+
for (const key in props) {
|
|
229
|
+
const val = props[key];
|
|
230
|
+
if (key.charCodeAt(0) === 64 && typeof val === "object") {
|
|
231
|
+
const bp = mediaMap?.[key.slice(1)];
|
|
232
|
+
if (bp) {
|
|
233
|
+
const inner = resolveInnerProps(val, colorMap);
|
|
234
|
+
if (Object.keys(inner).length) mediaRules[bp] = inner;
|
|
235
|
+
}
|
|
236
|
+
continue;
|
|
237
|
+
}
|
|
238
|
+
if (key.charCodeAt(0) === 58 && typeof val === "object") {
|
|
239
|
+
const inner = resolveInnerProps(val, colorMap);
|
|
240
|
+
if (Object.keys(inner).length) pseudoRules[key] = inner;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (typeof val !== "string" && typeof val !== "number") continue;
|
|
244
|
+
if (key.charCodeAt(0) >= 65 && key.charCodeAt(0) <= 90) continue;
|
|
245
|
+
if (NON_CSS_PROPS.has(key)) continue;
|
|
246
|
+
const expanded = resolveShorthand(key, val);
|
|
247
|
+
if (expanded) {
|
|
248
|
+
Object.assign(base, expanded);
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
base[camelToKebab(key)] = CSS_COLOR_PROPS.has(key) && colorMap[val] ? colorMap[val] : val;
|
|
252
|
+
}
|
|
253
|
+
return { base, mediaRules, pseudoRules };
|
|
254
|
+
};
|
|
255
|
+
const renderCSSRule = (selector, { base, mediaRules, pseudoRules }) => {
|
|
256
|
+
const lines = [];
|
|
257
|
+
const baseDecls = Object.entries(base).map(([k, v]) => `${k}: ${v}`).join("; ");
|
|
258
|
+
if (baseDecls) lines.push(`${selector} { ${baseDecls}; }`);
|
|
259
|
+
for (const [pseudo, p] of Object.entries(pseudoRules)) {
|
|
260
|
+
const decls = Object.entries(p).map(([k, v]) => `${k}: ${v}`).join("; ");
|
|
261
|
+
if (decls) lines.push(`${selector}${pseudo} { ${decls}; }`);
|
|
262
|
+
}
|
|
263
|
+
for (const [query, p] of Object.entries(mediaRules)) {
|
|
264
|
+
const decls = Object.entries(p).map(([k, v]) => `${k}: ${v}`).join("; ");
|
|
265
|
+
const mq = query.startsWith("@") ? query : `@media ${query}`;
|
|
266
|
+
if (decls) lines.push(`${mq} { ${selector} { ${decls}; } }`);
|
|
267
|
+
}
|
|
268
|
+
return lines.join("\n");
|
|
269
|
+
};
|
|
270
|
+
const extractCSS = (element, ds) => {
|
|
271
|
+
const colorMap = ds?.color || {};
|
|
272
|
+
const mediaMap = ds?.media || {};
|
|
273
|
+
const animations = ds?.animation || {};
|
|
274
|
+
const rules = [];
|
|
275
|
+
const seen = /* @__PURE__ */ new Set();
|
|
276
|
+
const usedAnimations = /* @__PURE__ */ new Set();
|
|
277
|
+
const walk = (el) => {
|
|
278
|
+
if (!el || !el.__ref) return;
|
|
279
|
+
const { props } = el;
|
|
280
|
+
if (props && el.node) {
|
|
281
|
+
const cls = el.node.getAttribute?.("class");
|
|
282
|
+
if (cls && !seen.has(cls)) {
|
|
283
|
+
seen.add(cls);
|
|
284
|
+
const cssResult = buildCSSFromProps(props, colorMap, mediaMap);
|
|
285
|
+
const has = Object.keys(cssResult.base).length || Object.keys(cssResult.mediaRules).length || Object.keys(cssResult.pseudoRules).length;
|
|
286
|
+
if (has) rules.push(renderCSSRule("." + cls.split(" ")[0], cssResult));
|
|
287
|
+
const anim = props.animation || props.animationName;
|
|
288
|
+
if (typeof anim === "string") {
|
|
289
|
+
const name = anim.split(" ")[0];
|
|
290
|
+
if (animations[name]) usedAnimations.add(name);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
if (el.__ref.__children) {
|
|
295
|
+
for (const ck of el.__ref.__children) {
|
|
296
|
+
if (el[ck]?.__ref) walk(el[ck]);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
walk(element);
|
|
301
|
+
const keyframes = [];
|
|
302
|
+
for (const name of usedAnimations) {
|
|
303
|
+
const frames = animations[name];
|
|
304
|
+
const frameRules = Object.entries(frames).map(([step, p]) => {
|
|
305
|
+
const decls = Object.entries(p).map(([k, v]) => `${camelToKebab(k)}: ${v}`).join("; ");
|
|
306
|
+
return ` ${step} { ${decls}; }`;
|
|
307
|
+
}).join("\n");
|
|
308
|
+
keyframes.push(`@keyframes ${name} {
|
|
309
|
+
${frameRules}
|
|
310
|
+
}`);
|
|
311
|
+
}
|
|
312
|
+
return [...keyframes, ...rules].join("\n");
|
|
313
|
+
};
|
|
314
|
+
const generateResetCSS = (reset) => {
|
|
315
|
+
if (!reset) return "";
|
|
316
|
+
const rules = [];
|
|
317
|
+
for (const [selector, props] of Object.entries(reset)) {
|
|
318
|
+
const decls = Object.entries(props).map(([k, v]) => `${camelToKebab(k)}: ${v}`).join("; ");
|
|
319
|
+
if (decls) rules.push(`${selector} { ${decls}; }`);
|
|
320
|
+
}
|
|
321
|
+
return rules.join("\n");
|
|
322
|
+
};
|
|
323
|
+
const generateFontLinks = (ds) => {
|
|
324
|
+
if (!ds) return "";
|
|
325
|
+
const families = ds.font_family || ds.fontFamily || {};
|
|
326
|
+
const fontNames = /* @__PURE__ */ new Set();
|
|
327
|
+
for (const val of Object.values(families)) {
|
|
328
|
+
const match = val.match(/'([^']+)'/);
|
|
329
|
+
if (match) fontNames.add(match[1]);
|
|
330
|
+
}
|
|
331
|
+
if (!fontNames.size) return "";
|
|
332
|
+
const params = [...fontNames].map((name) => {
|
|
333
|
+
const slug = name.replace(/\s+/g, "+");
|
|
334
|
+
return `family=${slug}:wght@300;400;500;600;700`;
|
|
335
|
+
}).join("&");
|
|
336
|
+
return [
|
|
337
|
+
'<link rel="preconnect" href="https://fonts.googleapis.com">',
|
|
338
|
+
'<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>',
|
|
339
|
+
`<link href="https://fonts.googleapis.com/css2?${params}&display=swap" rel="stylesheet">`
|
|
340
|
+
].join("\n");
|
|
341
|
+
};
|
package/dist/esm/env.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { parseHTML } from "linkedom";
|
|
2
|
+
const createEnv = (html = "<!DOCTYPE html><html><head></head><body></body></html>") => {
|
|
3
|
+
const { window, document } = parseHTML(html);
|
|
4
|
+
if (!window.requestAnimationFrame) {
|
|
5
|
+
window.requestAnimationFrame = (fn) => setTimeout(fn, 0);
|
|
6
|
+
}
|
|
7
|
+
if (!window.cancelAnimationFrame) {
|
|
8
|
+
window.cancelAnimationFrame = (id) => clearTimeout(id);
|
|
9
|
+
}
|
|
10
|
+
if (!window.history) {
|
|
11
|
+
window.history = {
|
|
12
|
+
pushState: () => {
|
|
13
|
+
},
|
|
14
|
+
replaceState: () => {
|
|
15
|
+
},
|
|
16
|
+
state: null
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
if (!window.location) {
|
|
20
|
+
window.location = { pathname: "/", search: "", hash: "", origin: "http://localhost" };
|
|
21
|
+
}
|
|
22
|
+
if (!window.URL) {
|
|
23
|
+
window.URL = URL;
|
|
24
|
+
}
|
|
25
|
+
if (!window.scrollTo) {
|
|
26
|
+
window.scrollTo = () => {
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
globalThis.window = window;
|
|
30
|
+
globalThis.document = document;
|
|
31
|
+
globalThis.Node = window.Node || globalThis.Node;
|
|
32
|
+
globalThis.HTMLElement = window.HTMLElement || globalThis.HTMLElement;
|
|
33
|
+
globalThis.Window = window.constructor;
|
|
34
|
+
return { window, document };
|
|
35
|
+
};
|
|
36
|
+
export {
|
|
37
|
+
createEnv
|
|
38
|
+
};
|