@justeattakeaway/pie-cookie-banner 1.9.0 → 1.10.0

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/dist/react.d.ts CHANGED
@@ -59,6 +59,23 @@ export declare interface CookieBannerProps {
59
59
  * The URL of the cookie statement page the banner should link to.
60
60
  */
61
61
  cookieStatementLink: string;
62
+ /**
63
+ * An optional override for the personalised preference label rendered in the
64
+ * "Manage preferences" modal. When provided, this string replaces the locale-defined
65
+ * label for the personalised preference. Consumers can include plain text.
66
+ * When omitted or set to an empty string, the built-in locale string is used.
67
+ */
68
+ personalizedLabel?: string;
69
+ /**
70
+ * An optional override for the personalised preference description rendered in the
71
+ * "Manage preferences" modal. When provided, this string replaces the locale-defined
72
+ * description for the personalised preference. Consumers can include plain text,
73
+ * HTML anchor tags (e.g. `<a href="...">Privacy Policy</a>`), or `<pie-link>` tags
74
+ * to embed a privacy policy link. The HTML is sanitised, so only the allowed link
75
+ * attributes are preserved and any others are stripped or normalised. When omitted or
76
+ * set to an empty string, the built-in locale string is used.
77
+ */
78
+ personalizedDescription?: string;
62
79
  /**
63
80
  * The URL for the cookie technology link.
64
81
  */
@@ -153,6 +170,8 @@ declare class PieCookieBanner_2 extends PieElement implements CookieBannerProps
153
170
  hasPrimaryActionsOnly: boolean;
154
171
  defaultPreferences: Partial<Record<PreferenceIds, boolean>>;
155
172
  cookieStatementLink: string;
173
+ personalizedLabel: string;
174
+ personalizedDescription: string;
156
175
  cookieTechnologiesLink: string;
157
176
  country: string;
158
177
  language: string;
@@ -177,6 +196,20 @@ declare class PieCookieBanner_2 extends PieElement implements CookieBannerProps
177
196
  private _customTagEnhancers;
178
197
  private _localiseText;
179
198
  private _localiseRichText;
199
+ /**
200
+ * Renders a preference label.
201
+ * For the personalised preference, uses the consumer-supplied `personalizedLabel`
202
+ * prop when provided as plain text, and falls back to the built-in locale string otherwise.
203
+ */
204
+ private _renderPreferenceLabel;
205
+ /**
206
+ * Renders a preference description.
207
+ * For the personalised preference, uses the consumer-supplied `personalizedDescription`
208
+ * prop when provided (allowing consumers to embed their own privacy policy link using
209
+ * plain HTML `<a>` or `<pie-link>` tags), and falls back to the built-in locale string otherwise.
210
+ * All other preferences use the plain locale text with HTML sanitisation.
211
+ */
212
+ private _renderPreferenceDescription;
180
213
  /**
181
214
  * Handles closing the modal and re-displaying the cookie banner
182
215
  * and making the cookie banner visible
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@justeattakeaway/pie-cookie-banner",
3
3
  "description": "PIE Design System Cookie Banner built using Web Components",
4
- "version": "1.9.0",
4
+ "version": "1.10.0",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/justeattakeaway/pie",
@@ -51,17 +51,17 @@
51
51
  "devDependencies": {
52
52
  "@justeattakeaway/pie-components-config": "0.21.3",
53
53
  "@justeattakeaway/pie-css": "1.2.0",
54
- "@justeattakeaway/pie-monorepo-utils": "0.9.5",
54
+ "@justeattakeaway/pie-monorepo-utils": "0.9.6",
55
55
  "@justeattakeaway/pie-wrapper-react": "0.14.5"
56
56
  },
57
57
  "dependencies": {
58
- "@justeattakeaway/pie-button": "1.14.4",
59
- "@justeattakeaway/pie-divider": "1.5.25",
60
- "@justeattakeaway/pie-icon-button": "2.7.19",
61
- "@justeattakeaway/pie-link": "1.3.35",
62
- "@justeattakeaway/pie-modal": "1.26.11",
63
- "@justeattakeaway/pie-switch": "2.4.2",
64
- "@justeattakeaway/pie-webc-core": "15.0.0",
58
+ "@justeattakeaway/pie-button": "1.14.5",
59
+ "@justeattakeaway/pie-divider": "1.5.26",
60
+ "@justeattakeaway/pie-icon-button": "2.7.20",
61
+ "@justeattakeaway/pie-link": "1.3.36",
62
+ "@justeattakeaway/pie-modal": "1.26.12",
63
+ "@justeattakeaway/pie-switch": "2.5.1",
64
+ "@justeattakeaway/pie-webc-core": "15.0.1",
65
65
  "dompurify": "3.4.8"
66
66
  },
67
67
  "customElements": "custom-elements.json",
package/src/defs.ts CHANGED
@@ -97,6 +97,25 @@ export interface CookieBannerProps {
97
97
  */
98
98
  cookieStatementLink: string;
99
99
 
100
+ /**
101
+ * An optional override for the personalised preference label rendered in the
102
+ * "Manage preferences" modal. When provided, this string replaces the locale-defined
103
+ * label for the personalised preference. Consumers can include plain text.
104
+ * When omitted or set to an empty string, the built-in locale string is used.
105
+ */
106
+ personalizedLabel?: string;
107
+
108
+ /**
109
+ * An optional override for the personalised preference description rendered in the
110
+ * "Manage preferences" modal. When provided, this string replaces the locale-defined
111
+ * description for the personalised preference. Consumers can include plain text,
112
+ * HTML anchor tags (e.g. `<a href="...">Privacy Policy</a>`), or `<pie-link>` tags
113
+ * to embed a privacy policy link. The HTML is sanitised, so only the allowed link
114
+ * attributes are preserved and any others are stripped or normalised. When omitted or
115
+ * set to an empty string, the built-in locale string is used.
116
+ */
117
+ personalizedDescription?: string;
118
+
100
119
  /**
101
120
  * The URL for the cookie technology link.
102
121
  */
@@ -205,6 +224,8 @@ export const defaultProps: DefaultProps = {
205
224
  country: Country.GREAT_BRITAIN,
206
225
  language: Language.ENGLISH,
207
226
  cookieStatementLink: '',
227
+ personalizedLabel: '',
228
+ personalizedDescription: '',
208
229
  cookieTechnologiesLink: '',
209
230
  openLinksInSameTab: false,
210
231
  };
package/src/index.ts CHANGED
@@ -74,6 +74,12 @@ export class PieCookieBanner extends PieElement implements CookieBannerProps {
74
74
  @property({ type: String })
75
75
  public cookieStatementLink = defaultProps.cookieStatementLink;
76
76
 
77
+ @property({ type: String })
78
+ public personalizedLabel = defaultProps.personalizedLabel;
79
+
80
+ @property({ type: String })
81
+ public personalizedDescription = defaultProps.personalizedDescription;
82
+
77
83
  @property({ type: String })
78
84
  public cookieTechnologiesLink = defaultProps.cookieTechnologiesLink;
79
85
 
@@ -162,6 +168,33 @@ export class PieCookieBanner extends PieElement implements CookieBannerProps {
162
168
  return localiseRichText(this._locale, key, this._customTagEnhancers);
163
169
  }
164
170
 
171
+ /**
172
+ * Renders a preference label.
173
+ * For the personalised preference, uses the consumer-supplied `personalizedLabel`
174
+ * prop when provided as plain text, and falls back to the built-in locale string otherwise.
175
+ */
176
+ private _renderPreferenceLabel (id: PreferenceIds) {
177
+ if (id === 'personalized' && this.personalizedLabel) {
178
+ return this.personalizedLabel;
179
+ }
180
+ return this._localiseText(`preferencesManagement.${id}.title`);
181
+ }
182
+
183
+ /**
184
+ * Renders a preference description.
185
+ * For the personalised preference, uses the consumer-supplied `personalizedDescription`
186
+ * prop when provided (allowing consumers to embed their own privacy policy link using
187
+ * plain HTML `<a>` or `<pie-link>` tags), and falls back to the built-in locale string otherwise.
188
+ * All other preferences use the plain locale text with HTML sanitisation.
189
+ */
190
+ private _renderPreferenceDescription (id: PreferenceIds, description: string) {
191
+ if (id === 'personalized' && this.personalizedDescription) {
192
+ return unsafeHTML(sanitiseDescriptionHtml(this.personalizedDescription, this._linkTargetAttribute));
193
+ }
194
+
195
+ return unsafeHTML(sanitiseDescriptionHtml(description, this._linkTargetAttribute));
196
+ }
197
+
165
198
  /**
166
199
  * Handles closing the modal and re-displaying the cookie banner
167
200
  * and making the cookie banner visible
@@ -250,7 +283,7 @@ export class PieCookieBanner extends PieElement implements CookieBannerProps {
250
283
  private renderPreference ({
251
284
  id, checked, disabled, hasDivider, hasDescription,
252
285
  }: Preference) {
253
- const title = this._localiseText(`preferencesManagement.${id}.title`);
286
+ const title = this._renderPreferenceLabel(id);
254
287
  const descriptionLocaleKey = `preferencesManagement.${id}.description`;
255
288
  // Ensure not to display fallback text as description as its expected that some items might not have its own description
256
289
  const description = hasDescription && this._localiseText(descriptionLocaleKey);
@@ -258,13 +291,12 @@ export class PieCookieBanner extends PieElement implements CookieBannerProps {
258
291
 
259
292
  const shouldToggleAll =
260
293
  requiredToggleAllKeys.every((key) => this.defaultPreferences?.[key as PreferenceIds] === true);
261
-
262
294
  return html`
263
295
  <div class="c-cookieBanner-preference">
264
296
  <div>
265
- <h3 class="c-cookieBanner-subheading">${title}</h3>
266
- ${description ? html`<p class="c-cookieBanner-description">${unsafeHTML(sanitiseDescriptionHtml(description, this._linkTargetAttribute))}</p>` : nothing}
267
- </div>
297
+ <h3 class="c-cookieBanner-subheading" data-test-id="${id}-label">${title}</h3>
298
+ ${description ? html`<p class="c-cookieBanner-description" data-test-id="${id}-description">${this._renderPreferenceDescription(id, description)}</p>` : nothing}
299
+ </div>
268
300
  <pie-switch
269
301
  id="${id}"
270
302
  .aria="${{ label: title }}"
@@ -136,11 +136,11 @@ function enhanceCustomTags (richText:string, customTagEnhancers:CustomTagEnhance
136
136
  }
137
137
 
138
138
  /**
139
- * Sanitises an HTML string to allow only safe <a> tags, and normalises anchor
139
+ * Sanitises an HTML string to allow only safe <a> and <pie-link> tags, and normalises link
140
140
  * attributes to respect the component's link-target behaviour.
141
141
  *
142
142
  * Uses DOMPurify for the core sanitisation:
143
- * - Strips all non-<a> elements (keeping their text content).
143
+ * - Strips all non-link elements (keeping their text content).
144
144
  * - Removes unsafe href protocols (javascript:, data:, vbscript:).
145
145
  * - Removes non-allowlisted attributes (only href, rel, target survive).
146
146
  *
@@ -158,10 +158,12 @@ export function sanitiseDescriptionHtml (input: string, linkTarget = '_blank'):
158
158
  return input.replace(/<[^>]*>/g, '');
159
159
  }
160
160
 
161
+ // Define the allowed tags in uppercase to match node.tagName
162
+ const ALLOWED_LINK_TAGS = ['A', 'PIE-LINK'];
161
163
  const normalisedLinkTarget = linkTarget === '_self' ? '_self' : '_blank';
162
164
 
163
165
  const enforceAnchorAttributes = (node: Element) => {
164
- if (node.tagName !== 'A') return;
166
+ if (!ALLOWED_LINK_TAGS.includes(node.tagName)) return;
165
167
 
166
168
  node.setAttribute('target', normalisedLinkTarget);
167
169
 
@@ -182,7 +184,8 @@ export function sanitiseDescriptionHtml (input: string, linkTarget = '_blank'):
182
184
  DOMPurify.addHook('afterSanitizeAttributes', enforceAnchorAttributes);
183
185
 
184
186
  return DOMPurify.sanitize(input, {
185
- ALLOWED_TAGS: ['a'],
187
+ // Convert to lowercase for DOMPurify's tag list
188
+ ALLOWED_TAGS: ALLOWED_LINK_TAGS.map((tag) => tag.toLowerCase()),
186
189
  ALLOWED_ATTR: ['href', 'rel', 'target'],
187
190
  }) as string;
188
191
  } finally {