@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.
- package/components/ic-accordion.js +53 -38
- package/components/ic-accordion.js.map +1 -1
- package/components/ic-menu2.js +274 -35
- package/components/ic-menu2.js.map +1 -1
- package/components/ic-navigation-button.js +8 -5
- package/components/ic-navigation-button.js.map +1 -1
- package/components/ic-pagination-bar.js.map +1 -1
- package/components/ic-skip-link.js.map +1 -1
- package/components/ic-status-tag.js.map +1 -1
- package/components/ic-switch.js.map +1 -1
- package/dist/cjs/ic-accordion.cjs.entry.js +53 -38
- package/dist/cjs/ic-accordion.cjs.entry.js.map +1 -1
- package/dist/cjs/ic-button_3.cjs.entry.js.map +1 -1
- package/dist/cjs/ic-horizontal-scroll.cjs.entry.js.map +1 -1
- package/dist/cjs/ic-input-component-container_3.cjs.entry.js +274 -35
- package/dist/cjs/ic-input-component-container_3.cjs.entry.js.map +1 -1
- package/dist/cjs/ic-navigation-button.cjs.entry.js +8 -5
- package/dist/cjs/ic-navigation-button.cjs.entry.js.map +1 -1
- package/dist/cjs/ic-section-container.cjs.entry.js.map +1 -1
- package/dist/collection/components/ic-accordion/ic-accordion.js +53 -38
- package/dist/collection/components/ic-accordion/ic-accordion.js.map +1 -1
- package/dist/collection/components/ic-navigation-button/ic-navigation-button.js +8 -5
- package/dist/collection/components/ic-navigation-button/ic-navigation-button.js.map +1 -1
- package/dist/components/ic-accordion.js +53 -38
- package/dist/components/ic-accordion.js.map +1 -1
- package/dist/components/ic-back-to-top.js.map +1 -1
- package/dist/components/ic-hero.js.map +1 -1
- package/dist/components/ic-menu2.js +274 -35
- package/dist/components/ic-menu2.js.map +1 -1
- package/dist/components/ic-navigation-button.js +8 -5
- package/dist/components/ic-navigation-button.js.map +1 -1
- package/dist/components/ic-pagination-bar.js.map +1 -1
- package/dist/components/ic-popover-menu.js.map +1 -1
- package/dist/components/ic-radio-group.js.map +1 -1
- package/dist/components/ic-radio-option.js.map +1 -1
- package/dist/components/ic-search-bar.js.map +1 -1
- package/dist/components/ic-skip-link.js.map +1 -1
- package/dist/components/ic-status-tag.js.map +1 -1
- package/dist/components/ic-switch.js.map +1 -1
- package/dist/core/core.esm.js +1 -1
- package/dist/core/{p-9ced00a7.entry.js → p-41bbdc4c.entry.js} +2 -2
- package/dist/core/{p-9ced00a7.entry.js.map → p-41bbdc4c.entry.js.map} +1 -1
- package/dist/core/p-8fc5e9f9.entry.js.map +1 -1
- package/dist/core/p-98dee727.entry.js.map +1 -1
- package/dist/core/{p-fc4b7d2b.entry.js → p-9cf35c23.entry.js} +2 -2
- package/dist/core/p-9cf35c23.entry.js.map +1 -0
- package/dist/core/p-a8d98164.entry.js.map +1 -1
- package/dist/core/p-ccba84b7.entry.js +3 -0
- package/dist/core/p-ccba84b7.entry.js.map +1 -0
- package/dist/esm/ic-accordion.entry.js +53 -38
- package/dist/esm/ic-accordion.entry.js.map +1 -1
- package/dist/esm/ic-button_3.entry.js.map +1 -1
- package/dist/esm/ic-horizontal-scroll.entry.js.map +1 -1
- package/dist/esm/ic-input-component-container_3.entry.js +274 -35
- package/dist/esm/ic-input-component-container_3.entry.js.map +1 -1
- package/dist/esm/ic-navigation-button.entry.js +8 -5
- package/dist/esm/ic-navigation-button.entry.js.map +1 -1
- package/dist/esm/ic-section-container.entry.js.map +1 -1
- package/dist/types/components/ic-accordion/ic-accordion.d.ts +2 -0
- package/hydrate/index.js +334 -77
- package/hydrate/index.mjs +334 -77
- package/package.json +1 -1
- package/dist/core/p-305d9639.entry.js +0 -3
- package/dist/core/p-305d9639.entry.js.map +0 -1
- package/dist/core/p-fc4b7d2b.entry.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"file":"ic-horizontal-scroll.entry.js","mappings":"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","names":[],"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.js","mappings":"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","names":[],"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}
|
|
@@ -97,7 +97,7 @@ var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof win
|
|
|
97
97
|
|
|
98
98
|
var purify = {exports: {}};
|
|
99
99
|
|
|
100
|
-
/*! @license DOMPurify 3.4.
|
|
100
|
+
/*! @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 */
|
|
101
101
|
|
|
102
102
|
(function (module, exports) {
|
|
103
103
|
(function (global, factory) {
|
|
@@ -414,7 +414,7 @@ var purify = {exports: {}};
|
|
|
414
414
|
const text = freeze(['#text']);
|
|
415
415
|
|
|
416
416
|
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']);
|
|
417
|
-
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']);
|
|
417
|
+
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']);
|
|
418
418
|
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']);
|
|
419
419
|
const xml = freeze(['xlink:href', 'xml:id', 'xlink:title', 'xml:space', 'xmlns:xlink']);
|
|
420
420
|
|
|
@@ -527,7 +527,7 @@ var purify = {exports: {}};
|
|
|
527
527
|
function createDOMPurify() {
|
|
528
528
|
let window = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : getGlobal();
|
|
529
529
|
const DOMPurify = root => createDOMPurify(root);
|
|
530
|
-
DOMPurify.version = '3.4.
|
|
530
|
+
DOMPurify.version = '3.4.13';
|
|
531
531
|
DOMPurify.removed = [];
|
|
532
532
|
if (!window || !window.document || window.document.nodeType !== NODE_TYPE.document || !window.Element) {
|
|
533
533
|
// Not running in a browser, provide a factory function
|
|
@@ -554,6 +554,7 @@ var purify = {exports: {}};
|
|
|
554
554
|
const getAttributes = lookupGetter(ElementPrototype, 'attributes');
|
|
555
555
|
const getNodeType = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeType') : null;
|
|
556
556
|
const getNodeName = Node && Node.prototype ? lookupGetter(Node.prototype, 'nodeName') : null;
|
|
557
|
+
const getOwnerDocument = Node && Node.prototype ? lookupGetter(Node.prototype, 'ownerDocument') : null;
|
|
557
558
|
// As per issue #47, the web-components registry is inherited by a
|
|
558
559
|
// new document created via createHTMLDocument. As per the spec
|
|
559
560
|
// (http://w3c.github.io/webcomponents/spec/custom/#creating-and-passing-registries)
|
|
@@ -1205,6 +1206,13 @@ var purify = {exports: {}};
|
|
|
1205
1206
|
* @param root the in-place root to empty
|
|
1206
1207
|
*/
|
|
1207
1208
|
const _neutralizeRoot = function _neutralizeRoot(root) {
|
|
1209
|
+
/* Strip every disallowed attribute (on* handlers included) off the whole
|
|
1210
|
+
subtree BEFORE detaching anything. Detaching first would hand back
|
|
1211
|
+
handler-bearing originals (e.g. an already-loading `<img onerror>`)
|
|
1212
|
+
whose queued resource event still fires in page scope after we throw.
|
|
1213
|
+
Clobber-safe reads; a doomed clobbered node's own attributes are
|
|
1214
|
+
irrelevant while its non-clobbered descendants are reached and scrubbed. */
|
|
1215
|
+
_neutralizeSubtree(root);
|
|
1208
1216
|
const childNodes = getChildNodes(root);
|
|
1209
1217
|
if (childNodes) {
|
|
1210
1218
|
const snapshot = [];
|
|
@@ -1332,6 +1340,82 @@ var purify = {exports: {}};
|
|
|
1332
1340
|
}
|
|
1333
1341
|
}
|
|
1334
1342
|
};
|
|
1343
|
+
/**
|
|
1344
|
+
* _neutralizePatchLinkage
|
|
1345
|
+
*
|
|
1346
|
+
* IN_PLACE entry pre-pass (declarative-partial-updates / streaming
|
|
1347
|
+
* hardening, https://github.com/WICG/declarative-partial-updates).
|
|
1348
|
+
*
|
|
1349
|
+
* The main walk strips patch linkage (`for`/`patchsrc`) and removes range
|
|
1350
|
+
* markers (PIs / markup comments) node-by-node, in document order, AS it
|
|
1351
|
+
* reaches each node. On a live in-place root that leaves a window: from the
|
|
1352
|
+
* moment the root is connected until the walk arrives at a given node, that
|
|
1353
|
+
* node's linkage is live. A patch applied on connection/stream can fire as
|
|
1354
|
+
* a microtask during the walk and inject or teleport an unsanitized DOM
|
|
1355
|
+
* range into a region the iterator has already passed and will not revisit,
|
|
1356
|
+
* so the post-return "tree is sanitized" contract is violated. Sweep the
|
|
1357
|
+
* whole tree once up front and sever every linkage before the walk begins,
|
|
1358
|
+
* closing that window.
|
|
1359
|
+
*
|
|
1360
|
+
* This CANNOT undo a patch that already fired before sanitize ran — that is
|
|
1361
|
+
* the irreducible "do not IN_PLACE a live-connected attacker tree" caveat —
|
|
1362
|
+
* but it closes everything from sanitize-start onward. Gated on SAFE_FOR_XML
|
|
1363
|
+
* to group with the rest of the declarative-partial-updates handling and
|
|
1364
|
+
* stay overridable, consistent with the codebase.
|
|
1365
|
+
*
|
|
1366
|
+
* Clobber-safe traversal (cached childNodes getter); per-node try/catch so a
|
|
1367
|
+
* clobbered root cannot defeat the sweep of its non-clobbered descendants.
|
|
1368
|
+
*
|
|
1369
|
+
* NOTE (pending real-Chrome confirmation, see test/declarative-patch-probe
|
|
1370
|
+
* .html Q1): this mirrors the existing policy of keeping `for` on
|
|
1371
|
+
* <label>/<output>. If the shipping feature can drive a patch through a
|
|
1372
|
+
* surviving `for`-on-label/output + `id` pair, this pre-pass and the
|
|
1373
|
+
* attribute check at _isBasicCustomElement's caller must additionally drop
|
|
1374
|
+
* that pair on the IN_PLACE path. Left as-is until the taxonomy is verified.
|
|
1375
|
+
*
|
|
1376
|
+
* @param root the in-place root to sweep
|
|
1377
|
+
*/
|
|
1378
|
+
const _neutralizePatchLinkage = function _neutralizePatchLinkage(root) {
|
|
1379
|
+
if (!SAFE_FOR_XML) {
|
|
1380
|
+
return;
|
|
1381
|
+
}
|
|
1382
|
+
const stack = [root];
|
|
1383
|
+
while (stack.length > 0) {
|
|
1384
|
+
const node = stack.pop();
|
|
1385
|
+
const nodeType = getNodeType ? getNodeType(node) : node.nodeType;
|
|
1386
|
+
/* Remove range markers (the target side of a patch linkage): every
|
|
1387
|
+
processing instruction, and any markup-bearing comment. */
|
|
1388
|
+
if (nodeType === NODE_TYPE.processingInstruction || nodeType === NODE_TYPE.comment && regExpTest(COMMENT_MARKUP_PROBE, node.data)) {
|
|
1389
|
+
try {
|
|
1390
|
+
remove(node);
|
|
1391
|
+
} catch (_) {
|
|
1392
|
+
/* Best-effort */
|
|
1393
|
+
}
|
|
1394
|
+
continue;
|
|
1395
|
+
}
|
|
1396
|
+
/* Strip patch-source attributes (the source side) off elements. */
|
|
1397
|
+
if (nodeType === NODE_TYPE.element) {
|
|
1398
|
+
const element = node;
|
|
1399
|
+
const lcTag = transformCaseFunc(getNodeName ? getNodeName(node) : node.nodeName);
|
|
1400
|
+
try {
|
|
1401
|
+
if (element.hasAttribute && element.hasAttribute('patchsrc')) {
|
|
1402
|
+
element.removeAttribute('patchsrc');
|
|
1403
|
+
}
|
|
1404
|
+
if (element.hasAttribute && element.hasAttribute('for') && lcTag !== 'label' && lcTag !== 'output') {
|
|
1405
|
+
element.removeAttribute('for');
|
|
1406
|
+
}
|
|
1407
|
+
} catch (_) {
|
|
1408
|
+
/* Clobbered removeAttribute/hasAttribute on a doomed node — ignore */
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
const childNodes = getChildNodes(node);
|
|
1412
|
+
if (childNodes) {
|
|
1413
|
+
for (let i = childNodes.length - 1; i >= 0; --i) {
|
|
1414
|
+
stack.push(childNodes[i]);
|
|
1415
|
+
}
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1335
1419
|
/**
|
|
1336
1420
|
* _initDocument
|
|
1337
1421
|
*
|
|
@@ -1389,7 +1473,17 @@ var purify = {exports: {}};
|
|
|
1389
1473
|
* @return The created NodeIterator
|
|
1390
1474
|
*/
|
|
1391
1475
|
const _createNodeIterator = function _createNodeIterator(root) {
|
|
1392
|
-
|
|
1476
|
+
/* Read ownerDocument through the cached Node.prototype getter, never the
|
|
1477
|
+
direct property. HTMLFormElement has [LegacyOverrideBuiltIns], so a
|
|
1478
|
+
clobbering child (<input name="ownerDocument"> or a form-associated
|
|
1479
|
+
external input) shadows the prototype getter and makes a direct read
|
|
1480
|
+
return that <input>. createNodeIterator.call(<input>, ...) then throws
|
|
1481
|
+
"Illegal invocation", and on the IN_PLACE path that throw lands before
|
|
1482
|
+
the walk's fail-closed barrier - leaving the caller's live tree, with
|
|
1483
|
+
any already-armed handler in it, un-neutralized. The cached getter
|
|
1484
|
+
returns the real Document regardless of the clobber. */
|
|
1485
|
+
const doc = getOwnerDocument ? getOwnerDocument(root) : root.ownerDocument;
|
|
1486
|
+
return createNodeIterator.call(doc || root, root,
|
|
1393
1487
|
// eslint-disable-next-line no-bitwise
|
|
1394
1488
|
NodeFilter.SHOW_ELEMENT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_TEXT | NodeFilter.SHOW_PROCESSING_INSTRUCTION | NodeFilter.SHOW_CDATA_SECTION, null);
|
|
1395
1489
|
};
|
|
@@ -1429,7 +1523,11 @@ var purify = {exports: {}};
|
|
|
1429
1523
|
const _scrubTemplateExpressions2 = function _scrubTemplateExpressions(node) {
|
|
1430
1524
|
var _node$querySelectorAl;
|
|
1431
1525
|
node.normalize();
|
|
1432
|
-
|
|
1526
|
+
/* Clobber-safe ownerDocument read, same reasoning as _createNodeIterator:
|
|
1527
|
+
under SAFE_FOR_TEMPLATES this runs on the live IN_PLACE root, which may
|
|
1528
|
+
carry a form-named-getter override of ownerDocument. */
|
|
1529
|
+
const doc = getOwnerDocument ? getOwnerDocument(node) : node.ownerDocument;
|
|
1530
|
+
const walker = createNodeIterator.call(doc || node, node,
|
|
1433
1531
|
// eslint-disable-next-line no-bitwise
|
|
1434
1532
|
NodeFilter.SHOW_TEXT | NodeFilter.SHOW_COMMENT | NodeFilter.SHOW_CDATA_SECTION | NodeFilter.SHOW_PROCESSING_INSTRUCTION, null);
|
|
1435
1533
|
let currentNode = walker.nextNode();
|
|
@@ -1582,15 +1680,21 @@ var purify = {exports: {}};
|
|
|
1582
1680
|
/**
|
|
1583
1681
|
* Handle a node whose tag is forbidden or not allowlisted: keep
|
|
1584
1682
|
* allowed custom elements (false return exits _sanitizeElements
|
|
1585
|
-
* early - namespace
|
|
1586
|
-
*
|
|
1587
|
-
*
|
|
1683
|
+
* early - the namespace and fallback-tag removal checks are
|
|
1684
|
+
* intentionally skipped for kept custom elements), else hoist
|
|
1685
|
+
* content per KEEP_CONTENT and remove.
|
|
1686
|
+
*
|
|
1687
|
+
* A kept custom element is the ONLY case in which this function
|
|
1688
|
+
* returns false, so the caller uses that return value to run the
|
|
1689
|
+
* afterSanitizeElements hook on the kept element and keep the
|
|
1690
|
+
* element-hook lifecycle consistent with normal allowlisted
|
|
1691
|
+
* elements (GHSA-c2j3-45gr-mqc4).
|
|
1588
1692
|
*
|
|
1589
1693
|
* @param currentNode the disallowed node
|
|
1590
1694
|
* @param tagName the node's transformCaseFunc'd tag name
|
|
1591
1695
|
* @return true if the node was removed, false if kept
|
|
1592
1696
|
*/
|
|
1593
|
-
const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName) {
|
|
1697
|
+
const _sanitizeDisallowedNode = function _sanitizeDisallowedNode(currentNode, tagName, root) {
|
|
1594
1698
|
/* Check if we have a custom element to handle */
|
|
1595
1699
|
if (!FORBID_TAGS[tagName] && _isBasicCustomElement(tagName)) {
|
|
1596
1700
|
if (CUSTOM_ELEMENT_HANDLING.tagNameCheck instanceof RegExp && regExpTest(CUSTOM_ELEMENT_HANDLING.tagNameCheck, tagName)) {
|
|
@@ -1613,27 +1717,26 @@ var purify = {exports: {}};
|
|
|
1613
1717
|
const childNodes = getChildNodes(currentNode);
|
|
1614
1718
|
if (childNodes && parentNode) {
|
|
1615
1719
|
const childCount = childNodes.length;
|
|
1616
|
-
/*
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
event to neutralise.
|
|
1720
|
+
/* Hoist by moving each child up one level rather than deep-cloning
|
|
1721
|
+
it. Moving transfers every descendant exactly once, so a chain of
|
|
1722
|
+
nested disallowed elements costs O(n) instead of the O(n^2) that
|
|
1723
|
+
re-cloning the shrinking subtree at each level produced; it also
|
|
1724
|
+
empties the removed original, so `DOMPurify.removed` no longer
|
|
1725
|
+
pins whole subtrees. Moving preserves the in-place guarantee too:
|
|
1726
|
+
an original carrying already-queued resource events (`<img
|
|
1727
|
+
onerror>`, `<video>`/`<audio>` error, lazy/`onload`, …) is
|
|
1728
|
+
relocated and sanitised rather than left detached but still armed.
|
|
1729
|
+
The sole case that must clone is removing the walk root itself.
|
|
1730
|
+
The result is serialised from the root's subtree, so a restrictive
|
|
1731
|
+
ALLOWED_TAGS that strips the root (`body` on the string path) must
|
|
1732
|
+
leave the content inside it, which only cloning does. In IN_PLACE
|
|
1733
|
+
the root is pre-validated as an allowed tag and so is never removed
|
|
1734
|
+
here, so that path always takes the move branch.
|
|
1632
1735
|
`childNodes` is live; a tail-to-head walk keeps `childNodes[i]`
|
|
1633
1736
|
valid whether we move (drops the trailing entry) or clone (leaves
|
|
1634
1737
|
the list intact). */
|
|
1635
1738
|
for (let i = childCount - 1; i >= 0; --i) {
|
|
1636
|
-
const hoisted =
|
|
1739
|
+
const hoisted = currentNode === root ? cloneNode(childNodes[i], true) : childNodes[i];
|
|
1637
1740
|
parentNode.insertBefore(hoisted, getNextSibling(currentNode));
|
|
1638
1741
|
}
|
|
1639
1742
|
}
|
|
@@ -1641,6 +1744,26 @@ var purify = {exports: {}};
|
|
|
1641
1744
|
_forceRemove(currentNode);
|
|
1642
1745
|
return true;
|
|
1643
1746
|
};
|
|
1747
|
+
/**
|
|
1748
|
+
* Fork a hook-mutable allowlist off its shared binding the first time a
|
|
1749
|
+
* (possibly lazily-installed) uponSanitize* hook is about to see it, so the
|
|
1750
|
+
* hook cannot widen the per-instance default or the setConfig binding by
|
|
1751
|
+
* reference and leak past the call. Returns the set unchanged once it is
|
|
1752
|
+
* already call-local, so repeated calls across elements are idempotent.
|
|
1753
|
+
*
|
|
1754
|
+
* @param hookList the uponSanitize* hook array for this event
|
|
1755
|
+
* @param set the current ALLOWED_TAGS / ALLOWED_ATTR binding
|
|
1756
|
+
* @param defaultSet the per-instance DEFAULT_ALLOWED_* constant
|
|
1757
|
+
* @param setConfigSet the captured setConfig() binding, or null
|
|
1758
|
+
* @return a call-local clone if a hook is present and set is still shared,
|
|
1759
|
+
* else set unchanged
|
|
1760
|
+
*/
|
|
1761
|
+
const _forkSharedAllowlist = function _forkSharedAllowlist(hookList, set, defaultSet, setConfigSet) {
|
|
1762
|
+
if (hookList.length === 0) {
|
|
1763
|
+
return set;
|
|
1764
|
+
}
|
|
1765
|
+
return set === defaultSet || set === setConfigSet ? clone(set) : set;
|
|
1766
|
+
};
|
|
1644
1767
|
/**
|
|
1645
1768
|
* _sanitizeElements
|
|
1646
1769
|
*
|
|
@@ -1650,9 +1773,20 @@ var purify = {exports: {}};
|
|
|
1650
1773
|
* @param currentNode to check for permission to exist
|
|
1651
1774
|
* @return true if node was killed, false if left alive
|
|
1652
1775
|
*/
|
|
1653
|
-
|
|
1776
|
+
// eslint-disable-next-line complexity
|
|
1777
|
+
const _sanitizeElements = function _sanitizeElements(currentNode, root) {
|
|
1654
1778
|
/* Execute a hook if present */
|
|
1655
1779
|
_executeHooks(hooks.beforeSanitizeElements, currentNode, null);
|
|
1780
|
+
/* A hook may have detached the node - treat it as removed (see the
|
|
1781
|
+
detached-node comment after the uponSanitizeElement hook below). On
|
|
1782
|
+
the IN_PLACE path, neutralize the detached subtree first so a queued
|
|
1783
|
+
resource handler on it cannot fire in page scope after we return. */
|
|
1784
|
+
if (currentNode !== root && getParentNode(currentNode) === null) {
|
|
1785
|
+
if (IN_PLACE) {
|
|
1786
|
+
_neutralizeSubtree(currentNode);
|
|
1787
|
+
}
|
|
1788
|
+
return true;
|
|
1789
|
+
}
|
|
1656
1790
|
/* Check if element is clobbered or can clobber */
|
|
1657
1791
|
if (_isClobbered(currentNode)) {
|
|
1658
1792
|
_forceRemove(currentNode);
|
|
@@ -1660,11 +1794,47 @@ var purify = {exports: {}};
|
|
|
1660
1794
|
}
|
|
1661
1795
|
/* Now let's check the element's type and name */
|
|
1662
1796
|
const tagName = transformCaseFunc(getNodeName ? getNodeName(currentNode) : currentNode.nodeName);
|
|
1797
|
+
/* Close the pre-walk clone-guard's timing gap: an uponSanitizeElement
|
|
1798
|
+
hook may have been installed after that guard sampled the hook arrays
|
|
1799
|
+
(e.g. lazily from beforeSanitizeElements), leaving ALLOWED_TAGS still
|
|
1800
|
+
aliasing a shared binding that a widening hook would mutate by
|
|
1801
|
+
reference. Fork it before exposing it to the hook. */
|
|
1802
|
+
ALLOWED_TAGS = _forkSharedAllowlist(hooks.uponSanitizeElement, ALLOWED_TAGS, DEFAULT_ALLOWED_TAGS, SET_CONFIG_ALLOWED_TAGS);
|
|
1663
1803
|
/* Execute a hook if present */
|
|
1664
1804
|
_executeHooks(hooks.uponSanitizeElement, currentNode, {
|
|
1665
1805
|
tagName,
|
|
1666
1806
|
allowedTags: ALLOWED_TAGS
|
|
1667
1807
|
});
|
|
1808
|
+
/* A hook may have detached the node from the tree — a long-standing
|
|
1809
|
+
user pattern (issue #469; draw.io-style foreignObject filtering).
|
|
1810
|
+
Per the cached, unclobberable parentNode getter the node is
|
|
1811
|
+
genuinely out of the tree, so it can reach neither the serialized
|
|
1812
|
+
output nor an IN_PLACE live tree; treat it as removed and stop
|
|
1813
|
+
processing it. Without this guard, the unsafe-node / namespace
|
|
1814
|
+
checks below would call _forceRemove on a parentless node and hit
|
|
1815
|
+
the REPORT-3 fail-closed throw — which exists for nodes DOMPurify
|
|
1816
|
+
wants gone but *cannot* detach (clobbered / parentless roots), the
|
|
1817
|
+
opposite of a node that is already safely gone. The walk root is
|
|
1818
|
+
exempt: a detached IN_PLACE root is legitimate input and must still
|
|
1819
|
+
be fully sanitized, and a kill-decision on it must keep hitting the
|
|
1820
|
+
REPORT-3 throw. Nodes detached by hooks stay the hook's
|
|
1821
|
+
responsibility for placement: they are not recorded in
|
|
1822
|
+
DOMPurify.removed, so the post-walk IN_PLACE pass (which iterates
|
|
1823
|
+
DOMPurify.removed) does not reach them. But a hook-detached subtree
|
|
1824
|
+
can still hold a queued resource-event handler - e.g. an <img onload>
|
|
1825
|
+
that began loading when the caller built the live tree - which fires
|
|
1826
|
+
in page scope after sanitize returns even though the handler never
|
|
1827
|
+
reached the returned tree. That is the audit-5 F1 hazard, and the
|
|
1828
|
+
documented node.remove() hook pattern walks straight into it. So on
|
|
1829
|
+
the IN_PLACE path we neutralize the detached subtree inline here,
|
|
1830
|
+
stripping its non-allow-listed attributes before returning, exactly
|
|
1831
|
+
as the post-walk pass does for _forceRemove'd subtrees. */
|
|
1832
|
+
if (currentNode !== root && getParentNode(currentNode) === null) {
|
|
1833
|
+
if (IN_PLACE) {
|
|
1834
|
+
_neutralizeSubtree(currentNode);
|
|
1835
|
+
}
|
|
1836
|
+
return true;
|
|
1837
|
+
}
|
|
1668
1838
|
/* Remove mXSS vectors, processing instructions and risky comments */
|
|
1669
1839
|
if (_isUnsafeNode(currentNode, tagName)) {
|
|
1670
1840
|
_forceRemove(currentNode);
|
|
@@ -1672,7 +1842,22 @@ var purify = {exports: {}};
|
|
|
1672
1842
|
}
|
|
1673
1843
|
/* Remove element if anything forbids its presence */
|
|
1674
1844
|
if (FORBID_TAGS[tagName] || !(EXTRA_ELEMENT_HANDLING.tagCheck instanceof Function && EXTRA_ELEMENT_HANDLING.tagCheck(tagName)) && !ALLOWED_TAGS[tagName]) {
|
|
1675
|
-
|
|
1845
|
+
const removed = _sanitizeDisallowedNode(currentNode, tagName, root);
|
|
1846
|
+
/* A false return means the node is a custom element kept via
|
|
1847
|
+
CUSTOM_ELEMENT_HANDLING - the only keep path through
|
|
1848
|
+
_sanitizeDisallowedNode. Run afterSanitizeElements on it so the
|
|
1849
|
+
element-hook lifecycle matches normal allowlisted elements: a
|
|
1850
|
+
security policy applied in this hook (e.g. stripping an attribute
|
|
1851
|
+
from every surviving element) must not silently skip kept custom
|
|
1852
|
+
elements (GHSA-c2j3-45gr-mqc4). This mirrors the normal-element
|
|
1853
|
+
tail below - the hook runs, then the walker's subsequent
|
|
1854
|
+
_sanitizeAttributes pass sanitizes the element's attributes. The
|
|
1855
|
+
deliberately skipped namespace and fallback-tag removal checks stay
|
|
1856
|
+
skipped; they are removal decisions, not the hook contract. */
|
|
1857
|
+
if (removed === false) {
|
|
1858
|
+
_executeHooks(hooks.afterSanitizeElements, currentNode, null);
|
|
1859
|
+
}
|
|
1860
|
+
return removed;
|
|
1676
1861
|
}
|
|
1677
1862
|
/* Check whether element has a valid namespace.
|
|
1678
1863
|
Realm-safe check (GHSA-hpcv-96wg-7vj8): use the cached Node.prototype
|
|
@@ -1719,6 +1904,33 @@ var purify = {exports: {}};
|
|
|
1719
1904
|
if (FORBID_ATTR[lcName]) {
|
|
1720
1905
|
return false;
|
|
1721
1906
|
}
|
|
1907
|
+
/* Reject declarative-partial-updates patch-linkage attributes
|
|
1908
|
+
(https://github.com/WICG/declarative-partial-updates).
|
|
1909
|
+
Empirical note (Chrome 150, verified — see
|
|
1910
|
+
test/declarative-patch-probe-v3.html): expansion is NOT applied after
|
|
1911
|
+
sanitization. For the string path it fires during sanitize()'s own
|
|
1912
|
+
parse, so the walk sees and sanitizes the fully materialized expanded
|
|
1913
|
+
tree — teleports into MathML/SVG integration points included; a
|
|
1914
|
+
weaponized `<template for>`->`<img onerror>` comes back with the handler
|
|
1915
|
+
stripped. For the IN_PLACE path it fires on connection, before the walk.
|
|
1916
|
+
Either way DOMPurify is NOT blind to the patch.
|
|
1917
|
+
This removal is therefore defense-in-depth rather than the sole barrier:
|
|
1918
|
+
it prevents live linkage from surviving into the OUTPUT and re-expanding
|
|
1919
|
+
in the caller's context, and keeps behaviour deterministic if a future
|
|
1920
|
+
engine defers expansion. `for` is legitimate only on <label>/<output>;
|
|
1921
|
+
anywhere else (notably <template for>) it links the element to a patch
|
|
1922
|
+
target and teleports or removes an arbitrary DOM range by id/marker name.
|
|
1923
|
+
`patchsrc` fetches remote markup and is treated as a script-loading
|
|
1924
|
+
mechanism (CSP). Gated on SAFE_FOR_XML so the removal groups with the
|
|
1925
|
+
other structural-threat checks and stays overridable, consistent with
|
|
1926
|
+
the rest of the codebase. PI range markers are already removed by
|
|
1927
|
+
_isUnsafeNode. */
|
|
1928
|
+
if (SAFE_FOR_XML && lcName === 'patchsrc') {
|
|
1929
|
+
return false;
|
|
1930
|
+
}
|
|
1931
|
+
if (SAFE_FOR_XML && lcName === 'for' && lcTag !== 'label' && lcTag !== 'output') {
|
|
1932
|
+
return false;
|
|
1933
|
+
}
|
|
1722
1934
|
/* Make sure attribute cannot clobber */
|
|
1723
1935
|
if (SANITIZE_DOM && (lcName === 'id' || lcName === 'name') && (value in document || value in formElement)) {
|
|
1724
1936
|
return false;
|
|
@@ -1835,6 +2047,9 @@ var purify = {exports: {}};
|
|
|
1835
2047
|
if (!attributes || _isClobbered(currentNode)) {
|
|
1836
2048
|
return;
|
|
1837
2049
|
}
|
|
2050
|
+
/* Same lazy-install guard as uponSanitizeElement (see there): fork the
|
|
2051
|
+
attribute allowlist off its shared binding before a hook can see it. */
|
|
2052
|
+
ALLOWED_ATTR = _forkSharedAllowlist(hooks.uponSanitizeAttribute, ALLOWED_ATTR, DEFAULT_ALLOWED_ATTR, SET_CONFIG_ALLOWED_ATTR);
|
|
1838
2053
|
const hookEvent = {
|
|
1839
2054
|
attrName: '',
|
|
1840
2055
|
attrValue: '',
|
|
@@ -1928,7 +2143,7 @@ var purify = {exports: {}};
|
|
|
1928
2143
|
/* Execute a hook if present */
|
|
1929
2144
|
_executeHooks(hooks.uponSanitizeShadowNode, shadowNode, null);
|
|
1930
2145
|
/* Sanitize tags and elements */
|
|
1931
|
-
_sanitizeElements(shadowNode);
|
|
2146
|
+
_sanitizeElements(shadowNode, fragment);
|
|
1932
2147
|
/* Check attributes next */
|
|
1933
2148
|
_sanitizeAttributes(shadowNode);
|
|
1934
2149
|
/* Deep shadow DOM detected.
|
|
@@ -2119,6 +2334,11 @@ var purify = {exports: {}};
|
|
|
2119
2334
|
keep using and whose return value they ignore — unsanitized. REPORT-2. */
|
|
2120
2335
|
const inPlace = IN_PLACE && typeof dirty !== 'string' && _isNode(dirty);
|
|
2121
2336
|
if (inPlace) {
|
|
2337
|
+
/* Declarative-partial-updates / streaming pre-pass: sever every patch
|
|
2338
|
+
linkage across the live tree BEFORE the walk, so no patch can fire
|
|
2339
|
+
mid-walk and inject into an already-processed region. Runs first, so
|
|
2340
|
+
it also covers the forbidden/clobbered roots that throw below. */
|
|
2341
|
+
_neutralizePatchLinkage(dirty);
|
|
2122
2342
|
/* Do some early pre-sanitization to avoid unsafe root nodes.
|
|
2123
2343
|
Read nodeName through the cached prototype getter — a clobbering
|
|
2124
2344
|
child named "nodeName" on the form root would otherwise shadow
|
|
@@ -2128,6 +2348,9 @@ var purify = {exports: {}};
|
|
|
2128
2348
|
if (typeof nn === 'string') {
|
|
2129
2349
|
const tagName = transformCaseFunc(nn);
|
|
2130
2350
|
if (!ALLOWED_TAGS[tagName] || FORBID_TAGS[tagName]) {
|
|
2351
|
+
/* Fail closed on a live root: neutralize handlers/children before
|
|
2352
|
+
throwing, exactly as the mid-walk abort path does. */
|
|
2353
|
+
_neutralizeRoot(dirty);
|
|
2131
2354
|
throw typeErrorCreate('root node is forbidden and cannot be sanitized in-place');
|
|
2132
2355
|
}
|
|
2133
2356
|
}
|
|
@@ -2142,6 +2365,10 @@ var purify = {exports: {}};
|
|
|
2142
2365
|
the application unsanitized. Refuse to sanitize such a root
|
|
2143
2366
|
the same way we refuse a forbidden tag. GHSA-r47g-fvhr-h676. */
|
|
2144
2367
|
if (_isClobbered(dirty)) {
|
|
2368
|
+
/* Fail closed on a live clobbered root before throwing.
|
|
2369
|
+
_neutralizeRoot's reads are clobber-safe (cached getters); the
|
|
2370
|
+
form's non-clobbered descendants, e.g. an armed <img>, are scrubbed. */
|
|
2371
|
+
_neutralizeRoot(dirty);
|
|
2145
2372
|
throw typeErrorCreate('root node is clobbered and cannot be sanitized in-place');
|
|
2146
2373
|
}
|
|
2147
2374
|
/* Sanitize attached shadow roots before the main iterator runs.
|
|
@@ -2194,20 +2421,24 @@ var purify = {exports: {}};
|
|
|
2194
2421
|
_forceRemove(body.firstChild);
|
|
2195
2422
|
}
|
|
2196
2423
|
/* Get node iterator */
|
|
2197
|
-
const
|
|
2424
|
+
const walkRoot = inPlace ? dirty : body;
|
|
2198
2425
|
/* Now start iterating over the created document.
|
|
2199
2426
|
The walk runs inside an exception barrier (campaign-3 F2): a re-entrant
|
|
2200
2427
|
engine/custom-element mutation can detach a node mid-walk so
|
|
2201
2428
|
`_forceRemove`'s parentless guard throws, aborting the loop. Without the
|
|
2202
2429
|
barrier the caller's in-place tree would be left half-sanitized with the
|
|
2203
|
-
unvisited tail still armed.
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2430
|
+
unvisited tail still armed. _createNodeIterator itself is inside the
|
|
2431
|
+
barrier too: constructing the iterator dereferences the root's document,
|
|
2432
|
+
and any failure there (e.g. an exotic/clobbered root) must still fail
|
|
2433
|
+
closed rather than skip the neutralize. On any throw we fail closed -
|
|
2434
|
+
strip the in-place root bare - then rethrow so the existing throw
|
|
2435
|
+
contract is preserved. (String/DOM-copy paths never return the partial
|
|
2436
|
+
body, so the propagating throw is already fail-closed there.) */
|
|
2207
2437
|
try {
|
|
2438
|
+
const nodeIterator = _createNodeIterator(walkRoot);
|
|
2208
2439
|
while (currentNode = nodeIterator.nextNode()) {
|
|
2209
2440
|
/* Sanitize tags and elements */
|
|
2210
|
-
_sanitizeElements(currentNode);
|
|
2441
|
+
_sanitizeElements(currentNode, walkRoot);
|
|
2211
2442
|
/* Check attributes next */
|
|
2212
2443
|
_sanitizeAttributes(currentNode);
|
|
2213
2444
|
/* Shadow DOM detected, sanitize it.
|
|
@@ -2221,6 +2452,14 @@ var purify = {exports: {}};
|
|
|
2221
2452
|
} catch (error) {
|
|
2222
2453
|
if (inPlace) {
|
|
2223
2454
|
_neutralizeRoot(dirty);
|
|
2455
|
+
/* Nodes _forceRemove'd earlier in the aborted walk are already
|
|
2456
|
+
detached from the root, so _neutralizeRoot's subtree pass does not
|
|
2457
|
+
reach them. Defuse them too, mirroring the success-path loop below. */
|
|
2458
|
+
arrayForEach(DOMPurify.removed, entry => {
|
|
2459
|
+
if (entry.element) {
|
|
2460
|
+
_neutralizeSubtree(entry.element);
|
|
2461
|
+
}
|
|
2462
|
+
});
|
|
2224
2463
|
}
|
|
2225
2464
|
throw error;
|
|
2226
2465
|
}
|