JezK
Edit File: sc-drawer2.js.map
{"file":"sc-drawer2.js","mappings":";;;;AAAA,MAAM,WAAW,GAAG,+9EAA+9E,CAAC;AACp/E,uBAAe,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YCyOJ,UAAE;;;;;;;;;;;;;;;;;;;AAuBxB;AACA;;;;;;;AAQA;;;;;;;AAQA;AACA;AACA;;;;;;;;;;;AAYA;;;;;;;;;;;AAYA;AACA;;;;;;;AAQA;;;;;;;AAQA;AACA;AACA;;;;;;;;;;;AAYA;;;;;;;;;;;AAYA;AACA;;;;AAKA;AACA;;;;AAKA;;;;;;;;;;;;;;;;;;;;;;;;;","names":[],"sources":["src/components/ui/sc-drawer/sc-drawer.css?tag=sc-drawer&encapsulation=shadow","src/components/ui/sc-drawer/sc-drawer.tsx"],"sourcesContent":[":host {\n display: contents;\n}\n.drawer {\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n overflow: hidden;\n font-family: var(--sc-font-sans);\n font-weight: var(--sc-font-weight-normal);\n}\n.drawer--contained {\n position: absolute;\n z-index: initial;\n}\n.drawer--fixed {\n position: fixed;\n z-index: var(--sc-z-index-drawer);\n}\n.drawer__panel {\n position: absolute;\n display: flex;\n flex-direction: column;\n z-index: 2;\n max-width: 100%;\n max-height: 100%;\n background-color: var(--sc-panel-background-color);\n box-shadow: var(--sc-shadow-x-large);\n transition: var(--sc-transition-medium) transform;\n overflow: auto;\n pointer-events: all;\n}\n.drawer__panel:focus {\n outline: none;\n}\n.drawer--top .drawer__panel {\n top: 0;\n right: auto;\n bottom: auto;\n left: 0;\n width: 100%;\n height: var(--sc-drawer-size, 400px);\n}\n.drawer--end .drawer__panel {\n top: 0;\n inset-inline-end: 0;\n bottom: auto;\n inset-inline-start: auto;\n width: 100%;\n max-width: var(--sc-drawer-size, 400px);\n height: 100%;\n}\n.drawer--bottom .drawer__panel {\n top: auto;\n right: auto;\n bottom: 0;\n left: 0;\n width: 100%;\n height: var(--sc-drawer-size, 400px);\n}\n.drawer--start .drawer__panel {\n top: 0;\n inset-inline-end: auto;\n bottom: auto;\n inset-inline-start: 0;\n width: var(--sc-drawer-size, 400px);\n height: 100%;\n}\n.header__sticky {\n position: sticky;\n top: 0;\n z-index: 10;\n background: #fff;\n}\n.drawer__header {\n display: flex;\n align-items: center;\n padding: var(--sc-drawer-header-spacing);\n border-bottom: var(--sc-drawer-border);\n}\n\n.drawer__title {\n flex: 1 1 auto;\n font: inherit;\n font-size: var(--sc-font-size-large);\n line-height: var(--sc-line-height-dense);\n margin: 0;\n}\n.drawer__close {\n flex: 0 0 auto;\n display: flex;\n align-items: center;\n font-size: var(--sc-font-size-x-large);\n color: var(--sc-color-gray-500);\n cursor: pointer;\n}\n.drawer__body {\n flex: 1 1 auto;\n}\n\n.drawer--has-footer .drawer__footer {\n border-top: var(--sc-drawer-border);\n padding: var(--sc-drawer-footer-spacing);\n\n &.is-sticky {\n position: sticky;\n bottom: 0;\n background: #fff;\n }\n}\n\n.drawer__overlay {\n display: block;\n position: fixed;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n background-color: var(--sc-overlay-background-color);\n pointer-events: all;\n}\n.drawer--contained .drawer__overlay {\n position: absolute;\n}\n","import { Component, Element, Event, EventEmitter, h, Method, Prop, Watch } from '@stencil/core';\nimport { __ } from '@wordpress/i18n';\n\nimport { animateTo, stopAnimations } from '../../../functions/animate';\nimport { getAnimation, setDefaultAnimation } from '../../../functions/animation-registry';\n\n@Component({\n tag: 'sc-drawer',\n styleUrl: 'sc-drawer.css',\n shadow: true,\n})\nexport class ScDrawer {\n @Element() el: HTMLScDrawerElement;\n private drawer: HTMLElement;\n private panel: HTMLElement;\n private overlay: HTMLElement;\n\n private originalTrigger: HTMLElement | null;\n\n @Event({ cancelable: true }) scInitialFocus: EventEmitter<void>;\n @Event({ cancelable: true }) scRequestClose: EventEmitter<'close-button' | 'keyboard' | 'overlay' | 'method'>;\n @Event() scShow: EventEmitter<void>;\n @Event() scHide: EventEmitter<void>;\n @Event() scAfterShow: EventEmitter<void>;\n @Event() scAfterHide: EventEmitter<void>;\n\n /** Indicates whether or not the drawer is open. You can use this in lieu of the show/hide methods. */\n @Prop({ reflect: true }) open: boolean = false;\n\n /**\n * The drawer's label as displayed in the header. You should always include a relevant label even when using\n * `no-header`, as it is required for proper accessibility.\n */\n @Prop({ reflect: true }) label = '';\n\n /** The direction from which the drawer will open. */\n @Prop({ reflect: true }) placement: 'top' | 'end' | 'bottom' | 'start' = 'end';\n\n /**\n * By default, the drawer slides out of its containing block (usually the viewport). To make the drawer slide out of\n * its parent element, set this prop and add `position: relative` to the parent.\n */\n @Prop({ reflect: true }) contained: boolean = false;\n\n /**\n * Removes the header. This will also remove the default close button, so please ensure you provide an easy,\n * accessible way for users to dismiss the drawer.\n */\n @Prop({ attribute: 'no-header', reflect: true }) noHeader: boolean = false;\n\n /** Sticky drawer header */\n @Prop() stickyHeader: boolean = false;\n\n /** Sticky drawer footer */\n @Prop() stickyFooter: boolean = false;\n\n componentDidLoad() {\n this.drawer.hidden = !this.open;\n if (this.open && !this.contained) {\n this.lockBodyScrolling();\n }\n this.handleOpenChange();\n }\n\n disconnectedCallback() {\n this.unLockBodyScrolling();\n }\n\n lockBodyScrolling() {\n document.body.classList.add('sc-scroll-lock');\n }\n\n unLockBodyScrolling() {\n document.body.classList.remove('sc-scroll-lock');\n }\n\n /** Shows the drawer. */\n async show() {\n if (this.open) {\n return undefined;\n }\n this.open = true;\n }\n\n /** Hides the drawer */\n async hide() {\n if (!this.open) {\n return undefined;\n }\n this.open = false;\n }\n\n private getDirection(): 'ltr' | 'rtl' {\n return getComputedStyle(this.el).direction === 'rtl' ? 'rtl' : 'ltr';\n }\n\n @Method()\n async requestClose(source: 'close-button' | 'keyboard' | 'overlay' | 'method' = 'method') {\n const slRequestClose = this.scRequestClose.emit(source);\n\n if (slRequestClose.defaultPrevented) {\n const animation = getAnimation(this.el, 'drawer.denyClose', { dir: this.getDirection() });\n animateTo(this.panel, animation.keyframes, animation.options);\n return;\n }\n\n this.hide();\n }\n\n handleKeyDown(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n event.stopPropagation();\n this.requestClose('keyboard');\n }\n }\n\n @Watch('open')\n async handleOpenChange() {\n if (this.open) {\n this.scShow.emit();\n this.originalTrigger = document.activeElement as HTMLElement;\n\n // Lock body scrolling only if the drawer isn't contained\n if (!this.contained) {\n this.lockBodyScrolling();\n }\n\n // When the drawer is shown, Safari will attempt to set focus on whatever element has autofocus. This causes the\n // drawer's animation to jitter, so we'll temporarily remove the attribute, call `focus({ preventScroll: true })`\n // ourselves, and add the attribute back afterwards.\n //\n // Related: https://github.com/shoelace-style/shoelace/issues/693\n //\n const autoFocusTarget = this.el.querySelector('[autofocus]');\n if (autoFocusTarget) {\n autoFocusTarget.removeAttribute('autofocus');\n }\n\n await Promise.all([stopAnimations(this.drawer), stopAnimations(this.overlay)]);\n this.drawer.hidden = false;\n\n // Set initial focus\n requestAnimationFrame(() => {\n const slInitialFocus = this.scInitialFocus.emit();\n\n if (!slInitialFocus.defaultPrevented) {\n // Set focus to the autofocus target and restore the attribute\n if (autoFocusTarget) {\n (autoFocusTarget as HTMLInputElement).focus({ preventScroll: true });\n } else {\n this.panel.focus({ preventScroll: true });\n }\n }\n\n // Restore the autofocus attribute\n if (autoFocusTarget) {\n autoFocusTarget.setAttribute('autofocus', '');\n }\n });\n\n const dir = this.getDirection();\n const panelAnimation = getAnimation(this.el, `drawer.show${this.placement.charAt(0).toUpperCase() + this.placement.slice(1)}`, { dir });\n const overlayAnimation = getAnimation(this.el, 'drawer.overlay.show', { dir });\n await Promise.all([animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options), animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options)]);\n\n this.scAfterShow.emit();\n } else {\n // Hide\n this.scHide.emit();\n this.unLockBodyScrolling();\n\n await Promise.all([stopAnimations(this.drawer), stopAnimations(this.overlay)]);\n const dir = this.getDirection();\n const panelAnimation = getAnimation(this.el, `drawer.hide${this.placement.charAt(0).toUpperCase() + this.placement.slice(1)}`, { dir });\n const overlayAnimation = getAnimation(this.el, 'drawer.overlay.hide', { dir });\n await Promise.all([animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options), animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options)]);\n\n this.drawer.hidden = true;\n\n // Restore focus to the original trigger\n const trigger = this.originalTrigger;\n if (typeof trigger?.focus === 'function') {\n setTimeout(() => trigger.focus());\n }\n\n this.scAfterHide.emit();\n }\n }\n\n render() {\n return (\n <div\n part=\"base\"\n class={{\n 'drawer': true,\n 'drawer--open': this.open,\n 'drawer--top': this.placement === 'top',\n 'drawer--end': this.placement === 'end',\n 'drawer--bottom': this.placement === 'bottom',\n 'drawer--start': this.placement === 'start',\n 'drawer--contained': this.contained,\n 'drawer--fixed': !this.contained,\n 'drawer--has-footer': this.el.querySelector('[slot=\"footer\"]') !== null,\n }}\n ref={el => (this.drawer = el as HTMLElement)}\n onKeyDown={(e: KeyboardEvent) => this.handleKeyDown(e)}\n >\n <div part=\"overlay\" class=\"drawer__overlay\" onClick={() => this.requestClose('overlay')} tabindex=\"-1\" ref={el => (this.overlay = el as HTMLElement)}></div>\n <div\n part=\"panel\"\n class=\"drawer__panel\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-hidden={this.open ? 'false' : 'true'}\n aria-label={this.noHeader ? this.label : undefined}\n aria-labelledby={!this.noHeader ? 'title' : undefined}\n tabindex=\"0\"\n ref={el => (this.panel = el as HTMLElement)}\n >\n {!this.noHeader && (\n <header part=\"header\" class={this.stickyHeader ? 'header__sticky' : ''}>\n <slot name=\"header\">\n <div class=\"drawer__header\">\n <h2 part=\"title\" class=\"drawer__title\" id=\"title\">\n {/** If there's no label, use an invisible character to prevent the header from collapsing */}\n <slot name=\"label\">{this.label.length > 0 ? this.label : ' '} </slot>\n </h2>\n <sc-icon\n part=\"close-button\"\n exportparts=\"base:close-button__base\"\n class=\"drawer__close\"\n name=\"x\"\n label={\n /** translators: Close this modal window. */\n __('Close', 'surecart')\n }\n onClick={() => this.requestClose('close-button')}\n ></sc-icon>\n </div>\n </slot>\n </header>\n )}\n <footer part=\"header-suffix\" class=\"drawer__header-suffix\">\n <slot name=\"header-suffix\"></slot>\n </footer>\n <div part=\"body\" class=\"drawer__body\">\n <slot></slot>\n </div>\n <footer part=\"footer\" class={this.stickyFooter ? 'drawer__footer is-sticky' : 'drawer__footer'}>\n <slot name=\"footer\"></slot>\n </footer>\n </div>\n </div>\n );\n }\n}\n\n// Top\nsetDefaultAnimation('drawer.showTop', {\n keyframes: [\n { opacity: 0, transform: 'translateY(-100%)' },\n { opacity: 1, transform: 'translateY(0)' },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('drawer.hideTop', {\n keyframes: [\n { opacity: 1, transform: 'translateY(0)' },\n { opacity: 0, transform: 'translateY(-100%)' },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\n// End — in LTR the panel rests on the right and slides in from the right (translateX 100%). In RTL the panel rests on\n// the left (because `inset-inline-end` flips), so it must slide in from the left (translateX -100%).\nsetDefaultAnimation('drawer.showEnd', {\n keyframes: [\n { opacity: 0, transform: 'translateX(100%)' },\n { opacity: 1, transform: 'translateX(0)' },\n ],\n rtlKeyframes: [\n { opacity: 0, transform: 'translateX(-100%)' },\n { opacity: 1, transform: 'translateX(0)' },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('drawer.hideEnd', {\n keyframes: [\n { opacity: 1, transform: 'translateX(0)' },\n { opacity: 0, transform: 'translateX(100%)' },\n ],\n rtlKeyframes: [\n { opacity: 1, transform: 'translateX(0)' },\n { opacity: 0, transform: 'translateX(-100%)' },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\n// Bottom\nsetDefaultAnimation('drawer.showBottom', {\n keyframes: [\n { opacity: 0, transform: 'translateY(100%)' },\n { opacity: 1, transform: 'translateY(0)' },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('drawer.hideBottom', {\n keyframes: [\n { opacity: 1, transform: 'translateY(0)' },\n { opacity: 0, transform: 'translateY(100%)' },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\n// Start — mirrors End. In LTR slides in from the left; in RTL the panel rests on the right (because `inset-inline-start`\n// flips), so it must slide in from the right.\nsetDefaultAnimation('drawer.showStart', {\n keyframes: [\n { opacity: 0, transform: 'translateX(-100%)' },\n { opacity: 1, transform: 'translateX(0)' },\n ],\n rtlKeyframes: [\n { opacity: 0, transform: 'translateX(100%)' },\n { opacity: 1, transform: 'translateX(0)' },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('drawer.hideStart', {\n keyframes: [\n { opacity: 1, transform: 'translateX(0)' },\n { opacity: 0, transform: 'translateX(-100%)' },\n ],\n rtlKeyframes: [\n { opacity: 1, transform: 'translateX(0)' },\n { opacity: 0, transform: 'translateX(100%)' },\n ],\n options: { duration: 250, easing: 'ease' },\n});\n\n// Deny close\nsetDefaultAnimation('drawer.denyClose', {\n keyframes: [{ transform: 'scale(1)' }, { transform: 'scale(1.01)' }, { transform: 'scale(1)' }],\n options: { duration: 250 },\n});\n\n// Overlay\nsetDefaultAnimation('drawer.overlay.show', {\n keyframes: [{ opacity: 0 }, { opacity: 1 }],\n options: { duration: 250, easing: 'ease' },\n});\n\nsetDefaultAnimation('drawer.overlay.hide', {\n keyframes: [{ opacity: 1 }, { opacity: 0 }],\n options: { duration: 250, easing: 'ease' },\n});\n"],"version":3}