@ionic/core 8.8.12-dev.11782342444.186b6e9c → 8.8.12-dev.11782931922.18ba507c

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 (64) hide show
  1. package/components/index.js +1 -1
  2. package/components/ion-action-sheet.js +1 -1
  3. package/components/ion-alert.js +1 -1
  4. package/components/ion-infinite-scroll-content.js +1 -1
  5. package/components/ion-loading.js +1 -1
  6. package/components/ion-refresher-content.js +1 -1
  7. package/components/ion-select-modal.js +1 -1
  8. package/components/ion-select-option.js +1 -1
  9. package/components/ion-select-popover.js +1 -1
  10. package/components/ion-select.js +1 -1
  11. package/components/ion-toast.js +1 -1
  12. package/components/{p-VlRjwhIK.js → p-279dFMvg.js} +1 -1
  13. package/components/{p-CWo79Ftj.js → p-C-Rx1zny.js} +1 -1
  14. package/components/{p-C6x7QJKS.js → p-COdmnpcX.js} +1 -1
  15. package/components/{p-CgGiBa26.js → p-LMGfIvTf.js} +1 -1
  16. package/components/{p-DiCu-HwG.js → p-j9Da6cYO.js} +1 -1
  17. package/components/p-jOtMJMv8.js +4 -0
  18. package/dist/cjs/{index-C147NqgL.js → index-Cueg3U4w.js} +37 -22
  19. package/dist/cjs/index.cjs.js +1 -1
  20. package/dist/cjs/ion-action-sheet.cjs.entry.js +2 -2
  21. package/dist/cjs/ion-alert.cjs.entry.js +2 -2
  22. package/dist/cjs/ion-infinite-scroll_2.cjs.entry.js +1 -1
  23. package/dist/cjs/ion-loading.cjs.entry.js +1 -1
  24. package/dist/cjs/ion-refresher_2.cjs.entry.js +1 -1
  25. package/dist/cjs/ion-select-modal.cjs.entry.js +2 -2
  26. package/dist/cjs/ion-select_3.cjs.entry.js +4 -4
  27. package/dist/cjs/ion-toast.cjs.entry.js +1 -1
  28. package/dist/cjs/{select-option-render-BUmJxlqW.js → select-option-render-DTF50t5r.js} +9 -1
  29. package/dist/collection/components/select-option/select-option.js +3 -3
  30. package/dist/collection/utils/sanitization/index.js +37 -22
  31. package/dist/collection/utils/select-option-render.js +8 -0
  32. package/dist/docs.json +2 -2
  33. package/dist/esm/{index-CtAGDdQq.js → index-DQSkZyOJ.js} +37 -22
  34. package/dist/esm/index.js +1 -1
  35. package/dist/esm/ion-action-sheet.entry.js +2 -2
  36. package/dist/esm/ion-alert.entry.js +2 -2
  37. package/dist/esm/ion-infinite-scroll_2.entry.js +1 -1
  38. package/dist/esm/ion-loading.entry.js +1 -1
  39. package/dist/esm/ion-refresher_2.entry.js +1 -1
  40. package/dist/esm/ion-select-modal.entry.js +2 -2
  41. package/dist/esm/ion-select_3.entry.js +4 -4
  42. package/dist/esm/ion-toast.entry.js +1 -1
  43. package/dist/esm/{select-option-render-CZcvbJ--.js → select-option-render-B8nWZRnd.js} +9 -1
  44. package/dist/html.html-data.json +1 -1
  45. package/dist/ionic/index.esm.js +1 -1
  46. package/dist/ionic/ionic.esm.js +1 -1
  47. package/dist/ionic/{p-5be4fdc3.entry.js → p-038eb991.entry.js} +1 -1
  48. package/dist/ionic/{p-1c5a5a59.entry.js → p-4ace7762.entry.js} +1 -1
  49. package/dist/ionic/{p-c11135d4.entry.js → p-4e9ec5c5.entry.js} +1 -1
  50. package/dist/ionic/{p-74c540f5.entry.js → p-913b218a.entry.js} +1 -1
  51. package/dist/ionic/p-BDtODLZ4.js +4 -0
  52. package/dist/ionic/{p-D3I30-jC.js → p-DCOvXkOm.js} +1 -1
  53. package/dist/ionic/{p-8e00858b.entry.js → p-a9a33367.entry.js} +1 -1
  54. package/dist/ionic/{p-c4156e73.entry.js → p-ad728198.entry.js} +1 -1
  55. package/dist/ionic/{p-0feac19e.entry.js → p-bfc8c629.entry.js} +1 -1
  56. package/dist/ionic/{p-aedf1108.entry.js → p-c08e666a.entry.js} +1 -1
  57. package/dist/types/components/select-option/select-option.d.ts +1 -1
  58. package/dist/types/components.d.ts +2 -2
  59. package/dist/types/utils/sanitization/index.d.ts +9 -5
  60. package/hydrate/index.js +47 -24
  61. package/hydrate/index.mjs +47 -24
  62. package/package.json +1 -1
  63. package/components/p-CMpqV7Co.js +0 -4
  64. package/dist/ionic/p-5x6vmGTf.js +0 -4
@@ -9,13 +9,17 @@ var index = require('./index-Ct7gcRif.js');
9
9
  * Sanitize an untrusted HTML string.
10
10
  *
11
11
  * Parses the string into a detached DOM, removes blocked tags, strips
12
- * attributes outside the `allowedAttributes` list (refer `sanitizeElement`),
13
- * and scrubs script-scheme URLs. Returns the sanitized HTML string.
12
+ * attributes outside the narrow `domStringAllowedAttributes` list (refer
13
+ * `sanitizeElement`), and scrubs script-scheme URLs. Returns the sanitized
14
+ * HTML string.
14
15
  *
15
16
  * Use this when you have an HTML string from an unknown source and need to
16
17
  * render it via `innerHTML`. Use `sanitizeDOMTree` instead when you already
17
18
  * have a DOM tree and want to sanitize it in place without a string round
18
- * trip; both apply the same attribute policy.
19
+ * trip. The two apply the same dangerous-vector scrubbing but different
20
+ * attribute allowlists: this path stays narrow so existing consumers
21
+ * (toast, loading, alert message, etc.) are unaffected, while
22
+ * `sanitizeDOMTree` uses the wider rich-content allowlist.
19
23
  *
20
24
  * @param untrustedString - The HTML string to sanitize. Pass an
21
25
  * `IonicSafeString` to bypass sanitization, or `undefined` to short-circuit.
@@ -71,7 +75,7 @@ const sanitizeDOMString = (untrustedString) => {
71
75
  const childElements = getElementChildren(element);
72
76
  /* eslint-disable-next-line */
73
77
  for (let childIndex = 0; childIndex < childElements.length; childIndex++) {
74
- sanitizeElement(childElements[childIndex]);
78
+ sanitizeElement(childElements[childIndex], domStringAllowedAttributes);
75
79
  }
76
80
  }
77
81
  });
@@ -83,7 +87,7 @@ const sanitizeDOMString = (untrustedString) => {
83
87
  const dfChildren = getElementChildren(documentFragment);
84
88
  /* eslint-disable-next-line */
85
89
  for (let childIndex = 0; childIndex < dfChildren.length; childIndex++) {
86
- sanitizeElement(dfChildren[childIndex]);
90
+ sanitizeElement(dfChildren[childIndex], domStringAllowedAttributes);
87
91
  }
88
92
  // Append document fragment to div
89
93
  const fragmentDiv = document.createElement('div');
@@ -101,8 +105,8 @@ const sanitizeDOMString = (untrustedString) => {
101
105
  * Sanitize an entire trusted DOM tree in place.
102
106
  *
103
107
  * Removes blocked tags (`script`, `iframe`, etc.) from the subtree and
104
- * then sanitizes attributes on every remaining element using the same
105
- * allowlist policy as `sanitizeDOMString` (refer `sanitizeElement`).
108
+ * then sanitizes attributes on every remaining element using the wider
109
+ * `richContentAllowedAttributes` allowlist (refer `sanitizeElement`).
106
110
  * Component presentational attributes (`size`, `color`, `shape`, inline
107
111
  * SVG, `aria-*`, `data-*`) are preserved; `style`, event handlers (`on*`),
108
112
  * form/navigation-hijack attributes, script-scheme URLs, and non-image
@@ -125,7 +129,7 @@ const sanitizeDOMTree = (root) => {
125
129
  matches[i].remove();
126
130
  }
127
131
  });
128
- sanitizeElement(root);
132
+ sanitizeElement(root, richContentAllowedAttributes, richContentAllowedAttributePrefixes);
129
133
  };
130
134
  /**
131
135
  * Clean up current element based on allowed attributes
@@ -133,7 +137,7 @@ const sanitizeDOMTree = (root) => {
133
137
  * clean those up as well
134
138
  */
135
139
  // TODO(FW-2832): type (using Element triggers other type errors as well)
136
- const sanitizeElement = (element) => {
140
+ const sanitizeElement = (element, allowedAttributes, allowedAttributePrefixes = []) => {
137
141
  // IE uses childNodes, so ignore nodes that are not elements
138
142
  if (element.nodeType && element.nodeType !== 1) {
139
143
  return;
@@ -166,7 +170,7 @@ const sanitizeElement = (element) => {
166
170
  * (`formaction`, `action`, `target`), namespaced attributes like
167
171
  * `xlink:href`, and anything else not explicitly known to be safe.
168
172
  */
169
- if (!isAttributeAllowed(lowerName)) {
173
+ if (!isAttributeAllowed(lowerName, allowedAttributes, allowedAttributePrefixes)) {
170
174
  element.removeAttribute(attributeName);
171
175
  continue;
172
176
  }
@@ -209,7 +213,7 @@ const sanitizeElement = (element) => {
209
213
  const childElements = getElementChildren(element);
210
214
  /* eslint-disable-next-line */
211
215
  for (let i = 0; i < childElements.length; i++) {
212
- sanitizeElement(childElements[i]);
216
+ sanitizeElement(childElements[i], allowedAttributes, allowedAttributePrefixes);
213
217
  }
214
218
  };
215
219
  /**
@@ -269,13 +273,24 @@ const reflectPropertiesToAttributes = (root) => {
269
273
  }
270
274
  };
271
275
  /**
272
- * Attribute names that are always safe to keep. Covers global HTML
273
- * attributes, the Ionic component presentational props that cloned rich
274
- * content (e.g. `ion-select-option` markup) relies on, and the inert SVG
275
- * presentation attributes used by inline icons.
276
+ * Attribute allowlist for `sanitizeDOMString`. Intentionally narrow: this
277
+ * path sanitizes developer HTML strings rendered via `innerHTML` by
278
+ * `ion-toast`, `ion-loading`, the `ion-alert` message,
279
+ * `ion-refresher-content`, and `ion-infinite-scroll-content`, so the list
280
+ * is kept to the minimum those have always needed. Broadening it here would
281
+ * change sanitization output for all of those consumers, so the wider
282
+ * rich-content allowlist below is deliberately scoped to `sanitizeDOMTree`
283
+ * instead.
284
+ */
285
+ const domStringAllowedAttributes = ['class', 'id', 'href', 'src', 'name', 'slot'];
286
+ /**
287
+ * Attribute allowlist for `sanitizeDOMTree` (the select rich-content path).
288
+ * Covers global HTML attributes, the Ionic component presentational props
289
+ * that cloned rich content (e.g. `ion-select-option` markup) relies on, and
290
+ * the inert SVG presentation attributes used by inline icons.
276
291
  *
277
292
  * `aria-*` and `data-*` are allowed separately by prefix (refer
278
- * `allowedAttributePrefixes`) since they are inert and not worth
293
+ * `richContentAllowedAttributePrefixes`) since they are inert and not worth
279
294
  * enumerating. URL-bearing names (`href`, `src`) are allowed here, but
280
295
  * their values are still scrubbed for script schemes in `sanitizeElement`.
281
296
  *
@@ -283,7 +298,7 @@ const reflectPropertiesToAttributes = (root) => {
283
298
  * form/navigation-hijack attributes (`formaction`, `action`, `target`),
284
299
  * which are therefore stripped.
285
300
  */
286
- const allowedAttributes = [
301
+ const richContentAllowedAttributes = [
287
302
  // Global / structural
288
303
  'class',
289
304
  'id',
@@ -347,16 +362,16 @@ const allowedAttributes = [
347
362
  'opacity',
348
363
  ];
349
364
  /**
350
- * Attribute-name prefixes that are always safe to keep. `aria-*` and
351
- * `data-*` attributes cannot execute script or load resources, so they are
352
- * allowed wholesale rather than enumerated by name.
365
+ * Attribute-name prefixes that are always safe to keep in the rich-content
366
+ * path. `aria-*` and `data-*` attributes cannot execute script or load
367
+ * resources, so they are allowed wholesale rather than enumerated by name.
353
368
  */
354
- const allowedAttributePrefixes = ['aria-', 'data-'];
369
+ const richContentAllowedAttributePrefixes = ['aria-', 'data-'];
355
370
  /**
356
371
  * Whether an attribute name (already lowercased) is safe to keep, by exact
357
372
  * match or by an allowed prefix.
358
373
  */
359
- const isAttributeAllowed = (lowerName) => {
374
+ const isAttributeAllowed = (lowerName, allowedAttributes, allowedAttributePrefixes) => {
360
375
  if (allowedAttributes.includes(lowerName)) {
361
376
  return true;
362
377
  }
@@ -12,7 +12,7 @@ var index$1 = require('./index-CAvQ7Tka.js');
12
12
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
13
13
  var helpers = require('./helpers-Cv23MFHM.js');
14
14
  var index$2 = require('./index-Ct7gcRif.js');
15
- var index$3 = require('./index-C147NqgL.js');
15
+ var index$3 = require('./index-Cueg3U4w.js');
16
16
  var config = require('./config-DWdFbSNK.js');
17
17
  var theme = require('./theme-CeDs6Hcv.js');
18
18
  var index$4 = require('./index-aC4x3Fk3.js');
@@ -8,7 +8,7 @@ var buttonActive = require('./button-active-0mPOKmV2.js');
8
8
  var helpers = require('./helpers-Cv23MFHM.js');
9
9
  var lockController = require('./lock-controller-aDB9wrEf.js');
10
10
  var overlays = require('./overlays-DSmSrd_4.js');
11
- var selectOptionRender = require('./select-option-render-BUmJxlqW.js');
11
+ var selectOptionRender = require('./select-option-render-DTF50t5r.js');
12
12
  var theme = require('./theme-CeDs6Hcv.js');
13
13
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
14
14
  var animation = require('./animation-BJq0kcy2.js');
@@ -19,7 +19,7 @@ require('./index-CAvQ7Tka.js');
19
19
  require('./gesture-controller-dtqlP_q4.js');
20
20
  require('./hardware-back-button-iUuF_76h.js');
21
21
  require('./framework-delegate-BtICZDHr.js');
22
- require('./index-C147NqgL.js');
22
+ require('./index-Cueg3U4w.js');
23
23
 
24
24
  /**
25
25
  * iOS Action Sheet Enter Animation
@@ -10,8 +10,8 @@ var helpers = require('./helpers-Cv23MFHM.js');
10
10
  var lockController = require('./lock-controller-aDB9wrEf.js');
11
11
  var overlayControlLabel = require('./overlay-control-label-D2sdL2O8.js');
12
12
  var overlays = require('./overlays-DSmSrd_4.js');
13
- var index$1 = require('./index-C147NqgL.js');
14
- var selectOptionRender = require('./select-option-render-BUmJxlqW.js');
13
+ var index$1 = require('./index-Cueg3U4w.js');
14
+ var selectOptionRender = require('./select-option-render-DTF50t5r.js');
15
15
  var theme = require('./theme-CeDs6Hcv.js');
16
16
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
17
17
  var animation = require('./animation-BJq0kcy2.js');
@@ -7,7 +7,7 @@ var index = require('./index-Ct7gcRif.js');
7
7
  var index$1 = require('./index-CIrkNXqJ.js');
8
8
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
9
9
  var config = require('./config-DWdFbSNK.js');
10
- var index$2 = require('./index-C147NqgL.js');
10
+ var index$2 = require('./index-Cueg3U4w.js');
11
11
  require('./helpers-Cv23MFHM.js');
12
12
 
13
13
  const infiniteScrollCss = () => `ion-infinite-scroll{display:none;width:100%}.infinite-scroll-enabled{display:block}`;
@@ -8,7 +8,7 @@ var config = require('./config-DWdFbSNK.js');
8
8
  var helpers = require('./helpers-Cv23MFHM.js');
9
9
  var lockController = require('./lock-controller-aDB9wrEf.js');
10
10
  var overlays = require('./overlays-DSmSrd_4.js');
11
- var index$1 = require('./index-C147NqgL.js');
11
+ var index$1 = require('./index-Cueg3U4w.js');
12
12
  var theme = require('./theme-CeDs6Hcv.js');
13
13
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
14
14
  var animation = require('./animation-BJq0kcy2.js');
@@ -11,7 +11,7 @@ var haptic = require('./haptic-ClPPQ_PS.js');
11
11
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
12
12
  var animation = require('./animation-BJq0kcy2.js');
13
13
  var config = require('./config-DWdFbSNK.js');
14
- var index$3 = require('./index-C147NqgL.js');
14
+ var index$3 = require('./index-Cueg3U4w.js');
15
15
  var index$2 = require('./index-DqmRDbxg.js');
16
16
  var spinnerConfigs = require('./spinner-configs-DxHKnd3-.js');
17
17
  require('./capacitor-DmA66EwP.js');
@@ -7,14 +7,14 @@ var index = require('./index-Ct7gcRif.js');
7
7
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
8
8
  var overlayControlLabel = require('./overlay-control-label-D2sdL2O8.js');
9
9
  var overlays = require('./overlays-DSmSrd_4.js');
10
- var selectOptionRender = require('./select-option-render-BUmJxlqW.js');
10
+ var selectOptionRender = require('./select-option-render-DTF50t5r.js');
11
11
  var theme = require('./theme-CeDs6Hcv.js');
12
12
  require('./index-DkNv4J_i.js');
13
13
  require('./helpers-Cv23MFHM.js');
14
14
  require('./hardware-back-button-iUuF_76h.js');
15
15
  require('./framework-delegate-BtICZDHr.js');
16
16
  require('./gesture-controller-dtqlP_q4.js');
17
- require('./index-C147NqgL.js');
17
+ require('./index-Cueg3U4w.js');
18
18
 
19
19
  const ionicSelectModalMdCss = () => `.action-sheet-button-label-has-rich-content.sc-ion-select-modal-ionic,.alert-radio-label-has-rich-content.sc-ion-select-modal-ionic,.alert-checkbox-label-has-rich-content.sc-ion-select-modal-ionic,.select-option-label-has-rich-content.sc-ion-select-modal-ionic{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;gap:16px}.action-sheet-button-label-has-rich-content.sc-ion-select-modal-ionic,.alert-radio-label-has-rich-content.sc-ion-select-modal-ionic,.alert-checkbox-label-has-rich-content.sc-ion-select-modal-ionic,.select-option-content.sc-ion-select-modal-ionic{-ms-flex:1;flex:1}.action-sheet-button-label-text.sc-ion-select-modal-ionic,.alert-checkbox-label-text.sc-ion-select-modal-ionic,.alert-radio-label-text.sc-ion-select-modal-ionic,.select-option-label-text.sc-ion-select-modal-ionic{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;gap:12px}.select-option-start.sc-ion-select-modal-ionic,.select-option-end.sc-ion-select-modal-ionic{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center;gap:8px}.select-option-description.sc-ion-select-modal-ionic{padding-left:0;padding-right:0;padding-top:5px;padding-bottom:0;display:block;color:var(--ion-color-step-700, var(--ion-text-color-step-300, #4d4d4d));font-size:0.75rem}.select-option-label.sc-ion-select-modal-ionic:not(.select-option-label-has-rich-content){text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.select-option-label-has-rich-content.sc-ion-select-modal-ionic{display:-ms-flexbox;display:flex;-ms-flex-align:center;align-items:center}ion-radio.select-option-has-rich-content.sc-ion-select-modal-ionic::part(label),ion-radio.select-option-has-rich-content.sc-ion-select-modal-ionic [part~="label"],ion-checkbox.select-option-has-rich-content.sc-ion-select-modal-ionic::part(label),ion-checkbox.select-option-has-rich-content.sc-ion-select-modal-ionic [part~="label"],.select-option-content.sc-ion-select-modal-ionic{-ms-flex:1;flex:1;white-space:normal}.select-option-start.sc-ion-select-modal-ionic>ion-avatar.sc-ion-select-modal-ionic,.select-option-end.sc-ion-select-modal-ionic>ion-avatar.sc-ion-select-modal-ionic{width:40px;height:40px}.select-option-start.sc-ion-select-modal-ionic>ion-icon.sc-ion-select-modal-ionic,.select-option-end.sc-ion-select-modal-ionic>ion-icon.sc-ion-select-modal-ionic{width:24px;height:24px}.select-option-start.sc-ion-select-modal-ionic>ion-img.sc-ion-select-modal-ionic,.select-option-start.sc-ion-select-modal-ionic>img.sc-ion-select-modal-ionic,.select-option-start.sc-ion-select-modal-ionic>svg.sc-ion-select-modal-ionic,.select-option-start.sc-ion-select-modal-ionic>ion-thumbnail.sc-ion-select-modal-ionic,.select-option-end.sc-ion-select-modal-ionic>ion-img.sc-ion-select-modal-ionic,.select-option-end.sc-ion-select-modal-ionic>img.sc-ion-select-modal-ionic,.select-option-end.sc-ion-select-modal-ionic>svg.sc-ion-select-modal-ionic,.select-option-end.sc-ion-select-modal-ionic>ion-thumbnail.sc-ion-select-modal-ionic{width:56px;height:56px}.select-option-start.sc-ion-select-modal-ionic>video.sc-ion-select-modal-ionic,.select-option-end.sc-ion-select-modal-ionic>video.sc-ion-select-modal-ionic{width:114px;height:56px}.sc-ion-select-modal-ionic-h{height:100%}ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic::part(container),ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic [part~="container"]{display:none}ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic::part(label),ion-list.sc-ion-select-modal-ionic ion-radio.sc-ion-select-modal-ionic [part~="label"]{margin-left:0;margin-right:0;margin-top:0;margin-bottom:0}ion-item.sc-ion-select-modal-ionic{--inner-border-width:0}.item-radio-checked.sc-ion-select-modal-ionic{--background:rgba(var(--ion-color-primary-rgb, 0, 84, 233), 0.08);--background-focused:var(--ion-color-primary, #0054e9);--background-focused-opacity:0.2;--background-hover:var(--ion-color-primary, #0054e9);--background-hover-opacity:0.12}.item-checkbox-checked.sc-ion-select-modal-ionic{--background-activated:var(--ion-item-color, var(--ion-text-color, #000));--background-focused:var(--ion-item-color, var(--ion-text-color, #000));--background-hover:var(--ion-item-color, var(--ion-text-color, #000));--color:var(--ion-color-primary, #0054e9)}`;
20
20
 
@@ -11,13 +11,13 @@ var validity = require('./validity-BpS37YFM.js');
11
11
  var helpers = require('./helpers-Cv23MFHM.js');
12
12
  var overlays = require('./overlays-DSmSrd_4.js');
13
13
  var dir = require('./dir-Cn0z1rJH.js');
14
- var index$2 = require('./index-C147NqgL.js');
14
+ var index$2 = require('./index-Cueg3U4w.js');
15
15
  var theme = require('./theme-CeDs6Hcv.js');
16
16
  var watchOptions = require('./watch-options-CviOsrTS.js');
17
17
  var index$1 = require('./index-DqmRDbxg.js');
18
18
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
19
19
  var overlayControlLabel = require('./overlay-control-label-D2sdL2O8.js');
20
- var selectOptionRender = require('./select-option-render-BUmJxlqW.js');
20
+ var selectOptionRender = require('./select-option-render-DTF50t5r.js');
21
21
  require('./index-DkNv4J_i.js');
22
22
  require('./hardware-back-button-iUuF_76h.js');
23
23
  require('./framework-delegate-BtICZDHr.js');
@@ -1181,12 +1181,12 @@ const SelectOption = class {
1181
1181
  index.registerInstance(this, hostRef);
1182
1182
  this.inputId = `ion-selopt-${selectOptionIds++}`;
1183
1183
  /**
1184
- * If `true`, the user cannot interact with the select option. This property does not apply when `interface="action-sheet"` as `ion-action-sheet` does not allow for disabled buttons.
1184
+ * If `true`, the user cannot interact with the select option.
1185
1185
  */
1186
1186
  this.disabled = false;
1187
1187
  }
1188
1188
  render() {
1189
- return index.h(index.Host, { key: '4f284411b91b98eda59aadc401bc4d8e423caae9', role: "option", id: this.inputId, class: ionicGlobal.getIonMode(this) });
1189
+ return index.h(index.Host, { key: '8b8bef0f5a55f18048708c34d3ea3ff0ff2f1d47', role: "option", id: this.inputId, class: ionicGlobal.getIonMode(this) });
1190
1190
  }
1191
1191
  get el() { return index.getElement(this); }
1192
1192
  };
@@ -8,7 +8,7 @@ var config = require('./config-DWdFbSNK.js');
8
8
  var helpers = require('./helpers-Cv23MFHM.js');
9
9
  var lockController = require('./lock-controller-aDB9wrEf.js');
10
10
  var overlays = require('./overlays-DSmSrd_4.js');
11
- var index$3 = require('./index-C147NqgL.js');
11
+ var index$3 = require('./index-Cueg3U4w.js');
12
12
  var theme = require('./theme-CeDs6Hcv.js');
13
13
  var ionicGlobal = require('./ionic-global-B-cA6LkY.js');
14
14
  var animation = require('./animation-BJq0kcy2.js');
@@ -4,7 +4,7 @@
4
4
  'use strict';
5
5
 
6
6
  var index = require('./index-Ct7gcRif.js');
7
- var index$1 = require('./index-C147NqgL.js');
7
+ var index$1 = require('./index-Cueg3U4w.js');
8
8
 
9
9
  /**
10
10
  * Converts a DOM node into a Stencil VNode (or text string) so the
@@ -75,6 +75,14 @@ const cloneToVNode = (node, keyPrefix, index$1) => {
75
75
  const renderClonedContent = (id, content, className, useSpan = false) => {
76
76
  const Tag = useSpan ? 'span' : 'div';
77
77
  const keyPrefix = `${className}-${id}`;
78
+ /**
79
+ * Do not remove. This is the only sanitization pass for callers that pass
80
+ * an `HTMLElement` straight to `renderOptionLabel` (e.g. vanilla JS)
81
+ * without going through `getOptionContent`, which sanitizes upstream.
82
+ * `cloneToVNode` does pure structural conversion and no security
83
+ * filtering, so dropping this call would reopen an XSS hole on the
84
+ * direct `HTMLElement` path.
85
+ */
78
86
  index$1.sanitizeDOMTree(content);
79
87
  return (index.h(Tag, { class: className, key: keyPrefix }, Array.from(content.childNodes).map((child, i) => cloneToVNode(child, keyPrefix, i))));
80
88
  };
@@ -14,12 +14,12 @@ export class SelectOption {
14
14
  constructor() {
15
15
  this.inputId = `ion-selopt-${selectOptionIds++}`;
16
16
  /**
17
- * If `true`, the user cannot interact with the select option. This property does not apply when `interface="action-sheet"` as `ion-action-sheet` does not allow for disabled buttons.
17
+ * If `true`, the user cannot interact with the select option.
18
18
  */
19
19
  this.disabled = false;
20
20
  }
21
21
  render() {
22
- return h(Host, { key: '4f284411b91b98eda59aadc401bc4d8e423caae9', role: "option", id: this.inputId, class: getIonMode(this) });
22
+ return h(Host, { key: '8b8bef0f5a55f18048708c34d3ea3ff0ff2f1d47', role: "option", id: this.inputId, class: getIonMode(this) });
23
23
  }
24
24
  static get is() { return "ion-select-option"; }
25
25
  static get encapsulation() { return "shadow"; }
@@ -47,7 +47,7 @@ export class SelectOption {
47
47
  "optional": false,
48
48
  "docs": {
49
49
  "tags": [],
50
- "text": "If `true`, the user cannot interact with the select option. This property does not apply when `interface=\"action-sheet\"` as `ion-action-sheet` does not allow for disabled buttons."
50
+ "text": "If `true`, the user cannot interact with the select option."
51
51
  },
52
52
  "getter": false,
53
53
  "setter": false,
@@ -6,13 +6,17 @@ import { printIonError } from "../logging/index";
6
6
  * Sanitize an untrusted HTML string.
7
7
  *
8
8
  * Parses the string into a detached DOM, removes blocked tags, strips
9
- * attributes outside the `allowedAttributes` list (refer `sanitizeElement`),
10
- * and scrubs script-scheme URLs. Returns the sanitized HTML string.
9
+ * attributes outside the narrow `domStringAllowedAttributes` list (refer
10
+ * `sanitizeElement`), and scrubs script-scheme URLs. Returns the sanitized
11
+ * HTML string.
11
12
  *
12
13
  * Use this when you have an HTML string from an unknown source and need to
13
14
  * render it via `innerHTML`. Use `sanitizeDOMTree` instead when you already
14
15
  * have a DOM tree and want to sanitize it in place without a string round
15
- * trip; both apply the same attribute policy.
16
+ * trip. The two apply the same dangerous-vector scrubbing but different
17
+ * attribute allowlists: this path stays narrow so existing consumers
18
+ * (toast, loading, alert message, etc.) are unaffected, while
19
+ * `sanitizeDOMTree` uses the wider rich-content allowlist.
16
20
  *
17
21
  * @param untrustedString - The HTML string to sanitize. Pass an
18
22
  * `IonicSafeString` to bypass sanitization, or `undefined` to short-circuit.
@@ -68,7 +72,7 @@ export const sanitizeDOMString = (untrustedString) => {
68
72
  const childElements = getElementChildren(element);
69
73
  /* eslint-disable-next-line */
70
74
  for (let childIndex = 0; childIndex < childElements.length; childIndex++) {
71
- sanitizeElement(childElements[childIndex]);
75
+ sanitizeElement(childElements[childIndex], domStringAllowedAttributes);
72
76
  }
73
77
  }
74
78
  });
@@ -80,7 +84,7 @@ export const sanitizeDOMString = (untrustedString) => {
80
84
  const dfChildren = getElementChildren(documentFragment);
81
85
  /* eslint-disable-next-line */
82
86
  for (let childIndex = 0; childIndex < dfChildren.length; childIndex++) {
83
- sanitizeElement(dfChildren[childIndex]);
87
+ sanitizeElement(dfChildren[childIndex], domStringAllowedAttributes);
84
88
  }
85
89
  // Append document fragment to div
86
90
  const fragmentDiv = document.createElement('div');
@@ -98,8 +102,8 @@ export const sanitizeDOMString = (untrustedString) => {
98
102
  * Sanitize an entire trusted DOM tree in place.
99
103
  *
100
104
  * Removes blocked tags (`script`, `iframe`, etc.) from the subtree and
101
- * then sanitizes attributes on every remaining element using the same
102
- * allowlist policy as `sanitizeDOMString` (refer `sanitizeElement`).
105
+ * then sanitizes attributes on every remaining element using the wider
106
+ * `richContentAllowedAttributes` allowlist (refer `sanitizeElement`).
103
107
  * Component presentational attributes (`size`, `color`, `shape`, inline
104
108
  * SVG, `aria-*`, `data-*`) are preserved; `style`, event handlers (`on*`),
105
109
  * form/navigation-hijack attributes, script-scheme URLs, and non-image
@@ -122,7 +126,7 @@ export const sanitizeDOMTree = (root) => {
122
126
  matches[i].remove();
123
127
  }
124
128
  });
125
- sanitizeElement(root);
129
+ sanitizeElement(root, richContentAllowedAttributes, richContentAllowedAttributePrefixes);
126
130
  };
127
131
  /**
128
132
  * Clean up current element based on allowed attributes
@@ -130,7 +134,7 @@ export const sanitizeDOMTree = (root) => {
130
134
  * clean those up as well
131
135
  */
132
136
  // TODO(FW-2832): type (using Element triggers other type errors as well)
133
- const sanitizeElement = (element) => {
137
+ const sanitizeElement = (element, allowedAttributes, allowedAttributePrefixes = []) => {
134
138
  // IE uses childNodes, so ignore nodes that are not elements
135
139
  if (element.nodeType && element.nodeType !== 1) {
136
140
  return;
@@ -163,7 +167,7 @@ const sanitizeElement = (element) => {
163
167
  * (`formaction`, `action`, `target`), namespaced attributes like
164
168
  * `xlink:href`, and anything else not explicitly known to be safe.
165
169
  */
166
- if (!isAttributeAllowed(lowerName)) {
170
+ if (!isAttributeAllowed(lowerName, allowedAttributes, allowedAttributePrefixes)) {
167
171
  element.removeAttribute(attributeName);
168
172
  continue;
169
173
  }
@@ -206,7 +210,7 @@ const sanitizeElement = (element) => {
206
210
  const childElements = getElementChildren(element);
207
211
  /* eslint-disable-next-line */
208
212
  for (let i = 0; i < childElements.length; i++) {
209
- sanitizeElement(childElements[i]);
213
+ sanitizeElement(childElements[i], allowedAttributes, allowedAttributePrefixes);
210
214
  }
211
215
  };
212
216
  /**
@@ -266,13 +270,24 @@ export const reflectPropertiesToAttributes = (root) => {
266
270
  }
267
271
  };
268
272
  /**
269
- * Attribute names that are always safe to keep. Covers global HTML
270
- * attributes, the Ionic component presentational props that cloned rich
271
- * content (e.g. `ion-select-option` markup) relies on, and the inert SVG
272
- * presentation attributes used by inline icons.
273
+ * Attribute allowlist for `sanitizeDOMString`. Intentionally narrow: this
274
+ * path sanitizes developer HTML strings rendered via `innerHTML` by
275
+ * `ion-toast`, `ion-loading`, the `ion-alert` message,
276
+ * `ion-refresher-content`, and `ion-infinite-scroll-content`, so the list
277
+ * is kept to the minimum those have always needed. Broadening it here would
278
+ * change sanitization output for all of those consumers, so the wider
279
+ * rich-content allowlist below is deliberately scoped to `sanitizeDOMTree`
280
+ * instead.
281
+ */
282
+ const domStringAllowedAttributes = ['class', 'id', 'href', 'src', 'name', 'slot'];
283
+ /**
284
+ * Attribute allowlist for `sanitizeDOMTree` (the select rich-content path).
285
+ * Covers global HTML attributes, the Ionic component presentational props
286
+ * that cloned rich content (e.g. `ion-select-option` markup) relies on, and
287
+ * the inert SVG presentation attributes used by inline icons.
273
288
  *
274
289
  * `aria-*` and `data-*` are allowed separately by prefix (refer
275
- * `allowedAttributePrefixes`) since they are inert and not worth
290
+ * `richContentAllowedAttributePrefixes`) since they are inert and not worth
276
291
  * enumerating. URL-bearing names (`href`, `src`) are allowed here, but
277
292
  * their values are still scrubbed for script schemes in `sanitizeElement`.
278
293
  *
@@ -280,7 +295,7 @@ export const reflectPropertiesToAttributes = (root) => {
280
295
  * form/navigation-hijack attributes (`formaction`, `action`, `target`),
281
296
  * which are therefore stripped.
282
297
  */
283
- const allowedAttributes = [
298
+ const richContentAllowedAttributes = [
284
299
  // Global / structural
285
300
  'class',
286
301
  'id',
@@ -344,16 +359,16 @@ const allowedAttributes = [
344
359
  'opacity',
345
360
  ];
346
361
  /**
347
- * Attribute-name prefixes that are always safe to keep. `aria-*` and
348
- * `data-*` attributes cannot execute script or load resources, so they are
349
- * allowed wholesale rather than enumerated by name.
362
+ * Attribute-name prefixes that are always safe to keep in the rich-content
363
+ * path. `aria-*` and `data-*` attributes cannot execute script or load
364
+ * resources, so they are allowed wholesale rather than enumerated by name.
350
365
  */
351
- const allowedAttributePrefixes = ['aria-', 'data-'];
366
+ const richContentAllowedAttributePrefixes = ['aria-', 'data-'];
352
367
  /**
353
368
  * Whether an attribute name (already lowercased) is safe to keep, by exact
354
369
  * match or by an allowed prefix.
355
370
  */
356
- const isAttributeAllowed = (lowerName) => {
371
+ const isAttributeAllowed = (lowerName, allowedAttributes, allowedAttributePrefixes) => {
357
372
  if (allowedAttributes.includes(lowerName)) {
358
373
  return true;
359
374
  }
@@ -72,6 +72,14 @@ export const cloneToVNode = (node, keyPrefix, index) => {
72
72
  const renderClonedContent = (id, content, className, useSpan = false) => {
73
73
  const Tag = useSpan ? 'span' : 'div';
74
74
  const keyPrefix = `${className}-${id}`;
75
+ /**
76
+ * Do not remove. This is the only sanitization pass for callers that pass
77
+ * an `HTMLElement` straight to `renderOptionLabel` (e.g. vanilla JS)
78
+ * without going through `getOptionContent`, which sanitizes upstream.
79
+ * `cloneToVNode` does pure structural conversion and no security
80
+ * filtering, so dropping this call would reopen an XSS hole on the
81
+ * direct `HTMLElement` path.
82
+ */
75
83
  sanitizeDOMTree(content);
76
84
  return (h(Tag, { class: className, key: keyPrefix }, Array.from(content.childNodes).map((child, i) => cloneToVNode(child, keyPrefix, i))));
77
85
  };
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-06-24T23:09:21",
2
+ "timestamp": "2026-07-01T18:53:53",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.43.5",
@@ -31885,7 +31885,7 @@
31885
31885
  "mutable": false,
31886
31886
  "attr": "disabled",
31887
31887
  "reflectToAttr": false,
31888
- "docs": "If `true`, the user cannot interact with the select option. This property does not apply when `interface=\"action-sheet\"` as `ion-action-sheet` does not allow for disabled buttons.",
31888
+ "docs": "If `true`, the user cannot interact with the select option.",
31889
31889
  "docsTags": [
31890
31890
  {
31891
31891
  "name": "default",