@designcrowd/library.brand-page 6.2.13 → 6.2.14

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.
Files changed (33) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-COhZYMwW.js → CreatedOnBrandCrowd-de-de-Deoc6s8r.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-De5eIVfZ.js → CreatedOnBrandCrowd-en-us-BxDzsLl-.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-D7Bk2q4d.js → CreatedOnBrandCrowd-es-es-B-5VS2MV.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-BBCuO0D-.js → CreatedOnBrandCrowd-fr-ca-C6h05sUZ.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-BBCuO0D-.js → CreatedOnBrandCrowd-fr-fr-C6h05sUZ.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-B5MrGFq-.js → CreatedOnBrandCrowd-pt-br-BC6XU3ev.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-B5MrGFq-.js → CreatedOnBrandCrowd-pt-pt-BC6XU3ev.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-CJSWCbRg.js → CreatedOnDcom-de-de-dUTedh8v.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-OO0s0TRW.js → CreatedOnDcom-en-us-DY0jkOeW.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-DQX1lZq7.js → CreatedOnDcom-es-es-DRioej2A.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-C5cQ3rla.js → CreatedOnDcom-fr-ca-CcglfcUU.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-UdyUX0b_.js → CreatedOnDcom-fr-fr-B7v_e6HI.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-C0FiDCQG.js → CreatedOnDcom-pt-br-5XGcKJb7.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-CbbnZ7aN.js → CreatedOnDcom-pt-pt-DepC53tO.js} +1 -1
  15. package/lib/src/brand-page/utils/container-text-color.util.d.ts +12 -2
  16. package/lib/src/brand-page/utils/container-text-color.util.js +1 -1
  17. package/lib/src/brand-page/utils/migration/migration-22.d.ts +3 -2
  18. package/lib/src/brand-page/utils/migration/migration-22.js +8 -3
  19. package/lib/src/brand-page-maker/models/content-settings.js +3 -1
  20. package/lib/src/index.mjs +1 -1
  21. package/lib/src/{lib-DgFekeRm.js → lib-CidddZOL.js} +2810 -2801
  22. package/package.json +1 -1
  23. package/src/brand-page/utils/container-text-color.util.ts +3 -3
  24. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/new-brandcontact-every-section.v22.json +4 -8
  25. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/new-brandpage-every-section.v22.json +4 -8
  26. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/new-brandsite-every-section.v22.json +4 -8
  27. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandcontact.v22.json +1 -2
  28. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandpage-general-link.v22.json +3 -6
  29. package/src/brand-page/utils/migration/__snapshots__/migration-22-output/real-brandpage-links.v22.json +1 -2
  30. package/src/brand-page/utils/migration/migration-22.test.ts +88 -0
  31. package/src/brand-page/utils/migration/migration-22.ts +9 -2
  32. package/src/brand-page-maker/models/content-settings.test.ts +49 -1
  33. package/src/brand-page-maker/models/content-settings.ts +3 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@designcrowd/library.brand-page",
3
3
  "description": "A collection of Maker/Designer applications",
4
- "version": "6.2.13",
4
+ "version": "6.2.14",
5
5
  "author": "Design.com Eng",
6
6
  "license": "UNLICENSED",
7
7
  "type": "module",
@@ -9,8 +9,8 @@
9
9
  * reason `resolveTextColor` lives in one place (`text-style.util.ts`).
10
10
  *
11
11
  * MIGRATION-22 SNAPSHOT DEPENDENCY: the v21 -> v22 colour bake calls
12
- * `containerTextColorDefaults` and `titleSurfaceContrastFill`. Pin that migration's behaviour
13
- * before changing either helper after it releases.
12
+ * `containerTextColorDefaults`, `titleSurfaceContrastFill` and `isButtonLabelField`. Pin that
13
+ * migration's behaviour before changing any of them after it releases.
14
14
  */
15
15
  import type {
16
16
  Content,
@@ -180,7 +180,7 @@ const NON_SECTION_SURFACE_KEYS = new Set<ContentTextStylePropertyKey>([
180
180
  * contrast the PAGE instead and collide with the fill (the default theme paints both from the same
181
181
  * brand role, hiding the text).
182
182
  */
183
- const isButtonLabelField = (
183
+ export const isButtonLabelField = (
184
184
  content: Content,
185
185
  key: ContentTextStylePropertyKey,
186
186
  ): boolean => key === 'titleStyle' && isButtonContent(content);
@@ -646,8 +646,7 @@
646
646
  "textStyleType": "button",
647
647
  "textAlign": "center",
648
648
  "lineHeight": "1.5",
649
- "letterSpacing": "0",
650
- "color": "var(--palette-1)"
649
+ "letterSpacing": "0"
651
650
  },
652
651
  "url": "",
653
652
  "colorReplacements": [],
@@ -665,8 +664,7 @@
665
664
  "textStyleType": "button",
666
665
  "textAlign": "center",
667
666
  "lineHeight": "1.5",
668
- "letterSpacing": "0",
669
- "color": "var(--palette-1)"
667
+ "letterSpacing": "0"
670
668
  },
671
669
  "url": "",
672
670
  "colorReplacements": [],
@@ -684,8 +682,7 @@
684
682
  "textStyleType": "button",
685
683
  "textAlign": "center",
686
684
  "lineHeight": "1.5",
687
- "letterSpacing": "0",
688
- "color": "var(--palette-1)"
685
+ "letterSpacing": "0"
689
686
  },
690
687
  "url": "",
691
688
  "colorReplacements": [],
@@ -708,8 +705,7 @@
708
705
  "textStyleType": "button",
709
706
  "textAlign": "center",
710
707
  "lineHeight": "1.5",
711
- "letterSpacing": "0",
712
- "color": "var(--palette-1)"
708
+ "letterSpacing": "0"
713
709
  },
714
710
  "fieldRole": "button"
715
711
  },
@@ -646,8 +646,7 @@
646
646
  "textStyleType": "button",
647
647
  "textAlign": "center",
648
648
  "lineHeight": "1.5",
649
- "letterSpacing": "0",
650
- "color": "var(--palette-1)"
649
+ "letterSpacing": "0"
651
650
  },
652
651
  "url": "",
653
652
  "colorReplacements": [],
@@ -665,8 +664,7 @@
665
664
  "textStyleType": "button",
666
665
  "textAlign": "center",
667
666
  "lineHeight": "1.5",
668
- "letterSpacing": "0",
669
- "color": "var(--palette-1)"
667
+ "letterSpacing": "0"
670
668
  },
671
669
  "url": "",
672
670
  "colorReplacements": [],
@@ -684,8 +682,7 @@
684
682
  "textStyleType": "button",
685
683
  "textAlign": "center",
686
684
  "lineHeight": "1.5",
687
- "letterSpacing": "0",
688
- "color": "var(--palette-1)"
685
+ "letterSpacing": "0"
689
686
  },
690
687
  "url": "",
691
688
  "colorReplacements": [],
@@ -708,8 +705,7 @@
708
705
  "textStyleType": "button",
709
706
  "textAlign": "center",
710
707
  "lineHeight": "1.5",
711
- "letterSpacing": "0",
712
- "color": "var(--palette-1)"
708
+ "letterSpacing": "0"
713
709
  },
714
710
  "fieldRole": "button"
715
711
  },
@@ -646,8 +646,7 @@
646
646
  "textStyleType": "button",
647
647
  "textAlign": "center",
648
648
  "lineHeight": "1.5",
649
- "letterSpacing": "0",
650
- "color": "var(--palette-1)"
649
+ "letterSpacing": "0"
651
650
  },
652
651
  "url": "",
653
652
  "colorReplacements": [],
@@ -665,8 +664,7 @@
665
664
  "textStyleType": "button",
666
665
  "textAlign": "center",
667
666
  "lineHeight": "1.5",
668
- "letterSpacing": "0",
669
- "color": "var(--palette-1)"
667
+ "letterSpacing": "0"
670
668
  },
671
669
  "url": "",
672
670
  "colorReplacements": [],
@@ -684,8 +682,7 @@
684
682
  "textStyleType": "button",
685
683
  "textAlign": "center",
686
684
  "lineHeight": "1.5",
687
- "letterSpacing": "0",
688
- "color": "var(--palette-1)"
685
+ "letterSpacing": "0"
689
686
  },
690
687
  "url": "",
691
688
  "colorReplacements": [],
@@ -708,8 +705,7 @@
708
705
  "textStyleType": "button",
709
706
  "textAlign": "center",
710
707
  "lineHeight": "1.5",
711
- "letterSpacing": "0",
712
- "color": "var(--palette-1)"
708
+ "letterSpacing": "0"
713
709
  },
714
710
  "fieldRole": "button"
715
711
  },
@@ -659,8 +659,7 @@
659
659
  "textAlign": "center",
660
660
  "lineHeight": "1.5",
661
661
  "applyAutoScale": false,
662
- "textStyleType": "button",
663
- "color": "var(--palette-0)"
662
+ "textStyleType": "button"
664
663
  },
665
664
  "colorReplacements": [],
666
665
  "page": ""
@@ -531,8 +531,7 @@
531
531
  "textStyleType": "button",
532
532
  "lineHeight": "1.5",
533
533
  "applyAutoScale": false,
534
- "letterSpacing": "0",
535
- "color": "var(--palette-1)"
534
+ "letterSpacing": "0"
536
535
  },
537
536
  "modalImageUrl": "",
538
537
  "clickActionField": "url",
@@ -551,8 +550,7 @@
551
550
  "textStyleType": "button",
552
551
  "lineHeight": "1.5",
553
552
  "applyAutoScale": false,
554
- "letterSpacing": "0",
555
- "color": "var(--palette-1)"
553
+ "letterSpacing": "0"
556
554
  },
557
555
  "modalImageUrl": "https://bc-user-uploads.brandcrowd.com/public/media-uat4/b0377e32-964c-430d-b0c4-05062e5d240d/fb0ec8f5-713e-43e0-8a0a-469109ca5876.png",
558
556
  "clickActionField": "modalImageUrl",
@@ -571,8 +569,7 @@
571
569
  "textStyleType": "button",
572
570
  "lineHeight": "1.5",
573
571
  "applyAutoScale": false,
574
- "letterSpacing": "0",
575
- "color": "var(--palette-1)"
572
+ "letterSpacing": "0"
576
573
  },
577
574
  "modalImageUrl": "",
578
575
  "clickActionField": "page",
@@ -659,8 +659,7 @@
659
659
  "textAlign": "center",
660
660
  "lineHeight": "1.5",
661
661
  "applyAutoScale": false,
662
- "textStyleType": "button",
663
- "color": "var(--palette-0)"
662
+ "textStyleType": "button"
664
663
  },
665
664
  "colorReplacements": [],
666
665
  "page": ""
@@ -48,6 +48,11 @@ import { DETACHED_UNSET_EFFECTIVE } from '../text-role-reconnect.util';
48
48
  import * as textRoleCss from '../text-role-css.util';
49
49
  import * as rteRoleLift from '../rte-role-lift.util';
50
50
  import { applyTextContrast } from '../container-text-color.util';
51
+ import {
52
+ resolveColorReference,
53
+ STRATEGY_COPY_MIN_CONTRAST,
54
+ } from '../color-palette.util';
55
+ import Color from 'color';
51
56
  import {
52
57
  PRODUCTION_BUTTON_DEFAULTS,
53
58
  PRODUCTION_HEADER_BUTTON_STYLE,
@@ -3103,6 +3108,89 @@ describe('migration-22 · bakeElementColours (D — freeze resolved colour)', ()
3103
3108
  });
3104
3109
  });
3105
3110
 
3111
+ describe('migration-22 · standalone button label colour (plain text on the one global button fill)', () => {
3112
+ // The old logo-token sites: the page text colour, and so the base coat, is also the button fill.
3113
+ const linkButtonSite = (content: Record<string, unknown>): BrandPageModel => {
3114
+ const options = TextStyles.GetDefaultTextStyle().textStyleOptions;
3115
+
3116
+ setRoleColor(options.paragraphs.style, 'var(--palette-0)');
3117
+ setRoleColor(options.buttons.style, 'var(--palette-1)');
3118
+
3119
+ return {
3120
+ pages: [{ contents: [content] }],
3121
+ styles: {
3122
+ textStyles: { textFontFamily: 'lato', textStyleOptions: options },
3123
+ buttonStyles: {
3124
+ style: {
3125
+ backgroundColor: 'var(--palette-0)',
3126
+ color: 'var(--palette-1)',
3127
+ },
3128
+ },
3129
+ colors: [
3130
+ { id: 'palette-0', value: '#1b2a41', type: 'palette' },
3131
+ { id: 'palette-1', value: '#f4f1de', type: 'palette' },
3132
+ ],
3133
+ },
3134
+ brandPageType: BRAND_PAGE_TYPES.default,
3135
+ } as unknown as BrandPageModel;
3136
+ };
3137
+
3138
+ // WCAG ratio of what the label finally draws (its own colour, else the button text colour it
3139
+ // inherits) on the global button fill.
3140
+ const labelContrastOnFill = (
3141
+ model: BrandPageModel,
3142
+ label: { color?: string },
3143
+ ): number => {
3144
+ const { buttonStyles, colors } = model.styles;
3145
+ const resolve = (value: string): string =>
3146
+ resolveColorReference(value, colors, { withRoleDefaults: true });
3147
+
3148
+ return Color(resolve(label.color || buttonStyles.style.color!)).contrast(
3149
+ Color(resolve(buttonStyles.style.backgroundColor!)),
3150
+ );
3151
+ };
3152
+
3153
+ it.each(['general-link', 'email', 'facebook'])(
3154
+ 'a %s label on no role reads on the global button fill',
3155
+ async (type) => {
3156
+ const model = await runMigration22(
3157
+ linkButtonSite({
3158
+ type,
3159
+ title: 'Get A Quote',
3160
+ titleStyle: { textAlign: 'center', fontFamily: 'Lato' },
3161
+ }),
3162
+ );
3163
+ const content = model.pages[0].contents[0] as unknown as {
3164
+ title: unknown;
3165
+ titleStyle: { color?: string; textStyleType?: string };
3166
+ };
3167
+
3168
+ expect(typeof content.title).toBe('string'); // not RTE: no run mark can hold a colour
3169
+ expect(content.titleStyle.textStyleType).toBe('button');
3170
+ expect(
3171
+ labelContrastOnFill(model, content.titleStyle),
3172
+ ).toBeGreaterThanOrEqual(STRATEGY_COPY_MIN_CONTRAST);
3173
+ },
3174
+ );
3175
+
3176
+ it('a label on the retired Buttons role still reads on the global button fill', async () => {
3177
+ const model = await runMigration22(
3178
+ linkButtonSite({
3179
+ type: 'general-link',
3180
+ title: 'Reviews',
3181
+ titleStyle: { textStyleType: 'buttons' },
3182
+ }),
3183
+ );
3184
+ const { titleStyle } = model.pages[0].contents[0] as unknown as {
3185
+ titleStyle: { color?: string };
3186
+ };
3187
+
3188
+ expect(labelContrastOnFill(model, titleStyle)).toBeGreaterThanOrEqual(
3189
+ STRATEGY_COPY_MIN_CONTRAST,
3190
+ );
3191
+ });
3192
+ });
3193
+
3106
3194
  describe('migration-22 · convertPlainRteFields (B1 — plain text → Tiptap doc)', () => {
3107
3195
  it('converts a plain-string RTE field to a Tiptap doc', async () => {
3108
3196
  const content = {
@@ -44,6 +44,7 @@ import {
44
44
  } from '@shared/color-strategies/rte-field-pairs';
45
45
  import {
46
46
  containerTextColorDefaults,
47
+ isButtonLabelField,
47
48
  titleSurfaceContrastFill,
48
49
  } from '../container-text-color.util';
49
50
  import {
@@ -776,8 +777,9 @@ const roleColour = (
776
777
  * and the role colour (E) changes no pixels. migration-21 already baked element→frame→role
777
778
  * colour into RTE runs, so the only uncoloured runs reaching here inherit the base coat;
778
779
  * non-RTE fields (21 left them alone) resolve element→container-default→role→base coat.
779
- * `buttonTextStyle` is excluded — the button label takes its colour from `buttonStyles`,
780
- * never the base coat. A social-links section's unset icon fill is frozen here too.
780
+ * `buttonTextStyle` and a link button's `titleStyle` are excluded — the button label takes its
781
+ * colour from `buttonStyles`, never the base coat. A social-links section's unset icon fill is
782
+ * frozen here too.
781
783
  */
782
784
  export const bakeElementColours = (
783
785
  brandPageModel: BrandPageModel,
@@ -812,6 +814,11 @@ export const bakeElementColours = (
812
814
  for (const key of Object.keys(CONTENT_TEXT_STYLE_PROPERTY_KEYS)) {
813
815
  if (key === 'buttonTextStyle' || rteStyleFields.has(key)) continue;
814
816
 
817
+ // A link button's label sits on the global button fill, not the page the base coat
818
+ // contrasts: left bare it inherits the button text colour (`isButtonLabelField`).
819
+ if (isButtonLabelField(content, key as ContentTextStylePropertyKey))
820
+ continue;
821
+
815
822
  const style = fields[key] as RawStyleObject | undefined;
816
823
 
817
824
  if (!style || !isBlankColorValue(style.color)) continue;
@@ -25,7 +25,10 @@ import {
25
25
  import { applyTextContrast } from '@brand-page/utils/container-text-color.util';
26
26
  import { authorContentRteFields } from '@brand-page-maker/utils/rte-authoring.util';
27
27
  import * as contentFactories from './content-settings';
28
- import { isTiptapDocument } from '@brand-page-maker/utils';
28
+ import {
29
+ isTiptapDocument,
30
+ mapBrandPageContentToContentSettingsItem,
31
+ } from '@brand-page-maker/utils';
29
32
  import { setLocaleAsync } from '@src/composables/useTranslate';
30
33
  import {
31
34
  BRAND_PAGE_TYPES,
@@ -215,6 +218,51 @@ describe('createInitialBannerSectionContent — RTE source detail', () => {
215
218
  });
216
219
  });
217
220
 
221
+ describe('createInitialMailingListContent — default title', () => {
222
+ beforeAll(async () => {
223
+ await setLocaleAsync('en-US');
224
+ });
225
+
226
+ const blocksOf = (doc: unknown) =>
227
+ (
228
+ doc as {
229
+ content?: {
230
+ attrs?: { textAlign?: string };
231
+ content?: { text?: string }[];
232
+ }[];
233
+ }
234
+ ).content ?? [];
235
+
236
+ it('is a centred doc, matching its title style', () => {
237
+ const content = createInitialMailingListContent(opts);
238
+ const blocks = blocksOf(content.title);
239
+
240
+ expect(blocks[0].content?.[0]?.text).toBe('Join mailing list');
241
+
242
+ for (const block of blocks) {
243
+ expect(block.attrs?.textAlign).toBe('center');
244
+ }
245
+
246
+ expect(content.titleStyle.textAlign).toBe('center');
247
+ });
248
+
249
+ // The editor loads a block with no title through this factory alone, without the add-content
250
+ // step that stamps alignment from the style, so the doc has to carry it.
251
+ it('is centred on an existing block with no title when the editor loads it', () => {
252
+ const item = mapBrandPageContentToContentSettingsItem(
253
+ { id: 'ml-1', type: 'mailing-list', buttonText: 'SUBSCRIBE' } as never,
254
+ opts,
255
+ );
256
+ const blocks = blocksOf(item.settings.content.title);
257
+
258
+ expect(blocks[0].content?.[0]?.text).toBe('Join mailing list');
259
+
260
+ for (const block of blocks) {
261
+ expect(block.attrs?.textAlign).toBe('center');
262
+ }
263
+ });
264
+ });
265
+
218
266
  // Every text a factory creates is linked to one of the ten roles at birth, so nothing new needs the
219
267
  // reconnect, and saves no typography of its own, so every role edit reaches it. The two button
220
268
  // factories are curried by their content type, and capitalise their translated title, so they need
@@ -306,7 +306,9 @@ export const createInitialMailingListContent = (
306
306
  type: 'mailing-list',
307
307
  topPadding: 0,
308
308
  bottomPadding: 0,
309
- title: rteDoc(contentSettingsTr(`mailingListTitle`)),
309
+ // Centred in the doc itself: the editor fills a loaded block's missing title from this factory
310
+ // alone, without the add-content step that stamps alignment from `titleStyle`.
311
+ title: rteDoc(contentSettingsTr(`mailingListTitle`), 'center'),
310
312
  buttonText: contentSettingsTr(`subscribePlaceholder`),
311
313
  acceptedFields: 'emailOnly',
312
314
  titleStyle: {