@unlayer/react-elements 0.1.22 → 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 +43 -2
- package/dist/index.cjs +1367 -478
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +48 -9
- package/dist/index.d.ts +48 -9
- package/dist/index.js +1341 -471
- package/dist/index.js.map +1 -1
- package/package.json +9 -3
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,
|
|
@@ -824,9 +1297,9 @@ var Button = createItemComponent({
|
|
|
824
1297
|
DEFAULT_VALUES,
|
|
825
1298
|
"Button"
|
|
826
1299
|
);
|
|
827
|
-
const
|
|
828
|
-
if (
|
|
829
|
-
const s =
|
|
1300
|
+
const size2 = mapped.size;
|
|
1301
|
+
if (size2 && typeof size2 === "object" && !Array.isArray(size2)) {
|
|
1302
|
+
const s = size2;
|
|
830
1303
|
if (typeof s.width === "number") {
|
|
831
1304
|
s.width = `${s.width}px`;
|
|
832
1305
|
} else if (typeof s.width === "string" && /^\d+(?:\.\d+)?$/.test(s.width.trim())) {
|
|
@@ -1235,6 +1708,35 @@ var {
|
|
|
1235
1708
|
var BODY_DEFAULTS = bodyRest;
|
|
1236
1709
|
var ROW_DEFAULTS = { ...exporters.RowDefaults };
|
|
1237
1710
|
var COLUMN_DEFAULTS = { ...exporters.ColumnDefaults };
|
|
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
|
+
}
|
|
1238
1740
|
var DEFAULT_VALUES12 = ROW_DEFAULTS;
|
|
1239
1741
|
var DEFAULT_BODY_VALUES = BODY_DEFAULTS;
|
|
1240
1742
|
function getWidthPercentages(cells) {
|
|
@@ -1264,8 +1766,8 @@ ${maxQuery} {
|
|
|
1264
1766
|
.u-row { width: 100% !important; }
|
|
1265
1767
|
.u-row .u-col { display: block !important; width: 100% !important; min-width: 320px !important; max-width: 100% !important; }
|
|
1266
1768
|
.u-row .u-col > div { margin: 0 auto; }
|
|
1267
|
-
.no-stack .u-col { min-width: 0 !important; display: table-cell !important; }
|
|
1268
|
-
${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")}
|
|
1269
1771
|
}`;
|
|
1270
1772
|
}
|
|
1271
1773
|
const baseCSS = `
|
|
@@ -1305,17 +1807,18 @@ function renderRowToHtml(innerHTML, values, bodyValues, mode, cells, collection
|
|
|
1305
1807
|
variant: mode
|
|
1306
1808
|
});
|
|
1307
1809
|
const contentWidth = toContentWidthPx(bodyValues);
|
|
1308
|
-
const
|
|
1309
|
-
return
|
|
1810
|
+
const css2 = generateGridCSS(cells, mode, contentWidth);
|
|
1811
|
+
return css2 ? `<style>${css2}</style>${html}` : html;
|
|
1310
1812
|
}
|
|
1311
1813
|
function processChildren(children, cells, bodyValues, rowValues, mode, _config) {
|
|
1312
1814
|
if (!children) return "";
|
|
1313
1815
|
let innerHTML = "";
|
|
1314
|
-
const childrenArray =
|
|
1315
|
-
|
|
1316
|
-
|
|
1816
|
+
const childrenArray = React4__default.default.Children.toArray(children);
|
|
1817
|
+
let index = 0;
|
|
1818
|
+
childrenArray.forEach((child) => {
|
|
1819
|
+
if (!React4__default.default.isValidElement(child)) {
|
|
1317
1820
|
if (typeof child === "string" || typeof child === "number") {
|
|
1318
|
-
innerHTML +=
|
|
1821
|
+
innerHTML += looseText(child, "Row");
|
|
1319
1822
|
}
|
|
1320
1823
|
return;
|
|
1321
1824
|
}
|
|
@@ -1324,7 +1827,7 @@ function processChildren(children, cells, bodyValues, rowValues, mode, _config)
|
|
|
1324
1827
|
if (isColumn && typeof child.type === "function") {
|
|
1325
1828
|
const rendered = child.type({
|
|
1326
1829
|
...child.props,
|
|
1327
|
-
index
|
|
1830
|
+
index: index++,
|
|
1328
1831
|
cells,
|
|
1329
1832
|
bodyValues,
|
|
1330
1833
|
rowValues,
|
|
@@ -1334,7 +1837,7 @@ function processChildren(children, cells, bodyValues, rowValues, mode, _config)
|
|
|
1334
1837
|
if (rendered?.props?.dangerouslySetInnerHTML?.__html) {
|
|
1335
1838
|
innerHTML += rendered.props.dangerouslySetInnerHTML.__html;
|
|
1336
1839
|
}
|
|
1337
|
-
} else if (
|
|
1840
|
+
} else if (React4__default.default.isValidElement(child)) {
|
|
1338
1841
|
const name = child.type?.displayName || child.type?.name || "Unknown";
|
|
1339
1842
|
console.warn(
|
|
1340
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>`
|
|
@@ -1343,7 +1846,7 @@ function processChildren(children, cells, bodyValues, rowValues, mode, _config)
|
|
|
1343
1846
|
});
|
|
1344
1847
|
return innerHTML;
|
|
1345
1848
|
}
|
|
1346
|
-
|
|
1849
|
+
function renderRow(props) {
|
|
1347
1850
|
const {
|
|
1348
1851
|
layout,
|
|
1349
1852
|
cells: propsCells,
|
|
@@ -1358,16 +1861,16 @@ var Row = (props) => {
|
|
|
1358
1861
|
...semanticProps
|
|
1359
1862
|
} = props;
|
|
1360
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;
|
|
1361
1867
|
let cells;
|
|
1362
1868
|
if (layout) {
|
|
1363
|
-
validateColumnLayout(layout,
|
|
1869
|
+
if (columnCount !== layout.expectedColumns) validateColumnLayout(layout, React4__default.default.Children.count(children));
|
|
1364
1870
|
cells = layout.cells;
|
|
1365
1871
|
} else if (propsCells) {
|
|
1366
1872
|
cells = propsCells;
|
|
1367
1873
|
} else {
|
|
1368
|
-
const columnCount = React__default.default.Children.toArray(children).filter(
|
|
1369
|
-
(c) => React__default.default.isValidElement(c) && /^Column$/.test(c.type?.displayName || c.type?.name || "")
|
|
1370
|
-
).length;
|
|
1371
1874
|
cells = Array(Math.max(1, columnCount)).fill(1);
|
|
1372
1875
|
}
|
|
1373
1876
|
const safeBodyValues = { ...DEFAULT_BODY_VALUES, ...bodyValues };
|
|
@@ -1376,15 +1879,7 @@ var Row = (props) => {
|
|
|
1376
1879
|
DEFAULT_VALUES12,
|
|
1377
1880
|
"Row"
|
|
1378
1881
|
);
|
|
1379
|
-
const valuesWithMeta = {
|
|
1380
|
-
...values,
|
|
1381
|
-
cells,
|
|
1382
|
-
_meta: {
|
|
1383
|
-
htmlID: nextHtmlId(_config, "u_row"),
|
|
1384
|
-
htmlClassNames: "u_row",
|
|
1385
|
-
...values._meta || {}
|
|
1386
|
-
}
|
|
1387
|
-
};
|
|
1882
|
+
const valuesWithMeta = { ...values, cells, _meta: safeMeta({ htmlID: nextHtmlId(_config, "u_row"), htmlClassNames: "u_row", ...values._meta || {} }) };
|
|
1388
1883
|
const innerHTML = processChildren(
|
|
1389
1884
|
children,
|
|
1390
1885
|
cells,
|
|
@@ -1407,10 +1902,11 @@ var Row = (props) => {
|
|
|
1407
1902
|
console.error("Row rendering failed:", error);
|
|
1408
1903
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style, children });
|
|
1409
1904
|
}
|
|
1410
|
-
}
|
|
1905
|
+
}
|
|
1906
|
+
var Row = (props) => collecting() ? whileCollecting(() => recordContainer("row", props), () => renderRow(props), "Row") : renderRow(props);
|
|
1411
1907
|
Row.displayName = "Row";
|
|
1908
|
+
Row[RECORDS] = true;
|
|
1412
1909
|
var Row_default = Row;
|
|
1413
|
-
var DEFAULT_CONTAINER_PADDING2 = "10px";
|
|
1414
1910
|
var DEFAULT_VALUES13 = COLUMN_DEFAULTS;
|
|
1415
1911
|
function renderColumnToHtml(innerHTML, values, index, cells, bodyValues, rowValues, mode) {
|
|
1416
1912
|
const columnExporter = exporters.ColumnExporters[mode] || exporters.ColumnExporters.web;
|
|
@@ -1421,6 +1917,7 @@ function renderContentToHtml(innerHTML, values, bodyValues, mode) {
|
|
|
1421
1917
|
return contentExporter(innerHTML, values, bodyValues, {});
|
|
1422
1918
|
}
|
|
1423
1919
|
var Column = (props) => {
|
|
1920
|
+
if (collecting()) return whileCollecting(() => recordContainer("column", props), () => Column(props), "Column");
|
|
1424
1921
|
const {
|
|
1425
1922
|
children,
|
|
1426
1923
|
index = 0,
|
|
@@ -1439,27 +1936,20 @@ var Column = (props) => {
|
|
|
1439
1936
|
DEFAULT_VALUES13,
|
|
1440
1937
|
"Column"
|
|
1441
1938
|
);
|
|
1442
|
-
const valuesWithMeta = {
|
|
1443
|
-
...values,
|
|
1444
|
-
_meta: {
|
|
1445
|
-
htmlID: nextHtmlId(_config, "u_column"),
|
|
1446
|
-
htmlClassNames: "u_column",
|
|
1447
|
-
...values._meta || {}
|
|
1448
|
-
}
|
|
1449
|
-
};
|
|
1939
|
+
const valuesWithMeta = { ...values, _meta: safeMeta({ htmlID: nextHtmlId(_config, "u_column"), htmlClassNames: "u_column", ...values._meta || {} }) };
|
|
1450
1940
|
let innerHTML = "";
|
|
1451
1941
|
if (children) {
|
|
1452
1942
|
try {
|
|
1453
|
-
const childrenArray =
|
|
1943
|
+
const childrenArray = React4__default.default.Children.toArray(children);
|
|
1454
1944
|
childrenArray.forEach((child, childIndex) => {
|
|
1455
1945
|
if (typeof child === "string" || typeof child === "number") {
|
|
1456
|
-
innerHTML +=
|
|
1457
|
-
} else if (
|
|
1946
|
+
innerHTML += looseText(child, "Column");
|
|
1947
|
+
} else if (React4__default.default.isValidElement(child)) {
|
|
1458
1948
|
if (typeof child.type === "function") {
|
|
1459
1949
|
const ComponentType = child.type;
|
|
1460
1950
|
const renderFn = ComponentType[UNLAYER_RENDER_KEY] || ComponentType;
|
|
1461
|
-
const
|
|
1462
|
-
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}`);
|
|
1463
1953
|
const rendered = renderFn({
|
|
1464
1954
|
...child.props,
|
|
1465
1955
|
_config,
|
|
@@ -1474,13 +1964,26 @@ var Column = (props) => {
|
|
|
1474
1964
|
const componentHTML = rendered.props.dangerouslySetInnerHTML.__html;
|
|
1475
1965
|
if (!componentHTML && ComponentType?.[UNLAYER_CONFIG_KEY]?.omitEmptyOutput) return;
|
|
1476
1966
|
const childProps = child.props;
|
|
1477
|
-
const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ??
|
|
1967
|
+
const rawContainerPadding = childProps.containerPadding ?? childProps.values?.containerPadding ?? DEFAULT_CONTAINER_PADDING;
|
|
1478
1968
|
const containerPadding = typeof rawContainerPadding === "number" ? `${rawContainerPadding}px` : rawContainerPadding;
|
|
1969
|
+
const device = ComponentType?.[UNLAYER_CONFIG_KEY]?.contentType === "custom" ? {} : childProps;
|
|
1479
1970
|
const contentValues = {
|
|
1480
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
|
+
},
|
|
1481
1983
|
_meta: {
|
|
1482
1984
|
htmlID: contentHtmlId,
|
|
1483
|
-
htmlClassNames: `u_content_${
|
|
1985
|
+
htmlClassNames: `u_content_${componentName2}`,
|
|
1986
|
+
...childProps.values?._meta?.htmlID ? { htmlID: safeName(childProps.values._meta.htmlID) } : {}
|
|
1484
1987
|
}
|
|
1485
1988
|
};
|
|
1486
1989
|
innerHTML += renderContentToHtml(
|
|
@@ -1519,7 +2022,330 @@ var Column = (props) => {
|
|
|
1519
2022
|
}
|
|
1520
2023
|
};
|
|
1521
2024
|
Column.displayName = "Column";
|
|
2025
|
+
Column[RECORDS] = true;
|
|
1522
2026
|
var Column_default = Column;
|
|
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
|
+
}
|
|
1523
2349
|
var DEFAULT_VALUES14 = BODY_DEFAULTS;
|
|
1524
2350
|
var MAX_PREVIEW_LENGTH = 150;
|
|
1525
2351
|
var PADDING_CHARS = [
|
|
@@ -1531,6 +2357,9 @@ var PADDING_CHARS = [
|
|
|
1531
2357
|
"\u200F",
|
|
1532
2358
|
"\uFEFF"
|
|
1533
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
|
+
}
|
|
1534
2363
|
function generatePreviewHtml(text) {
|
|
1535
2364
|
if (!text || text.trim().length === 0) return "";
|
|
1536
2365
|
const truncated = text.length > MAX_PREVIEW_LENGTH ? text.slice(0, MAX_PREVIEW_LENGTH) : text;
|
|
@@ -1539,7 +2368,7 @@ function generatePreviewHtml(text) {
|
|
|
1539
2368
|
for (let i = 0; i < paddingLength; i++) {
|
|
1540
2369
|
padding += PADDING_CHARS[i % PADDING_CHARS.length];
|
|
1541
2370
|
}
|
|
1542
|
-
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>`;
|
|
1543
2372
|
}
|
|
1544
2373
|
function renderBodyToHtml(innerHTML, values, mode, previewText) {
|
|
1545
2374
|
let finalInnerHtml = innerHTML;
|
|
@@ -1560,7 +2389,7 @@ function renderBodyToHtml(innerHTML, values, mode, previewText) {
|
|
|
1560
2389
|
return raw.replace("min-height: 100vh; ", "").replace("min-height: 100vh;", "");
|
|
1561
2390
|
}
|
|
1562
2391
|
var Body = (props) => {
|
|
1563
|
-
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;
|
|
1564
2393
|
const resolvedConfig = { ...DEFAULT_CONFIG, ...configProp };
|
|
1565
2394
|
const mode = modeProp ?? resolvedConfig.mode ?? "web";
|
|
1566
2395
|
const _config = { ...resolvedConfig, mode };
|
|
@@ -1577,22 +2406,12 @@ var Body = (props) => {
|
|
|
1577
2406
|
...values._meta || {}
|
|
1578
2407
|
}
|
|
1579
2408
|
};
|
|
1580
|
-
let enrichedChildren = children;
|
|
1581
|
-
if (children) {
|
|
1582
|
-
enrichedChildren = React__default.default.Children.map(children, (child) => {
|
|
1583
|
-
if (React__default.default.isValidElement(child)) {
|
|
1584
|
-
return React__default.default.cloneElement(child, {
|
|
1585
|
-
_config,
|
|
1586
|
-
bodyValues: values
|
|
1587
|
-
});
|
|
1588
|
-
}
|
|
1589
|
-
return child;
|
|
1590
|
-
});
|
|
1591
|
-
}
|
|
1592
2409
|
let innerHTML = "";
|
|
1593
|
-
if (
|
|
2410
|
+
if (children) {
|
|
1594
2411
|
try {
|
|
1595
|
-
innerHTML =
|
|
2412
|
+
innerHTML = withRenderScope(() => {
|
|
2413
|
+
return childrenHtml2(children, (child) => React4__default.default.cloneElement(child, { _config, bodyValues: values }));
|
|
2414
|
+
}, true);
|
|
1596
2415
|
} catch (error) {
|
|
1597
2416
|
console.error("Body: Failed to render children:", error);
|
|
1598
2417
|
innerHTML = "";
|
|
@@ -1631,7 +2450,7 @@ var PROVIDER_ACTIVE_KEY = "__unlayerProviderActive";
|
|
|
1631
2450
|
var _UnlayerContext = null;
|
|
1632
2451
|
function getUnlayerContext() {
|
|
1633
2452
|
if (!_UnlayerContext) {
|
|
1634
|
-
_UnlayerContext =
|
|
2453
|
+
_UnlayerContext = React4.createContext(DEFAULT_CONFIG);
|
|
1635
2454
|
}
|
|
1636
2455
|
return _UnlayerContext;
|
|
1637
2456
|
}
|
|
@@ -1639,7 +2458,7 @@ var UnlayerProvider = ({
|
|
|
1639
2458
|
config,
|
|
1640
2459
|
children
|
|
1641
2460
|
}) => {
|
|
1642
|
-
const merged =
|
|
2461
|
+
const merged = React4.useMemo(
|
|
1643
2462
|
() => ({ ...DEFAULT_CONFIG, ...config, [PROVIDER_ACTIVE_KEY]: true }),
|
|
1644
2463
|
[config]
|
|
1645
2464
|
);
|
|
@@ -1648,31 +2467,106 @@ var UnlayerProvider = ({
|
|
|
1648
2467
|
};
|
|
1649
2468
|
UnlayerProvider.displayName = "UnlayerProvider";
|
|
1650
2469
|
function useUnlayerConfig() {
|
|
1651
|
-
return
|
|
2470
|
+
return React4.useContext(getUnlayerContext());
|
|
1652
2471
|
}
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
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
|
+
}
|
|
1660
2542
|
}
|
|
1661
|
-
}
|
|
2543
|
+
}
|
|
1662
2544
|
}
|
|
1663
|
-
function
|
|
1664
|
-
|
|
1665
|
-
|
|
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");
|
|
1666
2550
|
}
|
|
1667
|
-
function
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
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
|
+
}
|
|
1675
2568
|
}
|
|
2569
|
+
var collectChildren = (node) => React4__default.default.Children.toArray(node).filter(React4__default.default.isValidElement);
|
|
1676
2570
|
function extractSemanticProps(props, extraKeys = []) {
|
|
1677
2571
|
const internalKeys = /* @__PURE__ */ new Set([
|
|
1678
2572
|
"children",
|
|
@@ -1687,6 +2581,8 @@ function extractSemanticProps(props, extraKeys = []) {
|
|
|
1687
2581
|
"_config",
|
|
1688
2582
|
"config",
|
|
1689
2583
|
"previewText",
|
|
2584
|
+
"fonts",
|
|
2585
|
+
"lang",
|
|
1690
2586
|
"layout",
|
|
1691
2587
|
"collection",
|
|
1692
2588
|
...extraKeys
|
|
@@ -1703,68 +2599,313 @@ function nextCounter(counters, key) {
|
|
|
1703
2599
|
counters[key] = (counters[key] || 0) + 1;
|
|
1704
2600
|
return counters[key];
|
|
1705
2601
|
}
|
|
1706
|
-
function
|
|
1707
|
-
if (
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
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(""));
|
|
1717
2623
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
if (js) scripts.push(js);
|
|
1723
|
-
const headTags = head.tags?.(...headArgs);
|
|
1724
|
-
if (headTags) tags.push(...headTags);
|
|
2624
|
+
return paragraphs.join("\n");
|
|
2625
|
+
} catch {
|
|
2626
|
+
return "";
|
|
2627
|
+
}
|
|
1725
2628
|
}
|
|
1726
|
-
function
|
|
1727
|
-
const componentType =
|
|
2629
|
+
function processItem(element2, counters, layout = {}, metaName) {
|
|
2630
|
+
const componentType = element2.type;
|
|
1728
2631
|
const config = componentType[UNLAYER_CONFIG_KEY];
|
|
1729
|
-
if (!config)
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
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);
|
|
2856
|
+
if (js) scripts.push(js);
|
|
2857
|
+
const headTags = head.tags?.(...headArgs);
|
|
2858
|
+
if (headTags) tags.push(...headTags);
|
|
2859
|
+
}
|
|
2860
|
+
function walkItem(element2, bodyValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles) {
|
|
2861
|
+
const componentType = element2.type;
|
|
2862
|
+
const config = componentType[UNLAYER_CONFIG_KEY];
|
|
2863
|
+
if (!config) {
|
|
2864
|
+
if (componentType?.[KEPT]) nextCounter(counters, `u_content_${(componentType.displayName || componentType.name || "component").toLowerCase()}`);
|
|
2865
|
+
return;
|
|
2866
|
+
}
|
|
2867
|
+
const { name, defaultValues, propMapper } = config;
|
|
2868
|
+
const { children, ...restProps } = element2.props;
|
|
2869
|
+
const mappedValues = propMapper({ children, ...restProps });
|
|
2870
|
+
const finalValues = mergeValues(defaultValues, mappedValues);
|
|
2871
|
+
const contentType = config.metaName ?? name.toLowerCase();
|
|
2872
|
+
const count = nextCounter(counters, `u_content_${contentType}`);
|
|
1736
2873
|
const valuesWithMeta = ensureMeta(finalValues, contentType, count - 1);
|
|
2874
|
+
collectDeviceStyles(valuesWithMeta, "contents", name, displayMode, deviceStyles);
|
|
1737
2875
|
const head = config.head ?? exporters.heads[name];
|
|
1738
2876
|
callHead(head, valuesWithMeta, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1739
2877
|
}
|
|
1740
|
-
function walkColumn(
|
|
1741
|
-
const semanticProps = extractSemanticProps(
|
|
2878
|
+
function walkColumn(element2, bodyValues, rowValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles) {
|
|
2879
|
+
const semanticProps = extractSemanticProps(element2.props);
|
|
1742
2880
|
const mapped = mapSemanticProps(semanticProps, COLUMN_DEFAULTS, "Column");
|
|
1743
2881
|
const count = nextCounter(counters, "u_column");
|
|
1744
2882
|
const columnValues = ensureMeta(mergeValues(COLUMN_DEFAULTS, mapped), "column", count - 1);
|
|
2883
|
+
collectDeviceStyles(columnValues, "columns", "Column", displayMode, deviceStyles);
|
|
1745
2884
|
const columnHead = exporters.heads["Column"];
|
|
1746
2885
|
callHead(columnHead, columnValues, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1747
|
-
const children =
|
|
2886
|
+
const children = collectChildren2(element2.props.children);
|
|
1748
2887
|
for (const child of children) {
|
|
1749
|
-
walkItem(child, bodyValues, displayMode, headConfig, counters, styles, scripts, tags);
|
|
2888
|
+
walkItem(child, bodyValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles);
|
|
1750
2889
|
}
|
|
1751
2890
|
}
|
|
1752
|
-
function walkRow(
|
|
1753
|
-
const semanticProps = extractSemanticProps(
|
|
2891
|
+
function walkRow(element2, bodyValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles) {
|
|
2892
|
+
const semanticProps = extractSemanticProps(element2.props, ["layout"]);
|
|
1754
2893
|
const mapped = mapSemanticProps(semanticProps, ROW_DEFAULTS, "Row");
|
|
1755
2894
|
const count = nextCounter(counters, "u_row");
|
|
1756
2895
|
const rowValues = ensureMeta(mergeValues(ROW_DEFAULTS, mapped), "row", count - 1);
|
|
2896
|
+
collectDeviceStyles(rowValues, "rows", "Row", displayMode, deviceStyles);
|
|
1757
2897
|
const rowHead = exporters.heads["Row"];
|
|
1758
2898
|
callHead(rowHead, rowValues, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1759
|
-
const children =
|
|
2899
|
+
const children = collectChildren2(element2.props.children);
|
|
1760
2900
|
for (const child of children) {
|
|
1761
2901
|
const name = getDisplayName(child);
|
|
1762
2902
|
if (name === "Column") {
|
|
1763
|
-
walkColumn(child, bodyValues, rowValues, displayMode, headConfig, counters, styles, scripts, tags);
|
|
2903
|
+
walkColumn(child, bodyValues, rowValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles);
|
|
1764
2904
|
}
|
|
1765
2905
|
}
|
|
1766
2906
|
}
|
|
1767
|
-
function extractHeadFromTree(
|
|
2907
|
+
function extractHeadFromTree(element2, options) {
|
|
2908
|
+
element2 = normalizedRoot(element2);
|
|
1768
2909
|
const { displayMode } = options;
|
|
1769
2910
|
const headConfig = {
|
|
1770
2911
|
hasFeature: options.headConfig?.hasFeature ?? (() => false),
|
|
@@ -1774,18 +2915,22 @@ function extractHeadFromTree(element, options) {
|
|
|
1774
2915
|
const scripts = [];
|
|
1775
2916
|
const tags = [];
|
|
1776
2917
|
const counters = {};
|
|
1777
|
-
const
|
|
2918
|
+
const deviceStyles = {};
|
|
2919
|
+
const semanticProps = extractSemanticProps(element2.props);
|
|
1778
2920
|
const mapped = mapSemanticProps(semanticProps, BODY_DEFAULTS, "Body");
|
|
1779
2921
|
const bodyValues = ensureMeta(mergeValues(BODY_DEFAULTS, mapped), "body", 0);
|
|
1780
2922
|
const bodyHead = exporters.heads["Body"];
|
|
1781
2923
|
callHead(bodyHead, bodyValues, bodyValues, displayMode, headConfig, styles, scripts, tags);
|
|
1782
|
-
const children =
|
|
2924
|
+
const children = collectChildren2(element2.props.children);
|
|
1783
2925
|
for (const child of children) {
|
|
1784
2926
|
const name = getDisplayName(child);
|
|
1785
2927
|
if (name === "Row") {
|
|
1786
|
-
walkRow(child, bodyValues, displayMode, headConfig, counters, styles, scripts, tags);
|
|
2928
|
+
walkRow(child, bodyValues, displayMode, headConfig, counters, styles, scripts, tags, deviceStyles);
|
|
1787
2929
|
}
|
|
1788
2930
|
}
|
|
2931
|
+
styles.unshift(deviceVisibilityCss(displayMode));
|
|
2932
|
+
const overrides = deviceStylesCss(deviceStyles, displayMode);
|
|
2933
|
+
if (overrides) styles.push(overrides);
|
|
1789
2934
|
const uniqueTags = [...new Set(tags.filter(Boolean))];
|
|
1790
2935
|
return {
|
|
1791
2936
|
css: styles.filter(Boolean).join("\n"),
|
|
@@ -1805,7 +2950,7 @@ function emailLayout(args) {
|
|
|
1805
2950
|
fontLinks && `<!--[if !mso]><!-->${fontLinks}<!--<![endif]-->`
|
|
1806
2951
|
].filter(Boolean).join("\n ");
|
|
1807
2952
|
return `<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
1808
|
-
<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">
|
|
1809
2954
|
<head>
|
|
1810
2955
|
<!--[if gte mso 9]>
|
|
1811
2956
|
<xml>
|
|
@@ -1829,7 +2974,7 @@ function documentLayout(args) {
|
|
|
1829
2974
|
const { dir, titleTag, tagLines, styleTag, scriptTag, fontLinks, body } = args;
|
|
1830
2975
|
const head = [titleTag, tagLines, styleTag, scriptTag, fontLinks].filter(Boolean).join("\n ");
|
|
1831
2976
|
return `<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
1832
|
-
<html${dir} xmlns="http://www.w3.org/1999/xhtml">
|
|
2977
|
+
<html${dir}${args.lang || ""} xmlns="http://www.w3.org/1999/xhtml">
|
|
1833
2978
|
<head>
|
|
1834
2979
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
|
1835
2980
|
${head}
|
|
@@ -1842,7 +2987,7 @@ function webLayout(args) {
|
|
|
1842
2987
|
const { dir, titleTag, tagLines, styleTag, scriptTag, fontLinks, body } = args;
|
|
1843
2988
|
const head = [titleTag, fontLinks, tagLines, styleTag, scriptTag].filter(Boolean).join("\n ");
|
|
1844
2989
|
return `<!doctype html>
|
|
1845
|
-
<html${dir}>
|
|
2990
|
+
<html${dir}${args.lang || ""}>
|
|
1846
2991
|
<head>
|
|
1847
2992
|
<meta charset="utf-8">
|
|
1848
2993
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
|
@@ -1863,20 +3008,25 @@ var MODE_BY_WRAPPER = {
|
|
|
1863
3008
|
Page: "web",
|
|
1864
3009
|
Document: "document"
|
|
1865
3010
|
};
|
|
1866
|
-
function
|
|
1867
|
-
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;
|
|
1868
3018
|
const wrapperMode = displayName ? MODE_BY_WRAPPER[displayName] : void 0;
|
|
1869
|
-
return wrapperMode ??
|
|
3019
|
+
return wrapperMode ?? element2.props.mode ?? mergedConfig.mode ?? "web";
|
|
1870
3020
|
}
|
|
1871
|
-
function renderBody(
|
|
1872
|
-
const mergedConfig =
|
|
3021
|
+
function renderBody(element2, config, name = "renderToHtml") {
|
|
3022
|
+
const mergedConfig = resolveConfig(element2, config);
|
|
1873
3023
|
try {
|
|
1874
|
-
const enriched =
|
|
1875
|
-
return
|
|
3024
|
+
const enriched = React4__default.default.cloneElement(element2, { config: mergedConfig });
|
|
3025
|
+
return renderToStaticMarkup(enriched);
|
|
1876
3026
|
} catch (error) {
|
|
1877
3027
|
const message = error instanceof Error ? error.message : String(error);
|
|
1878
3028
|
throw new Error(
|
|
1879
|
-
`[Unlayer]
|
|
3029
|
+
`[Unlayer] ${name} failed: ${message}
|
|
1880
3030
|
Tip: Ensure your tree uses Body > Row > Column > Item structure.`
|
|
1881
3031
|
);
|
|
1882
3032
|
}
|
|
@@ -1888,30 +3038,41 @@ function stripOuterDiv(html) {
|
|
|
1888
3038
|
function escapeForHtml(text) {
|
|
1889
3039
|
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
1890
3040
|
}
|
|
1891
|
-
function renderToHtml(
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
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;
|
|
1896
3056
|
const isUnlayerWrapper = wrapperName === "Body" || (wrapperName ? wrapperName in MODE_BY_WRAPPER : false);
|
|
1897
|
-
const rawBody = renderBody(
|
|
3057
|
+
const rawBody = renderBody(element2, config);
|
|
1898
3058
|
const body = isUnlayerWrapper ? stripOuterDiv(rawBody) : rawBody;
|
|
1899
|
-
const { css, js, tags } = extractHeadFromTree(
|
|
3059
|
+
const { css: css2, js, tags } = extractHeadFromTree(element2, {
|
|
1900
3060
|
displayMode,
|
|
1901
3061
|
headConfig: mergedConfig.headConfig
|
|
1902
3062
|
});
|
|
1903
3063
|
const layoutArgs = {
|
|
3064
|
+
lang: lang ? ` lang="${escapeForHtml(String(lang))}"` : "",
|
|
1904
3065
|
dir: mergedConfig.textDirection ? ` dir="${escapeForHtml(String(mergedConfig.textDirection))}"` : "",
|
|
1905
3066
|
titleTag: title ? `<title>${escapeForHtml(title.trim())}</title>` : "",
|
|
1906
|
-
styleTag:
|
|
1907
|
-
${
|
|
3067
|
+
styleTag: css2 ? `<style type="text/css">
|
|
3068
|
+
${styleText(css2)}
|
|
1908
3069
|
</style>` : "",
|
|
1909
3070
|
scriptTag: js ? `<script type="application/javascript">
|
|
1910
3071
|
${js}
|
|
1911
3072
|
</script>` : "",
|
|
1912
3073
|
tagLines: tags.join("\n"),
|
|
1913
3074
|
fontLinks: fonts.filter((font) => font?.url).map(
|
|
1914
|
-
(font) => `<link href="${escapeForHtml(font.url)}" rel="stylesheet" type="text/css">`
|
|
3075
|
+
(font) => `<link href="${escapeForHtml(String(font.url))}" rel="stylesheet" type="text/css">`
|
|
1915
3076
|
).join(""),
|
|
1916
3077
|
body
|
|
1917
3078
|
};
|
|
@@ -1919,21 +3080,29 @@ ${js}
|
|
|
1919
3080
|
if (displayMode === "document") return documentLayout(layoutArgs);
|
|
1920
3081
|
return webLayout(layoutArgs);
|
|
1921
3082
|
}
|
|
1922
|
-
function renderToPlainText(
|
|
1923
|
-
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
|
+
});
|
|
1924
3089
|
return htmlToPlainText(html);
|
|
1925
3090
|
}
|
|
1926
|
-
function renderToHtmlParts(
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
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, {
|
|
1931
3100
|
displayMode,
|
|
1932
3101
|
headConfig: mergedConfig.headConfig
|
|
1933
3102
|
});
|
|
1934
3103
|
const headParts = [];
|
|
1935
|
-
if (
|
|
1936
|
-
headParts.push(`<style>${
|
|
3104
|
+
if (css2) {
|
|
3105
|
+
headParts.push(`<style>${styleText(css2)}</style>`);
|
|
1937
3106
|
}
|
|
1938
3107
|
if (js) {
|
|
1939
3108
|
headParts.push(`<script>${js}</script>`);
|
|
@@ -1944,291 +3113,11 @@ function renderToHtmlParts(element, config) {
|
|
|
1944
3113
|
return {
|
|
1945
3114
|
head: headParts.join("\n"),
|
|
1946
3115
|
body,
|
|
1947
|
-
css,
|
|
3116
|
+
css: css2,
|
|
1948
3117
|
js,
|
|
1949
3118
|
tags
|
|
1950
3119
|
};
|
|
1951
3120
|
}
|
|
1952
|
-
var schemaVersion = exporters.schemaVersion ?? 24;
|
|
1953
|
-
function getDisplayName2(element) {
|
|
1954
|
-
const type = element.type;
|
|
1955
|
-
return type?.displayName || type?.name;
|
|
1956
|
-
}
|
|
1957
|
-
var VALID_ROOTS = /* @__PURE__ */ new Set(["Body", "Email", "Page", "Document"]);
|
|
1958
|
-
function unwrapRoot(element) {
|
|
1959
|
-
let current = element;
|
|
1960
|
-
for (let depth = 0; depth < 10; depth++) {
|
|
1961
|
-
const name = getDisplayName2(current);
|
|
1962
|
-
if (name && VALID_ROOTS.has(name)) break;
|
|
1963
|
-
const type = current.type;
|
|
1964
|
-
const isPlainFunctionComponent = typeof type === "function" && !type.prototype?.isReactComponent;
|
|
1965
|
-
if (!isPlainFunctionComponent) break;
|
|
1966
|
-
let produced;
|
|
1967
|
-
try {
|
|
1968
|
-
produced = type({ ...current.props });
|
|
1969
|
-
} catch (cause) {
|
|
1970
|
-
const detail = cause instanceof Error ? cause.message : String(cause);
|
|
1971
|
-
throw new Error(
|
|
1972
|
-
`[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})`
|
|
1973
|
-
);
|
|
1974
|
-
}
|
|
1975
|
-
if (!React__default.default.isValidElement(produced)) break;
|
|
1976
|
-
current = produced;
|
|
1977
|
-
}
|
|
1978
|
-
return current;
|
|
1979
|
-
}
|
|
1980
|
-
function collectChildren2(node) {
|
|
1981
|
-
const result = [];
|
|
1982
|
-
React__default.default.Children.forEach(node, (child) => {
|
|
1983
|
-
if (React__default.default.isValidElement(child)) {
|
|
1984
|
-
result.push(child);
|
|
1985
|
-
}
|
|
1986
|
-
});
|
|
1987
|
-
return result;
|
|
1988
|
-
}
|
|
1989
|
-
function extractSemanticProps2(props, extraKeys = []) {
|
|
1990
|
-
const internalKeys = /* @__PURE__ */ new Set([
|
|
1991
|
-
"children",
|
|
1992
|
-
"mode",
|
|
1993
|
-
"className",
|
|
1994
|
-
"style",
|
|
1995
|
-
"index",
|
|
1996
|
-
"colIndex",
|
|
1997
|
-
"cells",
|
|
1998
|
-
"bodyValues",
|
|
1999
|
-
"rowValues",
|
|
2000
|
-
"_config",
|
|
2001
|
-
"config",
|
|
2002
|
-
"previewText",
|
|
2003
|
-
"layout",
|
|
2004
|
-
"collection",
|
|
2005
|
-
...extraKeys
|
|
2006
|
-
]);
|
|
2007
|
-
const result = {};
|
|
2008
|
-
for (const [key, value] of Object.entries(props)) {
|
|
2009
|
-
if (!internalKeys.has(key) && value !== void 0) {
|
|
2010
|
-
result[key] = value;
|
|
2011
|
-
}
|
|
2012
|
-
}
|
|
2013
|
-
return result;
|
|
2014
|
-
}
|
|
2015
|
-
function nextCounter2(counters, key) {
|
|
2016
|
-
counters[key] = (counters[key] || 0) + 1;
|
|
2017
|
-
return counters[key];
|
|
2018
|
-
}
|
|
2019
|
-
function toContentType(displayName) {
|
|
2020
|
-
if (displayName === "Paragraph") return "text";
|
|
2021
|
-
return displayName.toLowerCase();
|
|
2022
|
-
}
|
|
2023
|
-
function makeId(prefix, counter) {
|
|
2024
|
-
return `${prefix}_${counter}`;
|
|
2025
|
-
}
|
|
2026
|
-
function extractTextFromTextJson(textJson) {
|
|
2027
|
-
try {
|
|
2028
|
-
const parsed = JSON.parse(textJson);
|
|
2029
|
-
if (parsed.__html) return parsed.__html;
|
|
2030
|
-
const root = parsed?.root;
|
|
2031
|
-
if (!root?.children) return "";
|
|
2032
|
-
const paragraphs = [];
|
|
2033
|
-
for (const paragraph of root.children) {
|
|
2034
|
-
if (!paragraph?.children) continue;
|
|
2035
|
-
const parts = [];
|
|
2036
|
-
for (const node of paragraph.children) {
|
|
2037
|
-
if (node?.text) parts.push(node.text);
|
|
2038
|
-
}
|
|
2039
|
-
paragraphs.push(parts.join(""));
|
|
2040
|
-
}
|
|
2041
|
-
return paragraphs.join("\n");
|
|
2042
|
-
} catch {
|
|
2043
|
-
return "";
|
|
2044
|
-
}
|
|
2045
|
-
}
|
|
2046
|
-
function processItem(element, counters, layout = {}) {
|
|
2047
|
-
const componentType = element.type;
|
|
2048
|
-
const config = componentType[UNLAYER_CONFIG_KEY];
|
|
2049
|
-
if (!config) {
|
|
2050
|
-
const name2 = getDisplayName2(element) || "Unknown";
|
|
2051
|
-
throw new Error(
|
|
2052
|
-
`[Unlayer] renderToJson: <${name2}> is not a recognized Unlayer item component. Only components created with createItemComponent are supported.`
|
|
2053
|
-
);
|
|
2054
|
-
}
|
|
2055
|
-
const { name, defaultValues, propMapper, slug } = config;
|
|
2056
|
-
const contentType = config.contentType ?? toContentType(name);
|
|
2057
|
-
const metaBase = `u_content_${config.metaName ?? contentType}`;
|
|
2058
|
-
const count = nextCounter2(counters, metaBase);
|
|
2059
|
-
const id = makeId(metaBase, count);
|
|
2060
|
-
const { children, ...restProps } = element.props;
|
|
2061
|
-
const mappedValues = propMapper({ children, ...restProps });
|
|
2062
|
-
const finalValues = mergeValues(defaultValues, mappedValues);
|
|
2063
|
-
if (contentType === "text" && finalValues.textJson) {
|
|
2064
|
-
finalValues.text = extractTextFromTextJson(finalValues.textJson);
|
|
2065
|
-
delete finalValues.textJson;
|
|
2066
|
-
}
|
|
2067
|
-
const values = {
|
|
2068
|
-
containerPadding: "10px",
|
|
2069
|
-
...finalValues,
|
|
2070
|
-
_meta: {
|
|
2071
|
-
htmlID: id,
|
|
2072
|
-
htmlClassNames: metaBase,
|
|
2073
|
-
...finalValues._meta || {}
|
|
2074
|
-
},
|
|
2075
|
-
selectable: true,
|
|
2076
|
-
draggable: true,
|
|
2077
|
-
duplicatable: true,
|
|
2078
|
-
deletable: true,
|
|
2079
|
-
hideable: true
|
|
2080
|
-
};
|
|
2081
|
-
const itemSrc = values.src;
|
|
2082
|
-
if (itemSrc && typeof itemSrc === "object" && itemSrc.autoWidth === false) {
|
|
2083
|
-
const availableWidth = contentSlotWidth({
|
|
2084
|
-
...layout,
|
|
2085
|
-
containerPadding: values.containerPadding
|
|
2086
|
-
});
|
|
2087
|
-
values.src = pinImageSrc(itemSrc, availableWidth);
|
|
2088
|
-
}
|
|
2089
|
-
return slug ? { type: contentType, slug, values } : { type: contentType, values };
|
|
2090
|
-
}
|
|
2091
|
-
function processColumn(element, counters, layout = {}) {
|
|
2092
|
-
const count = nextCounter2(counters, "u_column");
|
|
2093
|
-
const id = makeId("u_column", count);
|
|
2094
|
-
const semanticProps = extractSemanticProps2(element.props);
|
|
2095
|
-
const mapped = mapSemanticProps(semanticProps, COLUMN_DEFAULTS, "Column");
|
|
2096
|
-
const values = mergeValues(COLUMN_DEFAULTS, mapped);
|
|
2097
|
-
const valuesWithMeta = {
|
|
2098
|
-
...values,
|
|
2099
|
-
_meta: {
|
|
2100
|
-
htmlID: id,
|
|
2101
|
-
htmlClassNames: "u_column",
|
|
2102
|
-
...values._meta || {}
|
|
2103
|
-
}
|
|
2104
|
-
};
|
|
2105
|
-
const contents = [];
|
|
2106
|
-
const children = collectChildren2(element.props.children);
|
|
2107
|
-
const itemLayout = { ...layout, columnValues: valuesWithMeta };
|
|
2108
|
-
for (const child of children) {
|
|
2109
|
-
contents.push(processItem(child, counters, itemLayout));
|
|
2110
|
-
}
|
|
2111
|
-
return { contents, values: valuesWithMeta };
|
|
2112
|
-
}
|
|
2113
|
-
function processRow(element, counters, parentLayout = {}) {
|
|
2114
|
-
const count = nextCounter2(counters, "u_row");
|
|
2115
|
-
const id = makeId("u_row", count);
|
|
2116
|
-
const { layout, cells: propsCells } = element.props;
|
|
2117
|
-
let cells;
|
|
2118
|
-
if (layout) {
|
|
2119
|
-
cells = layout.cells;
|
|
2120
|
-
} else if (propsCells) {
|
|
2121
|
-
cells = propsCells;
|
|
2122
|
-
} else {
|
|
2123
|
-
const columnCount = Math.max(
|
|
2124
|
-
1,
|
|
2125
|
-
collectChildren2(element.props.children).filter(
|
|
2126
|
-
(child) => getDisplayName2(child) === "Column"
|
|
2127
|
-
).length
|
|
2128
|
-
);
|
|
2129
|
-
cells = Array(columnCount).fill(1);
|
|
2130
|
-
}
|
|
2131
|
-
const semanticProps = extractSemanticProps2(element.props, ["layout"]);
|
|
2132
|
-
const mapped = mapSemanticProps(semanticProps, ROW_DEFAULTS, "Row");
|
|
2133
|
-
const values = mergeValues(ROW_DEFAULTS, mapped);
|
|
2134
|
-
const valuesWithMeta = {
|
|
2135
|
-
...values,
|
|
2136
|
-
columns: values.columns ?? false,
|
|
2137
|
-
cells,
|
|
2138
|
-
_meta: {
|
|
2139
|
-
htmlID: id,
|
|
2140
|
-
htmlClassNames: "u_row",
|
|
2141
|
-
...values._meta || {}
|
|
2142
|
-
},
|
|
2143
|
-
selectable: true,
|
|
2144
|
-
draggable: true,
|
|
2145
|
-
duplicatable: true,
|
|
2146
|
-
deletable: true,
|
|
2147
|
-
hideable: true
|
|
2148
|
-
};
|
|
2149
|
-
const columns = [];
|
|
2150
|
-
const children = collectChildren2(element.props.children);
|
|
2151
|
-
const columnLayout = {
|
|
2152
|
-
bodyValues: parentLayout.bodyValues,
|
|
2153
|
-
rowValues: valuesWithMeta,
|
|
2154
|
-
rowCells: cells
|
|
2155
|
-
};
|
|
2156
|
-
let columnIndex = 0;
|
|
2157
|
-
for (const child of children) {
|
|
2158
|
-
const name = getDisplayName2(child);
|
|
2159
|
-
if (name === "Column") {
|
|
2160
|
-
columns.push(
|
|
2161
|
-
processColumn(child, counters, { ...columnLayout, columnIndex })
|
|
2162
|
-
);
|
|
2163
|
-
columnIndex += 1;
|
|
2164
|
-
} else {
|
|
2165
|
-
console.warn(
|
|
2166
|
-
`[Unlayer] renderToJson: <${name}> is not a valid Row child. Only <Column> is allowed.`
|
|
2167
|
-
);
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
return { cells, columns, values: valuesWithMeta };
|
|
2171
|
-
}
|
|
2172
|
-
function processBody(element, counters) {
|
|
2173
|
-
const id = "u_body";
|
|
2174
|
-
const semanticProps = extractSemanticProps2(element.props);
|
|
2175
|
-
const mapped = mapSemanticProps(semanticProps, BODY_DEFAULTS, "Body");
|
|
2176
|
-
const values = mergeValues(BODY_DEFAULTS, mapped);
|
|
2177
|
-
const previewText = element.props.previewText;
|
|
2178
|
-
if (previewText !== void 0) {
|
|
2179
|
-
values.preheaderText = previewText;
|
|
2180
|
-
}
|
|
2181
|
-
const valuesWithMeta = {
|
|
2182
|
-
...values,
|
|
2183
|
-
_meta: {
|
|
2184
|
-
htmlID: id,
|
|
2185
|
-
htmlClassNames: "u_body",
|
|
2186
|
-
...values._meta || {}
|
|
2187
|
-
}
|
|
2188
|
-
};
|
|
2189
|
-
const rows = [];
|
|
2190
|
-
const children = collectChildren2(element.props.children);
|
|
2191
|
-
for (const child of children) {
|
|
2192
|
-
const name = getDisplayName2(child);
|
|
2193
|
-
if (name === "Row") {
|
|
2194
|
-
rows.push(processRow(child, counters, { bodyValues: valuesWithMeta }));
|
|
2195
|
-
} else {
|
|
2196
|
-
console.warn(
|
|
2197
|
-
`[Unlayer] renderToJson: <${name}> is not a valid Body child. Only <Row> is allowed.`
|
|
2198
|
-
);
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
return {
|
|
2202
|
-
rows,
|
|
2203
|
-
values: valuesWithMeta
|
|
2204
|
-
};
|
|
2205
|
-
}
|
|
2206
|
-
function renderRowToJson(element) {
|
|
2207
|
-
const displayName = getDisplayName2(element);
|
|
2208
|
-
if (displayName !== "Row") {
|
|
2209
|
-
throw new Error(
|
|
2210
|
-
`[Unlayer] renderRowToJson: Element must be <Row>, but got <${displayName || "unknown"}>. For full designs, use renderToJson instead.`
|
|
2211
|
-
);
|
|
2212
|
-
}
|
|
2213
|
-
const counters = {};
|
|
2214
|
-
return processRow(element, counters);
|
|
2215
|
-
}
|
|
2216
|
-
function renderToJson(element) {
|
|
2217
|
-
element = unwrapRoot(element);
|
|
2218
|
-
const displayName = getDisplayName2(element);
|
|
2219
|
-
if (!displayName || !VALID_ROOTS.has(displayName)) {
|
|
2220
|
-
throw new Error(
|
|
2221
|
-
`[Unlayer] renderToJson: Root element must be <Body>, <Email>, <Page>, or <Document>, but got <${displayName || "unknown"}>. Wrap your content: <Body><Row><Column>...</Column></Row></Body>`
|
|
2222
|
-
);
|
|
2223
|
-
}
|
|
2224
|
-
const counters = {};
|
|
2225
|
-
const body = processBody(element, counters);
|
|
2226
|
-
return {
|
|
2227
|
-
counters,
|
|
2228
|
-
body,
|
|
2229
|
-
schemaVersion
|
|
2230
|
-
};
|
|
2231
|
-
}
|
|
2232
3121
|
|
|
2233
3122
|
// src/utils/register-tool.tsx
|
|
2234
3123
|
function initialValuesFromOptions(options) {
|