@orion-studios/payload-studio 0.6.0-beta.43 → 0.6.0-beta.44

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.
@@ -0,0 +1,403 @@
1
+ import "../chunk-6BWS3CLP.mjs";
2
+
3
+ // src/builder-v2/payload/builderFields.ts
4
+ var withHiddenAdmin = (field, hidden) => ({
5
+ ...field,
6
+ admin: {
7
+ ...field.admin || {},
8
+ hidden
9
+ }
10
+ });
11
+ var createBuilderV2PageFields = (options = {}) => {
12
+ const hidden = options.hidden ?? true;
13
+ return [
14
+ withHiddenAdmin(
15
+ {
16
+ name: "builderMode",
17
+ type: "select",
18
+ defaultValue: "studio-v1",
19
+ options: [
20
+ { label: "Classic Studio Builder", value: "studio-v1" },
21
+ { label: "Website Builder V2", value: "grapes-v2" }
22
+ ]
23
+ },
24
+ hidden
25
+ ),
26
+ withHiddenAdmin(
27
+ {
28
+ name: "builderProjectData",
29
+ type: "json"
30
+ },
31
+ hidden
32
+ ),
33
+ withHiddenAdmin(
34
+ {
35
+ name: "builderPublishedProjectData",
36
+ type: "json"
37
+ },
38
+ hidden
39
+ ),
40
+ withHiddenAdmin(
41
+ {
42
+ name: "compiledHtml",
43
+ type: "textarea"
44
+ },
45
+ hidden
46
+ ),
47
+ withHiddenAdmin(
48
+ {
49
+ name: "compiledCss",
50
+ type: "textarea"
51
+ },
52
+ hidden
53
+ ),
54
+ withHiddenAdmin(
55
+ {
56
+ name: "builderDynamicComponents",
57
+ type: "json"
58
+ },
59
+ hidden
60
+ ),
61
+ withHiddenAdmin(
62
+ {
63
+ name: "builderValidationIssues",
64
+ type: "json"
65
+ },
66
+ hidden
67
+ )
68
+ ];
69
+ };
70
+ var appendBuilderV2PageFields = (fields, options) => [
71
+ ...fields,
72
+ ...createBuilderV2PageFields(options)
73
+ ];
74
+
75
+ // src/builder-v2/runtime/placeholders.ts
76
+ var placeholderPattern = /<(?<tag>[a-zA-Z][a-zA-Z0-9-]*)\b(?<attrs>[^>]*)data-orion-component=["'](?<component>[^"']+)["'](?<rest>[^>]*)>(?<content>.*?)<\/\k<tag>>/gis;
77
+ var attrPattern = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)=(?:"([^"]*)"|'([^']*)')/g;
78
+ var decodeHtmlAttribute = (value) => value.replace(/&quot;/g, '"').replace(/&#39;/g, "'").replace(/&amp;/g, "&").replace(/&lt;/g, "<").replace(/&gt;/g, ">");
79
+ var parseAttributes = (value) => {
80
+ const props = {};
81
+ let match;
82
+ while ((match = attrPattern.exec(value)) !== null) {
83
+ const name = match[1];
84
+ const rawValue = match[2] ?? match[3] ?? "";
85
+ if (!name.startsWith("data-")) {
86
+ continue;
87
+ }
88
+ if (name === "data-orion-component" || name === "data-orion-id") {
89
+ continue;
90
+ }
91
+ const propName = name.replace(/^data-orion-/, "").replace(/^data-/, "").replace(/-([a-z])/g, (_, char) => char.toUpperCase());
92
+ props[propName] = decodeHtmlAttribute(rawValue);
93
+ }
94
+ return props;
95
+ };
96
+ var extractAttribute = (attrs, name) => {
97
+ const pattern = new RegExp(`${name}=["']([^"']+)["']`, "i");
98
+ const match = attrs.match(pattern);
99
+ return match ? decodeHtmlAttribute(match[1]) : null;
100
+ };
101
+ var parseBuilderV2DynamicComponents = (html) => {
102
+ const instances = [];
103
+ let match;
104
+ while ((match = placeholderPattern.exec(html)) !== null) {
105
+ const attrs = `${match.groups?.attrs ?? ""} ${match.groups?.rest ?? ""}`;
106
+ const component = match.groups?.component ?? "";
107
+ if (!component) {
108
+ continue;
109
+ }
110
+ instances.push({
111
+ component,
112
+ id: extractAttribute(attrs, "data-orion-id") || `component-${instances.length + 1}`,
113
+ props: parseAttributes(attrs)
114
+ });
115
+ }
116
+ return instances;
117
+ };
118
+ var splitBuilderV2HtmlIntoChunks = (html) => {
119
+ const chunks = [];
120
+ let lastIndex = 0;
121
+ let componentIndex = 0;
122
+ let match;
123
+ while ((match = placeholderPattern.exec(html)) !== null) {
124
+ const before = html.slice(lastIndex, match.index);
125
+ if (before.length > 0) {
126
+ chunks.push({ html: before, kind: "html" });
127
+ }
128
+ const attrs = `${match.groups?.attrs ?? ""} ${match.groups?.rest ?? ""}`;
129
+ const component = match.groups?.component ?? "";
130
+ chunks.push({
131
+ instance: {
132
+ component,
133
+ id: extractAttribute(attrs, "data-orion-id") || `component-${componentIndex + 1}`,
134
+ props: parseAttributes(attrs)
135
+ },
136
+ kind: "component"
137
+ });
138
+ componentIndex += 1;
139
+ lastIndex = match.index + match[0].length;
140
+ }
141
+ const after = html.slice(lastIndex);
142
+ if (after.length > 0) {
143
+ chunks.push({ html: after, kind: "html" });
144
+ }
145
+ return chunks;
146
+ };
147
+
148
+ // src/builder-v2/sanitize.ts
149
+ import sanitizeHtml from "sanitize-html";
150
+ var allowedTags = sanitizeHtml.defaults.allowedTags.concat([
151
+ "article",
152
+ "aside",
153
+ "button",
154
+ "figure",
155
+ "figcaption",
156
+ "footer",
157
+ "header",
158
+ "main",
159
+ "nav",
160
+ "section",
161
+ "source",
162
+ "video"
163
+ ]);
164
+ var allowedAttributes = {
165
+ ...sanitizeHtml.defaults.allowedAttributes,
166
+ "*": [
167
+ "aria-*",
168
+ "class",
169
+ "data-*",
170
+ "id",
171
+ "role",
172
+ "style",
173
+ "title"
174
+ ],
175
+ a: ["aria-*", "class", "data-*", "href", "id", "name", "rel", "style", "target", "title"],
176
+ button: ["aria-*", "class", "data-*", "disabled", "id", "style", "title", "type"],
177
+ iframe: ["allow", "allowfullscreen", "class", "data-*", "height", "loading", "src", "style", "title", "width"],
178
+ img: ["alt", "class", "data-*", "height", "id", "loading", "sizes", "src", "srcset", "style", "title", "width"],
179
+ source: ["media", "src", "srcset", "type"],
180
+ video: ["autoplay", "class", "controls", "height", "loop", "muted", "playsinline", "poster", "preload", "src", "style", "width"]
181
+ };
182
+ var allowedIframeHosts = [
183
+ "calendar.google.com",
184
+ "calendly.com",
185
+ "player.vimeo.com",
186
+ "www.youtube.com",
187
+ "youtube.com"
188
+ ];
189
+ var sanitizeBuilderHtml = (value) => {
190
+ if (typeof value !== "string" || value.trim().length === 0) {
191
+ return "";
192
+ }
193
+ return sanitizeHtml(value, {
194
+ allowedAttributes,
195
+ allowedIframeHostnames: allowedIframeHosts,
196
+ allowedSchemes: ["http", "https", "mailto", "tel"],
197
+ allowedSchemesByTag: {
198
+ img: ["http", "https", "data"]
199
+ },
200
+ allowedTags,
201
+ allowProtocolRelative: false,
202
+ parseStyleAttributes: false
203
+ });
204
+ };
205
+ var sanitizeBuilderCss = (value) => {
206
+ if (typeof value !== "string" || value.trim().length === 0) {
207
+ return "";
208
+ }
209
+ return value.replace(/@import\s+[^;]+;/gi, "").replace(/expression\s*\(/gi, "").replace(/javascript\s*:/gi, "");
210
+ };
211
+
212
+ // src/builder-v2/payload/compile.ts
213
+ var compileBuilderV2Output = (input) => {
214
+ const html = sanitizeBuilderHtml(input.html);
215
+ const css = sanitizeBuilderCss(input.css);
216
+ return {
217
+ css,
218
+ dynamicComponents: parseBuilderV2DynamicComponents(html),
219
+ html
220
+ };
221
+ };
222
+
223
+ // src/builder-v2/projectData.ts
224
+ var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
225
+ var createEmptyBuilderV2ProjectData = (title = "Untitled Page") => ({
226
+ assets: [],
227
+ pages: [
228
+ {
229
+ component: {
230
+ components: [
231
+ {
232
+ attributes: {
233
+ class: "orion-builder-v2-section"
234
+ },
235
+ components: [
236
+ {
237
+ content: title,
238
+ tagName: "h1",
239
+ type: "text"
240
+ },
241
+ {
242
+ content: "Start building this page by dragging blocks from the panel.",
243
+ tagName: "p",
244
+ type: "text"
245
+ }
246
+ ],
247
+ tagName: "section"
248
+ }
249
+ ],
250
+ type: "wrapper"
251
+ },
252
+ id: "page",
253
+ name: title
254
+ }
255
+ ],
256
+ styles: []
257
+ });
258
+ var normalizeBuilderV2ProjectData = (value, fallbackTitle = "Untitled Page") => {
259
+ if (!isRecord(value)) {
260
+ return createEmptyBuilderV2ProjectData(fallbackTitle);
261
+ }
262
+ return value;
263
+ };
264
+
265
+ // src/builder-v2/payload/pageService.ts
266
+ var pageTitle = (page) => typeof page.title === "string" && page.title.trim().length > 0 ? page.title : "Untitled Page";
267
+ var toBuilderV2EditorInitialData = (page) => ({
268
+ projectData: normalizeBuilderV2ProjectData(
269
+ page.builderProjectData || page.builderPublishedProjectData,
270
+ pageTitle(page)
271
+ ),
272
+ title: pageTitle(page)
273
+ });
274
+ var createBuilderV2PageService = ({
275
+ collectionSlug = "pages",
276
+ payload,
277
+ user
278
+ }) => ({
279
+ getPageForBuilder: async (pageID) => {
280
+ const page = await payload.findByID({
281
+ collection: collectionSlug,
282
+ depth: 2,
283
+ draft: true,
284
+ id: pageID,
285
+ overrideAccess: false,
286
+ user
287
+ });
288
+ return {
289
+ id: String(page.id),
290
+ initialData: toBuilderV2EditorInitialData(page),
291
+ page
292
+ };
293
+ },
294
+ saveDraft: async (pageID, input) => {
295
+ const compiled = compileBuilderV2Output(input.compiled);
296
+ await payload.update({
297
+ collection: collectionSlug,
298
+ data: {
299
+ _status: "draft",
300
+ builderDynamicComponents: compiled.dynamicComponents,
301
+ builderMode: "grapes-v2",
302
+ builderProjectData: input.projectData,
303
+ builderValidationIssues: input.validationIssues || [],
304
+ compiledCss: compiled.css,
305
+ compiledHtml: compiled.html,
306
+ ...input.title ? { title: input.title } : {}
307
+ },
308
+ id: pageID,
309
+ overrideAccess: false,
310
+ user
311
+ });
312
+ return {
313
+ compiled,
314
+ id: pageID,
315
+ status: "draft"
316
+ };
317
+ },
318
+ publish: async (pageID, input) => {
319
+ const compiled = compileBuilderV2Output(input.compiled);
320
+ await payload.update({
321
+ collection: collectionSlug,
322
+ data: {
323
+ _status: "published",
324
+ builderDynamicComponents: compiled.dynamicComponents,
325
+ builderMode: "grapes-v2",
326
+ builderProjectData: input.projectData,
327
+ builderPublishedProjectData: input.projectData,
328
+ builderValidationIssues: input.validationIssues || [],
329
+ compiledCss: compiled.css,
330
+ compiledHtml: compiled.html,
331
+ ...input.title ? { title: input.title } : {}
332
+ },
333
+ id: pageID,
334
+ overrideAccess: false,
335
+ user
336
+ });
337
+ return {
338
+ compiled,
339
+ id: pageID,
340
+ status: "published"
341
+ };
342
+ }
343
+ });
344
+
345
+ // src/builder-v2/runtime/BuilderPageRuntime.tsx
346
+ import { createElement, Fragment } from "react";
347
+ import { jsx, jsxs } from "react/jsx-runtime";
348
+ var resolveRuntimeComponent = (adapter, type) => {
349
+ const definition = adapter?.components?.[type];
350
+ if (!definition) {
351
+ return null;
352
+ }
353
+ if (typeof definition === "function") {
354
+ return definition;
355
+ }
356
+ return definition.render;
357
+ };
358
+ function BuilderPageRuntime({ adapter, className, page }) {
359
+ const html = sanitizeBuilderHtml(page.compiledHtml);
360
+ const css = sanitizeBuilderCss(page.compiledCss);
361
+ const chunks = splitBuilderV2HtmlIntoChunks(html);
362
+ return /* @__PURE__ */ jsxs("div", { className: ["orion-builder-v2-runtime", className].filter(Boolean).join(" "), children: [
363
+ css ? /* @__PURE__ */ jsx("style", { dangerouslySetInnerHTML: { __html: css } }) : null,
364
+ chunks.map((chunk, index) => {
365
+ if (chunk.kind === "html") {
366
+ return /* @__PURE__ */ jsx(
367
+ "div",
368
+ {
369
+ className: "orion-builder-v2-html-chunk",
370
+ dangerouslySetInnerHTML: { __html: chunk.html }
371
+ },
372
+ `html-${index}`
373
+ );
374
+ }
375
+ const Component = resolveRuntimeComponent(adapter, chunk.instance.component);
376
+ if (!Component) {
377
+ return /* @__PURE__ */ jsx(
378
+ "div",
379
+ {
380
+ className: "orion-builder-v2-missing-component",
381
+ "data-orion-missing-component": chunk.instance.component
382
+ },
383
+ `component-${chunk.instance.id}-${index}`
384
+ );
385
+ }
386
+ return createElement(Fragment, { key: `component-${chunk.instance.id}-${index}` }, /* @__PURE__ */ jsx(Component, { instance: chunk.instance, page }));
387
+ })
388
+ ] });
389
+ }
390
+ export {
391
+ BuilderPageRuntime,
392
+ appendBuilderV2PageFields,
393
+ compileBuilderV2Output,
394
+ createBuilderV2PageFields,
395
+ createBuilderV2PageService,
396
+ createEmptyBuilderV2ProjectData,
397
+ normalizeBuilderV2ProjectData,
398
+ parseBuilderV2DynamicComponents,
399
+ sanitizeBuilderCss,
400
+ sanitizeBuilderHtml,
401
+ splitBuilderV2HtmlIntoChunks,
402
+ toBuilderV2EditorInitialData
403
+ };
@@ -0,0 +1,165 @@
1
+ @import 'grapesjs/dist/css/grapes.min.css';
2
+
3
+ .orion-builder-v2-editor {
4
+ background: #f4f6f8;
5
+ color: #172033;
6
+ display: grid;
7
+ grid-template-columns: minmax(260px, 310px) 1fr;
8
+ height: 100dvh;
9
+ min-height: 640px;
10
+ }
11
+
12
+ .orion-builder-v2-sidebar {
13
+ background: #ffffff;
14
+ border-right: 1px solid rgba(23, 32, 51, 0.12);
15
+ display: grid;
16
+ gap: 12px;
17
+ overflow: auto;
18
+ padding: 12px;
19
+ }
20
+
21
+ .orion-builder-v2-panel {
22
+ display: grid;
23
+ gap: 10px;
24
+ }
25
+
26
+ .orion-builder-v2-panel h2 {
27
+ font-size: 0.8rem;
28
+ letter-spacing: 0;
29
+ margin: 0;
30
+ text-transform: uppercase;
31
+ }
32
+
33
+ .orion-builder-v2-main {
34
+ min-width: 0;
35
+ position: relative;
36
+ }
37
+
38
+ .orion-builder-v2-canvas {
39
+ height: 100%;
40
+ }
41
+
42
+ .orion-builder-v2-status,
43
+ .orion-builder-v2-error {
44
+ border-radius: 8px;
45
+ font-weight: 800;
46
+ left: 16px;
47
+ padding: 10px 12px;
48
+ position: absolute;
49
+ top: 16px;
50
+ z-index: 10;
51
+ }
52
+
53
+ .orion-builder-v2-status {
54
+ background: #ffffff;
55
+ border: 1px solid rgba(23, 32, 51, 0.12);
56
+ }
57
+
58
+ .orion-builder-v2-error {
59
+ background: #fff1f2;
60
+ border: 1px solid #fecdd3;
61
+ color: #9f1239;
62
+ }
63
+
64
+ .orion-builder-v2-runtime {
65
+ width: 100%;
66
+ }
67
+
68
+ .orion-builder-v2-html-chunk {
69
+ display: contents;
70
+ }
71
+
72
+ .orion-builder-v2-missing-component {
73
+ display: none;
74
+ }
75
+
76
+ .orion-builder-v2-section,
77
+ .orion-builder-v2-hero {
78
+ padding: 64px 24px;
79
+ }
80
+
81
+ .orion-builder-v2-hero {
82
+ background: #172033;
83
+ color: #ffffff;
84
+ }
85
+
86
+ .orion-builder-v2-container {
87
+ margin: 0 auto;
88
+ max-width: 1120px;
89
+ }
90
+
91
+ .orion-builder-v2-grid {
92
+ display: grid;
93
+ gap: 20px;
94
+ }
95
+
96
+ .orion-builder-v2-grid.is-3 {
97
+ grid-template-columns: repeat(3, minmax(0, 1fr));
98
+ }
99
+
100
+ .orion-builder-v2-card {
101
+ background: #ffffff;
102
+ border: 1px solid rgba(23, 32, 51, 0.12);
103
+ border-radius: 8px;
104
+ color: #172033;
105
+ padding: 20px;
106
+ }
107
+
108
+ .orion-builder-v2-button {
109
+ background: #172033;
110
+ border-radius: 8px;
111
+ color: #ffffff;
112
+ display: inline-flex;
113
+ font-weight: 800;
114
+ padding: 10px 16px;
115
+ text-decoration: none;
116
+ }
117
+
118
+ .orion-builder-v2-hero .orion-builder-v2-button {
119
+ background: #ffffff;
120
+ color: #172033;
121
+ }
122
+
123
+ .orion-builder-v2-kicker {
124
+ font-size: 0.85rem;
125
+ font-weight: 900;
126
+ text-transform: uppercase;
127
+ }
128
+
129
+ .orion-builder-v2-image {
130
+ display: block;
131
+ height: auto;
132
+ max-width: 100%;
133
+ }
134
+
135
+ .orion-builder-v2-dynamic-placeholder {
136
+ align-items: center;
137
+ background: repeating-linear-gradient(
138
+ 45deg,
139
+ rgba(23, 32, 51, 0.06),
140
+ rgba(23, 32, 51, 0.06) 8px,
141
+ rgba(23, 32, 51, 0.11) 8px,
142
+ rgba(23, 32, 51, 0.11) 16px
143
+ );
144
+ border: 1px dashed rgba(23, 32, 51, 0.35);
145
+ border-radius: 8px;
146
+ display: flex;
147
+ gap: 8px;
148
+ min-height: 96px;
149
+ padding: 20px;
150
+ }
151
+
152
+ @media (max-width: 800px) {
153
+ .orion-builder-v2-editor {
154
+ grid-template-columns: 1fr;
155
+ grid-template-rows: auto 1fr;
156
+ }
157
+
158
+ .orion-builder-v2-sidebar {
159
+ max-height: 260px;
160
+ }
161
+
162
+ .orion-builder-v2-grid.is-3 {
163
+ grid-template-columns: 1fr;
164
+ }
165
+ }