@designcrowd/library.brand-page 6.0.6-tracker-1 → 6.0.6-undo-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-DD0OBnij.js → CreatedOnBrandCrowd-de-de-x7BcD7Sj.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-DysrpsmM.js → CreatedOnBrandCrowd-en-us-CG-ThD_q.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-B6twGr9h.js → CreatedOnBrandCrowd-es-es-aab4_Re2.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-yxl0ih_4.js → CreatedOnBrandCrowd-fr-ca-Drl8X5uh.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-yxl0ih_4.js → CreatedOnBrandCrowd-fr-fr-Drl8X5uh.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-BtXDrIcx.js → CreatedOnBrandCrowd-pt-br-8Ib7T70i.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-BtXDrIcx.js → CreatedOnBrandCrowd-pt-pt-8Ib7T70i.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-ho_ROy1L.js → CreatedOnDcom-de-de-FJtydzc5.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-C91p9kls.js → CreatedOnDcom-en-us-BMiXru6P.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-B3FYmObE.js → CreatedOnDcom-es-es-B8Srdnku.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-D40m7fPx.js → CreatedOnDcom-fr-ca-tcXGiBNt.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-Cd57oYyc.js → CreatedOnDcom-fr-fr-nE1cuUEU.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-Du57mWxG.js → CreatedOnDcom-pt-br-DxCCXCg8.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-fYoPZWwr.js → CreatedOnDcom-pt-pt-Csabip9G.js} +1 -1
- package/lib/src/brand-page/utils/logo.util.d.ts +14 -0
- package/lib/src/brand-page/utils/logo.util.js +19 -0
- package/lib/src/brand-page-maker/components/action-bar/ActionBar.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +2 -2
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.js +1 -1
- package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMakerTemplateSettings.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +3 -3
- package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/preview/Preview.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +2 -2
- package/lib/src/brand-page-maker/components/seo-settings/UrlSettings.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/social-share/SocialShare.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/template-preview/TemplatePreview.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +25 -4
- package/lib/src/brand-page-maker/composables/useUndoRedoFlag.d.ts +6 -7
- package/lib/src/brand-page-maker/composables/useUndoRedoFlag.js +7 -12
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.d.ts +1 -1
- package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +12 -7
- package/lib/src/brand-page-maker/stores/history/history-store.d.ts +7 -1
- package/lib/src/brand-page-maker/stores/history/history-store.js +11 -1
- package/lib/src/index.mjs +83 -84
- package/lib/src/{lib-lMNy66QO.js → lib-C_UlYMJy.js} +32835 -32458
- package/lib/src/metadata-builder/builders/reorder-pages-builder.d.ts +13 -0
- package/lib/src/metadata-builder/builders/reorder-pages-builder.js +49 -0
- package/lib/src/shared/content-settings/components/GenericTextInput.mixin.d.ts +5 -0
- package/lib/src/shared/content-settings/components/GenericTextInput.mixin.js +29 -0
- package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +3 -3
- package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +2 -2
- package/lib/src/shared/content-settings/components/email-field/EmailField.mixin.d.ts +5 -0
- package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.d.ts +0 -67
- package/lib/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.js +4 -6
- package/lib/src/shared/content-settings/components/tel-field/TelField.mixin.d.ts +5 -0
- package/lib/src/shared/content-settings/components/text-field/TextField.mixin.d.ts +5 -0
- package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.d.ts +2 -0
- package/lib/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.js +19 -0
- package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.d.ts +1 -0
- package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.js +18 -7
- package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +5 -0
- package/lib/src/shared/content-settings/components/url-field/UrlField.mixin.d.ts +5 -0
- package/lib/src/shared/content-settings/components/youtube-video-field/YoutubeVideoField.mixin.d.ts +5 -0
- package/lib/src/shared/content-settings/models.d.ts +11 -0
- package/lib/src/shared/content-settings/store/content-settings-store.d.ts +1 -1
- package/lib/src/shared/content-settings/store/content-settings-store.js +15 -1
- package/lib/src/shared/logo-settings/components/LogoSettings.mixin.d.ts +1 -1
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +2 -2
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +2 -2
- package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts +1 -1
- package/lib/src/shared/style-settings/components/StyleSettings.mixin.d.ts +1 -1
- package/package.json +1 -16
- package/src/brand-page/utils/logo.util.test.ts +54 -1
- package/src/brand-page/utils/logo.util.ts +23 -0
- package/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.ts +1 -1
- package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +26 -5
- package/src/brand-page-maker/composables/useUndoRedoFlag.ts +7 -13
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.test.ts +53 -0
- package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +13 -16
- package/src/brand-page-maker/stores/history/history-store.test.ts +51 -0
- package/src/brand-page-maker/stores/history/history-store.ts +19 -0
- package/src/metadata-builder/builders/reorder-pages-builder.ts +80 -0
- package/src/shared/content-settings/components/GenericTextInput.mixin.test.ts +119 -0
- package/src/shared/content-settings/components/GenericTextInput.mixin.ts +34 -0
- package/src/shared/content-settings/components/page-dropdown-field/PageDropdownField.vue +10 -5
- package/src/shared/content-settings/components/payment-config-field/PaymentConfigField.mixin.ts +4 -7
- package/src/shared/content-settings/components/text-field/TextField.vue +2 -1
- package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.test.ts +149 -0
- package/src/shared/content-settings/components/text-items-field/TextItemsField.mixin.ts +26 -0
- package/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.ts +19 -11
- package/src/shared/content-settings/components/textarea-field/TextareaField.vue +2 -1
- package/src/shared/content-settings/models.ts +11 -0
- package/src/shared/content-settings/store/content-settings-store.test.ts +110 -0
- package/src/shared/content-settings/store/content-settings-store.ts +17 -0
- package/lib/src/tracker.d.ts +0 -2
- package/lib/src/tracker.js +0 -12
- package/lib/src/tracker.mjs +0 -12
- package/lib/src/useEventTracker-DmQ6AkNn.js +0 -356
- package/src/tracker.ts +0 -28
|
@@ -84,6 +84,11 @@ export default defineComponent({
|
|
|
84
84
|
textEmptyErrorMessage: TEXT_EMPTY(),
|
|
85
85
|
textMaxLengthErrorMessage: MAX_LENGTH_ERROR_MESSAGE(),
|
|
86
86
|
isInternalWatchEnabled: true,
|
|
87
|
+
// Second burst layer on top of GenericTextInput's (this field re-wraps
|
|
88
|
+
// per-item TextareaField payloads into one textItems array payload
|
|
89
|
+
// behind its own debounce). Hydration only if EVERY write in the burst
|
|
90
|
+
// was hydration; any user action downgrades it. undefined = no burst.
|
|
91
|
+
burstIsHydration: undefined as boolean | undefined,
|
|
87
92
|
}),
|
|
88
93
|
async created() {
|
|
89
94
|
this.options = cloneDeep(this.value);
|
|
@@ -97,6 +102,9 @@ export default defineComponent({
|
|
|
97
102
|
onDelete(index: number) {
|
|
98
103
|
this.options = this.options.filter((_o, i) => i !== index);
|
|
99
104
|
|
|
105
|
+
// Deleting is a user action — downgrade any pending hydration burst.
|
|
106
|
+
this.burstIsHydration = false;
|
|
107
|
+
|
|
100
108
|
if (this.changeDebounce) {
|
|
101
109
|
this.changeDebounce();
|
|
102
110
|
}
|
|
@@ -107,6 +115,8 @@ export default defineComponent({
|
|
|
107
115
|
this.addOption();
|
|
108
116
|
},
|
|
109
117
|
addOption(): void {
|
|
118
|
+
this.burstIsHydration = false;
|
|
119
|
+
|
|
110
120
|
this.options.push({
|
|
111
121
|
text: '',
|
|
112
122
|
textStyle: {
|
|
@@ -131,16 +141,24 @@ export default defineComponent({
|
|
|
131
141
|
return decodeHtmlEntities(text);
|
|
132
142
|
},
|
|
133
143
|
emitChange(): void {
|
|
144
|
+
const isHydrationWrite = this.burstIsHydration === true;
|
|
145
|
+
|
|
146
|
+
this.burstIsHydration = undefined;
|
|
147
|
+
|
|
134
148
|
const payload: UpdateItemValuePayload<TextItem[]> = {
|
|
135
149
|
id: this.id,
|
|
136
150
|
name: this.name,
|
|
137
151
|
value: this.options,
|
|
152
|
+
...(isHydrationWrite ? { isHydrationWrite: true } : {}),
|
|
138
153
|
};
|
|
139
154
|
|
|
140
155
|
this.$emit('update:model-value', payload);
|
|
141
156
|
},
|
|
142
157
|
|
|
143
158
|
onItemsChange(items: TextItem[]) {
|
|
159
|
+
// Reordering is a user action — downgrade any pending hydration burst.
|
|
160
|
+
this.burstIsHydration = false;
|
|
161
|
+
|
|
144
162
|
const payload: UpdateItemValuePayload<TextItem[]> = {
|
|
145
163
|
id: this.id,
|
|
146
164
|
name: this.name,
|
|
@@ -161,9 +179,15 @@ export default defineComponent({
|
|
|
161
179
|
id: string;
|
|
162
180
|
name: string;
|
|
163
181
|
value: string;
|
|
182
|
+
isHydrationWrite?: boolean;
|
|
164
183
|
},
|
|
165
184
|
index: number,
|
|
166
185
|
) {
|
|
186
|
+
// Carry the hydration flag from the per-item TextareaField burst into
|
|
187
|
+
// this field's own burst (AND rule — one user write downgrades it).
|
|
188
|
+
this.burstIsHydration =
|
|
189
|
+
this.burstIsHydration !== false && payload.isHydrationWrite === true;
|
|
190
|
+
|
|
167
191
|
this.options[index].text = payload.value;
|
|
168
192
|
this.isModified[index] = true;
|
|
169
193
|
},
|
|
@@ -177,6 +201,8 @@ export default defineComponent({
|
|
|
177
201
|
index: number,
|
|
178
202
|
) {
|
|
179
203
|
this.options[index].textStyle = payload.value;
|
|
204
|
+
// Style edits are user actions — downgrade any pending hydration burst.
|
|
205
|
+
this.burstIsHydration = false;
|
|
180
206
|
this.emitChange();
|
|
181
207
|
},
|
|
182
208
|
|
|
@@ -176,17 +176,7 @@ export default defineComponent({
|
|
|
176
176
|
TEXT_SIZE_CHANGE_DEBOUNCE_WAIT_IN_MS,
|
|
177
177
|
);
|
|
178
178
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
if (value.textStyleType) {
|
|
182
|
-
const textStyleTypeOption = this.textStyleTypeOptions.find(
|
|
183
|
-
(x) => x.value === value.textStyleType,
|
|
184
|
-
);
|
|
185
|
-
|
|
186
|
-
if (textStyleTypeOption) {
|
|
187
|
-
textStyleTypeOption.isSelected = true;
|
|
188
|
-
}
|
|
189
|
-
}
|
|
179
|
+
this.syncTextStyleTypeSelection();
|
|
190
180
|
},
|
|
191
181
|
computed: {
|
|
192
182
|
selectedTextStyle(): TextStyleDeclaration {
|
|
@@ -423,9 +413,27 @@ export default defineComponent({
|
|
|
423
413
|
generateFontFamilySelectorKey() {
|
|
424
414
|
return `fontFamilySelector-${this.id}-${Date.now()}`;
|
|
425
415
|
},
|
|
416
|
+
// Re-derive the text-style-type selection from the current `value`.
|
|
417
|
+
// Seeded in created() and re-run whenever `value` changes (e.g. undo/redo
|
|
418
|
+
// restores the model) so the dropdown title and `selectedTextStyle`
|
|
419
|
+
// reflect the model rather than a stale local flag. (BP-5811 / BP-5817)
|
|
420
|
+
syncTextStyleTypeSelection() {
|
|
421
|
+
const value = this.value as unknown as TextStyleDeclaration;
|
|
422
|
+
|
|
423
|
+
this.textStyleTypeOptions.forEach((option) => {
|
|
424
|
+
// The leading Boolean(...) guard is deliberate — do NOT simplify to
|
|
425
|
+
// `option.value === value?.textStyleType`. The "none" option's value
|
|
426
|
+
// is `undefined`, so that form would SELECT it whenever no style is
|
|
427
|
+
// set, whereas the convention (see emitChange) is all-flags-false
|
|
428
|
+
// when there is no textStyleType.
|
|
429
|
+
option.isSelected =
|
|
430
|
+
Boolean(value?.textStyleType) && option.value === value.textStyleType;
|
|
431
|
+
});
|
|
432
|
+
},
|
|
426
433
|
},
|
|
427
434
|
watch: {
|
|
428
435
|
value() {
|
|
436
|
+
this.syncTextStyleTypeSelection();
|
|
429
437
|
this.$nextTick(() => {
|
|
430
438
|
this.fontFamilySelectorKey = this.generateFontFamilySelectorKey();
|
|
431
439
|
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
v-if="showRichTextEditor"
|
|
6
6
|
:id="`${id}-${name}`"
|
|
7
7
|
ref="richTextEditorRef"
|
|
8
|
-
|
|
8
|
+
:model-value="text"
|
|
9
9
|
class="tw-bg-white"
|
|
10
10
|
:attrs="attrs"
|
|
11
11
|
:label="label"
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
:content-type="contentType"
|
|
22
22
|
@focus="onFocus"
|
|
23
23
|
@blur="onBlur"
|
|
24
|
+
@update:model-value="onRteModelValue"
|
|
24
25
|
/>
|
|
25
26
|
<Textarea
|
|
26
27
|
v-else
|
|
@@ -123,6 +123,15 @@ export interface UpdateItemValuePayload<T> {
|
|
|
123
123
|
name: string;
|
|
124
124
|
value: T;
|
|
125
125
|
multipleValues?: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Marks this write as a hydration write-back (e.g. the RTE rewriting the
|
|
128
|
+
* model into canonical HTML on mount) rather than a user edit. The
|
|
129
|
+
* content-settings store arms the undo history's merge flag synchronously
|
|
130
|
+
* before applying a flagged write, so it folds into the current history
|
|
131
|
+
* head instead of pushing a phantom entry (BP-5810). The flag travels
|
|
132
|
+
* with the value so it survives the debounced field → store hops.
|
|
133
|
+
*/
|
|
134
|
+
isHydrationWrite?: boolean;
|
|
126
135
|
}
|
|
127
136
|
|
|
128
137
|
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
@@ -131,6 +140,8 @@ export interface UpdateMultipleItemValuesPayload<T extends object> {
|
|
|
131
140
|
name: string;
|
|
132
141
|
value: T;
|
|
133
142
|
index?: number;
|
|
143
|
+
/** See UpdateItemValuePayload.isHydrationWrite. */
|
|
144
|
+
isHydrationWrite?: boolean;
|
|
134
145
|
}
|
|
135
146
|
|
|
136
147
|
export interface ValidateItemPayload {
|
|
@@ -5,6 +5,16 @@ import {
|
|
|
5
5
|
useUiContentSettingsStore,
|
|
6
6
|
} from './index';
|
|
7
7
|
|
|
8
|
+
const { mergeNextMutationMock } = vi.hoisted(() => ({
|
|
9
|
+
mergeNextMutationMock: vi.fn(),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
vi.mock('@brand-page-maker/stores/history/history-store', () => ({
|
|
13
|
+
useHistoryStore: vi.fn(() => ({
|
|
14
|
+
mergeNextMutation: mergeNextMutationMock,
|
|
15
|
+
})),
|
|
16
|
+
}));
|
|
17
|
+
|
|
8
18
|
describe('content settings store', () => {
|
|
9
19
|
beforeAll(() => {
|
|
10
20
|
const pinia = createPinia();
|
|
@@ -69,3 +79,103 @@ describe('content settings store', () => {
|
|
|
69
79
|
expect(store.modeStack[0].mode).toBe(DEFAULT_CONSTANT_SETTINGS_MODE);
|
|
70
80
|
});
|
|
71
81
|
});
|
|
82
|
+
|
|
83
|
+
// BP-5810: hydration write-backs (RTE canonical HTML on mount, lazy config
|
|
84
|
+
// hydration, stale-id clears) arrive with `isHydrationWrite` on the payload.
|
|
85
|
+
// The store must arm the undo history's merge flag in the same tick as the
|
|
86
|
+
// write so it folds into the current head instead of pushing a phantom entry.
|
|
87
|
+
describe('content settings store — hydration writes arm the history merge', () => {
|
|
88
|
+
const makeItem = () => ({
|
|
89
|
+
id: 'item-1',
|
|
90
|
+
type: 'social-links',
|
|
91
|
+
settings: {
|
|
92
|
+
content: { title: '<p>old</p>' },
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const setupStore = () => {
|
|
97
|
+
setActivePinia(createPinia());
|
|
98
|
+
|
|
99
|
+
const store = useUiContentSettingsStore();
|
|
100
|
+
|
|
101
|
+
store.items.push(makeItem() as never);
|
|
102
|
+
|
|
103
|
+
// Isolate updateItemValue: validation and the content-changed fan-out
|
|
104
|
+
// reach into maker stores that are out of scope here.
|
|
105
|
+
store.validateItem = vi.fn();
|
|
106
|
+
store.onContentChanged = vi.fn();
|
|
107
|
+
|
|
108
|
+
return store;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
beforeEach(() => {
|
|
112
|
+
mergeNextMutationMock.mockClear();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
test('updateItemValue with isHydrationWrite arms the merge and applies the write', () => {
|
|
116
|
+
const store = setupStore();
|
|
117
|
+
|
|
118
|
+
store.updateItemValue({
|
|
119
|
+
id: 'item-1',
|
|
120
|
+
name: 'title',
|
|
121
|
+
value: '<p style="text-align: center;"></p>',
|
|
122
|
+
isHydrationWrite: true,
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
expect(mergeNextMutationMock).toHaveBeenCalledTimes(1);
|
|
126
|
+
expect((store.items[0].settings.content as { title?: string }).title).toBe(
|
|
127
|
+
'<p style="text-align: center;"></p>',
|
|
128
|
+
);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test('updateItemValue without the flag does not touch the history merge', () => {
|
|
132
|
+
const store = setupStore();
|
|
133
|
+
|
|
134
|
+
store.updateItemValue({
|
|
135
|
+
id: 'item-1',
|
|
136
|
+
name: 'title',
|
|
137
|
+
value: '<p>user edit</p>',
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
expect(mergeNextMutationMock).not.toHaveBeenCalled();
|
|
141
|
+
expect((store.items[0].settings.content as { title?: string }).title).toBe(
|
|
142
|
+
'<p>user edit</p>',
|
|
143
|
+
);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test('updateItemValue for an unknown item does not arm the merge', () => {
|
|
147
|
+
const store = setupStore();
|
|
148
|
+
|
|
149
|
+
store.updateItemValue({
|
|
150
|
+
id: 'missing-item',
|
|
151
|
+
name: 'title',
|
|
152
|
+
value: '<p>x</p>',
|
|
153
|
+
isHydrationWrite: true,
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
expect(mergeNextMutationMock).not.toHaveBeenCalled();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('updateMultipleItemValues honours the same contract', () => {
|
|
160
|
+
const store = setupStore();
|
|
161
|
+
|
|
162
|
+
store.updateMultipleItemValues({
|
|
163
|
+
id: 'item-1',
|
|
164
|
+
name: 'title',
|
|
165
|
+
value: { title: '<p>merged</p>' },
|
|
166
|
+
isHydrationWrite: true,
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
expect(mergeNextMutationMock).toHaveBeenCalledTimes(1);
|
|
170
|
+
|
|
171
|
+
mergeNextMutationMock.mockClear();
|
|
172
|
+
|
|
173
|
+
store.updateMultipleItemValues({
|
|
174
|
+
id: 'item-1',
|
|
175
|
+
name: 'title',
|
|
176
|
+
value: { title: '<p>user</p>' },
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
expect(mergeNextMutationMock).not.toHaveBeenCalled();
|
|
180
|
+
});
|
|
181
|
+
});
|
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
useBrandPageMakerStore,
|
|
37
37
|
useVideoStore,
|
|
38
38
|
} from '@brand-page-maker/stores';
|
|
39
|
+
import { useHistoryStore } from '@brand-page-maker/stores/history/history-store';
|
|
39
40
|
import { useUiSideBarStore } from '../../side-bar/store';
|
|
40
41
|
import {
|
|
41
42
|
createDefaultContentItemGroupState,
|
|
@@ -389,6 +390,16 @@ export const useUiContentSettingsStore = defineStore('uiContentSettings', {
|
|
|
389
390
|
return;
|
|
390
391
|
}
|
|
391
392
|
|
|
393
|
+
// Hydration write-backs (RTE canonical HTML on mount, lazy config
|
|
394
|
+
// hydration, stale-id clears) fold into the current undo head instead
|
|
395
|
+
// of pushing an entry. Arming here — same tick as the write — is what
|
|
396
|
+
// makes the merge reliable: the flag travelled with the payload
|
|
397
|
+
// through the debounced field chain, so emit-time arming would lapse
|
|
398
|
+
// before the write lands (BP-5810).
|
|
399
|
+
if (payload.isHydrationWrite) {
|
|
400
|
+
useHistoryStore().mergeNextMutation();
|
|
401
|
+
}
|
|
402
|
+
|
|
392
403
|
item.settings.content[payload.name] = payload.value;
|
|
393
404
|
|
|
394
405
|
this.validateItem({
|
|
@@ -402,6 +413,7 @@ export const useUiContentSettingsStore = defineStore('uiContentSettings', {
|
|
|
402
413
|
id,
|
|
403
414
|
name,
|
|
404
415
|
value,
|
|
416
|
+
isHydrationWrite,
|
|
405
417
|
}: UpdateMultipleItemValuesPayload<any>): void {
|
|
406
418
|
const item = this.items.find((i) => i.id === id);
|
|
407
419
|
|
|
@@ -409,6 +421,11 @@ export const useUiContentSettingsStore = defineStore('uiContentSettings', {
|
|
|
409
421
|
return;
|
|
410
422
|
}
|
|
411
423
|
|
|
424
|
+
// Same hydration-write contract as updateItemValue.
|
|
425
|
+
if (isHydrationWrite) {
|
|
426
|
+
useHistoryStore().mergeNextMutation();
|
|
427
|
+
}
|
|
428
|
+
|
|
412
429
|
item.settings.content = vueDeepMerge(item.settings.content, value);
|
|
413
430
|
this.validateItem({ id, name });
|
|
414
431
|
this.onContentChanged();
|
package/lib/src/tracker.d.ts
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
export { useEventTracker, EVENTS, SELECT_LOCATIONS, UPGRADE_CTA_LOCATIONS, AI_CTA_LOCATIONS, TRIGGER_TYPE, PUBLISH_MODAL_CONTINUATION_EVENTS, GENERATE_TEXT_CONTINUATION_EVENTS, PUBLISH_OPTION_MODAL_CONTINUATION_EVENTS, } from './brand-page-maker/composables/useEventTracker';
|
|
2
|
-
export type { EventTracker, BpEventTrackerEvent, BpGlobalEventProps, BpUpsellEventProps, } from './brand-page-maker/composables/useEventTracker';
|
package/lib/src/tracker.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Lightweight subpath entry: `@designcrowd/library.brand-page/tracker`.
|
|
2
|
-
// Re-exports ONLY the analytics surface (useEventTracker + event constants),
|
|
3
|
-
// which depends solely on `vue`. This lets consumers import the tracker without
|
|
4
|
-
// pulling the full library graph (maker, TipTap, renderer). See
|
|
5
|
-
// docs/plans/multi-entrypoint-tree-shaking.md and the /tracker proposal.
|
|
6
|
-
//
|
|
7
|
-
// IMPORTANT: useEventTracker holds module-scoped pub/sub state (LISTENERS,
|
|
8
|
-
// GLOBAL_EVENT_PROPS). It MUST resolve to a single shared instance across this
|
|
9
|
-
// entry and the root `.` entry, or subscribers registered here won't receive
|
|
10
|
-
// events published via the root. The multi-entry build hoists it into a shared
|
|
11
|
-
// chunk (both `index` and `tracker` import it) — verified at build time.
|
|
12
|
-
export { useEventTracker, EVENTS, SELECT_LOCATIONS, UPGRADE_CTA_LOCATIONS, AI_CTA_LOCATIONS, TRIGGER_TYPE, PUBLISH_MODAL_CONTINUATION_EVENTS, GENERATE_TEXT_CONTINUATION_EVENTS, PUBLISH_OPTION_MODAL_CONTINUATION_EVENTS, } from './brand-page-maker/composables/useEventTracker';
|
package/lib/src/tracker.mjs
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { A as N, E as O, G as _, P as A, a as I, S as a, T as S, U as s, u as C } from "./useEventTracker-DmQ6AkNn.js";
|
|
2
|
-
export {
|
|
3
|
-
N as AI_CTA_LOCATIONS,
|
|
4
|
-
O as EVENTS,
|
|
5
|
-
_ as GENERATE_TEXT_CONTINUATION_EVENTS,
|
|
6
|
-
A as PUBLISH_MODAL_CONTINUATION_EVENTS,
|
|
7
|
-
I as PUBLISH_OPTION_MODAL_CONTINUATION_EVENTS,
|
|
8
|
-
a as SELECT_LOCATIONS,
|
|
9
|
-
S as TRIGGER_TYPE,
|
|
10
|
-
s as UPGRADE_CTA_LOCATIONS,
|
|
11
|
-
C as useEventTracker
|
|
12
|
-
};
|