{"version":3,"names":["AtomicFocusTrap","this","active","shouldHideSelf","scope","document","body","hiddenElements","hide","element","hasAttribute","tagName","toLowerCase","setAttribute","push","showAll","el","pop","removeAttribute","hideSiblingsRecursively","parent","getParent","Array","from","children","forEach","sibling","assignedSlot","isAncestorOf","host","showSelf","parentToHide","hideSelf","onDeactivated","isInitialLoad","defer","_a","source","focus","onActivated","getFirstFocusableDescendant","activeChanged","wasActive","onFocusChanged","e","elementIsPartOfHost","focusedElement","elementIsPartOfScope","target","getFocusedElement","connectedCallback","disconnectedCallback","container","atomicModalCss","AtomicModal","fullscreen","isOpen","close","boundary","wasEverOpened","headerId","randomID","currentWatchToggleOpenExecution","updateBreakpoints","once","watchToggleOpen","watchToggleOpenExecution","modalOpenedClass","classList","add","bindings","interfaceElement","waitForAnimationEnded","focusTrap","remove","isIOS","handleCloseOnEscape","key","Promise","resolve","listenOnce","animatableContainer","getClasses","classes","onWindowTouchMove","preventDefault","componentDidLoad","render","Content","h","part","class","onAnimationEnd","animationEnded","emit","ref","id","name","addEventListener","stopPropagation","passive","Host","join","onClick","currentTarget","role","toString","__decorate","InitializeBindings"],"sources":["src/components/common/atomic-focus-trap.tsx","src/components/common/atomic-modal/atomic-modal.pcss?tag=atomic-modal&encapsulation=shadow","src/components/common/atomic-modal/atomic-modal.tsx"],"sourcesContent":["import {Component, Element, Listen, Prop, Watch} from '@stencil/core';\nimport {getFirstFocusableDescendant} from '../../utils/accessibility-utils';\nimport {\n isAncestorOf,\n defer,\n getFocusedElement,\n getParent,\n} from '../../utils/utils';\n\n/**\n * @internal\n */\n@Component({\n tag: 'atomic-focus-trap',\n shadow: false,\n})\nexport class AtomicFocusTrap {\n @Element() private host!: HTMLElement;\n @Prop() public active = false;\n /**\n * The source to focus when the focus trap becomes inactive.\n */\n @Prop({mutable: true}) source?: HTMLElement;\n /**\n * The container to hide from the tabindex and accessibility DOM when the focus trap is inactive.\n */\n @Prop({mutable: true}) container?: HTMLElement;\n\n /**\n * Whether the element should be hidden from screen readers & not interactive with the tab, when not active.\n */\n @Prop() shouldHideSelf = true;\n\n /**\n * The common ancestor of the focus trap and of all the elements that should be inaccessible when inside the focus trap.\n */\n @Prop() scope = document.body;\n\n private readonly hiddenElements: Element[] = [];\n\n hide(element: Element) {\n // aria-hidden -> already hidden\n // aria-live or atomic-aria-live -> must not be hidden otherwise it won't announce dynamic changes in the live region\n if (\n element.hasAttribute('aria-hidden') ||\n element.hasAttribute('aria-live') ||\n element.tagName.toLowerCase() === 'atomic-aria-live'\n ) {\n return;\n }\n element.setAttribute('aria-hidden', 'true');\n this.hiddenElements.push(element);\n }\n\n showAll() {\n let el: Element | undefined;\n while ((el = this.hiddenElements.pop())) {\n el.removeAttribute('aria-hidden');\n }\n }\n\n hideSiblingsRecursively(element: Element | ShadowRoot) {\n const parent = getParent(element);\n if (parent === null) {\n return;\n }\n Array.from(parent.children as HTMLCollection).forEach((sibling) => {\n if (sibling === element) {\n return;\n }\n if (\n sibling.assignedSlot &&\n isAncestorOf(this.host, sibling.assignedSlot)\n ) {\n return;\n }\n this.hide(sibling);\n });\n if (parent !== this.scope) {\n this.hideSiblingsRecursively(parent);\n }\n }\n\n showSelf() {\n this.parentToHide.removeAttribute('aria-hidden');\n this.parentToHide.removeAttribute('tabindex');\n }\n\n hideSelf() {\n if (this.shouldHideSelf) {\n this.parentToHide.setAttribute('aria-hidden', 'true');\n this.parentToHide.setAttribute('tabindex', '-1');\n }\n }\n\n async onDeactivated(isInitialLoad: boolean) {\n this.showAll();\n if (!isInitialLoad) {\n await defer();\n this.source?.focus();\n }\n this.hideSelf();\n }\n\n async onActivated(isInitialLoad: boolean) {\n this.showSelf();\n if (!isInitialLoad) {\n await defer();\n getFirstFocusableDescendant(this.host)?.focus();\n }\n this.hideSiblingsRecursively(this.host);\n }\n\n @Watch('active')\n async activeChanged(active: boolean, wasActive: boolean) {\n const isInitialLoad = active === wasActive;\n if (active) {\n await this.onActivated(isInitialLoad);\n } else {\n await this.onDeactivated(isInitialLoad);\n }\n }\n\n @Listen('focusin', {target: 'document'})\n onFocusChanged(e: FocusEvent) {\n const elementIsPartOfHost = (focusedElement: Element | ShadowRoot) =>\n isAncestorOf(this.host, focusedElement);\n\n const elementIsPartOfScope = (focusedElement: Element | ShadowRoot) =>\n isAncestorOf(this.scope, focusedElement);\n\n if (!e.target || !this.active) {\n return;\n }\n\n const focusedElement = getFocusedElement();\n\n if (\n focusedElement &&\n (elementIsPartOfHost(focusedElement) ||\n !elementIsPartOfScope(focusedElement))\n ) {\n return;\n }\n\n getFirstFocusableDescendant(this.host)?.focus();\n }\n\n connectedCallback() {\n this.activeChanged(this.active, this.active);\n }\n\n disconnectedCallback() {\n this.showAll();\n }\n\n private get parentToHide() {\n return this.container ?? this.host;\n }\n}\n","@import '../../../global/global.pcss';\n\n[part='backdrop'] {\n @apply pointer-events-none;\n}\n\natomic-focus-trap {\n @apply contents;\n}\n\n[part='container'] {\n @apply overflow-hidden;\n grid-area: modal;\n}\n\n.animate-scaleUpModalIPX[part='container'] {\n @apply rounded shadow;\n}\n\n:host(.open) {\n [part='backdrop'] {\n @apply pointer-events-auto;\n }\n}\n\n:host(.open.dialog) {\n [part='backdrop'] {\n background-color: rgba(40, 40, 40, 0.8);\n }\n}\n\n:host(.dialog) {\n [part='backdrop'] {\n @apply grid p-6;\n transition: background-color 500ms ease-in-out;\n\n grid-template-areas:\n '. . .'\n '. modal .'\n '. . .';\n\n grid-template-columns: 1fr min(30rem, 100%) 1fr;\n grid-template-rows: 1fr auto 3fr;\n }\n\n [part='container'] {\n @apply rounded shadow;\n }\n\n [part='header-wrapper'] {\n @apply px-6 py-4;\n }\n\n [part='header'] {\n @apply font-bold;\n }\n\n [part='body-wrapper'] {\n @apply p-6;\n }\n\n [part='footer-wrapper'] {\n @apply bg-neutral-light;\n padding: 1rem 1.125rem;\n }\n}\n\n:host(.fullscreen) {\n [part='container'] {\n @apply absolute inset-0;\n }\n\n [part='header-wrapper'] {\n @apply p-6;\n }\n\n [part='body-wrapper'] {\n @apply px-6 pt-8 pb-5;\n }\n\n [part='footer-wrapper'] {\n @apply shadow-t-lg px-6 py-4;\n }\n}\n","import {\n Component,\n h,\n State,\n Prop,\n Element,\n Watch,\n Event,\n EventEmitter,\n Host,\n Listen,\n} from '@stencil/core';\nimport {isIOS} from '../../../utils/device-utils';\nimport {listenOnce} from '../../../utils/event-utils';\nimport {\n InitializableComponent,\n InitializeBindings,\n} from '../../../utils/initialization-utils';\nimport {updateBreakpoints} from '../../../utils/replace-breakpoint';\nimport {once, randomID} from '../../../utils/utils';\nimport {AnyBindings} from '../interface/bindings';\n\n/**\n * When the modal is opened, the class `atomic-modal-opened` is added to the interfaceElement and the body, allowing further customization.\n *\n * @part backdrop - The transparent backdrop hiding the content behind the modal.\n * @part container - The modal's outermost container with the outline and background.\n * @part header-wrapper - The wrapper around the header.\n * @part header - The header at the top of the modal.\n * @part header-ruler - The horizontal ruler underneath the header.\n * @part body-wrapper - The wrapper around the body.\n * @part body - The body of the modal, between the header and the footer.\n * @part footer-wrapper - The wrapper with a shadow or background color around the footer.\n * @part footer - The footer at the bottom of the modal.\n * @internal\n */\n@Component({\n tag: 'atomic-modal',\n styleUrl: 'atomic-modal.pcss',\n shadow: true,\n})\nexport class AtomicModal implements InitializableComponent<AnyBindings> {\n @InitializeBindings() public bindings!: AnyBindings;\n @Element() public host!: HTMLElement;\n\n @State() public error!: Error;\n\n @Prop({reflect: true, mutable: true}) fullscreen = false;\n @Prop({mutable: true}) source?: HTMLElement;\n /**\n * The container to hide from the tabindex and accessibility DOM when the modal is closed.\n */\n @Prop({mutable: true}) container?: HTMLElement;\n @Prop({reflect: true, mutable: true}) isOpen = false;\n @Prop({mutable: true}) close: () => void = () => (this.isOpen = false);\n @Prop({reflect: true}) scope?: HTMLElement;\n /**\n * Whether to display the open and close animations over the entire page or the atomic-modal only.\n */\n @Prop({reflect: true}) boundary: 'page' | 'element' = 'page';\n\n @Event() animationEnded!: EventEmitter<never>;\n\n private wasEverOpened = false;\n private headerId = randomID('atomic-modal-header-');\n private focusTrap?: HTMLAtomicFocusTrapElement;\n private animatableContainer?: HTMLElement;\n private currentWatchToggleOpenExecution = 0;\n\n @Watch('isOpen')\n async watchToggleOpen(isOpen: boolean) {\n const watchToggleOpenExecution = ++this.currentWatchToggleOpenExecution;\n const modalOpenedClass = 'atomic-modal-opened';\n\n if (isOpen) {\n this.wasEverOpened = true;\n //TODO: remove the addition of a class to the body in atomicV3\n document.body.classList.add(modalOpenedClass);\n this.bindings.interfaceElement.classList.add(modalOpenedClass);\n await this.waitForAnimationEnded();\n if (watchToggleOpenExecution !== this.currentWatchToggleOpenExecution) {\n return;\n }\n this.focusTrap!.active = true;\n } else {\n //TODO: remove the removal of a class to the body in atomicV3\n document.body.classList.remove(modalOpenedClass);\n this.bindings.interfaceElement.classList.remove(modalOpenedClass);\n if (isIOS()) {\n await this.waitForAnimationEnded();\n }\n if (watchToggleOpenExecution !== this.currentWatchToggleOpenExecution) {\n return;\n }\n this.focusTrap!.active = false;\n }\n }\n\n @Listen('keyup', {target: 'body'})\n handleCloseOnEscape(e: KeyboardEvent) {\n if (e.key?.toLowerCase() === 'escape') {\n this.close();\n }\n }\n\n private waitForAnimationEnded() {\n // The focus trap focuses its first child when active. It cannot do that while an animation is ongoing.\n return new Promise((resolve) =>\n listenOnce(this.animatableContainer!, 'animationend', resolve)\n );\n }\n\n private getClasses() {\n const classes: string[] = [];\n if (this.isOpen) {\n classes.push('open');\n }\n if (this.fullscreen) {\n classes.push('fullscreen');\n } else {\n classes.push('dialog');\n }\n return classes;\n }\n\n @Listen('touchmove', {passive: false})\n onWindowTouchMove(e: Event) {\n this.isOpen && e.preventDefault();\n }\n\n public componentDidLoad() {\n this.watchToggleOpen(this.isOpen);\n }\n\n private updateBreakpoints = once(() => updateBreakpoints(this.host));\n\n public render() {\n this.updateBreakpoints();\n\n const Content = () => (\n <article\n part=\"container\"\n class={`flex flex-col justify-between bg-background text-on-background\n ${this.isOpen ? 'animate-scaleUpModal' : 'animate-slideDownModal'}\n ${this.wasEverOpened ? '' : 'invisible'}`}\n onAnimationEnd={() => this.animationEnded.emit()}\n ref={(ref) => (this.animatableContainer = ref)}\n >\n <header part=\"header-wrapper\" class=\"flex flex-col items-center\">\n <div\n part=\"header\"\n class=\"flex justify-between text-xl w-full max-w-lg\"\n id={this.headerId}\n >\n <slot name=\"header\"></slot>\n </div>\n </header>\n <hr part=\"header-ruler\" class=\"border-neutral\"></hr>\n <div\n part=\"body-wrapper\"\n class=\"overflow-auto grow flex flex-col items-center w-full\"\n >\n <div\n part=\"body\"\n class=\"w-full max-w-lg\"\n ref={(element) =>\n element?.addEventListener(\n 'touchmove',\n (e) => this.isOpen && e.stopPropagation(),\n {passive: false}\n )\n }\n >\n <slot name=\"body\"></slot>\n </div>\n </div>\n <footer\n part=\"footer-wrapper\"\n class=\"border-neutral border-t bg-background z-10 flex flex-col items-center w-full\"\n >\n <div part=\"footer\" class=\"w-full max-w-lg\">\n <slot name=\"footer\"></slot>\n </div>\n </footer>\n </article>\n );\n\n return (\n <Host class={this.getClasses().join(' ')}>\n <div\n part=\"backdrop\"\n class={`\n ${this.boundary === 'page' ? 'fixed' : 'absolute'}\n left-0 top-0 right-0 bottom-0 z-[9999]\n `}\n onClick={(e) => e.target === e.currentTarget && this.close()}\n >\n <atomic-focus-trap\n role=\"dialog\"\n aria-modal={this.isOpen.toString()}\n aria-labelledby={this.headerId}\n source={this.source}\n container={this.container ?? this.host}\n ref={(ref) => (this.focusTrap = ref)}\n scope={this.scope}\n >\n <Content />\n </atomic-focus-trap>\n </div>\n </Host>\n );\n }\n}\n"],"mappings":"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"}