@designcrowd/library.brand-page 6.0.6-json-prereq-1 → 6.0.6-json-prereq-3
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/lib/src/{CreatedOnBrandCrowd-de-de-Dx3e-vQ6.js → CreatedOnBrandCrowd-de-de-CvDAZ3Qq.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-CbchLDa2.js → CreatedOnBrandCrowd-en-us-DgROckDq.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-BXbpN7li.js → CreatedOnBrandCrowd-es-es-lvQ5oABV.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-hIk7h9bV.js → CreatedOnBrandCrowd-fr-ca-DDM2q89U.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-hIk7h9bV.js → CreatedOnBrandCrowd-fr-fr-DDM2q89U.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-CqsCRIqc.js → CreatedOnBrandCrowd-pt-br-xlgcCsw2.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-CqsCRIqc.js → CreatedOnBrandCrowd-pt-pt-xlgcCsw2.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-NEOtgsvz.js → CreatedOnDcom-de-de-BtoXg_n-.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-CKtEdcoG.js → CreatedOnDcom-en-us-DxcNxmi9.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-DZR9o6DK.js → CreatedOnDcom-es-es-BWaZAgQW.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-Bo_oTp-T.js → CreatedOnDcom-fr-ca-Co05A_WA.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-DE6Fa3ie.js → CreatedOnDcom-fr-fr-BtJXovuS.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-Cws2QJ7J.js → CreatedOnDcom-pt-br-DWIPipkQ.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-DYGQo6q3.js → CreatedOnDcom-pt-pt-BIfV_ZdE.js} +1 -1
- package/lib/src/brand-page-maker/utils/rte-render.util.d.ts +8 -7
- package/lib/src/brand-page-maker/utils/rte-render.util.js +8 -36
- package/lib/src/brand-page-maker/utils/rte-serializer.d.ts +5 -0
- package/lib/src/brand-page-maker/utils/rte-serializer.js +112 -0
- package/lib/src/index.mjs +1 -1
- package/lib/src/{lib-C5H_bvMR.js → lib-BHQg-PvG.js} +16218 -16140
- package/lib/src/shared/content-settings/components/GenericTextInput.mixin.js +14 -1
- package/package.json +1 -1
- package/src/brand-page-maker/utils/__snapshots__/rte-render-parity.test.ts.snap +2 -0
- package/src/brand-page-maker/utils/rte-render-parity.test.ts +21 -9
- package/src/brand-page-maker/utils/rte-render.util.ts +12 -47
- package/src/brand-page-maker/utils/rte-serializer.ts +172 -0
- package/src/shared/content-settings/components/GenericTextInput.mixin.ts +17 -1
|
@@ -12,16 +12,17 @@ export { isTiptapDocument, getRteJsonPlainText };
|
|
|
12
12
|
* - renderRteToHtml — render either form to final HTML for display.
|
|
13
13
|
* - toRteJson — normalise either form to JSON for storage.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
15
|
+
* - renderRteToHtml uses a DOM-less serialiser (works on the server).
|
|
16
|
+
* - toRteJson uses a headless editor to PARSE HTML → JSON, so it only runs
|
|
17
|
+
* where a DOM exists (browser, or jsdom in tests); the server never parses
|
|
18
|
+
* HTML (migration-18 is DOM-guarded, translation/fraud walk JSON directly).
|
|
18
19
|
*/
|
|
19
20
|
export type RichTextValue = string | JSONContent;
|
|
20
21
|
/**
|
|
21
|
-
* Render an RTE value to final HTML. Legacy HTML strings pass through
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* Render an RTE value to final HTML. Legacy HTML strings pass through untouched
|
|
23
|
+
* (they are already HTML); Tiptap JSON is serialised by a DOM-less pure
|
|
24
|
+
* function (rte-serializer) — no editor, no DOM — so it works on the server
|
|
25
|
+
* (SSR/publish), not just the browser, and is cheap enough to run per render.
|
|
25
26
|
*/
|
|
26
27
|
export declare const renderRteToHtml: (value: RichTextValue | null | undefined) => string;
|
|
27
28
|
/**
|
|
@@ -1,15 +1,12 @@
|
|
|
1
1
|
import { Editor } from '@tiptap/vue-3';
|
|
2
2
|
import { getRteExtensions } from '../composables/rich-text-editor/getRteExtensions';
|
|
3
3
|
import { isTiptapDocument, getRteJsonPlainText } from './rich-text-editor.util';
|
|
4
|
+
import { serializeRteJsonToHtml } from './rte-serializer';
|
|
4
5
|
export { isTiptapDocument, getRteJsonPlainText };
|
|
5
6
|
/**
|
|
6
7
|
* Run a function with a short-lived headless editor (created then destroyed).
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* editor throws "document is not defined" when a test DOM (jsdom) is torn down.
|
|
10
|
-
* The expensive repeat-render case (re-rendering unchanged content on a
|
|
11
|
-
* display-style/layout change) is handled by the render cache below, so this
|
|
12
|
-
* only runs on a cache miss — i.e. genuinely new/changed content.
|
|
8
|
+
* Used only by toRteJson (HTML → JSON parsing), which needs a real DOM. Not
|
|
9
|
+
* used by the render path, which is DOM-less.
|
|
13
10
|
*/
|
|
14
11
|
const withHeadlessEditor = (fn) => {
|
|
15
12
|
const editor = new Editor({
|
|
@@ -24,42 +21,17 @@ const withHeadlessEditor = (fn) => {
|
|
|
24
21
|
}
|
|
25
22
|
};
|
|
26
23
|
/**
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* keyed by the document makes those repeat renders a near-free map lookup.
|
|
32
|
-
*/
|
|
33
|
-
const RENDER_CACHE_LIMIT = 200;
|
|
34
|
-
const renderCache = new Map();
|
|
35
|
-
/**
|
|
36
|
-
* Render an RTE value to final HTML. Legacy HTML strings pass through
|
|
37
|
-
* untouched (they are already HTML); Tiptap JSON is rendered via the
|
|
38
|
-
* headless editor's renderHTML, matching the stored-HTML output exactly,
|
|
39
|
-
* and memoised so repeat renders of unchanged content don't re-convert.
|
|
24
|
+
* Render an RTE value to final HTML. Legacy HTML strings pass through untouched
|
|
25
|
+
* (they are already HTML); Tiptap JSON is serialised by a DOM-less pure
|
|
26
|
+
* function (rte-serializer) — no editor, no DOM — so it works on the server
|
|
27
|
+
* (SSR/publish), not just the browser, and is cheap enough to run per render.
|
|
40
28
|
*/
|
|
41
29
|
export const renderRteToHtml = (value) => {
|
|
42
30
|
if (value == null || value === '')
|
|
43
31
|
return '';
|
|
44
32
|
if (typeof value === 'string')
|
|
45
33
|
return value;
|
|
46
|
-
|
|
47
|
-
const cached = renderCache.get(key);
|
|
48
|
-
if (cached !== undefined) {
|
|
49
|
-
// LRU bump: re-insert so the most-recently-used key is evicted last.
|
|
50
|
-
renderCache.delete(key);
|
|
51
|
-
renderCache.set(key, cached);
|
|
52
|
-
return cached;
|
|
53
|
-
}
|
|
54
|
-
const html = withHeadlessEditor((editor) => {
|
|
55
|
-
editor.commands.setContent(value);
|
|
56
|
-
return editor.getHTML();
|
|
57
|
-
});
|
|
58
|
-
renderCache.set(key, html);
|
|
59
|
-
if (renderCache.size > RENDER_CACHE_LIMIT) {
|
|
60
|
-
renderCache.delete(renderCache.keys().next().value);
|
|
61
|
-
}
|
|
62
|
-
return html;
|
|
34
|
+
return serializeRteJsonToHtml(value);
|
|
63
35
|
};
|
|
64
36
|
/**
|
|
65
37
|
* Normalise an RTE value to a Tiptap JSON document. HTML strings are parsed
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const escapeHtml = (value) => value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
2
|
+
const escapeAttr = (value) => escapeHtml(value).replace(/"/g, '"');
|
|
3
|
+
// textStyle attr → CSS property, in a stable order.
|
|
4
|
+
const TEXT_STYLE_PROPS = [
|
|
5
|
+
['fontFamily', 'font-family'],
|
|
6
|
+
['fontSize', 'font-size'],
|
|
7
|
+
['letterSpacing', 'letter-spacing'],
|
|
8
|
+
['lineHeight', 'line-height'],
|
|
9
|
+
['color', 'color'],
|
|
10
|
+
];
|
|
11
|
+
const textStyleCss = (attrs) => TEXT_STYLE_PROPS.filter(([key]) => typeof attrs[key] === 'string' && attrs[key])
|
|
12
|
+
.map(([key, css]) => `${css}: ${attrs[key]}`)
|
|
13
|
+
.join('; ');
|
|
14
|
+
// Outermost → innermost. Reversed at wrap time so links wrap outside spans,
|
|
15
|
+
// which wrap outside the plain formatting marks.
|
|
16
|
+
const MARK_ORDER = [
|
|
17
|
+
'link',
|
|
18
|
+
'textStyle',
|
|
19
|
+
'highlight',
|
|
20
|
+
'strike',
|
|
21
|
+
'underline',
|
|
22
|
+
'italic',
|
|
23
|
+
'bold',
|
|
24
|
+
'code',
|
|
25
|
+
];
|
|
26
|
+
const wrapMark = (type, attrs, inner) => {
|
|
27
|
+
switch (type) {
|
|
28
|
+
case 'bold':
|
|
29
|
+
return `<strong>${inner}</strong>`;
|
|
30
|
+
case 'italic':
|
|
31
|
+
return `<em>${inner}</em>`;
|
|
32
|
+
case 'underline':
|
|
33
|
+
return `<u>${inner}</u>`;
|
|
34
|
+
case 'strike':
|
|
35
|
+
return `<s>${inner}</s>`;
|
|
36
|
+
case 'code':
|
|
37
|
+
return `<code>${inner}</code>`;
|
|
38
|
+
case 'textStyle': {
|
|
39
|
+
const css = textStyleCss(attrs);
|
|
40
|
+
return css ? `<span style="${escapeAttr(css)}">${inner}</span>` : inner;
|
|
41
|
+
}
|
|
42
|
+
case 'highlight': {
|
|
43
|
+
const color = typeof attrs.color === 'string' ? attrs.color : '';
|
|
44
|
+
return color
|
|
45
|
+
? `<mark data-color="${escapeAttr(color)}" style="background-color: ${escapeAttr(color)}; color: inherit;">${inner}</mark>`
|
|
46
|
+
: `<mark>${inner}</mark>`;
|
|
47
|
+
}
|
|
48
|
+
case 'link': {
|
|
49
|
+
const href = typeof attrs.href === 'string' ? attrs.href : '';
|
|
50
|
+
let open = `<a href="${escapeAttr(href)}"`;
|
|
51
|
+
if (attrs.target)
|
|
52
|
+
open += ` target="${escapeAttr(String(attrs.target))}"`;
|
|
53
|
+
if (attrs.rel)
|
|
54
|
+
open += ` rel="${escapeAttr(String(attrs.rel))}"`;
|
|
55
|
+
return `${open}>${inner}</a>`;
|
|
56
|
+
}
|
|
57
|
+
default:
|
|
58
|
+
return inner;
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
const renderText = (node) => {
|
|
62
|
+
let html = escapeHtml(node.text ?? '');
|
|
63
|
+
const marks = Array.isArray(node.marks) ? node.marks : [];
|
|
64
|
+
for (const type of [...MARK_ORDER].reverse()) {
|
|
65
|
+
const mark = marks.find((m) => m?.type === type);
|
|
66
|
+
if (mark)
|
|
67
|
+
html = wrapMark(type, mark.attrs ?? {}, html);
|
|
68
|
+
}
|
|
69
|
+
return html;
|
|
70
|
+
};
|
|
71
|
+
const alignAttr = (node) => {
|
|
72
|
+
const align = node.attrs?.textAlign;
|
|
73
|
+
return typeof align === 'string' && align
|
|
74
|
+
? ` style="text-align: ${escapeAttr(align)}"`
|
|
75
|
+
: '';
|
|
76
|
+
};
|
|
77
|
+
const renderChildren = (node) => (node.content ?? []).map(renderNode).join('');
|
|
78
|
+
const renderNode = (node) => {
|
|
79
|
+
if (!node || typeof node !== 'object')
|
|
80
|
+
return '';
|
|
81
|
+
switch (node.type) {
|
|
82
|
+
case 'text':
|
|
83
|
+
return renderText(node);
|
|
84
|
+
case 'hardBreak':
|
|
85
|
+
return '<br>';
|
|
86
|
+
case 'horizontalRule':
|
|
87
|
+
return '<hr>';
|
|
88
|
+
case 'paragraph':
|
|
89
|
+
return `<p${alignAttr(node)}>${renderChildren(node)}</p>`;
|
|
90
|
+
case 'heading': {
|
|
91
|
+
const level = Math.min(6, Math.max(1, Number(node.attrs?.level) || 1));
|
|
92
|
+
return `<h${level}${alignAttr(node)}>${renderChildren(node)}</h${level}>`;
|
|
93
|
+
}
|
|
94
|
+
case 'bulletList':
|
|
95
|
+
return `<ul>${renderChildren(node)}</ul>`;
|
|
96
|
+
case 'orderedList':
|
|
97
|
+
return `<ol>${renderChildren(node)}</ol>`;
|
|
98
|
+
case 'listItem':
|
|
99
|
+
return `<li>${renderChildren(node)}</li>`;
|
|
100
|
+
case 'blockquote':
|
|
101
|
+
return `<blockquote>${renderChildren(node)}</blockquote>`;
|
|
102
|
+
case 'codeBlock':
|
|
103
|
+
return `<pre><code>${renderChildren(node)}</code></pre>`;
|
|
104
|
+
// doc and any unknown container: render children.
|
|
105
|
+
default:
|
|
106
|
+
return renderChildren(node);
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Serialise a Tiptap JSON document to HTML without an editor/DOM.
|
|
111
|
+
*/
|
|
112
|
+
export const serializeRteJsonToHtml = (doc) => renderChildren(doc);
|
package/lib/src/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as _, a as E, b as s, c as I, d as S, e as N, f as e, B as A, g as O, h as t, i as C, j as G, k as D, l as P, m as R, n as o, o as L, p as M, q as r, r as n, s as b, t as l, u as i, v as c, w as F, x as g, y as B, z as Y, C as U, D as d, E as u, F as H, G as p, H as y, I as m, J as K, K as k, L as V, M as X, N as v, O as h, P as x, Q as f, R as W, S as z, T as w, U as J, V as Z, W as j, X as q, Y as Q, Z as $, $ as aa, a0 as Ta, a1 as _a, a2 as Ea, a3 as sa, a4 as Ia, a5 as Sa, a6 as Na, a7 as ea, a8 as Aa, a9 as Oa, aa as ta, ab as Ca, ac as Ga, ad as Da, ae as Pa, af as Ra, ag as oa, ah as La, ai as Ma, aj as ra, ak as na, al as ba, am as la, an as ia, ao as ca, ap as Fa, aq as ga, ar as Ba, as as Ya, at as Ua, au as da, av as ua, aw as Ha, ax as pa, ay as ya, az as ma, aA as Ka, aB as ka, aC as Va, aD as Xa, aE as va, aF as ha, aG as xa, aH as fa, aI as Wa, aJ as za, aK as wa, aL as Ja, aM as Za, aN as ja, aO as qa, aP as Qa, aQ as $a, aR as aT, aS as TT, aT as _T, aU as ET, aV as sT, aW as IT, aX as ST, aY as NT, aZ as eT, a_ as AT, a$ as OT, b0 as tT, b1 as CT, b2 as GT, b3 as DT, b4 as PT, b5 as RT, b6 as oT, b7 as LT, b8 as MT, b9 as rT, ba as nT, bb as bT, bc as lT, bd as iT, be as cT, bf as FT, bg as gT, bh as BT, bi as YT, bj as UT, bk as dT, bl as uT, bm as HT, bn as pT, bo as yT, bp as mT, bq as KT, br as kT, bs as VT, bt as XT, bu as vT, bv as hT, bw as xT, bx as fT, by as WT, bz as zT, bA as wT, bB as JT, bC as ZT, bD as jT, bE as qT, bF as QT, bG as $T, bH as a_, bI as T_, bJ as __, bK as E_, bL as s_, bM as I_, bN as S_, bO as N_, bP as e_, bQ as A_, bR as O_, bS as t_, bT as C_, bU as G_, bV as D_, bW as P_, bX as R_, bY as o_, bZ as L_, b_ as M_, b$ as r_, c0 as n_, c1 as b_, c2 as l_, c3 as i_, c4 as c_, c5 as F_, c6 as g_, c7 as B_, c8 as Y_, c9 as U_, ca as d_, cb as u_, cc as H_, cd as p_, ce as y_, cf as m_, cg as K_, ch as k_, ci as V_, cj as X_, ck as v_, cl as h_, cm as x_, cn as f_, co as W_, cp as z_, cq as w_, cr as J_, cs as Z_, ct as j_, cu as q_, cv as Q_, cw as $_, cx as aE, cy as TE, cz as _E } from "./lib-
|
|
1
|
+
import { A as _, a as E, b as s, c as I, d as S, e as N, f as e, B as A, g as O, h as t, i as C, j as G, k as D, l as P, m as R, n as o, o as L, p as M, q as r, r as n, s as b, t as l, u as i, v as c, w as F, x as g, y as B, z as Y, C as U, D as d, E as u, F as H, G as p, H as y, I as m, J as K, K as k, L as V, M as X, N as v, O as h, P as x, Q as f, R as W, S as z, T as w, U as J, V as Z, W as j, X as q, Y as Q, Z as $, $ as aa, a0 as Ta, a1 as _a, a2 as Ea, a3 as sa, a4 as Ia, a5 as Sa, a6 as Na, a7 as ea, a8 as Aa, a9 as Oa, aa as ta, ab as Ca, ac as Ga, ad as Da, ae as Pa, af as Ra, ag as oa, ah as La, ai as Ma, aj as ra, ak as na, al as ba, am as la, an as ia, ao as ca, ap as Fa, aq as ga, ar as Ba, as as Ya, at as Ua, au as da, av as ua, aw as Ha, ax as pa, ay as ya, az as ma, aA as Ka, aB as ka, aC as Va, aD as Xa, aE as va, aF as ha, aG as xa, aH as fa, aI as Wa, aJ as za, aK as wa, aL as Ja, aM as Za, aN as ja, aO as qa, aP as Qa, aQ as $a, aR as aT, aS as TT, aT as _T, aU as ET, aV as sT, aW as IT, aX as ST, aY as NT, aZ as eT, a_ as AT, a$ as OT, b0 as tT, b1 as CT, b2 as GT, b3 as DT, b4 as PT, b5 as RT, b6 as oT, b7 as LT, b8 as MT, b9 as rT, ba as nT, bb as bT, bc as lT, bd as iT, be as cT, bf as FT, bg as gT, bh as BT, bi as YT, bj as UT, bk as dT, bl as uT, bm as HT, bn as pT, bo as yT, bp as mT, bq as KT, br as kT, bs as VT, bt as XT, bu as vT, bv as hT, bw as xT, bx as fT, by as WT, bz as zT, bA as wT, bB as JT, bC as ZT, bD as jT, bE as qT, bF as QT, bG as $T, bH as a_, bI as T_, bJ as __, bK as E_, bL as s_, bM as I_, bN as S_, bO as N_, bP as e_, bQ as A_, bR as O_, bS as t_, bT as C_, bU as G_, bV as D_, bW as P_, bX as R_, bY as o_, bZ as L_, b_ as M_, b$ as r_, c0 as n_, c1 as b_, c2 as l_, c3 as i_, c4 as c_, c5 as F_, c6 as g_, c7 as B_, c8 as Y_, c9 as U_, ca as d_, cb as u_, cc as H_, cd as p_, ce as y_, cf as m_, cg as K_, ch as k_, ci as V_, cj as X_, ck as v_, cl as h_, cm as x_, cn as f_, co as W_, cp as z_, cq as w_, cr as J_, cs as Z_, ct as j_, cu as q_, cv as Q_, cw as $_, cx as aE, cy as TE, cz as _E } from "./lib-BHQg-PvG.js";
|
|
2
2
|
import { createPinia as sE, setActivePinia as IE } from "pinia";
|
|
3
3
|
export {
|
|
4
4
|
_ as ABOUT_SECTION_SETTINGS_CONFIG,
|