@unlayer/react-elements 0.1.21 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +65 -3
- package/dist/index.cjs +1416 -492
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +71 -11
- package/dist/index.d.ts +71 -11
- package/dist/index.js +1396 -492
- package/dist/index.js.map +1 -1
- package/package.json +11 -5
package/dist/index.cjs
CHANGED
|
@@ -1,16 +1,375 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var exporters = require('@unlayer/exporters');
|
|
4
|
+
var React4 = require('react');
|
|
5
|
+
var defaultBuild = require('react-dom/server');
|
|
4
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
-
var React = require('react');
|
|
6
|
-
var ReactDOMServer = require('react-dom/server');
|
|
7
7
|
|
|
8
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
function _interopNamespace(e) {
|
|
11
|
+
if (e && e.__esModule) return e;
|
|
12
|
+
var n = Object.create(null);
|
|
13
|
+
if (e) {
|
|
14
|
+
Object.keys(e).forEach(function (k) {
|
|
15
|
+
if (k !== 'default') {
|
|
16
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
17
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
get: function () { return e[k]; }
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
n.default = e;
|
|
25
|
+
return Object.freeze(n);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var React4__default = /*#__PURE__*/_interopDefault(React4);
|
|
29
|
+
var defaultBuild__namespace = /*#__PURE__*/_interopNamespace(defaultBuild);
|
|
12
30
|
|
|
13
31
|
// src/components/Button.tsx
|
|
32
|
+
var SHARED = Symbol.for("@unlayer/react-elements/collecting");
|
|
33
|
+
var frames = globalThis[SHARED] ?? (globalThis[SHARED] = []);
|
|
34
|
+
function collecting() {
|
|
35
|
+
return frames[frames.length - 1] ?? void 0;
|
|
36
|
+
}
|
|
37
|
+
function within(frame, run) {
|
|
38
|
+
frames.push(frame);
|
|
39
|
+
try {
|
|
40
|
+
return run();
|
|
41
|
+
} finally {
|
|
42
|
+
frames.pop();
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
var MARK = "unlayer-mark";
|
|
46
|
+
var RECORDS = Symbol.for("@unlayer/react-elements/records");
|
|
47
|
+
var COLLECTING_ID = "unlayer-collect-";
|
|
48
|
+
function marker(collection, at, edge) {
|
|
49
|
+
return React4__default.default.createElement(MARK, { key: `${at}${edge ?? ""}`, "data-n": collection.nonce, "data-i": at, ...edge ? { "data-e": edge } : {} });
|
|
50
|
+
}
|
|
51
|
+
var SHARED2 = Symbol.for("@unlayer/react-elements/render-builds");
|
|
52
|
+
var using = globalThis[SHARED2] ?? (globalThis[SHARED2] = []);
|
|
53
|
+
var same = (a, b) => a.renderToString === b.renderToString;
|
|
54
|
+
function dispatcher() {
|
|
55
|
+
const internals = React4__default.default;
|
|
56
|
+
return internals.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE?.H ?? internals.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?.ReactCurrentDispatcher?.current ?? null;
|
|
57
|
+
}
|
|
58
|
+
var dispatchers = /* @__PURE__ */ new Map();
|
|
59
|
+
function dispatcherOf(build) {
|
|
60
|
+
if (!dispatchers.has(build)) {
|
|
61
|
+
let seen = null;
|
|
62
|
+
try {
|
|
63
|
+
class Probe extends React4__default.default.Component {
|
|
64
|
+
render() {
|
|
65
|
+
seen = dispatcher();
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
build.renderToStaticMarkup(React4__default.default.createElement(Probe));
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
dispatchers.set(build, seen);
|
|
73
|
+
}
|
|
74
|
+
return dispatchers.get(build);
|
|
75
|
+
}
|
|
76
|
+
var second;
|
|
77
|
+
function secondBuild(outer) {
|
|
78
|
+
if (second === void 0) {
|
|
79
|
+
second = null;
|
|
80
|
+
const node = globalThis.process;
|
|
81
|
+
const requirers = [
|
|
82
|
+
// (`module`'s, read so that a bundler doesn't take it for a require of a path worked out when it runs.)
|
|
83
|
+
() => {
|
|
84
|
+
const own = typeof module === "object" ? Reflect.get(module ?? {}, "require") : void 0;
|
|
85
|
+
return typeof own === "function" ? (id) => own.call(module, id) : void 0;
|
|
86
|
+
},
|
|
87
|
+
// From this module's URL (as a stack names it: webpack 4 can't parse the syntax for it), the app's script, then
|
|
88
|
+
// the folder Node started in; only where `react` is this React. Another React's isn't loaded (React 19's browser
|
|
89
|
+
// build keeps Node running).
|
|
90
|
+
...[/file:\/\/\S+?(?=:\d+:\d+)/.exec(String(new Error().stack))?.[0], node?.argv?.[1], `${node?.cwd?.()}/`].map((from) => () => {
|
|
91
|
+
const required = node?.getBuiltinModule?.("module")?.createRequire(from);
|
|
92
|
+
return required?.("react")?.createElement === React4__default.default.createElement ? required : void 0;
|
|
93
|
+
})
|
|
94
|
+
];
|
|
95
|
+
const ids = ["react-dom/server.bun", ...Number.parseInt(React4__default.default.version) >= 19 ? [] : ["react-dom/server.browser"], "react-dom/server.node"];
|
|
96
|
+
search: for (const id of ids) {
|
|
97
|
+
for (const requirer of requirers) {
|
|
98
|
+
try {
|
|
99
|
+
const build = requirer()?.(id);
|
|
100
|
+
if (build?.renderToStaticMarkup && !same(build, defaultBuild__namespace) && ![null, outer].includes(dispatcherOf(build))) {
|
|
101
|
+
second = build;
|
|
102
|
+
break search;
|
|
103
|
+
}
|
|
104
|
+
} catch {
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return second ?? void 0;
|
|
110
|
+
}
|
|
111
|
+
var buildOf = (outer) => outer === null ? void 0 : [defaultBuild__namespace, second].find((b) => !!b && dispatcherOf(b) === outer);
|
|
112
|
+
function withBuild(render, own = false) {
|
|
113
|
+
const outer = own ? null : dispatcher();
|
|
114
|
+
let build = current();
|
|
115
|
+
const theirs = !own && (using.length === 0 || collecting() !== void 0) ? buildOf(outer) : void 0;
|
|
116
|
+
const busy = [];
|
|
117
|
+
if (theirs) {
|
|
118
|
+
const free = (b) => !same(b, theirs) && !using.some((u) => same(u, b));
|
|
119
|
+
const other = free(defaultBuild__namespace) ? defaultBuild__namespace : secondBuild(outer);
|
|
120
|
+
if (other && free(other)) {
|
|
121
|
+
busy.push(theirs);
|
|
122
|
+
build = other;
|
|
123
|
+
} else build = theirs;
|
|
124
|
+
}
|
|
125
|
+
using.push(...busy, build);
|
|
126
|
+
try {
|
|
127
|
+
return render();
|
|
128
|
+
} catch (error) {
|
|
129
|
+
if (build !== theirs && !rendersHere(build)) throw Object.assign(new Error("[Unlayer] react-dom can't render with this React (React Server Components', as in Next.js's edge runtime): render emails in the Node.js runtime."), { cause: error });
|
|
130
|
+
throw error;
|
|
131
|
+
} finally {
|
|
132
|
+
using.length -= busy.length + 1;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function rendersHere(build) {
|
|
136
|
+
try {
|
|
137
|
+
build.renderToStaticMarkup(React4__default.default.createElement(() => null));
|
|
138
|
+
return true;
|
|
139
|
+
} catch {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function current() {
|
|
144
|
+
return using[using.length - 1] ?? defaultBuild__namespace;
|
|
145
|
+
}
|
|
146
|
+
var renderToStaticMarkup = (element2, options) => current().renderToStaticMarkup(element2, options);
|
|
147
|
+
var renderToString = (element2, options) => current().renderToString(element2, options);
|
|
148
|
+
|
|
149
|
+
// src/utils/unwrap-root.ts
|
|
150
|
+
var ROOT_NAMES = /* @__PURE__ */ new Set(["Body", "Email", "Page", "Document"]);
|
|
151
|
+
var CONTAINER_NAMES = /* @__PURE__ */ new Set([...ROOT_NAMES, "Row", "Column"]);
|
|
152
|
+
var MEMO = Symbol.for("react.memo");
|
|
153
|
+
var FORWARD_REF = Symbol.for("react.forward_ref");
|
|
154
|
+
var PROVIDER = Symbol.for("react.provider");
|
|
155
|
+
var CONTEXT = Symbol.for("react.context");
|
|
156
|
+
function getDisplayName(element2) {
|
|
157
|
+
return element2.type?.displayName;
|
|
158
|
+
}
|
|
159
|
+
function componentName(element2) {
|
|
160
|
+
const type = element2.type;
|
|
161
|
+
return type?.displayName || type?.name;
|
|
162
|
+
}
|
|
163
|
+
function isElementsType(type) {
|
|
164
|
+
return !!type?.[UNLAYER_RENDER_KEY] || CONTAINER_NAMES.has(type?.displayName);
|
|
165
|
+
}
|
|
166
|
+
function isElementsComponent(element2) {
|
|
167
|
+
return isElementsType(element2.type);
|
|
168
|
+
}
|
|
169
|
+
var ASYNC_TEMPLATE = "async and suspending templates aren't supported: load the data first and pass it as props";
|
|
170
|
+
var isThenable = (value) => typeof value?.then === "function";
|
|
171
|
+
var settle = (value) => {
|
|
172
|
+
if (isThenable(value)) value.then(void 0, () => {
|
|
173
|
+
});
|
|
174
|
+
};
|
|
175
|
+
function isAsyncComponent(type) {
|
|
176
|
+
while (type?.$$typeof === MEMO) type = type.type;
|
|
177
|
+
return (type?.$$typeof === FORWARD_REF ? type.render : type)?.[Symbol.toStringTag] === "AsyncFunction";
|
|
178
|
+
}
|
|
179
|
+
function callIsolated(call, prefix, providers = []) {
|
|
180
|
+
let result;
|
|
181
|
+
let error;
|
|
182
|
+
let ran = false;
|
|
183
|
+
let threw = false;
|
|
184
|
+
let calling = false;
|
|
185
|
+
const Probe = () => {
|
|
186
|
+
if (calling) return null;
|
|
187
|
+
ran = calling = true;
|
|
188
|
+
threw = false;
|
|
189
|
+
try {
|
|
190
|
+
result = call();
|
|
191
|
+
} catch (cause) {
|
|
192
|
+
threw = true;
|
|
193
|
+
error = cause;
|
|
194
|
+
} finally {
|
|
195
|
+
calling = false;
|
|
196
|
+
}
|
|
197
|
+
return null;
|
|
198
|
+
};
|
|
199
|
+
const probe = providers.reduceRight((inside, provider) => React4__default.default.cloneElement(provider, void 0, inside), React4__default.default.createElement(Probe));
|
|
200
|
+
renderToStaticMarkup(probe, prefix ? { identifierPrefix: prefix } : void 0);
|
|
201
|
+
settle(error);
|
|
202
|
+
settle(result);
|
|
203
|
+
if (threw) throw isThenable(error) ? new Error(ASYNC_TEMPLATE) : error;
|
|
204
|
+
if (!ran) throw new Error("the template wasn't rendered");
|
|
205
|
+
if (isThenable(result)) throw new Error(ASYNC_TEMPLATE);
|
|
206
|
+
return result;
|
|
207
|
+
}
|
|
208
|
+
function unwrapRoot(element2, why = {}) {
|
|
209
|
+
let current2 = element2;
|
|
210
|
+
const providers = [];
|
|
211
|
+
for (let depth = 0; ; depth++) {
|
|
212
|
+
if (ROOT_NAMES.has(getDisplayName(current2) ?? "")) break;
|
|
213
|
+
if (elementsOwn(current2)) break;
|
|
214
|
+
if (depth === 20) {
|
|
215
|
+
why.unread = "it wraps more than 20 components";
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
const type = current2.type;
|
|
219
|
+
const props = current2.props;
|
|
220
|
+
if (type?.$$typeof === MEMO) {
|
|
221
|
+
current2 = React4__default.default.createElement(type.type, props);
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
if ((type?.$$typeof === PROVIDER || type?.$$typeof === CONTEXT) && "value" in props) {
|
|
225
|
+
const inside = React4__default.default.Children.toArray(props.children);
|
|
226
|
+
if (inside.length !== 1 || !React4__default.default.isValidElement(inside[0])) break;
|
|
227
|
+
providers.push(current2);
|
|
228
|
+
current2 = inside[0];
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (type === React4__default.default.Fragment || type === React4__default.default.StrictMode || type === React4__default.default.Profiler) {
|
|
232
|
+
const inside = React4__default.default.Children.toArray(props.children);
|
|
233
|
+
if (inside.length !== 1 || !React4__default.default.isValidElement(inside[0])) break;
|
|
234
|
+
current2 = inside[0];
|
|
235
|
+
continue;
|
|
236
|
+
}
|
|
237
|
+
let produced;
|
|
238
|
+
const prefix = depth ? `w${depth}-` : void 0;
|
|
239
|
+
if (type?.$$typeof === FORWARD_REF) produced = callIsolated(() => type.render({ ...props }, null), prefix, providers);
|
|
240
|
+
else if (typeof type === "function" && !type.prototype?.isReactComponent) produced = callIsolated(() => type({ ...props }), prefix, providers);
|
|
241
|
+
else {
|
|
242
|
+
if (type?.prototype?.isReactComponent) why.unread = `<${componentName(current2)}> is a class component, which isn't called to find it`;
|
|
243
|
+
break;
|
|
244
|
+
}
|
|
245
|
+
if (!React4__default.default.isValidElement(produced)) {
|
|
246
|
+
if (holdsRoot(produced)) why.unread = "it doesn't return a root element";
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
current2 = produced;
|
|
250
|
+
}
|
|
251
|
+
if (!providers.length || !ROOT_NAMES.has(getDisplayName(current2) ?? "")) return current2;
|
|
252
|
+
const children = providers.reduceRight((inside, provider) => React4__default.default.cloneElement(provider, void 0, inside), current2.props.children);
|
|
253
|
+
return React4__default.default.cloneElement(current2, void 0, children);
|
|
254
|
+
}
|
|
255
|
+
var elementsOwn = (element2) => {
|
|
256
|
+
const type = element2.type;
|
|
257
|
+
return !!(type?.[UNLAYER_RENDER_KEY] || type?.[RECORDS]);
|
|
258
|
+
};
|
|
259
|
+
function holdsRoot(node) {
|
|
260
|
+
if (Array.isArray(node)) return node.some(holdsRoot);
|
|
261
|
+
if (!React4__default.default.isValidElement(node)) return false;
|
|
262
|
+
return ROOT_NAMES.has(getDisplayName(node) ?? "") || !elementsOwn(node) && holdsRoot(node.props.children);
|
|
263
|
+
}
|
|
264
|
+
var UNWRAP_ADVICE = "Pass the root element (<Email>\u2026</Email>), or a function component that returns one.";
|
|
265
|
+
function htmlRoot(element2, api) {
|
|
266
|
+
if (typeof element2.type === "string" || isElementsComponent(element2)) return element2;
|
|
267
|
+
let reason;
|
|
268
|
+
try {
|
|
269
|
+
const why = {};
|
|
270
|
+
const root = unwrapRoot(element2, why);
|
|
271
|
+
if (ROOT_NAMES.has(getDisplayName(root) ?? "")) return root;
|
|
272
|
+
if (!why.unread && !holdsRoot(root)) return element2;
|
|
273
|
+
reason = why.unread ?? "its root is inside other markup";
|
|
274
|
+
} catch (cause) {
|
|
275
|
+
if (cause instanceof Error && cause.message === ASYNC_TEMPLATE) throw new Error(`[Unlayer] ${api}: ${ASYNC_TEMPLATE}.`);
|
|
276
|
+
reason = cause instanceof Error ? cause.message : String(cause);
|
|
277
|
+
}
|
|
278
|
+
console.warn(`[Unlayer] ${api}: couldn't unwrap <${componentName(element2) || "wrapper"}> (${reason}): its root's fonts, lang, dir and phone styles are ignored. ${UNWRAP_ADVICE}`);
|
|
279
|
+
return element2;
|
|
280
|
+
}
|
|
281
|
+
function guard(children, collection, inContainer = false) {
|
|
282
|
+
return React4__default.default.Children.toArray(children).map((child) => {
|
|
283
|
+
const placed = guarded(child, collection, inContainer);
|
|
284
|
+
return placed === child && React4__default.default.isValidElement(child) ? React4__default.default.cloneElement(child) : placed;
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
function guarded(child, collection, inContainer) {
|
|
288
|
+
if (!React4__default.default.isValidElement(child)) return child;
|
|
289
|
+
if (isElementsType(child.type)) {
|
|
290
|
+
if (child.type[RECORDS]) return child;
|
|
291
|
+
if (!olderContainer(child.type)) return bounded(child, collection);
|
|
292
|
+
return recordedForOlder(child, collection, inContainer);
|
|
293
|
+
}
|
|
294
|
+
if (!child.type || typeof child.type === "object" && !("$$typeof" in child.type)) return child;
|
|
295
|
+
if (typeof child.type === "string") {
|
|
296
|
+
const inside = child.props.children;
|
|
297
|
+
const element2 = inside !== void 0 && hasComponent(inside) ? React4__default.default.cloneElement(child, void 0, guard(inside, collection, inContainer)) : child;
|
|
298
|
+
return collection.markup ? bounded(element2, collection) : element2;
|
|
299
|
+
}
|
|
300
|
+
if (child.type === React4__default.default.Fragment) {
|
|
301
|
+
return React4__default.default.createElement(React4__default.default.Fragment, { key: child.key }, guard(child.props.children, collection, inContainer));
|
|
302
|
+
}
|
|
303
|
+
return bounded(child, collection);
|
|
304
|
+
}
|
|
305
|
+
function bounded(child, collection) {
|
|
306
|
+
const at = collection.recorded.push({ kind: "boundary", element: child }) - 1;
|
|
307
|
+
if (isAsyncComponent(child.type)) return marker(collection, at, "f");
|
|
308
|
+
return React4__default.default.createElement(
|
|
309
|
+
React4.Suspense,
|
|
310
|
+
{ key: child.key ?? `b${at}`, fallback: marker(collection, at, "f") },
|
|
311
|
+
marker(collection, at, "o"),
|
|
312
|
+
child,
|
|
313
|
+
marker(collection, at, "c")
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
function olderContainer(type) {
|
|
317
|
+
return !/^(Row|Column)$/.test(type?.displayName ?? "") || /\b_config\b/.test(String(type));
|
|
318
|
+
}
|
|
319
|
+
function recordedForOlder(child, collection, inContainer) {
|
|
320
|
+
const type = child.type;
|
|
321
|
+
const props = child.props;
|
|
322
|
+
if (type.displayName === "Row" || type.displayName === "Column") {
|
|
323
|
+
const at2 = collection.recorded.push({ kind: type.displayName === "Row" ? "row" : "column", props }) - 1;
|
|
324
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(React4__default.default.Fragment, { children: [
|
|
325
|
+
marker(collection, at2, "o"),
|
|
326
|
+
guard(props.children, collection, true),
|
|
327
|
+
marker(collection, at2, "c")
|
|
328
|
+
] }, child.key ?? `r${at2}`);
|
|
329
|
+
}
|
|
330
|
+
if (!type.__unlayerRender && !inContainer) return child;
|
|
331
|
+
if (!type.__unlayerRender) {
|
|
332
|
+
console.warn(`[Unlayer] <${type.displayName}> is a root: it can't be placed in a Row or Column, so it's left out.`);
|
|
333
|
+
return null;
|
|
334
|
+
}
|
|
335
|
+
const at = collection.recorded.push({ kind: "block", type: child.type, props }) - 1;
|
|
336
|
+
return React4__default.default.cloneElement(marker(collection, at), { key: child.key ?? `b${at}` });
|
|
337
|
+
}
|
|
338
|
+
function hasComponent(children) {
|
|
339
|
+
return React4__default.default.Children.toArray(children).some(
|
|
340
|
+
(child) => React4__default.default.isValidElement(child) && (typeof child.type === "string" || child.type === React4__default.default.Fragment ? hasComponent(child.props.children) : !isElementsType(child.type))
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
function Sentinel({ record, real }) {
|
|
344
|
+
let collected2 = !!collecting()?.blind;
|
|
345
|
+
if (!collected2) {
|
|
346
|
+
try {
|
|
347
|
+
collected2 = React4__default.default.useId().slice(1).startsWith(COLLECTING_ID);
|
|
348
|
+
} catch {
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return collected2 ? record() : within(null, real);
|
|
352
|
+
}
|
|
353
|
+
var named = /* @__PURE__ */ new Map();
|
|
354
|
+
function whileCollecting(record, real, name) {
|
|
355
|
+
let type = named.get(name);
|
|
356
|
+
if (!type) named.set(name, type = Object.assign((props) => Sentinel(props), { displayName: name }));
|
|
357
|
+
return React4__default.default.createElement(type, { record, real });
|
|
358
|
+
}
|
|
359
|
+
function recordContainer(kind, props) {
|
|
360
|
+
const collection = collecting();
|
|
361
|
+
const at = collection.recorded.push({ kind, props }) - 1;
|
|
362
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
363
|
+
marker(collection, at, "o"),
|
|
364
|
+
guard(props.children, collection, true),
|
|
365
|
+
marker(collection, at, "c")
|
|
366
|
+
] });
|
|
367
|
+
}
|
|
368
|
+
function recordBlock(type, props) {
|
|
369
|
+
const collection = collecting();
|
|
370
|
+
const at = collection.recorded.push({ kind: "block", type, props }) - 1;
|
|
371
|
+
return marker(collection, at);
|
|
372
|
+
}
|
|
14
373
|
|
|
15
374
|
// src/utils/image-sizing.ts
|
|
16
375
|
function toPx(value) {
|
|
@@ -22,11 +381,11 @@ function toPx(value) {
|
|
|
22
381
|
function edges(value) {
|
|
23
382
|
if (value == null) return { left: 0, right: 0 };
|
|
24
383
|
if (typeof value === "number") return { left: value, right: value };
|
|
25
|
-
const
|
|
26
|
-
if (
|
|
27
|
-
if (
|
|
28
|
-
return { left:
|
|
29
|
-
return { left:
|
|
384
|
+
const parts2 = String(value).trim().split(/\s+/).map((p) => parseFloat(p) || 0);
|
|
385
|
+
if (parts2.length === 1) return { left: parts2[0], right: parts2[0] };
|
|
386
|
+
if (parts2.length === 2 || parts2.length === 3)
|
|
387
|
+
return { left: parts2[1], right: parts2[1] };
|
|
388
|
+
return { left: parts2[3] || 0, right: parts2[1] || 0 };
|
|
30
389
|
}
|
|
31
390
|
function borderEdges(border) {
|
|
32
391
|
if (!border || typeof border !== "object") return { left: 0, right: 0 };
|
|
@@ -216,7 +575,7 @@ function paragraphAlign(format) {
|
|
|
216
575
|
}
|
|
217
576
|
return void 0;
|
|
218
577
|
}
|
|
219
|
-
function paragraphNodeToHtml(node,
|
|
578
|
+
function paragraphNodeToHtml(node, childrenHtml22) {
|
|
220
579
|
const isInlineTool = !!node.isInlineTool;
|
|
221
580
|
const tag = isInlineTool ? "span" : "p";
|
|
222
581
|
const dir = dirAttribute(node.direction);
|
|
@@ -240,7 +599,7 @@ function paragraphNodeToHtml(node, childrenHtml) {
|
|
|
240
599
|
styleParts.push(`text-align: ${align}`);
|
|
241
600
|
}
|
|
242
601
|
const style = styleParts.length > 0 ? ` style="${escapeHtml(styleParts.join("; ") + ";")}"` : "";
|
|
243
|
-
return `<${tag}${dir}${style}>${
|
|
602
|
+
return `<${tag}${dir}${style}>${childrenHtml22 || "<br>"}</${tag}>`;
|
|
244
603
|
}
|
|
245
604
|
function nodeToHtml(node) {
|
|
246
605
|
if (!node || typeof node !== "object") return "";
|
|
@@ -251,32 +610,32 @@ function nodeToHtml(node) {
|
|
|
251
610
|
if (type === "linebreak") {
|
|
252
611
|
return "<br>";
|
|
253
612
|
}
|
|
254
|
-
const
|
|
613
|
+
const childrenHtml22 = (node.children || []).map(nodeToHtml).join("");
|
|
255
614
|
switch (type) {
|
|
256
615
|
case "root":
|
|
257
|
-
return
|
|
616
|
+
return childrenHtml22;
|
|
258
617
|
case "paragraph":
|
|
259
618
|
case "extended-paragraph":
|
|
260
|
-
return paragraphNodeToHtml(node,
|
|
619
|
+
return paragraphNodeToHtml(node, childrenHtml22);
|
|
261
620
|
case "heading": {
|
|
262
621
|
const tag = /^h[1-6]$/.test(node.tag) ? node.tag : "h1";
|
|
263
622
|
const dir = dirAttribute(node.direction);
|
|
264
|
-
return `<${tag}${dir}>${
|
|
623
|
+
return `<${tag}${dir}>${childrenHtml22}</${tag}>`;
|
|
265
624
|
}
|
|
266
625
|
case "link": {
|
|
267
626
|
const href = node.url ? ` href="${escapeHtml(node.url)}"` : "";
|
|
268
627
|
const target = node.target ? ` target="${escapeHtml(node.target)}"` : "";
|
|
269
628
|
const rel = node.rel ? ` rel="${escapeHtml(node.rel)}"` : "";
|
|
270
|
-
return `<a${href}${target}${rel}>${
|
|
629
|
+
return `<a${href}${target}${rel}>${childrenHtml22}</a>`;
|
|
271
630
|
}
|
|
272
631
|
case "list": {
|
|
273
632
|
const tag = node.listType === "number" ? "ol" : "ul";
|
|
274
|
-
return `<${tag}>${
|
|
633
|
+
return `<${tag}>${childrenHtml22}</${tag}>`;
|
|
275
634
|
}
|
|
276
635
|
case "listitem":
|
|
277
|
-
return `<li>${
|
|
636
|
+
return `<li>${childrenHtml22}</li>`;
|
|
278
637
|
default:
|
|
279
|
-
return
|
|
638
|
+
return childrenHtml22;
|
|
280
639
|
}
|
|
281
640
|
}
|
|
282
641
|
function generateHtmlFromTextJson(textJson) {
|
|
@@ -307,6 +666,57 @@ function mergeValues(defaults, userValues) {
|
|
|
307
666
|
}
|
|
308
667
|
return result;
|
|
309
668
|
}
|
|
669
|
+
var CHANNEL = /^-?(?:\d+(?:\.\d*)?|\.\d+)%?$/;
|
|
670
|
+
function normalizeColor(value) {
|
|
671
|
+
const text = value.trim();
|
|
672
|
+
const open = text.indexOf("(");
|
|
673
|
+
if (!/^rgba?$/i.test(text.slice(0, open)) || !text.endsWith(")")) return value;
|
|
674
|
+
const [rgb, slashed, extra] = text.slice(open + 1, -1).split("/");
|
|
675
|
+
const channels = rgb.trim().split(/\s*,\s*|\s+/);
|
|
676
|
+
if (slashed !== void 0) channels.push(slashed.trim());
|
|
677
|
+
if (extra !== void 0 || channels.length > 4 || channels.length < (slashed === void 0 ? 3 : 4) || !channels.every((c) => CHANNEL.test(c))) return value;
|
|
678
|
+
const num = (text2, full) => text2.endsWith("%") ? parseFloat(text2) / 100 * full : parseFloat(text2);
|
|
679
|
+
const [r, g, b] = channels.slice(0, 3).map((text2) => Math.max(0, Math.min(255, Math.round(num(text2, 255)))));
|
|
680
|
+
const alpha = channels[3] === void 0 ? 1 : num(channels[3], 1);
|
|
681
|
+
if (alpha < 1) return `rgba(${r}, ${g}, ${b}, ${Math.max(0, alpha)})`;
|
|
682
|
+
return `#${[r, g, b].map((n) => n.toString(16).padStart(2, "0")).join("")}`;
|
|
683
|
+
}
|
|
684
|
+
function cssValueSafe(text) {
|
|
685
|
+
if (/[<>{};]|\/\*|\*\//.test(text)) return false;
|
|
686
|
+
const open = [];
|
|
687
|
+
for (const c of text) {
|
|
688
|
+
if (c === "(" || c === "[") open.push(c === "(" ? ")" : "]");
|
|
689
|
+
else if ((c === ")" || c === "]") && open.pop() !== c) return false;
|
|
690
|
+
}
|
|
691
|
+
return !open.length;
|
|
692
|
+
}
|
|
693
|
+
function cssSafeValues(value) {
|
|
694
|
+
if (typeof value === "string") return cssValueSafe(value) ? value : void 0;
|
|
695
|
+
if (Array.isArray(value)) return value.map(cssSafeValues);
|
|
696
|
+
if (!isPlainObject(value)) return value;
|
|
697
|
+
const out = {};
|
|
698
|
+
for (const [k, v] of Object.entries(value)) {
|
|
699
|
+
const safe = cssSafeValues(v);
|
|
700
|
+
if (safe !== void 0 || v === void 0) out[k] = safe;
|
|
701
|
+
}
|
|
702
|
+
return out;
|
|
703
|
+
}
|
|
704
|
+
function normalizeFontStack(value) {
|
|
705
|
+
return value.replace(/"([^"]*)"?/g, (_, name) => `'${name.replace(/'/g, "\\'")}'`);
|
|
706
|
+
}
|
|
707
|
+
function normalizeCssValues(value, key) {
|
|
708
|
+
if (typeof value === "string") return key === "fontFamily" ? normalizeFontStack(value) : key === "color" || key?.endsWith("Color") ? normalizeColor(value) : value;
|
|
709
|
+
if (Array.isArray(value)) return value.map((item) => normalizeCssValues(item));
|
|
710
|
+
if (!isPlainObject(value)) return value;
|
|
711
|
+
const out = {};
|
|
712
|
+
for (const [k, v] of Object.entries(value)) out[k] = normalizeCssValues(v, key === "fontFamily" ? key : k);
|
|
713
|
+
return out;
|
|
714
|
+
}
|
|
715
|
+
function isPlainObject(value) {
|
|
716
|
+
if (value === null || typeof value !== "object") return false;
|
|
717
|
+
const proto = Object.getPrototypeOf(value);
|
|
718
|
+
return proto === Object.prototype || proto === null;
|
|
719
|
+
}
|
|
310
720
|
var nestedStructureCache = /* @__PURE__ */ new WeakMap();
|
|
311
721
|
function analyzeNestedStructure(defaultValues) {
|
|
312
722
|
const cached = nestedStructureCache.get(defaultValues);
|
|
@@ -351,24 +761,39 @@ function normalizeCssProps(props) {
|
|
|
351
761
|
}
|
|
352
762
|
}
|
|
353
763
|
}
|
|
354
|
-
|
|
764
|
+
var ENTITIES = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
765
|
+
function escapeText(text, quotes) {
|
|
766
|
+
return text.replace(quotes ? /[&<>"']/g : /[&<>]/g, (c) => ENTITIES[c]);
|
|
767
|
+
}
|
|
768
|
+
function escapeKeepingTags(text, quotes, escape = (part) => escapeText(part, quotes)) {
|
|
769
|
+
return text.split(/(<%[\w.]+%>)/).map((part, i) => i % 2 ? part : escape(part)).join("");
|
|
770
|
+
}
|
|
771
|
+
var menuText = (text) => escapeKeepingTags(text, false, (part) => part.replace(/&(?!(?:#\d+|#x[\da-f]+|[a-z][\da-z]*);)|[<>"]/gi, (c) => ENTITIES[c]));
|
|
772
|
+
function flattenChildrenText(node, breaks) {
|
|
355
773
|
if (node == null || typeof node === "boolean") return "";
|
|
356
774
|
if (typeof node === "string") return node;
|
|
357
775
|
if (typeof node === "number") return String(node);
|
|
358
|
-
if (Array.isArray(node)) return node.map(flattenChildrenText).join("");
|
|
776
|
+
if (Array.isArray(node)) return node.map((child) => flattenChildrenText(child, breaks)).join("");
|
|
359
777
|
if (typeof node === "object" && "props" in node) {
|
|
360
|
-
return flattenChildrenText(node.props?.children);
|
|
778
|
+
return breaks && node.type === "br" ? "<br/>" : flattenChildrenText(node.props?.children, breaks);
|
|
361
779
|
}
|
|
362
780
|
return "";
|
|
363
781
|
}
|
|
782
|
+
function childrenHtml(children) {
|
|
783
|
+
return flattenChildrenText(children, true).split(/(<br\s*\/?>)/i).map((part, i) => i % 2 ? "<br/>" : escapeKeepingTags(part)).join("");
|
|
784
|
+
}
|
|
364
785
|
function mapSemanticProps(props, defaultValues, componentType) {
|
|
365
|
-
const { children, values, ...restProps } = props;
|
|
786
|
+
const { children, values, mobile, hideOnMobile: hideMobileProp, hideOnDesktop: hideDesktopProp, ...restProps } = props;
|
|
787
|
+
const hideOnMobile = componentType === "Column" ? void 0 : hideMobileProp;
|
|
788
|
+
const hideOnDesktop = componentType === "Column" ? void 0 : hideDesktopProp;
|
|
366
789
|
const userProps = { ...restProps };
|
|
367
790
|
const result = values ? { ...values } : {};
|
|
368
791
|
if (children !== void 0 && !result.text && !result.textJson) {
|
|
369
792
|
const textContent = typeof children === "string" ? children : flattenChildrenText(children);
|
|
370
793
|
if (componentType === "Paragraph") {
|
|
371
794
|
result.textJson = textToTextJson(textContent);
|
|
795
|
+
} else if (componentType === "Heading" || componentType === "Button") {
|
|
796
|
+
result.text = childrenHtml(children);
|
|
372
797
|
} else {
|
|
373
798
|
result.text = textContent;
|
|
374
799
|
}
|
|
@@ -446,15 +871,15 @@ function mapSemanticProps(props, defaultValues, componentType) {
|
|
|
446
871
|
}
|
|
447
872
|
if (defaultValues && typeof defaultValues === "object" && "border" in defaultValues) {
|
|
448
873
|
const borderSideRe = /^border(Top|Right|Bottom|Left)(Width|Style|Color)$/;
|
|
449
|
-
const
|
|
874
|
+
const collected2 = {};
|
|
450
875
|
for (const key of Object.keys(final)) {
|
|
451
876
|
if (borderSideRe.test(key)) {
|
|
452
|
-
|
|
877
|
+
collected2[key] = final[key];
|
|
453
878
|
delete final[key];
|
|
454
879
|
}
|
|
455
880
|
}
|
|
456
|
-
if (Object.keys(
|
|
457
|
-
final.border = { ...final.border || {}, ...
|
|
881
|
+
if (Object.keys(collected2).length > 0) {
|
|
882
|
+
final.border = { ...final.border || {}, ...collected2 };
|
|
458
883
|
}
|
|
459
884
|
if (final.border && typeof final.border === "object") {
|
|
460
885
|
const b = { ...final.border };
|
|
@@ -467,7 +892,31 @@ function mapSemanticProps(props, defaultValues, componentType) {
|
|
|
467
892
|
final.border = b;
|
|
468
893
|
}
|
|
469
894
|
}
|
|
470
|
-
|
|
895
|
+
if (mobile || hideOnMobile !== void 0 || hideOnDesktop !== void 0) {
|
|
896
|
+
const overrides = { ...final._override };
|
|
897
|
+
if (mobile || hideOnMobile !== void 0) {
|
|
898
|
+
const { width, maxWidth, autoWidth, ...phone } = mobile || {};
|
|
899
|
+
const mapped = mapSemanticProps(phone, defaultValues, componentType);
|
|
900
|
+
if (componentType === "Image" && (width !== void 0 || maxWidth !== void 0 || autoWidth !== void 0)) {
|
|
901
|
+
mapped.src = {
|
|
902
|
+
...overrides.mobile?.src || {},
|
|
903
|
+
...autoWidth !== void 0 ? { autoWidth } : { autoWidth: false },
|
|
904
|
+
...width !== void 0 || maxWidth !== void 0 ? { maxWidth: width ?? maxWidth } : {}
|
|
905
|
+
};
|
|
906
|
+
} else if (width !== void 0 || autoWidth !== void 0) {
|
|
907
|
+
const key = componentType === "Button" ? "size" : "width";
|
|
908
|
+
mapped[key] = { autoWidth: autoWidth ?? false, ...width !== void 0 ? { width: typeof width === "number" ? `${width}px` : width } : {} };
|
|
909
|
+
}
|
|
910
|
+
overrides.mobile = { ...overrides.mobile, ...cssSafeValues(mapped), ...hideOnMobile !== void 0 ? { hideMobile: hideOnMobile } : {} };
|
|
911
|
+
}
|
|
912
|
+
if (hideOnDesktop !== void 0) overrides.desktop = { ...overrides.desktop, hideDesktop: hideOnDesktop };
|
|
913
|
+
final._override = overrides;
|
|
914
|
+
}
|
|
915
|
+
if (componentType === "Row" && final.noStackMobile === true) {
|
|
916
|
+
final._override = { ...final._override, mobile: { ...final._override?.mobile, noStackMobile: true } };
|
|
917
|
+
final.noStackMobile = false;
|
|
918
|
+
}
|
|
919
|
+
return normalizeCssValues(final);
|
|
471
920
|
}
|
|
472
921
|
function normalizeLinkValue(value) {
|
|
473
922
|
if (value == null) return void 0;
|
|
@@ -489,26 +938,39 @@ function normalizeLinkValue(value) {
|
|
|
489
938
|
}
|
|
490
939
|
return void 0;
|
|
491
940
|
}
|
|
492
|
-
function
|
|
941
|
+
function safeLink(link) {
|
|
942
|
+
const url = link.url === void 0 || link.url === null ? link.url : String(link.url);
|
|
943
|
+
return typeof url === "string" ? { ...link, url: url.replace(/<%[\w.]+%>|["<>]/g, (c) => c.length > 1 ? c : encodeURIComponent(c)) } : link;
|
|
944
|
+
}
|
|
945
|
+
function normalizeValuesForExporter(values, componentName2, mode) {
|
|
493
946
|
if (values == null || typeof values !== "object") return values;
|
|
494
947
|
const out = { ...values };
|
|
495
948
|
for (const key of ["href", "action"]) {
|
|
496
949
|
if (out[key] !== void 0) {
|
|
497
950
|
const normalized = normalizeLinkValue(out[key]);
|
|
498
|
-
if (normalized !== void 0) out[key] = normalized;
|
|
951
|
+
if (normalized !== void 0) out[key] = safeLink(normalized);
|
|
499
952
|
}
|
|
500
953
|
}
|
|
501
|
-
if (
|
|
954
|
+
if (componentName2 === "Button" && typeof out.text === "string") {
|
|
955
|
+
out.text = escapeKeepingTags(out.text, true);
|
|
956
|
+
}
|
|
957
|
+
if (componentName2 === "Menu" && out.menu && Array.isArray(out.menu.items)) {
|
|
502
958
|
out.menu = {
|
|
503
959
|
...out.menu,
|
|
504
960
|
items: out.menu.items.map((item) => {
|
|
505
|
-
if (!item
|
|
506
|
-
const
|
|
507
|
-
if (
|
|
508
|
-
|
|
961
|
+
if (!item) return item;
|
|
962
|
+
const next = mode === "email" && typeof item.text === "string" ? { ...item, text: menuText(item.text) } : item;
|
|
963
|
+
if (next.link === void 0) return next;
|
|
964
|
+
const normalized = normalizeLinkValue(next.link);
|
|
965
|
+
if (normalized === void 0) return next;
|
|
966
|
+
return { ...next, link: safeLink(normalized) };
|
|
509
967
|
})
|
|
510
968
|
};
|
|
511
969
|
}
|
|
970
|
+
if (componentName2 === "Social" && out.icons && Array.isArray(out.icons.icons)) {
|
|
971
|
+
const named2 = (icon) => mode === "email" && typeof icon.name === "string" ? { ...icon, name: escapeText(icon.name, true) } : icon;
|
|
972
|
+
out.icons = { ...out.icons, icons: out.icons.icons.map((icon) => icon && typeof icon === "object" ? named2(safeLink(icon)) : icon) };
|
|
973
|
+
}
|
|
512
974
|
return out;
|
|
513
975
|
}
|
|
514
976
|
var HTML_ENTITIES = {
|
|
@@ -601,9 +1063,11 @@ function htmlToPlainText(html) {
|
|
|
601
1063
|
text = text.replace(/<head[\s\S]*?<\/head>/gi, "");
|
|
602
1064
|
text = text.replace(/<style[\s\S]*?<\/style>/gi, "");
|
|
603
1065
|
text = text.replace(/<script[\s\S]*?<\/script>/gi, "");
|
|
1066
|
+
text = text.replace(/<br\s*\/?>/gi, "\n");
|
|
604
1067
|
text = text.replace(/<h[12][^>]*>([\s\S]*?)<\/h[12]>/gi, (_, content) => {
|
|
605
1068
|
const clean = content.replace(/<[^>]+>/g, "").trim();
|
|
606
|
-
|
|
1069
|
+
const upper = clean.replace(/&#?\w+;|[^&]+|&/g, (part) => /^&#?\w+;$/.test(part) ? part : part.toUpperCase());
|
|
1070
|
+
return "\n" + upper + "\n";
|
|
607
1071
|
});
|
|
608
1072
|
text = text.replace(/<h[3-6][^>]*>([\s\S]*?)<\/h[3-6]>/gi, (_, content) => {
|
|
609
1073
|
const clean = content.replace(/<[^>]+>/g, "").trim();
|
|
@@ -625,7 +1089,6 @@ function htmlToPlainText(html) {
|
|
|
625
1089
|
const clean = content.replace(/<[^>]+>/g, "").trim();
|
|
626
1090
|
return "- " + clean + "\n";
|
|
627
1091
|
});
|
|
628
|
-
text = text.replace(/<br\s*\/?>/gi, "\n");
|
|
629
1092
|
text = text.replace(/<\/(?:p|div|tr|blockquote|section|article|header|footer|main|nav|aside)>/gi, "\n");
|
|
630
1093
|
text = text.replace(/<\/(?:ul|ol|table|thead|tbody|tfoot)>/gi, "\n");
|
|
631
1094
|
text = text.replace(/<\/(?:td|th)>/gi, " ");
|
|
@@ -672,6 +1135,15 @@ function nextHtmlId(config, prefix) {
|
|
|
672
1135
|
ids[prefix] = (ids[prefix] || 0) + 1;
|
|
673
1136
|
return `${prefix}_${ids[prefix]}`;
|
|
674
1137
|
}
|
|
1138
|
+
function safeName(value, spaces = false) {
|
|
1139
|
+
const text = String(value ?? "");
|
|
1140
|
+
return spaces ? text.replace(/[\t\n\f\r]/g, " ").replace(/["'<>&`\u0000-\u001f\u007f]/g, "") : text.replace(/["'<>&`\s\u0000-\u001f\u007f]/g, "");
|
|
1141
|
+
}
|
|
1142
|
+
var safeMeta = (meta) => ({ ...meta, htmlID: safeName(meta.htmlID), htmlClassNames: safeName(meta.htmlClassNames, true) });
|
|
1143
|
+
function textDirectionOf(value) {
|
|
1144
|
+
const dir = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
1145
|
+
return dir === "ltr" || dir === "rtl" || dir === "auto" ? dir : void 0;
|
|
1146
|
+
}
|
|
675
1147
|
function renderComponent(config) {
|
|
676
1148
|
const { type, values, className, style, args = [], innerHTML, _config, exporter, metaContext } = config;
|
|
677
1149
|
try {
|
|
@@ -679,7 +1151,7 @@ function renderComponent(config) {
|
|
|
679
1151
|
const exporterConfig = {
|
|
680
1152
|
generateHtmlFromTextJson,
|
|
681
1153
|
toSafeHtml: cfg.toSafeHtml,
|
|
682
|
-
textDirection: cfg.textDirection,
|
|
1154
|
+
textDirection: textDirectionOf(cfg.textDirection),
|
|
683
1155
|
cdnBaseUrl: cfg.cdnBaseUrl
|
|
684
1156
|
};
|
|
685
1157
|
let html;
|
|
@@ -743,21 +1215,20 @@ function createItemComponent(config) {
|
|
|
743
1215
|
});
|
|
744
1216
|
const finalValues = mergeValues(config.defaultValues, mappedValues);
|
|
745
1217
|
const metaName = config.metaName ?? config.name.toLowerCase();
|
|
746
|
-
const
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
htmlClassNames: `u_content_${metaName}`,
|
|
751
|
-
...finalValues._meta || {}
|
|
752
|
-
}
|
|
1218
|
+
const meta = {
|
|
1219
|
+
htmlID: _metaHtmlId ?? `u_content_${metaName}_${index + 1}`,
|
|
1220
|
+
htmlClassNames: `u_content_${metaName}`,
|
|
1221
|
+
...finalValues._meta || {}
|
|
753
1222
|
};
|
|
1223
|
+
const valuesWithMeta = { ...finalValues, _meta: safeMeta(meta) };
|
|
754
1224
|
const safeBodyValues = {
|
|
755
1225
|
contentWidth: "500px",
|
|
756
1226
|
...bodyValues
|
|
757
1227
|
};
|
|
758
1228
|
const valuesForExporter = normalizeValuesForExporter(
|
|
759
1229
|
valuesWithMeta,
|
|
760
|
-
config.name
|
|
1230
|
+
config.name,
|
|
1231
|
+
mode
|
|
761
1232
|
);
|
|
762
1233
|
const exportSrc = valuesForExporter.src;
|
|
763
1234
|
if (exportSrc && typeof exportSrc === "object" && exportSrc.autoWidth === false) {
|
|
@@ -792,10 +1263,12 @@ function createItemComponent(config) {
|
|
|
792
1263
|
});
|
|
793
1264
|
}
|
|
794
1265
|
const ItemComponent = (props) => {
|
|
1266
|
+
if (collecting()) return whileCollecting(() => recordBlock(ItemComponent, props), () => renderFn(props), ItemComponent.displayName ?? "Block");
|
|
795
1267
|
return renderFn(props);
|
|
796
1268
|
};
|
|
797
1269
|
ItemComponent.displayName = config.displayName || config.name;
|
|
798
1270
|
ItemComponent[UNLAYER_RENDER_KEY] = renderFn;
|
|
1271
|
+
ItemComponent[RECORDS] = true;
|
|
799
1272
|
ItemComponent[UNLAYER_CONFIG_KEY] = {
|
|
800
1273
|
name: config.name,
|
|
801
1274
|
defaultValues: config.defaultValues,
|
|
@@ -803,7 +1276,8 @@ function createItemComponent(config) {
|
|
|
803
1276
|
contentType: config.contentType,
|
|
804
1277
|
slug: config.slug,
|
|
805
1278
|
metaName: config.metaName,
|
|
806
|
-
head: config.head
|
|
1279
|
+
head: config.head,
|
|
1280
|
+
omitEmptyOutput: config.omitEmptyOutput
|
|
807
1281
|
};
|
|
808
1282
|
return ItemComponent;
|
|
809
1283
|
}
|
|
@@ -823,9 +1297,9 @@ var Button = createItemComponent({
|
|
|
823
1297
|
DEFAULT_VALUES,
|
|
824
1298
|
"Button"
|
|
825
1299
|
);
|
|
826
|
-
const
|
|
827
|
-
if (
|
|
828
|
-
const s =
|
|
1300
|
+
const size2 = mapped.size;
|
|
1301
|
+
if (size2 && typeof size2 === "object" && !Array.isArray(size2)) {
|
|
1302
|
+
const s = size2;
|
|
829
1303
|
if (typeof s.width === "number") {
|
|
830
1304
|
s.width = `${s.width}px`;
|
|
831
1305
|
} else if (typeof s.width === "string" && /^\d+(?:\.\d+)?$/.test(s.width.trim())) {
|
|
@@ -1015,13 +1489,45 @@ var Paragraph = createItemComponent({
|
|
|
1015
1489
|
exporters: exporters.ParagraphExporters
|
|
1016
1490
|
});
|
|
1017
1491
|
var Paragraph_default = Paragraph;
|
|
1018
|
-
|
|
1492
|
+
|
|
1493
|
+
// src/components/PageBreak.tsx
|
|
1019
1494
|
var DEFAULT_VALUES8 = {
|
|
1495
|
+
color: "#6b7280"
|
|
1496
|
+
};
|
|
1497
|
+
var pageBreakExporters = {
|
|
1498
|
+
// Page breaks are a document-only concept. Keep the unsupported renderers
|
|
1499
|
+
// inert so a component rendered outside <Document> does not throw.
|
|
1500
|
+
web: () => "",
|
|
1501
|
+
email: () => "",
|
|
1502
|
+
document: () => '<div class="u-content-page-break" aria-hidden="true"></div>'
|
|
1503
|
+
};
|
|
1504
|
+
var pageBreakHead = {
|
|
1505
|
+
css: (_values, _bodyValues, meta) => meta.displayMode === "document" ? `
|
|
1506
|
+
.u-content-page-break {
|
|
1507
|
+
break-after: page;
|
|
1508
|
+
page-break-after: always;
|
|
1509
|
+
}
|
|
1510
|
+
` : void 0
|
|
1511
|
+
};
|
|
1512
|
+
var PageBreak = createItemComponent({
|
|
1513
|
+
name: "PageBreak",
|
|
1514
|
+
contentType: "page_break",
|
|
1515
|
+
metaName: "page_break",
|
|
1516
|
+
defaultValues: DEFAULT_VALUES8,
|
|
1517
|
+
propMapper: (props) => mapSemanticProps(props, DEFAULT_VALUES8, "PageBreak"),
|
|
1518
|
+
displayName: "PageBreak",
|
|
1519
|
+
exporters: pageBreakExporters,
|
|
1520
|
+
head: pageBreakHead,
|
|
1521
|
+
omitEmptyOutput: true
|
|
1522
|
+
});
|
|
1523
|
+
var PageBreak_default = PageBreak;
|
|
1524
|
+
var DEFAULT_ICONS = exporters.SocialDefaults.icons ?? { iconType: "circle", icons: [] };
|
|
1525
|
+
var DEFAULT_VALUES9 = {
|
|
1020
1526
|
...exporters.SocialDefaults
|
|
1021
1527
|
};
|
|
1022
1528
|
var Social = createItemComponent({
|
|
1023
1529
|
name: "Social",
|
|
1024
|
-
defaultValues:
|
|
1530
|
+
defaultValues: DEFAULT_VALUES9,
|
|
1025
1531
|
propMapper: (props) => {
|
|
1026
1532
|
const { icons, iconType, ...rest } = props;
|
|
1027
1533
|
const coerceSizes = (base) => {
|
|
@@ -1042,7 +1548,7 @@ var Social = createItemComponent({
|
|
|
1042
1548
|
}));
|
|
1043
1549
|
const base = mapSemanticProps(
|
|
1044
1550
|
rest,
|
|
1045
|
-
|
|
1551
|
+
DEFAULT_VALUES9,
|
|
1046
1552
|
"Social"
|
|
1047
1553
|
);
|
|
1048
1554
|
base.icons = {
|
|
@@ -1054,14 +1560,14 @@ var Social = createItemComponent({
|
|
|
1054
1560
|
if (iconType !== void 0) {
|
|
1055
1561
|
const base = mapSemanticProps(
|
|
1056
1562
|
rest,
|
|
1057
|
-
|
|
1563
|
+
DEFAULT_VALUES9,
|
|
1058
1564
|
"Social"
|
|
1059
1565
|
);
|
|
1060
1566
|
base.icons = { ...DEFAULT_ICONS, ...base.icons, iconType };
|
|
1061
1567
|
return coerceSizes(base);
|
|
1062
1568
|
}
|
|
1063
1569
|
return coerceSizes(
|
|
1064
|
-
mapSemanticProps(props,
|
|
1570
|
+
mapSemanticProps(props, DEFAULT_VALUES9, "Social")
|
|
1065
1571
|
);
|
|
1066
1572
|
},
|
|
1067
1573
|
displayName: "Social",
|
|
@@ -1069,20 +1575,20 @@ var Social = createItemComponent({
|
|
|
1069
1575
|
});
|
|
1070
1576
|
var Social_default = Social;
|
|
1071
1577
|
var DEFAULT_TABLE = { headers: [], rows: [], footers: [] };
|
|
1072
|
-
var
|
|
1578
|
+
var DEFAULT_VALUES10 = {
|
|
1073
1579
|
...exporters.TableDefaults,
|
|
1074
1580
|
table: DEFAULT_TABLE
|
|
1075
1581
|
// Schema doesn't include table data structure
|
|
1076
1582
|
};
|
|
1077
1583
|
var Table = createItemComponent({
|
|
1078
1584
|
name: "Table",
|
|
1079
|
-
defaultValues:
|
|
1585
|
+
defaultValues: DEFAULT_VALUES10,
|
|
1080
1586
|
propMapper: (props) => {
|
|
1081
1587
|
const { headers, data, columns, rows, ...rest } = props;
|
|
1082
1588
|
if (headers || data || typeof columns === "number" || typeof rows === "number") {
|
|
1083
1589
|
const base = mapSemanticProps(
|
|
1084
1590
|
rest,
|
|
1085
|
-
|
|
1591
|
+
DEFAULT_VALUES10,
|
|
1086
1592
|
"Table"
|
|
1087
1593
|
);
|
|
1088
1594
|
const colCount = headers ? headers.length : typeof columns === "number" ? columns : data?.[0]?.length ?? 0;
|
|
@@ -1114,7 +1620,7 @@ var Table = createItemComponent({
|
|
|
1114
1620
|
}
|
|
1115
1621
|
return mapSemanticProps(
|
|
1116
1622
|
props,
|
|
1117
|
-
|
|
1623
|
+
DEFAULT_VALUES10,
|
|
1118
1624
|
"Table"
|
|
1119
1625
|
);
|
|
1120
1626
|
},
|
|
@@ -1129,7 +1635,7 @@ var DEFAULT_VIDEO = {
|
|
|
1129
1635
|
loading: false,
|
|
1130
1636
|
...exporters.VideoDefaults.video
|
|
1131
1637
|
};
|
|
1132
|
-
var
|
|
1638
|
+
var DEFAULT_VALUES11 = {
|
|
1133
1639
|
...exporters.VideoDefaults,
|
|
1134
1640
|
video: DEFAULT_VIDEO
|
|
1135
1641
|
};
|
|
@@ -1157,14 +1663,14 @@ function parseVideoUrl(url) {
|
|
|
1157
1663
|
}
|
|
1158
1664
|
var Video = createItemComponent({
|
|
1159
1665
|
name: "Video",
|
|
1160
|
-
defaultValues:
|
|
1666
|
+
defaultValues: DEFAULT_VALUES11,
|
|
1161
1667
|
propMapper: (props) => {
|
|
1162
1668
|
const { videoUrl, ...rest } = props;
|
|
1163
1669
|
if (typeof videoUrl === "string") {
|
|
1164
1670
|
const parsed = parseVideoUrl(videoUrl);
|
|
1165
1671
|
const base = mapSemanticProps(
|
|
1166
1672
|
rest,
|
|
1167
|
-
|
|
1673
|
+
DEFAULT_VALUES11,
|
|
1168
1674
|
"Video"
|
|
1169
1675
|
);
|
|
1170
1676
|
if (parsed) {
|
|
@@ -1174,7 +1680,7 @@ var Video = createItemComponent({
|
|
|
1174
1680
|
}
|
|
1175
1681
|
return mapSemanticProps(
|
|
1176
1682
|
props,
|
|
1177
|
-
|
|
1683
|
+
DEFAULT_VALUES11,
|
|
1178
1684
|
"Video"
|
|
1179
1685
|
);
|
|
1180
1686
|
},
|
|
@@ -1202,7 +1708,36 @@ var {
|
|
|
1202
1708
|
var BODY_DEFAULTS = bodyRest;
|
|
1203
1709
|
var ROW_DEFAULTS = { ...exporters.RowDefaults };
|
|
1204
1710
|
var COLUMN_DEFAULTS = { ...exporters.ColumnDefaults };
|
|
1205
|
-
|
|
1711
|
+
|
|
1712
|
+
// src/utils/render-scope.ts
|
|
1713
|
+
var scoped;
|
|
1714
|
+
function scopeCache(key, make) {
|
|
1715
|
+
if (!scoped) return make();
|
|
1716
|
+
if (!scoped.has(key)) scoped.set(key, make());
|
|
1717
|
+
return scoped.get(key);
|
|
1718
|
+
}
|
|
1719
|
+
function withRenderScope(render, own = false) {
|
|
1720
|
+
const scope = () => {
|
|
1721
|
+
if (scoped) return render();
|
|
1722
|
+
scoped = /* @__PURE__ */ new WeakMap();
|
|
1723
|
+
try {
|
|
1724
|
+
return render();
|
|
1725
|
+
} finally {
|
|
1726
|
+
scoped = void 0;
|
|
1727
|
+
}
|
|
1728
|
+
};
|
|
1729
|
+
return withBuild(() => within(null, scope), own);
|
|
1730
|
+
}
|
|
1731
|
+
var warnedLoose = /* @__PURE__ */ new Set();
|
|
1732
|
+
function looseText(child, container) {
|
|
1733
|
+
const text = String(child);
|
|
1734
|
+
if (text.trim() && !warnedLoose.has(container)) {
|
|
1735
|
+
warnedLoose.add(container);
|
|
1736
|
+
console.warn(`${container}: text placed straight in a ${container} shows as text and isn't kept in the editor's design. Put it in a <Paragraph>, or HTML in an <Html> block.`);
|
|
1737
|
+
}
|
|
1738
|
+
return escapeKeepingTags(text, true);
|
|
1739
|
+
}
|
|
1740
|
+
var DEFAULT_VALUES12 = ROW_DEFAULTS;
|
|
1206
1741
|
var DEFAULT_BODY_VALUES = BODY_DEFAULTS;
|
|
1207
1742
|
function getWidthPercentages(cells) {
|
|
1208
1743
|
if (cells.length === 0) return [];
|
|
@@ -1231,8 +1766,8 @@ ${maxQuery} {
|
|
|
1231
1766
|
.u-row { width: 100% !important; }
|
|
1232
1767
|
.u-row .u-col { display: block !important; width: 100% !important; min-width: 320px !important; max-width: 100% !important; }
|
|
1233
1768
|
.u-row .u-col > div { margin: 0 auto; }
|
|
1234
|
-
.no-stack .u-col { min-width: 0 !important; display: table-cell !important; }
|
|
1235
|
-
${widths.map(({ value, className }) => ` .no-stack .u-col-${className} { width: ${value}% !important; }`).join("\n")}
|
|
1769
|
+
.u-row.no-stack .u-col { min-width: 0 !important; display: table-cell !important; }
|
|
1770
|
+
${widths.map(({ value, className }) => ` .u-row.no-stack .u-col-${className} { width: ${value}% !important; }`).join("\n")}
|
|
1236
1771
|
}`;
|
|
1237
1772
|
}
|
|
1238
1773
|
const baseCSS = `
|
|
@@ -1272,17 +1807,18 @@ function renderRowToHtml(innerHTML, values, bodyValues, mode, cells, collection
|
|
|
1272
1807
|
variant: mode
|
|
1273
1808
|
});
|
|
1274
1809
|
const contentWidth = toContentWidthPx(bodyValues);
|
|
1275
|
-
const
|
|
1276
|
-
return
|
|
1810
|
+
const css2 = generateGridCSS(cells, mode, contentWidth);
|
|
1811
|
+
return css2 ? `<style>${css2}</style>${html}` : html;
|
|
1277
1812
|
}
|
|
1278
1813
|
function processChildren(children, cells, bodyValues, rowValues, mode, _config) {
|
|
1279
1814
|
if (!children) return "";
|
|
1280
1815
|
let innerHTML = "";
|
|
1281
|
-
const childrenArray =
|
|
1282
|
-
|
|
1283
|
-
|
|
1816
|
+
const childrenArray = React4__default.default.Children.toArray(children);
|
|
1817
|
+
let index = 0;
|
|
1818
|
+
childrenArray.forEach((child) => {
|
|
1819
|
+
if (!React4__default.default.isValidElement(child)) {
|
|
1284
1820
|
if (typeof child === "string" || typeof child === "number") {
|
|
1285
|
-
innerHTML +=
|
|
1821
|
+
innerHTML += looseText(child, "Row");
|
|
1286
1822
|
}
|
|
1287
1823
|
return;
|
|
1288
1824
|
}
|
|
@@ -1291,7 +1827,7 @@ function processChildren(children, cells, bodyValues, rowValues, mode, _config)
|
|
|
1291
1827
|
if (isColumn && typeof child.type === "function") {
|
|
1292
1828
|
const rendered = child.type({
|
|
1293
1829
|
...child.props,
|
|
1294
|
-
index
|
|
1830
|
+
index: index++,
|
|
1295
1831
|
cells,
|
|
1296
1832
|
bodyValues,
|
|
1297
1833
|
rowValues,
|
|
@@ -1301,7 +1837,7 @@ function processChildren(children, cells, bodyValues, rowValues, mode, _config)
|
|
|
1301
1837
|
if (rendered?.props?.dangerouslySetInnerHTML?.__html) {
|
|
1302
1838
|
innerHTML += rendered.props.dangerouslySetInnerHTML.__html;
|
|
1303
1839
|
}
|
|
1304
|
-
} else if (
|
|
1840
|
+
} else if (React4__default.default.isValidElement(child)) {
|
|
1305
1841
|
const name = child.type?.displayName || child.type?.name || "Unknown";
|
|
1306
1842
|
console.warn(
|
|
1307
1843
|
`Row: <${name}> is not a valid Row child. Only <Column> components can be direct children of <Row>. Wrap it in a <Column>: <Row><Column><${name} /></Column></Row>`
|
|
@@ -1310,7 +1846,7 @@ function processChildren(children, cells, bodyValues, rowValues, mode, _config)
|
|
|
1310
1846
|
});
|
|
1311
1847
|
return innerHTML;
|
|
1312
1848
|
}
|
|
1313
|
-
|
|
1849
|
+
function renderRow(props) {
|
|
1314
1850
|
const {
|
|
1315
1851
|
layout,
|
|
1316
1852
|
cells: propsCells,
|
|
@@ -1325,33 +1861,25 @@ var Row = (props) => {
|
|
|
1325
1861
|
...semanticProps
|
|
1326
1862
|
} = props;
|
|
1327
1863
|
const mode = modeProp ?? _config?.mode ?? "web";
|
|
1864
|
+
const columnCount = React4__default.default.Children.toArray(children).filter(
|
|
1865
|
+
(c) => React4__default.default.isValidElement(c) && /^Column$/.test(c.type?.displayName || c.type?.name || "")
|
|
1866
|
+
).length;
|
|
1328
1867
|
let cells;
|
|
1329
1868
|
if (layout) {
|
|
1330
|
-
validateColumnLayout(layout,
|
|
1869
|
+
if (columnCount !== layout.expectedColumns) validateColumnLayout(layout, React4__default.default.Children.count(children));
|
|
1331
1870
|
cells = layout.cells;
|
|
1332
1871
|
} else if (propsCells) {
|
|
1333
1872
|
cells = propsCells;
|
|
1334
1873
|
} else {
|
|
1335
|
-
const columnCount = React__default.default.Children.toArray(children).filter(
|
|
1336
|
-
(c) => React__default.default.isValidElement(c) && /^Column$/.test(c.type?.displayName || c.type?.name || "")
|
|
1337
|
-
).length;
|
|
1338
1874
|
cells = Array(Math.max(1, columnCount)).fill(1);
|
|
1339
1875
|
}
|
|
1340
1876
|
const safeBodyValues = { ...DEFAULT_BODY_VALUES, ...bodyValues };
|
|
1341
1877
|
const values = mapSemanticProps(
|
|
1342
1878
|
semanticProps,
|
|
1343
|
-
|
|
1879
|
+
DEFAULT_VALUES12,
|
|
1344
1880
|
"Row"
|
|
1345
1881
|
);
|
|
1346
|
-
const valuesWithMeta = {
|
|
1347
|
-
...values,
|
|
1348
|
-
cells,
|
|
1349
|
-
_meta: {
|
|
1350
|
-
htmlID: nextHtmlId(_config, "u_row"),
|
|
1351
|
-
htmlClassNames: "u_row",
|
|
1352
|
-
...values._meta || {}
|
|
1353
|
-
}
|
|
1354
|
-
};
|
|
1882
|
+
const valuesWithMeta = { ...values, cells, _meta: safeMeta({ htmlID: nextHtmlId(_config, "u_row"), htmlClassNames: "u_row", ...values._meta || {} }) };
|
|
1355
1883
|
const innerHTML = processChildren(
|
|
1356
1884
|
children,
|
|
1357
1885
|
cells,
|
|
@@ -1374,11 +1902,12 @@ var Row = (props) => {
|
|
|
1374
1902
|
console.error("Row rendering failed:", error);
|
|
1375
1903
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children });
|
|
1376
1904
|
}
|
|
1377
|
-
}
|
|
1905
|
+
}
|
|
1906
|
+
var Row = (props) => collecting() ? whileCollecting(() => recordContainer("row", props), () => renderRow(props), "Row") : renderRow(props);
|
|
1378
1907
|
Row.displayName = "Row";
|
|
1908
|
+
Row[RECORDS] = true;
|
|
1379
1909
|
var Row_default = Row;
|
|
1380
|
-
var
|
|
1381
|
-
var DEFAULT_VALUES12 = COLUMN_DEFAULTS;
|
|
1910
|
+
var DEFAULT_VALUES13 = COLUMN_DEFAULTS;
|
|
1382
1911
|
function renderColumnToHtml(innerHTML, values, index, cells, bodyValues, rowValues, mode) {
|
|
1383
1912
|
const columnExporter = exporters.ColumnExporters[mode] || exporters.ColumnExporters.web;
|
|
1384
1913
|
return columnExporter(innerHTML, values, index, cells, bodyValues, rowValues);
|
|
@@ -1388,6 +1917,7 @@ function renderContentToHtml(innerHTML, values, bodyValues, mode) {
|
|
|
1388
1917
|
return contentExporter(innerHTML, values, bodyValues, {});
|
|
1389
1918
|
}
|
|
1390
1919
|
var Column = (props) => {
|
|
1920
|
+
if (collecting()) return whileCollecting(() => recordContainer("column", props), () => Column(props), "Column");
|
|
1391
1921
|
const {
|
|
1392
1922
|
children,
|
|
1393
1923
|
index = 0,
|
|
@@ -1403,30 +1933,23 @@ var Column = (props) => {
|
|
|
1403
1933
|
const mode = modeProp ?? _config?.mode ?? "web";
|
|
1404
1934
|
const values = mapSemanticProps(
|
|
1405
1935
|
semanticProps,
|
|
1406
|
-
|
|
1936
|
+
DEFAULT_VALUES13,
|
|
1407
1937
|
"Column"
|
|
1408
1938
|
);
|
|
1409
|
-
const valuesWithMeta = {
|
|
1410
|
-
...values,
|
|
1411
|
-
_meta: {
|
|
1412
|
-
htmlID: nextHtmlId(_config, "u_column"),
|
|
1413
|
-
htmlClassNames: "u_column",
|
|
1414
|
-
...values._meta || {}
|
|
1415
|
-
}
|
|
1416
|
-
};
|
|
1939
|
+
const valuesWithMeta = { ...values, _meta: safeMeta({ htmlID: nextHtmlId(_config, "u_column"), htmlClassNames: "u_column", ...values._meta || {} }) };
|
|
1417
1940
|
let innerHTML = "";
|
|
1418
1941
|
if (children) {
|
|
1419
1942
|
try {
|
|
1420
|
-
const childrenArray =
|
|
1943
|
+
const childrenArray = React4__default.default.Children.toArray(children);
|
|
1421
1944
|
childrenArray.forEach((child, childIndex) => {
|
|
1422
1945
|
if (typeof child === "string" || typeof child === "number") {
|
|
1423
|
-
innerHTML +=
|
|
1424
|
-
} else if (
|
|
1946
|
+
innerHTML += looseText(child, "Column");
|
|
1947
|
+
} else if (React4__default.default.isValidElement(child)) {
|
|
1425
1948
|
if (typeof child.type === "function") {
|
|
1426
1949
|
const ComponentType = child.type;
|
|
1427
1950
|
const renderFn = ComponentType[UNLAYER_RENDER_KEY] || ComponentType;
|
|
1428
|
-
const
|
|
1429
|
-
const contentHtmlId = nextHtmlId(_config, `u_content_${
|
|
1951
|
+
const componentName2 = ComponentType?.[UNLAYER_CONFIG_KEY]?.metaName ?? (ComponentType?.displayName || ComponentType?.name || "component").toLowerCase();
|
|
1952
|
+
const contentHtmlId = nextHtmlId(_config, `u_content_${componentName2}`);
|
|
1430
1953
|
const rendered = renderFn({
|
|
1431
1954
|
...child.props,
|
|
1432
1955
|
_config,
|
|
@@ -1439,14 +1962,28 @@ var Column = (props) => {
|
|
|
1439
1962
|
});
|
|
1440
1963
|
if (rendered && typeof rendered === "object" && rendered.props && rendered.props.dangerouslySetInnerHTML) {
|
|
1441
1964
|
const componentHTML = rendered.props.dangerouslySetInnerHTML.__html;
|
|
1965
|
+
if (!componentHTML && ComponentType?.[UNLAYER_CONFIG_KEY]?.omitEmptyOutput) return;
|
|
1442
1966
|
const childProps = child.props;
|
|
1443
|
-
const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ??
|
|
1967
|
+
const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ?? DEFAULT_CONTAINER_PADDING;
|
|
1444
1968
|
const containerPadding = typeof rawContainerPadding === "number" ? `${rawContainerPadding}px` : rawContainerPadding;
|
|
1969
|
+
const device = ComponentType?.[UNLAYER_CONFIG_KEY]?.contentType === "custom" ? {} : childProps;
|
|
1445
1970
|
const contentValues = {
|
|
1446
1971
|
containerPadding,
|
|
1972
|
+
_override: {
|
|
1973
|
+
...childProps.values?._override,
|
|
1974
|
+
mobile: {
|
|
1975
|
+
...childProps.values?._override?.mobile,
|
|
1976
|
+
...device.hideOnMobile !== void 0 ? { hideMobile: device.hideOnMobile } : {}
|
|
1977
|
+
},
|
|
1978
|
+
desktop: {
|
|
1979
|
+
...childProps.values?._override?.desktop,
|
|
1980
|
+
...device.hideOnDesktop !== void 0 ? { hideDesktop: device.hideOnDesktop } : {}
|
|
1981
|
+
}
|
|
1982
|
+
},
|
|
1447
1983
|
_meta: {
|
|
1448
1984
|
htmlID: contentHtmlId,
|
|
1449
|
-
htmlClassNames: `u_content_${
|
|
1985
|
+
htmlClassNames: `u_content_${componentName2}`,
|
|
1986
|
+
...childProps.values?._meta?.htmlID ? { htmlID: safeName(childProps.values._meta.htmlID) } : {}
|
|
1450
1987
|
}
|
|
1451
1988
|
};
|
|
1452
1989
|
innerHTML += renderContentToHtml(
|
|
@@ -1485,8 +2022,331 @@ var Column = (props) => {
|
|
|
1485
2022
|
}
|
|
1486
2023
|
};
|
|
1487
2024
|
Column.displayName = "Column";
|
|
2025
|
+
Column[RECORDS] = true;
|
|
1488
2026
|
var Column_default = Column;
|
|
1489
|
-
var
|
|
2027
|
+
var KEPT = Symbol.for("@unlayer/react-elements/kept");
|
|
2028
|
+
function parse(html, collection) {
|
|
2029
|
+
const root = [];
|
|
2030
|
+
const open = [root];
|
|
2031
|
+
const pattern = new RegExp(`<${MARK} data-n="${collection.nonce}" data-i="(\\d+)"(?: data-e="([ocf])")?></${MARK}>`, "g");
|
|
2032
|
+
let last = 0;
|
|
2033
|
+
for (const match of html.matchAll(pattern)) {
|
|
2034
|
+
const into = open[open.length - 1];
|
|
2035
|
+
if (match.index > last) into.push({ kind: "raw", html: html.slice(last, match.index) });
|
|
2036
|
+
last = match.index + match[0].length;
|
|
2037
|
+
const at = Number(match[1]);
|
|
2038
|
+
const edge = match[2];
|
|
2039
|
+
if (edge === "o") {
|
|
2040
|
+
const children = [];
|
|
2041
|
+
into.push({ kind: collection.recorded[at].kind, at, children });
|
|
2042
|
+
open.push(children);
|
|
2043
|
+
} else if (edge === "c") open.pop();
|
|
2044
|
+
else into.push({ kind: edge === "f" ? "failed" : "block", at });
|
|
2045
|
+
}
|
|
2046
|
+
if (last < html.length) open[open.length - 1].push({ kind: "raw", html: html.slice(last) });
|
|
2047
|
+
if (open.length !== 1) throw new Error("[Unlayer] a collected render's markers don't pair up");
|
|
2048
|
+
return root;
|
|
2049
|
+
}
|
|
2050
|
+
var TEXT_ENTITIES = { "&": "&", "<": "<", ">": ">", """: '"', "'": "'" };
|
|
2051
|
+
var VOID = /^(area|base|br|col|embed|hr|img|input|link|meta|source|track|wbr)$/i;
|
|
2052
|
+
function parts(html) {
|
|
2053
|
+
const out = [];
|
|
2054
|
+
let at = 0;
|
|
2055
|
+
const text = (s) => s && out.push({ text: s.replace(/&|<|>|"|'/g, (e) => TEXT_ENTITIES[e]) });
|
|
2056
|
+
while (at < html.length) {
|
|
2057
|
+
const start = html.indexOf("<", at);
|
|
2058
|
+
if (start < 0) {
|
|
2059
|
+
text(html.slice(at));
|
|
2060
|
+
break;
|
|
2061
|
+
}
|
|
2062
|
+
text(html.slice(at, start));
|
|
2063
|
+
const name = /^<([a-zA-Z][\w:-]*)/.exec(html.slice(start))?.[1];
|
|
2064
|
+
if (!name) {
|
|
2065
|
+
out.push({ tag: "#", html: html.slice(start) });
|
|
2066
|
+
break;
|
|
2067
|
+
}
|
|
2068
|
+
const openEnd = html.indexOf(">", start);
|
|
2069
|
+
if (VOID.test(name) || html[openEnd - 1] === "/") {
|
|
2070
|
+
out.push({ tag: name, html: html.slice(start, openEnd + 1) });
|
|
2071
|
+
at = openEnd + 1;
|
|
2072
|
+
continue;
|
|
2073
|
+
}
|
|
2074
|
+
const tags = new RegExp(`<(/?)${name}(?=[\\s>/])`, "gi");
|
|
2075
|
+
tags.lastIndex = openEnd + 1;
|
|
2076
|
+
let depth = 1;
|
|
2077
|
+
let end = -1;
|
|
2078
|
+
for (let m = tags.exec(html); m; m = tags.exec(html)) {
|
|
2079
|
+
depth += m[1] ? -1 : 1;
|
|
2080
|
+
if (depth === 0) {
|
|
2081
|
+
end = m.index;
|
|
2082
|
+
break;
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
if (end < 0) {
|
|
2086
|
+
out.push({ tag: "#", html: html.slice(start) });
|
|
2087
|
+
break;
|
|
2088
|
+
}
|
|
2089
|
+
const close = html.indexOf(">", end) + 1;
|
|
2090
|
+
out.push({ tag: name, html: html.slice(start, close), inner: html.slice(openEnd + 1, end) });
|
|
2091
|
+
at = close;
|
|
2092
|
+
}
|
|
2093
|
+
return out;
|
|
2094
|
+
}
|
|
2095
|
+
function innerType(type) {
|
|
2096
|
+
while (type?.$$typeof === MEMO) type = type.type;
|
|
2097
|
+
return type;
|
|
2098
|
+
}
|
|
2099
|
+
var recorded = (c, node) => c.collection.recorded[node.at];
|
|
2100
|
+
var nameOf = (element2) => {
|
|
2101
|
+
if (typeof element2.type === "string") return element2.type;
|
|
2102
|
+
const type = innerType(element2.type);
|
|
2103
|
+
return type?.displayName || type?.name || "component";
|
|
2104
|
+
};
|
|
2105
|
+
function leftOut(c, node) {
|
|
2106
|
+
if (c.fatal) throw c.fatal;
|
|
2107
|
+
if (!c.told.has(node.at)) {
|
|
2108
|
+
c.told.add(node.at);
|
|
2109
|
+
try {
|
|
2110
|
+
tell(recorded(c, node).element);
|
|
2111
|
+
} catch (error) {
|
|
2112
|
+
c.fatal = error;
|
|
2113
|
+
throw error;
|
|
2114
|
+
}
|
|
2115
|
+
}
|
|
2116
|
+
return [];
|
|
2117
|
+
}
|
|
2118
|
+
function calledAgain(element2) {
|
|
2119
|
+
const type = innerType(element2.type);
|
|
2120
|
+
if (type?.$$typeof !== FORWARD_REF && (typeof type !== "function" || type.prototype?.isReactComponent)) return void 0;
|
|
2121
|
+
const props = { ...element2.props };
|
|
2122
|
+
for (const key in type.defaultProps) if (props[key] === void 0) props[key] = type.defaultProps[key];
|
|
2123
|
+
return { out: callIsolated(() => type.$$typeof === FORWARD_REF ? type.render(props, null) : type(props)) };
|
|
2124
|
+
}
|
|
2125
|
+
function tell(element2) {
|
|
2126
|
+
const type = innerType(element2.type);
|
|
2127
|
+
const name = nameOf(element2);
|
|
2128
|
+
const async = () => console.warn(`[Unlayer] <${name}> is async or suspends: Elements renders synchronously, so it's left out. Load its data first and pass it as props.`);
|
|
2129
|
+
if (isAsyncComponent(type)) return async();
|
|
2130
|
+
try {
|
|
2131
|
+
const again = calledAgain(element2);
|
|
2132
|
+
const inner = again ? collected(again.out) : collected(element2, false);
|
|
2133
|
+
const failed = (nodes) => nodes.flatMap((n) => n.kind === "failed" ? [n] : "children" in n ? failed(n.children) : []);
|
|
2134
|
+
const found = failed(inner.nodes);
|
|
2135
|
+
for (const node of found) tell(recorded(inner, node).element);
|
|
2136
|
+
if (!found.length) console.error(`[Unlayer] <${name}> failed while rendering, so it's left out.`);
|
|
2137
|
+
} catch (error) {
|
|
2138
|
+
const message = String(error?.message);
|
|
2139
|
+
if (/Element type is invalid|Objects are not valid as a React child|Minified React error #(130|31)\b/.test(message)) throw error;
|
|
2140
|
+
if (isThenable(error) || /async and suspending|suspended|Minified React error #426\b/.test(message)) async();
|
|
2141
|
+
else console.error(`[Unlayer] <${name}> threw while rendering, so it's left out:`, error);
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
function markupOnly(c, nodes) {
|
|
2145
|
+
let out = "";
|
|
2146
|
+
for (const node of nodes) {
|
|
2147
|
+
if (node.kind === "raw") out += node.html;
|
|
2148
|
+
else if (node.kind === "failed") leftOut(c, node);
|
|
2149
|
+
else if (node.kind !== "boundary") return void 0;
|
|
2150
|
+
else {
|
|
2151
|
+
const inner = markupOnly(c, node.children);
|
|
2152
|
+
if (inner === void 0) return void 0;
|
|
2153
|
+
out += inner;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
return out;
|
|
2157
|
+
}
|
|
2158
|
+
function keptMarkup(c, node) {
|
|
2159
|
+
c.kept ?? (c.kept = /* @__PURE__ */ new Map());
|
|
2160
|
+
if (!c.kept.has(node.at)) c.kept.set(node.at, keptMarkupOnce(c, node));
|
|
2161
|
+
return c.kept.get(node.at);
|
|
2162
|
+
}
|
|
2163
|
+
function keptMarkupOnce(c, node) {
|
|
2164
|
+
const raw = markupOnly(c, node.children);
|
|
2165
|
+
if (raw === void 0) return void 0;
|
|
2166
|
+
const list = parts(raw);
|
|
2167
|
+
if (!list.some((p) => "tag" in p)) return void 0;
|
|
2168
|
+
const element2 = recorded(c, node).element;
|
|
2169
|
+
const one = list.length === 1 || list.some((p) => "tag" in p && p.tag === "#") ? /^<([a-zA-Z][\w:-]*)\b[^>]*>([\s\S]*)<\/\1>$/.exec(raw) : null;
|
|
2170
|
+
let given = false;
|
|
2171
|
+
if (one) {
|
|
2172
|
+
try {
|
|
2173
|
+
const out = calledAgain(element2)?.out;
|
|
2174
|
+
given = React4__default.default.isValidElement(out) && typeof out.type === "string" && out.props.dangerouslySetInnerHTML != null;
|
|
2175
|
+
} catch {
|
|
2176
|
+
given = one[1].toLowerCase() === "div";
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2179
|
+
const html = one && given ? one[2] : raw;
|
|
2180
|
+
const Rendered = () => React4__default.default.createElement("div", { dangerouslySetInnerHTML: { __html: html } });
|
|
2181
|
+
Rendered.displayName = nameOf(element2);
|
|
2182
|
+
const { containerPadding, hideOnMobile, hideOnDesktop } = element2.props ?? {};
|
|
2183
|
+
Rendered[KEPT] = React4__default.default.createElement(Html_default, {
|
|
2184
|
+
html,
|
|
2185
|
+
...containerPadding !== void 0 ? { containerPadding } : {},
|
|
2186
|
+
...hideOnMobile !== void 0 ? { hideOnMobile } : {},
|
|
2187
|
+
...hideOnDesktop !== void 0 ? { hideOnDesktop } : {}
|
|
2188
|
+
});
|
|
2189
|
+
return React4__default.default.createElement(Rendered, { ...element2.props });
|
|
2190
|
+
}
|
|
2191
|
+
function resolvedProps(c, props) {
|
|
2192
|
+
let out = props;
|
|
2193
|
+
for (const [key, value] of Object.entries(props)) {
|
|
2194
|
+
if (typeof value !== "string" || !value.includes(MARK)) continue;
|
|
2195
|
+
let html = value;
|
|
2196
|
+
try {
|
|
2197
|
+
if (value.includes(c.collection.nonce)) html = markup(c, parse(value, c.collection), (block) => within(null, () => renderToStaticMarkup(block)));
|
|
2198
|
+
} catch {
|
|
2199
|
+
}
|
|
2200
|
+
out = out === props ? { ...props } : out;
|
|
2201
|
+
out[key] = withoutMarkers(html, c.collection.nonce);
|
|
2202
|
+
}
|
|
2203
|
+
return out;
|
|
2204
|
+
}
|
|
2205
|
+
function withoutMarkers(html, nonce2) {
|
|
2206
|
+
const left = new RegExp(`<${MARK} data-n="${nonce2}" data-i="\\d+"(?: data-e="[ocf]")?></${MARK}>`, "g");
|
|
2207
|
+
if (!html.includes(nonce2) || !html.match(left)) return html;
|
|
2208
|
+
console.error(`[Unlayer] an Elements block rendered inside a component left a marker behind; it's taken out, and the block it stood for is missing.`);
|
|
2209
|
+
return html.replace(left, "");
|
|
2210
|
+
}
|
|
2211
|
+
function markup(c, nodes, render) {
|
|
2212
|
+
return nodes.map((node) => {
|
|
2213
|
+
switch (node.kind) {
|
|
2214
|
+
case "raw":
|
|
2215
|
+
return node.html;
|
|
2216
|
+
case "boundary":
|
|
2217
|
+
return markup(c, node.children, render);
|
|
2218
|
+
case "failed":
|
|
2219
|
+
leftOut(c, node);
|
|
2220
|
+
return "";
|
|
2221
|
+
default:
|
|
2222
|
+
return render(element(c, node));
|
|
2223
|
+
}
|
|
2224
|
+
}).join("");
|
|
2225
|
+
}
|
|
2226
|
+
var keyed = (list) => list.map((child, i) => React4__default.default.isValidElement(child) && child.key == null ? React4__default.default.cloneElement(child, { key: `k${i}` }) : child);
|
|
2227
|
+
function element(c, node) {
|
|
2228
|
+
const r = recorded(c, node);
|
|
2229
|
+
if (node.kind === "block") return React4__default.default.createElement(r.type, resolvedProps(c, r.props));
|
|
2230
|
+
if (node.kind === "column") return React4__default.default.createElement(Column_default, { ...r.props, children: keyed(elements(c, node.children, "column")) });
|
|
2231
|
+
const props = { ...r.props };
|
|
2232
|
+
const children = keyed(elements(c, node.children, "row"));
|
|
2233
|
+
if (props.layout) {
|
|
2234
|
+
const columns = children.filter((child) => React4__default.default.isValidElement(child) && child.type === Column_default).length;
|
|
2235
|
+
if (columns === props.layout.expectedColumns || React4__default.default.Children.count(props.children) === props.layout.expectedColumns) {
|
|
2236
|
+
props.cells = props.layout.cells;
|
|
2237
|
+
delete props.layout;
|
|
2238
|
+
}
|
|
2239
|
+
}
|
|
2240
|
+
return React4__default.default.createElement(Row_default, { ...props, children });
|
|
2241
|
+
}
|
|
2242
|
+
function spanned(nodes) {
|
|
2243
|
+
const out = [];
|
|
2244
|
+
const spans = [];
|
|
2245
|
+
for (const node of nodes) {
|
|
2246
|
+
if (node.kind !== "raw") {
|
|
2247
|
+
out.push({ node, inside: spans.length > 0 });
|
|
2248
|
+
continue;
|
|
2249
|
+
}
|
|
2250
|
+
const html = node.html;
|
|
2251
|
+
const open = [];
|
|
2252
|
+
let closed = spans.length ? -1 : 0;
|
|
2253
|
+
for (const m of html.matchAll(/<!--[\s\S]*?(?:-->|$)|<(\/?)([a-zA-Z][\w:-]*)\b[^>]*>/g)) {
|
|
2254
|
+
if (!m[2]) continue;
|
|
2255
|
+
const name = m[2].toLowerCase();
|
|
2256
|
+
if (m[1]) {
|
|
2257
|
+
const i = open.map((o) => o.name).lastIndexOf(name);
|
|
2258
|
+
const across = spans.lastIndexOf(name);
|
|
2259
|
+
if (i >= 0) open.length = i;
|
|
2260
|
+
else if (across >= 0) {
|
|
2261
|
+
spans.length = across;
|
|
2262
|
+
open.length = 0;
|
|
2263
|
+
if (!spans.length) closed = m.index + m[0].length;
|
|
2264
|
+
}
|
|
2265
|
+
} else if (!VOID.test(name) && !m[0].endsWith("/>")) open.push({ name, at: m.index });
|
|
2266
|
+
}
|
|
2267
|
+
const piece = (from, to, inside) => {
|
|
2268
|
+
if (to > from) out.push({ node: { kind: "raw", html: html.slice(from, to) }, inside });
|
|
2269
|
+
};
|
|
2270
|
+
if (closed < 0) piece(0, html.length, true);
|
|
2271
|
+
else {
|
|
2272
|
+
piece(0, closed, true);
|
|
2273
|
+
piece(closed, open[0]?.at ?? html.length, false);
|
|
2274
|
+
if (open.length) piece(open[0].at, html.length, true);
|
|
2275
|
+
}
|
|
2276
|
+
spans.push(...open.map((o) => o.name));
|
|
2277
|
+
}
|
|
2278
|
+
return out;
|
|
2279
|
+
}
|
|
2280
|
+
function elements(c, nodes, place, owner, inMarkup = false) {
|
|
2281
|
+
const inColumn = place === "column";
|
|
2282
|
+
return (place === "root" || inMarkup ? nodes.map((node) => ({ node, inside: inMarkup })) : spanned(nodes)).flatMap(({ node, inside }) => {
|
|
2283
|
+
switch (node.kind) {
|
|
2284
|
+
case "failed":
|
|
2285
|
+
return leftOut(c, node);
|
|
2286
|
+
case "boundary": {
|
|
2287
|
+
const kept = inColumn && !inside ? keptMarkup(c, node) : void 0;
|
|
2288
|
+
if (kept) return [kept];
|
|
2289
|
+
const Named = () => null;
|
|
2290
|
+
Named.displayName = nameOf(recorded(c, node).element);
|
|
2291
|
+
if (inColumn && !inside && !c.told.has(node.at) && node.children.some((n) => n.kind === "raw" && parts(n.html).some((p) => "tag" in p))) {
|
|
2292
|
+
c.told.add(node.at);
|
|
2293
|
+
console.warn(`Column: <${Named.displayName}> rendered markup that isn't a block, so it's left out. Put HTML in an <Html> block.`);
|
|
2294
|
+
}
|
|
2295
|
+
return elements(c, node.children, place, Named, inside);
|
|
2296
|
+
}
|
|
2297
|
+
case "raw":
|
|
2298
|
+
if (inside) {
|
|
2299
|
+
const name = /^<([a-zA-Z][\w:-]*)/.exec(node.html)?.[1];
|
|
2300
|
+
return place === "row" && name && !inMarkup ? [React4__default.default.createElement(owner ?? name)] : [];
|
|
2301
|
+
}
|
|
2302
|
+
return parts(node.html).flatMap((p) => "text" in p ? [p.text] : inColumn ? [] : [React4__default.default.createElement(owner ?? (p.tag === "#" ? "div" : p.tag))]);
|
|
2303
|
+
default:
|
|
2304
|
+
return [element(c, node)];
|
|
2305
|
+
}
|
|
2306
|
+
});
|
|
2307
|
+
}
|
|
2308
|
+
function collected(children, guarded2 = true) {
|
|
2309
|
+
const once = (markup2) => {
|
|
2310
|
+
const collection = { nonce: nonce(), recorded: [], ...markup2 ? { markup: markup2 } : {}, ...idsSeen() ? {} : { blind: true } };
|
|
2311
|
+
const html = within(collection, () => renderToStaticMarkup(/* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: guarded2 ? guard(children, collection) : children }), { identifierPrefix: COLLECTING_ID }));
|
|
2312
|
+
return { nodes: parse(html, collection), collection, told: /* @__PURE__ */ new Set() };
|
|
2313
|
+
};
|
|
2314
|
+
try {
|
|
2315
|
+
return once(false);
|
|
2316
|
+
} catch (error) {
|
|
2317
|
+
if (!guarded2) throw error;
|
|
2318
|
+
return once(true);
|
|
2319
|
+
}
|
|
2320
|
+
}
|
|
2321
|
+
function idsSeen() {
|
|
2322
|
+
let seen = false;
|
|
2323
|
+
const Probe = () => {
|
|
2324
|
+
try {
|
|
2325
|
+
seen = React4__default.default.useId().slice(1).startsWith(COLLECTING_ID);
|
|
2326
|
+
} catch {
|
|
2327
|
+
}
|
|
2328
|
+
return null;
|
|
2329
|
+
};
|
|
2330
|
+
renderToStaticMarkup(/* @__PURE__ */ jsxRuntime.jsx(Probe, {}), { identifierPrefix: COLLECTING_ID });
|
|
2331
|
+
return seen;
|
|
2332
|
+
}
|
|
2333
|
+
function nonce() {
|
|
2334
|
+
const random = globalThis.crypto?.getRandomValues?.(new Uint32Array(2));
|
|
2335
|
+
return random ? Array.from(random, (n) => n.toString(36)).join("") : `${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;
|
|
2336
|
+
}
|
|
2337
|
+
var collect = (children) => children !== null && typeof children === "object" ? scopeCache(children, () => collected(children)) : collected(children);
|
|
2338
|
+
function childrenHtml2(children, place) {
|
|
2339
|
+
const c = collect(children);
|
|
2340
|
+
return withoutMarkers(markup(c, c.nodes, (child) => within(null, () => renderToString(place(child)))), c.collection.nonce);
|
|
2341
|
+
}
|
|
2342
|
+
function normalizedChildren(children) {
|
|
2343
|
+
const c = collect(children);
|
|
2344
|
+
return elements(c, c.nodes, "root");
|
|
2345
|
+
}
|
|
2346
|
+
function normalizedRoot(root) {
|
|
2347
|
+
return React4__default.default.cloneElement(root, void 0, ...normalizedChildren(root.props.children));
|
|
2348
|
+
}
|
|
2349
|
+
var DEFAULT_VALUES14 = BODY_DEFAULTS;
|
|
1490
2350
|
var MAX_PREVIEW_LENGTH = 150;
|
|
1491
2351
|
var PADDING_CHARS = [
|
|
1492
2352
|
"\xA0",
|
|
@@ -1497,6 +2357,9 @@ var PADDING_CHARS = [
|
|
|
1497
2357
|
"\u200F",
|
|
1498
2358
|
"\uFEFF"
|
|
1499
2359
|
];
|
|
2360
|
+
function escapePreviewText(text) {
|
|
2361
|
+
return text.split(/(<%[\w.]+%>)/).map((part, i) => i % 2 ? part : part.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")).join("");
|
|
2362
|
+
}
|
|
1500
2363
|
function generatePreviewHtml(text) {
|
|
1501
2364
|
if (!text || text.trim().length === 0) return "";
|
|
1502
2365
|
const truncated = text.length > MAX_PREVIEW_LENGTH ? text.slice(0, MAX_PREVIEW_LENGTH) : text;
|
|
@@ -1505,7 +2368,7 @@ function generatePreviewHtml(text) {
|
|
|
1505
2368
|
for (let i = 0; i < paddingLength; i++) {
|
|
1506
2369
|
padding += PADDING_CHARS[i % PADDING_CHARS.length];
|
|
1507
2370
|
}
|
|
1508
|
-
return `<div data-skip-in-text="true" style="display:none;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;">` + truncated + padding + `</div>`;
|
|
2371
|
+
return `<div data-skip-in-text="true" style="display:none;font-size:1px;color:#ffffff;line-height:1px;max-height:0px;max-width:0px;opacity:0;overflow:hidden;">` + escapePreviewText(truncated) + padding + `</div>`;
|
|
1509
2372
|
}
|
|
1510
2373
|
function renderBodyToHtml(innerHTML, values, mode, previewText) {
|
|
1511
2374
|
let finalInnerHtml = innerHTML;
|
|
@@ -1526,14 +2389,14 @@ function renderBodyToHtml(innerHTML, values, mode, previewText) {
|
|
|
1526
2389
|
return raw.replace("min-height: 100vh; ", "").replace("min-height: 100vh;", "");
|
|
1527
2390
|
}
|
|
1528
2391
|
var Body = (props) => {
|
|
1529
|
-
const { children, mode: modeProp, className, style, index = 0, config: configProp, previewText, ...semanticProps } = props;
|
|
2392
|
+
const { children, mode: modeProp, className, style, index = 0, config: configProp, previewText, fonts: _fonts, lang: _lang, ...semanticProps } = props;
|
|
1530
2393
|
const resolvedConfig = { ...DEFAULT_CONFIG, ...configProp };
|
|
1531
2394
|
const mode = modeProp ?? resolvedConfig.mode ?? "web";
|
|
1532
2395
|
const _config = { ...resolvedConfig, mode };
|
|
1533
2396
|
_config.__ids = {};
|
|
1534
2397
|
const values = mergeValues(
|
|
1535
|
-
|
|
1536
|
-
mapSemanticProps(semanticProps,
|
|
2398
|
+
DEFAULT_VALUES14,
|
|
2399
|
+
mapSemanticProps(semanticProps, DEFAULT_VALUES14, "Body")
|
|
1537
2400
|
);
|
|
1538
2401
|
const valuesWithMeta = {
|
|
1539
2402
|
...values,
|
|
@@ -1543,22 +2406,12 @@ var Body = (props) => {
|
|
|
1543
2406
|
...values._meta || {}
|
|
1544
2407
|
}
|
|
1545
2408
|
};
|
|
1546
|
-
let enrichedChildren = children;
|
|
1547
|
-
if (children) {
|
|
1548
|
-
enrichedChildren = React__default.default.Children.map(children, (child) => {
|
|
1549
|
-
if (React__default.default.isValidElement(child)) {
|
|
1550
|
-
return React__default.default.cloneElement(child, {
|
|
1551
|
-
_config,
|
|
1552
|
-
bodyValues: values
|
|
1553
|
-
});
|
|
1554
|
-
}
|
|
1555
|
-
return child;
|
|
1556
|
-
});
|
|
1557
|
-
}
|
|
1558
2409
|
let innerHTML = "";
|
|
1559
|
-
if (
|
|
2410
|
+
if (children) {
|
|
1560
2411
|
try {
|
|
1561
|
-
innerHTML =
|
|
2412
|
+
innerHTML = withRenderScope(() => {
|
|
2413
|
+
return childrenHtml2(children, (child) => React4__default.default.cloneElement(child, { _config, bodyValues: values }));
|
|
2414
|
+
}, true);
|
|
1562
2415
|
} catch (error) {
|
|
1563
2416
|
console.error("Body: Failed to render children:", error);
|
|
1564
2417
|
innerHTML = "";
|
|
@@ -1597,7 +2450,7 @@ var PROVIDER_ACTIVE_KEY = "__unlayerProviderActive";
|
|
|
1597
2450
|
var _UnlayerContext = null;
|
|
1598
2451
|
function getUnlayerContext() {
|
|
1599
2452
|
if (!_UnlayerContext) {
|
|
1600
|
-
_UnlayerContext =
|
|
2453
|
+
_UnlayerContext = React4.createContext(DEFAULT_CONFIG);
|
|
1601
2454
|
}
|
|
1602
2455
|
return _UnlayerContext;
|
|
1603
2456
|
}
|
|
@@ -1605,7 +2458,7 @@ var UnlayerProvider = ({
|
|
|
1605
2458
|
config,
|
|
1606
2459
|
children
|
|
1607
2460
|
}) => {
|
|
1608
|
-
const merged =
|
|
2461
|
+
const merged = React4.useMemo(
|
|
1609
2462
|
() => ({ ...DEFAULT_CONFIG, ...config, [PROVIDER_ACTIVE_KEY]: true }),
|
|
1610
2463
|
[config]
|
|
1611
2464
|
);
|
|
@@ -1614,31 +2467,106 @@ var UnlayerProvider = ({
|
|
|
1614
2467
|
};
|
|
1615
2468
|
UnlayerProvider.displayName = "UnlayerProvider";
|
|
1616
2469
|
function useUnlayerConfig() {
|
|
1617
|
-
return
|
|
2470
|
+
return React4.useContext(getUnlayerContext());
|
|
1618
2471
|
}
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
2472
|
+
|
|
2473
|
+
// src/utils/device-overrides.ts
|
|
2474
|
+
var contentOptions = {
|
|
2475
|
+
Button: ["size", "fontSize", "lineHeight", "textAlign", "padding"],
|
|
2476
|
+
Image: ["src", "textAlign"],
|
|
2477
|
+
Heading: ["fontSize", "textAlign", "lineHeight"],
|
|
2478
|
+
Paragraph: ["fontSize", "textAlign", "lineHeight"],
|
|
2479
|
+
Menu: ["fontSize", "padding"],
|
|
2480
|
+
Divider: ["width", "textAlign"]
|
|
2481
|
+
};
|
|
2482
|
+
function css(value) {
|
|
2483
|
+
const text = String(value).trim();
|
|
2484
|
+
return text && !/[!\\"'\n\r]/.test(text) && cssValueSafe(text) ? text : void 0;
|
|
2485
|
+
}
|
|
2486
|
+
function ident(id) {
|
|
2487
|
+
return id.replace(/^-?\d|^-$|[^\w\u0080-\uffff-]/g, (c) => /\d/.test(c.slice(-1)) ? `${c.slice(0, -1)}\\${c.slice(-1).charCodeAt(0).toString(16)} ` : `\\${c}`);
|
|
2488
|
+
}
|
|
2489
|
+
function size(value) {
|
|
2490
|
+
const number = parseFloat(String(value));
|
|
2491
|
+
if (!Number.isFinite(number)) return;
|
|
2492
|
+
const rounded = parseFloat(number.toFixed(2));
|
|
2493
|
+
if (typeof value === "number" || String(value).endsWith("px")) return `${rounded}px`;
|
|
2494
|
+
if (String(value).endsWith("%")) return `${rounded}%`;
|
|
2495
|
+
}
|
|
2496
|
+
function collectDeviceStyles(values, collection, name, mode, styles) {
|
|
2497
|
+
const given = safeName(values._meta?.htmlID);
|
|
2498
|
+
if (!given) return;
|
|
2499
|
+
const id = ident(given);
|
|
2500
|
+
const options = collection === "contents" ? ["containerPadding", ...contentOptions[name] || []] : collection === "columns" ? ["padding", "border"] : ["padding"];
|
|
2501
|
+
for (const device of mode === "document" ? ["desktop"] : ["desktop", "mobile"]) {
|
|
2502
|
+
const overrides = values._override?.[device];
|
|
2503
|
+
if (!overrides) continue;
|
|
2504
|
+
for (const option of options) {
|
|
2505
|
+
if (!(option in overrides)) continue;
|
|
2506
|
+
const value = overrides[option];
|
|
2507
|
+
const property = option.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`);
|
|
2508
|
+
const prefix = collection === "rows" ? "row-" : collection === "columns" ? "col-" : "";
|
|
2509
|
+
const selector = (attribute) => `#${id} .v-${prefix}${property === attribute ? property : `${property}-${attribute}`}`;
|
|
2510
|
+
const push = (rule) => (styles[device] || (styles[device] = [])).push(rule);
|
|
2511
|
+
if (option === "padding" || option === "containerPadding") {
|
|
2512
|
+
if (!(value || value === 0) || css(value) === void 0) continue;
|
|
2513
|
+
const direct = collection === "rows" || mode === "web" && collection === "contents" && option === "containerPadding";
|
|
2514
|
+
const target = direct ? selector("padding").replace(`#${id} `, `#${id}`) : selector("padding");
|
|
2515
|
+
push(`${target} { padding: ${css(value)} !important; }`);
|
|
2516
|
+
if (mode === "email" && collection === "rows") {
|
|
2517
|
+
const parts2 = String(value).trim().split(/\s+/);
|
|
2518
|
+
const [top, bottom] = [parts2[0], parts2[2] || parts2[0]].map((part) => size(part) ?? css(part));
|
|
2519
|
+
if (top !== void 0 && bottom !== void 0) push(`${target}--vertical { padding-top: ${top} !important; padding-bottom: ${bottom} !important; }`);
|
|
2520
|
+
}
|
|
2521
|
+
} else if (option === "border") {
|
|
2522
|
+
if (value) push(`${selector("border")} { ${["Top", "Left", "Right", "Bottom"].map((d) => {
|
|
2523
|
+
const w = css(value[`border${d}Width`] || "0px") ?? "0px";
|
|
2524
|
+
return `border-${d.toLowerCase()}: ${w} ${css(value[`border${d}Style`] || "solid") ?? "solid"} ${parseInt(w) > 0 && css(value[`border${d}Color`]) || "transparent"} !important;`;
|
|
2525
|
+
}).join("")} }`);
|
|
2526
|
+
} else if (option === "src") {
|
|
2527
|
+
if (!value) continue;
|
|
2528
|
+
const merged = { ...values.src, ...value };
|
|
2529
|
+
const maximum = merged.autoWidth === false ? size(merged.maxWidth) : void 0;
|
|
2530
|
+
push(`${selector("width")} { width: ${maximum || "100%"} !important; }`);
|
|
2531
|
+
push(`${selector("max-width")} { max-width: ${size(maximum || merged.width || "100%")} !important; }`);
|
|
2532
|
+
} else if (option === "size" || option === "width") {
|
|
2533
|
+
if (!value) continue;
|
|
2534
|
+
push(`${selector("width")} { width: ${size(value.width) && !value.autoWidth ? size(value.width) : "auto"} !important; }`);
|
|
2535
|
+
push(`${selector("max-width")} { max-width: 100% !important; }`);
|
|
2536
|
+
} else {
|
|
2537
|
+
if (!(value || option === "lineHeight" && `${value}` === "0")) continue;
|
|
2538
|
+
const rendered = css(option === "fontSize" && typeof value === "number" ? `${value}px` : value);
|
|
2539
|
+
if (rendered === void 0) continue;
|
|
2540
|
+
push(`${selector(property)} { ${property}: ${rendered} !important; }`);
|
|
2541
|
+
}
|
|
1626
2542
|
}
|
|
1627
|
-
}
|
|
2543
|
+
}
|
|
1628
2544
|
}
|
|
1629
|
-
function
|
|
1630
|
-
|
|
1631
|
-
|
|
2545
|
+
function deviceStylesCss(styles, mode) {
|
|
2546
|
+
return Object.entries(styles).filter(([, rules]) => rules.length).map(([device, rules]) => {
|
|
2547
|
+
const query = device === "mobile" ? "@media (max-width: 480px)" : `@media (min-width: ${mode === "document" ? 1 : 481}px)`;
|
|
2548
|
+
return `${query} { ${rules.join(" ")} }`;
|
|
2549
|
+
}).join("\n");
|
|
1632
2550
|
}
|
|
1633
|
-
function
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
2551
|
+
function deviceVisibilityCss(mode) {
|
|
2552
|
+
if (mode === "document") return "";
|
|
2553
|
+
const extra = mode === "email" ? "max-height: 0px; overflow: hidden; " : "";
|
|
2554
|
+
const reset = mode === "email" ? "@media (min-width: 0px) { .hide-default__display-block { display: block !important; mso-hide: unset !important; } .hide-default__display-table { display: table !important; mso-hide: unset !important; } }\n" : "";
|
|
2555
|
+
return reset + `@media (max-width: 480px) { .hide-mobile { ${extra}display: none !important; } }
|
|
2556
|
+
@media (min-width: 481px) { .hide-desktop { ${extra}display: none !important; } }`;
|
|
2557
|
+
}
|
|
2558
|
+
var schemaVersion = exporters.schemaVersion ?? 24;
|
|
2559
|
+
function unwrapForJson(element2) {
|
|
2560
|
+
try {
|
|
2561
|
+
return unwrapRoot(element2);
|
|
2562
|
+
} catch (cause) {
|
|
2563
|
+
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
2564
|
+
throw new Error(
|
|
2565
|
+
`[Unlayer] renderToJson: could not unwrap <${componentName(element2) || "wrapper"}>. ${UNWRAP_ADVICE} (${detail})`
|
|
2566
|
+
);
|
|
2567
|
+
}
|
|
1641
2568
|
}
|
|
2569
|
+
var collectChildren = (node) => React4__default.default.Children.toArray(node).filter(React4__default.default.isValidElement);
|
|
1642
2570
|
function extractSemanticProps(props, extraKeys = []) {
|
|
1643
2571
|
const internalKeys = /* @__PURE__ */ new Set([
|
|
1644
2572
|
"children",
|
|
@@ -1653,6 +2581,8 @@ function extractSemanticProps(props, extraKeys = []) {
|
|
|
1653
2581
|
"_config",
|
|
1654
2582
|
"config",
|
|
1655
2583
|
"previewText",
|
|
2584
|
+
"fonts",
|
|
2585
|
+
"lang",
|
|
1656
2586
|
"layout",
|
|
1657
2587
|
"collection",
|
|
1658
2588
|
...extraKeys
|
|
@@ -1669,68 +2599,313 @@ function nextCounter(counters, key) {
|
|
|
1669
2599
|
counters[key] = (counters[key] || 0) + 1;
|
|
1670
2600
|
return counters[key];
|
|
1671
2601
|
}
|
|
1672
|
-
function
|
|
1673
|
-
if (
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
2602
|
+
function toContentType(displayName) {
|
|
2603
|
+
if (displayName === "Paragraph") return "text";
|
|
2604
|
+
return displayName.toLowerCase();
|
|
2605
|
+
}
|
|
2606
|
+
function makeId(prefix, counter) {
|
|
2607
|
+
return `${prefix}_${counter}`;
|
|
2608
|
+
}
|
|
2609
|
+
function extractTextFromTextJson(textJson) {
|
|
2610
|
+
try {
|
|
2611
|
+
const parsed = JSON.parse(textJson);
|
|
2612
|
+
if (parsed.__html) return parsed.__html;
|
|
2613
|
+
const root = parsed?.root;
|
|
2614
|
+
if (!root?.children) return "";
|
|
2615
|
+
const paragraphs = [];
|
|
2616
|
+
for (const paragraph of root.children) {
|
|
2617
|
+
if (!paragraph?.children) continue;
|
|
2618
|
+
const parts2 = [];
|
|
2619
|
+
for (const node of paragraph.children) {
|
|
2620
|
+
if (node?.text) parts2.push(node.text);
|
|
2621
|
+
}
|
|
2622
|
+
paragraphs.push(parts2.join(""));
|
|
2623
|
+
}
|
|
2624
|
+
return paragraphs.join("\n");
|
|
2625
|
+
} catch {
|
|
2626
|
+
return "";
|
|
2627
|
+
}
|
|
2628
|
+
}
|
|
2629
|
+
function processItem(element2, counters, layout = {}, metaName) {
|
|
2630
|
+
const componentType = element2.type;
|
|
2631
|
+
const config = componentType[UNLAYER_CONFIG_KEY];
|
|
2632
|
+
if (!config && componentType?.[KEPT]) {
|
|
2633
|
+
return processItem(componentType[KEPT], counters, layout, (componentType.displayName || componentType.name || "component").toLowerCase());
|
|
2634
|
+
}
|
|
2635
|
+
if (!config) {
|
|
2636
|
+
const name2 = componentName(element2) || "Unknown";
|
|
2637
|
+
throw new Error(
|
|
2638
|
+
`[Unlayer] renderToJson: <${name2}> is not a recognized Unlayer item component. Only components created with createItemComponent are supported.`
|
|
2639
|
+
);
|
|
2640
|
+
}
|
|
2641
|
+
const { name, defaultValues, propMapper, slug } = config;
|
|
2642
|
+
const contentType = config.contentType ?? toContentType(name);
|
|
2643
|
+
const metaBase = `u_content_${metaName ?? config.metaName ?? contentType}`;
|
|
2644
|
+
const count = nextCounter(counters, metaBase);
|
|
2645
|
+
const id = makeId(metaBase, count);
|
|
2646
|
+
const { children, ...restProps } = element2.props;
|
|
2647
|
+
const mappedValues = propMapper({ children, ...restProps });
|
|
2648
|
+
const finalValues = mergeValues(defaultValues, mappedValues);
|
|
2649
|
+
if (contentType === "text" && finalValues.textJson) {
|
|
2650
|
+
finalValues.text = extractTextFromTextJson(finalValues.textJson);
|
|
2651
|
+
delete finalValues.textJson;
|
|
2652
|
+
}
|
|
2653
|
+
const values = {
|
|
2654
|
+
containerPadding: "10px",
|
|
2655
|
+
...finalValues,
|
|
2656
|
+
_meta: {
|
|
2657
|
+
htmlID: id,
|
|
2658
|
+
htmlClassNames: metaBase,
|
|
2659
|
+
...finalValues._meta || {}
|
|
2660
|
+
},
|
|
2661
|
+
selectable: true,
|
|
2662
|
+
draggable: true,
|
|
2663
|
+
duplicatable: true,
|
|
2664
|
+
deletable: true,
|
|
2665
|
+
hideable: true
|
|
2666
|
+
};
|
|
2667
|
+
const itemSrc = values.src;
|
|
2668
|
+
if (itemSrc && typeof itemSrc === "object" && itemSrc.autoWidth === false) {
|
|
2669
|
+
const availableWidth = contentSlotWidth({
|
|
2670
|
+
...layout,
|
|
2671
|
+
containerPadding: values.containerPadding
|
|
2672
|
+
});
|
|
2673
|
+
values.src = pinImageSrc(itemSrc, availableWidth);
|
|
2674
|
+
}
|
|
2675
|
+
return slug ? { type: contentType, slug, values } : { type: contentType, values };
|
|
2676
|
+
}
|
|
2677
|
+
function processColumn(element2, counters, layout = {}) {
|
|
2678
|
+
const count = nextCounter(counters, "u_column");
|
|
2679
|
+
const id = makeId("u_column", count);
|
|
2680
|
+
const semanticProps = extractSemanticProps(element2.props);
|
|
2681
|
+
const mapped = mapSemanticProps(semanticProps, COLUMN_DEFAULTS, "Column");
|
|
2682
|
+
const values = mergeValues(COLUMN_DEFAULTS, mapped);
|
|
2683
|
+
const valuesWithMeta = {
|
|
2684
|
+
...values,
|
|
2685
|
+
_meta: {
|
|
2686
|
+
htmlID: id,
|
|
2687
|
+
htmlClassNames: "u_column",
|
|
2688
|
+
...values._meta || {}
|
|
2689
|
+
}
|
|
2690
|
+
};
|
|
2691
|
+
const contents = [];
|
|
2692
|
+
const children = collectChildren(element2.props.children);
|
|
2693
|
+
const itemLayout = { ...layout, columnValues: valuesWithMeta };
|
|
2694
|
+
for (const child of children) {
|
|
2695
|
+
contents.push(processItem(child, counters, itemLayout));
|
|
2696
|
+
}
|
|
2697
|
+
return { contents, values: valuesWithMeta };
|
|
2698
|
+
}
|
|
2699
|
+
function processRow(element2, counters, parentLayout = {}) {
|
|
2700
|
+
const count = nextCounter(counters, "u_row");
|
|
2701
|
+
const id = makeId("u_row", count);
|
|
2702
|
+
const { layout, cells: propsCells } = element2.props;
|
|
2703
|
+
let cells;
|
|
2704
|
+
if (layout) {
|
|
2705
|
+
cells = layout.cells;
|
|
2706
|
+
} else if (propsCells) {
|
|
2707
|
+
cells = propsCells;
|
|
2708
|
+
} else {
|
|
2709
|
+
const columnCount = Math.max(
|
|
2710
|
+
1,
|
|
2711
|
+
collectChildren(element2.props.children).filter(
|
|
2712
|
+
(child) => getDisplayName(child) === "Column"
|
|
2713
|
+
).length
|
|
2714
|
+
);
|
|
2715
|
+
cells = Array(columnCount).fill(1);
|
|
2716
|
+
}
|
|
2717
|
+
const semanticProps = extractSemanticProps(element2.props, ["layout"]);
|
|
2718
|
+
const mapped = mapSemanticProps(semanticProps, ROW_DEFAULTS, "Row");
|
|
2719
|
+
const values = mergeValues(ROW_DEFAULTS, mapped);
|
|
2720
|
+
const valuesWithMeta = {
|
|
2721
|
+
...values,
|
|
2722
|
+
columns: values.columns ?? false,
|
|
2723
|
+
cells,
|
|
2724
|
+
_meta: {
|
|
2725
|
+
htmlID: id,
|
|
2726
|
+
htmlClassNames: "u_row",
|
|
2727
|
+
...values._meta || {}
|
|
2728
|
+
},
|
|
2729
|
+
selectable: true,
|
|
2730
|
+
draggable: true,
|
|
2731
|
+
duplicatable: true,
|
|
2732
|
+
deletable: true,
|
|
2733
|
+
hideable: true
|
|
2734
|
+
};
|
|
2735
|
+
const columns = [];
|
|
2736
|
+
const children = collectChildren(element2.props.children);
|
|
2737
|
+
const columnLayout = {
|
|
2738
|
+
bodyValues: parentLayout.bodyValues,
|
|
2739
|
+
rowValues: valuesWithMeta,
|
|
2740
|
+
rowCells: cells
|
|
2741
|
+
};
|
|
2742
|
+
let columnIndex = 0;
|
|
2743
|
+
for (const child of children) {
|
|
2744
|
+
const name = getDisplayName(child);
|
|
2745
|
+
if (name === "Column") {
|
|
2746
|
+
columns.push(
|
|
2747
|
+
processColumn(child, counters, { ...columnLayout, columnIndex })
|
|
2748
|
+
);
|
|
2749
|
+
columnIndex += 1;
|
|
2750
|
+
} else {
|
|
2751
|
+
console.warn(
|
|
2752
|
+
`[Unlayer] renderToJson: <${componentName(child) ?? String(child.type)}> is not a valid Row child. Only <Column> is allowed.`
|
|
2753
|
+
);
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2756
|
+
return { cells, columns, values: valuesWithMeta };
|
|
2757
|
+
}
|
|
2758
|
+
function processBody(element2, counters) {
|
|
2759
|
+
const id = "u_body";
|
|
2760
|
+
const semanticProps = extractSemanticProps(element2.props);
|
|
2761
|
+
const mapped = mapSemanticProps(semanticProps, BODY_DEFAULTS, "Body");
|
|
2762
|
+
const values = mergeValues(BODY_DEFAULTS, mapped);
|
|
2763
|
+
if ("textDirection" in values) {
|
|
2764
|
+
const direction = textDirectionOf(values.textDirection);
|
|
2765
|
+
if (direction) values.textDirection = direction;
|
|
2766
|
+
else delete values.textDirection;
|
|
2767
|
+
}
|
|
2768
|
+
const previewText = element2.props.previewText;
|
|
2769
|
+
if (previewText !== void 0) {
|
|
2770
|
+
values.preheaderText = previewText;
|
|
2771
|
+
}
|
|
2772
|
+
const valuesWithMeta = {
|
|
2773
|
+
...values,
|
|
2774
|
+
_meta: {
|
|
2775
|
+
htmlID: id,
|
|
2776
|
+
htmlClassNames: "u_body",
|
|
2777
|
+
...values._meta || {}
|
|
2778
|
+
}
|
|
2779
|
+
};
|
|
2780
|
+
const rows = [];
|
|
2781
|
+
const children = collectChildren(element2.props.children);
|
|
2782
|
+
for (const child of children) {
|
|
2783
|
+
const name = getDisplayName(child);
|
|
2784
|
+
if (name === "Row") {
|
|
2785
|
+
rows.push(processRow(child, counters, { bodyValues: valuesWithMeta }));
|
|
2786
|
+
} else {
|
|
2787
|
+
console.warn(
|
|
2788
|
+
`[Unlayer] renderToJson: <${componentName(child) ?? String(child.type)}> is not a valid Body child. Only <Row> is allowed.`
|
|
2789
|
+
);
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
return {
|
|
2793
|
+
rows,
|
|
2794
|
+
values: valuesWithMeta
|
|
2795
|
+
};
|
|
2796
|
+
}
|
|
2797
|
+
function renderRowToJson(element2) {
|
|
2798
|
+
const displayName = getDisplayName(element2);
|
|
2799
|
+
if (displayName !== "Row") {
|
|
2800
|
+
throw new Error(
|
|
2801
|
+
`[Unlayer] renderRowToJson: Element must be <Row>, but got <${componentName(element2) || "unknown"}>. For full designs, use renderToJson instead.`
|
|
2802
|
+
);
|
|
2803
|
+
}
|
|
2804
|
+
const counters = {};
|
|
2805
|
+
return withRenderScope(() => processRow(normalizedChildren(element2).find((c) => React4__default.default.isValidElement(c)) ?? element2, counters));
|
|
2806
|
+
}
|
|
2807
|
+
function renderToJson(element2) {
|
|
2808
|
+
return withRenderScope(() => designJson(element2));
|
|
2809
|
+
}
|
|
2810
|
+
function designJson(element2) {
|
|
2811
|
+
element2 = unwrapForJson(element2);
|
|
2812
|
+
const displayName = getDisplayName(element2);
|
|
2813
|
+
if (displayName && ROOT_NAMES.has(displayName)) element2 = normalizedRoot(element2);
|
|
2814
|
+
if (!displayName || !ROOT_NAMES.has(displayName)) {
|
|
2815
|
+
throw new Error(
|
|
2816
|
+
`[Unlayer] renderToJson: Root element must be <Body>, <Email>, <Page>, or <Document>, but got <${componentName(element2) || "unknown"}>. Wrap your content: <Body><Row><Column>...</Column></Row></Body>`
|
|
2817
|
+
);
|
|
2818
|
+
}
|
|
2819
|
+
const counters = {};
|
|
2820
|
+
const body = processBody(element2, counters);
|
|
2821
|
+
return {
|
|
2822
|
+
counters,
|
|
2823
|
+
body,
|
|
2824
|
+
schemaVersion
|
|
2825
|
+
};
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2828
|
+
// src/utils/extract-head.ts
|
|
2829
|
+
function ensureMeta(values, type, index = 0) {
|
|
2830
|
+
return {
|
|
2831
|
+
...values,
|
|
2832
|
+
_meta: {
|
|
2833
|
+
htmlID: `${["row", "column"].includes(type) ? "u" : "u_content"}_${type.toLowerCase()}_${index + 1}`,
|
|
2834
|
+
htmlClassNames: `u_content_${type.toLowerCase()}`,
|
|
2835
|
+
...values._meta || {}
|
|
2836
|
+
}
|
|
2837
|
+
};
|
|
2838
|
+
}
|
|
2839
|
+
var collectChildren2 = (node) => React4__default.default.Children.toArray(node).filter(React4__default.default.isValidElement);
|
|
2840
|
+
function callHead(head, values, bodyValues, displayMode, headConfig, styles, scripts, tags) {
|
|
2841
|
+
if (!head) return;
|
|
2842
|
+
const headArgs = [
|
|
2843
|
+
values,
|
|
2844
|
+
bodyValues,
|
|
2845
|
+
{
|
|
2846
|
+
displayMode,
|
|
2847
|
+
isViewer: false,
|
|
2848
|
+
variant: null,
|
|
2849
|
+
type: "rows",
|
|
2850
|
+
headConfig
|
|
2851
|
+
}
|
|
2852
|
+
];
|
|
2853
|
+
const css2 = head.css?.(...headArgs);
|
|
2854
|
+
if (css2) styles.push(css2);
|
|
2855
|
+
const js = head.js?.(...headArgs);
|
|
1688
2856
|
if (js) scripts.push(js);
|
|
1689
2857
|
const headTags = head.tags?.(...headArgs);
|
|
1690
2858
|
if (headTags) tags.push(...headTags);
|
|
1691
2859
|
}
|
|
1692
|
-
function walkItem(
|
|
1693
|
-
const componentType =
|
|
2860
|
+
function walkItem(element2, bodyValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles) {
|
|
2861
|
+
const componentType = element2.type;
|
|
1694
2862
|
const config = componentType[UNLAYER_CONFIG_KEY];
|
|
1695
|
-
if (!config)
|
|
2863
|
+
if (!config) {
|
|
2864
|
+
if (componentType?.[KEPT]) nextCounter(counters, `u_content_${(componentType.displayName || componentType.name || "component").toLowerCase()}`);
|
|
2865
|
+
return;
|
|
2866
|
+
}
|
|
1696
2867
|
const { name, defaultValues, propMapper } = config;
|
|
1697
|
-
const { children, ...restProps } =
|
|
2868
|
+
const { children, ...restProps } = element2.props;
|
|
1698
2869
|
const mappedValues = propMapper({ children, ...restProps });
|
|
1699
2870
|
const finalValues = mergeValues(defaultValues, mappedValues);
|
|
1700
2871
|
const contentType = config.metaName ?? name.toLowerCase();
|
|
1701
2872
|
const count = nextCounter(counters, `u_content_${contentType}`);
|
|
1702
2873
|
const valuesWithMeta = ensureMeta(finalValues, contentType, count - 1);
|
|
2874
|
+
collectDeviceStyles(valuesWithMeta, "contents", name, displayMode, deviceStyles);
|
|
1703
2875
|
const head = config.head ?? exporters.heads[name];
|
|
1704
2876
|
callHead(head, valuesWithMeta, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1705
2877
|
}
|
|
1706
|
-
function walkColumn(
|
|
1707
|
-
const semanticProps = extractSemanticProps(
|
|
2878
|
+
function walkColumn(element2, bodyValues, rowValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles) {
|
|
2879
|
+
const semanticProps = extractSemanticProps(element2.props);
|
|
1708
2880
|
const mapped = mapSemanticProps(semanticProps, COLUMN_DEFAULTS, "Column");
|
|
1709
2881
|
const count = nextCounter(counters, "u_column");
|
|
1710
2882
|
const columnValues = ensureMeta(mergeValues(COLUMN_DEFAULTS, mapped), "column", count - 1);
|
|
2883
|
+
collectDeviceStyles(columnValues, "columns", "Column", displayMode, deviceStyles);
|
|
1711
2884
|
const columnHead = exporters.heads["Column"];
|
|
1712
2885
|
callHead(columnHead, columnValues, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1713
|
-
const children =
|
|
2886
|
+
const children = collectChildren2(element2.props.children);
|
|
1714
2887
|
for (const child of children) {
|
|
1715
|
-
walkItem(child, bodyValues, displayMode, headConfig, counters, styles, scripts, tags);
|
|
2888
|
+
walkItem(child, bodyValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles);
|
|
1716
2889
|
}
|
|
1717
2890
|
}
|
|
1718
|
-
function walkRow(
|
|
1719
|
-
const semanticProps = extractSemanticProps(
|
|
2891
|
+
function walkRow(element2, bodyValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles) {
|
|
2892
|
+
const semanticProps = extractSemanticProps(element2.props, ["layout"]);
|
|
1720
2893
|
const mapped = mapSemanticProps(semanticProps, ROW_DEFAULTS, "Row");
|
|
1721
2894
|
const count = nextCounter(counters, "u_row");
|
|
1722
2895
|
const rowValues = ensureMeta(mergeValues(ROW_DEFAULTS, mapped), "row", count - 1);
|
|
2896
|
+
collectDeviceStyles(rowValues, "rows", "Row", displayMode, deviceStyles);
|
|
1723
2897
|
const rowHead = exporters.heads["Row"];
|
|
1724
2898
|
callHead(rowHead, rowValues, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1725
|
-
const children =
|
|
2899
|
+
const children = collectChildren2(element2.props.children);
|
|
1726
2900
|
for (const child of children) {
|
|
1727
2901
|
const name = getDisplayName(child);
|
|
1728
2902
|
if (name === "Column") {
|
|
1729
|
-
walkColumn(child, bodyValues, rowValues, displayMode, headConfig, counters, styles, scripts, tags);
|
|
2903
|
+
walkColumn(child, bodyValues, rowValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles);
|
|
1730
2904
|
}
|
|
1731
2905
|
}
|
|
1732
2906
|
}
|
|
1733
|
-
function extractHeadFromTree(
|
|
2907
|
+
function extractHeadFromTree(element2, options) {
|
|
2908
|
+
element2 = normalizedRoot(element2);
|
|
1734
2909
|
const { displayMode } = options;
|
|
1735
2910
|
const headConfig = {
|
|
1736
2911
|
hasFeature: options.headConfig?.hasFeature ?? (() => false),
|
|
@@ -1740,18 +2915,22 @@ function extractHeadFromTree(element, options) {
|
|
|
1740
2915
|
const scripts = [];
|
|
1741
2916
|
const tags = [];
|
|
1742
2917
|
const counters = {};
|
|
1743
|
-
const
|
|
2918
|
+
const deviceStyles = {};
|
|
2919
|
+
const semanticProps = extractSemanticProps(element2.props);
|
|
1744
2920
|
const mapped = mapSemanticProps(semanticProps, BODY_DEFAULTS, "Body");
|
|
1745
2921
|
const bodyValues = ensureMeta(mergeValues(BODY_DEFAULTS, mapped), "body", 0);
|
|
1746
2922
|
const bodyHead = exporters.heads["Body"];
|
|
1747
2923
|
callHead(bodyHead, bodyValues, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1748
|
-
const children =
|
|
2924
|
+
const children = collectChildren2(element2.props.children);
|
|
1749
2925
|
for (const child of children) {
|
|
1750
2926
|
const name = getDisplayName(child);
|
|
1751
2927
|
if (name === "Row") {
|
|
1752
|
-
walkRow(child, bodyValues, displayMode, headConfig, counters, styles, scripts, tags);
|
|
2928
|
+
walkRow(child, bodyValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles);
|
|
1753
2929
|
}
|
|
1754
2930
|
}
|
|
2931
|
+
styles.unshift(deviceVisibilityCss(displayMode));
|
|
2932
|
+
const overrides = deviceStylesCss(deviceStyles, displayMode);
|
|
2933
|
+
if (overrides) styles.push(overrides);
|
|
1755
2934
|
const uniqueTags = [...new Set(tags.filter(Boolean))];
|
|
1756
2935
|
return {
|
|
1757
2936
|
css: styles.filter(Boolean).join("\n"),
|
|
@@ -1771,7 +2950,7 @@ function emailLayout(args) {
|
|
|
1771
2950
|
fontLinks && `<!--[if !mso]><!-->${fontLinks}<!--<![endif]-->`
|
|
1772
2951
|
].filter(Boolean).join("\n ");
|
|
1773
2952
|
return `<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
1774
|
-
<html${dir} xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
|
2953
|
+
<html${dir}${args.lang || ""} xmlns="http://www.w3.org/1999/xhtml" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:o="urn:schemas-microsoft-com:office:office">
|
|
1775
2954
|
<head>
|
|
1776
2955
|
<!--[if gte mso 9]>
|
|
1777
2956
|
<xml>
|
|
@@ -1795,7 +2974,7 @@ function documentLayout(args) {
|
|
|
1795
2974
|
const { dir, titleTag, tagLines, styleTag, scriptTag, fontLinks, body } = args;
|
|
1796
2975
|
const head = [titleTag, tagLines, styleTag, scriptTag, fontLinks].filter(Boolean).join("\n ");
|
|
1797
2976
|
return `<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
1798
|
-
<html${dir} xmlns="http://www.w3.org/1999/xhtml">
|
|
2977
|
+
<html${dir}${args.lang || ""} xmlns="http://www.w3.org/1999/xhtml">
|
|
1799
2978
|
<head>
|
|
1800
2979
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
1801
2980
|
${head}
|
|
@@ -1808,7 +2987,7 @@ function webLayout(args) {
|
|
|
1808
2987
|
const { dir, titleTag, tagLines, styleTag, scriptTag, fontLinks, body } = args;
|
|
1809
2988
|
const head = [titleTag, fontLinks, tagLines, styleTag, scriptTag].filter(Boolean).join("\n ");
|
|
1810
2989
|
return `<!doctype html>
|
|
1811
|
-
<html${dir}>
|
|
2990
|
+
<html${dir}${args.lang || ""}>
|
|
1812
2991
|
<head>
|
|
1813
2992
|
<meta charset="utf-8">
|
|
1814
2993
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
@@ -1829,20 +3008,25 @@ var MODE_BY_WRAPPER = {
|
|
|
1829
3008
|
Page: "web",
|
|
1830
3009
|
Document: "document"
|
|
1831
3010
|
};
|
|
1832
|
-
function
|
|
1833
|
-
const
|
|
3011
|
+
function resolveConfig(element2, config) {
|
|
3012
|
+
const props = element2.props;
|
|
3013
|
+
const textDirection = textDirectionOf(props.textDirection ?? props.values?.textDirection);
|
|
3014
|
+
return { ...DEFAULT_CONFIG, ...textDirection !== void 0 ? { textDirection } : {}, ...config };
|
|
3015
|
+
}
|
|
3016
|
+
function resolveDisplayMode(element2, mergedConfig) {
|
|
3017
|
+
const displayName = element2.type?.displayName;
|
|
1834
3018
|
const wrapperMode = displayName ? MODE_BY_WRAPPER[displayName] : void 0;
|
|
1835
|
-
return wrapperMode ??
|
|
3019
|
+
return wrapperMode ?? element2.props.mode ?? mergedConfig.mode ?? "web";
|
|
1836
3020
|
}
|
|
1837
|
-
function renderBody(
|
|
1838
|
-
const mergedConfig =
|
|
3021
|
+
function renderBody(element2, config, name = "renderToHtml") {
|
|
3022
|
+
const mergedConfig = resolveConfig(element2, config);
|
|
1839
3023
|
try {
|
|
1840
|
-
const enriched =
|
|
1841
|
-
return
|
|
3024
|
+
const enriched = React4__default.default.cloneElement(element2, { config: mergedConfig });
|
|
3025
|
+
return renderToStaticMarkup(enriched);
|
|
1842
3026
|
} catch (error) {
|
|
1843
3027
|
const message = error instanceof Error ? error.message : String(error);
|
|
1844
3028
|
throw new Error(
|
|
1845
|
-
`[Unlayer]
|
|
3029
|
+
`[Unlayer] ${name} failed: ${message}
|
|
1846
3030
|
Tip: Ensure your tree uses Body > Row > Column > Item structure.`
|
|
1847
3031
|
);
|
|
1848
3032
|
}
|
|
@@ -1854,30 +3038,41 @@ function stripOuterDiv(html) {
|
|
|
1854
3038
|
function escapeForHtml(text) {
|
|
1855
3039
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1856
3040
|
}
|
|
1857
|
-
function renderToHtml(
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
3041
|
+
function renderToHtml(element2, options) {
|
|
3042
|
+
return withRenderScope(() => htmlDocument(element2, options));
|
|
3043
|
+
}
|
|
3044
|
+
function styleText(css2) {
|
|
3045
|
+
return css2.replace(/<\/(style)/gi, "<\\/$1");
|
|
3046
|
+
}
|
|
3047
|
+
function htmlDocument(element2, options) {
|
|
3048
|
+
const { title, lang: optionLang, fonts: optionFonts = [], ...config } = options ?? {};
|
|
3049
|
+
element2 = htmlRoot(element2, "renderToHtml");
|
|
3050
|
+
const rootFonts = element2.props?.fonts ?? [];
|
|
3051
|
+
const fonts = [...rootFonts, ...optionFonts].filter((font, i, all) => font?.url && all.findIndex((f) => f?.url === font.url) === i);
|
|
3052
|
+
const lang = optionLang ?? element2.props.lang;
|
|
3053
|
+
const mergedConfig = resolveConfig(element2, config);
|
|
3054
|
+
const displayMode = resolveDisplayMode(element2, mergedConfig);
|
|
3055
|
+
const wrapperName = element2.type?.displayName;
|
|
1862
3056
|
const isUnlayerWrapper = wrapperName === "Body" || (wrapperName ? wrapperName in MODE_BY_WRAPPER : false);
|
|
1863
|
-
const rawBody = renderBody(
|
|
3057
|
+
const rawBody = renderBody(element2, config);
|
|
1864
3058
|
const body = isUnlayerWrapper ? stripOuterDiv(rawBody) : rawBody;
|
|
1865
|
-
const { css, js, tags } = extractHeadFromTree(
|
|
3059
|
+
const { css: css2, js, tags } = extractHeadFromTree(element2, {
|
|
1866
3060
|
displayMode,
|
|
1867
3061
|
headConfig: mergedConfig.headConfig
|
|
1868
3062
|
});
|
|
1869
3063
|
const layoutArgs = {
|
|
3064
|
+
lang: lang ? ` lang="${escapeForHtml(String(lang))}"` : "",
|
|
1870
3065
|
dir: mergedConfig.textDirection ? ` dir="${escapeForHtml(String(mergedConfig.textDirection))}"` : "",
|
|
1871
3066
|
titleTag: title ? `<title>${escapeForHtml(title.trim())}</title>` : "",
|
|
1872
|
-
styleTag:
|
|
1873
|
-
${
|
|
3067
|
+
styleTag: css2 ? `<style type="text/css">
|
|
3068
|
+
${styleText(css2)}
|
|
1874
3069
|
</style>` : "",
|
|
1875
3070
|
scriptTag: js ? `<script type="application/javascript">
|
|
1876
3071
|
${js}
|
|
1877
3072
|
</script>` : "",
|
|
1878
3073
|
tagLines: tags.join("\n"),
|
|
1879
3074
|
fontLinks: fonts.filter((font) => font?.url).map(
|
|
1880
|
-
(font) => `<link href="${escapeForHtml(font.url)}" rel="stylesheet" type="text/css">`
|
|
3075
|
+
(font) => `<link href="${escapeForHtml(String(font.url))}" rel="stylesheet" type="text/css">`
|
|
1881
3076
|
).join(""),
|
|
1882
3077
|
body
|
|
1883
3078
|
};
|
|
@@ -1885,21 +3080,29 @@ ${js}
|
|
|
1885
3080
|
if (displayMode === "document") return documentLayout(layoutArgs);
|
|
1886
3081
|
return webLayout(layoutArgs);
|
|
1887
3082
|
}
|
|
1888
|
-
function renderToPlainText(
|
|
1889
|
-
const html =
|
|
3083
|
+
function renderToPlainText(element2, config) {
|
|
3084
|
+
const html = withRenderScope(() => {
|
|
3085
|
+
const root = htmlRoot(element2, "renderToPlainText");
|
|
3086
|
+
normalizedRoot(root);
|
|
3087
|
+
return renderBody(root, config, "renderToPlainText");
|
|
3088
|
+
});
|
|
1890
3089
|
return htmlToPlainText(html);
|
|
1891
3090
|
}
|
|
1892
|
-
function renderToHtmlParts(
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
3091
|
+
function renderToHtmlParts(element2, config) {
|
|
3092
|
+
return withRenderScope(() => htmlParts(element2, config));
|
|
3093
|
+
}
|
|
3094
|
+
function htmlParts(element2, config) {
|
|
3095
|
+
element2 = htmlRoot(element2, "renderToHtmlParts");
|
|
3096
|
+
const body = renderBody(element2, config, "renderToHtmlParts");
|
|
3097
|
+
const mergedConfig = resolveConfig(element2, config);
|
|
3098
|
+
const displayMode = resolveDisplayMode(element2, mergedConfig);
|
|
3099
|
+
const { css: css2, js, tags } = extractHeadFromTree(element2, {
|
|
1897
3100
|
displayMode,
|
|
1898
3101
|
headConfig: mergedConfig.headConfig
|
|
1899
3102
|
});
|
|
1900
3103
|
const headParts = [];
|
|
1901
|
-
if (
|
|
1902
|
-
headParts.push(`<style>${
|
|
3104
|
+
if (css2) {
|
|
3105
|
+
headParts.push(`<style>${styleText(css2)}</style>`);
|
|
1903
3106
|
}
|
|
1904
3107
|
if (js) {
|
|
1905
3108
|
headParts.push(`<script>${js}</script>`);
|
|
@@ -1910,291 +3113,11 @@ function renderToHtmlParts(element, config) {
|
|
|
1910
3113
|
return {
|
|
1911
3114
|
head: headParts.join("\n"),
|
|
1912
3115
|
body,
|
|
1913
|
-
css,
|
|
3116
|
+
css: css2,
|
|
1914
3117
|
js,
|
|
1915
3118
|
tags
|
|
1916
3119
|
};
|
|
1917
3120
|
}
|
|
1918
|
-
var schemaVersion = exporters.schemaVersion ?? 24;
|
|
1919
|
-
function getDisplayName2(element) {
|
|
1920
|
-
const type = element.type;
|
|
1921
|
-
return type?.displayName || type?.name;
|
|
1922
|
-
}
|
|
1923
|
-
var VALID_ROOTS = /* @__PURE__ */ new Set(["Body", "Email", "Page", "Document"]);
|
|
1924
|
-
function unwrapRoot(element) {
|
|
1925
|
-
let current = element;
|
|
1926
|
-
for (let depth = 0; depth < 10; depth++) {
|
|
1927
|
-
const name = getDisplayName2(current);
|
|
1928
|
-
if (name && VALID_ROOTS.has(name)) break;
|
|
1929
|
-
const type = current.type;
|
|
1930
|
-
const isPlainFunctionComponent = typeof type === "function" && !type.prototype?.isReactComponent;
|
|
1931
|
-
if (!isPlainFunctionComponent) break;
|
|
1932
|
-
let produced;
|
|
1933
|
-
try {
|
|
1934
|
-
produced = type({ ...current.props });
|
|
1935
|
-
} catch (cause) {
|
|
1936
|
-
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
1937
|
-
throw new Error(
|
|
1938
|
-
`[Unlayer] renderToJson: could not unwrap <${name || "wrapper"}>. A wrapper must be a plain component that synchronously returns a root (<Email>, <Page>, <Document>, or <Body>) and uses no React hooks. Pass the root element directly \u2014 e.g. renderToJson(<Email>\u2026</Email>). (${detail})`
|
|
1939
|
-
);
|
|
1940
|
-
}
|
|
1941
|
-
if (!React__default.default.isValidElement(produced)) break;
|
|
1942
|
-
current = produced;
|
|
1943
|
-
}
|
|
1944
|
-
return current;
|
|
1945
|
-
}
|
|
1946
|
-
function collectChildren2(node) {
|
|
1947
|
-
const result = [];
|
|
1948
|
-
React__default.default.Children.forEach(node, (child) => {
|
|
1949
|
-
if (React__default.default.isValidElement(child)) {
|
|
1950
|
-
result.push(child);
|
|
1951
|
-
}
|
|
1952
|
-
});
|
|
1953
|
-
return result;
|
|
1954
|
-
}
|
|
1955
|
-
function extractSemanticProps2(props, extraKeys = []) {
|
|
1956
|
-
const internalKeys = /* @__PURE__ */ new Set([
|
|
1957
|
-
"children",
|
|
1958
|
-
"mode",
|
|
1959
|
-
"className",
|
|
1960
|
-
"style",
|
|
1961
|
-
"index",
|
|
1962
|
-
"colIndex",
|
|
1963
|
-
"cells",
|
|
1964
|
-
"bodyValues",
|
|
1965
|
-
"rowValues",
|
|
1966
|
-
"_config",
|
|
1967
|
-
"config",
|
|
1968
|
-
"previewText",
|
|
1969
|
-
"layout",
|
|
1970
|
-
"collection",
|
|
1971
|
-
...extraKeys
|
|
1972
|
-
]);
|
|
1973
|
-
const result = {};
|
|
1974
|
-
for (const [key, value] of Object.entries(props)) {
|
|
1975
|
-
if (!internalKeys.has(key) && value !== void 0) {
|
|
1976
|
-
result[key] = value;
|
|
1977
|
-
}
|
|
1978
|
-
}
|
|
1979
|
-
return result;
|
|
1980
|
-
}
|
|
1981
|
-
function nextCounter2(counters, key) {
|
|
1982
|
-
counters[key] = (counters[key] || 0) + 1;
|
|
1983
|
-
return counters[key];
|
|
1984
|
-
}
|
|
1985
|
-
function toContentType(displayName) {
|
|
1986
|
-
if (displayName === "Paragraph") return "text";
|
|
1987
|
-
return displayName.toLowerCase();
|
|
1988
|
-
}
|
|
1989
|
-
function makeId(prefix, counter) {
|
|
1990
|
-
return `${prefix}_${counter}`;
|
|
1991
|
-
}
|
|
1992
|
-
function extractTextFromTextJson(textJson) {
|
|
1993
|
-
try {
|
|
1994
|
-
const parsed = JSON.parse(textJson);
|
|
1995
|
-
if (parsed.__html) return parsed.__html;
|
|
1996
|
-
const root = parsed?.root;
|
|
1997
|
-
if (!root?.children) return "";
|
|
1998
|
-
const paragraphs = [];
|
|
1999
|
-
for (const paragraph of root.children) {
|
|
2000
|
-
if (!paragraph?.children) continue;
|
|
2001
|
-
const parts = [];
|
|
2002
|
-
for (const node of paragraph.children) {
|
|
2003
|
-
if (node?.text) parts.push(node.text);
|
|
2004
|
-
}
|
|
2005
|
-
paragraphs.push(parts.join(""));
|
|
2006
|
-
}
|
|
2007
|
-
return paragraphs.join("\n");
|
|
2008
|
-
} catch {
|
|
2009
|
-
return "";
|
|
2010
|
-
}
|
|
2011
|
-
}
|
|
2012
|
-
function processItem(element, counters, layout = {}) {
|
|
2013
|
-
const componentType = element.type;
|
|
2014
|
-
const config = componentType[UNLAYER_CONFIG_KEY];
|
|
2015
|
-
if (!config) {
|
|
2016
|
-
const name2 = getDisplayName2(element) || "Unknown";
|
|
2017
|
-
throw new Error(
|
|
2018
|
-
`[Unlayer] renderToJson: <${name2}> is not a recognized Unlayer item component. Only components created with createItemComponent are supported.`
|
|
2019
|
-
);
|
|
2020
|
-
}
|
|
2021
|
-
const { name, defaultValues, propMapper, slug } = config;
|
|
2022
|
-
const contentType = config.contentType ?? toContentType(name);
|
|
2023
|
-
const metaBase = `u_content_${config.metaName ?? contentType}`;
|
|
2024
|
-
const count = nextCounter2(counters, metaBase);
|
|
2025
|
-
const id = makeId(metaBase, count);
|
|
2026
|
-
const { children, ...restProps } = element.props;
|
|
2027
|
-
const mappedValues = propMapper({ children, ...restProps });
|
|
2028
|
-
const finalValues = mergeValues(defaultValues, mappedValues);
|
|
2029
|
-
if (contentType === "text" && finalValues.textJson) {
|
|
2030
|
-
finalValues.text = extractTextFromTextJson(finalValues.textJson);
|
|
2031
|
-
delete finalValues.textJson;
|
|
2032
|
-
}
|
|
2033
|
-
const values = {
|
|
2034
|
-
containerPadding: "10px",
|
|
2035
|
-
...finalValues,
|
|
2036
|
-
_meta: {
|
|
2037
|
-
htmlID: id,
|
|
2038
|
-
htmlClassNames: metaBase,
|
|
2039
|
-
...finalValues._meta || {}
|
|
2040
|
-
},
|
|
2041
|
-
selectable: true,
|
|
2042
|
-
draggable: true,
|
|
2043
|
-
duplicatable: true,
|
|
2044
|
-
deletable: true,
|
|
2045
|
-
hideable: true
|
|
2046
|
-
};
|
|
2047
|
-
const itemSrc = values.src;
|
|
2048
|
-
if (itemSrc && typeof itemSrc === "object" && itemSrc.autoWidth === false) {
|
|
2049
|
-
const availableWidth = contentSlotWidth({
|
|
2050
|
-
...layout,
|
|
2051
|
-
containerPadding: values.containerPadding
|
|
2052
|
-
});
|
|
2053
|
-
values.src = pinImageSrc(itemSrc, availableWidth);
|
|
2054
|
-
}
|
|
2055
|
-
return slug ? { type: contentType, slug, values } : { type: contentType, values };
|
|
2056
|
-
}
|
|
2057
|
-
function processColumn(element, counters, layout = {}) {
|
|
2058
|
-
const count = nextCounter2(counters, "u_column");
|
|
2059
|
-
const id = makeId("u_column", count);
|
|
2060
|
-
const semanticProps = extractSemanticProps2(element.props);
|
|
2061
|
-
const mapped = mapSemanticProps(semanticProps, COLUMN_DEFAULTS, "Column");
|
|
2062
|
-
const values = mergeValues(COLUMN_DEFAULTS, mapped);
|
|
2063
|
-
const valuesWithMeta = {
|
|
2064
|
-
...values,
|
|
2065
|
-
_meta: {
|
|
2066
|
-
htmlID: id,
|
|
2067
|
-
htmlClassNames: "u_column",
|
|
2068
|
-
...values._meta || {}
|
|
2069
|
-
}
|
|
2070
|
-
};
|
|
2071
|
-
const contents = [];
|
|
2072
|
-
const children = collectChildren2(element.props.children);
|
|
2073
|
-
const itemLayout = { ...layout, columnValues: valuesWithMeta };
|
|
2074
|
-
for (const child of children) {
|
|
2075
|
-
contents.push(processItem(child, counters, itemLayout));
|
|
2076
|
-
}
|
|
2077
|
-
return { contents, values: valuesWithMeta };
|
|
2078
|
-
}
|
|
2079
|
-
function processRow(element, counters, parentLayout = {}) {
|
|
2080
|
-
const count = nextCounter2(counters, "u_row");
|
|
2081
|
-
const id = makeId("u_row", count);
|
|
2082
|
-
const { layout, cells: propsCells } = element.props;
|
|
2083
|
-
let cells;
|
|
2084
|
-
if (layout) {
|
|
2085
|
-
cells = layout.cells;
|
|
2086
|
-
} else if (propsCells) {
|
|
2087
|
-
cells = propsCells;
|
|
2088
|
-
} else {
|
|
2089
|
-
const columnCount = Math.max(
|
|
2090
|
-
1,
|
|
2091
|
-
collectChildren2(element.props.children).filter(
|
|
2092
|
-
(child) => getDisplayName2(child) === "Column"
|
|
2093
|
-
).length
|
|
2094
|
-
);
|
|
2095
|
-
cells = Array(columnCount).fill(1);
|
|
2096
|
-
}
|
|
2097
|
-
const semanticProps = extractSemanticProps2(element.props, ["layout"]);
|
|
2098
|
-
const mapped = mapSemanticProps(semanticProps, ROW_DEFAULTS, "Row");
|
|
2099
|
-
const values = mergeValues(ROW_DEFAULTS, mapped);
|
|
2100
|
-
const valuesWithMeta = {
|
|
2101
|
-
...values,
|
|
2102
|
-
columns: values.columns ?? false,
|
|
2103
|
-
cells,
|
|
2104
|
-
_meta: {
|
|
2105
|
-
htmlID: id,
|
|
2106
|
-
htmlClassNames: "u_row",
|
|
2107
|
-
...values._meta || {}
|
|
2108
|
-
},
|
|
2109
|
-
selectable: true,
|
|
2110
|
-
draggable: true,
|
|
2111
|
-
duplicatable: true,
|
|
2112
|
-
deletable: true,
|
|
2113
|
-
hideable: true
|
|
2114
|
-
};
|
|
2115
|
-
const columns = [];
|
|
2116
|
-
const children = collectChildren2(element.props.children);
|
|
2117
|
-
const columnLayout = {
|
|
2118
|
-
bodyValues: parentLayout.bodyValues,
|
|
2119
|
-
rowValues: valuesWithMeta,
|
|
2120
|
-
rowCells: cells
|
|
2121
|
-
};
|
|
2122
|
-
let columnIndex = 0;
|
|
2123
|
-
for (const child of children) {
|
|
2124
|
-
const name = getDisplayName2(child);
|
|
2125
|
-
if (name === "Column") {
|
|
2126
|
-
columns.push(
|
|
2127
|
-
processColumn(child, counters, { ...columnLayout, columnIndex })
|
|
2128
|
-
);
|
|
2129
|
-
columnIndex += 1;
|
|
2130
|
-
} else {
|
|
2131
|
-
console.warn(
|
|
2132
|
-
`[Unlayer] renderToJson: <${name}> is not a valid Row child. Only <Column> is allowed.`
|
|
2133
|
-
);
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
return { cells, columns, values: valuesWithMeta };
|
|
2137
|
-
}
|
|
2138
|
-
function processBody(element, counters) {
|
|
2139
|
-
const id = "u_body";
|
|
2140
|
-
const semanticProps = extractSemanticProps2(element.props);
|
|
2141
|
-
const mapped = mapSemanticProps(semanticProps, BODY_DEFAULTS, "Body");
|
|
2142
|
-
const values = mergeValues(BODY_DEFAULTS, mapped);
|
|
2143
|
-
const previewText = element.props.previewText;
|
|
2144
|
-
if (previewText !== void 0) {
|
|
2145
|
-
values.preheaderText = previewText;
|
|
2146
|
-
}
|
|
2147
|
-
const valuesWithMeta = {
|
|
2148
|
-
...values,
|
|
2149
|
-
_meta: {
|
|
2150
|
-
htmlID: id,
|
|
2151
|
-
htmlClassNames: "u_body",
|
|
2152
|
-
...values._meta || {}
|
|
2153
|
-
}
|
|
2154
|
-
};
|
|
2155
|
-
const rows = [];
|
|
2156
|
-
const children = collectChildren2(element.props.children);
|
|
2157
|
-
for (const child of children) {
|
|
2158
|
-
const name = getDisplayName2(child);
|
|
2159
|
-
if (name === "Row") {
|
|
2160
|
-
rows.push(processRow(child, counters, { bodyValues: valuesWithMeta }));
|
|
2161
|
-
} else {
|
|
2162
|
-
console.warn(
|
|
2163
|
-
`[Unlayer] renderToJson: <${name}> is not a valid Body child. Only <Row> is allowed.`
|
|
2164
|
-
);
|
|
2165
|
-
}
|
|
2166
|
-
}
|
|
2167
|
-
return {
|
|
2168
|
-
rows,
|
|
2169
|
-
values: valuesWithMeta
|
|
2170
|
-
};
|
|
2171
|
-
}
|
|
2172
|
-
function renderRowToJson(element) {
|
|
2173
|
-
const displayName = getDisplayName2(element);
|
|
2174
|
-
if (displayName !== "Row") {
|
|
2175
|
-
throw new Error(
|
|
2176
|
-
`[Unlayer] renderRowToJson: Element must be <Row>, but got <${displayName || "unknown"}>. For full designs, use renderToJson instead.`
|
|
2177
|
-
);
|
|
2178
|
-
}
|
|
2179
|
-
const counters = {};
|
|
2180
|
-
return processRow(element, counters);
|
|
2181
|
-
}
|
|
2182
|
-
function renderToJson(element) {
|
|
2183
|
-
element = unwrapRoot(element);
|
|
2184
|
-
const displayName = getDisplayName2(element);
|
|
2185
|
-
if (!displayName || !VALID_ROOTS.has(displayName)) {
|
|
2186
|
-
throw new Error(
|
|
2187
|
-
`[Unlayer] renderToJson: Root element must be <Body>, <Email>, <Page>, or <Document>, but got <${displayName || "unknown"}>. Wrap your content: <Body><Row><Column>...</Column></Row></Body>`
|
|
2188
|
-
);
|
|
2189
|
-
}
|
|
2190
|
-
const counters = {};
|
|
2191
|
-
const body = processBody(element, counters);
|
|
2192
|
-
return {
|
|
2193
|
-
counters,
|
|
2194
|
-
body,
|
|
2195
|
-
schemaVersion
|
|
2196
|
-
};
|
|
2197
|
-
}
|
|
2198
3121
|
|
|
2199
3122
|
// src/utils/register-tool.tsx
|
|
2200
3123
|
function initialValuesFromOptions(options) {
|
|
@@ -2292,6 +3215,7 @@ exports.Html = Html_default;
|
|
|
2292
3215
|
exports.Image = Image_default;
|
|
2293
3216
|
exports.Menu = Menu_default;
|
|
2294
3217
|
exports.Page = Page;
|
|
3218
|
+
exports.PageBreak = PageBreak_default;
|
|
2295
3219
|
exports.Paragraph = Paragraph_default;
|
|
2296
3220
|
exports.Row = Row_default;
|
|
2297
3221
|
exports.Social = Social_default;
|