@ukic/web-components 3.29.0 → 3.30.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.
Files changed (65) hide show
  1. package/components/ic-accordion.js +53 -38
  2. package/components/ic-accordion.js.map +1 -1
  3. package/components/ic-menu2.js +274 -35
  4. package/components/ic-menu2.js.map +1 -1
  5. package/components/ic-navigation-button.js +8 -5
  6. package/components/ic-navigation-button.js.map +1 -1
  7. package/components/ic-pagination-bar.js.map +1 -1
  8. package/components/ic-skip-link.js.map +1 -1
  9. package/components/ic-status-tag.js.map +1 -1
  10. package/components/ic-switch.js.map +1 -1
  11. package/dist/cjs/ic-accordion.cjs.entry.js +53 -38
  12. package/dist/cjs/ic-accordion.cjs.entry.js.map +1 -1
  13. package/dist/cjs/ic-button_3.cjs.entry.js.map +1 -1
  14. package/dist/cjs/ic-horizontal-scroll.cjs.entry.js.map +1 -1
  15. package/dist/cjs/ic-input-component-container_3.cjs.entry.js +274 -35
  16. package/dist/cjs/ic-input-component-container_3.cjs.entry.js.map +1 -1
  17. package/dist/cjs/ic-navigation-button.cjs.entry.js +8 -5
  18. package/dist/cjs/ic-navigation-button.cjs.entry.js.map +1 -1
  19. package/dist/cjs/ic-section-container.cjs.entry.js.map +1 -1
  20. package/dist/collection/components/ic-accordion/ic-accordion.js +53 -38
  21. package/dist/collection/components/ic-accordion/ic-accordion.js.map +1 -1
  22. package/dist/collection/components/ic-navigation-button/ic-navigation-button.js +8 -5
  23. package/dist/collection/components/ic-navigation-button/ic-navigation-button.js.map +1 -1
  24. package/dist/components/ic-accordion.js +53 -38
  25. package/dist/components/ic-accordion.js.map +1 -1
  26. package/dist/components/ic-back-to-top.js.map +1 -1
  27. package/dist/components/ic-hero.js.map +1 -1
  28. package/dist/components/ic-menu2.js +274 -35
  29. package/dist/components/ic-menu2.js.map +1 -1
  30. package/dist/components/ic-navigation-button.js +8 -5
  31. package/dist/components/ic-navigation-button.js.map +1 -1
  32. package/dist/components/ic-pagination-bar.js.map +1 -1
  33. package/dist/components/ic-popover-menu.js.map +1 -1
  34. package/dist/components/ic-radio-group.js.map +1 -1
  35. package/dist/components/ic-radio-option.js.map +1 -1
  36. package/dist/components/ic-search-bar.js.map +1 -1
  37. package/dist/components/ic-skip-link.js.map +1 -1
  38. package/dist/components/ic-status-tag.js.map +1 -1
  39. package/dist/components/ic-switch.js.map +1 -1
  40. package/dist/core/core.esm.js +1 -1
  41. package/dist/core/{p-9ced00a7.entry.js → p-41bbdc4c.entry.js} +2 -2
  42. package/dist/core/{p-9ced00a7.entry.js.map → p-41bbdc4c.entry.js.map} +1 -1
  43. package/dist/core/p-8fc5e9f9.entry.js.map +1 -1
  44. package/dist/core/p-98dee727.entry.js.map +1 -1
  45. package/dist/core/{p-fc4b7d2b.entry.js → p-9cf35c23.entry.js} +2 -2
  46. package/dist/core/p-9cf35c23.entry.js.map +1 -0
  47. package/dist/core/p-a8d98164.entry.js.map +1 -1
  48. package/dist/core/p-ccba84b7.entry.js +3 -0
  49. package/dist/core/p-ccba84b7.entry.js.map +1 -0
  50. package/dist/esm/ic-accordion.entry.js +53 -38
  51. package/dist/esm/ic-accordion.entry.js.map +1 -1
  52. package/dist/esm/ic-button_3.entry.js.map +1 -1
  53. package/dist/esm/ic-horizontal-scroll.entry.js.map +1 -1
  54. package/dist/esm/ic-input-component-container_3.entry.js +274 -35
  55. package/dist/esm/ic-input-component-container_3.entry.js.map +1 -1
  56. package/dist/esm/ic-navigation-button.entry.js +8 -5
  57. package/dist/esm/ic-navigation-button.entry.js.map +1 -1
  58. package/dist/esm/ic-section-container.entry.js.map +1 -1
  59. package/dist/types/components/ic-accordion/ic-accordion.d.ts +2 -0
  60. package/hydrate/index.js +334 -77
  61. package/hydrate/index.mjs +334 -77
  62. package/package.json +1 -1
  63. package/dist/core/p-305d9639.entry.js +0 -3
  64. package/dist/core/p-305d9639.entry.js.map +0 -1
  65. package/dist/core/p-fc4b7d2b.entry.js.map +0 -1
@@ -1 +1 @@
1
- {"file":"ic-horizontal-scroll.entry.cjs.js","mappings":"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","names":["elementOverflowsX","getSlotElements","checkResizeObserver","h","Host","IcBrandForegroundEnum"],"sources":["src/components/ic-horizontal-scroll/ic-horizontal-scroll.css?tag=ic-horizontal-scroll&encapsulation=shadow","src/components/ic-horizontal-scroll/ic-horizontal-scroll.tsx"],"sourcesContent":["@import \"../../global/normalize.css\";\n\n:host {\n --border-bottom-color: var(--ic-architectural-300);\n --splitter-color: var(--ic-architectural-100);\n\n display: flex;\n max-width: 100%;\n}\n\n:host(.ic-horizontal-scroll-light) {\n --splitter-color: var(--ic-color-keyline-lighten);\n}\n\n:host(.ic-horizontal-scroll-light) ic-button > svg {\n color: var(--ic-color-text-action-monochrome-dark);\n}\n\n:host(.ic-horizontal-scroll-dark) {\n --splitter-color: var(--ic-color-keyline-darken);\n}\n\n:host(.ic-horizontal-scroll-dark) ic-button > svg {\n color: var(--ic-color-text-action-monochrome-light);\n}\n\n/* Slotted items container element */\n::slotted(*) {\n overflow-x: scroll;\n overflow-y: hidden;\n scroll-behavior: smooth;\n scrollbar-width: none;\n -ms-overflow-style: none;\n margin: calc(var(--ic-space-xs) * -1) !important;\n padding: var(--ic-space-xs) !important;\n}\n\n:host(.ic-horizontal-scroll-visible) ::slotted(*) {\n margin: calc(var(--ic-space-xs) * -1) 0 !important;\n padding: var(--ic-space-xs) !important;\n}\n\n.tabs-container::-webkit-scrollbar {\n display: none;\n}\n\n.scroll-container-left,\n.scroll-container-right {\n display: flex;\n}\n\n.scroll-container-left {\n margin-left: var(--ic-space-xxs);\n}\n\n.scroll-container-right {\n margin-right: var(--ic-space-xxs);\n}\n\n.hidden {\n display: none;\n}\n\n.scroll-arrow {\n margin: var(--ic-space-xxs) 0;\n}\n\n.disabled .ic-tooltip-container {\n display: none !important;\n}\n\n.scroll-splitter-left,\n.scroll-splitter-right {\n display: flex;\n height: var(--ic-space-lg);\n width: var(--ic-space-1px);\n margin-top: var(--ic-space-xs);\n border-radius: var(--ic-space-1px);\n background-color: var(--splitter-color);\n}\n\n.scroll-splitter-left {\n margin-left: calc(var(--ic-space-xxs) - var(--ic-space-1px));\n}\n\n.scroll-splitter-right {\n margin-right: calc(var(--ic-space-xxs) - var(--ic-space-1px));\n}\n\n.disabled .scroll-splitter-left,\n.disabled .scroll-splitter-right {\n background-color: transparent;\n}\n\n:host(.ic-horizontal-scroll-dark) .disabled ic-button > svg,\n:host(.ic-horizontal-scroll-light) .disabled ic-button > svg {\n color: var(--splitter-color) !important;\n}\n\n@media (prefers-reduced-motion: reduce) {\n ::slotted(*) {\n scroll-behavior: auto;\n }\n}\n","import {\n Component,\n Element,\n h,\n Host,\n State,\n Method,\n Prop,\n} from \"@stencil/core\";\n\nimport LeftArrow from \"./assets/left-arrow.svg\";\nimport RightArrow from \"./assets/right-arrow.svg\";\nimport { getSlotElements } from \"../../utils/helpers\";\n\nimport { checkResizeObserver, elementOverflowsX } from \"../../utils/helpers\";\nimport {\n IcBrandForeground,\n IcBrandForegroundEnum,\n IcThemeMode,\n} from \"../../utils/types\";\n\nconst SCROLL_DELAY_MS = 200;\n\n@Component({\n tag: \"ic-horizontal-scroll\",\n styleUrl: \"./ic-horizontal-scroll.css\",\n shadow: true,\n})\nexport class HorizontalScroll {\n private buttonStateSet: boolean = false;\n private isScrolling: number;\n private itemOffsets: number[];\n private items: HTMLElement[];\n private itemsContainerEl: HTMLElement;\n private resizeObserver: ResizeObserver;\n private scrollDelay: number;\n\n @Element() el: HTMLIcHorizontalScrollElement;\n\n @State() firstItemVisible: boolean = true;\n @State() itemOverflow: boolean = false;\n @State() lastItemVisible: boolean = false;\n\n /**\n * The appearance of the horizontal scroll, e.g. dark, light or the default.\n */\n @Prop() appearance?: IcBrandForeground = \"default\";\n\n /** @internal Determines whether black variant of the tabs should be displayed. */\n @Prop() monochrome?: boolean = false;\n\n /**\n * @internal Sets the theme color to the dark or light theme color. \"inherit\" will set the color based on the system settings or ic-theme component.\n */\n @Prop() theme?: IcThemeMode = \"inherit\";\n\n /**\n * @internal The name of the event that triggers focus handler logic.\n */\n @Prop() focusTrigger?: string = \"focus\";\n\n componentWillLoad(): void {\n this.itemsContainerEl = this.el.children[0] as HTMLElement;\n this.itemsContainerEl.addEventListener(\"scroll\", this.scrollHandler);\n this.items = getSlotElements(this.itemsContainerEl) as HTMLElement[];\n this.items.forEach((item) => {\n if (item.addEventListener) {\n item.addEventListener(\n this.focusTrigger as keyof HTMLElementEventMap,\n this.focusHandler\n );\n }\n });\n }\n\n componentDidLoad(): void {\n let runningTotal = 0;\n this.itemOffsets = this.items.map((item) => {\n runningTotal += item.offsetWidth;\n return runningTotal;\n });\n\n checkResizeObserver(this.runResizeObserver);\n\n // Add event listener to scroll containers as mouse events are not fired on disabled elements (ic-button's <button>)\n // 'mouseleave' needed in case the user moves their mouse while holding the arrow buttons\n // - 'mouseup' otherwise not detected and scrolling not stopped\n const scrollArrows = Array.from(\n this.el.shadowRoot?.querySelectorAll(\"div\") || []\n ) as HTMLElement[];\n [\"mouseup\", \"mouseleave\"].forEach((event) => {\n scrollArrows.forEach((arrow) =>\n arrow.addEventListener(event, this.arrowMouseUpHandler)\n );\n });\n }\n\n disconnectedCallback(): void {\n if (this.resizeObserver !== undefined) {\n this.resizeObserver.disconnect();\n }\n\n const scrollArrows = Array.from(\n this.el.shadowRoot?.querySelectorAll(\"div\") || []\n ) as HTMLElement[];\n [\"mouseup\", \"mouseleave\"].forEach((event) => {\n scrollArrows.forEach((arrow) =>\n arrow.removeEventListener(event, this.arrowMouseUpHandler)\n );\n });\n\n this.items?.forEach((item) => {\n if (item.removeEventListener) {\n item.removeEventListener(\n this.focusTrigger as keyof HTMLElementEventMap,\n this.focusHandler\n );\n }\n });\n\n this.itemsContainerEl?.removeEventListener(\"scroll\", this.scrollHandler);\n }\n\n /**\n * @internal if side scrolling enabled, scrolls the specified item into view.\n */\n @Method()\n async scrollItemIntoView(itemPosition: number): Promise<void> {\n this.firstItemVisible = itemPosition <= 0;\n const newScrollPos =\n itemPosition <= 0 ? 0 : this.itemOffsets[itemPosition - 1];\n this.lastItemVisible =\n this.itemsContainerEl.offsetWidth + newScrollPos >=\n this.itemsContainerEl.scrollWidth;\n this.buttonStateSet = true;\n this.itemsContainerEl.scrollLeft = newScrollPos;\n }\n\n private focusHandler = (event: Event) => {\n this.itemFocusHandler(\n Array.from(this.items).indexOf(event.target as HTMLElement)\n );\n };\n\n private itemFocusHandler(itemPosition: number): void {\n if (this.itemOverflow) {\n this.scrollItemIntoView(itemPosition);\n }\n }\n\n private resizeObserverCallback = () => {\n if (this.el.clientWidth >= this.itemsContainerEl.scrollWidth) {\n this.itemOverflow = false;\n } else {\n this.itemOverflow = elementOverflowsX(this.itemsContainerEl);\n }\n\n if (this.itemOverflow) {\n this.lastItemVisible =\n this.itemsContainerEl.offsetWidth + this.itemsContainerEl.scrollLeft >=\n this.itemsContainerEl.scrollWidth;\n }\n };\n\n private runResizeObserver = () => {\n this.resizeObserver = new ResizeObserver(() => {\n this.resizeObserverCallback();\n });\n this.resizeObserver.observe(this.itemsContainerEl);\n };\n\n private scrollLeft = () => {\n this.scrollItemIntoView(this.getCurrentLeftItem() - 1);\n };\n\n private scrollRight = () => {\n this.scrollItemIntoView(this.getCurrentLeftItem() + 1);\n };\n\n private longScrollRight = () => {\n this.scrollRight();\n this.scrollDelay = window.setTimeout(this.longScrollRight, SCROLL_DELAY_MS);\n };\n\n private longScrollLeft = () => {\n this.scrollLeft();\n this.scrollDelay = window.setTimeout(this.longScrollLeft, SCROLL_DELAY_MS);\n };\n\n private leftArrowMouseDownHandler = (e: MouseEvent) => {\n e.preventDefault();\n this.scrollDelay = window.setTimeout(this.longScrollLeft, SCROLL_DELAY_MS);\n };\n\n private rightArrowMouseDownHandler = (e: MouseEvent) => {\n e.preventDefault();\n this.scrollDelay = window.setTimeout(this.longScrollRight, SCROLL_DELAY_MS);\n };\n\n private arrowMouseUpHandler = () => {\n window.clearTimeout(this.scrollDelay);\n };\n\n private getCurrentLeftItem = (): number => {\n const index = this.itemOffsets.findIndex(\n (el) => el > Math.round(this.itemsContainerEl.scrollLeft)\n );\n return index < 0 ? 0 : index;\n };\n\n private scrollHandler = () => {\n window.clearTimeout(this.isScrolling);\n // Set a timeout to run after scrolling ends\n this.isScrolling = window.setTimeout(this.scrollStopped, 50);\n };\n\n private scrollStopped = () => {\n // If scrollItemIntoView has been called, the button states will already be set\n // Can't just handle it here as it causes strange jumping behaviour in positioning\n const scrollLeft = Math.round(this.itemsContainerEl.scrollLeft);\n if (this.buttonStateSet === false) {\n this.firstItemVisible = scrollLeft === 0;\n this.lastItemVisible =\n this.itemsContainerEl.offsetWidth + scrollLeft >=\n this.itemsContainerEl.scrollWidth;\n }\n this.buttonStateSet = false;\n };\n\n render() {\n const { firstItemVisible, lastItemVisible, itemOverflow } = this;\n\n return (\n <Host\n class={{\n [\"ic-horizontal-scroll-visible\"]: itemOverflow,\n [\"ic-horizontal-scroll-dark\"]:\n this.appearance === IcBrandForegroundEnum.Dark,\n [\"ic-horizontal-scroll-light\"]:\n this.appearance === IcBrandForegroundEnum.Light,\n [`ic-theme-${this.theme}`]: this.theme !== \"inherit\",\n }}\n >\n <div\n aria-hidden=\"true\"\n class={{\n [\"scroll-container-left\"]: true,\n [\"hidden\"]: !itemOverflow,\n [\"disabled\"]: firstItemVisible,\n }}\n role=\"tab\"\n >\n <ic-button\n class=\"scroll-arrow\"\n variant=\"icon-tertiary\"\n aria-label=\"Scroll left\"\n theme={\n this.theme === \"light\" || this.theme === \"inherit\"\n ? \"dark\"\n : \"light\"\n }\n monochrome={this.monochrome}\n innerHTML={LeftArrow}\n disabled={firstItemVisible}\n tabindex=\"-1\"\n onClick={this.scrollLeft}\n onMouseDown={this.leftArrowMouseDownHandler}\n ></ic-button>\n <span class=\"scroll-splitter-left\"></span>\n </div>\n <slot></slot>\n <div\n aria-hidden=\"true\"\n class={{\n [\"scroll-container-right\"]: true,\n [\"hidden\"]: !itemOverflow,\n [\"disabled\"]: lastItemVisible,\n }}\n role=\"tab\"\n >\n <span class=\"scroll-splitter-right\"></span>\n <ic-button\n class=\"scroll-arrow\"\n variant=\"icon-tertiary\"\n aria-label=\"Scroll right\"\n theme={\n this.theme === \"light\" || this.theme === \"inherit\"\n ? \"dark\"\n : \"light\"\n }\n monochrome={this.monochrome}\n innerHTML={RightArrow}\n disabled={lastItemVisible}\n tabindex=\"-1\"\n onClick={this.scrollRight}\n onMouseDown={this.rightArrowMouseDownHandler}\n ></ic-button>\n </div>\n </Host>\n );\n }\n}\n"],"version":3}
1
+ {"file":"ic-horizontal-scroll.entry.cjs.js","mappings":"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","names":["elementOverflowsX","getSlotElements","checkResizeObserver","h","Host","IcBrandForegroundEnum"],"sources":["src/components/ic-horizontal-scroll/ic-horizontal-scroll.css?tag=ic-horizontal-scroll&encapsulation=shadow","src/components/ic-horizontal-scroll/ic-horizontal-scroll.tsx"],"sourcesContent":["/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */\n\n/* Document\n ========================================================================== */\n\n/**\n * 1. Correct the line height in all browsers.\n * 2. Prevent adjustments of font size after orientation changes in iOS.\n */\n\nhtml {\n line-height: 1.15; /* 1 */\n -webkit-text-size-adjust: 100%; /* 2 */\n}\n\n/* Sections\n ========================================================================== */\n\n/**\n * Remove the margin in all browsers.\n */\n\nbody {\n margin: 0;\n}\n\n/**\n * Render the `main` element consistently in IE.\n */\n\nmain {\n display: block;\n}\n\n/**\n * Correct the font size and margin on `h1` elements within `section` and\n * `article` contexts in Chrome, Firefox, and Safari.\n */\n\nh1 {\n font-size: 2em;\n margin: 0.67em 0;\n}\n\n/* Grouping content\n ========================================================================== */\n\n/**\n * 1. Add the correct box sizing in Firefox.\n * 2. Show the overflow in Edge and IE.\n */\n\nhr {\n box-sizing: content-box; /* 1 */\n height: 0; /* 1 */\n overflow: visible; /* 2 */\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\npre {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/* Text-level semantics\n ========================================================================== */\n\n/**\n * Remove the gray background on active links in IE 10.\n */\n\na {\n background-color: transparent;\n}\n\n/**\n * 1. Remove the bottom border in Chrome 57-\n * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.\n */\n\nabbr[title] {\n border-bottom: none; /* 1 */\n text-decoration: underline; /* 2 */\n -webkit-text-decoration: underline dotted;\n text-decoration: underline dotted; /* 2 */\n}\n\n/**\n * Add the correct font weight in Chrome, Edge, and Safari.\n */\n\nb,\nstrong {\n font-weight: bolder;\n}\n\n/**\n * 1. Correct the inheritance and scaling of font size in all browsers.\n * 2. Correct the odd `em` font sizing in all browsers.\n */\n\ncode,\nkbd,\nsamp {\n font-family: monospace, monospace; /* 1 */\n font-size: 1em; /* 2 */\n}\n\n/**\n * Add the correct font size in all browsers.\n */\n\nsmall {\n font-size: 80%;\n}\n\n/**\n * Prevent `sub` and `sup` elements from affecting the line height in\n * all browsers.\n */\n\nsub,\nsup {\n font-size: 75%;\n line-height: 0;\n position: relative;\n vertical-align: baseline;\n}\n\nsub {\n bottom: -0.25em;\n}\n\nsup {\n top: -0.5em;\n}\n\n/* Embedded content\n ========================================================================== */\n\n/**\n * Remove the border on images inside links in IE 10.\n */\n\nimg {\n border-style: none;\n}\n\n/* Forms\n ========================================================================== */\n\n/**\n * 1. Change the font styles in all browsers.\n * 2. Remove the margin in Firefox and Safari.\n */\n\nbutton,\ninput,\noptgroup,\nselect,\ntextarea {\n font-family: inherit; /* 1 */\n font-size: 100%; /* 1 */\n line-height: 1.15; /* 1 */\n margin: 0; /* 2 */\n}\n\n/**\n * Show the overflow in IE.\n * 1. Show the overflow in Edge.\n */\n\nbutton,\ninput {\n /* 1 */\n overflow: visible;\n}\n\n/**\n * Remove the inheritance of text transform in Edge, Firefox, and IE.\n * 1. Remove the inheritance of text transform in Firefox.\n */\n\nbutton,\nselect {\n /* 1 */\n text-transform: none;\n}\n\n/**\n * Correct the inability to style clickable types in iOS and Safari.\n */\n\nbutton,\n[type=\"button\"],\n[type=\"reset\"],\n[type=\"submit\"] {\n -webkit-appearance: button;\n}\n\n/**\n * Remove the inner border and padding in Firefox.\n */\n\nbutton::-moz-focus-inner,\n[type=\"button\"]::-moz-focus-inner,\n[type=\"reset\"]::-moz-focus-inner,\n[type=\"submit\"]::-moz-focus-inner {\n border-style: none;\n padding: 0;\n}\n\n/**\n * Restore the focus styles unset by the previous rule.\n */\n\nbutton:-moz-focusring,\n[type=\"button\"]:-moz-focusring,\n[type=\"reset\"]:-moz-focusring,\n[type=\"submit\"]:-moz-focusring {\n outline: 1px dotted ButtonText;\n}\n\n/**\n * Correct the padding in Firefox.\n */\n\nfieldset {\n padding: 0.35em 0.75em 0.625em;\n}\n\n/**\n * 1. Correct the text wrapping in Edge and IE.\n * 2. Correct the color inheritance from `fieldset` elements in IE.\n * 3. Remove the padding so developers are not caught out when they zero out\n * `fieldset` elements in all browsers.\n */\n\nlegend {\n box-sizing: border-box; /* 1 */\n color: inherit; /* 2 */\n display: table; /* 1 */\n max-width: 100%; /* 1 */\n padding: 0; /* 3 */\n white-space: normal; /* 1 */\n}\n\n/**\n * Add the correct vertical alignment in Chrome, Firefox, and Opera.\n */\n\nprogress {\n vertical-align: baseline;\n}\n\n/**\n * Remove the default vertical scrollbar in IE 10+.\n */\n\ntextarea {\n overflow: auto;\n}\n\n/**\n * 1. Add the correct box sizing in IE 10.\n * 2. Remove the padding in IE 10.\n */\n\n[type=\"checkbox\"],\n[type=\"radio\"] {\n box-sizing: border-box; /* 1 */\n padding: 0; /* 2 */\n}\n\n/**\n * Correct the cursor style of increment and decrement buttons in Chrome.\n */\n\n[type=\"number\"]::-webkit-inner-spin-button,\n[type=\"number\"]::-webkit-outer-spin-button {\n height: auto;\n}\n\n/**\n * 1. Correct the odd appearance in Chrome and Safari.\n * 2. Correct the outline style in Safari.\n */\n\n[type=\"search\"] {\n -webkit-appearance: textfield; /* 1 */\n outline-offset: -2px; /* 2 */\n}\n\n/**\n * Remove the inner padding in Chrome and Safari on macOS.\n */\n\n[type=\"search\"]::-webkit-search-decoration {\n -webkit-appearance: none;\n}\n\n/**\n * 1. Correct the inability to style clickable types in iOS and Safari.\n * 2. Change font properties to `inherit` in Safari.\n */\n\n::-webkit-file-upload-button {\n -webkit-appearance: button; /* 1 */\n font: inherit; /* 2 */\n}\n\n/* Interactive\n ========================================================================== */\n\n/*\n * Add the correct display in Edge, IE 10+, and Firefox.\n */\n\ndetails {\n display: block;\n}\n\n/*\n * Add the correct display in all browsers.\n */\n\nsummary {\n display: list-item;\n}\n\n/* Misc\n ========================================================================== */\n\n/**\n * Add the correct display in IE 10+.\n */\n\ntemplate {\n display: none;\n}\n\n/**\n * Add the correct display in IE 10.\n */\n\n[hidden] {\n display: none;\n}\n\nhtml,\nbody,\ndiv,\nspan,\napplet,\nobject,\niframe,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\np,\nblockquote,\npre,\na,\nabbr,\nacronym,\naddress,\nbig,\ncite,\ncode,\ndel,\ndfn,\nem,\nimg,\nins,\nkbd,\nq,\ns,\nsamp,\nsmall,\nstrike,\nstrong,\nsub,\nsup,\ntt,\nvar,\nb,\nu,\ni,\ncenter,\ndl,\ndt,\ndd,\nol,\nul,\nli,\nfieldset,\nform,\nlabel,\nlegend,\ntable,\ncaption,\ntbody,\ntfoot,\nthead,\ntr,\nth,\ntd,\narticle,\naside,\ncanvas,\ndetails,\nembed,\nfigure,\nfigcaption,\nfooter,\nheader,\nhgroup,\nmenu,\nnav,\noutput,\nruby,\nsection,\nsummary,\ntime,\nmark,\naudio,\nvideo {\n margin: 0;\n padding: 0;\n border: 0;\n font-size: 100%;\n font-style: inherit;\n vertical-align: baseline;\n}\n\n\n:host {\n --border-bottom-color: var(--ic-architectural-300);\n --splitter-color: var(--ic-architectural-100);\n\n display: flex;\n max-width: 100%;\n}\n\n:host(.ic-horizontal-scroll-light) {\n --splitter-color: var(--ic-color-keyline-lighten);\n}\n\n:host(.ic-horizontal-scroll-light) ic-button > svg {\n color: var(--ic-color-text-action-monochrome-dark);\n}\n\n:host(.ic-horizontal-scroll-dark) {\n --splitter-color: var(--ic-color-keyline-darken);\n}\n\n:host(.ic-horizontal-scroll-dark) ic-button > svg {\n color: var(--ic-color-text-action-monochrome-light);\n}\n\n/* Slotted items container element */\n::slotted(*) {\n overflow-x: scroll;\n overflow-y: hidden;\n scroll-behavior: smooth;\n scrollbar-width: none;\n -ms-overflow-style: none;\n margin: calc(var(--ic-space-xs) * -1) !important;\n padding: var(--ic-space-xs) !important;\n}\n\n:host(.ic-horizontal-scroll-visible) ::slotted(*) {\n margin: calc(var(--ic-space-xs) * -1) 0 !important;\n padding: var(--ic-space-xs) !important;\n}\n\n.tabs-container::-webkit-scrollbar {\n display: none;\n}\n\n.scroll-container-left,\n.scroll-container-right {\n display: flex;\n}\n\n.scroll-container-left {\n margin-left: var(--ic-space-xxs);\n}\n\n.scroll-container-right {\n margin-right: var(--ic-space-xxs);\n}\n\n.hidden {\n display: none;\n}\n\n.scroll-arrow {\n margin: var(--ic-space-xxs) 0;\n}\n\n.disabled .ic-tooltip-container {\n display: none !important;\n}\n\n.scroll-splitter-left,\n.scroll-splitter-right {\n display: flex;\n height: var(--ic-space-lg);\n width: var(--ic-space-1px);\n margin-top: var(--ic-space-xs);\n border-radius: var(--ic-space-1px);\n background-color: var(--splitter-color);\n}\n\n.scroll-splitter-left {\n margin-left: calc(var(--ic-space-xxs) - var(--ic-space-1px));\n}\n\n.scroll-splitter-right {\n margin-right: calc(var(--ic-space-xxs) - var(--ic-space-1px));\n}\n\n.disabled .scroll-splitter-left,\n.disabled .scroll-splitter-right {\n background-color: transparent;\n}\n\n:host(.ic-horizontal-scroll-dark) .disabled ic-button > svg,\n:host(.ic-horizontal-scroll-light) .disabled ic-button > svg {\n color: var(--splitter-color) !important;\n}\n\n@media (prefers-reduced-motion: reduce) {\n ::slotted(*) {\n scroll-behavior: auto;\n }\n}\n","import {\n Component,\n Element,\n h,\n Host,\n State,\n Method,\n Prop,\n} from \"@stencil/core\";\n\nimport LeftArrow from \"./assets/left-arrow.svg\";\nimport RightArrow from \"./assets/right-arrow.svg\";\nimport { getSlotElements } from \"../../utils/helpers\";\n\nimport { checkResizeObserver, elementOverflowsX } from \"../../utils/helpers\";\nimport {\n IcBrandForeground,\n IcBrandForegroundEnum,\n IcThemeMode,\n} from \"../../utils/types\";\n\nconst SCROLL_DELAY_MS = 200;\n\n@Component({\n tag: \"ic-horizontal-scroll\",\n styleUrl: \"./ic-horizontal-scroll.css\",\n shadow: true,\n})\nexport class HorizontalScroll {\n private buttonStateSet: boolean = false;\n private isScrolling: number;\n private itemOffsets: number[];\n private items: HTMLElement[];\n private itemsContainerEl: HTMLElement;\n private resizeObserver: ResizeObserver;\n private scrollDelay: number;\n\n @Element() el: HTMLIcHorizontalScrollElement;\n\n @State() firstItemVisible: boolean = true;\n @State() itemOverflow: boolean = false;\n @State() lastItemVisible: boolean = false;\n\n /**\n * The appearance of the horizontal scroll, e.g. dark, light or the default.\n */\n @Prop() appearance?: IcBrandForeground = \"default\";\n\n /** @internal Determines whether black variant of the tabs should be displayed. */\n @Prop() monochrome?: boolean = false;\n\n /**\n * @internal Sets the theme color to the dark or light theme color. \"inherit\" will set the color based on the system settings or ic-theme component.\n */\n @Prop() theme?: IcThemeMode = \"inherit\";\n\n /**\n * @internal The name of the event that triggers focus handler logic.\n */\n @Prop() focusTrigger?: string = \"focus\";\n\n componentWillLoad(): void {\n this.itemsContainerEl = this.el.children[0] as HTMLElement;\n this.itemsContainerEl.addEventListener(\"scroll\", this.scrollHandler);\n this.items = getSlotElements(this.itemsContainerEl) as HTMLElement[];\n this.items.forEach((item) => {\n if (item.addEventListener) {\n item.addEventListener(\n this.focusTrigger as keyof HTMLElementEventMap,\n this.focusHandler\n );\n }\n });\n }\n\n componentDidLoad(): void {\n let runningTotal = 0;\n this.itemOffsets = this.items.map((item) => {\n runningTotal += item.offsetWidth;\n return runningTotal;\n });\n\n checkResizeObserver(this.runResizeObserver);\n\n // Add event listener to scroll containers as mouse events are not fired on disabled elements (ic-button's <button>)\n // 'mouseleave' needed in case the user moves their mouse while holding the arrow buttons\n // - 'mouseup' otherwise not detected and scrolling not stopped\n const scrollArrows = Array.from(\n this.el.shadowRoot?.querySelectorAll(\"div\") || []\n ) as HTMLElement[];\n [\"mouseup\", \"mouseleave\"].forEach((event) => {\n scrollArrows.forEach((arrow) =>\n arrow.addEventListener(event, this.arrowMouseUpHandler)\n );\n });\n }\n\n disconnectedCallback(): void {\n if (this.resizeObserver !== undefined) {\n this.resizeObserver.disconnect();\n }\n\n const scrollArrows = Array.from(\n this.el.shadowRoot?.querySelectorAll(\"div\") || []\n ) as HTMLElement[];\n [\"mouseup\", \"mouseleave\"].forEach((event) => {\n scrollArrows.forEach((arrow) =>\n arrow.removeEventListener(event, this.arrowMouseUpHandler)\n );\n });\n\n this.items?.forEach((item) => {\n if (item.removeEventListener) {\n item.removeEventListener(\n this.focusTrigger as keyof HTMLElementEventMap,\n this.focusHandler\n );\n }\n });\n\n this.itemsContainerEl?.removeEventListener(\"scroll\", this.scrollHandler);\n }\n\n /**\n * @internal if side scrolling enabled, scrolls the specified item into view.\n */\n @Method()\n async scrollItemIntoView(itemPosition: number): Promise<void> {\n this.firstItemVisible = itemPosition <= 0;\n const newScrollPos =\n itemPosition <= 0 ? 0 : this.itemOffsets[itemPosition - 1];\n this.lastItemVisible =\n this.itemsContainerEl.offsetWidth + newScrollPos >=\n this.itemsContainerEl.scrollWidth;\n this.buttonStateSet = true;\n this.itemsContainerEl.scrollLeft = newScrollPos;\n }\n\n private focusHandler = (event: Event) => {\n this.itemFocusHandler(\n Array.from(this.items).indexOf(event.target as HTMLElement)\n );\n };\n\n private itemFocusHandler(itemPosition: number): void {\n if (this.itemOverflow) {\n this.scrollItemIntoView(itemPosition);\n }\n }\n\n private resizeObserverCallback = () => {\n if (this.el.clientWidth >= this.itemsContainerEl.scrollWidth) {\n this.itemOverflow = false;\n } else {\n this.itemOverflow = elementOverflowsX(this.itemsContainerEl);\n }\n\n if (this.itemOverflow) {\n this.lastItemVisible =\n this.itemsContainerEl.offsetWidth + this.itemsContainerEl.scrollLeft >=\n this.itemsContainerEl.scrollWidth;\n }\n };\n\n private runResizeObserver = () => {\n this.resizeObserver = new ResizeObserver(() => {\n this.resizeObserverCallback();\n });\n this.resizeObserver.observe(this.itemsContainerEl);\n };\n\n private scrollLeft = () => {\n this.scrollItemIntoView(this.getCurrentLeftItem() - 1);\n };\n\n private scrollRight = () => {\n this.scrollItemIntoView(this.getCurrentLeftItem() + 1);\n };\n\n private longScrollRight = () => {\n this.scrollRight();\n this.scrollDelay = window.setTimeout(this.longScrollRight, SCROLL_DELAY_MS);\n };\n\n private longScrollLeft = () => {\n this.scrollLeft();\n this.scrollDelay = window.setTimeout(this.longScrollLeft, SCROLL_DELAY_MS);\n };\n\n private leftArrowMouseDownHandler = (e: MouseEvent) => {\n e.preventDefault();\n this.scrollDelay = window.setTimeout(this.longScrollLeft, SCROLL_DELAY_MS);\n };\n\n private rightArrowMouseDownHandler = (e: MouseEvent) => {\n e.preventDefault();\n this.scrollDelay = window.setTimeout(this.longScrollRight, SCROLL_DELAY_MS);\n };\n\n private arrowMouseUpHandler = () => {\n window.clearTimeout(this.scrollDelay);\n };\n\n private getCurrentLeftItem = (): number => {\n const index = this.itemOffsets.findIndex(\n (el) => el > Math.round(this.itemsContainerEl.scrollLeft)\n );\n return index < 0 ? 0 : index;\n };\n\n private scrollHandler = () => {\n window.clearTimeout(this.isScrolling);\n // Set a timeout to run after scrolling ends\n this.isScrolling = window.setTimeout(this.scrollStopped, 50);\n };\n\n private scrollStopped = () => {\n // If scrollItemIntoView has been called, the button states will already be set\n // Can't just handle it here as it causes strange jumping behaviour in positioning\n const scrollLeft = Math.round(this.itemsContainerEl.scrollLeft);\n if (this.buttonStateSet === false) {\n this.firstItemVisible = scrollLeft === 0;\n this.lastItemVisible =\n this.itemsContainerEl.offsetWidth + scrollLeft >=\n this.itemsContainerEl.scrollWidth;\n }\n this.buttonStateSet = false;\n };\n\n render() {\n const { firstItemVisible, lastItemVisible, itemOverflow } = this;\n\n return (\n <Host\n class={{\n [\"ic-horizontal-scroll-visible\"]: itemOverflow,\n [\"ic-horizontal-scroll-dark\"]:\n this.appearance === IcBrandForegroundEnum.Dark,\n [\"ic-horizontal-scroll-light\"]:\n this.appearance === IcBrandForegroundEnum.Light,\n [`ic-theme-${this.theme}`]: this.theme !== \"inherit\",\n }}\n >\n <div\n aria-hidden=\"true\"\n class={{\n [\"scroll-container-left\"]: true,\n [\"hidden\"]: !itemOverflow,\n [\"disabled\"]: firstItemVisible,\n }}\n role=\"tab\"\n >\n <ic-button\n class=\"scroll-arrow\"\n variant=\"icon-tertiary\"\n aria-label=\"Scroll left\"\n theme={\n this.theme === \"light\" || this.theme === \"inherit\"\n ? \"dark\"\n : \"light\"\n }\n monochrome={this.monochrome}\n innerHTML={LeftArrow}\n disabled={firstItemVisible}\n tabindex=\"-1\"\n onClick={this.scrollLeft}\n onMouseDown={this.leftArrowMouseDownHandler}\n ></ic-button>\n <span class=\"scroll-splitter-left\"></span>\n </div>\n <slot></slot>\n <div\n aria-hidden=\"true\"\n class={{\n [\"scroll-container-right\"]: true,\n [\"hidden\"]: !itemOverflow,\n [\"disabled\"]: lastItemVisible,\n }}\n role=\"tab\"\n >\n <span class=\"scroll-splitter-right\"></span>\n <ic-button\n class=\"scroll-arrow\"\n variant=\"icon-tertiary\"\n aria-label=\"Scroll right\"\n theme={\n this.theme === \"light\" || this.theme === \"inherit\"\n ? \"dark\"\n : \"light\"\n }\n monochrome={this.monochrome}\n innerHTML={RightArrow}\n disabled={lastItemVisible}\n tabindex=\"-1\"\n onClick={this.scrollRight}\n onMouseDown={this.rightArrowMouseDownHandler}\n ></ic-button>\n </div>\n </Host>\n );\n }\n}\n"],"version":3}
@@ -101,7 +101,7 @@ var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof win
101
101
 
102
102
  var purify = {exports: {}};
103
103
 
104
- /*! @license DOMPurify 3.4.11 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.11/LICENSE */
104
+ /*! @license DOMPurify 3.4.13 | (c) Cure53 and other contributors | Released under the Apache license 2.0 and Mozilla Public License 2.0 | github.com/cure53/DOMPurify/blob/3.4.13/LICENSE */
105
105
 
106
106
  (function (module, exports) {
107
107
  (function (global, factory) {
@@ -418,7 +418,7 @@ var purify = {exports: {}};
418
418
  const text = freeze(['#text']);
419
419
 
420
420
  const html = freeze(['accept', 'action', 'align', 'alt', 'autocapitalize', 'autocomplete', 'autopictureinpicture', 'autoplay', 'background', 'bgcolor', 'border', 'capture', 'cellpadding', 'cellspacing', 'checked', 'cite', 'class', 'clear', 'color', 'cols', 'colspan', 'command', 'commandfor', 'controls', 'controlslist', 'coords', 'crossorigin', 'datetime', 'decoding', 'default', 'dir', 'disabled', 'disablepictureinpicture', 'disableremoteplayback', 'download', 'draggable', 'enctype', 'enterkeyhint', 'exportparts', 'face', 'for', 'headers', 'height', 'hidden', 'high', 'href', 'hreflang', 'id', 'inert', 'inputmode', 'integrity', 'ismap', 'kind', 'label', 'lang', 'list', 'loading', 'loop', 'low', 'max', 'maxlength', 'media', 'method', 'min', 'minlength', 'multiple', 'muted', 'name', 'nonce', 'noshade', 'novalidate', 'nowrap', 'open', 'optimum', 'part', 'pattern', 'placeholder', 'playsinline', 'popover', 'popovertarget', 'popovertargetaction', 'poster', 'preload', 'pubdate', 'radiogroup', 'readonly', 'rel', 'required', 'rev', 'reversed', 'role', 'rows', 'rowspan', 'spellcheck', 'scope', 'selected', 'shape', 'size', 'sizes', 'slot', 'span', 'srclang', 'start', 'src', 'srcset', 'step', 'style', 'summary', 'tabindex', 'title', 'translate', 'type', 'usemap', 'valign', 'value', 'width', 'wrap', 'xmlns']);
421
- const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
421
+ const svg = freeze(['accent-height', 'accumulate', 'additive', 'alignment-baseline', 'amplitude', 'ascent', 'attributename', 'attributetype', 'azimuth', 'basefrequency', 'baseline-shift', 'begin', 'bias', 'by', 'class', 'clip', 'clippathunits', 'clip-path', 'clip-rule', 'color', 'color-interpolation', 'color-interpolation-filters', 'color-profile', 'color-rendering', 'cx', 'cy', 'd', 'dx', 'dy', 'diffuseconstant', 'direction', 'display', 'divisor', 'dominant-baseline', 'dur', 'edgemode', 'elevation', 'end', 'exponent', 'fill', 'fill-opacity', 'fill-rule', 'filter', 'filterunits', 'flood-color', 'flood-opacity', 'font-family', 'font-size', 'font-size-adjust', 'font-stretch', 'font-style', 'font-variant', 'font-weight', 'fx', 'fy', 'g1', 'g2', 'glyph-name', 'glyphref', 'gradientunits', 'gradienttransform', 'height', 'href', 'id', 'image-rendering', 'in', 'in2', 'intercept', 'k', 'k1', 'k2', 'k3', 'k4', 'kerning', 'keypoints', 'keysplines', 'keytimes', 'lang', 'lengthadjust', 'letter-spacing', 'kernelmatrix', 'kernelunitlength', 'lighting-color', 'local', 'marker-end', 'marker-mid', 'marker-start', 'markerheight', 'markerunits', 'markerwidth', 'maskcontentunits', 'maskunits', 'max', 'mask', 'mask-type', 'media', 'method', 'mode', 'min', 'name', 'numoctaves', 'offset', 'operator', 'opacity', 'order', 'orient', 'orientation', 'origin', 'overflow', 'paint-order', 'path', 'pathlength', 'patterncontentunits', 'patterntransform', 'patternunits', 'points', 'preservealpha', 'preserveaspectratio', 'primitiveunits', 'r', 'rx', 'ry', 'radius', 'refx', 'refy', 'repeatcount', 'repeatdur', 'restart', 'result', 'rotate', 'scale', 'seed', 'shape-rendering', 'slope', 'specularconstant', 'specularexponent', 'spreadmethod', 'startoffset', 'stddeviation', 'stitchtiles', 'stop-color', 'stop-opacity', 'stroke-dasharray', 'stroke-dashoffset', 'stroke-linecap', 'stroke-linejoin', 'stroke-miterlimit', 'stroke-opacity', 'stroke', 'stroke-width', 'style', 'surfacescale', 'systemlanguage', 'tabindex', 'tablevalues', 'targetx', 'targety', 'transform', 'transform-origin', 'text-anchor', 'text-decoration', 'text-orientation', 'text-rendering', 'textlength', 'type', 'u1', 'u2', 'unicode', 'values', 'viewbox', 'visibility', 'version', 'vert-adv-y', 'vert-origin-x', 'vert-origin-y', 'width', 'word-spacing', 'wrap', 'writing-mode', 'xchannelselector', 'ychannelselector', 'x', 'x1', 'x2', 'xmlns', 'y', 'y1', 'y2', 'z', 'zoomandpan']);
422
422
  const mathMl = freeze(['accent', 'accentunder', 'align', 'bevelled', 'close', 'columnalign', 'columnlines', 'columnspacing', 'columnspan', 'denomalign', 'depth', 'dir', 'display', 'displaystyle', 'encoding', 'fence', 'frame', 'height', 'href', 'id', 'largeop', 'length', 'linethickness', 'lquote', 'lspace', 'mathbackground', 'mathcolor', 'mathsize', 'mathvariant', 'maxsize', 'minsize', 'movablelimits', 'notation', 'numalign', 'open', 'rowalign', 'rowlines', 'rowspacing', 'rowspan', 'rspace', 'rquote', 'scriptlevel', 'scriptminsize', 'scriptsizemultiplier', 'selection', 'separator', 'separators', 'stretchy', 'subscriptshift', 'supscriptshift', 'symmetric', 'voffset', 'width', 'xmlns']);
423
423
  const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
424
424
 
@@ -531,7 +531,7 @@ var purify = {exports: {}};
531
531
  function createDOMPurify() {
532
532
  let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
533
533
  const DOMPurify = root => createDOMPurify(root);
534
- DOMPurify.version = '3.4.11';
534
+ DOMPurify.version = '3.4.13';
535
535
  DOMPurify.removed = [];
536
536
  if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
537
537
  // Not running in a browser, provide a factory function
@@ -558,6 +558,7 @@ var purify = {exports: {}};
558
558
  const getAttributes = lookupGetter(ElementPrototype, 'attributes');
559
559
  const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;
560
560
  const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null;
561
+ const getOwnerDocument = Node && Node.prototype ? lookupGetter(Node.prototype, 'ownerDocument') : null;
561
562
  // As per issue #47, the web-components registry is inherited by a
562
563
  // new document created via createHTMLDocument. As per the spec
563
564
  // (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
@@ -1209,6 +1210,13 @@ var purify = {exports: {}};
1209
1210
  * @param root the in-place root to empty
1210
1211
  */
1211
1212
  const _neutralizeRoot = function _neutralizeRoot(root) {
1213
+ /* Strip every disallowed attribute (on* handlers included) off the whole
1214
+ subtree BEFORE detaching anything. Detaching first would hand back
1215
+ handler-bearing originals (e.g. an already-loading `<img onerror>`)
1216
+ whose queued resource event still fires in page scope after we throw.
1217
+ Clobber-safe reads; a doomed clobbered node's own attributes are
1218
+ irrelevant while its non-clobbered descendants are reached and scrubbed. */
1219
+ _neutralizeSubtree(root);
1212
1220
  const childNodes = getChildNodes(root);
1213
1221
  if (childNodes) {
1214
1222
  const snapshot = [];
@@ -1336,6 +1344,82 @@ var purify = {exports: {}};
1336
1344
  }
1337
1345
  }
1338
1346
  };
1347
+ /**
1348
+ * _neutralizePatchLinkage
1349
+ *
1350
+ * IN_PLACE entry pre-pass (declarative-partial-updates / streaming
1351
+ * hardening, https://github.com/WICG/declarative-partial-updates).
1352
+ *
1353
+ * The main walk strips patch linkage (`for`/`patchsrc`) and removes range
1354
+ * markers (PIs / markup comments) node-by-node, in document order, AS it
1355
+ * reaches each node. On a live in-place root that leaves a window: from the
1356
+ * moment the root is connected until the walk arrives at a given node, that
1357
+ * node's linkage is live. A patch applied on connection/stream can fire as
1358
+ * a microtask during the walk and inject or teleport an unsanitized DOM
1359
+ * range into a region the iterator has already passed and will not revisit,
1360
+ * so the post-return "tree is sanitized" contract is violated. Sweep the
1361
+ * whole tree once up front and sever every linkage before the walk begins,
1362
+ * closing that window.
1363
+ *
1364
+ * This CANNOT undo a patch that already fired before sanitize ran — that is
1365
+ * the irreducible "do not IN_PLACE a live-connected attacker tree" caveat —
1366
+ * but it closes everything from sanitize-start onward. Gated on SAFE_FOR_XML
1367
+ * to group with the rest of the declarative-partial-updates handling and
1368
+ * stay overridable, consistent with the codebase.
1369
+ *
1370
+ * Clobber-safe traversal (cached childNodes getter); per-node try/catch so a
1371
+ * clobbered root cannot defeat the sweep of its non-clobbered descendants.
1372
+ *
1373
+ * NOTE (pending real-Chrome confirmation, see test/declarative-patch-probe
1374
+ * .html Q1): this mirrors the existing policy of keeping `for` on
1375
+ * <label>/<output>. If the shipping feature can drive a patch through a
1376
+ * surviving `for`-on-label/output + `id` pair, this pre-pass and the
1377
+ * attribute check at _isBasicCustomElement's caller must additionally drop
1378
+ * that pair on the IN_PLACE path. Left as-is until the taxonomy is verified.
1379
+ *
1380
+ * @param root the in-place root to sweep
1381
+ */
1382
+ const _neutralizePatchLinkage = function _neutralizePatchLinkage(root) {
1383
+ if (!SAFE_FOR_XML) {
1384
+ return;
1385
+ }
1386
+ const stack = [root];
1387
+ while (stack.length > 0) {
1388
+ const node = stack.pop();
1389
+ const nodeType = getNodeType ? getNodeType(node) : node.nodeType;
1390
+ /* Remove range markers (the target side of a patch linkage): every
1391
+ processing instruction, and any markup-bearing comment. */
1392
+ if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
1393
+ try {
1394
+ remove(node);
1395
+ } catch (_) {
1396
+ /* Best-effort */
1397
+ }
1398
+ continue;
1399
+ }
1400
+ /* Strip patch-source attributes (the source side) off elements. */
1401
+ if (nodeType === NODE_TYPE.element) {
1402
+ const element = node;
1403
+ const lcTag = transformCaseFunc(getNodeName ? getNodeName(node) : node.nodeName);
1404
+ try {
1405
+ if (element.hasAttribute && element.hasAttribute('patchsrc')) {
1406
+ element.removeAttribute('patchsrc');
1407
+ }
1408
+ if (element.hasAttribute && element.hasAttribute('for') && lcTag !== 'label' && lcTag !== 'output') {
1409
+ element.removeAttribute('for');
1410
+ }
1411
+ } catch (_) {
1412
+ /* Clobbered removeAttribute/hasAttribute on a doomed node — ignore */
1413
+ }
1414
+ }
1415
+ const childNodes = getChildNodes(node);
1416
+ if (childNodes) {
1417
+ for (let i = childNodes.length - 1; i >= 0; --i) {
1418
+ stack.push(childNodes[i]);
1419
+ }
1420
+ }
1421
+ }
1422
+ };
1339
1423
  /**
1340
1424
  * _initDocument
1341
1425
  *
@@ -1393,7 +1477,17 @@ var purify = {exports: {}};
1393
1477
  * @return The created NodeIterator
1394
1478
  */
1395
1479
  const _createNodeIterator = function _createNodeIterator(root) {
1396
- return createNodeIterator.call(root.ownerDocument || root, root,
1480
+ /* Read ownerDocument through the cached Node.prototype getter, never the
1481
+ direct property. HTMLFormElement has [LegacyOverrideBuiltIns], so a
1482
+ clobbering child (<input name="ownerDocument"> or a form-associated
1483
+ external input) shadows the prototype getter and makes a direct read
1484
+ return that <input>. createNodeIterator.call(<input>, ...) then throws
1485
+ "Illegal invocation", and on the IN_PLACE path that throw lands before
1486
+ the walk's fail-closed barrier - leaving the caller's live tree, with
1487
+ any already-armed handler in it, un-neutralized. The cached getter
1488
+ returns the real Document regardless of the clobber. */
1489
+ const doc = getOwnerDocument ? getOwnerDocument(root) : root.ownerDocument;
1490
+ return createNodeIterator.call(doc || root, root,
1397
1491
  // eslint-disable-next-line no-bitwise
1398
1492
  NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
1399
1493
  };
@@ -1433,7 +1527,11 @@ var purify = {exports: {}};
1433
1527
  const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
1434
1528
  var _node$querySelectorAl;
1435
1529
  node.normalize();
1436
- const walker = createNodeIterator.call(node.ownerDocument || node, node,
1530
+ /* Clobber-safe ownerDocument read, same reasoning as _createNodeIterator:
1531
+ under SAFE_FOR_TEMPLATES this runs on the live IN_PLACE root, which may
1532
+ carry a form-named-getter override of ownerDocument. */
1533
+ const doc = getOwnerDocument ? getOwnerDocument(node) : node.ownerDocument;
1534
+ const walker = createNodeIterator.call(doc || node, node,
1437
1535
  // eslint-disable-next-line no-bitwise
1438
1536
  NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
1439
1537
  let currentNode = walker.nextNode();
@@ -1586,15 +1684,21 @@ var purify = {exports: {}};
1586
1684
  /**
1587
1685
  * Handle a node whose tag is forbidden or not allowlisted: keep
1588
1686
  * allowed custom elements (false return exits _sanitizeElements
1589
- * early - namespace/fallback checks and the afterSanitizeElements
1590
- * hook are intentionally skipped for kept custom elements), else
1591
- * hoist content per KEEP_CONTENT and remove.
1687
+ * early - the namespace and fallback-tag removal checks are
1688
+ * intentionally skipped for kept custom elements), else hoist
1689
+ * content per KEEP_CONTENT and remove.
1690
+ *
1691
+ * A kept custom element is the ONLY case in which this function
1692
+ * returns false, so the caller uses that return value to run the
1693
+ * afterSanitizeElements hook on the kept element and keep the
1694
+ * element-hook lifecycle consistent with normal allowlisted
1695
+ * elements (GHSA-c2j3-45gr-mqc4).
1592
1696
  *
1593
1697
  * @param currentNode the disallowed node
1594
1698
  * @param tagName the node's transformCaseFunc'd tag name
1595
1699
  * @return true if the node was removed, false if kept
1596
1700
  */
1597
- const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName) {
1701
+ const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName, root) {
1598
1702
  /* Check if we have a custom element to handle */
1599
1703
  if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
1600
1704
  if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
@@ -1617,27 +1721,26 @@ var purify = {exports: {}};
1617
1721
  const childNodes = getChildNodes(currentNode);
1618
1722
  if (childNodes && parentNode) {
1619
1723
  const childCount = childNodes.length;
1620
- /* In-place: hoist the *original* children so the iterator visits
1621
- and sanitises them through the same allowlist pass as every other
1622
- node. The caller built the tree in the live document, so the
1623
- originals carry already-queued resource events (`<img onerror>`,
1624
- `<video>`/`<audio>` error, lazy/`onload`, …); cloning would leave
1625
- those originals detached but still armed, firing in page scope
1626
- while the returned tree looked clean. Moving is safe in-place: the
1627
- root is pre-validated as an allowed tag and so is never the node
1628
- being removed, which keeps `parentNode` inside the iterator root
1629
- and the relocated child inside the serialised tree.
1630
- Otherwise (string / DOM-copy paths): clone. The iterator is rooted
1631
- at — and the result serialised from — `body`, so a restrictive
1632
- ALLOWED_TAGS that removes `body` itself must leave its content in
1633
- place, which only cloning does; and those paths parse into an
1634
- inert document, so their discarded originals never had a queued
1635
- event to neutralise.
1724
+ /* Hoist by moving each child up one level rather than deep-cloning
1725
+ it. Moving transfers every descendant exactly once, so a chain of
1726
+ nested disallowed elements costs O(n) instead of the O(n^2) that
1727
+ re-cloning the shrinking subtree at each level produced; it also
1728
+ empties the removed original, so `DOMPurify.removed` no longer
1729
+ pins whole subtrees. Moving preserves the in-place guarantee too:
1730
+ an original carrying already-queued resource events (`<img
1731
+ onerror>`, `<video>`/`<audio>` error, lazy/`onload`, …) is
1732
+ relocated and sanitised rather than left detached but still armed.
1733
+ The sole case that must clone is removing the walk root itself.
1734
+ The result is serialised from the root's subtree, so a restrictive
1735
+ ALLOWED_TAGS that strips the root (`body` on the string path) must
1736
+ leave the content inside it, which only cloning does. In IN_PLACE
1737
+ the root is pre-validated as an allowed tag and so is never removed
1738
+ here, so that path always takes the move branch.
1636
1739
  `childNodes` is live; a tail-to-head walk keeps `childNodes[i]`
1637
1740
  valid whether we move (drops the trailing entry) or clone (leaves
1638
1741
  the list intact). */
1639
1742
  for (let i = childCount - 1; i >= 0; --i) {
1640
- const hoisted = IN_PLACE ? childNodes[i] : cloneNode(childNodes[i], true);
1743
+ const hoisted = currentNode === root ? cloneNode(childNodes[i], true) : childNodes[i];
1641
1744
  parentNode.insertBefore(hoisted, getNextSibling(currentNode));
1642
1745
  }
1643
1746
  }
@@ -1645,6 +1748,26 @@ var purify = {exports: {}};
1645
1748
  _forceRemove(currentNode);
1646
1749
  return true;
1647
1750
  };
1751
+ /**
1752
+ * Fork a hook-mutable allowlist off its shared binding the first time a
1753
+ * (possibly lazily-installed) uponSanitize* hook is about to see it, so the
1754
+ * hook cannot widen the per-instance default or the setConfig binding by
1755
+ * reference and leak past the call. Returns the set unchanged once it is
1756
+ * already call-local, so repeated calls across elements are idempotent.
1757
+ *
1758
+ * @param hookList the uponSanitize* hook array for this event
1759
+ * @param set the current ALLOWED_TAGS / ALLOWED_ATTR binding
1760
+ * @param defaultSet the per-instance DEFAULT_ALLOWED_* constant
1761
+ * @param setConfigSet the captured setConfig() binding, or null
1762
+ * @return a call-local clone if a hook is present and set is still shared,
1763
+ * else set unchanged
1764
+ */
1765
+ const _forkSharedAllowlist = function _forkSharedAllowlist(hookList, set, defaultSet, setConfigSet) {
1766
+ if (hookList.length === 0) {
1767
+ return set;
1768
+ }
1769
+ return set === defaultSet || set === setConfigSet ? clone(set) : set;
1770
+ };
1648
1771
  /**
1649
1772
  * _sanitizeElements
1650
1773
  *
@@ -1654,9 +1777,20 @@ var purify = {exports: {}};
1654
1777
  * @param currentNode to check for permission to exist
1655
1778
  * @return true if node was killed, false if left alive
1656
1779
  */
1657
- const _sanitizeElements = function _sanitizeElements(currentNode) {
1780
+ // eslint-disable-next-line complexity
1781
+ const _sanitizeElements = function _sanitizeElements(currentNode, root) {
1658
1782
  /* Execute a hook if present */
1659
1783
  _executeHooks(hooks.beforeSanitizeElements, currentNode, null);
1784
+ /* A hook may have detached the node - treat it as removed (see the
1785
+ detached-node comment after the uponSanitizeElement hook below). On
1786
+ the IN_PLACE path, neutralize the detached subtree first so a queued
1787
+ resource handler on it cannot fire in page scope after we return. */
1788
+ if (currentNode !== root && getParentNode(currentNode) === null) {
1789
+ if (IN_PLACE) {
1790
+ _neutralizeSubtree(currentNode);
1791
+ }
1792
+ return true;
1793
+ }
1660
1794
  /* Check if element is clobbered or can clobber */
1661
1795
  if (_isClobbered(currentNode)) {
1662
1796
  _forceRemove(currentNode);
@@ -1664,11 +1798,47 @@ var purify = {exports: {}};
1664
1798
  }
1665
1799
  /* Now let's check the element's type and name */
1666
1800
  const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName);
1801
+ /* Close the pre-walk clone-guard's timing gap: an uponSanitizeElement
1802
+ hook may have been installed after that guard sampled the hook arrays
1803
+ (e.g. lazily from beforeSanitizeElements), leaving ALLOWED_TAGS still
1804
+ aliasing a shared binding that a widening hook would mutate by
1805
+ reference. Fork it before exposing it to the hook. */
1806
+ ALLOWED_TAGS = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS);
1667
1807
  /* Execute a hook if present */
1668
1808
  _executeHooks(hooks.uponSanitizeElement, currentNode, {
1669
1809
  tagName,
1670
1810
  allowedTags: ALLOWED_TAGS
1671
1811
  });
1812
+ /* A hook may have detached the node from the tree — a long-standing
1813
+ user pattern (issue #469; draw.io-style foreignObject filtering).
1814
+ Per the cached, unclobberable parentNode getter the node is
1815
+ genuinely out of the tree, so it can reach neither the serialized
1816
+ output nor an IN_PLACE live tree; treat it as removed and stop
1817
+ processing it. Without this guard, the unsafe-node / namespace
1818
+ checks below would call _forceRemove on a parentless node and hit
1819
+ the REPORT-3 fail-closed throw — which exists for nodes DOMPurify
1820
+ wants gone but *cannot* detach (clobbered / parentless roots), the
1821
+ opposite of a node that is already safely gone. The walk root is
1822
+ exempt: a detached IN_PLACE root is legitimate input and must still
1823
+ be fully sanitized, and a kill-decision on it must keep hitting the
1824
+ REPORT-3 throw. Nodes detached by hooks stay the hook's
1825
+ responsibility for placement: they are not recorded in
1826
+ DOMPurify.removed, so the post-walk IN_PLACE pass (which iterates
1827
+ DOMPurify.removed) does not reach them. But a hook-detached subtree
1828
+ can still hold a queued resource-event handler - e.g. an <img onload>
1829
+ that began loading when the caller built the live tree - which fires
1830
+ in page scope after sanitize returns even though the handler never
1831
+ reached the returned tree. That is the audit-5 F1 hazard, and the
1832
+ documented node.remove() hook pattern walks straight into it. So on
1833
+ the IN_PLACE path we neutralize the detached subtree inline here,
1834
+ stripping its non-allow-listed attributes before returning, exactly
1835
+ as the post-walk pass does for _forceRemove'd subtrees. */
1836
+ if (currentNode !== root && getParentNode(currentNode) === null) {
1837
+ if (IN_PLACE) {
1838
+ _neutralizeSubtree(currentNode);
1839
+ }
1840
+ return true;
1841
+ }
1672
1842
  /* Remove mXSS vectors, processing instructions and risky comments */
1673
1843
  if (_isUnsafeNode(currentNode, tagName)) {
1674
1844
  _forceRemove(currentNode);
@@ -1676,7 +1846,22 @@ var purify = {exports: {}};
1676
1846
  }
1677
1847
  /* Remove element if anything forbids its presence */
1678
1848
  if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
1679
- return _sanitizeDisallowedNode(currentNode, tagName);
1849
+ const removed = _sanitizeDisallowedNode(currentNode, tagName, root);
1850
+ /* A false return means the node is a custom element kept via
1851
+ CUSTOM_ELEMENT_HANDLING - the only keep path through
1852
+ _sanitizeDisallowedNode. Run afterSanitizeElements on it so the
1853
+ element-hook lifecycle matches normal allowlisted elements: a
1854
+ security policy applied in this hook (e.g. stripping an attribute
1855
+ from every surviving element) must not silently skip kept custom
1856
+ elements (GHSA-c2j3-45gr-mqc4). This mirrors the normal-element
1857
+ tail below - the hook runs, then the walker's subsequent
1858
+ _sanitizeAttributes pass sanitizes the element's attributes. The
1859
+ deliberately skipped namespace and fallback-tag removal checks stay
1860
+ skipped; they are removal decisions, not the hook contract. */
1861
+ if (removed === false) {
1862
+ _executeHooks(hooks.afterSanitizeElements, currentNode, null);
1863
+ }
1864
+ return removed;
1680
1865
  }
1681
1866
  /* Check whether element has a valid namespace.
1682
1867
  Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype
@@ -1723,6 +1908,33 @@ var purify = {exports: {}};
1723
1908
  if (FORBID_ATTR[lcName]) {
1724
1909
  return false;
1725
1910
  }
1911
+ /* Reject declarative-partial-updates patch-linkage attributes
1912
+ (https://github.com/WICG/declarative-partial-updates).
1913
+ Empirical note (Chrome 150, verified — see
1914
+ test/declarative-patch-probe-v3.html): expansion is NOT applied after
1915
+ sanitization. For the string path it fires during sanitize()'s own
1916
+ parse, so the walk sees and sanitizes the fully materialized expanded
1917
+ tree — teleports into MathML/SVG integration points included; a
1918
+ weaponized `<template for>`->`<img onerror>` comes back with the handler
1919
+ stripped. For the IN_PLACE path it fires on connection, before the walk.
1920
+ Either way DOMPurify is NOT blind to the patch.
1921
+ This removal is therefore defense-in-depth rather than the sole barrier:
1922
+ it prevents live linkage from surviving into the OUTPUT and re-expanding
1923
+ in the caller's context, and keeps behaviour deterministic if a future
1924
+ engine defers expansion. `for` is legitimate only on <label>/<output>;
1925
+ anywhere else (notably <template for>) it links the element to a patch
1926
+ target and teleports or removes an arbitrary DOM range by id/marker name.
1927
+ `patchsrc` fetches remote markup and is treated as a script-loading
1928
+ mechanism (CSP). Gated on SAFE_FOR_XML so the removal groups with the
1929
+ other structural-threat checks and stays overridable, consistent with
1930
+ the rest of the codebase. PI range markers are already removed by
1931
+ _isUnsafeNode. */
1932
+ if (SAFE_FOR_XML && lcName === 'patchsrc') {
1933
+ return false;
1934
+ }
1935
+ if (SAFE_FOR_XML && lcName === 'for' && lcTag !== 'label' && lcTag !== 'output') {
1936
+ return false;
1937
+ }
1726
1938
  /* Make sure attribute cannot clobber */
1727
1939
  if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
1728
1940
  return false;
@@ -1839,6 +2051,9 @@ var purify = {exports: {}};
1839
2051
  if (!attributes || _isClobbered(currentNode)) {
1840
2052
  return;
1841
2053
  }
2054
+ /* Same lazy-install guard as uponSanitizeElement (see there): fork the
2055
+ attribute allowlist off its shared binding before a hook can see it. */
2056
+ ALLOWED_ATTR = _forkSharedAllowlist(hooks.uponSanitizeAttribute, ALLOWED_ATTR, DEFAULT_ALLOWED_ATTR, SET_CONFIG_ALLOWED_ATTR);
1842
2057
  const hookEvent = {
1843
2058
  attrName: '',
1844
2059
  attrValue: '',
@@ -1932,7 +2147,7 @@ var purify = {exports: {}};
1932
2147
  /* Execute a hook if present */
1933
2148
  _executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
1934
2149
  /* Sanitize tags and elements */
1935
- _sanitizeElements(shadowNode);
2150
+ _sanitizeElements(shadowNode, fragment);
1936
2151
  /* Check attributes next */
1937
2152
  _sanitizeAttributes(shadowNode);
1938
2153
  /* Deep shadow DOM detected.
@@ -2123,6 +2338,11 @@ var purify = {exports: {}};
2123
2338
  keep using and whose return value they ignore — unsanitized. REPORT-2. */
2124
2339
  const inPlace = IN_PLACE && typeof dirty !== 'string' && _isNode(dirty);
2125
2340
  if (inPlace) {
2341
+ /* Declarative-partial-updates / streaming pre-pass: sever every patch
2342
+ linkage across the live tree BEFORE the walk, so no patch can fire
2343
+ mid-walk and inject into an already-processed region. Runs first, so
2344
+ it also covers the forbidden/clobbered roots that throw below. */
2345
+ _neutralizePatchLinkage(dirty);
2126
2346
  /* Do some early pre-sanitization to avoid unsafe root nodes.
2127
2347
  Read nodeName through the cached prototype getter — a clobbering
2128
2348
  child named "nodeName" on the form root would otherwise shadow
@@ -2132,6 +2352,9 @@ var purify = {exports: {}};
2132
2352
  if (typeof nn === 'string') {
2133
2353
  const tagName = transformCaseFunc(nn);
2134
2354
  if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
2355
+ /* Fail closed on a live root: neutralize handlers/children before
2356
+ throwing, exactly as the mid-walk abort path does. */
2357
+ _neutralizeRoot(dirty);
2135
2358
  throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
2136
2359
  }
2137
2360
  }
@@ -2146,6 +2369,10 @@ var purify = {exports: {}};
2146
2369
  the application unsanitized. Refuse to sanitize such a root
2147
2370
  the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */
2148
2371
  if (_isClobbered(dirty)) {
2372
+ /* Fail closed on a live clobbered root before throwing.
2373
+ _neutralizeRoot's reads are clobber-safe (cached getters); the
2374
+ form's non-clobbered descendants, e.g. an armed <img>, are scrubbed. */
2375
+ _neutralizeRoot(dirty);
2149
2376
  throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place');
2150
2377
  }
2151
2378
  /* Sanitize attached shadow roots before the main iterator runs.
@@ -2198,20 +2425,24 @@ var purify = {exports: {}};
2198
2425
  _forceRemove(body.firstChild);
2199
2426
  }
2200
2427
  /* Get node iterator */
2201
- const nodeIterator = _createNodeIterator(inPlace ? dirty : body);
2428
+ const walkRoot = inPlace ? dirty : body;
2202
2429
  /* Now start iterating over the created document.
2203
2430
  The walk runs inside an exception barrier (campaign-3 F2): a re-entrant
2204
2431
  engine/custom-element mutation can detach a node mid-walk so
2205
2432
  `_forceRemove`'s parentless guard throws, aborting the loop. Without the
2206
2433
  barrier the caller's in-place tree would be left half-sanitized with the
2207
- unvisited tail still armed. On any throw we fail closed — strip the
2208
- in-place root bare — then rethrow so the existing throw contract is
2209
- preserved. (String/DOM-copy paths never return the partial body, so the
2210
- propagating throw is already fail-closed there.) */
2434
+ unvisited tail still armed. _createNodeIterator itself is inside the
2435
+ barrier too: constructing the iterator dereferences the root's document,
2436
+ and any failure there (e.g. an exotic/clobbered root) must still fail
2437
+ closed rather than skip the neutralize. On any throw we fail closed -
2438
+ strip the in-place root bare - then rethrow so the existing throw
2439
+ contract is preserved. (String/DOM-copy paths never return the partial
2440
+ body, so the propagating throw is already fail-closed there.) */
2211
2441
  try {
2442
+ const nodeIterator = _createNodeIterator(walkRoot);
2212
2443
  while (currentNode = nodeIterator.nextNode()) {
2213
2444
  /* Sanitize tags and elements */
2214
- _sanitizeElements(currentNode);
2445
+ _sanitizeElements(currentNode, walkRoot);
2215
2446
  /* Check attributes next */
2216
2447
  _sanitizeAttributes(currentNode);
2217
2448
  /* Shadow DOM detected, sanitize it.
@@ -2225,6 +2456,14 @@ var purify = {exports: {}};
2225
2456
  } catch (error) {
2226
2457
  if (inPlace) {
2227
2458
  _neutralizeRoot(dirty);
2459
+ /* Nodes _forceRemove'd earlier in the aborted walk are already
2460
+ detached from the root, so _neutralizeRoot's subtree pass does not
2461
+ reach them. Defuse them too, mirroring the success-path loop below. */
2462
+ arrayForEach(DOMPurify.removed, entry => {
2463
+ if (entry.element) {
2464
+ _neutralizeSubtree(entry.element);
2465
+ }
2466
+ });
2228
2467
  }
2229
2468
  throw error;
2230
2469
  }