@designcrowd/library.brand-page 5.19.1-error-html2canvas-2 → 5.19.1-error-html2canvas-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 (25) hide show
  1. package/lib/src/{CreatedOnBrandCrowd-de-de-DmKe7W8L.js → CreatedOnBrandCrowd-de-de-BPP1Wtpt.js} +1 -1
  2. package/lib/src/{CreatedOnBrandCrowd-en-us-D2EeiNep.js → CreatedOnBrandCrowd-en-us-BlfpQiIg.js} +1 -1
  3. package/lib/src/{CreatedOnBrandCrowd-es-es-BqVwNY1D.js → CreatedOnBrandCrowd-es-es-Tldy_pIo.js} +1 -1
  4. package/lib/src/{CreatedOnBrandCrowd-fr-fr-C756a27-.js → CreatedOnBrandCrowd-fr-ca-CHmb3VQE.js} +1 -1
  5. package/lib/src/{CreatedOnBrandCrowd-fr-ca-C756a27-.js → CreatedOnBrandCrowd-fr-fr-CHmb3VQE.js} +1 -1
  6. package/lib/src/{CreatedOnBrandCrowd-pt-pt-FNHAnZUw.js → CreatedOnBrandCrowd-pt-br-XbU3eK3Z.js} +1 -1
  7. package/lib/src/{CreatedOnBrandCrowd-pt-br-FNHAnZUw.js → CreatedOnBrandCrowd-pt-pt-XbU3eK3Z.js} +1 -1
  8. package/lib/src/{CreatedOnDcom-de-de-8AZZFmDt.js → CreatedOnDcom-de-de-BVMFbVbI.js} +1 -1
  9. package/lib/src/{CreatedOnDcom-en-us-DizTP32i.js → CreatedOnDcom-en-us--kaKb1kI.js} +1 -1
  10. package/lib/src/{CreatedOnDcom-es-es-qnp9_n_A.js → CreatedOnDcom-es-es-XXVLpF2I.js} +1 -1
  11. package/lib/src/{CreatedOnDcom-fr-ca-jUs352uK.js → CreatedOnDcom-fr-ca-D-7vtMZ5.js} +1 -1
  12. package/lib/src/{CreatedOnDcom-fr-fr-CTxXtHyk.js → CreatedOnDcom-fr-fr-CM9oQk77.js} +1 -1
  13. package/lib/src/{CreatedOnDcom-pt-br-nQHj8P7d.js → CreatedOnDcom-pt-br-VVgu3BEa.js} +1 -1
  14. package/lib/src/{CreatedOnDcom-pt-pt-DJmVYQuL.js → CreatedOnDcom-pt-pt-CWhA8Vla.js} +1 -1
  15. package/lib/src/index.mjs +1 -1
  16. package/lib/src/{lib-DityivZa.js → lib-yEV1yYI5.js} +8529 -8525
  17. package/lib/src/metadata-builder/builders/footer-builder.js +16 -8
  18. package/lib/src/metadata-builder/builders/section-field-utils.d.ts +7 -0
  19. package/lib/src/metadata-builder/builders/section-field-utils.js +1 -1
  20. package/lib/src/metadata-builder/parsers/ai-toolcall-parser.d.ts +3 -3
  21. package/package.json +1 -1
  22. package/src/metadata-builder/builders/footer-builder.test.ts +63 -1
  23. package/src/metadata-builder/builders/footer-builder.ts +30 -14
  24. package/src/metadata-builder/builders/section-field-utils.ts +1 -1
  25. package/src/metadata-builder/parsers/ai-toolcall-parser.ts +3 -3
@@ -1,7 +1,7 @@
1
1
  import {} from '../../brand-page/models';
2
2
  import { BaseMetadataBuilder, } from '../models';
3
3
  import { FOOTER_CHECKS } from './section-rules/footer.rules';
4
- import { applyDetachedStyleOverride } from './section-field-utils';
4
+ import { applyDetachedStyleOverride, normalizeStyleValue, } from './section-field-utils';
5
5
  const normaliseSocialUrl = (url) => {
6
6
  for (const prefix of ['mailto:', 'tel:']) {
7
7
  if (url.startsWith(prefix))
@@ -89,8 +89,21 @@ const computeSocialLinks = (current, args) => {
89
89
  const applyGlobalFooterChanges = (footer, args, textStyleOptions) => {
90
90
  if (args.copyright_text !== undefined)
91
91
  footer.copyrightText = args.copyright_text;
92
- if (args.copyright_text_font_family !== undefined)
93
- footer.copyrightStyle = applyDetachedStyleOverride(footer.copyrightStyle, { fontFamily: args.copyright_text_font_family }, textStyleOptions);
92
+ // copyright_text_style is the same text-style object sections use (typography
93
+ // + colour). Normalise each value the way section styles are normalised
94
+ // (letterSpacing int→em, lineHeight snap, null→''), then detach from the
95
+ // global preset via the override helper so a single call resolves the preset
96
+ // and clears textStyleType once — see resolveGlobalPresetIntoStyle (BP-5420).
97
+ if (args.copyright_text_style) {
98
+ const updates = {};
99
+ for (const [key, value] of Object.entries(args.copyright_text_style)) {
100
+ const normalized = normalizeStyleValue(key, value);
101
+ if (normalized !== undefined)
102
+ updates[key] = normalized;
103
+ }
104
+ if (Object.keys(updates).length > 0)
105
+ footer.copyrightStyle = applyDetachedStyleOverride(footer.copyrightStyle, updates, textStyleOptions);
106
+ }
94
107
  };
95
108
  const applyViewportFooterChanges = (footer, overrides) => {
96
109
  if (overrides.display_style !== undefined)
@@ -107,11 +120,6 @@ const applyViewportFooterChanges = (footer, overrides) => {
107
120
  color: overrides.icon_color,
108
121
  fill: overrides.icon_color,
109
122
  };
110
- if (overrides.copyright_text_color !== undefined)
111
- footer.copyrightStyle = {
112
- ...footer.copyrightStyle,
113
- color: overrides.copyright_text_color,
114
- };
115
123
  if (overrides.is_logo_visible !== undefined)
116
124
  footer.isLogoVisible = overrides.is_logo_visible;
117
125
  if (overrides.logo_image_height !== undefined)
@@ -21,6 +21,13 @@ interface ButtonLinkArgs {
21
21
  */
22
22
  export declare const applyButtonLink: (content: ButtonLinkContent, args: ButtonLinkArgs) => void;
23
23
  export declare const applyScalarFields: (content: Content, args: SectionToolArguments, sectionType: string) => void;
24
+ /**
25
+ * Convert AI-sent style value to the format expected by the model.
26
+ * - letterSpacing: unitless 0-100 → em string (e.g., 50 → '0.5em')
27
+ * - null → '' (explicitly clear/reset the property)
28
+ * - everything else passes through as-is
29
+ */
30
+ export declare const normalizeStyleValue: (key: string, value: unknown) => unknown;
24
31
  /**
25
32
  * When an executor is about to mark a content-level text style "custom" by
26
33
  * clearing `textStyleType`, the resolved preset values (font, size, spacing,
@@ -58,7 +58,7 @@ export const applyScalarFields = (content, args, sectionType) => {
58
58
  * - null → '' (explicitly clear/reset the property)
59
59
  * - everything else passes through as-is
60
60
  */
61
- const normalizeStyleValue = (key, value) => {
61
+ export const normalizeStyleValue = (key, value) => {
62
62
  if (value === null)
63
63
  return '';
64
64
  if (value === undefined)
@@ -1,6 +1,6 @@
1
1
  import type { AiAssistantToolCall } from '../../clients/ai-assistant-client';
2
2
  import type { FooterDisplayStyle, HeaderDisplayStyle, NavigationDisplayType } from '../../brand-page/constants';
3
- import type { SectionType } from './section-tool-arguments';
3
+ import type { SectionType, TextStyleArguments } from './section-tool-arguments';
4
4
  export declare const AI_ASSISTANT_TOOL_NAMES: {
5
5
  readonly UPDATE_TEXT: "updateText";
6
6
  readonly UPDATE_STYLE: "updateStyle";
@@ -111,7 +111,6 @@ export interface FooterSocialLinkItem {
111
111
  export interface ViewportFooterOverrides {
112
112
  display_style?: FooterDisplayStyle;
113
113
  background_color?: string | null;
114
- copyright_text_color?: string;
115
114
  icon_color?: string;
116
115
  is_logo_visible?: boolean;
117
116
  logo_image_height?: string;
@@ -119,7 +118,8 @@ export interface ViewportFooterOverrides {
119
118
  }
120
119
  export interface UpdateFooterArguments {
121
120
  copyright_text?: string;
122
- copyright_text_font_family?: string;
121
+ /** Copyright line text-style object (typography + colour) — same shape as a section's *_style. Global: applies to both viewports. */
122
+ copyright_text_style?: TextStyleArguments;
123
123
  social_links?: FooterSocialLinkItem[];
124
124
  _replace_social_links?: boolean;
125
125
  _remove_social_link_indices?: number[];
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": "5.19.1-error-html2canvas-2",
4
+ "version": "5.19.1-error-html2canvas-3",
5
5
  "author": "Design.com Eng",
6
6
  "license": "UNLICENSED",
7
7
  "type": "module",
@@ -57,7 +57,7 @@ describe('FooterBuilder — copyright font vs global style', () => {
57
57
  });
58
58
 
59
59
  const { model: out } = await run(
60
- { copyright_text_font_family: 'Anton' },
60
+ { copyright_text_style: { fontFamily: 'Anton' } },
61
61
  model,
62
62
  );
63
63
 
@@ -73,6 +73,68 @@ describe('FooterBuilder — copyright font vs global style', () => {
73
73
  expect(style.color).toBe('#2d0b3f');
74
74
  expect(style.textAlign).toBe('center');
75
75
  });
76
+
77
+ it('applies copyright font size + weight via the style object, detaches, preserves the text', async () => {
78
+ const model = makeModel({
79
+ textStyleType: 'paragraphs',
80
+ textAlign: 'center',
81
+ fontWeight: 'bold',
82
+ });
83
+
84
+ const { model: out } = await run(
85
+ { copyright_text_style: { fontSize: '0.875em', fontWeight: 'normal' } },
86
+ model,
87
+ );
88
+
89
+ const desktop = out.pageFooterDesktop!;
90
+ const style = desktop.copyrightStyle as Record<string, unknown>;
91
+
92
+ expect(style.fontSize).toBe('0.875em');
93
+ expect(style.fontWeight).toBe('normal');
94
+ expect(style.textStyleType).toBeUndefined();
95
+ // preset values resolved in, not lost
96
+ expect(style.fontFamily).toBe('Inter');
97
+ expect(style.textAlign).toBe('center');
98
+ // style-only change must NOT touch the copyright text itself
99
+ expect(desktop.copyrightText).toBeUndefined();
100
+ });
101
+
102
+ it('applies copyright style to both viewports', async () => {
103
+ const model = makeModel({ textStyleType: 'paragraphs' });
104
+
105
+ const { model: out } = await run(
106
+ { copyright_text_style: { fontSize: '0.75em', fontWeight: 'normal' } },
107
+ model,
108
+ );
109
+
110
+ for (const vp of [out.pageFooterDesktop!, out.pageFooterMobile!]) {
111
+ const style = vp.copyrightStyle as Record<string, unknown>;
112
+
113
+ expect(style.fontSize).toBe('0.75em');
114
+ expect(style.fontWeight).toBe('normal');
115
+ expect(style.textStyleType).toBeUndefined();
116
+ }
117
+ });
118
+
119
+ it('applies copyright colour and normalises letterSpacing (int→em) via the style object', async () => {
120
+ const model = makeModel({ textStyleType: 'paragraphs' });
121
+
122
+ const { model: out } = await run(
123
+ { copyright_text_style: { color: '#f5f5f5', letterSpacing: 50 } },
124
+ model,
125
+ );
126
+
127
+ const style = out.pageFooterDesktop!.copyrightStyle as Record<
128
+ string,
129
+ unknown
130
+ >;
131
+
132
+ expect(style.color).toBe('#f5f5f5');
133
+ // letterSpacing int 0–100 is normalised to an em string (50 → '0.5em'),
134
+ // exactly as section *_style values are.
135
+ expect(style.letterSpacing).toBe('0.5em');
136
+ expect(style.textStyleType).toBeUndefined();
137
+ });
76
138
  });
77
139
 
78
140
  type Link = { imageUrl: string; url: string };
@@ -13,9 +13,15 @@ import type {
13
13
  FooterSocialLinkItem,
14
14
  } from '../parsers/ai-toolcall-parser';
15
15
  import type { Logger } from '../logger';
16
- import type { TextStyleOptions } from '../../brand-page/models/styles.model';
16
+ import type {
17
+ TextStyleDeclaration,
18
+ TextStyleOptions,
19
+ } from '../../brand-page/models/styles.model';
17
20
  import { FOOTER_CHECKS } from './section-rules/footer.rules';
18
- import { applyDetachedStyleOverride } from './section-field-utils';
21
+ import {
22
+ applyDetachedStyleOverride,
23
+ normalizeStyleValue,
24
+ } from './section-field-utils';
19
25
 
20
26
  type FooterSocialLink = NonNullable<
21
27
  AbstractPageFooterStyles['socialLinks']
@@ -144,12 +150,28 @@ const applyGlobalFooterChanges = (
144
150
  if (args.copyright_text !== undefined)
145
151
  footer.copyrightText = args.copyright_text;
146
152
 
147
- if (args.copyright_text_font_family !== undefined)
148
- footer.copyrightStyle = applyDetachedStyleOverride(
149
- footer.copyrightStyle,
150
- { fontFamily: args.copyright_text_font_family },
151
- textStyleOptions,
152
- );
153
+ // copyright_text_style is the same text-style object sections use (typography
154
+ // + colour). Normalise each value the way section styles are normalised
155
+ // (letterSpacing int→em, lineHeight snap, null→''), then detach from the
156
+ // global preset via the override helper so a single call resolves the preset
157
+ // and clears textStyleType once — see resolveGlobalPresetIntoStyle (BP-5420).
158
+ if (args.copyright_text_style) {
159
+ const updates: Partial<TextStyleDeclaration> = {};
160
+
161
+ for (const [key, value] of Object.entries(args.copyright_text_style)) {
162
+ const normalized = normalizeStyleValue(key, value);
163
+
164
+ if (normalized !== undefined)
165
+ (updates as Record<string, unknown>)[key] = normalized;
166
+ }
167
+
168
+ if (Object.keys(updates).length > 0)
169
+ footer.copyrightStyle = applyDetachedStyleOverride(
170
+ footer.copyrightStyle,
171
+ updates,
172
+ textStyleOptions,
173
+ );
174
+ }
153
175
  };
154
176
 
155
177
  const applyViewportFooterChanges = (
@@ -173,12 +195,6 @@ const applyViewportFooterChanges = (
173
195
  fill: overrides.icon_color,
174
196
  };
175
197
 
176
- if (overrides.copyright_text_color !== undefined)
177
- footer.copyrightStyle = {
178
- ...footer.copyrightStyle,
179
- color: overrides.copyright_text_color,
180
- };
181
-
182
198
  if (overrides.is_logo_visible !== undefined)
183
199
  footer.isLogoVisible = overrides.is_logo_visible;
184
200
 
@@ -109,7 +109,7 @@ export const applyScalarFields = (
109
109
  * - null → '' (explicitly clear/reset the property)
110
110
  * - everything else passes through as-is
111
111
  */
112
- const normalizeStyleValue = (key: string, value: unknown): unknown => {
112
+ export const normalizeStyleValue = (key: string, value: unknown): unknown => {
113
113
  if (value === null) return '';
114
114
 
115
115
  if (value === undefined) return undefined;
@@ -4,7 +4,7 @@ import type {
4
4
  HeaderDisplayStyle,
5
5
  NavigationDisplayType,
6
6
  } from '../../brand-page/constants';
7
- import type { SectionType } from './section-tool-arguments';
7
+ import type { SectionType, TextStyleArguments } from './section-tool-arguments';
8
8
 
9
9
  // Tool names — must match the function names generated by the AI pipeline.
10
10
  // Text element tools use camelCase names.
@@ -215,7 +215,6 @@ export interface FooterSocialLinkItem {
215
215
  export interface ViewportFooterOverrides {
216
216
  display_style?: FooterDisplayStyle;
217
217
  background_color?: string | null;
218
- copyright_text_color?: string;
219
218
  icon_color?: string;
220
219
  is_logo_visible?: boolean;
221
220
  logo_image_height?: string;
@@ -224,7 +223,8 @@ export interface ViewportFooterOverrides {
224
223
 
225
224
  export interface UpdateFooterArguments {
226
225
  copyright_text?: string;
227
- copyright_text_font_family?: string;
226
+ /** Copyright line text-style object (typography + colour) — same shape as a section's *_style. Global: applies to both viewports. */
227
+ copyright_text_style?: TextStyleArguments;
228
228
  social_links?: FooterSocialLinkItem[];
229
229
  _replace_social_links?: boolean;
230
230
  _remove_social_link_indices?: number[];