@designcrowd/library.brand-page 6.0.6-tracker-1 → 6.0.6-undo-2
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-BSFTp6yl.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-en-us-DysrpsmM.js → CreatedOnBrandCrowd-en-us-rPQrOY1L.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-es-es-B6twGr9h.js → CreatedOnBrandCrowd-es-es-awd8-QFa.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-fr-yxl0ih_4.js → CreatedOnBrandCrowd-fr-ca-CwJ4J7Ow.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-fr-ca-yxl0ih_4.js → CreatedOnBrandCrowd-fr-fr-CwJ4J7Ow.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-pt-BtXDrIcx.js → CreatedOnBrandCrowd-pt-br-BXYfTLlD.js} +1 -1
- package/lib/src/{CreatedOnBrandCrowd-pt-br-BtXDrIcx.js → CreatedOnBrandCrowd-pt-pt-BXYfTLlD.js} +1 -1
- package/lib/src/{CreatedOnDcom-de-de-ho_ROy1L.js → CreatedOnDcom-de-de-kX6u1lNK.js} +1 -1
- package/lib/src/{CreatedOnDcom-en-us-C91p9kls.js → CreatedOnDcom-en-us-Bkq5sgFs.js} +1 -1
- package/lib/src/{CreatedOnDcom-es-es-B3FYmObE.js → CreatedOnDcom-es-es-zCAC9ujj.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-ca-D40m7fPx.js → CreatedOnDcom-fr-ca-BYz6Wzg5.js} +1 -1
- package/lib/src/{CreatedOnDcom-fr-fr-Cd57oYyc.js → CreatedOnDcom-fr-fr-CN-wAaSH.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-br-Du57mWxG.js → CreatedOnDcom-pt-br-BrK4Ngg-.js} +1 -1
- package/lib/src/{CreatedOnDcom-pt-pt-fYoPZWwr.js → CreatedOnDcom-pt-pt-AfI_g7xJ.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 +1 -1
- 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 +1 -1
- package/lib/src/brand-page-maker/components/brandpage-settings/ReplaceImageSettingsForBrandPageSettings.mixin.d.ts +1 -1
- package/lib/src/brand-page-maker/components/seo-settings/SeoPageSettings.mixin.d.ts +1 -1
- 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 +16 -0
- 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 +6 -0
- 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-BYFWAvIq.js} +22625 -22276
- 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/content-settings/ContentSettings.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +1 -1
- package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +1 -1
- 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/logo-settings/components/LogoSettings.mixin.d.ts +1 -1
- package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +1 -1
- package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +1 -1
- 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 +17 -0
- 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/text-style-field/TextStyleField.mixin.ts +19 -11
- 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
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { BrandPageModel } from '../../brand-page/models';
|
|
2
|
+
import { BaseMetadataBuilder, type BuilderResult, type MetadataBuilderRequest } from '../models';
|
|
3
|
+
import type { Logger } from '../logger';
|
|
4
|
+
export interface ReorderPagesPayload {
|
|
5
|
+
pageOrder: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare class ReorderPagesBuilder extends BaseMetadataBuilder<ReorderPagesPayload> {
|
|
8
|
+
constructor(request: MetadataBuilderRequest<ReorderPagesPayload>, logger?: Logger);
|
|
9
|
+
validateAsync(): Promise<{
|
|
10
|
+
errors: string[];
|
|
11
|
+
}>;
|
|
12
|
+
buildAsync(model: BrandPageModel): Promise<BuilderResult>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { BaseMetadataBuilder, } from '../models';
|
|
2
|
+
export class ReorderPagesBuilder extends BaseMetadataBuilder {
|
|
3
|
+
constructor(request, logger) {
|
|
4
|
+
super(request, logger);
|
|
5
|
+
}
|
|
6
|
+
async validateAsync() {
|
|
7
|
+
const errors = [];
|
|
8
|
+
const payload = this.request.payload;
|
|
9
|
+
if (!payload?.pageOrder?.length) {
|
|
10
|
+
errors.push('page_order is required for reorder_pages');
|
|
11
|
+
}
|
|
12
|
+
return { errors };
|
|
13
|
+
}
|
|
14
|
+
async buildAsync(model) {
|
|
15
|
+
this.log('Build called');
|
|
16
|
+
const validation = await this.validateAsync();
|
|
17
|
+
if (validation.errors.length) {
|
|
18
|
+
return { request: this.request, model, errors: validation.errors };
|
|
19
|
+
}
|
|
20
|
+
const { pageOrder } = this.request.payload;
|
|
21
|
+
// Build pageId → routeId lookup from nav.routes
|
|
22
|
+
const pageIdToRouteId = new Map();
|
|
23
|
+
for (const route of model.nav.routes) {
|
|
24
|
+
pageIdToRouteId.set(route.pageId, route.id);
|
|
25
|
+
}
|
|
26
|
+
// Build new nav.orders from the flat page_order (array of pageIds)
|
|
27
|
+
const newOrders = [];
|
|
28
|
+
const seenRouteIds = new Set();
|
|
29
|
+
for (const pageId of pageOrder) {
|
|
30
|
+
const routeId = pageIdToRouteId.get(pageId);
|
|
31
|
+
if (!routeId)
|
|
32
|
+
continue;
|
|
33
|
+
newOrders.push({ routeId, subRoutes: [] });
|
|
34
|
+
seenRouteIds.add(routeId);
|
|
35
|
+
}
|
|
36
|
+
// Safety: append any routes not mentioned (don't lose pages)
|
|
37
|
+
for (const route of model.nav.routes) {
|
|
38
|
+
const routeId = pageIdToRouteId.get(route.pageId);
|
|
39
|
+
if (routeId && !seenRouteIds.has(routeId)) {
|
|
40
|
+
newOrders.push({ routeId, subRoutes: [] });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
model.nav.orders = newOrders;
|
|
44
|
+
this.log({
|
|
45
|
+
message: `Reordered pages: ${pageOrder.join(', ')}`,
|
|
46
|
+
});
|
|
47
|
+
return { request: this.request, model };
|
|
48
|
+
}
|
|
49
|
+
}
|
package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts
CHANGED
|
@@ -147,7 +147,7 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
147
147
|
content: TContent;
|
|
148
148
|
}>(payload: P): Promise<void>;
|
|
149
149
|
_captureTemplateSwitchIfEnabled(): void;
|
|
150
|
-
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string): Promise<void>;
|
|
150
|
+
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string, selectedTemplateId?: string | false): Promise<void>;
|
|
151
151
|
_syncLogoSettingsFromSnapshot(snapshot: import("@brand-page").BrandPageModel, logoEditsStr?: string): Promise<void>;
|
|
152
152
|
_navigateToActivePage(activePageId?: string): void;
|
|
153
153
|
_fallbackSidebarIfSelectedContentMissing(snapshot: import("@brand-page").BrandPageModel): void;
|
|
@@ -676,7 +676,7 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
676
676
|
content: TContent;
|
|
677
677
|
}>(payload: P): Promise<void>;
|
|
678
678
|
_captureTemplateSwitchIfEnabled(): void;
|
|
679
|
-
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string): Promise<void>;
|
|
679
|
+
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string, selectedTemplateId?: string | false): Promise<void>;
|
|
680
680
|
_syncLogoSettingsFromSnapshot(snapshot: import("@brand-page").BrandPageModel, logoEditsStr?: string): Promise<void>;
|
|
681
681
|
_navigateToActivePage(activePageId?: string): void;
|
|
682
682
|
_fallbackSidebarIfSelectedContentMissing(snapshot: import("@brand-page").BrandPageModel): void;
|
|
@@ -620,7 +620,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
620
620
|
content: TContent;
|
|
621
621
|
}>(payload: P): Promise<void>;
|
|
622
622
|
_captureTemplateSwitchIfEnabled(): void;
|
|
623
|
-
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string): Promise<void>;
|
|
623
|
+
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string, selectedTemplateId?: string | false): Promise<void>;
|
|
624
624
|
_syncLogoSettingsFromSnapshot(snapshot: import("@brand-page").BrandPageModel, logoEditsStr?: string): Promise<void>;
|
|
625
625
|
_navigateToActivePage(activePageId?: string): void;
|
|
626
626
|
_fallbackSidebarIfSelectedContentMissing(snapshot: import("@brand-page").BrandPageModel): void;
|
package/lib/src/shared/content-settings/components/text-style-field/TextStyleField.mixin.d.ts
CHANGED
|
@@ -383,6 +383,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
383
383
|
onLetterSpacingChange(spacing: string): void;
|
|
384
384
|
onLineHeightChange(lineHeight: string): void;
|
|
385
385
|
generateFontFamilySelectorKey(): string;
|
|
386
|
+
syncTextStyleTypeSelection(): void;
|
|
386
387
|
}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "update:modelValue"[], "update:modelValue", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
387
388
|
id: {
|
|
388
389
|
type: StringConstructor;
|
|
@@ -124,13 +124,7 @@ export default defineComponent({
|
|
|
124
124
|
this.debounceOnTextSizeChange = debounce(this.onTextSizeChange, TEXT_SIZE_CHANGE_DEBOUNCE_WAIT_IN_MS);
|
|
125
125
|
this.debounceOnLetterSpacingChange = debounce(this.onLetterSpacingChange, TEXT_SIZE_CHANGE_DEBOUNCE_WAIT_IN_MS);
|
|
126
126
|
this.debounceOnLineHeightChange = debounce(this.onLineHeightChange, TEXT_SIZE_CHANGE_DEBOUNCE_WAIT_IN_MS);
|
|
127
|
-
|
|
128
|
-
if (value.textStyleType) {
|
|
129
|
-
const textStyleTypeOption = this.textStyleTypeOptions.find((x) => x.value === value.textStyleType);
|
|
130
|
-
if (textStyleTypeOption) {
|
|
131
|
-
textStyleTypeOption.isSelected = true;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
127
|
+
this.syncTextStyleTypeSelection();
|
|
134
128
|
},
|
|
135
129
|
computed: {
|
|
136
130
|
selectedTextStyle() {
|
|
@@ -320,9 +314,26 @@ export default defineComponent({
|
|
|
320
314
|
generateFontFamilySelectorKey() {
|
|
321
315
|
return `fontFamilySelector-${this.id}-${Date.now()}`;
|
|
322
316
|
},
|
|
317
|
+
// Re-derive the text-style-type selection from the current `value`.
|
|
318
|
+
// Seeded in created() and re-run whenever `value` changes (e.g. undo/redo
|
|
319
|
+
// restores the model) so the dropdown title and `selectedTextStyle`
|
|
320
|
+
// reflect the model rather than a stale local flag. (BP-5811 / BP-5817)
|
|
321
|
+
syncTextStyleTypeSelection() {
|
|
322
|
+
const value = this.value;
|
|
323
|
+
this.textStyleTypeOptions.forEach((option) => {
|
|
324
|
+
// The leading Boolean(...) guard is deliberate — do NOT simplify to
|
|
325
|
+
// `option.value === value?.textStyleType`. The "none" option's value
|
|
326
|
+
// is `undefined`, so that form would SELECT it whenever no style is
|
|
327
|
+
// set, whereas the convention (see emitChange) is all-flags-false
|
|
328
|
+
// when there is no textStyleType.
|
|
329
|
+
option.isSelected =
|
|
330
|
+
Boolean(value?.textStyleType) && option.value === value.textStyleType;
|
|
331
|
+
});
|
|
332
|
+
},
|
|
323
333
|
},
|
|
324
334
|
watch: {
|
|
325
335
|
value() {
|
|
336
|
+
this.syncTextStyleTypeSelection();
|
|
326
337
|
this.$nextTick(() => {
|
|
327
338
|
this.fontFamilySelectorKey = this.generateFontFamilySelectorKey();
|
|
328
339
|
});
|
|
@@ -134,7 +134,7 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
134
134
|
content: TContent;
|
|
135
135
|
}>(payload: P): Promise<void>;
|
|
136
136
|
_captureTemplateSwitchIfEnabled(): void;
|
|
137
|
-
applyHistorySnapshot(snapshot: import("../../../brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string): Promise<void>;
|
|
137
|
+
applyHistorySnapshot(snapshot: import("../../../brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string, selectedTemplateId?: string | false): Promise<void>;
|
|
138
138
|
_syncLogoSettingsFromSnapshot(snapshot: import("../../../brand-page").BrandPageModel, logoEditsStr?: string): Promise<void>;
|
|
139
139
|
_navigateToActivePage(activePageId?: string): void;
|
|
140
140
|
_fallbackSidebarIfSelectedContentMissing(snapshot: import("../../../brand-page").BrandPageModel): void;
|
|
@@ -3856,7 +3856,7 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
3856
3856
|
content: TContent;
|
|
3857
3857
|
}>(payload: P): Promise<void>;
|
|
3858
3858
|
_captureTemplateSwitchIfEnabled(): void;
|
|
3859
|
-
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string): Promise<void>;
|
|
3859
|
+
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string, selectedTemplateId?: string | false): Promise<void>;
|
|
3860
3860
|
_syncLogoSettingsFromSnapshot(snapshot: import("@brand-page").BrandPageModel, logoEditsStr?: string): Promise<void>;
|
|
3861
3861
|
_navigateToActivePage(activePageId?: string): void;
|
|
3862
3862
|
_fallbackSidebarIfSelectedContentMissing(snapshot: import("@brand-page").BrandPageModel): void;
|
|
@@ -4425,7 +4425,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
4425
4425
|
content: TContent;
|
|
4426
4426
|
}>(payload: P): Promise<void>;
|
|
4427
4427
|
_captureTemplateSwitchIfEnabled(): void;
|
|
4428
|
-
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string): Promise<void>;
|
|
4428
|
+
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string, selectedTemplateId?: string | false): Promise<void>;
|
|
4429
4429
|
_syncLogoSettingsFromSnapshot(snapshot: import("@brand-page").BrandPageModel, logoEditsStr?: string): Promise<void>;
|
|
4430
4430
|
_navigateToActivePage(activePageId?: string): void;
|
|
4431
4431
|
_fallbackSidebarIfSelectedContentMissing(snapshot: import("@brand-page").BrandPageModel): void;
|
package/lib/src/shared/publish-brand-page-with-state/PublishBrandPageModalWithState.mixin.d.ts
CHANGED
|
@@ -184,7 +184,7 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
184
184
|
content: TContent;
|
|
185
185
|
}>(payload: P): Promise<void>;
|
|
186
186
|
_captureTemplateSwitchIfEnabled(): void;
|
|
187
|
-
applyHistorySnapshot(snapshot: import("../../brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string): Promise<void>;
|
|
187
|
+
applyHistorySnapshot(snapshot: import("../../brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string, selectedTemplateId?: string | false): Promise<void>;
|
|
188
188
|
_syncLogoSettingsFromSnapshot(snapshot: import("../../brand-page").BrandPageModel, logoEditsStr?: string): Promise<void>;
|
|
189
189
|
_navigateToActivePage(activePageId?: string): void;
|
|
190
190
|
_fallbackSidebarIfSelectedContentMissing(snapshot: import("../../brand-page").BrandPageModel): void;
|
|
@@ -582,7 +582,7 @@ declare const _default: import("vue").DefineComponent<{}, {
|
|
|
582
582
|
content: TContent;
|
|
583
583
|
}>(payload: P): Promise<void>;
|
|
584
584
|
_captureTemplateSwitchIfEnabled(): void;
|
|
585
|
-
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string): Promise<void>;
|
|
585
|
+
applyHistorySnapshot(snapshot: import("@brand-page").BrandPageModel, activePageId?: string, logoEditsStr?: string, selectedTemplateId?: string | false): Promise<void>;
|
|
586
586
|
_syncLogoSettingsFromSnapshot(snapshot: import("@brand-page").BrandPageModel, logoEditsStr?: string): Promise<void>;
|
|
587
587
|
_navigateToActivePage(activePageId?: string): void;
|
|
588
588
|
_fallbackSidebarIfSelectedContentMissing(snapshot: import("@brand-page").BrandPageModel): void;
|
package/package.json
CHANGED
|
@@ -1,27 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@designcrowd/library.brand-page",
|
|
3
3
|
"description": "A collection of Maker/Designer applications",
|
|
4
|
-
"version": "6.0.6-
|
|
4
|
+
"version": "6.0.6-undo-2",
|
|
5
5
|
"author": "Design.com Eng",
|
|
6
6
|
"license": "UNLICENSED",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"types": "./lib/src/index.d.ts",
|
|
9
9
|
"main": "./lib/src/index.mjs",
|
|
10
|
-
"sideEffects": [
|
|
11
|
-
"**/*.css"
|
|
12
|
-
],
|
|
13
|
-
"exports": {
|
|
14
|
-
".": {
|
|
15
|
-
"types": "./lib/src/index.d.ts",
|
|
16
|
-
"import": "./lib/src/index.mjs"
|
|
17
|
-
},
|
|
18
|
-
"./tracker": {
|
|
19
|
-
"types": "./lib/src/tracker.d.ts",
|
|
20
|
-
"import": "./lib/src/tracker.mjs"
|
|
21
|
-
},
|
|
22
|
-
"./lib/src/css/*": "./lib/src/css/*",
|
|
23
|
-
"./package.json": "./package.json"
|
|
24
|
-
},
|
|
25
10
|
"files": [
|
|
26
11
|
"lib",
|
|
27
12
|
"src"
|
|
@@ -12,7 +12,12 @@ import {
|
|
|
12
12
|
PageHeaderMobile,
|
|
13
13
|
PageStyles,
|
|
14
14
|
} from '../models';
|
|
15
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
BrandPageModel,
|
|
17
|
+
BrandPageType,
|
|
18
|
+
LogoContent,
|
|
19
|
+
PageModel,
|
|
20
|
+
} from '../models';
|
|
16
21
|
import * as logoUtil from './logo.util';
|
|
17
22
|
|
|
18
23
|
interface GetLogoVariationIndexFromLogoImageUrlTestCase {
|
|
@@ -212,4 +217,52 @@ describe('logo-util', () => {
|
|
|
212
217
|
logoImage.logoDraftToken,
|
|
213
218
|
);
|
|
214
219
|
});
|
|
220
|
+
|
|
221
|
+
describe('getLogoImageFromModel', () => {
|
|
222
|
+
// Distinct tokens in the content block vs the header so each assertion
|
|
223
|
+
// proves which location the helper read from.
|
|
224
|
+
const buildModel = (brandPageType: BrandPageType): BrandPageModel => {
|
|
225
|
+
const model = createTestBrandPageModel();
|
|
226
|
+
|
|
227
|
+
model.brandPageType = brandPageType;
|
|
228
|
+
(model.pages[0].contents[0] as LogoContent).logoImage = {
|
|
229
|
+
logoDraftToken: 'content-token',
|
|
230
|
+
logoVariation: 0,
|
|
231
|
+
logoLastUpdate: undefined,
|
|
232
|
+
};
|
|
233
|
+
model.pageHeaderDesktop.logoImage = {
|
|
234
|
+
logoDraftToken: 'header-token',
|
|
235
|
+
logoVariation: 0,
|
|
236
|
+
logoLastUpdate: undefined,
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
return model;
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
test('reads the header logo for brand-site', () => {
|
|
243
|
+
const model = buildModel(BRAND_PAGE_TYPES.brandSite);
|
|
244
|
+
|
|
245
|
+
expect(logoUtil.getLogoImageFromModel(model)?.logoDraftToken).toBe(
|
|
246
|
+
'header-token',
|
|
247
|
+
);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
test('reads the content-block logo for brand-page', () => {
|
|
251
|
+
const model = buildModel(BRAND_PAGE_TYPES.default);
|
|
252
|
+
|
|
253
|
+
expect(logoUtil.getLogoImageFromModel(model)?.logoDraftToken).toBe(
|
|
254
|
+
'content-token',
|
|
255
|
+
);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
// Regression guard: brand-contact previously fell through to the header
|
|
259
|
+
// branch (the `=== brandPage` check) and read a stale header logo on undo.
|
|
260
|
+
test('reads the content-block logo for brand-contact', () => {
|
|
261
|
+
const model = buildModel(BRAND_PAGE_TYPES.brandContact);
|
|
262
|
+
|
|
263
|
+
expect(logoUtil.getLogoImageFromModel(model)?.logoDraftToken).toBe(
|
|
264
|
+
'content-token',
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
});
|
|
215
268
|
});
|
|
@@ -394,6 +394,29 @@ export const calculateOptimizedLogoDimensions = (
|
|
|
394
394
|
return { width: currentWidth, height: currentHeight };
|
|
395
395
|
};
|
|
396
396
|
|
|
397
|
+
/**
|
|
398
|
+
* Resolves the "current" logo image from a brand-page MODEL (the raw,
|
|
399
|
+
* deserialized shape — not the live stores, whose contents are wrapped in
|
|
400
|
+
* `settings.content`).
|
|
401
|
+
*
|
|
402
|
+
* Brand-site keeps its logo in the page header; brand-page and brand-contact
|
|
403
|
+
* keep it as a logo CONTENT block on the home page — the same `isBrandSite ?
|
|
404
|
+
* header : content` split the logo-settings store getters/setter use. This is
|
|
405
|
+
* the single source of truth for model-level logo reads: initial load and
|
|
406
|
+
* history-restore both call it so the two paths can't drift. They previously
|
|
407
|
+
* hard-coded `=== brandPage`, which silently excluded brand-contact and read a
|
|
408
|
+
* stale header logo on undo.
|
|
409
|
+
*/
|
|
410
|
+
export const getLogoImageFromModel = (
|
|
411
|
+
model: BrandPageModel,
|
|
412
|
+
): LogoImageModel | undefined => {
|
|
413
|
+
if (model.brandPageType === BRAND_PAGE_TYPES.brandSite) {
|
|
414
|
+
return model.pageHeaderDesktop?.logoImage;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
return model.pages?.[0]?.contents?.find(isLogoContent)?.logoImage;
|
|
418
|
+
};
|
|
419
|
+
|
|
397
420
|
export const recalculateLogoContentDimensions = async (
|
|
398
421
|
pageData: any,
|
|
399
422
|
editableLogoVariations: {
|
|
@@ -291,7 +291,7 @@ export default defineComponent({
|
|
|
291
291
|
|
|
292
292
|
// Capture baseline for undo/redo when the feature is active for this
|
|
293
293
|
// session — see useUndoRedoFlag.ts for the gate (LaunchDarkly flag +
|
|
294
|
-
//
|
|
294
|
+
// non-admin maker; all three brands).
|
|
295
295
|
if (useUndoRedoFlag().value) {
|
|
296
296
|
useHistoryStore().captureBaseline();
|
|
297
297
|
}
|
|
@@ -503,6 +503,23 @@ export const useRichTextEditor = (
|
|
|
503
503
|
editor.on('update', () => {
|
|
504
504
|
const sanitizedData = sanitiseClientSideRTE(editor.getHTML());
|
|
505
505
|
|
|
506
|
+
// An update fired while the editor is unfocused is TipTap rewriting the
|
|
507
|
+
// model back into its canonical HTML during mount rehydration or a
|
|
508
|
+
// programmatic setContent — not a user edit. Fold it into the current
|
|
509
|
+
// head so merely selecting a section doesn't push a phantom undo entry
|
|
510
|
+
// (BP-5810). The construction-time arm above lapses before this async
|
|
511
|
+
// write-back fires, so re-arm here. Genuine edits happen while focused and
|
|
512
|
+
// still push a new entry.
|
|
513
|
+
//
|
|
514
|
+
// Known limitation: a programmatic toolbar command run on an editor the
|
|
515
|
+
// user hasn't focused yet would also merge (losing that undo step). Today
|
|
516
|
+
// the RTE only mounts inside an already-open settings drawer and the user
|
|
517
|
+
// focuses it before formatting, so this doesn't occur — revisit if a
|
|
518
|
+
// consumer ever drives toolbar actions on an unfocused editor.
|
|
519
|
+
if (!editor.isFocused && !historyStore.isApplyingSnapshot) {
|
|
520
|
+
historyStore.mergeNextMutation();
|
|
521
|
+
}
|
|
522
|
+
|
|
506
523
|
emit('update:modelValue', sanitizedData.sanitizedHtml);
|
|
507
524
|
});
|
|
508
525
|
|
|
@@ -1,30 +1,24 @@
|
|
|
1
1
|
import { computed, type ComputedRef } from 'vue';
|
|
2
2
|
import { useBrandPageMakerUserStore } from '@brand-page-maker/stores/user';
|
|
3
|
-
import { useBrandPageMakerStore } from '@brand-page-maker/stores/brandpage-maker/brandpage-maker-store';
|
|
4
3
|
|
|
5
4
|
/**
|
|
6
|
-
* Returns whether undo/redo is active for the current maker session.
|
|
7
|
-
*
|
|
5
|
+
* Returns whether undo/redo is active for the current maker session. Both
|
|
6
|
+
* conditions must hold:
|
|
8
7
|
*
|
|
9
8
|
* 1. `userStore.features.canUseUndoRedo` is true. The flag is populated by
|
|
10
9
|
* the consumer (BrandCrowd.Net / web-renderer) via the
|
|
11
10
|
* `WebsiteDesignUserFeatures.CanUseUndoRedo` boolean on the ViewModel —
|
|
12
|
-
* same precedent as RichTextEditor / GettyVideos / AITextGenerator.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* 3. The session is NOT in admin-maker mode (`userStore.isAdmin`). The
|
|
11
|
+
* same precedent as RichTextEditor / GettyVideos / AITextGenerator. The
|
|
12
|
+
* one flag governs all three brands (brand-site, brand-page,
|
|
13
|
+
* brand-contact) — there is no per-brand gating.
|
|
14
|
+
* 2. The session is NOT in admin-maker mode (`userStore.isAdmin`). The
|
|
17
15
|
* admin maker uses the same components but a different editing flow
|
|
18
16
|
* (template authoring) where undo/redo is out of scope.
|
|
19
17
|
*/
|
|
20
18
|
export function useUndoRedoFlag(): ComputedRef<boolean> {
|
|
21
19
|
const userStore = useBrandPageMakerUserStore();
|
|
22
|
-
const brandPageMakerStore = useBrandPageMakerStore();
|
|
23
20
|
|
|
24
21
|
return computed(
|
|
25
|
-
() =>
|
|
26
|
-
userStore.features.canUseUndoRedo &&
|
|
27
|
-
brandPageMakerStore.isBrandSite &&
|
|
28
|
-
!userStore.isAdmin,
|
|
22
|
+
() => userStore.features.canUseUndoRedo && !userStore.isAdmin,
|
|
29
23
|
);
|
|
30
24
|
}
|
|
@@ -727,6 +727,59 @@ describe('brand page maker store module', () => {
|
|
|
727
727
|
expect(pageNavigationStore.activePageId).toBe(expectedFirstId);
|
|
728
728
|
});
|
|
729
729
|
|
|
730
|
+
// BP-5813: the templates sidebar highlight binds to `selectedTemplateId`,
|
|
731
|
+
// which isn't part of `brandPageData`. It rides along as a history-entry
|
|
732
|
+
// sidecar; applyHistorySnapshot restores it so the highlight reverts in
|
|
733
|
+
// lock-step with the canvas.
|
|
734
|
+
test('applyHistorySnapshot restores selectedTemplateId from the sidecar', async () => {
|
|
735
|
+
const makerStore = useBrandPageMakerStore();
|
|
736
|
+
|
|
737
|
+
await makerStore.initialise(INITIALISE_PAYLOAD);
|
|
738
|
+
|
|
739
|
+
makerStore.setSelectedTemplateId({ templateId: 'template-current' });
|
|
740
|
+
|
|
741
|
+
// Undo lands on an entry captured while 'template-previous' was selected.
|
|
742
|
+
await makerStore.applyHistorySnapshot(
|
|
743
|
+
makerStore.brandPageData,
|
|
744
|
+
undefined,
|
|
745
|
+
undefined,
|
|
746
|
+
'template-previous',
|
|
747
|
+
);
|
|
748
|
+
|
|
749
|
+
expect(makerStore.selectedTemplateId).toBe('template-previous');
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
test('applyHistorySnapshot restores a cleared (false) selectedTemplateId', async () => {
|
|
753
|
+
const makerStore = useBrandPageMakerStore();
|
|
754
|
+
|
|
755
|
+
await makerStore.initialise(INITIALISE_PAYLOAD);
|
|
756
|
+
|
|
757
|
+
makerStore.setSelectedTemplateId({ templateId: 'template-current' });
|
|
758
|
+
|
|
759
|
+
await makerStore.applyHistorySnapshot(
|
|
760
|
+
makerStore.brandPageData,
|
|
761
|
+
undefined,
|
|
762
|
+
undefined,
|
|
763
|
+
false,
|
|
764
|
+
);
|
|
765
|
+
|
|
766
|
+
expect(makerStore.selectedTemplateId).toBe(false);
|
|
767
|
+
});
|
|
768
|
+
|
|
769
|
+
test('applyHistorySnapshot leaves selectedTemplateId untouched when the sidecar is undefined', async () => {
|
|
770
|
+
const makerStore = useBrandPageMakerStore();
|
|
771
|
+
|
|
772
|
+
await makerStore.initialise(INITIALISE_PAYLOAD);
|
|
773
|
+
|
|
774
|
+
makerStore.setSelectedTemplateId({ templateId: 'template-current' });
|
|
775
|
+
|
|
776
|
+
// An entry with no sidecar (e.g. captured before the field existed) must
|
|
777
|
+
// not clobber the current selection.
|
|
778
|
+
await makerStore.applyHistorySnapshot(makerStore.brandPageData);
|
|
779
|
+
|
|
780
|
+
expect(makerStore.selectedTemplateId).toBe('template-current');
|
|
781
|
+
});
|
|
782
|
+
|
|
730
783
|
// BP-5506 follow-up: undoing a non-page-structural edit (e.g. a title
|
|
731
784
|
// change) must NOT push a new route. The router push fires
|
|
732
785
|
// `router.afterEach`, and BrandPageMaker.mixin's afterEach hook resets
|
|
@@ -793,6 +793,7 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
|
|
|
793
793
|
snapshot: BrandPageModel,
|
|
794
794
|
activePageId?: string,
|
|
795
795
|
logoEditsStr?: string,
|
|
796
|
+
selectedTemplateId?: string | false,
|
|
796
797
|
): Promise<void> {
|
|
797
798
|
const styleSettingsStore = useUiStyleSettingsStore();
|
|
798
799
|
const navigationStyleSettingsStore = useUiNavigationStyleSettingsStore();
|
|
@@ -883,6 +884,16 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
|
|
|
883
884
|
this.cookieOptions = snapshot.cookieOptions;
|
|
884
885
|
this.saveContactSettings = snapshot.saveContactSettings;
|
|
885
886
|
|
|
887
|
+
// 7b. Restore the selected-template pointer that drives the templates
|
|
888
|
+
// sidebar highlight. It's a UI pointer, not part of the persisted
|
|
889
|
+
// model, so it rides along as a history-entry sidecar (like
|
|
890
|
+
// `activePageId`). Its watchers only reset scroll position (no
|
|
891
|
+
// template re-application), so setting it here is safe during apply.
|
|
892
|
+
// (BP-5813)
|
|
893
|
+
if (selectedTemplateId !== undefined) {
|
|
894
|
+
this.setSelectedTemplateId({ templateId: selectedTemplateId });
|
|
895
|
+
}
|
|
896
|
+
|
|
886
897
|
// 8. Re-sync the logo-settings sidebar's `selectedLogoImage` from the
|
|
887
898
|
// restored header logo. The preview rehydrates via the page contents,
|
|
888
899
|
// but `uiLogoSettings` holds its own copy that drives the sidebar
|
|
@@ -945,14 +956,7 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
|
|
|
945
956
|
}
|
|
946
957
|
}
|
|
947
958
|
|
|
948
|
-
const logoImage =
|
|
949
|
-
snapshot.brandPageType === BRAND_PAGE_TYPES.default
|
|
950
|
-
? (
|
|
951
|
-
snapshot.pages?.[0]?.contents?.find(
|
|
952
|
-
(c) => c.type === 'logo',
|
|
953
|
-
) as any
|
|
954
|
-
)?.logoImage
|
|
955
|
-
: snapshot.pageHeaderDesktop?.logoImage;
|
|
959
|
+
const logoImage = logoUtil.getLogoImageFromModel(snapshot);
|
|
956
960
|
|
|
957
961
|
if (!logoImage) return;
|
|
958
962
|
|
|
@@ -1273,14 +1277,7 @@ export const useBrandPageMakerStore = defineStore('brandPageMaker', {
|
|
|
1273
1277
|
brandPageType: _brandPageType,
|
|
1274
1278
|
});
|
|
1275
1279
|
|
|
1276
|
-
let logoImage =
|
|
1277
|
-
brandPageModel.brandPageType === BRAND_PAGE_TYPES.default
|
|
1278
|
-
? (
|
|
1279
|
-
brandPageModel.pages?.[0].contents.find(
|
|
1280
|
-
(c) => c.type === 'logo',
|
|
1281
|
-
) as any
|
|
1282
|
-
)?.logoImage
|
|
1283
|
-
: brandPageModel.pageHeaderDesktop?.logoImage;
|
|
1280
|
+
let logoImage = logoUtil.getLogoImageFromModel(brandPageModel);
|
|
1284
1281
|
|
|
1285
1282
|
if (!logoImage?.logoDraftToken) {
|
|
1286
1283
|
logoImage = logoUtil.safeGetLogoImageFromLogoImageUrl(
|
|
@@ -16,6 +16,8 @@ const mockMakerStore = {
|
|
|
16
16
|
isBrandPageLoaded: false,
|
|
17
17
|
applyHistorySnapshot: vi.fn(async () => undefined),
|
|
18
18
|
setIsBrandPageLoaded: vi.fn(),
|
|
19
|
+
selectedTemplateId: false as string | false,
|
|
20
|
+
setSelectedTemplateId: vi.fn(),
|
|
19
21
|
};
|
|
20
22
|
|
|
21
23
|
const mockPageNavigationStore = {
|
|
@@ -64,6 +66,8 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
|
|
|
64
66
|
beforeEach(() => {
|
|
65
67
|
setActivePinia(createPinia());
|
|
66
68
|
mockMakerStore.applyHistorySnapshot.mockClear();
|
|
69
|
+
mockMakerStore.setSelectedTemplateId.mockClear();
|
|
70
|
+
mockMakerStore.selectedTemplateId = false;
|
|
67
71
|
mutationCounter = 0;
|
|
68
72
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
69
73
|
(mockMakerStore.brandPageData as any).v = 1;
|
|
@@ -443,6 +447,46 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
|
|
|
443
447
|
});
|
|
444
448
|
});
|
|
445
449
|
|
|
450
|
+
// BP-5813: the templates sidebar highlight binds to
|
|
451
|
+
// `brandPageMakerStore.selectedTemplateId`, which is NOT part of
|
|
452
|
+
// `brandPageData`. It rides along as a per-entry sidecar so undo/redo can
|
|
453
|
+
// restore the highlight in lock-step with the canvas.
|
|
454
|
+
describe('selectedTemplateId sidecar (BP-5813 — template sidebar highlight)', () => {
|
|
455
|
+
it('captures the current selectedTemplateId on each entry', async () => {
|
|
456
|
+
const store = useHistoryStore();
|
|
457
|
+
|
|
458
|
+
mockMakerStore.selectedTemplateId = 'template-a';
|
|
459
|
+
await store.captureBaseline();
|
|
460
|
+
|
|
461
|
+
expect(store.entries[0].selectedTemplateId).toBe('template-a');
|
|
462
|
+
|
|
463
|
+
mockMakerStore.selectedTemplateId = 'template-b';
|
|
464
|
+
captureMutated(store);
|
|
465
|
+
|
|
466
|
+
expect(store.entries[1].selectedTemplateId).toBe('template-b');
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
it('passes the target entry selectedTemplateId to applyHistorySnapshot on undo', async () => {
|
|
470
|
+
const store = useHistoryStore();
|
|
471
|
+
|
|
472
|
+
mockMakerStore.selectedTemplateId = 'template-a';
|
|
473
|
+
await store.captureBaseline();
|
|
474
|
+
|
|
475
|
+
mockMakerStore.selectedTemplateId = 'template-b';
|
|
476
|
+
captureMutated(store);
|
|
477
|
+
|
|
478
|
+
await store.undo();
|
|
479
|
+
|
|
480
|
+
// 4th arg is the baseline entry's template id — the sidebar reverts
|
|
481
|
+
// with the canvas instead of lagging on the undone template.
|
|
482
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
483
|
+
const callArgs = mockMakerStore.applyHistorySnapshot.mock
|
|
484
|
+
.calls[0] as any[];
|
|
485
|
+
|
|
486
|
+
expect(callArgs[3]).toBe('template-a');
|
|
487
|
+
});
|
|
488
|
+
});
|
|
489
|
+
|
|
446
490
|
it('reentrancy guard: capture no-ops when isApplyingSnapshot is true', async () => {
|
|
447
491
|
const store = useHistoryStore();
|
|
448
492
|
|
|
@@ -505,6 +549,7 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
|
|
|
505
549
|
expect.objectContaining(baselineBrandPageData),
|
|
506
550
|
undefined,
|
|
507
551
|
expect.any(String),
|
|
552
|
+
false,
|
|
508
553
|
);
|
|
509
554
|
});
|
|
510
555
|
|
|
@@ -767,6 +812,7 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
|
|
|
767
812
|
expect.anything(),
|
|
768
813
|
'page-home',
|
|
769
814
|
expect.any(String),
|
|
815
|
+
false,
|
|
770
816
|
);
|
|
771
817
|
});
|
|
772
818
|
|
|
@@ -801,6 +847,7 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
|
|
|
801
847
|
expect.anything(),
|
|
802
848
|
'page-home',
|
|
803
849
|
expect.any(String),
|
|
850
|
+
false,
|
|
804
851
|
);
|
|
805
852
|
});
|
|
806
853
|
|
|
@@ -842,6 +889,7 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
|
|
|
842
889
|
expect.anything(),
|
|
843
890
|
'page-about',
|
|
844
891
|
expect.any(String),
|
|
892
|
+
false,
|
|
845
893
|
);
|
|
846
894
|
});
|
|
847
895
|
|
|
@@ -879,6 +927,7 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
|
|
|
879
927
|
expect.anything(),
|
|
880
928
|
'page-new',
|
|
881
929
|
expect.any(String),
|
|
930
|
+
false,
|
|
882
931
|
);
|
|
883
932
|
});
|
|
884
933
|
|
|
@@ -912,6 +961,7 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
|
|
|
912
961
|
expect.anything(),
|
|
913
962
|
'page-home',
|
|
914
963
|
expect.any(String),
|
|
964
|
+
false,
|
|
915
965
|
);
|
|
916
966
|
|
|
917
967
|
// Now redo. Pointer moves forward to entry 1 (page-x captured),
|
|
@@ -922,6 +972,7 @@ describe('history-store (single stack + JSON-string snapshots)', () => {
|
|
|
922
972
|
expect.anything(),
|
|
923
973
|
'page-x',
|
|
924
974
|
expect.any(String),
|
|
975
|
+
false,
|
|
925
976
|
);
|
|
926
977
|
});
|
|
927
978
|
});
|