{"version":3,"names":["interceptedClick","disabled","this","HTMLElement","prototype","click","call","onPointerDown","event","interactiveElement","target","preventDefault","nonBubblingWhenDisabledMouseEvents","onNonBubblingWhenDisabledMouseEvent","stopImmediatePropagation","captureOnlyOptions","capture","updateHostInteraction","component","el","setAttribute","contains","document","activeElement","blur","blockInteraction","restoreInteraction","removeAttribute","addInteractionListeners","element","addEventListener","forEach","removeInteractionListeners","removeEventListener","CSS","container","InteractiveContainer","children","h","class","inert"],"sources":["src/utils/interactive.tsx"],"sourcesContent":["import { JSXAttributes } from \"@stencil/core/internal\";\nimport { FunctionalComponent, h, VNode } from \"@stencil/core\";\n\nexport interface InteractiveComponent {\n /**\n * The host element.\n */\n readonly el: InteractiveHTMLElement;\n\n /**\n * When true, prevents user interaction.\n *\n * Notes:\n *\n * This prop should use the @Prop decorator and reflect.\n * The `disabled` Sass mixin must be added to the component's stylesheet.\n */\n disabled: boolean;\n}\n\n/**\n * Exported for testing purposes only.\n *\n * @internal\n */\nexport type InteractiveHTMLElement = HTMLElement & Pick;\n\nfunction interceptedClick(): void {\n const { disabled } = this as InteractiveHTMLElement;\n\n if (!disabled) {\n HTMLElement.prototype.click.call(this);\n }\n}\n\nfunction onPointerDown(event: PointerEvent): void {\n const interactiveElement = event.target as InteractiveHTMLElement;\n\n if (interactiveElement.disabled) {\n // prevent click from moving focus on host\n event.preventDefault();\n }\n}\n\nconst nonBubblingWhenDisabledMouseEvents = [\"mousedown\", \"mouseup\", \"click\"];\n\nfunction onNonBubblingWhenDisabledMouseEvent(event: MouseEvent): void {\n const interactiveElement = event.target as InteractiveHTMLElement;\n\n // prevent disallowed mouse events from being emitted on the disabled host (per https://github.com/whatwg/html/issues/5886)\n // ⚠ we generally avoid stopping propagation of events, but this is needed to adhere to the intended spec changes above ⚠\n if (interactiveElement.disabled) {\n event.stopImmediatePropagation();\n event.preventDefault();\n }\n}\n\nconst captureOnlyOptions = { capture: true } as const;\n\n/**\n * This helper updates the host element to prevent keyboard interaction on its subtree and sets the appropriate aria attribute for accessibility.\n *\n * This should be used in the `componentDidRender` lifecycle hook.\n *\n * **Notes**\n *\n * this util is not needed for simple components whose root element or elements are an interactive component (custom element or native control). For those cases, set the `disabled` props on the root components instead.\n * technically, users can override `tabindex` and restore keyboard navigation, but this will be considered user error\n *\n * @param component\n */\nexport function updateHostInteraction(component: InteractiveComponent): void {\n if (component.disabled) {\n component.el.setAttribute(\"aria-disabled\", \"true\");\n\n if (component.el.contains(document.activeElement)) {\n (document.activeElement as HTMLElement).blur();\n }\n\n blockInteraction(component);\n\n return;\n }\n\n restoreInteraction(component);\n\n component.el.removeAttribute(\"aria-disabled\");\n}\n\nfunction blockInteraction(component: InteractiveComponent): void {\n component.el.click = interceptedClick;\n addInteractionListeners(component.el);\n}\n\nfunction addInteractionListeners(element: HTMLElement): void {\n element.addEventListener(\"pointerdown\", onPointerDown, captureOnlyOptions);\n nonBubblingWhenDisabledMouseEvents.forEach((event) =>\n element.addEventListener(event, onNonBubblingWhenDisabledMouseEvent, captureOnlyOptions),\n );\n}\n\nfunction restoreInteraction(component: InteractiveComponent): void {\n delete component.el.click; // fallback on HTMLElement.prototype.click\n removeInteractionListeners(component.el);\n}\n\nfunction removeInteractionListeners(element: HTMLElement): void {\n element.removeEventListener(\"pointerdown\", onPointerDown, captureOnlyOptions);\n nonBubblingWhenDisabledMouseEvents.forEach((event) =>\n element.removeEventListener(event, onNonBubblingWhenDisabledMouseEvent, captureOnlyOptions),\n );\n}\n\nexport interface InteractiveContainerProps extends JSXAttributes {\n disabled: boolean;\n}\n\nexport const CSS = {\n container: \"interaction-container\",\n};\n\nexport const InteractiveContainer: FunctionalComponent = (\n { disabled },\n children: VNode[],\n): VNode => (\n
\n {...children}\n
\n);\n"],"mappings":";;;;;oCA2BA,SAASA,IACP,MAAMC,SAAEA,GAAaC,KAErB,IAAKD,EAAU,CACbE,YAAYC,UAAUC,MAAMC,KAAKJ,K,CAErC,CAEA,SAASK,EAAcC,GACrB,MAAMC,EAAqBD,EAAME,OAEjC,GAAID,EAAmBR,SAAU,CAE/BO,EAAMG,gB,CAEV,CAEA,MAAMC,EAAqC,CAAC,YAAa,UAAW,SAEpE,SAASC,EAAoCL,GAC3C,MAAMC,EAAqBD,EAAME,OAIjC,GAAID,EAAmBR,SAAU,CAC/BO,EAAMM,2BACNN,EAAMG,gB,CAEV,CAEA,MAAMI,EAAqB,CAAEC,QAAS,M,SActBC,EAAsBC,GACpC,GAAIA,EAAUjB,SAAU,CACtBiB,EAAUC,GAAGC,aAAa,gBAAiB,QAE3C,GAAIF,EAAUC,GAAGE,SAASC,SAASC,eAAgB,CAChDD,SAASC,cAA8BC,M,CAG1CC,EAAiBP,GAEjB,M,CAGFQ,EAAmBR,GAEnBA,EAAUC,GAAGQ,gBAAgB,gBAC/B,CAEA,SAASF,EAAiBP,GACxBA,EAAUC,GAAGd,MAAQL,EACrB4B,EAAwBV,EAAUC,GACpC,CAEA,SAASS,EAAwBC,GAC/BA,EAAQC,iBAAiB,cAAevB,EAAeQ,GACvDH,EAAmCmB,SAASvB,GAC1CqB,EAAQC,iBAAiBtB,EAAOK,EAAqCE,IAEzE,CAEA,SAASW,EAAmBR,UACnBA,EAAUC,GAAGd,MACpB2B,EAA2Bd,EAAUC,GACvC,CAEA,SAASa,EAA2BH,GAClCA,EAAQI,oBAAoB,cAAe1B,EAAeQ,GAC1DH,EAAmCmB,SAASvB,GAC1CqB,EAAQI,oBAAoBzB,EAAOK,EAAqCE,IAE5E,CAMO,MAAMmB,EAAM,CACjBC,UAAW,yB,MAGAC,EAAuE,EAChFnC,YACFoC,IAEAC,EAAA,OAAKC,MAAOL,EAAIC,UAAWK,MAAOvC,MAC5BoC,U","ignoreList":[]}