@designcrowd/library.brand-page 5.17.25-undo-8 → 5.17.25-undo-10
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-AfnY8zoN.js → CreatedOnBrandCrowd-de-de-C2CJCAQ1.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-D8X7A_M5.js → CreatedOnBrandCrowd-en-us-Bg5k7y_D.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-DjKTziiy.js → CreatedOnBrandCrowd-es-es-DAaAXvzy.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-dSR3lZfa.js → CreatedOnBrandCrowd-fr-ca-B7C0ERbi.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-dSR3lZfa.js → CreatedOnBrandCrowd-fr-fr-B7C0ERbi.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-BTD44ERQ.js → CreatedOnBrandCrowd-pt-br-1pvCqQK1.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-BTD44ERQ.js → CreatedOnBrandCrowd-pt-pt-1pvCqQK1.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-QP4_OShH.js → CreatedOnDcom-de-de-hbcr-qW0.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-CWyO9t7x.js → CreatedOnDcom-en-us-BToix_74.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-B3sZqeKP.js → CreatedOnDcom-es-es-DOCxN0tr.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-BR3-inLX.js → CreatedOnDcom-fr-ca-Q3ZYgCxp.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-DdrT0HCa.js → CreatedOnDcom-fr-fr-C1-dUWKB.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-3Oz8RFHK.js → CreatedOnDcom-pt-br-KWKgld1I.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-DwrZkI_f.js → CreatedOnDcom-pt-pt-CRR3Hfej.js} +1 -1
- package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.d.ts +1 -0
- package/lib/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.js +6 -0
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +36 -0
- package/lib/src/brand-page-maker/stores/history/history-store.js +213 -20
- package/lib/src/css/library.brand-page-brandCrowd.min.css +1 -1
- package/lib/src/css/library.brand-page-brandPage.min.css +1 -1
- package/lib/src/css/library.brand-page-designCom.min.css +1 -1
- package/lib/src/css/library.brand-page-preview.min.css +1 -1
- package/lib/src/index.mjs +1 -1
- package/lib/src/{lib-Y0xSZnR9.js → lib-Bhf5ZHsd.js} +5967 -5886
- package/package.json +1 -1
- package/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.mixin.ts +7 -0
- package/src/brand-page-maker/components/quick-link-bar/QuickLinkBar.vue +1 -1
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +195 -0
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +42 -0
- package/src/brand-page-maker/stores/history/history-store.test.ts +234 -3
- package/src/brand-page-maker/stores/history/history-store.ts +239 -23
|
@@ -30,6 +30,12 @@ export default defineComponent({
|
|
|
30
30
|
isPublished() {
|
|
31
31
|
return this.brandPageContainerStore.isPublished;
|
|
32
32
|
},
|
|
33
|
+
// Only render the bar when at least one inner cluster has something to
|
|
34
|
+
// show. Otherwise we'd render an empty white strip — e.g. on an
|
|
35
|
+
// unpublished page with the undo flag off.
|
|
36
|
+
shouldShowBar() {
|
|
37
|
+
return Boolean(this.undoRedoEnabled) || this.isPublished;
|
|
38
|
+
},
|
|
33
39
|
brandPageUrl() {
|
|
34
40
|
if (this.brandPageContainerStore.isCustomDomainEnabled &&
|
|
35
41
|
this.brandPageContainerStore.customDomain &&
|
|
@@ -594,6 +594,28 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
|
|
|
594
594
|
const draft = logoStore.getLogoDraftAssetByToken(logoImage.logoDraftToken);
|
|
595
595
|
if (draft)
|
|
596
596
|
editableLogoStore.setEnableEditMode(!draft.isByo);
|
|
597
|
+
// Repaint the canvas logo when the restored draft token differs
|
|
598
|
+
// from the editable logo store's current token. History snapshots
|
|
599
|
+
// intentionally drop the rendered `logoImageBase64Url` (a high-res
|
|
600
|
+
// BYO upload renders ~10 MB across the four viewports, which would
|
|
601
|
+
// blow the 5 MB per-entry cap and freeze history). On undo back to
|
|
602
|
+
// a different draft, the page-settings logo fields now have an
|
|
603
|
+
// empty base64, so the canvas would show no logo until something
|
|
604
|
+
// re-renders. Pointing the editable logo store at the restored
|
|
605
|
+
// draft and asking it to re-render fans out fabric-render requests
|
|
606
|
+
// for the four variations and writes fresh base64 onto every page
|
|
607
|
+
// section + logo content block — same path as the original BYO
|
|
608
|
+
// upload. Fire-and-forget: the restore returns immediately and the
|
|
609
|
+
// canvas updates as the renders complete, just like the upload UX.
|
|
610
|
+
const tokenChanged = editableLogoStore.logoDraftToken !== logoImage.logoDraftToken;
|
|
611
|
+
if (tokenChanged && logoImage.logoDraftToken) {
|
|
612
|
+
editableLogoStore.setLogoDraftToken(logoImage.logoDraftToken);
|
|
613
|
+
editableLogoStore
|
|
614
|
+
.updateEditableLogoImageUrlAsync()
|
|
615
|
+
.catch((err) => {
|
|
616
|
+
console.error('history-store: failed to repaint logo on restore', err);
|
|
617
|
+
});
|
|
618
|
+
}
|
|
597
619
|
},
|
|
598
620
|
_fallbackSidebarIfSelectedContentMissing(snapshot) {
|
|
599
621
|
const contentSettingsStore = useUiContentSettingsStore();
|
|
@@ -610,9 +632,23 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
|
|
|
610
632
|
});
|
|
611
633
|
if (existingContentIds.has(selectedItemId))
|
|
612
634
|
return;
|
|
635
|
+
// The previously-selected content was undone away. Restore the
|
|
636
|
+
// Content tab's natural landing state — the same shape produced
|
|
637
|
+
// when the user clicks the Content tab fresh — instead of leaving
|
|
638
|
+
// the sidebar stuck rendering `<FocusedContentItemSettings>` for
|
|
639
|
+
// a missing item, which paints a blank panel.
|
|
640
|
+
//
|
|
641
|
+
// `resetMode()` pops the modeStack back to the base `edit` entry
|
|
642
|
+
// (the default landing mode); clearing `selectedItemId` releases
|
|
643
|
+
// the pointer to the now-deleted item.
|
|
613
644
|
sideBarStore.setSelectedTabName({
|
|
614
645
|
tabName: SIDE_BAR_TAB_NAMES.CONTENT_SETTINGS,
|
|
615
646
|
});
|
|
647
|
+
contentSettingsStore.resetMode();
|
|
648
|
+
contentSettingsStore.selectedItemId = null;
|
|
649
|
+
contentSettingsStore.selectedItemFieldName = null;
|
|
650
|
+
contentSettingsStore.selectedItemIndex = null;
|
|
651
|
+
contentSettingsStore.selectedItemValue = null;
|
|
616
652
|
},
|
|
617
653
|
export() {
|
|
618
654
|
const data = this.brandPageData;
|
|
@@ -73,7 +73,26 @@ export const useHistoryStore = defineStore('history', () => {
|
|
|
73
73
|
return null;
|
|
74
74
|
try {
|
|
75
75
|
const raw = toRaw(cachedMakerStore.brandPageData);
|
|
76
|
-
|
|
76
|
+
// Drop `logoImageBase64Url` from the serialized form. A high-res
|
|
77
|
+
// BYO upload renders a ~2.5 MB base64 PNG into each of the four
|
|
78
|
+
// viewport sections (~10 MB raw), which is well past the 5 MB
|
|
79
|
+
// per-entry cap and would otherwise stick every BYO capture — and
|
|
80
|
+
// every follow-up edit while the upload is on the page — into the
|
|
81
|
+
// `oversized` path, freezing history. Stripping the field at
|
|
82
|
+
// serialize time keeps entries small and is safe for restore:
|
|
83
|
+
// - BYO upload IS undoable. The undo-relevant signal is
|
|
84
|
+
// `logoImage.logoDraftToken`, which is preserved.
|
|
85
|
+
// - On undo `LogoRender` watches `viewModel` and falls back to
|
|
86
|
+
// fetching the SVG by `logoDraftToken` when `logoImageBase64Url`
|
|
87
|
+
// is undefined (LogoRender.vue:97-102, 139-161), so the canvas
|
|
88
|
+
// repaints the previous logo without the cached PNG.
|
|
89
|
+
// - Per-property logo edits (text, color, font) author via
|
|
90
|
+
// `editableLogoStore.logoEdits` — not `brandPageData` — so
|
|
91
|
+
// they're already out of V1 undo scope. Same key is also
|
|
92
|
+
// stripped in the dedup normalizer; that strip is now
|
|
93
|
+
// redundant for the watcher path but kept as belt-and-braces
|
|
94
|
+
// in case a snapshot string lands there from another origin.
|
|
95
|
+
return JSON.stringify(raw, (key, value) => key === 'logoImageBase64Url' ? undefined : value);
|
|
77
96
|
}
|
|
78
97
|
catch (error) {
|
|
79
98
|
console.error('history-store: failed to serialize brandPageData', error);
|
|
@@ -91,6 +110,10 @@ export const useHistoryStore = defineStore('history', () => {
|
|
|
91
110
|
* (e.g. `""` → `<p style="text-align: center;"></p>`).
|
|
92
111
|
* - TipTap RTE writing back its default-style hydration on first mount
|
|
93
112
|
* (e.g. plain `"Hello"` → `<p style="..."><span style="..."><mark ...>Hello</mark></span></p>`).
|
|
113
|
+
* - TipTap re-emitting whole-content `<strong>`/`<em>`/`<u>`/`<s>` tags
|
|
114
|
+
* to mirror the resolved `textStyle.fontWeight / fontStyle /
|
|
115
|
+
* textDecoration` (e.g. plain `"text"` →
|
|
116
|
+
* `<p>...<span>...<strong>text</strong></span></p>`).
|
|
94
117
|
* - Lazy hydration of `*Style` objects when a content settings panel —
|
|
95
118
|
* or section selection on the canvas — resolves `textStyleType` and
|
|
96
119
|
* writes the full resolved style (fontFamily, fontSize, color,
|
|
@@ -98,38 +121,197 @@ export const useHistoryStore = defineStore('history', () => {
|
|
|
98
121
|
* onto the model. The `textStyleType` itself is the authoring
|
|
99
122
|
* intent; the resolved keys are just cached values.
|
|
100
123
|
* - `isModifiedAfterTemplateApplied` flipping on first edit gesture.
|
|
124
|
+
* - `logoImageBase64Url` — the rendered logo PNG. Per-property logo
|
|
125
|
+
* edits author through `editableLogoStore.logoEdits` (not in
|
|
126
|
+
* `brandPageData`), so an undo would revert the canvas image but
|
|
127
|
+
* leave the sidebar fields showing the user's typed value. Logo
|
|
128
|
+
* property edits are excluded from V1 undo scope; BYO-upload undo
|
|
129
|
+
* still works because that diff lives in `logoImage.logoDraftToken`.
|
|
130
|
+
*
|
|
131
|
+
* RTE strings are canonicalized by parsing the HTML with DOMParser and
|
|
132
|
+
* walking the tree; only attributeless format wrappers (and a tightly
|
|
133
|
+
* scoped set of hydration styles on `<p>` / `<span>` / `<mark>`) are
|
|
134
|
+
* collapsed. Real authoring intent (links, custom colors, partial-text
|
|
135
|
+
* formatting like `Hello <strong>world</strong>`) survives the walk
|
|
136
|
+
* because at least one node falls outside the hydration whitelist,
|
|
137
|
+
* and the walker bails to "preserve original" the moment that happens.
|
|
101
138
|
*
|
|
102
139
|
* Used ONLY for dedup comparison. Stored snapshots remain unchanged so
|
|
103
140
|
* `applyHistorySnapshot` always sees the real state.
|
|
104
141
|
*/
|
|
142
|
+
// Tags TipTap re-emits purely to mirror the resolved textStyle on first
|
|
143
|
+
// hydration. None carry user authoring intent on their own when they are
|
|
144
|
+
// the sole element-child wrapping the entire content:
|
|
145
|
+
// - <p>: only its `text-align` style is meaningful, and that's already
|
|
146
|
+
// captured in `textStyle.textAlign`.
|
|
147
|
+
// - <span>: TipTap wraps content in a span with `font-family`, `font-size`,
|
|
148
|
+
// `color`, `letter-spacing`, `line-height` resolved from the
|
|
149
|
+
// textStyle. The textStyle object on the same content is the
|
|
150
|
+
// authoritative source.
|
|
151
|
+
// - <mark>: TipTap's highlight extension default — collapses regardless
|
|
152
|
+
// of `data-color` / `style` attrs, mirroring the original
|
|
153
|
+
// regex's behavior on a hydrated highlight.
|
|
154
|
+
// - <strong>/<em>/<u>/<s>: attributeless tags that mirror
|
|
155
|
+
// `fontWeight: bold` / `fontStyle: italic` / `textDecoration:
|
|
156
|
+
// underline / line-through`. ONLY recognized as hydration when
|
|
157
|
+
// they are the sole child of their parent — partial-content
|
|
158
|
+
// usage like `Hello <strong>world</strong>` is a real edit.
|
|
159
|
+
// Anything else (`<a>`, `<br>`, `<span style="color: red">`, attributes on
|
|
160
|
+
// <strong>/<em>, etc.) is preserved as a real diff.
|
|
161
|
+
const STRUCTURAL_HYDRATION_TAGS = new Set(['P', 'SPAN', 'MARK']);
|
|
162
|
+
const FORMAT_HYDRATION_TAGS = new Set(['STRONG', 'EM', 'U', 'S']);
|
|
163
|
+
// Default style properties TipTap emits on a hydration <span> /
|
|
164
|
+
// <mark>. The textStyle resolver writes all of these onto the live
|
|
165
|
+
// model, so when TipTap re-emits them as inline style on its
|
|
166
|
+
// hydration span/mark there is no user-visible delta.
|
|
167
|
+
// Anything outside this whitelist (e.g. `text-decoration` mid-content,
|
|
168
|
+
// `text-shadow`, `text-transform`) is treated as a real edit.
|
|
169
|
+
const HYDRATION_INLINE_STYLE_PROPS = new Set([
|
|
170
|
+
'font-family',
|
|
171
|
+
'font-size',
|
|
172
|
+
'letter-spacing',
|
|
173
|
+
'line-height',
|
|
174
|
+
'color',
|
|
175
|
+
'background-color',
|
|
176
|
+
]);
|
|
105
177
|
// Empty paragraph forms TipTap emits when an editor mounts on an empty
|
|
106
178
|
// string. Treated as equivalent to `""` for dedup.
|
|
107
|
-
const EMPTY_RTE_HTML = /^<p(\s[^>]*)?>(<br\s*\/?>)?<\/p>$/;
|
|
108
|
-
// TipTap's default-hydration shape: a single <p> (with optional align
|
|
109
|
-
// attr) containing the original plain text, optionally wrapped in
|
|
110
|
-
// default-styled <span> (font-family / font-size / color) and/or
|
|
111
|
-
// <mark> (highlight) tags. The inner capture intentionally rejects any
|
|
112
|
-
// string that itself contains `<` or `>` so that real formatting tags
|
|
113
|
-
// — `<strong>`, `<em>`, `<a>`, nested spans with non-default styles —
|
|
114
|
-
// are preserved as a real diff rather than collapsed.
|
|
115
|
-
const RTE_DEFAULT_HYDRATION = /^<p(\s[^>]*)?>(<span(\s[^>]*)?>)?(<mark(\s[^>]*)?>)?([^<>]*)(<\/mark>)?(<\/span>)?<\/p>$/;
|
|
116
179
|
function isEmptyRteHtml(value) {
|
|
117
|
-
|
|
180
|
+
if (typeof value !== 'string')
|
|
181
|
+
return false;
|
|
182
|
+
return /^<p(\s[^>]*)?>(<br\s*\/?>)?<\/p>$/.test(value);
|
|
183
|
+
}
|
|
184
|
+
function isHydrationOnlyAttributes(el) {
|
|
185
|
+
// Format tags (<strong>/<em>/<u>/<s>) must be attributeless. Anything
|
|
186
|
+
// with class/style/data-*/etc. is a real edit.
|
|
187
|
+
if (FORMAT_HYDRATION_TAGS.has(el.tagName))
|
|
188
|
+
return el.attributes.length === 0;
|
|
189
|
+
for (const attr of Array.from(el.attributes)) {
|
|
190
|
+
// <mark> may carry a `data-color` attr (TipTap highlight extension's
|
|
191
|
+
// default-and-resolved value). The accompanying `style` is checked
|
|
192
|
+
// against the same hydration-prop whitelist as <span>.
|
|
193
|
+
if (el.tagName === 'MARK' &&
|
|
194
|
+
(attr.name === 'data-color' || attr.name === 'style')) {
|
|
195
|
+
if (attr.name === 'data-color')
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
else if (attr.name !== 'style') {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
const decls = attr.value
|
|
202
|
+
.split(';')
|
|
203
|
+
.map((d) => d.trim())
|
|
204
|
+
.filter(Boolean);
|
|
205
|
+
if (el.tagName === 'P') {
|
|
206
|
+
for (const decl of decls) {
|
|
207
|
+
const [prop] = decl.split(':').map((s) => s.trim());
|
|
208
|
+
if (prop !== 'text-align')
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
else if (el.tagName === 'SPAN' || el.tagName === 'MARK') {
|
|
213
|
+
for (const decl of decls) {
|
|
214
|
+
const [prop, value] = decl.split(':').map((s) => s.trim());
|
|
215
|
+
// Allow `color: inherit` on <mark> (TipTap stamps it on the
|
|
216
|
+
// default highlight to inherit the span's color). Otherwise
|
|
217
|
+
// require the prop to be in the hydration whitelist.
|
|
218
|
+
if (el.tagName === 'MARK' &&
|
|
219
|
+
prop === 'color' &&
|
|
220
|
+
value === 'inherit') {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
if (!HYDRATION_INLINE_STYLE_PROPS.has(prop))
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
118
232
|
}
|
|
119
233
|
/**
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
234
|
+
* Walk a parsed HTML node tree. Return the joined text content if every
|
|
235
|
+
* descendant is hydration noise; return null if any node carries real
|
|
236
|
+
* authoring intent (links, partial formatting, custom styles, etc.).
|
|
237
|
+
*
|
|
238
|
+
* `isFormatTag` differs in how it's allowed to appear: a structural tag
|
|
239
|
+
* (P/SPAN/MARK) can have siblings; a format tag (STRONG/EM/U/S) is only
|
|
240
|
+
* allowed when it's the SOLE child of its parent. The caller enforces
|
|
241
|
+
* that at the iteration site.
|
|
242
|
+
*/
|
|
243
|
+
function extractCanonicalText(node) {
|
|
244
|
+
if (node.nodeType === 3 /* TEXT_NODE */)
|
|
245
|
+
return node.textContent ?? '';
|
|
246
|
+
if (node.nodeType !== 1 /* ELEMENT_NODE */) {
|
|
247
|
+
// Comments, CDATA, etc. — treat as opaque (preserve original).
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
250
|
+
const el = node;
|
|
251
|
+
const isStructural = STRUCTURAL_HYDRATION_TAGS.has(el.tagName);
|
|
252
|
+
const isFormat = FORMAT_HYDRATION_TAGS.has(el.tagName);
|
|
253
|
+
if (!isStructural && !isFormat)
|
|
254
|
+
return null;
|
|
255
|
+
if (!isHydrationOnlyAttributes(el))
|
|
256
|
+
return null;
|
|
257
|
+
const children = Array.from(el.childNodes);
|
|
258
|
+
let out = '';
|
|
259
|
+
for (const child of children) {
|
|
260
|
+
// Format tags only count as hydration when they wrap the ENTIRE
|
|
261
|
+
// content of their parent. If a <strong>/<em>/<u>/<s> appears
|
|
262
|
+
// alongside any sibling (text or element), it's partial-content
|
|
263
|
+
// formatting — a real edit that can't be expressed via textStyle —
|
|
264
|
+
// so bail.
|
|
265
|
+
if (child.nodeType === 1 &&
|
|
266
|
+
FORMAT_HYDRATION_TAGS.has(child.tagName) &&
|
|
267
|
+
children.length > 1) {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
const part = extractCanonicalText(child);
|
|
271
|
+
if (part === null)
|
|
272
|
+
return null;
|
|
273
|
+
out += part;
|
|
274
|
+
}
|
|
275
|
+
return out;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* If `value` is TipTap's default-hydration wrapper around plain text
|
|
279
|
+
* (only hydration-noise elements wrapping bare text), return that bare
|
|
280
|
+
* text. Otherwise return the original string unchanged.
|
|
281
|
+
*
|
|
282
|
+
* This collapses the BP-5506 phantom where opening a content sidebar —
|
|
283
|
+
* or selecting a section on the canvas — mounts every RTE editor at
|
|
284
|
+
* once and writes back wrapped HTML with no user-visible delta.
|
|
125
285
|
*/
|
|
126
286
|
function canonicalizeRteString(value) {
|
|
127
|
-
|
|
287
|
+
// Cheap exit: no tags at all.
|
|
288
|
+
if (!value.includes('<'))
|
|
289
|
+
return value;
|
|
290
|
+
if (isEmptyRteHtml(value))
|
|
128
291
|
return '';
|
|
129
|
-
|
|
130
|
-
|
|
292
|
+
// DOMParser is unavailable in some non-browser test environments;
|
|
293
|
+
// fall back to leaving the value as-is so the caller produces a
|
|
294
|
+
// real diff (i.e. fail open — never falsely collapse).
|
|
295
|
+
if (typeof DOMParser === 'undefined')
|
|
296
|
+
return value;
|
|
297
|
+
let doc;
|
|
298
|
+
try {
|
|
299
|
+
doc = new DOMParser().parseFromString(`<div id="__rte_root__">${value}</div>`, 'text/html');
|
|
300
|
+
}
|
|
301
|
+
catch {
|
|
302
|
+
return value;
|
|
303
|
+
}
|
|
304
|
+
const root = doc.getElementById('__rte_root__');
|
|
305
|
+
if (!root)
|
|
131
306
|
return value;
|
|
132
|
-
|
|
307
|
+
let out = '';
|
|
308
|
+
for (const child of Array.from(root.childNodes)) {
|
|
309
|
+
const part = extractCanonicalText(child);
|
|
310
|
+
if (part === null)
|
|
311
|
+
return value;
|
|
312
|
+
out += part;
|
|
313
|
+
}
|
|
314
|
+
return out;
|
|
133
315
|
}
|
|
134
316
|
function normalizeNode(node) {
|
|
135
317
|
if (Array.isArray(node))
|
|
@@ -144,6 +326,17 @@ export const useHistoryStore = defineStore('history', () => {
|
|
|
144
326
|
// represent a user-visible change.
|
|
145
327
|
if (key === 'isModifiedAfterTemplateApplied')
|
|
146
328
|
continue;
|
|
329
|
+
// Strip the rendered logo PNG. Logo property edits (text, color,
|
|
330
|
+
// font, outline, shadow) authored via the Logo sidebar live in
|
|
331
|
+
// `editableLogoStore.logoEdits` — which is NOT in `brandPageData`,
|
|
332
|
+
// so an undo would revert this base64 image on the canvas without
|
|
333
|
+
// touching the sidebar fields. Per V1 scope, logo property edits
|
|
334
|
+
// are non-undoable (parallels the PRD's admin-logo exclusion);
|
|
335
|
+
// BYO-upload undo still works because that change shows up in
|
|
336
|
+
// `logoImage.logoDraftToken`, not here. Stripping the field keeps
|
|
337
|
+
// those isolated render-output diffs out of the stack entirely.
|
|
338
|
+
if (key === 'logoImageBase64Url')
|
|
339
|
+
continue;
|
|
147
340
|
// Collapse RTE default-hydration wrappers down to the plain text
|
|
148
341
|
// they wrap. Plain "X" and `<p style="..."><span ...><mark ...>X
|
|
149
342
|
// </mark></span></p>` share the same canonical "X" so a sidebar
|
package/lib/src/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as E, a as T, b as s, c as I, d as S, e as N, f as e, B as A, g as O, h as C, i as G, j as D, k as P, l as t, m as R, n as L, o as M, p as o, q as r, r as b, s as n, t as F, u as i, v as l, w as g, x as B, y as c, z as Y, C as U, D as d, E as u, F as H, G as p, H as y, I as K, J as k, K as m, L as V, M as X, N as h, O as v, P as W, Q as f, R as x, S as z, T as w, U as Z, V as j, W as Q, X as q, Y as J, Z as $, $ as aa, a0 as _a, a1 as Ea, a2 as Ta, a3 as sa, a4 as Ia, a5 as Sa, a6 as Na, a7 as ea, a8 as Aa, a9 as Oa, aa as Ca, ab as Ga, ac as Da, ad as Pa, ae as ta, af as Ra, ag as La, ah as Ma, ai as oa, aj as ra, ak as ba, al as na, am as Fa, an as ia, ao as la, ap as ga, aq as Ba, ar as ca, as as Ya, at as Ua, au as da, av as ua, aw as Ha, ax as pa, ay as ya, az as Ka, aA as ka, aB as ma, aC as Va, aD as Xa, aE as ha, aF as va, aG as Wa, aH as fa, aI as xa, aJ as za, aK as wa, aL as Za, aM as ja, aN as Qa, aO as qa, aP as Ja, aQ as $a, aR as a_, aS as __, aT as E_, aU as T_, aV as s_, aW as I_, aX as S_, aY as N_, aZ as e_, a_ as A_, a$ as O_, b0 as C_, b1 as G_, b2 as D_, b3 as P_, b4 as t_, b5 as R_, b6 as L_, b7 as M_, b8 as o_, b9 as r_, ba as b_, bb as n_, bc as F_, bd as i_, be as l_, bf as g_, bg as B_, bh as c_, bi as Y_, bj as U_, bk as d_, bl as u_, bm as H_, bn as p_, bo as y_, bp as K_, bq as k_, br as m_, bs as V_, bt as X_, bu as h_, bv as v_, bw as W_, bx as f_, by as x_, bz as z_, bA as w_, bB as Z_, bC as j_, bD as Q_, bE as q_, bF as J_, bG as $_, bH as aE, bI as _E, bJ as EE, bK as TE, bL as sE, bM as IE, bN as SE, bO as NE, bP as eE, bQ as AE, bR as OE, bS as CE, bT as GE, bU as DE, bV as PE, bW as tE, bX as RE, bY as LE, bZ as ME, b_ as oE, b$ as rE, c0 as bE, c1 as nE, c2 as FE, c3 as iE, c4 as lE, c5 as gE, c6 as BE, c7 as cE, c8 as YE, c9 as UE, ca as dE, cb as uE, cc as HE, cd as pE, ce as yE, cf as KE, cg as kE, ch as mE, ci as VE, cj as XE, ck as hE, cl as vE, cm as WE, cn as fE, co as xE } from "./lib-
|
|
1
|
+
import { A as E, a as T, b as s, c as I, d as S, e as N, f as e, B as A, g as O, h as C, i as G, j as D, k as P, l as t, m as R, n as L, o as M, p as o, q as r, r as b, s as n, t as F, u as i, v as l, w as g, x as B, y as c, z as Y, C as U, D as d, E as u, F as H, G as p, H as y, I as K, J as k, K as m, L as V, M as X, N as h, O as v, P as W, Q as f, R as x, S as z, T as w, U as Z, V as j, W as Q, X as q, Y as J, Z as $, $ as aa, a0 as _a, a1 as Ea, a2 as Ta, a3 as sa, a4 as Ia, a5 as Sa, a6 as Na, a7 as ea, a8 as Aa, a9 as Oa, aa as Ca, ab as Ga, ac as Da, ad as Pa, ae as ta, af as Ra, ag as La, ah as Ma, ai as oa, aj as ra, ak as ba, al as na, am as Fa, an as ia, ao as la, ap as ga, aq as Ba, ar as ca, as as Ya, at as Ua, au as da, av as ua, aw as Ha, ax as pa, ay as ya, az as Ka, aA as ka, aB as ma, aC as Va, aD as Xa, aE as ha, aF as va, aG as Wa, aH as fa, aI as xa, aJ as za, aK as wa, aL as Za, aM as ja, aN as Qa, aO as qa, aP as Ja, aQ as $a, aR as a_, aS as __, aT as E_, aU as T_, aV as s_, aW as I_, aX as S_, aY as N_, aZ as e_, a_ as A_, a$ as O_, b0 as C_, b1 as G_, b2 as D_, b3 as P_, b4 as t_, b5 as R_, b6 as L_, b7 as M_, b8 as o_, b9 as r_, ba as b_, bb as n_, bc as F_, bd as i_, be as l_, bf as g_, bg as B_, bh as c_, bi as Y_, bj as U_, bk as d_, bl as u_, bm as H_, bn as p_, bo as y_, bp as K_, bq as k_, br as m_, bs as V_, bt as X_, bu as h_, bv as v_, bw as W_, bx as f_, by as x_, bz as z_, bA as w_, bB as Z_, bC as j_, bD as Q_, bE as q_, bF as J_, bG as $_, bH as aE, bI as _E, bJ as EE, bK as TE, bL as sE, bM as IE, bN as SE, bO as NE, bP as eE, bQ as AE, bR as OE, bS as CE, bT as GE, bU as DE, bV as PE, bW as tE, bX as RE, bY as LE, bZ as ME, b_ as oE, b$ as rE, c0 as bE, c1 as nE, c2 as FE, c3 as iE, c4 as lE, c5 as gE, c6 as BE, c7 as cE, c8 as YE, c9 as UE, ca as dE, cb as uE, cc as HE, cd as pE, ce as yE, cf as KE, cg as kE, ch as mE, ci as VE, cj as XE, ck as hE, cl as vE, cm as WE, cn as fE, co as xE } from "./lib-Bhf5ZHsd.js";
|
|
2
2
|
import { createPinia as wE, setActivePinia as ZE } from "pinia";
|
|
3
3
|
export {
|
|
4
4
|
E as ABOUT_SECTION_SETTINGS_CONFIG,
|