@designcrowd/library.brand-page 5.17.25-undo-3 → 5.17.25-undo-5
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-xR_8611Z.js → CreatedOnBrandCrowd-de-de-CHMMocnx.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-CrKMPM86.js → CreatedOnBrandCrowd-en-us-DHlWLkwc.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-C7lJoCwP.js → CreatedOnBrandCrowd-es-es-DeoGQeBU.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-B2P1kNsi.js → CreatedOnBrandCrowd-fr-ca-DmZV08MV.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-B2P1kNsi.js → CreatedOnBrandCrowd-fr-fr-DmZV08MV.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-Cg9ulkXK.js → CreatedOnBrandCrowd-pt-br-COuMaj13.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-Cg9ulkXK.js → CreatedOnBrandCrowd-pt-pt-COuMaj13.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-RKjXZKTE.js → CreatedOnDcom-de-de-C9XvdB6Y.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-Bma4WSgm.js → CreatedOnDcom-en-us-CSIczk-e.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-CAqF8RQd.js → CreatedOnDcom-es-es-B8PxGq85.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-BZzsaA-O.js → CreatedOnDcom-fr-ca-ClXbe4Tz.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-lB4hUGDb.js → CreatedOnDcom-fr-fr-DvVB8qIo.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-dD3iqhZb.js → CreatedOnDcom-pt-br-DmBFmt7n.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-80E4SvnQ.js → CreatedOnDcom-pt-pt-DdPrMHbl.js} +1 -1
- package/lib/src/brand-page-maker/stores/history/history-store.js +118 -2
- package/lib/src/index.mjs +1 -1
- package/lib/src/{lib-BBctNsms.js → lib-Cox69cyq.js} +4033 -3996
- package/package.json +1 -1
- package/src/brand-page-maker/stores/history/history-store.test.ts +241 -0
- package/src/brand-page-maker/stores/history/history-store.ts +137 -1
|
@@ -80,6 +80,111 @@ export const useHistoryStore = defineStore('history', () => {
|
|
|
80
80
|
return null;
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Normalize a snapshot for the dedup byte-compare. Strips/canonicalizes
|
|
85
|
+
* fields that get mutated by sidebar-open reactive cascades but aren't
|
|
86
|
+
* user-visible edits — without this, opening a content panel produces an
|
|
87
|
+
* undo step that "does nothing" when replayed.
|
|
88
|
+
*
|
|
89
|
+
* Known phantom sources (BP-5506):
|
|
90
|
+
* - TipTap RTE writing back its empty-paragraph default on first mount
|
|
91
|
+
* (e.g. `""` → `<p style="text-align: center;"></p>`).
|
|
92
|
+
* - Lazy hydration of `textStyle` fields (`fontSize`, `letterSpacing`)
|
|
93
|
+
* when a content settings panel computes resolved values from
|
|
94
|
+
* `textStyleType` and writes them onto the model.
|
|
95
|
+
* - `isModifiedAfterTemplateApplied` flipping on first edit gesture.
|
|
96
|
+
*
|
|
97
|
+
* Used ONLY for dedup comparison. Stored snapshots remain unchanged so
|
|
98
|
+
* `applyHistorySnapshot` always sees the real state.
|
|
99
|
+
*/
|
|
100
|
+
// Empty paragraph forms TipTap emits when an editor mounts on an empty
|
|
101
|
+
// string. Treated as equivalent to `""` for dedup.
|
|
102
|
+
const EMPTY_RTE_HTML = /^<p(\s[^>]*)?>(<br\s*\/?>)?<\/p>$/;
|
|
103
|
+
// TipTap's default-hydration shape: a single <p> (with optional align
|
|
104
|
+
// attr) containing the original plain text, optionally wrapped in
|
|
105
|
+
// default-styled <span> (font-family / font-size / color) and/or
|
|
106
|
+
// <mark> (highlight) tags. The inner capture intentionally rejects any
|
|
107
|
+
// string that itself contains `<` or `>` so that real formatting tags
|
|
108
|
+
// — `<strong>`, `<em>`, `<a>`, nested spans with non-default styles —
|
|
109
|
+
// are preserved as a real diff rather than collapsed.
|
|
110
|
+
const RTE_DEFAULT_HYDRATION = /^<p(\s[^>]*)?>(<span(\s[^>]*)?>)?(<mark(\s[^>]*)?>)?([^<>]*)(<\/mark>)?(<\/span>)?<\/p>$/;
|
|
111
|
+
function isEmptyRteHtml(value) {
|
|
112
|
+
return typeof value === 'string' && EMPTY_RTE_HTML.test(value);
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* If `value` is TipTap's default-hydration wrapper around a plain text
|
|
116
|
+
* (no inline formatting tags), return the bare inner text. Otherwise
|
|
117
|
+
* return the original string. This collapses the BP-5506 phantom where
|
|
118
|
+
* opening a content sidebar mounts every RTE editor at once and writes
|
|
119
|
+
* back wrapped HTML with no user-visible delta.
|
|
120
|
+
*/
|
|
121
|
+
function canonicalizeRteString(value) {
|
|
122
|
+
if (EMPTY_RTE_HTML.test(value))
|
|
123
|
+
return '';
|
|
124
|
+
const match = value.match(RTE_DEFAULT_HYDRATION);
|
|
125
|
+
if (!match)
|
|
126
|
+
return value;
|
|
127
|
+
return match[6] ?? '';
|
|
128
|
+
}
|
|
129
|
+
function normalizeNode(node) {
|
|
130
|
+
if (Array.isArray(node))
|
|
131
|
+
return node.map(normalizeNode);
|
|
132
|
+
if (node === null || typeof node !== 'object')
|
|
133
|
+
return node;
|
|
134
|
+
const out = {};
|
|
135
|
+
for (const key of Object.keys(node)) {
|
|
136
|
+
let v = node[key];
|
|
137
|
+
// Strip the template-modified flag — it's meta-state that flips on
|
|
138
|
+
// first edit gesture (e.g. clicking into a panel) and does not
|
|
139
|
+
// represent a user-visible change.
|
|
140
|
+
if (key === 'isModifiedAfterTemplateApplied')
|
|
141
|
+
continue;
|
|
142
|
+
// Collapse RTE default-hydration wrappers down to the plain text
|
|
143
|
+
// they wrap. Plain "X" and `<p style="..."><span ...><mark ...>X
|
|
144
|
+
// </mark></span></p>` share the same canonical "X" so a sidebar
|
|
145
|
+
// open that mounts every editor at once doesn't generate phantom
|
|
146
|
+
// undo steps.
|
|
147
|
+
if (typeof v === 'string') {
|
|
148
|
+
v = canonicalizeRteString(v);
|
|
149
|
+
}
|
|
150
|
+
// Empty TipTap paragraphs collapse to "" — and an empty string is
|
|
151
|
+
// equivalent to the key being absent (JSON.stringify drops `undefined`),
|
|
152
|
+
// so skip the key entirely. Otherwise the normalizer would emit
|
|
153
|
+
// `"description": ""` here while the baseline snapshot — captured when
|
|
154
|
+
// `description` was `undefined` — has no `description` key at all,
|
|
155
|
+
// and the two normalized strings would differ.
|
|
156
|
+
if (isEmptyRteHtml(v) || v === '')
|
|
157
|
+
continue;
|
|
158
|
+
// textStyle / descriptionStyle / titleStyle / *Style objects:
|
|
159
|
+
// strip lazily-hydrated fields that get filled in when the settings
|
|
160
|
+
// panel computes resolved values from `textStyleType`.
|
|
161
|
+
if (v !== null &&
|
|
162
|
+
typeof v === 'object' &&
|
|
163
|
+
!Array.isArray(v) &&
|
|
164
|
+
/Style$/.test(key)) {
|
|
165
|
+
const styleObj = v;
|
|
166
|
+
const cleanedStyle = {};
|
|
167
|
+
for (const sk of Object.keys(styleObj)) {
|
|
168
|
+
if (sk === 'fontSize' || sk === 'letterSpacing')
|
|
169
|
+
continue;
|
|
170
|
+
cleanedStyle[sk] = normalizeNode(styleObj[sk]);
|
|
171
|
+
}
|
|
172
|
+
out[key] = cleanedStyle;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
out[key] = normalizeNode(v);
|
|
176
|
+
}
|
|
177
|
+
return out;
|
|
178
|
+
}
|
|
179
|
+
function normalizeSnapshotForDedup(snapshotStr) {
|
|
180
|
+
try {
|
|
181
|
+
const parsed = JSON.parse(snapshotStr);
|
|
182
|
+
return JSON.stringify(normalizeNode(parsed));
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return snapshotStr;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
83
188
|
/**
|
|
84
189
|
* Commit a new entry into the stack at the current pointer position.
|
|
85
190
|
*
|
|
@@ -106,8 +211,19 @@ export const useHistoryStore = defineStore('history', () => {
|
|
|
106
211
|
*/
|
|
107
212
|
function commitEntry(args) {
|
|
108
213
|
const current = entries.value[currentIndex.value];
|
|
109
|
-
if (current
|
|
110
|
-
|
|
214
|
+
if (current) {
|
|
215
|
+
if (current.snapshot === args.snapshot)
|
|
216
|
+
return 'noop';
|
|
217
|
+
// Phantom-edit dedup: normalize both snapshots to ignore
|
|
218
|
+
// sidebar-open reactive cascades (RTE empty-paragraph init, lazy
|
|
219
|
+
// textStyle hydration, isModifiedAfterTemplateApplied flips). If
|
|
220
|
+
// they're equal after normalization, this capture has no
|
|
221
|
+
// user-visible diff vs. the entry at the pointer.
|
|
222
|
+
if (normalizeSnapshotForDedup(current.snapshot) ===
|
|
223
|
+
normalizeSnapshotForDedup(args.snapshot)) {
|
|
224
|
+
return 'noop';
|
|
225
|
+
}
|
|
226
|
+
}
|
|
111
227
|
if (args.snapshot.length > MAX_ENTRY_BYTES) {
|
|
112
228
|
eventTracker.sendHistoryOversizedEvent({
|
|
113
229
|
attempted_bytes: args.snapshot.length,
|
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-Cox69cyq.js";
|
|
2
2
|
import { createPinia as wE, setActivePinia as ZE } from "pinia";
|
|
3
3
|
export {
|
|
4
4
|
E as ABOUT_SECTION_SETTINGS_CONFIG,
|