@designcrowd/library.brand-page 6.2.3-ast-faq → 6.2.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.
Files changed (125) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-BRisMzFY.js → CreatedOnBrandCrowd-de-de-Cn0M-eZ1.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-CDDsL9GX.js → CreatedOnBrandCrowd-en-us-DRLMSDZr.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-BkZrEo4j.js → CreatedOnBrandCrowd-es-es-BglTu73U.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-sx_ury7R.js → CreatedOnBrandCrowd-fr-ca-Bj6YZ_el.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-sx_ury7R.js → CreatedOnBrandCrowd-fr-fr-Bj6YZ_el.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-DCWiAfkU.js → CreatedOnBrandCrowd-pt-br-DEoOmQ1F.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-DCWiAfkU.js → CreatedOnBrandCrowd-pt-pt-DEoOmQ1F.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-C1S7f22L.js → CreatedOnDcom-de-de-BZ7gTt4Z.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-DgTlWaXE.js → CreatedOnDcom-en-us-CD6Km5sH.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-CxSQJe_V.js → CreatedOnDcom-es-es-CNpZHvEl.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-Bbam2tt6.js → CreatedOnDcom-fr-ca-URS-ydJ1.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-Cb0XDRPL.js → CreatedOnDcom-fr-fr-D2AVeA3H.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-BjdX3-E3.js → CreatedOnDcom-pt-br-C32frnFs.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-BXpbfopB.js → CreatedOnDcom-pt-pt-TDYGjRXS.js} +1 -1
  15. package/lib/src/brand-page/constants/misc.constants.d.ts +0 -8
  16. package/lib/src/brand-page/constants/misc.constants.js +0 -7
  17. package/lib/src/brand-page/constants/styles.constants.d.ts +0 -2
  18. package/lib/src/brand-page/constants/styles.constants.js +0 -2
  19. package/lib/src/brand-page/models/content.model.d.ts +0 -1
  20. package/lib/src/brand-page/models/content.model.js +0 -1
  21. package/lib/src/brand-page/models/index.d.ts +0 -19
  22. package/lib/src/brand-page/utils/content-callback-util.d.ts +1 -2
  23. package/lib/src/brand-page/utils/content-callback-util.js +0 -3
  24. package/lib/src/brand-page/utils/model.util.d.ts +1 -2
  25. package/lib/src/brand-page/utils/model.util.js +0 -3
  26. package/lib/src/brand-page/utils/view-model.util.d.ts +0 -2
  27. package/lib/src/brand-page/utils/view-model.util.js +0 -24
  28. package/lib/src/brand-page/view-models.d.ts +2 -9
  29. package/lib/src/brand-page-maker/components/brand-page-maker/BrandPageMaker.mixin.d.ts +0 -10
  30. package/lib/src/brand-page-maker/components/brandpage-maker-page/BrandPageMakerPage.mixin.d.ts +0 -10
  31. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.d.ts +0 -13
  32. package/lib/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.js +30 -64
  33. package/lib/src/brand-page-maker/constants/config-settings-constant.d.ts +1 -2
  34. package/lib/src/brand-page-maker/constants/config-settings-constant.js +2 -101
  35. package/lib/src/brand-page-maker/models/content-settings-configs.d.ts +1 -22
  36. package/lib/src/brand-page-maker/models/content-settings-configs.js +0 -1
  37. package/lib/src/brand-page-maker/models/content-settings.d.ts +1 -4
  38. package/lib/src/brand-page-maker/models/content-settings.js +1 -45
  39. package/lib/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.js +0 -1
  40. package/lib/src/brand-page-maker/utils/apply-color-strategy.js +17 -47
  41. package/lib/src/brand-page-maker/utils/rich-text-editor.util.d.ts +0 -6
  42. package/lib/src/brand-page-maker/utils/rich-text-editor.util.js +1 -24
  43. package/lib/src/brand-page-maker/validators/field.validator.js +0 -2
  44. package/lib/src/bundled-translations-BYUfWBT3.js +179 -0
  45. package/lib/src/bundles/bundled-translations.json +2 -20
  46. package/lib/src/composables/useTranslate.d.ts +1 -1
  47. package/lib/src/composables/useTranslate.js +1 -1
  48. package/lib/src/css/library.brand-page-brandCrowd.min.css +36 -143
  49. package/lib/src/css/library.brand-page-brandPage.min.css +36 -143
  50. package/lib/src/css/library.brand-page-designCom.min.css +36 -143
  51. package/lib/src/css/library.brand-page-preview.min.css +36 -143
  52. package/lib/src/index.mjs +158 -159
  53. package/lib/src/{lib-DwpSAbLZ.js → lib-Dm9AuOJL.js} +26180 -26906
  54. package/lib/src/metadata-builder/parsers/section-tool-arguments.d.ts +1 -1
  55. package/lib/src/shared/color-strategies/color-strategies.js +0 -4
  56. package/lib/src/shared/color-strategies/rte-field-pairs.d.ts +0 -12
  57. package/lib/src/shared/color-strategies/rte-field-pairs.js +0 -10
  58. package/lib/src/shared/content-settings/components/content-settings/ContentSettings.mixin.d.ts +0 -10
  59. package/lib/src/shared/content-settings/components/content-settings/ReplaceImageSettingsForContent.mixin.d.ts +1 -11
  60. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItem.mixin.d.ts +0 -10
  61. package/lib/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.mixin.d.ts +0 -10
  62. package/lib/src/shared/content-settings/components/focused-content-item-settings/FocusedContentItemSettings.mixin.d.ts +0 -10
  63. package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.d.ts +1 -14
  64. package/lib/src/shared/content-settings/components/items-field/ItemsField.mixin.js +1 -11
  65. package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.d.ts +0 -12
  66. package/lib/src/shared/content-settings/components/textarea-field/TextareaField.mixin.js +0 -5
  67. package/lib/src/shared/content-settings/models.d.ts +0 -6
  68. package/lib/src/shared/content-settings/store/content-settings-store.d.ts +1 -14
  69. package/lib/src/shared/content-settings/store/content-settings-store.js +2 -24
  70. package/lib/src/shared/page-settings/components/page-settings/PageSettings.mixin.d.ts +0 -10
  71. package/lib/src/shared/page-settings/components/page-settings-section-styles/PageSettingsSectionStyles.mixin.d.ts +0 -10
  72. package/package.json +2 -2
  73. package/src/brand-page/components/page/PageComponent.vue +0 -2
  74. package/src/brand-page/constants/misc.constants.ts +0 -12
  75. package/src/brand-page/constants/styles.constants.ts +0 -2
  76. package/src/brand-page/models/content.model.ts +0 -1
  77. package/src/brand-page/models/index.ts +0 -21
  78. package/src/brand-page/utils/content-callback-util.ts +0 -5
  79. package/src/brand-page/utils/model.util.ts +0 -7
  80. package/src/brand-page/utils/view-model.util.test.ts +0 -96
  81. package/src/brand-page/utils/view-model.util.ts +0 -49
  82. package/src/brand-page/view-models.ts +1 -12
  83. package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.vue +49 -37
  84. package/src/brand-page-maker/composables/rich-text-editor/useRichTextEditor.ts +30 -87
  85. package/src/brand-page-maker/constants/config-settings-constant.ts +0 -108
  86. package/src/brand-page-maker/convertors/i18n/converter.json +1 -4
  87. package/src/brand-page-maker/models/content-settings-configs.ts +0 -24
  88. package/src/brand-page-maker/models/content-settings.ts +0 -57
  89. package/src/brand-page-maker/stores/brandpage-maker/brandpage-maker-store.ts +0 -2
  90. package/src/brand-page-maker/utils/__snapshots__/apply-color-strategy.golden.test.ts.snap +389 -3557
  91. package/src/brand-page-maker/utils/apply-color-strategy.test.ts +2 -104
  92. package/src/brand-page-maker/utils/apply-color-strategy.ts +19 -77
  93. package/src/brand-page-maker/utils/rich-text-editor.util.test.ts +0 -110
  94. package/src/brand-page-maker/utils/rich-text-editor.util.ts +0 -66
  95. package/src/brand-page-maker/validators/field.validator.ts +0 -2
  96. package/src/bundles/bundled-translations.json +2 -20
  97. package/src/composables/useTranslate.ts +1 -2
  98. package/src/metadata-builder/builders/item-id-utils.test.ts +0 -24
  99. package/src/metadata-builder/parsers/section-tool-arguments.ts +1 -2
  100. package/src/shared/color-strategies/color-strategies.ts +0 -4
  101. package/src/shared/color-strategies/rte-field-pairs.ts +0 -23
  102. package/src/shared/content-settings/components/content-settings/i18n/content-settings.json +1 -17
  103. package/src/shared/content-settings/components/content-settings-item/ContentSettingsItemField.vue +0 -3
  104. package/src/shared/content-settings/components/items-field/ItemsField.mixin.ts +1 -11
  105. package/src/shared/content-settings/components/items-field/ItemsField.vue +2 -8
  106. package/src/shared/content-settings/components/textarea-field/TextareaField.mixin.ts +0 -6
  107. package/src/shared/content-settings/components/textarea-field/TextareaField.vue +0 -1
  108. package/src/shared/content-settings/models.ts +0 -7
  109. package/src/shared/content-settings/store/content-settings-store.test.ts +0 -70
  110. package/src/shared/content-settings/store/content-settings-store.ts +3 -37
  111. package/src/shared/ecommerce-settings/util/refreshDuplicatedMetadata.test.ts +0 -19
  112. package/src/utils/minify-brand-page-metadata.test.ts +0 -35
  113. package/lib/src/brand-page-maker/convertors/faq-display-style.convertor.d.ts +0 -3
  114. package/lib/src/brand-page-maker/convertors/faq-display-style.convertor.js +0 -47
  115. package/lib/src/bundled-translations-DY9YvuL-.js +0 -179
  116. package/src/brand-page/components/faq-section/FaqSection.test.ts +0 -292
  117. package/src/brand-page/components/faq-section/FaqSection.vue +0 -299
  118. package/src/brand-page/components/section-heading/SectionHeading.vue +0 -52
  119. package/src/brand-page/components/text-wrapper/TextWrapper.test.ts +0 -33
  120. package/src/brand-page-maker/components/rich-text-editor/RichTextEditor.test.ts +0 -165
  121. package/src/brand-page-maker/constants/faq-section-config.test.ts +0 -151
  122. package/src/brand-page-maker/convertors/faq-display-style.convertor.ts +0 -59
  123. package/src/metadata-builder/parsers/section-tool-map.test.ts +0 -12
  124. package/src/shared/content-settings/components/list-items-field/ListItemsField.test.ts +0 -429
  125. package/src/shared/content-settings/components/list-items-field/ListItemsField.vue +0 -262
@@ -13,7 +13,6 @@ import {
13
13
  SECTION_RAISED_LAYER,
14
14
  } from '@shared/color-strategies/color-strategies';
15
15
  import { pageStrategyAnchors } from '@shared/color-strategies/page-anchors';
16
- import { RTE_ITEM_FIELD_PAIRS } from '@shared/color-strategies/rte-field-pairs';
17
16
  import type { ColorStrategy } from '@shared/color-strategies/models';
18
17
 
19
18
  const backgroundConvertor = {
@@ -1653,113 +1652,12 @@ describe('every colour field is bound or deliberately unbound (BP-5886)', () =>
1653
1652
  // `successMessageStyle` is a content-model field (contact-form's success
1654
1653
  // message) with no settings-config entry, so the config-driven applier can
1655
1654
  // never write it. Kept bound as documentation of intent; this pins that the
1656
- // phantom set never grows silently. Item-level styles (each FAQ item's
1657
- // `questionStyle`) are declared by RTE_ITEM_FIELD_PAIRS, not by a config field.
1658
- const itemStyleFields = new Set(
1659
- Object.values(RTE_ITEM_FIELD_PAIRS).flatMap((pairs) =>
1660
- pairs.map((pair) => pair.styleField),
1661
- ),
1662
- );
1655
+ // phantom set never grows silently.
1663
1656
  const phantoms = [
1664
1657
  ...Object.keys(FIELD_SLOT_MAP),
1665
1658
  ...Object.values(SECTION_RAISED_LAYER).flatMap((layer) => layer.content),
1666
- ].filter(
1667
- (name) => !configColourFields.has(name) && !itemStyleFields.has(name),
1668
- );
1659
+ ].filter((name) => !configColourFields.has(name));
1669
1660
 
1670
1661
  expect(new Set(phantoms)).toEqual(new Set(['successMessageStyle']));
1671
1662
  });
1672
1663
  });
1673
-
1674
- describe('buildColorStrategyValues — FAQ section', () => {
1675
- const doc = (text: string) => ({
1676
- type: 'doc',
1677
- content: [
1678
- {
1679
- type: 'paragraph',
1680
- content: [
1681
- {
1682
- type: 'text',
1683
- text,
1684
- marks: [{ type: 'textStyle', attrs: { color: '#123456' } }],
1685
- },
1686
- ],
1687
- },
1688
- ],
1689
- });
1690
-
1691
- const faq = () => ({
1692
- type: 'faq-section',
1693
- displayStyle: 'faq-centered',
1694
- backgroundStyle: {},
1695
- titleStyle: {},
1696
- descriptionStyle: {},
1697
- items: [
1698
- {
1699
- id: 'q1',
1700
- question: doc('Q1'),
1701
- questionStyle: { textStyleType: 'headings', backgroundColor: '#fff' },
1702
- answer: 'Plain answer',
1703
- answerStyle: { textStyleType: 'paragraphs' },
1704
- },
1705
- {
1706
- id: 'q2',
1707
- question: 'Plain question',
1708
- questionStyle: { textStyleType: 'headings' },
1709
- answer: doc('A2'),
1710
- answerStyle: { textStyleType: 'paragraphs' },
1711
- },
1712
- ],
1713
- });
1714
-
1715
- it('repaints every item: its styles and its rich-text documents', () => {
1716
- const config = CONTENT_SETTINGS_CONFIGS()['faq-section'];
1717
- const content = faq();
1718
- const values: Record<string, any> = buildColorStrategyValues(
1719
- config,
1720
- content,
1721
- 'duotone',
1722
- );
1723
- const [q1, q2] = values.items;
1724
- const questionRef = q1.questionStyle.color;
1725
-
1726
- expect(values.backgroundStyle).toBeDefined();
1727
- expect(questionRef).toMatch(/^var\(--palette-\d\)$/);
1728
- expect(q1.answerStyle.color).toMatch(/^var\(--palette-\d\)$/);
1729
- expect(q2.questionStyle.color).toBe(questionRef);
1730
- // Text on the band never takes the band's own role.
1731
- expect(questionRef).not.toBe(values.backgroundStyle?.backgroundColor);
1732
- // The strategy owns the text treatment: background cleared, typography kept.
1733
- expect('backgroundColor' in q1.questionStyle).toBe(false);
1734
- expect(q1.questionStyle.textStyleType).toBe('headings');
1735
- // RTE documents take the colour in their marks; plain text is left as text.
1736
- expect(JSON.stringify(q1.question)).toContain(questionRef);
1737
- expect(JSON.stringify(q1.question)).not.toContain('#123456');
1738
- expect(q1.answer).toBe('Plain answer');
1739
- expect(JSON.stringify(q2.answer)).toContain(q2.answerStyle.color);
1740
- // A new list — never the stored one mutated.
1741
- expect(values.items).not.toBe(content.items);
1742
- expect(content.items[0].questionStyle.backgroundColor).toBe('#fff');
1743
- });
1744
-
1745
- it('asks the live editors to re-seed when an item document was replaced', () => {
1746
- const updateItemValue = vi.fn();
1747
- const markRteResync = vi.fn();
1748
-
1749
- applyColorStrategyToItem(
1750
- { updateItemValue },
1751
- {
1752
- id: 'faq-1',
1753
- config: CONTENT_SETTINGS_CONFIGS()['faq-section'],
1754
- content: faq(),
1755
- strategyId: 'duotone',
1756
- markRteResync,
1757
- },
1758
- );
1759
-
1760
- expect(updateItemValue).toHaveBeenCalledWith(
1761
- expect.objectContaining({ name: 'items' }),
1762
- );
1763
- expect(markRteResync).toHaveBeenCalledTimes(1);
1764
- });
1765
- });
@@ -15,10 +15,7 @@ import type {
15
15
  SectionLayers,
16
16
  StrategyAnchors,
17
17
  } from '@shared/color-strategies/models';
18
- import {
19
- pairedRteTextField,
20
- RTE_ITEM_FIELD_PAIRS,
21
- } from '@shared/color-strategies/rte-field-pairs';
18
+ import { pairedRteTextField } from '@shared/color-strategies/rte-field-pairs';
22
19
 
23
20
  // A section colour field, narrowed to what the macro reads. Config is declared `<any>`,
24
21
  // so this keeps the applier honest without fighting the union.
@@ -119,23 +116,6 @@ const sectionLayers = (
119
116
  };
120
117
  };
121
118
 
122
- /**
123
- * The strategy's text treatment for one text-style field: `color` set, text background
124
- * cleared (matching the highlight strip in `setRteTextColor` — the toolbar writes both).
125
- * The key is deleted rather than set undefined so `'backgroundColor' in style` checks
126
- * downstream stay honest.
127
- */
128
- const withStrategyTextStyle = (
129
- current: Record<string, unknown> | undefined,
130
- ref: string,
131
- ): Record<string, unknown> => {
132
- const nextStyle: Record<string, unknown> = { ...(current ?? {}), color: ref };
133
-
134
- delete nextStyle.backgroundColor;
135
-
136
- return nextStyle;
137
- };
138
-
139
119
  /**
140
120
  * Build the per-field colour writes a strategy stamps onto a section. Pure — reads the
141
121
  * section config + current content and returns a `{ fieldName: value }` partial. Each
@@ -190,7 +170,18 @@ export const buildColorStrategyValues = (
190
170
  | Record<string, unknown>
191
171
  | undefined;
192
172
 
193
- values[name] = withStrategyTextStyle(current, ref);
173
+ const nextStyle: Record<string, unknown> = {
174
+ ...(current ?? {}),
175
+ color: ref,
176
+ };
177
+
178
+ // A strategy owns the text treatment, so it clears the text background colour
179
+ // too — matching the highlight strip in `setRteTextColor` (the toolbar writes
180
+ // both). Delete the key rather than set it undefined so `'backgroundColor' in
181
+ // style` checks downstream stay honest.
182
+ delete nextStyle.backgroundColor;
183
+
184
+ values[name] = nextStyle;
194
185
 
195
186
  // Also stamp the colour into the paired RTE document, if this field drives one.
196
187
  // `setRteTextColor` returns undefined for a plain string or legacy HTML RTE, so
@@ -228,52 +219,9 @@ export const buildColorStrategyValues = (
228
219
  values[name] = field.valueConvertor.convertBack(ref);
229
220
  });
230
221
 
231
- // Item-level RTE fields (each FAQ question) carry their own style and document, so
232
- // the section's field loop above never sees them. Same two halves, per item, written
233
- // back as one new list.
234
- const itemPairs =
235
- typeof contentRecord.type === 'string'
236
- ? (RTE_ITEM_FIELD_PAIRS[contentRecord.type] ?? [])
237
- : [];
238
-
239
- itemPairs.forEach((pair) => {
240
- const ref = strategyRoleRefForField(
241
- strategyId,
242
- pair.styleField,
243
- content,
244
- context,
245
- layers,
246
- anchors,
247
- );
248
- const items = (values[pair.itemsField] ??
249
- contentRecord[pair.itemsField]) as Record<string, unknown>[] | undefined;
250
-
251
- if (!ref || !Array.isArray(items)) {
252
- return;
253
- }
254
-
255
- values[pair.itemsField] = items.map((item) => {
256
- const nextDoc = setRteTextColor(item[pair.textField], ref);
257
-
258
- return {
259
- ...item,
260
- [pair.styleField]: withStrategyTextStyle(
261
- item[pair.styleField] as Record<string, unknown> | undefined,
262
- ref,
263
- ),
264
- ...(nextDoc ? { [pair.textField]: nextDoc } : {}),
265
- };
266
- });
267
- });
268
-
269
222
  return values;
270
223
  };
271
224
 
272
- const isRteDoc = (value: unknown): boolean =>
273
- typeof value === 'object' &&
274
- value !== null &&
275
- (value as { type?: unknown }).type === 'doc';
276
-
277
225
  // Just the slice of the content-settings store the macro writes through. Keeps
278
226
  // this util free of a store import (and of the module cycle that would create).
279
227
  interface ItemValueWriter {
@@ -326,20 +274,14 @@ export const applyColorStrategyToItem = (
326
274
  store.updateItemValue({ id, name, value });
327
275
  });
328
276
 
329
- // A recoloured RTE field is emitted as a whole Tiptap document (at the top level,
330
- // or inside a rewritten item list); the paired style-object writes are plain
331
- // objects. Only the former needs the live editor to re-seed, so signal it just
332
- // when a doc was among the writes.
277
+ // A recoloured RTE field is emitted as a whole Tiptap document; the paired
278
+ // style-object writes are plain objects. Only the former needs the live editor
279
+ // to re-seed, so signal it just when a doc was among the writes.
333
280
  const replacedRteDoc = Object.values(values).some(
334
281
  (value) =>
335
- isRteDoc(value) ||
336
- (Array.isArray(value) &&
337
- value.some(
338
- (item) =>
339
- typeof item === 'object' &&
340
- item !== null &&
341
- Object.values(item).some(isRteDoc),
342
- )),
282
+ typeof value === 'object' &&
283
+ value !== null &&
284
+ (value as { type?: unknown }).type === 'doc',
343
285
  );
344
286
 
345
287
  if (replacedRteDoc) {
@@ -15,9 +15,7 @@ import {
15
15
  resolveToolbarTextColor,
16
16
  resolveInitialToolbarTextColor,
17
17
  transformToRTE,
18
- switchAllContentToRTE,
19
18
  } from './rich-text-editor.util';
20
- import { useExternalRichTextEditor } from '../composables/rich-text-editor/useRichTextEditor';
21
19
  import type { TextStyleDeclaration } from '@brand-page';
22
20
 
23
21
  describe('isStyleChanged', () => {
@@ -587,114 +585,6 @@ describe('transformToRTE — respects existing RTE marks on selection (BP-5886)'
587
585
  });
588
586
  });
589
587
 
590
- describe('item-level RTE fields (FAQ questions and answers)', () => {
591
- const styleStore = () =>
592
- ({
593
- textStyles: {
594
- textStyleOptions: {
595
- headings: { style: { fontFamily: 'Oswald', fontSize: '1.5em' } },
596
- paragraphs: { style: { fontFamily: 'Lato', fontSize: '1em' } },
597
- },
598
- },
599
- }) as any;
600
-
601
- const faqPageStore = (items: any[]) =>
602
- ({
603
- pages: [
604
- {
605
- contents: [
606
- {
607
- id: 'faq-1',
608
- type: 'faq-section',
609
- settings: {
610
- content: {
611
- id: 'faq-1',
612
- type: 'faq-section',
613
- title: '',
614
- titleStyle: {},
615
- description: '',
616
- descriptionStyle: {},
617
- items,
618
- },
619
- },
620
- },
621
- ],
622
- },
623
- ],
624
- }) as any;
625
-
626
- const item = (id: string, questionStyle: any) => ({
627
- id,
628
- question: `Question ${id}`,
629
- questionStyle,
630
- answer: `Answer ${id}`,
631
- answerStyle: { textStyleType: 'paragraphs' },
632
- });
633
-
634
- const itemsOf = (store: any) =>
635
- store.pages[0].contents[0].settings.content.items;
636
-
637
- const fontOf = (value: unknown): string | undefined =>
638
- JSON.stringify(value).match(/"fontFamily":"([^"]+)"/)?.[1];
639
-
640
- it("converts every item's plain text to RTE, each from its own style", () => {
641
- const { externalEditor } = useExternalRichTextEditor();
642
- const store = faqPageStore([
643
- item('1', { textStyleType: 'headings' }),
644
- item('2', { fontFamily: 'Georgia', fontSize: '2em' }), // unlinked
645
- ]);
646
-
647
- switchAllContentToRTE(store, externalEditor, styleStore());
648
-
649
- const [first, second] = itemsOf(store);
650
-
651
- expect(first.question.type).toBe('doc');
652
- expect(fontOf(first.question)).toBe('Oswald');
653
- expect(fontOf(first.answer)).toBe('Lato');
654
- expect(fontOf(second.question)).toBe('Georgia');
655
- externalEditor.destroy();
656
- });
657
-
658
- it('a global text-style change re-stamps only the items linked to it', () => {
659
- const { externalEditor } = useExternalRichTextEditor();
660
- const store = faqPageStore([
661
- item('1', { textStyleType: 'headings' }),
662
- item('2', { textStyleType: 'headings' }),
663
- ]);
664
-
665
- switchAllContentToRTE(store, externalEditor, styleStore());
666
-
667
- const answerBefore = itemsOf(store)[0].answer;
668
-
669
- transformToRTE(store, externalEditor, undefined, undefined, 'headings', {
670
- fontFamily: 'Playfair Display',
671
- } as TextStyleDeclaration);
672
-
673
- const [first, second] = itemsOf(store);
674
-
675
- expect(fontOf(first.question)).toBe('Playfair Display');
676
- expect(fontOf(second.question)).toBe('Playfair Display');
677
- expect(first.answer).toEqual(answerBefore);
678
- externalEditor.destroy();
679
- });
680
-
681
- it('selecting the section leaves already-authored item documents alone', () => {
682
- const { externalEditor } = useExternalRichTextEditor();
683
- const store = faqPageStore([item('1', { textStyleType: 'headings' })]);
684
-
685
- switchAllContentToRTE(store, externalEditor, styleStore());
686
-
687
- const authored = itemsOf(store)[0].question;
688
-
689
- transformToRTE(store, externalEditor, styleStore(), {
690
- id: 'faq-1',
691
- } as any);
692
-
693
- expect(itemsOf(store)[0].question).toEqual(authored);
694
- externalEditor.destroy();
695
- });
696
- });
697
-
698
588
  describe('sanitiseClientSideRTE', () => {
699
589
  it('removes forbidden tags entirely', () => {
700
590
  const input =
@@ -31,7 +31,6 @@ import createDomPurify, { type DOMPurify } from 'dompurify';
31
31
  import Color from 'color';
32
32
  import { isHrefPageId } from '../composables/rich-text-editor/hyperlink';
33
33
  import {
34
- RTE_ITEM_FIELD_PAIRS,
35
34
  RTE_SECTION_FIELD_PAIRS,
36
35
  type RTEFieldPair,
37
36
  } from '@shared/color-strategies/rte-field-pairs';
@@ -548,46 +547,6 @@ const switchRTEField = (
548
547
  }
549
548
  };
550
549
 
551
- // Items are visited as their own "content": each item carries the style that drives its
552
- // text, so the section-field helpers apply unchanged.
553
- const forEachRteItem = (
554
- sectionType: string,
555
- content: unknown,
556
- visit: (item: RTESectionContent, pair: RTEFieldPair) => void,
557
- ): void => {
558
- for (const pair of RTE_ITEM_FIELD_PAIRS[sectionType] ?? []) {
559
- const items = (content as Record<string, unknown>)[pair.itemsField];
560
-
561
- if (Array.isArray(items)) {
562
- items.forEach((item) => visit(item as RTESectionContent, pair));
563
- }
564
- }
565
- };
566
-
567
- /**
568
- * Convert a new list item's plain text to RTE, as adding its section would. Goes through
569
- * `transformRTEField` (element-first colour), so an item that copied a sibling's
570
- * strategy-coloured style bakes that colour rather than the linked global one.
571
- */
572
- export const switchRteItemFieldsToRTE = (
573
- sectionType: string,
574
- item: Record<string, unknown>,
575
- externalEditor: Editor,
576
- uiStyleSettingsStore?: StyleSettingsState,
577
- ): void => {
578
- RTE_ITEM_FIELD_PAIRS[sectionType]?.forEach((pair) =>
579
- transformRTEField(
580
- item as unknown as RTESectionContent,
581
- pair,
582
- externalEditor,
583
- uiStyleSettingsStore,
584
- item as unknown as Content,
585
- undefined,
586
- undefined,
587
- ),
588
- );
589
- };
590
-
591
550
  export const transformToRTE = (
592
551
  uiPageSettingStore: PageSettingsState,
593
552
  externalEditor: Editor,
@@ -616,24 +575,6 @@ export const transformToRTE = (
616
575
  }
617
576
  }
618
577
 
619
- const isNewContent = !!newContent && newContent.id === contentItem.id;
620
-
621
- forEachRteItem(
622
- contentItem.type,
623
- contentItem.settings.content,
624
- (item, pair) =>
625
- transformRTEField(
626
- item,
627
- pair,
628
- externalEditor,
629
- uiStyleSettingsStore,
630
- // An unlinked item of the section being added bakes its own style.
631
- isNewContent ? (item as unknown as Content) : undefined,
632
- type,
633
- newStyle,
634
- ),
635
- );
636
-
637
578
  if (contentItem.type === 'text') {
638
579
  const textContent = contentItem.settings.content as TextContent;
639
580
 
@@ -758,13 +699,6 @@ export const switchAllContentToRTE = (
758
699
  }
759
700
  }
760
701
 
761
- forEachRteItem(
762
- contentItem.type,
763
- contentItem.settings.content,
764
- (item, pair) =>
765
- switchRTEField(item, pair, externalEditor, uiStyleSettingsStore),
766
- );
767
-
768
702
  if (contentItem.type === 'text') {
769
703
  const textContent = contentItem.settings.content as TextContent;
770
704
 
@@ -161,7 +161,6 @@ export const validatorDict: Record<ItemFieldType, Validator> = {
161
161
  'color-replacements': dummyValidator,
162
162
  'testimonial-items': dummyValidator,
163
163
  'text-items': dummyValidator,
164
- 'list-items': dummyValidator,
165
164
  'page-dropdown': dummyValidator,
166
165
  shape: dummyValidator,
167
166
  'logo-selection': dummyValidator,
@@ -205,7 +204,6 @@ export const adminValidatorsDict: Record<ItemFieldType, Validator> = {
205
204
  'color-replacements': dummyValidator,
206
205
  'testimonial-items': dummyValidator,
207
206
  'text-items': dummyValidator,
208
- 'list-items': dummyValidator,
209
207
  'page-dropdown': dummyValidator,
210
208
  shape: dummyValidator,
211
209
  'logo-selection': dummyValidator,
@@ -1262,10 +1262,7 @@
1262
1262
  "medium": "Medium",
1263
1263
  "large": "Large",
1264
1264
  "bigImage": "Big Image",
1265
- "columns": "Columns",
1266
- "faqCenteredAccordion": "Centered accordion",
1267
- "faqSplitAccordion": "Split accordion",
1268
- "faqGrid": "Grid"
1265
+ "columns": "Columns"
1269
1266
  },
1270
1267
  "model": {
1271
1268
  "defaultBackgroundColor": "Default background color",
@@ -1643,22 +1640,7 @@
1643
1640
  "enterTextHerePlaceholder": "Enter text here...",
1644
1641
  "bookNowLabel": "Book Now",
1645
1642
  "shippingLabel": "Enable Shipping Address",
1646
- "shippingPlaceholder": "Require customers to enter a shipping address during checkout.",
1647
- "faqSectionDisplayName": "FAQ",
1648
- "faqItemsDisplayName": "Items",
1649
- "defaultFaqTitle": "Frequently Asked Questions",
1650
- "defaultFaqDescription": "Find answers to common questions about our products, services, or business",
1651
- "defaultFaqQuestion": "What services do you offer?",
1652
- "defaultFaqAnswer": "We provide a range of products and services tailored to meet your needs. Contact us to learn more about how we can help.",
1653
- "faqNewQuestion": "New question?",
1654
- "faqNewAnswer": "Add the answer here.",
1655
- "faqQuestionTitle": "Question",
1656
- "faqAnswerTitle": "Answer",
1657
- "faqQuestionPlaceholder": "Enter a question",
1658
- "faqAnswerPlaceholder": "Enter the answer",
1659
- "listItemsAddItem": "Add item",
1660
- "listItemsMaxReached": "Max {{max}} items reached",
1661
- "listItemsDeleteLabel": "Delete item"
1643
+ "shippingPlaceholder": "Require customers to enter a shipping address during checkout."
1662
1644
  },
1663
1645
  "formFields": {
1664
1646
  "field": "Field",
@@ -121,8 +121,7 @@ const converterTr = (key) => tr(`converter.${key}`);
121
121
  const backgroundSettingsTr = (key) => tr(`backgroundSettings.${key}`);
122
122
  const colorPickerTr = (key) => tr(`colorPicker.${key}`);
123
123
  const colorReplacementFieldTr = (key) => tr(`colorReplacementField.${key}`);
124
- const contentSettingsTr = (key, valuesToInterpolate = {}) =>
125
- tr(`contentSettings.${key}`, valuesToInterpolate);
124
+ const contentSettingsTr = (key) => tr(`contentSettings.${key}`);
126
125
  const formFieldsTr = (key) => tr(`formFields.${key}`);
127
126
  const genericTextInputTr = (key) => tr(`genericTextInput.${key}`);
128
127
  const imageFieldTr = (key) => tr(`imageField.${key}`);
@@ -182,27 +182,3 @@ describe('ensureBrandPageItemIds', () => {
182
182
  ).not.toThrow();
183
183
  });
184
184
  });
185
-
186
- describe('ensureBrandPageItemIds — FAQ items', () => {
187
- it('fills a missing FAQ item id and keeps an existing one', () => {
188
- const model = {
189
- pages: [
190
- {
191
- contents: [
192
- {
193
- type: 'faq-section',
194
- items: [{ id: 'keep', question: 'Q1' }, { question: 'Q2' }],
195
- },
196
- ],
197
- },
198
- ],
199
- } as unknown as BrandPageModel;
200
-
201
- ensureBrandPageItemIds(model);
202
-
203
- const faqItems = (model.pages[0].contents[0] as any).items;
204
-
205
- expect(faqItems[0].id).toBe('keep');
206
- expect(faqItems[1].id).toMatch(UUID_RE);
207
- });
208
- });
@@ -18,8 +18,7 @@ type UnsupportedContentType =
18
18
  | 'map'
19
19
  | 'request-payment'
20
20
  | 'support-me'
21
- | 'shop-section'
22
- | 'faq-section';
21
+ | 'shop-section';
23
22
 
24
23
  export type SectionType = Exclude<ContentType, UnsupportedContentType>;
25
24
 
@@ -272,10 +272,6 @@ export const FIELD_SLOT_MAP: Record<string, ColorSlot> = {
272
272
  nameStyle: 'onSurface',
273
273
  positionStyle: 'onSurface',
274
274
  testimonialStyle: 'onSurface',
275
- // Per-item styles of each FAQ item (RTE_ITEM_FIELD_PAIRS). The rows sit on the
276
- // section band — there is no raised card.
277
- questionStyle: 'onSurface',
278
- answerStyle: 'onSurface',
279
275
  };
280
276
 
281
277
  /**
@@ -21,10 +21,6 @@ export const RTE_SECTION_FIELD_PAIRS: Record<string, RTEFieldPair[]> = {
21
21
  { textField: 'title', styleField: 'titleStyle' },
22
22
  { textField: 'description', styleField: 'descriptionStyle' },
23
23
  ],
24
- 'faq-section': [
25
- { textField: 'title', styleField: 'titleStyle' },
26
- { textField: 'description', styleField: 'descriptionStyle' },
27
- ],
28
24
  'images-section': [
29
25
  { textField: 'title', styleField: 'titleStyle' },
30
26
  { textField: 'description', styleField: 'descriptionStyle' },
@@ -64,25 +60,6 @@ export const RTE_SECTION_FIELD_PAIRS: Record<string, RTEFieldPair[]> = {
64
60
  ],
65
61
  };
66
62
 
67
- /**
68
- * RTE fields that live on each entry of an item list, each driven by a style field
69
- * on the SAME item — every question is its own title-like field. The rewrap walks and
70
- * the colour strategies visit every item for these.
71
- *
72
- * The Text block's `textItems` is not listed: its walk has its own legacy fallbacks
73
- * (single-text mode, section-level `textStyle`) in `transformToRTE`.
74
- */
75
- export interface RTEItemFieldPair extends RTEFieldPair {
76
- itemsField: string;
77
- }
78
-
79
- export const RTE_ITEM_FIELD_PAIRS: Record<string, RTEItemFieldPair[]> = {
80
- 'faq-section': [
81
- { itemsField: 'items', textField: 'question', styleField: 'questionStyle' },
82
- { itemsField: 'items', textField: 'answer', styleField: 'answerStyle' },
83
- ],
84
- };
85
-
86
63
  /**
87
64
  * The `text` section is absent from the map above: on brandSite its RTE lives
88
65
  * per-item in `textItems[]`, which the editor walks separately. On
@@ -206,22 +206,6 @@
206
206
  "enterTextHerePlaceholder": "Enter text here...",
207
207
  "bookNowLabel": "Book Now",
208
208
  "shippingLabel": "Enable Shipping Address",
209
- "shippingPlaceholder": "Require customers to enter a shipping address during checkout.",
210
-
211
- "faqSectionDisplayName": "FAQ",
212
- "faqItemsDisplayName": "Items",
213
- "defaultFaqTitle": "Frequently Asked Questions",
214
- "defaultFaqDescription": "Find answers to common questions about our products, services, or business",
215
- "defaultFaqQuestion": "What services do you offer?",
216
- "defaultFaqAnswer": "We provide a range of products and services tailored to meet your needs. Contact us to learn more about how we can help.",
217
- "faqNewQuestion": "New question?",
218
- "faqNewAnswer": "Add the answer here.",
219
- "faqQuestionTitle": "Question",
220
- "faqAnswerTitle": "Answer",
221
- "faqQuestionPlaceholder": "Enter a question",
222
- "faqAnswerPlaceholder": "Enter the answer",
223
- "listItemsAddItem": "Add item",
224
- "listItemsMaxReached": "Max {{max}} items reached",
225
- "listItemsDeleteLabel": "Delete item"
209
+ "shippingPlaceholder": "Require customers to enter a shipping address during checkout."
226
210
  }
227
211
  }
@@ -60,7 +60,6 @@
60
60
  :styles="content[styleName]"
61
61
  :label="field.label"
62
62
  :fields="field.fields"
63
- :item-fields="field.itemFields"
64
63
  :options-convertor="field.optionsConvertor"
65
64
  :value-convertor="field.valueConvertor"
66
65
  :variant="variant"
@@ -115,7 +114,6 @@ import ShapeField from '../shape-field/ShapeField.vue';
115
114
  import ColorReplacementsField from '../color-replacements-field/ColorReplacementsField.vue';
116
115
  import TestimonialItemsField from '../testimonial-items-field/TestimonialItemsField.vue';
117
116
  import TextItemsField from '../text-items-field/TextItemsField.vue';
118
- import ListItemsField from '../list-items-field/ListItemsField.vue';
119
117
  import SliderField from '../slider-field/SliderField.vue';
120
118
  import PageDropdownField from '../page-dropdown-field/PageDropdownField.vue';
121
119
  import PersonalisationOverrideField from '../personalisation-override-field/PersonalisationOverrideField.vue';
@@ -155,7 +153,6 @@ export default {
155
153
  'color-replacements-field': ColorReplacementsField,
156
154
  'testimonial-items-field': TestimonialItemsField,
157
155
  'text-items-field': TextItemsField,
158
- 'list-items-field': ListItemsField,
159
156
  'product-config-option-field': ProductConfigOptionField,
160
157
  FieldSubHeader,
161
158
  Toggle,