@orion-studios/payload-studio 0.6.0-beta.45 → 0.6.0-beta.47
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/builder-v2/client.d.mts +5 -0
- package/dist/builder-v2/client.d.ts +5 -0
- package/dist/builder-v2/client.js +382 -24
- package/dist/builder-v2/client.mjs +382 -24
- package/dist/builder-v2/index.d.mts +81 -1
- package/dist/builder-v2/index.d.ts +81 -1
- package/dist/builder-v2/index.js +281 -7
- package/dist/builder-v2/index.mjs +276 -6
- package/dist/builder-v2/styles.css +625 -10
- package/package.json +1 -1
|
@@ -30,6 +30,13 @@ var createBuilderV2PageFields = (options = {}) => {
|
|
|
30
30
|
},
|
|
31
31
|
hidden
|
|
32
32
|
),
|
|
33
|
+
withHiddenAdmin(
|
|
34
|
+
{
|
|
35
|
+
name: "builderAutosaveProjectData",
|
|
36
|
+
type: "json"
|
|
37
|
+
},
|
|
38
|
+
hidden
|
|
39
|
+
),
|
|
33
40
|
withHiddenAdmin(
|
|
34
41
|
{
|
|
35
42
|
name: "builderPublishedProjectData",
|
|
@@ -64,6 +71,62 @@ var createBuilderV2PageFields = (options = {}) => {
|
|
|
64
71
|
type: "json"
|
|
65
72
|
},
|
|
66
73
|
hidden
|
|
74
|
+
),
|
|
75
|
+
withHiddenAdmin(
|
|
76
|
+
{
|
|
77
|
+
name: "builderVersions",
|
|
78
|
+
type: "json"
|
|
79
|
+
},
|
|
80
|
+
hidden
|
|
81
|
+
),
|
|
82
|
+
withHiddenAdmin(
|
|
83
|
+
{
|
|
84
|
+
name: "builderPublishedSnapshot",
|
|
85
|
+
type: "json"
|
|
86
|
+
},
|
|
87
|
+
hidden
|
|
88
|
+
),
|
|
89
|
+
withHiddenAdmin(
|
|
90
|
+
{
|
|
91
|
+
name: "builderReusableSections",
|
|
92
|
+
type: "json"
|
|
93
|
+
},
|
|
94
|
+
hidden
|
|
95
|
+
),
|
|
96
|
+
withHiddenAdmin(
|
|
97
|
+
{
|
|
98
|
+
name: "builderThemeTokens",
|
|
99
|
+
type: "json"
|
|
100
|
+
},
|
|
101
|
+
hidden
|
|
102
|
+
),
|
|
103
|
+
withHiddenAdmin(
|
|
104
|
+
{
|
|
105
|
+
name: "builderLockedAreas",
|
|
106
|
+
type: "json"
|
|
107
|
+
},
|
|
108
|
+
hidden
|
|
109
|
+
),
|
|
110
|
+
withHiddenAdmin(
|
|
111
|
+
{
|
|
112
|
+
name: "builderSeo",
|
|
113
|
+
type: "json"
|
|
114
|
+
},
|
|
115
|
+
hidden
|
|
116
|
+
),
|
|
117
|
+
withHiddenAdmin(
|
|
118
|
+
{
|
|
119
|
+
name: "builderLastSavedAt",
|
|
120
|
+
type: "date"
|
|
121
|
+
},
|
|
122
|
+
hidden
|
|
123
|
+
),
|
|
124
|
+
withHiddenAdmin(
|
|
125
|
+
{
|
|
126
|
+
name: "builderLastPublishedAt",
|
|
127
|
+
type: "date"
|
|
128
|
+
},
|
|
129
|
+
hidden
|
|
67
130
|
)
|
|
68
131
|
];
|
|
69
132
|
};
|
|
@@ -183,6 +246,7 @@ var allowedIframeHosts = [
|
|
|
183
246
|
"calendar.google.com",
|
|
184
247
|
"calendly.com",
|
|
185
248
|
"player.vimeo.com",
|
|
249
|
+
"www.google.com",
|
|
186
250
|
"www.youtube.com",
|
|
187
251
|
"youtube.com"
|
|
188
252
|
];
|
|
@@ -208,15 +272,119 @@ var sanitizeBuilderCss = (value) => {
|
|
|
208
272
|
}
|
|
209
273
|
return value.replace(/@import\s+[^;]+;/gi, "").replace(/expression\s*\(/gi, "").replace(/javascript\s*:/gi, "");
|
|
210
274
|
};
|
|
275
|
+
var scopeSelector = (selector, scope) => selector.split(",").map((part) => {
|
|
276
|
+
const trimmed = part.trim();
|
|
277
|
+
if (!trimmed || trimmed.startsWith(scope) || trimmed.startsWith("@")) {
|
|
278
|
+
return trimmed;
|
|
279
|
+
}
|
|
280
|
+
if (/^(html|body|:root)\b/i.test(trimmed)) {
|
|
281
|
+
return trimmed.replace(/^(html|body|:root)\b/i, scope);
|
|
282
|
+
}
|
|
283
|
+
return `${scope} ${trimmed}`;
|
|
284
|
+
}).filter(Boolean).join(", ");
|
|
285
|
+
var scopeBuilderCss = (value, scope = ".orion-builder-v2-runtime") => {
|
|
286
|
+
const css = sanitizeBuilderCss(value);
|
|
287
|
+
if (!css) {
|
|
288
|
+
return "";
|
|
289
|
+
}
|
|
290
|
+
let output = "";
|
|
291
|
+
let cursor = 0;
|
|
292
|
+
const rulePattern = /([^{}]+)\{/g;
|
|
293
|
+
let match;
|
|
294
|
+
while ((match = rulePattern.exec(css)) !== null) {
|
|
295
|
+
const selectorStart = match.index;
|
|
296
|
+
const selector = match[1];
|
|
297
|
+
output += css.slice(cursor, selectorStart);
|
|
298
|
+
const trimmedSelector = selector.trim();
|
|
299
|
+
if (trimmedSelector.startsWith("@keyframes") || trimmedSelector.startsWith("@font-face") || trimmedSelector.startsWith("@page")) {
|
|
300
|
+
output += `${selector}{`;
|
|
301
|
+
} else if (trimmedSelector.startsWith("@media") || trimmedSelector.startsWith("@supports")) {
|
|
302
|
+
output += `${selector}{`;
|
|
303
|
+
} else {
|
|
304
|
+
output += `${scopeSelector(selector, scope)} {`;
|
|
305
|
+
}
|
|
306
|
+
cursor = rulePattern.lastIndex;
|
|
307
|
+
}
|
|
308
|
+
output += css.slice(cursor);
|
|
309
|
+
return output;
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// src/builder-v2/validation.ts
|
|
313
|
+
var hasMatch = (value, pattern) => pattern.test(value);
|
|
314
|
+
var validateBuilderV2Output = (input) => {
|
|
315
|
+
const html = typeof input.html === "string" ? input.html : "";
|
|
316
|
+
const css = typeof input.css === "string" ? input.css : "";
|
|
317
|
+
const issues = [];
|
|
318
|
+
if (!html.trim()) {
|
|
319
|
+
issues.push({
|
|
320
|
+
code: "empty-page",
|
|
321
|
+
message: "This page has no rendered content.",
|
|
322
|
+
path: "compiledHtml",
|
|
323
|
+
severity: "error"
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
if (!hasMatch(html, /<h1\b/i)) {
|
|
327
|
+
issues.push({
|
|
328
|
+
code: "missing-h1",
|
|
329
|
+
message: "Add one H1 so the published page has a clear primary heading.",
|
|
330
|
+
path: "compiledHtml",
|
|
331
|
+
severity: "warning"
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
if (hasMatch(html, /\son[a-z]+\s*=/i)) {
|
|
335
|
+
issues.push({
|
|
336
|
+
code: "inline-event-handler",
|
|
337
|
+
message: "Inline event handlers are not allowed in published builder HTML.",
|
|
338
|
+
path: "compiledHtml",
|
|
339
|
+
severity: "error"
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
if (hasMatch(html, /<(script|object|embed)\b/i)) {
|
|
343
|
+
issues.push({
|
|
344
|
+
code: "unsafe-element",
|
|
345
|
+
message: "Script, object, and embed tags are not allowed in builder content.",
|
|
346
|
+
path: "compiledHtml",
|
|
347
|
+
severity: "error"
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
if (hasMatch(html, /\b(?:href|src)=["']\s*javascript:/i)) {
|
|
351
|
+
issues.push({
|
|
352
|
+
code: "unsafe-url",
|
|
353
|
+
message: "Links and media cannot use javascript URLs.",
|
|
354
|
+
path: "compiledHtml",
|
|
355
|
+
severity: "error"
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
if (hasMatch(css, /@import\s/i)) {
|
|
359
|
+
issues.push({
|
|
360
|
+
code: "css-import",
|
|
361
|
+
message: "CSS imports are removed at publish time. Use the site font and theme managers instead.",
|
|
362
|
+
path: "compiledCss",
|
|
363
|
+
severity: "warning"
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
if (hasMatch(css, /position\s*:\s*fixed/i)) {
|
|
367
|
+
issues.push({
|
|
368
|
+
code: "fixed-position",
|
|
369
|
+
message: "Fixed positioning can cover site navigation or dialogs. Review this before publishing.",
|
|
370
|
+
path: "compiledCss",
|
|
371
|
+
severity: "warning"
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
return issues;
|
|
375
|
+
};
|
|
376
|
+
var hasBlockingBuilderV2Issues = (issues) => issues.some((issue) => issue.severity === "error");
|
|
211
377
|
|
|
212
378
|
// src/builder-v2/payload/compile.ts
|
|
213
379
|
var compileBuilderV2Output = (input) => {
|
|
214
380
|
const html = sanitizeBuilderHtml(input.html);
|
|
215
|
-
const css =
|
|
381
|
+
const css = scopeBuilderCss(input.css);
|
|
382
|
+
const validationIssues = validateBuilderV2Output({ css: input.css, html: input.html });
|
|
216
383
|
return {
|
|
217
384
|
css,
|
|
218
385
|
dynamicComponents: parseBuilderV2DynamicComponents(html),
|
|
219
|
-
html
|
|
386
|
+
html,
|
|
387
|
+
validationIssues
|
|
220
388
|
};
|
|
221
389
|
};
|
|
222
390
|
|
|
@@ -264,6 +432,25 @@ var normalizeBuilderV2ProjectData = (value, fallbackTitle = "Untitled Page") =>
|
|
|
264
432
|
|
|
265
433
|
// src/builder-v2/payload/pageService.ts
|
|
266
434
|
var pageTitle = (page) => typeof page.title === "string" && page.title.trim().length > 0 ? page.title : "Untitled Page";
|
|
435
|
+
var normalizeVersions = (value) => Array.isArray(value) ? value.filter((item) => Boolean(item && typeof item === "object")) : [];
|
|
436
|
+
var createVersionSnapshot = ({
|
|
437
|
+
compiled,
|
|
438
|
+
label,
|
|
439
|
+
projectData,
|
|
440
|
+
published = false
|
|
441
|
+
}) => {
|
|
442
|
+
const createdAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
443
|
+
return {
|
|
444
|
+
compiledCss: compiled.css,
|
|
445
|
+
compiledHtml: compiled.html,
|
|
446
|
+
createdAt,
|
|
447
|
+
id: `builder-v2-${createdAt.replace(/[^0-9]/g, "")}`,
|
|
448
|
+
label,
|
|
449
|
+
projectData,
|
|
450
|
+
published
|
|
451
|
+
};
|
|
452
|
+
};
|
|
453
|
+
var appendVersionSnapshot = (current, snapshot) => [snapshot, ...normalizeVersions(current)].slice(0, 50);
|
|
267
454
|
var toBuilderV2EditorInitialData = (page) => ({
|
|
268
455
|
projectData: normalizeBuilderV2ProjectData(
|
|
269
456
|
page.builderProjectData || page.builderPublishedProjectData,
|
|
@@ -293,14 +480,33 @@ var createBuilderV2PageService = ({
|
|
|
293
480
|
},
|
|
294
481
|
saveDraft: async (pageID, input) => {
|
|
295
482
|
const compiled = compileBuilderV2Output(input.compiled);
|
|
483
|
+
const existing = await payload.findByID({
|
|
484
|
+
collection: collectionSlug,
|
|
485
|
+
depth: 0,
|
|
486
|
+
draft: true,
|
|
487
|
+
id: pageID,
|
|
488
|
+
overrideAccess: false,
|
|
489
|
+
user
|
|
490
|
+
});
|
|
491
|
+
const validationIssues = input.validationIssues || compiled.validationIssues || [];
|
|
296
492
|
await payload.update({
|
|
297
493
|
collection: collectionSlug,
|
|
298
494
|
data: {
|
|
299
495
|
_status: "draft",
|
|
496
|
+
builderAutosaveProjectData: null,
|
|
300
497
|
builderDynamicComponents: compiled.dynamicComponents,
|
|
498
|
+
builderLastSavedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
301
499
|
builderMode: "grapes-v2",
|
|
302
500
|
builderProjectData: input.projectData,
|
|
303
|
-
builderValidationIssues:
|
|
501
|
+
builderValidationIssues: validationIssues,
|
|
502
|
+
builderVersions: appendVersionSnapshot(
|
|
503
|
+
existing.builderVersions,
|
|
504
|
+
createVersionSnapshot({
|
|
505
|
+
compiled,
|
|
506
|
+
label: "Draft saved",
|
|
507
|
+
projectData: input.projectData
|
|
508
|
+
})
|
|
509
|
+
),
|
|
304
510
|
compiledCss: compiled.css,
|
|
305
511
|
compiledHtml: compiled.html,
|
|
306
512
|
...input.title ? { title: input.title } : {}
|
|
@@ -317,15 +523,35 @@ var createBuilderV2PageService = ({
|
|
|
317
523
|
},
|
|
318
524
|
publish: async (pageID, input) => {
|
|
319
525
|
const compiled = compileBuilderV2Output(input.compiled);
|
|
526
|
+
const existing = await payload.findByID({
|
|
527
|
+
collection: collectionSlug,
|
|
528
|
+
depth: 0,
|
|
529
|
+
draft: true,
|
|
530
|
+
id: pageID,
|
|
531
|
+
overrideAccess: false,
|
|
532
|
+
user
|
|
533
|
+
});
|
|
534
|
+
const validationIssues = input.validationIssues || compiled.validationIssues || [];
|
|
535
|
+
const snapshot = createVersionSnapshot({
|
|
536
|
+
compiled,
|
|
537
|
+
label: "Published",
|
|
538
|
+
projectData: input.projectData,
|
|
539
|
+
published: true
|
|
540
|
+
});
|
|
320
541
|
await payload.update({
|
|
321
542
|
collection: collectionSlug,
|
|
322
543
|
data: {
|
|
323
544
|
_status: "published",
|
|
545
|
+
builderAutosaveProjectData: null,
|
|
324
546
|
builderDynamicComponents: compiled.dynamicComponents,
|
|
547
|
+
builderLastPublishedAt: snapshot.createdAt,
|
|
548
|
+
builderLastSavedAt: snapshot.createdAt,
|
|
325
549
|
builderMode: "grapes-v2",
|
|
326
550
|
builderProjectData: input.projectData,
|
|
327
551
|
builderPublishedProjectData: input.projectData,
|
|
328
|
-
|
|
552
|
+
builderPublishedSnapshot: snapshot,
|
|
553
|
+
builderValidationIssues: validationIssues,
|
|
554
|
+
builderVersions: appendVersionSnapshot(existing.builderVersions, snapshot),
|
|
329
555
|
compiledCss: compiled.css,
|
|
330
556
|
compiledHtml: compiled.html,
|
|
331
557
|
...input.title ? { title: input.title } : {}
|
|
@@ -342,6 +568,46 @@ var createBuilderV2PageService = ({
|
|
|
342
568
|
}
|
|
343
569
|
});
|
|
344
570
|
|
|
571
|
+
// src/builder-v2/pageTree.ts
|
|
572
|
+
var relationId = (value) => {
|
|
573
|
+
if (typeof value === "number" || typeof value === "string") {
|
|
574
|
+
return value;
|
|
575
|
+
}
|
|
576
|
+
if (value && typeof value === "object") {
|
|
577
|
+
const id = value.id;
|
|
578
|
+
return typeof id === "number" || typeof id === "string" ? id : null;
|
|
579
|
+
}
|
|
580
|
+
return null;
|
|
581
|
+
};
|
|
582
|
+
var buildBuilderV2PageTree = (pages) => {
|
|
583
|
+
const nodes = /* @__PURE__ */ new Map();
|
|
584
|
+
const roots = [];
|
|
585
|
+
pages.forEach((page) => {
|
|
586
|
+
nodes.set(page.id, {
|
|
587
|
+
children: [],
|
|
588
|
+
id: page.id,
|
|
589
|
+
parentId: page.parentId ?? relationId(page.parent),
|
|
590
|
+
path: page.path || (page.slug ? `/${page.slug}` : "/"),
|
|
591
|
+
slug: page.slug || "",
|
|
592
|
+
status: page._status,
|
|
593
|
+
title: page.title || "Untitled page"
|
|
594
|
+
});
|
|
595
|
+
});
|
|
596
|
+
nodes.forEach((node) => {
|
|
597
|
+
if (node.parentId && nodes.has(node.parentId)) {
|
|
598
|
+
nodes.get(node.parentId)?.children?.push(node);
|
|
599
|
+
} else {
|
|
600
|
+
roots.push(node);
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
const sortNodes = (items) => {
|
|
604
|
+
items.sort((a, b) => a.path.localeCompare(b.path));
|
|
605
|
+
items.forEach((item) => sortNodes(item.children || []));
|
|
606
|
+
};
|
|
607
|
+
sortNodes(roots);
|
|
608
|
+
return roots;
|
|
609
|
+
};
|
|
610
|
+
|
|
345
611
|
// src/builder-v2/runtime/BuilderPageRuntime.tsx
|
|
346
612
|
import { createElement, Fragment } from "react";
|
|
347
613
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -357,7 +623,7 @@ var resolveRuntimeComponent = (adapter, type) => {
|
|
|
357
623
|
};
|
|
358
624
|
function BuilderPageRuntime({ adapter, className, page }) {
|
|
359
625
|
const html = sanitizeBuilderHtml(page.compiledHtml);
|
|
360
|
-
const css =
|
|
626
|
+
const css = scopeBuilderCss(page.compiledCss);
|
|
361
627
|
const chunks = splitBuilderV2HtmlIntoChunks(html);
|
|
362
628
|
return /* @__PURE__ */ jsxs("div", { className: ["orion-builder-v2-runtime", className].filter(Boolean).join(" "), children: [
|
|
363
629
|
css ? /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: css } }) : null,
|
|
@@ -390,14 +656,18 @@ function BuilderPageRuntime({ adapter, className, page }) {
|
|
|
390
656
|
export {
|
|
391
657
|
BuilderPageRuntime,
|
|
392
658
|
appendBuilderV2PageFields,
|
|
659
|
+
buildBuilderV2PageTree,
|
|
393
660
|
compileBuilderV2Output,
|
|
394
661
|
createBuilderV2PageFields,
|
|
395
662
|
createBuilderV2PageService,
|
|
396
663
|
createEmptyBuilderV2ProjectData,
|
|
664
|
+
hasBlockingBuilderV2Issues,
|
|
397
665
|
normalizeBuilderV2ProjectData,
|
|
398
666
|
parseBuilderV2DynamicComponents,
|
|
399
667
|
sanitizeBuilderCss,
|
|
400
668
|
sanitizeBuilderHtml,
|
|
669
|
+
scopeBuilderCss,
|
|
401
670
|
splitBuilderV2HtmlIntoChunks,
|
|
402
|
-
toBuilderV2EditorInitialData
|
|
671
|
+
toBuilderV2EditorInitialData,
|
|
672
|
+
validateBuilderV2Output
|
|
403
673
|
};
|