@kubuild/renderer 0.0.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/dist/error-boundary.d.ts +20 -0
- package/dist/error-boundary.d.ts.map +1 -0
- package/dist/index.cjs +2084 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2030 -0
- package/dist/index.js.map +1 -0
- package/dist/preview-adapter.d.ts +120 -0
- package/dist/preview-adapter.d.ts.map +1 -0
- package/dist/prop-resolution.d.ts +16 -0
- package/dist/prop-resolution.d.ts.map +1 -0
- package/dist/render-context.d.ts +98 -0
- package/dist/render-context.d.ts.map +1 -0
- package/dist/renderer.d.ts +60 -0
- package/dist/renderer.d.ts.map +1 -0
- package/dist/styles.d.ts +23 -0
- package/dist/styles.d.ts.map +1 -0
- package/package.json +68 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2030 @@
|
|
|
1
|
+
// src/renderer.tsx
|
|
2
|
+
import { useRef, useLayoutEffect, useEffect, useMemo as useMemo2 } from "react";
|
|
3
|
+
import { isAssetReference, isActionBinding as isActionBinding2, isVariableBinding as isVariableBinding3 } from "@kubuild/schema";
|
|
4
|
+
import { createDefaultComponentRegistry } from "@kubuild/components";
|
|
5
|
+
|
|
6
|
+
// src/render-context.tsx
|
|
7
|
+
import { createContext, useContext, useMemo } from "react";
|
|
8
|
+
import { resolveBinding } from "@kubuild/core";
|
|
9
|
+
import { isVariableBinding, isActionBinding } from "@kubuild/schema";
|
|
10
|
+
import { jsx } from "react/jsx-runtime";
|
|
11
|
+
var DEFAULT_RENDER_CONTEXT = Object.freeze({});
|
|
12
|
+
var RenderContextReact = createContext(DEFAULT_RENDER_CONTEXT);
|
|
13
|
+
function createRenderContext(options) {
|
|
14
|
+
if (!options) {
|
|
15
|
+
return DEFAULT_RENDER_CONTEXT;
|
|
16
|
+
}
|
|
17
|
+
const frozenVariables = options.variables ? Object.freeze({ ...options.variables }) : void 0;
|
|
18
|
+
return Object.freeze({
|
|
19
|
+
variables: frozenVariables,
|
|
20
|
+
...options.assetProvider ? { assetProvider: options.assetProvider } : {},
|
|
21
|
+
...options.actionRegistry ? { actionRegistry: options.actionRegistry } : {},
|
|
22
|
+
...options.onDiagnostic ? { onDiagnostic: options.onDiagnostic } : {}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function createMinimalRenderContext(options) {
|
|
26
|
+
const assetsMap = new Map(Object.entries(options?.assets ?? {}));
|
|
27
|
+
const actionsMap = new Map(Object.entries(options?.actions ?? {}));
|
|
28
|
+
const assetProvider = {
|
|
29
|
+
resolve: (assetIdOrUri) => {
|
|
30
|
+
return assetsMap.get(assetIdOrUri) || assetIdOrUri;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
const actionRegistry = {
|
|
34
|
+
get: (type) => actionsMap.get(type),
|
|
35
|
+
register: (type, handler) => {
|
|
36
|
+
actionsMap.set(type, handler);
|
|
37
|
+
},
|
|
38
|
+
unregister: (type) => {
|
|
39
|
+
actionsMap.delete(type);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
return createRenderContext({
|
|
43
|
+
variables: options?.variables,
|
|
44
|
+
assetProvider,
|
|
45
|
+
actionRegistry,
|
|
46
|
+
onDiagnostic: options?.onDiagnostic
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
var RenderContextProvider = ({ value, children }) => {
|
|
50
|
+
const contextValue = useMemo(() => value || DEFAULT_RENDER_CONTEXT, [value]);
|
|
51
|
+
return /* @__PURE__ */ jsx(RenderContextReact.Provider, { value: contextValue, children });
|
|
52
|
+
};
|
|
53
|
+
function useRenderContext() {
|
|
54
|
+
return useContext(RenderContextReact);
|
|
55
|
+
}
|
|
56
|
+
function resolveAssetSync(assetProvider, assetIdOrUri) {
|
|
57
|
+
if (!assetProvider || !assetIdOrUri) {
|
|
58
|
+
return void 0;
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const result = assetProvider.resolve(assetIdOrUri);
|
|
62
|
+
return typeof result === "string" ? result : void 0;
|
|
63
|
+
} catch {
|
|
64
|
+
return void 0;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function resolveVariable(context, value) {
|
|
68
|
+
if (value === null || value === void 0) {
|
|
69
|
+
return value;
|
|
70
|
+
}
|
|
71
|
+
if (isVariableBinding(value)) {
|
|
72
|
+
return resolveBinding(value, context).value;
|
|
73
|
+
}
|
|
74
|
+
if (typeof value === "string" && value.includes("{{")) {
|
|
75
|
+
return value.replace(/\{\{\s*([\w.-]+)\s*\}\}/g, (match, key) => {
|
|
76
|
+
const outcome = resolveBinding({ key }, context);
|
|
77
|
+
if (outcome.status === "resolved") {
|
|
78
|
+
return String(outcome.value);
|
|
79
|
+
}
|
|
80
|
+
return match;
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
function resolveActionPayloadDetailed(context, payload) {
|
|
86
|
+
if (!payload || typeof payload !== "object") {
|
|
87
|
+
return { value: payload, invalidPaths: [] };
|
|
88
|
+
}
|
|
89
|
+
const invalidPaths = [];
|
|
90
|
+
const resolveValueRecursively = (val, path) => {
|
|
91
|
+
if (val === null || val === void 0) {
|
|
92
|
+
return val;
|
|
93
|
+
}
|
|
94
|
+
if (isVariableBinding(val)) {
|
|
95
|
+
const outcome = resolveBinding(val, context);
|
|
96
|
+
if (outcome.status === "empty") {
|
|
97
|
+
invalidPaths.push(path);
|
|
98
|
+
}
|
|
99
|
+
return outcome.value;
|
|
100
|
+
}
|
|
101
|
+
if (typeof val === "string") {
|
|
102
|
+
if (val.includes("{{")) {
|
|
103
|
+
return val.replace(/\{\{\s*([\w.-]+)\s*\}\}/g, (match, key) => {
|
|
104
|
+
const outcome = resolveBinding({ key }, context);
|
|
105
|
+
if (outcome.status !== "resolved") {
|
|
106
|
+
invalidPaths.push(path);
|
|
107
|
+
return match;
|
|
108
|
+
}
|
|
109
|
+
return String(outcome.value);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return val;
|
|
113
|
+
}
|
|
114
|
+
if (Array.isArray(val)) {
|
|
115
|
+
return val.map((item, index) => resolveValueRecursively(item, `${path}[${index}]`));
|
|
116
|
+
}
|
|
117
|
+
if (typeof val === "object") {
|
|
118
|
+
const copy = {};
|
|
119
|
+
for (const [k, v] of Object.entries(val)) {
|
|
120
|
+
copy[k] = resolveValueRecursively(v, path ? `${path}.${k}` : k);
|
|
121
|
+
}
|
|
122
|
+
return copy;
|
|
123
|
+
}
|
|
124
|
+
return val;
|
|
125
|
+
};
|
|
126
|
+
const resolved = {};
|
|
127
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
128
|
+
resolved[key] = resolveValueRecursively(value, key);
|
|
129
|
+
}
|
|
130
|
+
return { value: resolved, invalidPaths };
|
|
131
|
+
}
|
|
132
|
+
function resolveActionPayload(context, payload) {
|
|
133
|
+
return resolveActionPayloadDetailed(context, payload).value;
|
|
134
|
+
}
|
|
135
|
+
function isActionRegistered(actionRegistry, actionType) {
|
|
136
|
+
if (!actionRegistry || !actionType) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
return Boolean(actionRegistry.get(actionType));
|
|
140
|
+
}
|
|
141
|
+
function dispatchAction(options) {
|
|
142
|
+
const { action, nodeId, document, context, onDiagnostic } = options;
|
|
143
|
+
if (!isActionBinding(action)) {
|
|
144
|
+
const diagnostic = {
|
|
145
|
+
code: "INVALID_ACTION_PAYLOAD",
|
|
146
|
+
actionType: typeof action?.type === "string" ? action.type : "unknown",
|
|
147
|
+
nodeId,
|
|
148
|
+
message: `Invalid action binding on node ${nodeId || "unknown"}.`
|
|
149
|
+
};
|
|
150
|
+
onDiagnostic?.(diagnostic);
|
|
151
|
+
context?.onDiagnostic?.(diagnostic);
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
const handler = context?.actionRegistry?.get(action.type);
|
|
155
|
+
if (!handler) {
|
|
156
|
+
const diagnostic = {
|
|
157
|
+
code: "UNKNOWN_ACTION",
|
|
158
|
+
actionType: action.type,
|
|
159
|
+
nodeId,
|
|
160
|
+
message: `No action handler registered for action type "${action.type}".`
|
|
161
|
+
};
|
|
162
|
+
onDiagnostic?.(diagnostic);
|
|
163
|
+
context?.onDiagnostic?.(diagnostic);
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
const { value: resolvedPayload, invalidPaths } = resolveActionPayloadDetailed(context, action.payload);
|
|
167
|
+
if (invalidPaths.length > 0) {
|
|
168
|
+
const diagnostic = {
|
|
169
|
+
code: "INVALID_ACTION_BINDING",
|
|
170
|
+
actionType: action.type,
|
|
171
|
+
nodeId,
|
|
172
|
+
message: `Action "${action.type}" payload has unresolved binding path(s) [${invalidPaths.join(
|
|
173
|
+
", "
|
|
174
|
+
)}] on node ${nodeId || "unknown"}; handler was not invoked.`,
|
|
175
|
+
invalidPaths
|
|
176
|
+
};
|
|
177
|
+
onDiagnostic?.(diagnostic);
|
|
178
|
+
context?.onDiagnostic?.(diagnostic);
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
const executionContext = {
|
|
182
|
+
nodeId,
|
|
183
|
+
document,
|
|
184
|
+
variables: context?.variables
|
|
185
|
+
};
|
|
186
|
+
try {
|
|
187
|
+
const result = handler(resolvedPayload, executionContext);
|
|
188
|
+
if (result && typeof result.catch === "function") {
|
|
189
|
+
result.catch((error) => {
|
|
190
|
+
const diagnostic = {
|
|
191
|
+
code: "ACTION_EXECUTION_ERROR",
|
|
192
|
+
actionType: action.type,
|
|
193
|
+
nodeId,
|
|
194
|
+
message: `Action "${action.type}" handler threw an asynchronous error: ${error instanceof Error ? error.message : String(error)}`,
|
|
195
|
+
error
|
|
196
|
+
};
|
|
197
|
+
onDiagnostic?.(diagnostic);
|
|
198
|
+
context?.onDiagnostic?.(diagnostic);
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
return true;
|
|
202
|
+
} catch (error) {
|
|
203
|
+
const diagnostic = {
|
|
204
|
+
code: "ACTION_EXECUTION_ERROR",
|
|
205
|
+
actionType: action.type,
|
|
206
|
+
nodeId,
|
|
207
|
+
message: `Action "${action.type}" handler threw a synchronous error: ${error instanceof Error ? error.message : String(error)}`,
|
|
208
|
+
error
|
|
209
|
+
};
|
|
210
|
+
onDiagnostic?.(diagnostic);
|
|
211
|
+
context?.onDiagnostic?.(diagnostic);
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// src/renderer.tsx
|
|
217
|
+
import { resolveBinding as resolveBinding3, sanitizeUrl, sanitizeHtml } from "@kubuild/core";
|
|
218
|
+
import { icons as lucideIcons } from "lucide-react";
|
|
219
|
+
|
|
220
|
+
// src/styles.ts
|
|
221
|
+
function resolveNodeStyles(styles, viewport = "desktop") {
|
|
222
|
+
if (!styles) return {};
|
|
223
|
+
const base = styles.base || {};
|
|
224
|
+
const override = styles[viewport] || {};
|
|
225
|
+
return { ...base, ...override };
|
|
226
|
+
}
|
|
227
|
+
function escapeCssValue(value) {
|
|
228
|
+
return String(value).replace(/[{};]+/g, "");
|
|
229
|
+
}
|
|
230
|
+
function escapeCssIdent(value) {
|
|
231
|
+
return value.replace(/["\\\]]/g, "\\$&");
|
|
232
|
+
}
|
|
233
|
+
function styleDefinitionToCssDeclarations(styleDefinition) {
|
|
234
|
+
if (!styleDefinition || typeof styleDefinition !== "object") return "";
|
|
235
|
+
const declarations = [];
|
|
236
|
+
for (const [key, value] of Object.entries(styleDefinition)) {
|
|
237
|
+
if (value === null || value === void 0 || value === "") continue;
|
|
238
|
+
const property = key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
|
|
239
|
+
declarations.push(`${property}: ${escapeCssValue(value)};`);
|
|
240
|
+
}
|
|
241
|
+
return declarations.join(" ");
|
|
242
|
+
}
|
|
243
|
+
function collectStateStylesCss(document) {
|
|
244
|
+
if (!document?.document) return "";
|
|
245
|
+
const rules = [];
|
|
246
|
+
const walk = (node) => {
|
|
247
|
+
const states = node.styles?.states;
|
|
248
|
+
if (states && typeof states === "object") {
|
|
249
|
+
for (const [state, styleDefinition] of Object.entries(states)) {
|
|
250
|
+
const declarations = styleDefinitionToCssDeclarations(
|
|
251
|
+
styleDefinition
|
|
252
|
+
);
|
|
253
|
+
if (!declarations) continue;
|
|
254
|
+
const safeState = /^::?[a-zA-Z-]+$/.test(state) ? state : null;
|
|
255
|
+
if (!safeState) continue;
|
|
256
|
+
rules.push(`[data-kubuild-node="${escapeCssIdent(node.id)}"]${safeState} { ${declarations} }`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
node.children?.forEach(walk);
|
|
260
|
+
};
|
|
261
|
+
walk(document.document);
|
|
262
|
+
return rules.join("\n");
|
|
263
|
+
}
|
|
264
|
+
var DEFAULT_CSS_RESET = `
|
|
265
|
+
*, *::before, *::after {
|
|
266
|
+
box-sizing: border-box;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
* {
|
|
270
|
+
margin: 0;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
body {
|
|
274
|
+
line-height: 1.5;
|
|
275
|
+
-webkit-font-smoothing: antialiased;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
img, picture, video, canvas, svg {
|
|
279
|
+
display: block;
|
|
280
|
+
max-width: 100%;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
input, button, textarea, select {
|
|
284
|
+
font: inherit;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
p, h1, h2, h3, h4, h5, h6 {
|
|
288
|
+
overflow-wrap: break-word;
|
|
289
|
+
}
|
|
290
|
+
`.trim();
|
|
291
|
+
|
|
292
|
+
// src/error-boundary.tsx
|
|
293
|
+
import { Component } from "react";
|
|
294
|
+
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
295
|
+
var ComponentErrorBoundary = class extends Component {
|
|
296
|
+
constructor(props) {
|
|
297
|
+
super(props);
|
|
298
|
+
this.state = { hasError: false };
|
|
299
|
+
}
|
|
300
|
+
static getDerivedStateFromError(error) {
|
|
301
|
+
return { hasError: true, error };
|
|
302
|
+
}
|
|
303
|
+
componentDidCatch(error, errorInfo) {
|
|
304
|
+
if (this.props.onError) {
|
|
305
|
+
this.props.onError(error, errorInfo);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
render() {
|
|
309
|
+
if (this.state.hasError) {
|
|
310
|
+
const { nodeId, componentType, mode = "runtime" } = this.props;
|
|
311
|
+
const errorMessage = this.state.error?.message || "Unknown render error";
|
|
312
|
+
if (mode === "editor") {
|
|
313
|
+
return /* @__PURE__ */ jsxs(
|
|
314
|
+
"div",
|
|
315
|
+
{
|
|
316
|
+
"data-kubuild-node": nodeId,
|
|
317
|
+
"data-kubuild-error": componentType,
|
|
318
|
+
style: {
|
|
319
|
+
padding: "12px 16px",
|
|
320
|
+
margin: "4px 0",
|
|
321
|
+
backgroundColor: "#fef2f2",
|
|
322
|
+
border: "1px solid #ef4444",
|
|
323
|
+
borderRadius: "6px",
|
|
324
|
+
color: "#b91c1c",
|
|
325
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
326
|
+
fontSize: "13px",
|
|
327
|
+
lineHeight: "1.4"
|
|
328
|
+
},
|
|
329
|
+
children: [
|
|
330
|
+
/* @__PURE__ */ jsxs("div", { style: { fontWeight: 600, marginBottom: "4px" }, children: [
|
|
331
|
+
"\u26A0\uFE0F Component Render Error: <",
|
|
332
|
+
componentType,
|
|
333
|
+
">"
|
|
334
|
+
] }),
|
|
335
|
+
/* @__PURE__ */ jsxs("div", { style: { fontSize: "11px", color: "#7f1d1d", wordBreak: "break-all" }, children: [
|
|
336
|
+
"Node ID: ",
|
|
337
|
+
/* @__PURE__ */ jsx2("code", { children: nodeId }),
|
|
338
|
+
" \u2014 ",
|
|
339
|
+
errorMessage
|
|
340
|
+
] })
|
|
341
|
+
]
|
|
342
|
+
}
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
return /* @__PURE__ */ jsx2(
|
|
346
|
+
"div",
|
|
347
|
+
{
|
|
348
|
+
"data-kubuild-node": nodeId,
|
|
349
|
+
"data-kubuild-error": componentType,
|
|
350
|
+
style: { display: "none" },
|
|
351
|
+
"aria-hidden": "true"
|
|
352
|
+
}
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
return this.props.children;
|
|
356
|
+
}
|
|
357
|
+
};
|
|
358
|
+
|
|
359
|
+
// src/prop-resolution.ts
|
|
360
|
+
import { isVariableBinding as isVariableBinding2 } from "@kubuild/schema";
|
|
361
|
+
import { primitiveTypeForField } from "@kubuild/components";
|
|
362
|
+
import { resolveBinding as resolveBinding2 } from "@kubuild/core";
|
|
363
|
+
function emptyValueFor(primitiveType) {
|
|
364
|
+
switch (primitiveType) {
|
|
365
|
+
case "string":
|
|
366
|
+
return "";
|
|
367
|
+
case "number":
|
|
368
|
+
return 0;
|
|
369
|
+
case "boolean":
|
|
370
|
+
return false;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
function resolveBindableField(node, field, definition, context, diagnostics) {
|
|
374
|
+
const rawValue = node.props?.[field.name];
|
|
375
|
+
const expectedType = primitiveTypeForField(field);
|
|
376
|
+
if (expectedType === void 0 || rawValue === void 0) {
|
|
377
|
+
return rawValue;
|
|
378
|
+
}
|
|
379
|
+
const fallbackValue = definition.defaultProps?.[field.name] ?? field.defaultValue ?? emptyValueFor(expectedType);
|
|
380
|
+
if (isVariableBinding2(rawValue)) {
|
|
381
|
+
const outcome = resolveBinding2(rawValue, context);
|
|
382
|
+
if (typeof outcome.value === expectedType) {
|
|
383
|
+
return outcome.value;
|
|
384
|
+
}
|
|
385
|
+
diagnostics.push({
|
|
386
|
+
code: "INCOMPATIBLE_BINDING_TYPE",
|
|
387
|
+
nodeId: node.id,
|
|
388
|
+
propName: field.name,
|
|
389
|
+
expectedType,
|
|
390
|
+
actualType: typeof outcome.value,
|
|
391
|
+
message: `Prop "${field.name}" on node "${node.id}" expected a ${expectedType} but resolved binding "${rawValue.key}" produced a ${typeof outcome.value}.`
|
|
392
|
+
});
|
|
393
|
+
return fallbackValue;
|
|
394
|
+
}
|
|
395
|
+
if (expectedType === "string" && typeof rawValue === "string" && rawValue.includes("{{")) {
|
|
396
|
+
return resolveVariable(context, rawValue);
|
|
397
|
+
}
|
|
398
|
+
return rawValue;
|
|
399
|
+
}
|
|
400
|
+
function resolvePropsForNode(node, definition, context) {
|
|
401
|
+
const rawProps = node.props || {};
|
|
402
|
+
if (!definition || !definition.propFields || definition.propFields.length === 0) {
|
|
403
|
+
return { props: rawProps, diagnostics: [] };
|
|
404
|
+
}
|
|
405
|
+
const diagnostics = [];
|
|
406
|
+
const resolved = { ...rawProps };
|
|
407
|
+
for (const field of definition.propFields) {
|
|
408
|
+
if (primitiveTypeForField(field) === void 0) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
resolved[field.name] = resolveBindableField(node, field, definition, context, diagnostics);
|
|
412
|
+
}
|
|
413
|
+
return { props: resolved, diagnostics };
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// src/renderer.tsx
|
|
417
|
+
import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
418
|
+
function toPascalCase(str) {
|
|
419
|
+
if (!str) return "";
|
|
420
|
+
return str.replace(/[-_](\w)/g, (_, c) => c.toUpperCase()).replace(/^\w/, (c) => c.toUpperCase());
|
|
421
|
+
}
|
|
422
|
+
function getYouTubeId(url) {
|
|
423
|
+
if (!url || typeof url !== "string") return null;
|
|
424
|
+
const match = url.match(
|
|
425
|
+
/(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/i
|
|
426
|
+
);
|
|
427
|
+
return match ? match[1] : null;
|
|
428
|
+
}
|
|
429
|
+
function getVimeoId(url) {
|
|
430
|
+
if (!url || typeof url !== "string") return null;
|
|
431
|
+
const match = url.match(
|
|
432
|
+
/(?:vimeo\.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|))(\d+)/i
|
|
433
|
+
);
|
|
434
|
+
return match ? match[3] : null;
|
|
435
|
+
}
|
|
436
|
+
function aspectRatioToCss(ratio) {
|
|
437
|
+
if (ratio === "16:9") return "16 / 9";
|
|
438
|
+
if (ratio === "4:3") return "4 / 3";
|
|
439
|
+
if (ratio === "1:1") return "1 / 1";
|
|
440
|
+
if (ratio === "9:16") return "9 / 16";
|
|
441
|
+
if (typeof ratio === "string" && ratio !== "auto") return ratio.replace(":", " / ");
|
|
442
|
+
return void 0;
|
|
443
|
+
}
|
|
444
|
+
var EditableText = ({
|
|
445
|
+
as = "p",
|
|
446
|
+
id,
|
|
447
|
+
className,
|
|
448
|
+
style,
|
|
449
|
+
value,
|
|
450
|
+
isEditable,
|
|
451
|
+
nodeId,
|
|
452
|
+
onClick,
|
|
453
|
+
onChange,
|
|
454
|
+
...rest
|
|
455
|
+
}) => {
|
|
456
|
+
const isEditingRef = useRef(false);
|
|
457
|
+
const Tag = as;
|
|
458
|
+
if (!isEditable) {
|
|
459
|
+
return /* @__PURE__ */ jsx3(
|
|
460
|
+
Tag,
|
|
461
|
+
{
|
|
462
|
+
id,
|
|
463
|
+
className,
|
|
464
|
+
style,
|
|
465
|
+
onClick,
|
|
466
|
+
"data-kubuild-node": nodeId,
|
|
467
|
+
...rest,
|
|
468
|
+
children: value
|
|
469
|
+
}
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
return /* @__PURE__ */ jsx3(
|
|
473
|
+
Tag,
|
|
474
|
+
{
|
|
475
|
+
id,
|
|
476
|
+
className,
|
|
477
|
+
style: {
|
|
478
|
+
...style,
|
|
479
|
+
outline: "none",
|
|
480
|
+
cursor: "text"
|
|
481
|
+
},
|
|
482
|
+
contentEditable: true,
|
|
483
|
+
suppressContentEditableWarning: true,
|
|
484
|
+
"data-kubuild-node": nodeId,
|
|
485
|
+
onClick: (e) => {
|
|
486
|
+
onClick?.(e);
|
|
487
|
+
},
|
|
488
|
+
onFocus: () => {
|
|
489
|
+
isEditingRef.current = true;
|
|
490
|
+
},
|
|
491
|
+
onInput: (e) => {
|
|
492
|
+
const text = e.currentTarget.textContent ?? "";
|
|
493
|
+
onChange?.(text, false);
|
|
494
|
+
},
|
|
495
|
+
onBlur: (e) => {
|
|
496
|
+
isEditingRef.current = false;
|
|
497
|
+
const text = e.currentTarget.textContent ?? "";
|
|
498
|
+
onChange?.(text, true);
|
|
499
|
+
},
|
|
500
|
+
onKeyDown: (e) => {
|
|
501
|
+
if (e.key === "Escape") {
|
|
502
|
+
e.currentTarget.blur();
|
|
503
|
+
}
|
|
504
|
+
},
|
|
505
|
+
...rest,
|
|
506
|
+
children: value
|
|
507
|
+
}
|
|
508
|
+
);
|
|
509
|
+
};
|
|
510
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
511
|
+
function transformEmbedHtml(rawHtml) {
|
|
512
|
+
if (!rawHtml) return "";
|
|
513
|
+
return rawHtml.replace(/<style\b([^>]*)>([\s\S]*?)<\/style>/gi, (_match, attrs, cssContent) => {
|
|
514
|
+
let transformedCss = cssContent;
|
|
515
|
+
transformedCss = transformedCss.replace(/(^|[\s,{}])body(?=[\s,{])/g, "$1:host, body");
|
|
516
|
+
transformedCss = transformedCss.replace(/(^|[\s,{}])html(?=[\s,{])/g, "$1:host, html");
|
|
517
|
+
return `<style${attrs}>
|
|
518
|
+
:host { display: block; }
|
|
519
|
+
${transformedCss}</style>`;
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
var HtmlEmbedView = ({
|
|
523
|
+
id,
|
|
524
|
+
style,
|
|
525
|
+
onClick,
|
|
526
|
+
dataKubuildNode,
|
|
527
|
+
html,
|
|
528
|
+
role
|
|
529
|
+
}) => {
|
|
530
|
+
const hostRef = useRef(null);
|
|
531
|
+
const shadowRootRef = useRef(null);
|
|
532
|
+
const scopedHtml = useMemo2(() => transformEmbedHtml(html), [html]);
|
|
533
|
+
useIsomorphicLayoutEffect(() => {
|
|
534
|
+
const host = hostRef.current;
|
|
535
|
+
if (!host) return;
|
|
536
|
+
if (typeof host.attachShadow === "function") {
|
|
537
|
+
if (!shadowRootRef.current) {
|
|
538
|
+
if (host.shadowRoot) {
|
|
539
|
+
shadowRootRef.current = host.shadowRoot;
|
|
540
|
+
} else {
|
|
541
|
+
try {
|
|
542
|
+
shadowRootRef.current = host.attachShadow({ mode: "open" });
|
|
543
|
+
} catch {
|
|
544
|
+
shadowRootRef.current = host.shadowRoot;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
if (shadowRootRef.current) {
|
|
549
|
+
shadowRootRef.current.innerHTML = scopedHtml;
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
host.innerHTML = scopedHtml;
|
|
554
|
+
}, [scopedHtml]);
|
|
555
|
+
return /* @__PURE__ */ jsx3(
|
|
556
|
+
"div",
|
|
557
|
+
{
|
|
558
|
+
ref: hostRef,
|
|
559
|
+
id,
|
|
560
|
+
style,
|
|
561
|
+
onClick,
|
|
562
|
+
"data-kubuild-node": dataKubuildNode,
|
|
563
|
+
role,
|
|
564
|
+
children: /* @__PURE__ */ jsx3(
|
|
565
|
+
"template",
|
|
566
|
+
{
|
|
567
|
+
shadowrootmode: "open",
|
|
568
|
+
dangerouslySetInnerHTML: { __html: scopedHtml }
|
|
569
|
+
}
|
|
570
|
+
)
|
|
571
|
+
}
|
|
572
|
+
);
|
|
573
|
+
};
|
|
574
|
+
function NodeRenderer({
|
|
575
|
+
node,
|
|
576
|
+
document,
|
|
577
|
+
registry,
|
|
578
|
+
context: propContext,
|
|
579
|
+
viewport = "desktop",
|
|
580
|
+
mode = "runtime",
|
|
581
|
+
onNodeClick,
|
|
582
|
+
onDiagnostic,
|
|
583
|
+
onActionDispatch,
|
|
584
|
+
onNodePropChange,
|
|
585
|
+
instanceSuffix = ""
|
|
586
|
+
}) {
|
|
587
|
+
const context = propContext || DEFAULT_RENDER_CONTEXT;
|
|
588
|
+
const styles = resolveNodeStyles(node.styles, viewport);
|
|
589
|
+
const props = node.props || {};
|
|
590
|
+
const definition = registry.get(node.type);
|
|
591
|
+
const domId = instanceSuffix ? `${node.id}${instanceSuffix}` : node.id;
|
|
592
|
+
const { props: resolvedProps, diagnostics } = resolvePropsForNode(node, definition, context);
|
|
593
|
+
diagnostics.forEach((diagnostic) => {
|
|
594
|
+
onDiagnostic?.(diagnostic);
|
|
595
|
+
context?.onDiagnostic?.(diagnostic);
|
|
596
|
+
});
|
|
597
|
+
const handleClick = (e) => {
|
|
598
|
+
e.stopPropagation();
|
|
599
|
+
if (onNodeClick) {
|
|
600
|
+
onNodeClick(node.id, e);
|
|
601
|
+
}
|
|
602
|
+
if (props.action && !props.disabled) {
|
|
603
|
+
dispatchAction({
|
|
604
|
+
action: props.action,
|
|
605
|
+
nodeId: node.id,
|
|
606
|
+
document,
|
|
607
|
+
context,
|
|
608
|
+
onDiagnostic
|
|
609
|
+
});
|
|
610
|
+
if (onActionDispatch && isActionBinding2(props.action)) {
|
|
611
|
+
onActionDispatch(props.action.type, resolveActionPayload(context, props.action.payload), node.id);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
const childrenElements = node.children?.map((child) => /* @__PURE__ */ jsx3(
|
|
616
|
+
NodeRenderer,
|
|
617
|
+
{
|
|
618
|
+
node: child,
|
|
619
|
+
document,
|
|
620
|
+
registry,
|
|
621
|
+
context,
|
|
622
|
+
viewport,
|
|
623
|
+
mode,
|
|
624
|
+
onNodeClick,
|
|
625
|
+
onDiagnostic,
|
|
626
|
+
onActionDispatch,
|
|
627
|
+
onNodePropChange,
|
|
628
|
+
instanceSuffix
|
|
629
|
+
},
|
|
630
|
+
`${child.id}${instanceSuffix}`
|
|
631
|
+
));
|
|
632
|
+
const renderNodeContent = () => {
|
|
633
|
+
if (definition?.renderer && typeof definition.renderer === "function") {
|
|
634
|
+
const CustomRenderer = definition.renderer;
|
|
635
|
+
try {
|
|
636
|
+
if (typeof CustomRenderer === "function" && !CustomRenderer.prototype?.isReactComponent) {
|
|
637
|
+
return CustomRenderer({
|
|
638
|
+
node,
|
|
639
|
+
document,
|
|
640
|
+
props: resolvedProps,
|
|
641
|
+
styles,
|
|
642
|
+
context,
|
|
643
|
+
children: childrenElements,
|
|
644
|
+
onClick: handleClick
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
} catch (err) {
|
|
648
|
+
throw err;
|
|
649
|
+
}
|
|
650
|
+
return /* @__PURE__ */ jsx3(
|
|
651
|
+
CustomRenderer,
|
|
652
|
+
{
|
|
653
|
+
node,
|
|
654
|
+
document,
|
|
655
|
+
props: resolvedProps,
|
|
656
|
+
styles,
|
|
657
|
+
context,
|
|
658
|
+
onClick: handleClick,
|
|
659
|
+
children: childrenElements
|
|
660
|
+
}
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
switch (node.type) {
|
|
664
|
+
case "page":
|
|
665
|
+
return /* @__PURE__ */ jsx3("div", { id: domId, style: styles, onClick: handleClick, "data-kubuild-node": node.id, children: childrenElements });
|
|
666
|
+
case "section":
|
|
667
|
+
return /* @__PURE__ */ jsx3(
|
|
668
|
+
"section",
|
|
669
|
+
{
|
|
670
|
+
id: domId,
|
|
671
|
+
style: styles,
|
|
672
|
+
onClick: handleClick,
|
|
673
|
+
"data-kubuild-node": node.id,
|
|
674
|
+
"aria-label": typeof resolvedProps.ariaLabel === "string" ? resolvedProps.ariaLabel : void 0,
|
|
675
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
676
|
+
children: childrenElements
|
|
677
|
+
}
|
|
678
|
+
);
|
|
679
|
+
case "container":
|
|
680
|
+
return /* @__PURE__ */ jsx3(
|
|
681
|
+
"div",
|
|
682
|
+
{
|
|
683
|
+
id: domId,
|
|
684
|
+
style: styles,
|
|
685
|
+
onClick: handleClick,
|
|
686
|
+
"data-kubuild-node": node.id,
|
|
687
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
688
|
+
children: childrenElements
|
|
689
|
+
}
|
|
690
|
+
);
|
|
691
|
+
case "columns":
|
|
692
|
+
return /* @__PURE__ */ jsx3(
|
|
693
|
+
"div",
|
|
694
|
+
{
|
|
695
|
+
id: domId,
|
|
696
|
+
style: styles,
|
|
697
|
+
onClick: handleClick,
|
|
698
|
+
"data-kubuild-node": node.id,
|
|
699
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
700
|
+
children: childrenElements
|
|
701
|
+
}
|
|
702
|
+
);
|
|
703
|
+
case "heading": {
|
|
704
|
+
const rawLevel = typeof resolvedProps.level === "number" ? resolvedProps.level : typeof props.level === "number" ? props.level : 2;
|
|
705
|
+
const clampedLevel = Math.min(Math.max(rawLevel, 1), 6);
|
|
706
|
+
const text = String(resolvedProps.text ?? "");
|
|
707
|
+
const Tag = `h${clampedLevel}`;
|
|
708
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.text);
|
|
709
|
+
return /* @__PURE__ */ jsx3(
|
|
710
|
+
EditableText,
|
|
711
|
+
{
|
|
712
|
+
as: Tag,
|
|
713
|
+
id: domId,
|
|
714
|
+
style: styles,
|
|
715
|
+
value: text,
|
|
716
|
+
isEditable,
|
|
717
|
+
nodeId: node.id,
|
|
718
|
+
onClick: handleClick,
|
|
719
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "text", val, isBlur),
|
|
720
|
+
"aria-label": typeof resolvedProps.ariaLabel === "string" ? resolvedProps.ariaLabel : void 0
|
|
721
|
+
}
|
|
722
|
+
);
|
|
723
|
+
}
|
|
724
|
+
case "text": {
|
|
725
|
+
const content2 = String(resolvedProps.content ?? "");
|
|
726
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.content);
|
|
727
|
+
return /* @__PURE__ */ jsx3(
|
|
728
|
+
EditableText,
|
|
729
|
+
{
|
|
730
|
+
as: "p",
|
|
731
|
+
id: domId,
|
|
732
|
+
style: styles,
|
|
733
|
+
value: content2,
|
|
734
|
+
isEditable,
|
|
735
|
+
nodeId: node.id,
|
|
736
|
+
onClick: handleClick,
|
|
737
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "content", val, isBlur),
|
|
738
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0
|
|
739
|
+
}
|
|
740
|
+
);
|
|
741
|
+
}
|
|
742
|
+
case "paragraph": {
|
|
743
|
+
const text = String(resolvedProps.text ?? resolvedProps.content ?? props.text ?? props.content ?? "");
|
|
744
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.text) && !isVariableBinding3(props.content);
|
|
745
|
+
const propName = props.content !== void 0 ? "content" : "text";
|
|
746
|
+
return /* @__PURE__ */ jsx3(
|
|
747
|
+
EditableText,
|
|
748
|
+
{
|
|
749
|
+
as: "p",
|
|
750
|
+
id: domId,
|
|
751
|
+
style: styles,
|
|
752
|
+
value: text,
|
|
753
|
+
isEditable,
|
|
754
|
+
nodeId: node.id,
|
|
755
|
+
onClick: handleClick,
|
|
756
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, propName, val, isBlur),
|
|
757
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0
|
|
758
|
+
}
|
|
759
|
+
);
|
|
760
|
+
}
|
|
761
|
+
case "link": {
|
|
762
|
+
const text = String(resolvedProps.text ?? props.text ?? "");
|
|
763
|
+
const rawHref = typeof resolvedProps.href === "string" ? resolvedProps.href : typeof props.href === "string" ? props.href : void 0;
|
|
764
|
+
const href = rawHref ? sanitizeUrl(rawHref, "#") : "#";
|
|
765
|
+
const rawTarget = typeof resolvedProps.target === "string" ? resolvedProps.target : void 0;
|
|
766
|
+
const rawRel = typeof resolvedProps.rel === "string" ? resolvedProps.rel : void 0;
|
|
767
|
+
const rel = rawTarget === "_blank" && !rawRel ? "noopener noreferrer" : rawRel;
|
|
768
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.text);
|
|
769
|
+
if (isEditable) {
|
|
770
|
+
return /* @__PURE__ */ jsx3(
|
|
771
|
+
EditableText,
|
|
772
|
+
{
|
|
773
|
+
as: "a",
|
|
774
|
+
id: domId,
|
|
775
|
+
href: void 0,
|
|
776
|
+
target: rawTarget,
|
|
777
|
+
rel,
|
|
778
|
+
style: styles,
|
|
779
|
+
value: text,
|
|
780
|
+
isEditable,
|
|
781
|
+
nodeId: node.id,
|
|
782
|
+
onClick: handleClick,
|
|
783
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "text", val, isBlur),
|
|
784
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0
|
|
785
|
+
}
|
|
786
|
+
);
|
|
787
|
+
}
|
|
788
|
+
return /* @__PURE__ */ jsx3(
|
|
789
|
+
"a",
|
|
790
|
+
{
|
|
791
|
+
id: domId,
|
|
792
|
+
href,
|
|
793
|
+
target: rawTarget,
|
|
794
|
+
rel,
|
|
795
|
+
style: styles,
|
|
796
|
+
onClick: handleClick,
|
|
797
|
+
"data-kubuild-node": node.id,
|
|
798
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
799
|
+
children: text
|
|
800
|
+
}
|
|
801
|
+
);
|
|
802
|
+
}
|
|
803
|
+
case "blockquote": {
|
|
804
|
+
const text = resolvedProps.text !== void 0 ? String(resolvedProps.text) : props.text !== void 0 ? String(props.text) : "";
|
|
805
|
+
const rawCite = typeof resolvedProps.cite === "string" ? resolvedProps.cite : typeof props.cite === "string" ? props.cite : void 0;
|
|
806
|
+
const safeCite = rawCite ? sanitizeUrl(rawCite) : void 0;
|
|
807
|
+
const hasChildren = Boolean(childrenElements && childrenElements.length > 0);
|
|
808
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.text);
|
|
809
|
+
if (hasChildren) {
|
|
810
|
+
return /* @__PURE__ */ jsxs2(
|
|
811
|
+
"blockquote",
|
|
812
|
+
{
|
|
813
|
+
id: domId,
|
|
814
|
+
cite: safeCite,
|
|
815
|
+
style: styles,
|
|
816
|
+
onClick: handleClick,
|
|
817
|
+
"data-kubuild-node": node.id,
|
|
818
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
819
|
+
children: [
|
|
820
|
+
text ? isEditable ? /* @__PURE__ */ jsx3(
|
|
821
|
+
EditableText,
|
|
822
|
+
{
|
|
823
|
+
as: "p",
|
|
824
|
+
value: text,
|
|
825
|
+
isEditable,
|
|
826
|
+
nodeId: node.id,
|
|
827
|
+
onClick: handleClick,
|
|
828
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "text", val, isBlur)
|
|
829
|
+
}
|
|
830
|
+
) : /* @__PURE__ */ jsx3("p", { children: text }) : null,
|
|
831
|
+
childrenElements
|
|
832
|
+
]
|
|
833
|
+
}
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
return /* @__PURE__ */ jsx3(
|
|
837
|
+
EditableText,
|
|
838
|
+
{
|
|
839
|
+
as: "blockquote",
|
|
840
|
+
id: domId,
|
|
841
|
+
cite: safeCite,
|
|
842
|
+
style: styles,
|
|
843
|
+
value: text,
|
|
844
|
+
isEditable,
|
|
845
|
+
nodeId: node.id,
|
|
846
|
+
onClick: handleClick,
|
|
847
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "text", val, isBlur),
|
|
848
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0
|
|
849
|
+
}
|
|
850
|
+
);
|
|
851
|
+
}
|
|
852
|
+
case "badge": {
|
|
853
|
+
const text = String(resolvedProps.text ?? props.text ?? "Badge");
|
|
854
|
+
const variant = typeof resolvedProps.variant === "string" ? resolvedProps.variant : "default";
|
|
855
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.text);
|
|
856
|
+
return /* @__PURE__ */ jsx3(
|
|
857
|
+
EditableText,
|
|
858
|
+
{
|
|
859
|
+
as: "span",
|
|
860
|
+
id: domId,
|
|
861
|
+
style: styles,
|
|
862
|
+
value: text,
|
|
863
|
+
isEditable,
|
|
864
|
+
nodeId: node.id,
|
|
865
|
+
"data-variant": variant,
|
|
866
|
+
onClick: handleClick,
|
|
867
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "text", val, isBlur),
|
|
868
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0
|
|
869
|
+
}
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
case "code-block": {
|
|
873
|
+
const code = String(resolvedProps.code ?? props.code ?? "");
|
|
874
|
+
const language = typeof resolvedProps.language === "string" ? resolvedProps.language : typeof props.language === "string" ? props.language : void 0;
|
|
875
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.code);
|
|
876
|
+
return /* @__PURE__ */ jsx3(
|
|
877
|
+
"pre",
|
|
878
|
+
{
|
|
879
|
+
id: domId,
|
|
880
|
+
style: styles,
|
|
881
|
+
onClick: handleClick,
|
|
882
|
+
"data-kubuild-node": node.id,
|
|
883
|
+
"data-language": language,
|
|
884
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
885
|
+
children: /* @__PURE__ */ jsx3(
|
|
886
|
+
EditableText,
|
|
887
|
+
{
|
|
888
|
+
as: "code",
|
|
889
|
+
className: language ? `language-${language}` : void 0,
|
|
890
|
+
style: { fontFamily: "inherit", color: "inherit", display: "block", whiteSpace: "pre" },
|
|
891
|
+
value: code,
|
|
892
|
+
isEditable,
|
|
893
|
+
nodeId: node.id,
|
|
894
|
+
onClick: handleClick,
|
|
895
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "code", val, isBlur)
|
|
896
|
+
}
|
|
897
|
+
)
|
|
898
|
+
}
|
|
899
|
+
);
|
|
900
|
+
}
|
|
901
|
+
case "list": {
|
|
902
|
+
const rawTag = resolvedProps.tag;
|
|
903
|
+
const Tag = rawTag === "ol" ? "ol" : "ul";
|
|
904
|
+
const rawListStyle = resolvedProps.listStyleType;
|
|
905
|
+
const listStyleType = rawListStyle === "custom-icon" ? "none" : rawListStyle;
|
|
906
|
+
const listStyles = {
|
|
907
|
+
...styles,
|
|
908
|
+
...listStyleType ? { listStyleType } : {}
|
|
909
|
+
};
|
|
910
|
+
return /* @__PURE__ */ jsx3(
|
|
911
|
+
Tag,
|
|
912
|
+
{
|
|
913
|
+
id: domId,
|
|
914
|
+
style: listStyles,
|
|
915
|
+
onClick: handleClick,
|
|
916
|
+
"data-kubuild-node": node.id,
|
|
917
|
+
"data-list-style": rawListStyle,
|
|
918
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
919
|
+
children: childrenElements
|
|
920
|
+
}
|
|
921
|
+
);
|
|
922
|
+
}
|
|
923
|
+
case "list-item": {
|
|
924
|
+
const text = resolvedProps.text !== void 0 ? String(resolvedProps.text) : "";
|
|
925
|
+
const hasChildren = Boolean(childrenElements && childrenElements.length > 0);
|
|
926
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.text);
|
|
927
|
+
if (hasChildren) {
|
|
928
|
+
return /* @__PURE__ */ jsxs2(
|
|
929
|
+
"li",
|
|
930
|
+
{
|
|
931
|
+
id: domId,
|
|
932
|
+
style: styles,
|
|
933
|
+
onClick: handleClick,
|
|
934
|
+
"data-kubuild-node": node.id,
|
|
935
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
936
|
+
children: [
|
|
937
|
+
text ? isEditable ? /* @__PURE__ */ jsx3(
|
|
938
|
+
EditableText,
|
|
939
|
+
{
|
|
940
|
+
as: "span",
|
|
941
|
+
value: text,
|
|
942
|
+
isEditable,
|
|
943
|
+
nodeId: node.id,
|
|
944
|
+
onClick: handleClick,
|
|
945
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "text", val, isBlur)
|
|
946
|
+
}
|
|
947
|
+
) : /* @__PURE__ */ jsx3("span", { children: text }) : null,
|
|
948
|
+
childrenElements
|
|
949
|
+
]
|
|
950
|
+
}
|
|
951
|
+
);
|
|
952
|
+
}
|
|
953
|
+
return /* @__PURE__ */ jsx3(
|
|
954
|
+
EditableText,
|
|
955
|
+
{
|
|
956
|
+
as: "li",
|
|
957
|
+
id: domId,
|
|
958
|
+
style: styles,
|
|
959
|
+
value: text,
|
|
960
|
+
isEditable,
|
|
961
|
+
nodeId: node.id,
|
|
962
|
+
onClick: handleClick,
|
|
963
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "text", val, isBlur),
|
|
964
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0
|
|
965
|
+
}
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
case "table": {
|
|
969
|
+
const isStriped = resolvedProps.striped === true;
|
|
970
|
+
const isBordered = resolvedProps.bordered !== false;
|
|
971
|
+
const isCompact = resolvedProps.compact === true;
|
|
972
|
+
const tableStyles = {
|
|
973
|
+
width: "100%",
|
|
974
|
+
borderCollapse: "collapse",
|
|
975
|
+
...styles,
|
|
976
|
+
...isBordered ? { border: styles.border || "1px solid #e2e8f0" } : {}
|
|
977
|
+
};
|
|
978
|
+
return /* @__PURE__ */ jsx3(
|
|
979
|
+
"table",
|
|
980
|
+
{
|
|
981
|
+
id: domId,
|
|
982
|
+
style: tableStyles,
|
|
983
|
+
onClick: handleClick,
|
|
984
|
+
"data-kubuild-node": node.id,
|
|
985
|
+
"data-striped": isStriped ? "true" : void 0,
|
|
986
|
+
"data-bordered": isBordered ? "true" : void 0,
|
|
987
|
+
"data-compact": isCompact ? "true" : void 0,
|
|
988
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
989
|
+
children: /* @__PURE__ */ jsx3("tbody", { children: childrenElements })
|
|
990
|
+
}
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
case "table-row": {
|
|
994
|
+
return /* @__PURE__ */ jsx3(
|
|
995
|
+
"tr",
|
|
996
|
+
{
|
|
997
|
+
id: domId,
|
|
998
|
+
style: styles,
|
|
999
|
+
onClick: handleClick,
|
|
1000
|
+
"data-kubuild-node": node.id,
|
|
1001
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
1002
|
+
children: childrenElements
|
|
1003
|
+
}
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
case "table-cell": {
|
|
1007
|
+
const rawTag = resolvedProps.tag;
|
|
1008
|
+
const Tag = rawTag === "th" ? "th" : "td";
|
|
1009
|
+
const colSpan = typeof resolvedProps.colSpan === "number" && resolvedProps.colSpan > 1 ? resolvedProps.colSpan : void 0;
|
|
1010
|
+
const rowSpan = typeof resolvedProps.rowSpan === "number" && resolvedProps.rowSpan > 1 ? resolvedProps.rowSpan : void 0;
|
|
1011
|
+
const text = resolvedProps.text !== void 0 ? String(resolvedProps.text) : "";
|
|
1012
|
+
const hasChildren = Boolean(childrenElements && childrenElements.length > 0);
|
|
1013
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.text);
|
|
1014
|
+
const cellStyles = {
|
|
1015
|
+
padding: "8px 12px",
|
|
1016
|
+
border: "1px solid #e2e8f0",
|
|
1017
|
+
textAlign: "left",
|
|
1018
|
+
...styles,
|
|
1019
|
+
...Tag === "th" ? {
|
|
1020
|
+
fontWeight: styles.fontWeight || "600",
|
|
1021
|
+
backgroundColor: styles.backgroundColor || "#f8fafc"
|
|
1022
|
+
} : {}
|
|
1023
|
+
};
|
|
1024
|
+
if (hasChildren) {
|
|
1025
|
+
return /* @__PURE__ */ jsxs2(
|
|
1026
|
+
Tag,
|
|
1027
|
+
{
|
|
1028
|
+
id: domId,
|
|
1029
|
+
colSpan,
|
|
1030
|
+
rowSpan,
|
|
1031
|
+
style: cellStyles,
|
|
1032
|
+
onClick: handleClick,
|
|
1033
|
+
"data-kubuild-node": node.id,
|
|
1034
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
1035
|
+
children: [
|
|
1036
|
+
text ? isEditable ? /* @__PURE__ */ jsx3(
|
|
1037
|
+
EditableText,
|
|
1038
|
+
{
|
|
1039
|
+
as: "span",
|
|
1040
|
+
value: text,
|
|
1041
|
+
isEditable,
|
|
1042
|
+
nodeId: node.id,
|
|
1043
|
+
onClick: handleClick,
|
|
1044
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "text", val, isBlur)
|
|
1045
|
+
}
|
|
1046
|
+
) : /* @__PURE__ */ jsx3("span", { children: text }) : null,
|
|
1047
|
+
childrenElements
|
|
1048
|
+
]
|
|
1049
|
+
}
|
|
1050
|
+
);
|
|
1051
|
+
}
|
|
1052
|
+
return /* @__PURE__ */ jsx3(
|
|
1053
|
+
EditableText,
|
|
1054
|
+
{
|
|
1055
|
+
as: Tag,
|
|
1056
|
+
id: domId,
|
|
1057
|
+
colSpan,
|
|
1058
|
+
rowSpan,
|
|
1059
|
+
style: cellStyles,
|
|
1060
|
+
value: text,
|
|
1061
|
+
isEditable,
|
|
1062
|
+
nodeId: node.id,
|
|
1063
|
+
onClick: handleClick,
|
|
1064
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "text", val, isBlur),
|
|
1065
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0
|
|
1066
|
+
}
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
case "image": {
|
|
1070
|
+
const rawSrc = typeof resolvedProps.src === "string" && resolvedProps.src.length > 0 ? resolvedProps.src : void 0;
|
|
1071
|
+
const directSrc = rawSrc ?? void 0;
|
|
1072
|
+
const asset = isAssetReference(props.asset) ? props.asset : void 0;
|
|
1073
|
+
const resolvedSrc = !directSrc && asset && context?.assetProvider ? resolveAssetSync(context.assetProvider, asset.assetId) : void 0;
|
|
1074
|
+
const fallbackSrc = asset?.fallbackUrl;
|
|
1075
|
+
const rawUrl = directSrc || resolvedSrc || fallbackSrc;
|
|
1076
|
+
const safeSrc = rawUrl ? sanitizeUrl(rawUrl, "", { allowBlobMedia: true }) : void 0;
|
|
1077
|
+
const alt = typeof resolvedProps.alt === "string" ? resolvedProps.alt : "";
|
|
1078
|
+
const loading = resolvedProps.loading === "eager" ? "eager" : "lazy";
|
|
1079
|
+
return /* @__PURE__ */ jsx3(
|
|
1080
|
+
"img",
|
|
1081
|
+
{
|
|
1082
|
+
id: domId,
|
|
1083
|
+
src: safeSrc || void 0,
|
|
1084
|
+
alt,
|
|
1085
|
+
role: alt.length === 0 ? "presentation" : void 0,
|
|
1086
|
+
loading,
|
|
1087
|
+
width: resolvedProps.width,
|
|
1088
|
+
height: resolvedProps.height,
|
|
1089
|
+
style: styles,
|
|
1090
|
+
onClick: handleClick,
|
|
1091
|
+
"data-kubuild-node": node.id
|
|
1092
|
+
}
|
|
1093
|
+
);
|
|
1094
|
+
}
|
|
1095
|
+
case "video": {
|
|
1096
|
+
const rawSrc = typeof resolvedProps.src === "string" ? resolvedProps.src : typeof props.src === "string" ? props.src : "";
|
|
1097
|
+
const provider = typeof resolvedProps.provider === "string" ? resolvedProps.provider : typeof props.provider === "string" ? props.provider : "auto";
|
|
1098
|
+
const rawPoster = typeof resolvedProps.poster === "string" ? resolvedProps.poster : typeof props.poster === "string" ? props.poster : void 0;
|
|
1099
|
+
const poster = rawPoster ? sanitizeUrl(rawPoster) : void 0;
|
|
1100
|
+
const controls = resolvedProps.controls !== false && props.controls !== false;
|
|
1101
|
+
const autoplay = resolvedProps.autoplay === true || props.autoplay === true;
|
|
1102
|
+
const loop = resolvedProps.loop === true || props.loop === true;
|
|
1103
|
+
const muted = resolvedProps.muted === true || props.muted === true;
|
|
1104
|
+
const aspectRatio = aspectRatioToCss(resolvedProps.aspectRatio ?? props.aspectRatio ?? "16:9");
|
|
1105
|
+
const ytId = provider === "youtube" ? getYouTubeId(rawSrc) || rawSrc : provider === "auto" ? getYouTubeId(rawSrc) : null;
|
|
1106
|
+
const vimeoId = provider === "vimeo" ? getVimeoId(rawSrc) || rawSrc : provider === "auto" ? getVimeoId(rawSrc) : null;
|
|
1107
|
+
const videoStyles = {
|
|
1108
|
+
width: "100%",
|
|
1109
|
+
maxWidth: "100%",
|
|
1110
|
+
display: "block",
|
|
1111
|
+
...aspectRatio ? { aspectRatio } : {},
|
|
1112
|
+
...styles
|
|
1113
|
+
};
|
|
1114
|
+
if (ytId) {
|
|
1115
|
+
const autoplayParam = autoplay ? "1" : "0";
|
|
1116
|
+
const loopParam = loop ? `1&playlist=${ytId}` : "0";
|
|
1117
|
+
const muteParam = muted ? "1" : "0";
|
|
1118
|
+
const controlsParam = controls ? "1" : "0";
|
|
1119
|
+
const embedUrl = `https://www.youtube.com/embed/${ytId}?autoplay=${autoplayParam}&loop=${loopParam}&mute=${muteParam}&controls=${controlsParam}`;
|
|
1120
|
+
return /* @__PURE__ */ jsx3(
|
|
1121
|
+
"div",
|
|
1122
|
+
{
|
|
1123
|
+
id: domId,
|
|
1124
|
+
style: { ...videoStyles, position: "relative", overflow: "hidden" },
|
|
1125
|
+
onClick: handleClick,
|
|
1126
|
+
"data-kubuild-node": node.id,
|
|
1127
|
+
"data-video-provider": "youtube",
|
|
1128
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
1129
|
+
children: /* @__PURE__ */ jsx3(
|
|
1130
|
+
"iframe",
|
|
1131
|
+
{
|
|
1132
|
+
src: embedUrl,
|
|
1133
|
+
title: "YouTube video",
|
|
1134
|
+
style: { width: "100%", height: "100%", border: "none", minHeight: "240px" },
|
|
1135
|
+
allow: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share",
|
|
1136
|
+
allowFullScreen: true
|
|
1137
|
+
}
|
|
1138
|
+
)
|
|
1139
|
+
}
|
|
1140
|
+
);
|
|
1141
|
+
}
|
|
1142
|
+
if (vimeoId) {
|
|
1143
|
+
const autoplayParam = autoplay ? "1" : "0";
|
|
1144
|
+
const loopParam = loop ? "1" : "0";
|
|
1145
|
+
const muteParam = muted ? "1" : "0";
|
|
1146
|
+
const embedUrl = `https://player.vimeo.com/video/${vimeoId}?autoplay=${autoplayParam}&loop=${loopParam}&muted=${muteParam}`;
|
|
1147
|
+
return /* @__PURE__ */ jsx3(
|
|
1148
|
+
"div",
|
|
1149
|
+
{
|
|
1150
|
+
id: domId,
|
|
1151
|
+
style: { ...videoStyles, position: "relative", overflow: "hidden" },
|
|
1152
|
+
onClick: handleClick,
|
|
1153
|
+
"data-kubuild-node": node.id,
|
|
1154
|
+
"data-video-provider": "vimeo",
|
|
1155
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0,
|
|
1156
|
+
children: /* @__PURE__ */ jsx3(
|
|
1157
|
+
"iframe",
|
|
1158
|
+
{
|
|
1159
|
+
src: embedUrl,
|
|
1160
|
+
title: "Vimeo video",
|
|
1161
|
+
style: { width: "100%", height: "100%", border: "none", minHeight: "240px" },
|
|
1162
|
+
allow: "autoplay; fullscreen; picture-in-picture",
|
|
1163
|
+
allowFullScreen: true
|
|
1164
|
+
}
|
|
1165
|
+
)
|
|
1166
|
+
}
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
const safeSrc = sanitizeUrl(rawSrc, "", { allowBlobMedia: true });
|
|
1170
|
+
return /* @__PURE__ */ jsx3(
|
|
1171
|
+
"video",
|
|
1172
|
+
{
|
|
1173
|
+
id: domId,
|
|
1174
|
+
src: safeSrc || void 0,
|
|
1175
|
+
poster: poster || void 0,
|
|
1176
|
+
controls,
|
|
1177
|
+
autoPlay: autoplay,
|
|
1178
|
+
loop,
|
|
1179
|
+
muted,
|
|
1180
|
+
style: videoStyles,
|
|
1181
|
+
onClick: handleClick,
|
|
1182
|
+
"data-kubuild-node": node.id,
|
|
1183
|
+
"data-video-provider": "html5",
|
|
1184
|
+
playsInline: true,
|
|
1185
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0
|
|
1186
|
+
}
|
|
1187
|
+
);
|
|
1188
|
+
}
|
|
1189
|
+
case "icon": {
|
|
1190
|
+
const name = typeof resolvedProps.name === "string" && resolvedProps.name.trim().length > 0 ? resolvedProps.name.trim() : typeof props.name === "string" && props.name.trim().length > 0 ? props.name.trim() : "star";
|
|
1191
|
+
const size = typeof resolvedProps.size === "number" ? resolvedProps.size : typeof props.size === "number" ? props.size : 24;
|
|
1192
|
+
const color = typeof resolvedProps.color === "string" ? resolvedProps.color : typeof props.color === "string" ? props.color : "currentColor";
|
|
1193
|
+
const strokeWidth = typeof resolvedProps.strokeWidth === "number" ? resolvedProps.strokeWidth : typeof props.strokeWidth === "number" ? props.strokeWidth : 2;
|
|
1194
|
+
const pascalName = toPascalCase(name);
|
|
1195
|
+
const IconComponent = lucideIcons[pascalName];
|
|
1196
|
+
return /* @__PURE__ */ jsx3(
|
|
1197
|
+
"span",
|
|
1198
|
+
{
|
|
1199
|
+
id: domId,
|
|
1200
|
+
style: { display: "inline-flex", alignItems: "center", justifyContent: "center", color, ...styles },
|
|
1201
|
+
onClick: handleClick,
|
|
1202
|
+
"data-kubuild-node": node.id,
|
|
1203
|
+
"data-icon-name": name,
|
|
1204
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : "img",
|
|
1205
|
+
"aria-label": typeof resolvedProps.ariaLabel === "string" ? resolvedProps.ariaLabel : name,
|
|
1206
|
+
children: IconComponent ? /* @__PURE__ */ jsx3(IconComponent, { size, color, strokeWidth }) : /* @__PURE__ */ jsx3("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: color, strokeWidth, strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsx3("polygon", { points: "12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" }) })
|
|
1207
|
+
}
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
case "html-embed": {
|
|
1211
|
+
const rawHtml = typeof resolvedProps.html === "string" ? resolvedProps.html : typeof props.html === "string" ? props.html : "";
|
|
1212
|
+
const sanitized = sanitizeHtml(rawHtml);
|
|
1213
|
+
if (mode === "editor" && !rawHtml.trim()) {
|
|
1214
|
+
return /* @__PURE__ */ jsxs2(
|
|
1215
|
+
"div",
|
|
1216
|
+
{
|
|
1217
|
+
id: domId,
|
|
1218
|
+
style: {
|
|
1219
|
+
padding: "16px",
|
|
1220
|
+
border: "2px dashed #94a3b8",
|
|
1221
|
+
borderRadius: "8px",
|
|
1222
|
+
backgroundColor: "#f8fafc",
|
|
1223
|
+
color: "#64748b",
|
|
1224
|
+
textAlign: "center",
|
|
1225
|
+
fontSize: "13px",
|
|
1226
|
+
fontFamily: "sans-serif",
|
|
1227
|
+
...styles
|
|
1228
|
+
},
|
|
1229
|
+
onClick: handleClick,
|
|
1230
|
+
"data-kubuild-node": node.id,
|
|
1231
|
+
children: [
|
|
1232
|
+
/* @__PURE__ */ jsx3("span", { style: { fontWeight: 600 }, children: "</> HTML Embed" }),
|
|
1233
|
+
/* @__PURE__ */ jsx3("div", { style: { fontSize: "11px", marginTop: "4px" }, children: "Click to configure HTML code in Inspector Panel" })
|
|
1234
|
+
]
|
|
1235
|
+
}
|
|
1236
|
+
);
|
|
1237
|
+
}
|
|
1238
|
+
return /* @__PURE__ */ jsx3(
|
|
1239
|
+
HtmlEmbedView,
|
|
1240
|
+
{
|
|
1241
|
+
id: domId,
|
|
1242
|
+
style: styles,
|
|
1243
|
+
onClick: handleClick,
|
|
1244
|
+
dataKubuildNode: node.id,
|
|
1245
|
+
html: sanitized,
|
|
1246
|
+
role: typeof resolvedProps.role === "string" ? resolvedProps.role : void 0
|
|
1247
|
+
}
|
|
1248
|
+
);
|
|
1249
|
+
}
|
|
1250
|
+
case "button": {
|
|
1251
|
+
const label = String(resolvedProps.label ?? "Button");
|
|
1252
|
+
const disabled = resolvedProps.disabled === true;
|
|
1253
|
+
const rawHref = typeof resolvedProps.href === "string" ? resolvedProps.href : void 0;
|
|
1254
|
+
const href = rawHref ? sanitizeUrl(rawHref, "#") : void 0;
|
|
1255
|
+
const rawTarget = typeof resolvedProps.target === "string" ? resolvedProps.target : void 0;
|
|
1256
|
+
const rawRel = typeof resolvedProps.rel === "string" ? resolvedProps.rel : void 0;
|
|
1257
|
+
const rel = rawTarget === "_blank" && !rawRel ? "noopener noreferrer" : rawRel;
|
|
1258
|
+
const action = isActionBinding2(props.action) ? props.action : void 0;
|
|
1259
|
+
const actionResolved = action ? isActionRegistered(context?.actionRegistry, action.type) : void 0;
|
|
1260
|
+
const actionAttrs = action ? { "data-kubuild-action": action.type, "data-kubuild-action-resolved": actionResolved } : {};
|
|
1261
|
+
const ariaLabel = typeof resolvedProps.ariaLabel === "string" ? resolvedProps.ariaLabel : void 0;
|
|
1262
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.label);
|
|
1263
|
+
const rawButtonType = typeof resolvedProps.buttonType === "string" ? resolvedProps.buttonType : "button";
|
|
1264
|
+
const buttonType = rawButtonType === "submit" || rawButtonType === "reset" ? rawButtonType : "button";
|
|
1265
|
+
if (href && !disabled) {
|
|
1266
|
+
if (isEditable) {
|
|
1267
|
+
return /* @__PURE__ */ jsx3(
|
|
1268
|
+
EditableText,
|
|
1269
|
+
{
|
|
1270
|
+
as: "a",
|
|
1271
|
+
id: domId,
|
|
1272
|
+
href: mode === "editor" ? void 0 : href,
|
|
1273
|
+
target: rawTarget,
|
|
1274
|
+
rel,
|
|
1275
|
+
style: styles,
|
|
1276
|
+
value: label,
|
|
1277
|
+
isEditable,
|
|
1278
|
+
nodeId: node.id,
|
|
1279
|
+
onClick: handleClick,
|
|
1280
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "label", val, isBlur),
|
|
1281
|
+
"aria-label": ariaLabel,
|
|
1282
|
+
tabIndex: 0,
|
|
1283
|
+
...actionAttrs
|
|
1284
|
+
}
|
|
1285
|
+
);
|
|
1286
|
+
}
|
|
1287
|
+
return /* @__PURE__ */ jsx3(
|
|
1288
|
+
"a",
|
|
1289
|
+
{
|
|
1290
|
+
id: domId,
|
|
1291
|
+
href,
|
|
1292
|
+
target: rawTarget,
|
|
1293
|
+
rel,
|
|
1294
|
+
style: styles,
|
|
1295
|
+
onClick: handleClick,
|
|
1296
|
+
"data-kubuild-node": node.id,
|
|
1297
|
+
"aria-label": ariaLabel,
|
|
1298
|
+
tabIndex: 0,
|
|
1299
|
+
...actionAttrs,
|
|
1300
|
+
children: label
|
|
1301
|
+
}
|
|
1302
|
+
);
|
|
1303
|
+
}
|
|
1304
|
+
if (isEditable) {
|
|
1305
|
+
return /* @__PURE__ */ jsx3(
|
|
1306
|
+
EditableText,
|
|
1307
|
+
{
|
|
1308
|
+
as: "button",
|
|
1309
|
+
id: domId,
|
|
1310
|
+
type: mode === "editor" ? "button" : buttonType,
|
|
1311
|
+
disabled,
|
|
1312
|
+
"aria-disabled": disabled ? true : void 0,
|
|
1313
|
+
"aria-label": ariaLabel,
|
|
1314
|
+
tabIndex: disabled ? -1 : 0,
|
|
1315
|
+
style: styles,
|
|
1316
|
+
value: label,
|
|
1317
|
+
isEditable,
|
|
1318
|
+
nodeId: node.id,
|
|
1319
|
+
onClick: disabled ? void 0 : handleClick,
|
|
1320
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "label", val, isBlur),
|
|
1321
|
+
...actionAttrs
|
|
1322
|
+
}
|
|
1323
|
+
);
|
|
1324
|
+
}
|
|
1325
|
+
return /* @__PURE__ */ jsx3(
|
|
1326
|
+
"button",
|
|
1327
|
+
{
|
|
1328
|
+
id: domId,
|
|
1329
|
+
type: mode === "editor" ? "button" : buttonType,
|
|
1330
|
+
disabled,
|
|
1331
|
+
"aria-disabled": disabled ? true : void 0,
|
|
1332
|
+
"aria-label": ariaLabel,
|
|
1333
|
+
tabIndex: disabled ? -1 : 0,
|
|
1334
|
+
style: styles,
|
|
1335
|
+
onClick: disabled ? void 0 : handleClick,
|
|
1336
|
+
"data-kubuild-node": node.id,
|
|
1337
|
+
...actionAttrs,
|
|
1338
|
+
children: label
|
|
1339
|
+
}
|
|
1340
|
+
);
|
|
1341
|
+
}
|
|
1342
|
+
case "form": {
|
|
1343
|
+
const action = typeof resolvedProps.action === "string" ? resolvedProps.action : void 0;
|
|
1344
|
+
const method = typeof resolvedProps.method === "string" ? resolvedProps.method : "POST";
|
|
1345
|
+
const target = typeof resolvedProps.target === "string" ? resolvedProps.target : void 0;
|
|
1346
|
+
const autoComplete = typeof resolvedProps.autoComplete === "string" ? resolvedProps.autoComplete : void 0;
|
|
1347
|
+
const name = typeof resolvedProps.name === "string" ? resolvedProps.name : void 0;
|
|
1348
|
+
const handleSubmit = (e) => {
|
|
1349
|
+
if (mode === "editor") {
|
|
1350
|
+
e.preventDefault();
|
|
1351
|
+
}
|
|
1352
|
+
};
|
|
1353
|
+
return /* @__PURE__ */ jsx3(
|
|
1354
|
+
"form",
|
|
1355
|
+
{
|
|
1356
|
+
id: domId,
|
|
1357
|
+
name,
|
|
1358
|
+
action: action && mode !== "editor" ? sanitizeUrl(action, "") : void 0,
|
|
1359
|
+
method,
|
|
1360
|
+
target,
|
|
1361
|
+
autoComplete,
|
|
1362
|
+
style: styles,
|
|
1363
|
+
onClick: handleClick,
|
|
1364
|
+
onSubmit: handleSubmit,
|
|
1365
|
+
"data-kubuild-node": node.id,
|
|
1366
|
+
role: "form",
|
|
1367
|
+
"aria-label": name,
|
|
1368
|
+
children: childrenElements
|
|
1369
|
+
}
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1372
|
+
case "input": {
|
|
1373
|
+
const name = typeof resolvedProps.name === "string" ? resolvedProps.name : void 0;
|
|
1374
|
+
const inputType = typeof resolvedProps.type === "string" ? resolvedProps.type : "text";
|
|
1375
|
+
const placeholder = typeof resolvedProps.placeholder === "string" ? resolvedProps.placeholder : void 0;
|
|
1376
|
+
const defaultValue = resolvedProps.defaultValue !== void 0 ? String(resolvedProps.defaultValue) : void 0;
|
|
1377
|
+
const required = resolvedProps.required === true;
|
|
1378
|
+
const disabled = resolvedProps.disabled === true;
|
|
1379
|
+
const readOnly = resolvedProps.readOnly === true;
|
|
1380
|
+
return /* @__PURE__ */ jsx3(
|
|
1381
|
+
"input",
|
|
1382
|
+
{
|
|
1383
|
+
id: domId,
|
|
1384
|
+
type: inputType,
|
|
1385
|
+
name,
|
|
1386
|
+
placeholder,
|
|
1387
|
+
defaultValue,
|
|
1388
|
+
required,
|
|
1389
|
+
disabled,
|
|
1390
|
+
readOnly,
|
|
1391
|
+
style: styles,
|
|
1392
|
+
onClick: handleClick,
|
|
1393
|
+
"data-kubuild-node": node.id
|
|
1394
|
+
}
|
|
1395
|
+
);
|
|
1396
|
+
}
|
|
1397
|
+
case "textarea": {
|
|
1398
|
+
const name = typeof resolvedProps.name === "string" ? resolvedProps.name : void 0;
|
|
1399
|
+
const placeholder = typeof resolvedProps.placeholder === "string" ? resolvedProps.placeholder : void 0;
|
|
1400
|
+
const defaultValue = resolvedProps.defaultValue !== void 0 ? String(resolvedProps.defaultValue) : void 0;
|
|
1401
|
+
const rows = typeof resolvedProps.rows === "number" ? resolvedProps.rows : 4;
|
|
1402
|
+
const required = resolvedProps.required === true;
|
|
1403
|
+
const disabled = resolvedProps.disabled === true;
|
|
1404
|
+
const readOnly = resolvedProps.readOnly === true;
|
|
1405
|
+
return /* @__PURE__ */ jsx3(
|
|
1406
|
+
"textarea",
|
|
1407
|
+
{
|
|
1408
|
+
id: domId,
|
|
1409
|
+
name,
|
|
1410
|
+
placeholder,
|
|
1411
|
+
defaultValue,
|
|
1412
|
+
rows,
|
|
1413
|
+
required,
|
|
1414
|
+
disabled,
|
|
1415
|
+
readOnly,
|
|
1416
|
+
style: styles,
|
|
1417
|
+
onClick: handleClick,
|
|
1418
|
+
"data-kubuild-node": node.id
|
|
1419
|
+
}
|
|
1420
|
+
);
|
|
1421
|
+
}
|
|
1422
|
+
case "select": {
|
|
1423
|
+
const name = typeof resolvedProps.name === "string" ? resolvedProps.name : void 0;
|
|
1424
|
+
const placeholder = typeof resolvedProps.placeholder === "string" ? resolvedProps.placeholder : void 0;
|
|
1425
|
+
const defaultValue = resolvedProps.defaultValue !== void 0 ? String(resolvedProps.defaultValue) : void 0;
|
|
1426
|
+
const required = resolvedProps.required === true;
|
|
1427
|
+
const disabled = resolvedProps.disabled === true;
|
|
1428
|
+
let optionsList = [];
|
|
1429
|
+
const rawOptions = resolvedProps.options ?? props.options;
|
|
1430
|
+
if (Array.isArray(rawOptions)) {
|
|
1431
|
+
optionsList = rawOptions.map((opt) => {
|
|
1432
|
+
if (typeof opt === "object" && opt !== null) {
|
|
1433
|
+
const record = opt;
|
|
1434
|
+
return {
|
|
1435
|
+
label: String(record.label ?? record.value ?? ""),
|
|
1436
|
+
value: String(record.value ?? record.label ?? "")
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
return { label: String(opt), value: String(opt) };
|
|
1440
|
+
});
|
|
1441
|
+
} else if (typeof rawOptions === "string") {
|
|
1442
|
+
try {
|
|
1443
|
+
const parsed = JSON.parse(rawOptions);
|
|
1444
|
+
if (Array.isArray(parsed)) {
|
|
1445
|
+
optionsList = parsed.map((opt) => {
|
|
1446
|
+
if (typeof opt === "object" && opt !== null) {
|
|
1447
|
+
const record = opt;
|
|
1448
|
+
return {
|
|
1449
|
+
label: String(record.label ?? record.value ?? ""),
|
|
1450
|
+
value: String(record.value ?? record.label ?? "")
|
|
1451
|
+
};
|
|
1452
|
+
}
|
|
1453
|
+
return { label: String(opt), value: String(opt) };
|
|
1454
|
+
});
|
|
1455
|
+
}
|
|
1456
|
+
} catch {
|
|
1457
|
+
}
|
|
1458
|
+
}
|
|
1459
|
+
return /* @__PURE__ */ jsxs2(
|
|
1460
|
+
"select",
|
|
1461
|
+
{
|
|
1462
|
+
id: domId,
|
|
1463
|
+
name,
|
|
1464
|
+
defaultValue,
|
|
1465
|
+
required,
|
|
1466
|
+
disabled,
|
|
1467
|
+
style: styles,
|
|
1468
|
+
onClick: handleClick,
|
|
1469
|
+
"data-kubuild-node": node.id,
|
|
1470
|
+
children: [
|
|
1471
|
+
placeholder && /* @__PURE__ */ jsx3("option", { value: "", disabled: required, children: placeholder }),
|
|
1472
|
+
optionsList.map((opt, idx) => /* @__PURE__ */ jsx3("option", { value: opt.value, children: opt.label }, `${opt.value}-${idx}`))
|
|
1473
|
+
]
|
|
1474
|
+
}
|
|
1475
|
+
);
|
|
1476
|
+
}
|
|
1477
|
+
case "checkbox": {
|
|
1478
|
+
const name = typeof resolvedProps.name === "string" ? resolvedProps.name : void 0;
|
|
1479
|
+
const label = String(resolvedProps.label ?? "Checkbox");
|
|
1480
|
+
const value = resolvedProps.value !== void 0 ? String(resolvedProps.value) : "yes";
|
|
1481
|
+
const defaultChecked = resolvedProps.defaultChecked === true;
|
|
1482
|
+
const required = resolvedProps.required === true;
|
|
1483
|
+
const disabled = resolvedProps.disabled === true;
|
|
1484
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.label);
|
|
1485
|
+
return /* @__PURE__ */ jsxs2(
|
|
1486
|
+
"label",
|
|
1487
|
+
{
|
|
1488
|
+
id: domId,
|
|
1489
|
+
style: styles,
|
|
1490
|
+
onClick: handleClick,
|
|
1491
|
+
"data-kubuild-node": node.id,
|
|
1492
|
+
children: [
|
|
1493
|
+
/* @__PURE__ */ jsx3(
|
|
1494
|
+
"input",
|
|
1495
|
+
{
|
|
1496
|
+
type: "checkbox",
|
|
1497
|
+
name,
|
|
1498
|
+
value,
|
|
1499
|
+
defaultChecked,
|
|
1500
|
+
required,
|
|
1501
|
+
disabled,
|
|
1502
|
+
style: { cursor: disabled ? "not-allowed" : "pointer" }
|
|
1503
|
+
}
|
|
1504
|
+
),
|
|
1505
|
+
isEditable ? /* @__PURE__ */ jsx3(
|
|
1506
|
+
EditableText,
|
|
1507
|
+
{
|
|
1508
|
+
as: "span",
|
|
1509
|
+
value: label,
|
|
1510
|
+
isEditable,
|
|
1511
|
+
nodeId: node.id,
|
|
1512
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "label", val, isBlur)
|
|
1513
|
+
}
|
|
1514
|
+
) : /* @__PURE__ */ jsx3("span", { children: label })
|
|
1515
|
+
]
|
|
1516
|
+
}
|
|
1517
|
+
);
|
|
1518
|
+
}
|
|
1519
|
+
case "radio": {
|
|
1520
|
+
const name = typeof resolvedProps.name === "string" ? resolvedProps.name : void 0;
|
|
1521
|
+
const label = String(resolvedProps.label ?? "Radio");
|
|
1522
|
+
const value = resolvedProps.value !== void 0 ? String(resolvedProps.value) : "option";
|
|
1523
|
+
const defaultChecked = resolvedProps.defaultChecked === true;
|
|
1524
|
+
const required = resolvedProps.required === true;
|
|
1525
|
+
const disabled = resolvedProps.disabled === true;
|
|
1526
|
+
const isEditable = mode === "editor" && !isVariableBinding3(props.label);
|
|
1527
|
+
return /* @__PURE__ */ jsxs2(
|
|
1528
|
+
"label",
|
|
1529
|
+
{
|
|
1530
|
+
id: domId,
|
|
1531
|
+
style: styles,
|
|
1532
|
+
onClick: handleClick,
|
|
1533
|
+
"data-kubuild-node": node.id,
|
|
1534
|
+
children: [
|
|
1535
|
+
/* @__PURE__ */ jsx3(
|
|
1536
|
+
"input",
|
|
1537
|
+
{
|
|
1538
|
+
type: "radio",
|
|
1539
|
+
name,
|
|
1540
|
+
value,
|
|
1541
|
+
defaultChecked,
|
|
1542
|
+
required,
|
|
1543
|
+
disabled,
|
|
1544
|
+
style: { cursor: disabled ? "not-allowed" : "pointer" }
|
|
1545
|
+
}
|
|
1546
|
+
),
|
|
1547
|
+
isEditable ? /* @__PURE__ */ jsx3(
|
|
1548
|
+
EditableText,
|
|
1549
|
+
{
|
|
1550
|
+
as: "span",
|
|
1551
|
+
value: label,
|
|
1552
|
+
isEditable,
|
|
1553
|
+
nodeId: node.id,
|
|
1554
|
+
onChange: (val, isBlur) => onNodePropChange?.(node.id, "label", val, isBlur)
|
|
1555
|
+
}
|
|
1556
|
+
) : /* @__PURE__ */ jsx3("span", { children: label })
|
|
1557
|
+
]
|
|
1558
|
+
}
|
|
1559
|
+
);
|
|
1560
|
+
}
|
|
1561
|
+
case "collection": {
|
|
1562
|
+
const sourceKey = typeof props.sourceKey === "string" ? props.sourceKey : void 0;
|
|
1563
|
+
const itemAlias = typeof props.itemAlias === "string" && props.itemAlias.length > 0 ? props.itemAlias : "item";
|
|
1564
|
+
const indexKey = `${itemAlias}Index`;
|
|
1565
|
+
const sourceValue = sourceKey ? resolveBinding3({ key: sourceKey }, context).value : void 0;
|
|
1566
|
+
if (!Array.isArray(sourceValue)) {
|
|
1567
|
+
const collectionDiagnostic = {
|
|
1568
|
+
code: "INVALID_COLLECTION_SOURCE",
|
|
1569
|
+
nodeId: node.id,
|
|
1570
|
+
propName: "sourceKey",
|
|
1571
|
+
message: `Collection node "${node.id}" expected an array at variable path "${sourceKey ?? "(missing sourceKey)"}" but found ${sourceValue === void 0 ? "nothing" : typeof sourceValue}.`
|
|
1572
|
+
};
|
|
1573
|
+
onDiagnostic?.(collectionDiagnostic);
|
|
1574
|
+
context?.onDiagnostic?.(collectionDiagnostic);
|
|
1575
|
+
if (mode === "editor") {
|
|
1576
|
+
return /* @__PURE__ */ jsx3(
|
|
1577
|
+
"div",
|
|
1578
|
+
{
|
|
1579
|
+
id: domId,
|
|
1580
|
+
"data-kubuild-node": node.id,
|
|
1581
|
+
"data-kubuild-collection-invalid": node.type,
|
|
1582
|
+
style: {
|
|
1583
|
+
...styles,
|
|
1584
|
+
border: "2px dashed #f59e0b",
|
|
1585
|
+
backgroundColor: "#fffbeb",
|
|
1586
|
+
color: "#92400e",
|
|
1587
|
+
padding: "12px",
|
|
1588
|
+
borderRadius: "6px",
|
|
1589
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
1590
|
+
},
|
|
1591
|
+
onClick: handleClick,
|
|
1592
|
+
children: /* @__PURE__ */ jsxs2("div", { style: { fontWeight: 600, fontSize: "13px" }, children: [
|
|
1593
|
+
"\u{1F4E6} Collection: expected an array at ",
|
|
1594
|
+
/* @__PURE__ */ jsx3("code", { children: sourceKey ?? "(missing sourceKey)" })
|
|
1595
|
+
] })
|
|
1596
|
+
}
|
|
1597
|
+
);
|
|
1598
|
+
}
|
|
1599
|
+
return /* @__PURE__ */ jsx3("div", { id: domId, "data-kubuild-node": node.id, style: styles, onClick: handleClick, "aria-hidden": "true" });
|
|
1600
|
+
}
|
|
1601
|
+
return /* @__PURE__ */ jsx3("div", { id: domId, "data-kubuild-node": node.id, style: styles, onClick: handleClick, children: sourceValue.map((item, index) => {
|
|
1602
|
+
const childContext = {
|
|
1603
|
+
...context,
|
|
1604
|
+
variables: { ...context?.variables ?? {}, [itemAlias]: item, [indexKey]: index }
|
|
1605
|
+
};
|
|
1606
|
+
const itemSuffix = `${instanceSuffix}--${index}`;
|
|
1607
|
+
return node.children?.map((child) => /* @__PURE__ */ jsx3(
|
|
1608
|
+
NodeRenderer,
|
|
1609
|
+
{
|
|
1610
|
+
node: child,
|
|
1611
|
+
document,
|
|
1612
|
+
registry,
|
|
1613
|
+
context: childContext,
|
|
1614
|
+
viewport,
|
|
1615
|
+
mode,
|
|
1616
|
+
onNodeClick,
|
|
1617
|
+
onDiagnostic,
|
|
1618
|
+
onActionDispatch,
|
|
1619
|
+
onNodePropChange,
|
|
1620
|
+
instanceSuffix: itemSuffix
|
|
1621
|
+
},
|
|
1622
|
+
`${child.id}${itemSuffix}`
|
|
1623
|
+
));
|
|
1624
|
+
}) });
|
|
1625
|
+
}
|
|
1626
|
+
default:
|
|
1627
|
+
if (mode === "editor") {
|
|
1628
|
+
return /* @__PURE__ */ jsxs2(
|
|
1629
|
+
"div",
|
|
1630
|
+
{
|
|
1631
|
+
id: domId,
|
|
1632
|
+
"data-kubuild-node": node.id,
|
|
1633
|
+
"data-kubuild-unknown": node.type,
|
|
1634
|
+
style: {
|
|
1635
|
+
...styles,
|
|
1636
|
+
border: "2px dashed #f59e0b",
|
|
1637
|
+
backgroundColor: "#fffbeb",
|
|
1638
|
+
color: "#92400e",
|
|
1639
|
+
padding: "12px",
|
|
1640
|
+
borderRadius: "6px",
|
|
1641
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
1642
|
+
},
|
|
1643
|
+
onClick: handleClick,
|
|
1644
|
+
children: [
|
|
1645
|
+
/* @__PURE__ */ jsxs2("div", { style: { fontWeight: 600, fontSize: "13px", marginBottom: "4px" }, children: [
|
|
1646
|
+
"\u{1F9E9} Unknown Component: ",
|
|
1647
|
+
/* @__PURE__ */ jsx3("code", { children: node.type })
|
|
1648
|
+
] }),
|
|
1649
|
+
/* @__PURE__ */ jsxs2("div", { style: { fontSize: "11px", color: "#b45309", marginBottom: childrenElements ? "8px" : 0 }, children: [
|
|
1650
|
+
"Node ID: ",
|
|
1651
|
+
/* @__PURE__ */ jsx3("code", { children: node.id })
|
|
1652
|
+
] }),
|
|
1653
|
+
childrenElements
|
|
1654
|
+
]
|
|
1655
|
+
}
|
|
1656
|
+
);
|
|
1657
|
+
}
|
|
1658
|
+
return /* @__PURE__ */ jsx3(
|
|
1659
|
+
"div",
|
|
1660
|
+
{
|
|
1661
|
+
id: domId,
|
|
1662
|
+
"data-kubuild-node": node.id,
|
|
1663
|
+
"data-kubuild-unknown": node.type,
|
|
1664
|
+
style: styles,
|
|
1665
|
+
onClick: handleClick,
|
|
1666
|
+
children: childrenElements
|
|
1667
|
+
}
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
};
|
|
1671
|
+
let content;
|
|
1672
|
+
try {
|
|
1673
|
+
content = renderNodeContent();
|
|
1674
|
+
} catch (error) {
|
|
1675
|
+
if (mode === "editor") {
|
|
1676
|
+
content = /* @__PURE__ */ jsxs2(
|
|
1677
|
+
"div",
|
|
1678
|
+
{
|
|
1679
|
+
"data-kubuild-node": node.id,
|
|
1680
|
+
"data-kubuild-error": node.type,
|
|
1681
|
+
style: {
|
|
1682
|
+
padding: "12px 16px",
|
|
1683
|
+
margin: "4px 0",
|
|
1684
|
+
backgroundColor: "#fef2f2",
|
|
1685
|
+
border: "1px solid #ef4444",
|
|
1686
|
+
borderRadius: "6px",
|
|
1687
|
+
color: "#b91c1c",
|
|
1688
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
1689
|
+
fontSize: "13px",
|
|
1690
|
+
lineHeight: "1.4"
|
|
1691
|
+
},
|
|
1692
|
+
children: [
|
|
1693
|
+
/* @__PURE__ */ jsxs2("div", { style: { fontWeight: 600, marginBottom: "4px" }, children: [
|
|
1694
|
+
"\u26A0\uFE0F Component Render Error: <",
|
|
1695
|
+
node.type,
|
|
1696
|
+
">"
|
|
1697
|
+
] }),
|
|
1698
|
+
/* @__PURE__ */ jsxs2("div", { style: { fontSize: "11px", color: "#7f1d1d", wordBreak: "break-all" }, children: [
|
|
1699
|
+
"Node ID: ",
|
|
1700
|
+
/* @__PURE__ */ jsx3("code", { children: node.id }),
|
|
1701
|
+
" \u2014 ",
|
|
1702
|
+
error instanceof Error ? error.message : String(error)
|
|
1703
|
+
] })
|
|
1704
|
+
]
|
|
1705
|
+
}
|
|
1706
|
+
);
|
|
1707
|
+
} else {
|
|
1708
|
+
content = /* @__PURE__ */ jsx3(
|
|
1709
|
+
"div",
|
|
1710
|
+
{
|
|
1711
|
+
"data-kubuild-node": node.id,
|
|
1712
|
+
"data-kubuild-error": node.type,
|
|
1713
|
+
style: { display: "none" },
|
|
1714
|
+
"aria-hidden": "true"
|
|
1715
|
+
}
|
|
1716
|
+
);
|
|
1717
|
+
}
|
|
1718
|
+
}
|
|
1719
|
+
return /* @__PURE__ */ jsx3(ComponentErrorBoundary, { nodeId: node.id, componentType: node.type, mode, children: content });
|
|
1720
|
+
}
|
|
1721
|
+
var KubuildRenderer = ({
|
|
1722
|
+
document,
|
|
1723
|
+
registry = createDefaultComponentRegistry(),
|
|
1724
|
+
context,
|
|
1725
|
+
viewport = "desktop",
|
|
1726
|
+
mode = "runtime",
|
|
1727
|
+
className,
|
|
1728
|
+
onNodeClick,
|
|
1729
|
+
onDiagnostic,
|
|
1730
|
+
onActionDispatch,
|
|
1731
|
+
onNodePropChange
|
|
1732
|
+
}) => {
|
|
1733
|
+
if (!document || !document.document) {
|
|
1734
|
+
return /* @__PURE__ */ jsx3("div", { className, children: "Empty Document" });
|
|
1735
|
+
}
|
|
1736
|
+
return /* @__PURE__ */ jsx3(RenderContextProvider, { value: context, children: /* @__PURE__ */ jsxs2("div", { className: `kubuild-canvas-root ${className || ""}`, children: [
|
|
1737
|
+
(() => {
|
|
1738
|
+
const css = collectStateStylesCss(document);
|
|
1739
|
+
return css ? /* @__PURE__ */ jsx3("style", { "data-kubuild-state-styles": true, children: css }) : null;
|
|
1740
|
+
})(),
|
|
1741
|
+
/* @__PURE__ */ jsx3(
|
|
1742
|
+
NodeRenderer,
|
|
1743
|
+
{
|
|
1744
|
+
node: document.document,
|
|
1745
|
+
document,
|
|
1746
|
+
registry,
|
|
1747
|
+
context,
|
|
1748
|
+
viewport,
|
|
1749
|
+
mode,
|
|
1750
|
+
onNodeClick,
|
|
1751
|
+
onDiagnostic,
|
|
1752
|
+
onActionDispatch,
|
|
1753
|
+
onNodePropChange
|
|
1754
|
+
}
|
|
1755
|
+
)
|
|
1756
|
+
] }) });
|
|
1757
|
+
};
|
|
1758
|
+
|
|
1759
|
+
// src/preview-adapter.tsx
|
|
1760
|
+
import { useMemo as useMemo3 } from "react";
|
|
1761
|
+
import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1762
|
+
var DEFAULT_VIEWPORT_CONFIGS = Object.freeze({
|
|
1763
|
+
desktop: {
|
|
1764
|
+
width: "100%",
|
|
1765
|
+
maxWidth: "1280px",
|
|
1766
|
+
minHeight: "600px",
|
|
1767
|
+
label: "Desktop (1280px)",
|
|
1768
|
+
isFluid: true
|
|
1769
|
+
},
|
|
1770
|
+
tablet: {
|
|
1771
|
+
width: "768px",
|
|
1772
|
+
height: "1024px",
|
|
1773
|
+
minHeight: "600px",
|
|
1774
|
+
label: "Tablet (768 \xD7 1024)",
|
|
1775
|
+
isFluid: false
|
|
1776
|
+
},
|
|
1777
|
+
mobile: {
|
|
1778
|
+
width: "375px",
|
|
1779
|
+
height: "667px",
|
|
1780
|
+
minHeight: "500px",
|
|
1781
|
+
label: "Mobile (375 \xD7 667)",
|
|
1782
|
+
isFluid: false
|
|
1783
|
+
}
|
|
1784
|
+
});
|
|
1785
|
+
var DEFAULT_BREAKPOINTS = Object.freeze({
|
|
1786
|
+
mobile: 480,
|
|
1787
|
+
tablet: 768,
|
|
1788
|
+
desktop: 1024
|
|
1789
|
+
});
|
|
1790
|
+
function resolveViewportFromWidth(width, breakpoints) {
|
|
1791
|
+
const resolved = { ...DEFAULT_BREAKPOINTS, ...breakpoints };
|
|
1792
|
+
if (width <= resolved.mobile) {
|
|
1793
|
+
return "mobile";
|
|
1794
|
+
}
|
|
1795
|
+
if (width <= resolved.tablet) {
|
|
1796
|
+
return "tablet";
|
|
1797
|
+
}
|
|
1798
|
+
return "desktop";
|
|
1799
|
+
}
|
|
1800
|
+
function resolveViewportDimensions(viewport, customConfigs) {
|
|
1801
|
+
const baseConfig = DEFAULT_VIEWPORT_CONFIGS[viewport] || DEFAULT_VIEWPORT_CONFIGS.desktop;
|
|
1802
|
+
const custom = customConfigs?.[viewport];
|
|
1803
|
+
return { ...baseConfig, ...custom };
|
|
1804
|
+
}
|
|
1805
|
+
function resolveViewportContainerStyle(viewport, customConfigs, customScale) {
|
|
1806
|
+
const config = resolveViewportDimensions(viewport, customConfigs);
|
|
1807
|
+
const scale = customScale ?? config.scale ?? 1;
|
|
1808
|
+
const toCssVal = (v) => typeof v === "number" ? `${v}px` : v;
|
|
1809
|
+
const style = {
|
|
1810
|
+
width: toCssVal(config.width),
|
|
1811
|
+
maxWidth: toCssVal(config.maxWidth),
|
|
1812
|
+
minWidth: toCssVal(config.minWidth),
|
|
1813
|
+
height: toCssVal(config.height),
|
|
1814
|
+
minHeight: toCssVal(config.minHeight),
|
|
1815
|
+
maxHeight: toCssVal(config.maxHeight),
|
|
1816
|
+
aspectRatio: config.aspectRatio,
|
|
1817
|
+
transition: "width 0.2s ease, max-width 0.2s ease, height 0.2s ease"
|
|
1818
|
+
};
|
|
1819
|
+
if (scale !== 1) {
|
|
1820
|
+
style.transform = `scale(${scale})`;
|
|
1821
|
+
style.transformOrigin = "top center";
|
|
1822
|
+
}
|
|
1823
|
+
return style;
|
|
1824
|
+
}
|
|
1825
|
+
var PreviewViewportAdapter = ({
|
|
1826
|
+
document,
|
|
1827
|
+
viewport = "desktop",
|
|
1828
|
+
onViewportChange,
|
|
1829
|
+
viewportConfigs,
|
|
1830
|
+
breakpoints,
|
|
1831
|
+
registry,
|
|
1832
|
+
context,
|
|
1833
|
+
mode = "runtime",
|
|
1834
|
+
showChrome = false,
|
|
1835
|
+
chromeTitle,
|
|
1836
|
+
editorOverlay,
|
|
1837
|
+
scale,
|
|
1838
|
+
className,
|
|
1839
|
+
style,
|
|
1840
|
+
canvasClassName,
|
|
1841
|
+
canvasStyle,
|
|
1842
|
+
onNodeClick,
|
|
1843
|
+
onDiagnostic,
|
|
1844
|
+
onActionDispatch
|
|
1845
|
+
}) => {
|
|
1846
|
+
const currentConfig = useMemo3(
|
|
1847
|
+
() => resolveViewportDimensions(viewport, viewportConfigs),
|
|
1848
|
+
[viewport, viewportConfigs]
|
|
1849
|
+
);
|
|
1850
|
+
const containerStyle = useMemo3(
|
|
1851
|
+
() => resolveViewportContainerStyle(viewport, viewportConfigs, scale),
|
|
1852
|
+
[viewport, viewportConfigs, scale]
|
|
1853
|
+
);
|
|
1854
|
+
const mergedCanvasStyle = useMemo3(
|
|
1855
|
+
() => ({
|
|
1856
|
+
...containerStyle,
|
|
1857
|
+
...canvasStyle,
|
|
1858
|
+
position: "relative",
|
|
1859
|
+
boxSizing: "border-box"
|
|
1860
|
+
}),
|
|
1861
|
+
[containerStyle, canvasStyle]
|
|
1862
|
+
);
|
|
1863
|
+
return /* @__PURE__ */ jsxs3(
|
|
1864
|
+
"div",
|
|
1865
|
+
{
|
|
1866
|
+
"data-kubuild-preview-container": true,
|
|
1867
|
+
"data-viewport": viewport,
|
|
1868
|
+
className: `kubuild-preview-viewport-adapter ${className || ""}`,
|
|
1869
|
+
style: {
|
|
1870
|
+
display: "flex",
|
|
1871
|
+
flexDirection: "column",
|
|
1872
|
+
alignItems: "center",
|
|
1873
|
+
justifyContent: "flex-start",
|
|
1874
|
+
width: "100%",
|
|
1875
|
+
height: "100%",
|
|
1876
|
+
boxSizing: "border-box",
|
|
1877
|
+
...style
|
|
1878
|
+
},
|
|
1879
|
+
children: [
|
|
1880
|
+
showChrome && /* @__PURE__ */ jsxs3(
|
|
1881
|
+
"div",
|
|
1882
|
+
{
|
|
1883
|
+
"data-kubuild-preview-chrome": true,
|
|
1884
|
+
style: {
|
|
1885
|
+
display: "flex",
|
|
1886
|
+
alignItems: "center",
|
|
1887
|
+
justifyContent: "space-between",
|
|
1888
|
+
width: "100%",
|
|
1889
|
+
maxWidth: containerStyle.maxWidth || containerStyle.width,
|
|
1890
|
+
padding: "8px 12px",
|
|
1891
|
+
marginBottom: "8px",
|
|
1892
|
+
backgroundColor: "#1e293b",
|
|
1893
|
+
color: "#f8fafc",
|
|
1894
|
+
borderRadius: "8px",
|
|
1895
|
+
fontSize: "12px",
|
|
1896
|
+
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
1897
|
+
boxSizing: "border-box"
|
|
1898
|
+
},
|
|
1899
|
+
children: [
|
|
1900
|
+
/* @__PURE__ */ jsxs3("div", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [
|
|
1901
|
+
/* @__PURE__ */ jsx4("span", { style: { fontWeight: 600 }, children: chromeTitle || document.metadata?.title || "Preview" }),
|
|
1902
|
+
/* @__PURE__ */ jsx4(
|
|
1903
|
+
"span",
|
|
1904
|
+
{
|
|
1905
|
+
"data-testid": "viewport-badge",
|
|
1906
|
+
style: {
|
|
1907
|
+
fontSize: "10px",
|
|
1908
|
+
padding: "2px 6px",
|
|
1909
|
+
borderRadius: "4px",
|
|
1910
|
+
backgroundColor: "#334155",
|
|
1911
|
+
color: "#94a3b8",
|
|
1912
|
+
textTransform: "uppercase",
|
|
1913
|
+
fontWeight: 700
|
|
1914
|
+
},
|
|
1915
|
+
children: viewport
|
|
1916
|
+
}
|
|
1917
|
+
),
|
|
1918
|
+
/* @__PURE__ */ jsx4("span", { style: { fontSize: "11px", color: "#64748b" }, children: currentConfig.label || `${currentConfig.width} \xD7 ${currentConfig.height || "auto"}` })
|
|
1919
|
+
] }),
|
|
1920
|
+
onViewportChange && /* @__PURE__ */ jsx4(
|
|
1921
|
+
"div",
|
|
1922
|
+
{
|
|
1923
|
+
"data-testid": "viewport-switcher",
|
|
1924
|
+
style: { display: "flex", gap: "4px", backgroundColor: "#0f172a", padding: "2px", borderRadius: "6px" },
|
|
1925
|
+
children: ["desktop", "tablet", "mobile"].map((device) => {
|
|
1926
|
+
const isActive = viewport === device;
|
|
1927
|
+
return /* @__PURE__ */ jsx4(
|
|
1928
|
+
"button",
|
|
1929
|
+
{
|
|
1930
|
+
type: "button",
|
|
1931
|
+
"data-testid": `viewport-btn-${device}`,
|
|
1932
|
+
onClick: () => onViewportChange(device),
|
|
1933
|
+
style: {
|
|
1934
|
+
padding: "4px 10px",
|
|
1935
|
+
fontSize: "11px",
|
|
1936
|
+
fontWeight: 500,
|
|
1937
|
+
borderRadius: "4px",
|
|
1938
|
+
border: "none",
|
|
1939
|
+
cursor: "pointer",
|
|
1940
|
+
textTransform: "capitalize",
|
|
1941
|
+
backgroundColor: isActive ? "#3b82f6" : "transparent",
|
|
1942
|
+
color: isActive ? "#ffffff" : "#94a3b8",
|
|
1943
|
+
transition: "all 0.15s ease"
|
|
1944
|
+
},
|
|
1945
|
+
children: device
|
|
1946
|
+
},
|
|
1947
|
+
device
|
|
1948
|
+
);
|
|
1949
|
+
})
|
|
1950
|
+
}
|
|
1951
|
+
)
|
|
1952
|
+
]
|
|
1953
|
+
}
|
|
1954
|
+
),
|
|
1955
|
+
/* @__PURE__ */ jsxs3(
|
|
1956
|
+
"div",
|
|
1957
|
+
{
|
|
1958
|
+
"data-kubuild-preview-canvas": true,
|
|
1959
|
+
"data-viewport": viewport,
|
|
1960
|
+
className: `kubuild-preview-canvas ${canvasClassName || ""}`,
|
|
1961
|
+
style: mergedCanvasStyle,
|
|
1962
|
+
children: [
|
|
1963
|
+
/* @__PURE__ */ jsx4(
|
|
1964
|
+
KubuildRenderer,
|
|
1965
|
+
{
|
|
1966
|
+
document,
|
|
1967
|
+
registry,
|
|
1968
|
+
context,
|
|
1969
|
+
viewport,
|
|
1970
|
+
mode,
|
|
1971
|
+
onNodeClick,
|
|
1972
|
+
onDiagnostic,
|
|
1973
|
+
onActionDispatch
|
|
1974
|
+
}
|
|
1975
|
+
),
|
|
1976
|
+
editorOverlay && /* @__PURE__ */ jsx4(
|
|
1977
|
+
"div",
|
|
1978
|
+
{
|
|
1979
|
+
"data-kubuild-preview-overlay": true,
|
|
1980
|
+
style: {
|
|
1981
|
+
position: "absolute",
|
|
1982
|
+
top: 0,
|
|
1983
|
+
left: 0,
|
|
1984
|
+
right: 0,
|
|
1985
|
+
bottom: 0,
|
|
1986
|
+
pointerEvents: "none",
|
|
1987
|
+
zIndex: 10
|
|
1988
|
+
},
|
|
1989
|
+
children: editorOverlay
|
|
1990
|
+
}
|
|
1991
|
+
)
|
|
1992
|
+
]
|
|
1993
|
+
}
|
|
1994
|
+
)
|
|
1995
|
+
]
|
|
1996
|
+
}
|
|
1997
|
+
);
|
|
1998
|
+
};
|
|
1999
|
+
var KubuildPreviewViewport = PreviewViewportAdapter;
|
|
2000
|
+
export {
|
|
2001
|
+
ComponentErrorBoundary,
|
|
2002
|
+
DEFAULT_BREAKPOINTS,
|
|
2003
|
+
DEFAULT_CSS_RESET,
|
|
2004
|
+
DEFAULT_RENDER_CONTEXT,
|
|
2005
|
+
DEFAULT_VIEWPORT_CONFIGS,
|
|
2006
|
+
EditableText,
|
|
2007
|
+
HtmlEmbedView,
|
|
2008
|
+
KubuildPreviewViewport,
|
|
2009
|
+
KubuildRenderer,
|
|
2010
|
+
NodeRenderer,
|
|
2011
|
+
PreviewViewportAdapter,
|
|
2012
|
+
RenderContextProvider,
|
|
2013
|
+
collectStateStylesCss,
|
|
2014
|
+
createMinimalRenderContext,
|
|
2015
|
+
createRenderContext,
|
|
2016
|
+
dispatchAction,
|
|
2017
|
+
isActionRegistered,
|
|
2018
|
+
resolveActionPayload,
|
|
2019
|
+
resolveActionPayloadDetailed,
|
|
2020
|
+
resolveAssetSync,
|
|
2021
|
+
resolveNodeStyles,
|
|
2022
|
+
resolveVariable,
|
|
2023
|
+
resolveViewportContainerStyle,
|
|
2024
|
+
resolveViewportDimensions,
|
|
2025
|
+
resolveViewportFromWidth,
|
|
2026
|
+
styleDefinitionToCssDeclarations,
|
|
2027
|
+
transformEmbedHtml,
|
|
2028
|
+
useRenderContext
|
|
2029
|
+
};
|
|
2030
|
+
//# sourceMappingURL=index.js.map
|