JezK
Edit File: sc-popover.cjs.entry.js.map
{"file":"sc-popover.entry.cjs.js","mappings":";;;;;;;;AAAA,MAAM,YAAY,GAAG,qzDAAqzD,CAAC;AAC30D,wBAAe,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBCoKjB,UAAE;;;;;;;;;;;;;;;sBAeF,UAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;oLA4DU,UAAE,o2BAuBI,UAAE;;;;;;;;;;;","names":[],"sources":["src/components/ui/popover/sc-popover.scss?tag=sc-popover&encapsulation=shadow","src/components/ui/popover/sc-popover.tsx"],"sourcesContent":[":host {\n display: inline-block;\n --panel-height: 75vh;\n}\n\nslot[name='title'] {\n font-weight: 600;\n font-size: 14px;\n}\n.popover {\n position: relative;\n\n &.popover--open {\n .popover__positioner {\n visibility: visible;\n opacity: 1;\n transform: scale(1);\n }\n }\n\n &__header {\n display: flex;\n justify-content: space-between;\n padding-bottom: 1em;\n &-close-button {\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n margin: 0;\n border: none;\n background: transparent;\n cursor: pointer;\n border-radius: var(--sc-border-radius-small);\n\n &:focus {\n outline: 2px solid var(--sc-focus-ring-color, var(--sc-color-primary-500));\n outline-offset: 2px;\n }\n\n &:hover {\n opacity: 0.7;\n }\n }\n &-close-icon {\n vertical-align: middle;\n width: 1.5em;\n height: 1.5em;\n }\n }\n &__footer {\n border-top: 1px solid var(--sc-input-border-color);\n padding-top: 0.5em;\n margin-top: 1em;\n }\n &__trigger {\n display: block;\n cursor: pointer;\n border-width: 0;\n outline: none;\n background-color: unset;\n }\n\n &--disabled,\n &--disabled .popover__trigger {\n cursor: not-allowed;\n }\n}\n\n.popover__positioner {\n position: absolute;\n right: 0;\n width: 100%;\n z-index: var(--sc-z-index-popover);\n opacity: 0;\n visibility: hidden;\n transform: scale(0.9);\n min-width: var(--panel-width, 'fit-content');\n}\n.popover__panel {\n transform-origin: top left;\n box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);\n max-height: var(--panel-height);\n font-family: var(--sc-font-sans);\n font-size: var(--sc-font-size-medium);\n font-weight: var(--sc-font-weight-normal);\n color: var(--sc-input-label-color);\n background-color: var(--sc-panel-background-color);\n border: solid 1px var(--sc-panel-border-color);\n border-radius: var(--sc-border-radius-x-large);\n box-shadow: var(--sc-shadow-large);\n overflow: auto;\n overscroll-behavior: none;\n transition: var(--sc-transition-fast) opacity, var(--sc-transition-fast) transform;\n z-index: 5;\n padding: var(--sc-spacing-medium);\n\n}\n","import { Component, Element, Prop, Event, EventEmitter, Watch, State, h } from '@stencil/core';\nimport { autoUpdate, computePosition, flip, offset, shift, size } from '@floating-ui/dom';\nimport { __ } from '@wordpress/i18n';\nimport { speak } from '@wordpress/a11y';\n\n/**\n * @part base - The elements base wrapper.\n * @part trigger - The trigger.\n * @part panel - The panel.\n */\n@Component({\n tag: 'sc-popover',\n styleUrl: 'sc-popover.scss',\n shadow: true,\n})\nexport class ScPopover {\n @Element() el: HTMLDivElement;\n private panel?: HTMLElement;\n private trigger?: HTMLElement;\n private positioner?: HTMLDivElement;\n\n private positionerCleanup: ReturnType<typeof autoUpdate> | undefined;\n private boundHandleOutsideClick = (evt: MouseEvent) => this.handleOutsideClick(evt);\n private boundHandleKeyDown = (evt: KeyboardEvent) => this.handleKeyDown(evt);\n private boundHandleFocusOut = (evt: FocusEvent) => this.handleFocusOut(evt);\n\n /** Is this disabled. */\n @Prop() disabled: boolean;\n\n /** Indicates whether or not the popover is open. You can use this in lieu of the show/hide methods. */\n @Prop({ reflect: true, mutable: true }) open?: boolean = false;\n\n /** The placement of the popover. */\n @Prop({ reflect: true }) placement:\n | 'top'\n | 'top-start'\n | 'top-end'\n | 'bottom'\n | 'bottom-start'\n | 'bottom-end'\n | 'right'\n | 'right-start'\n | 'right-end'\n | 'left'\n | 'left-start'\n | 'left-end' = 'bottom-start';\n\n /** The distance in pixels from which to offset the panel away from its trigger. */\n @Prop() distance: number = 0;\n\n /** The distance in pixels from which to offset the panel along its trigger. */\n @Prop() skidding: number = 0;\n\n /**\n * Enable this option to prevent the panel from being clipped when the component is placed inside a container with\n * `overflow: auto|scroll`.\n */\n @Prop() hoist: boolean = false;\n\n /** Emitted when the popover opens. Calling `event.preventDefault()` will prevent it from being opened. */\n @Event() scShow: EventEmitter<void>;\n\n /** Emitted when the popover closes. Calling `event.preventDefault()` will prevent it from being closed. */\n @Event() scHide: EventEmitter<void>;\n\n /* Internal visible state */\n @State() isVisible: boolean;\n\n @Watch('open')\n handleOpenChange() {\n this.open ? this.show() : this.hide();\n }\n\n handleOutsideClick(evt: MouseEvent) {\n const path = evt.composedPath();\n if (\n !path.some(item => {\n return item === this.el;\n })\n ) {\n this.open = false;\n }\n }\n\n handleKeyDown(event: KeyboardEvent) {\n if (event.key === 'Escape') {\n event.stopPropagation();\n this.hide();\n }\n }\n\n handleTriggerKeyDown(event: KeyboardEvent) {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n if (this.disabled) return;\n if (this.open) {\n this.hide();\n } else {\n this.show();\n }\n }\n }\n\n /**\n * Handles focus leaving the popover.\n * Closes the popover if focus moves outside of it.\n */\n handleFocusOut(event: FocusEvent) {\n const relatedTarget = event.relatedTarget as Node;\n // If focus is moving to something outside the popover, close it\n if (relatedTarget && !this.el.contains(relatedTarget)) {\n this.open = false;\n }\n }\n\n startPositioner() {\n this.stopPositioner();\n this.updatePositioner();\n this.positionerCleanup = autoUpdate(this.trigger, this.positioner, this.updatePositioner.bind(this));\n }\n\n updatePositioner() {\n if (!this.open || !this.trigger || !this.positioner) {\n return;\n }\n\n computePosition(this.trigger, this.positioner, {\n placement: this.placement,\n middleware: [\n offset({ mainAxis: this.distance, crossAxis: this.skidding }),\n flip(),\n shift(),\n size({\n apply: ({ availableWidth: width, availableHeight: height }) => {\n // Ensure the panel stays within the viewport when we have lots of menu items\n Object.assign(this.panel.style, {\n maxWidth: `${width}px`,\n maxHeight: `${height}px`,\n });\n },\n padding: 8,\n }),\n ],\n strategy: this.hoist ? 'fixed' : 'absolute',\n }).then(({ x, y, placement }) => {\n this.positioner.setAttribute('data-placement', placement);\n\n Object.assign(this.positioner.style, {\n position: this.hoist ? 'fixed' : 'absolute',\n left: `${x}px`,\n top: `${y}px`,\n right: 'auto',\n });\n });\n }\n\n stopPositioner() {\n if (this.positionerCleanup) {\n this.positionerCleanup();\n this.positionerCleanup = undefined;\n this.positioner?.removeAttribute('data-placement');\n }\n }\n\n show() {\n speak(__('Popover opened. Press Escape to close.', 'surecart'), 'assertive');\n this.scShow.emit();\n // Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher\n if (this.isVisible) {\n return;\n }\n this.isVisible = true;\n this.open = true;\n this.startPositioner();\n document.addEventListener('keydown', this.boundHandleKeyDown);\n this.el.addEventListener('focusout', this.boundHandleFocusOut);\n this.panel.focus();\n }\n\n hide() {\n speak(__('Popover closed.', 'surecart'), 'assertive');\n this.scHide.emit();\n // Prevent subsequent calls to the method, whether manually or triggered by the `open` watcher\n if (!this.isVisible) {\n return;\n }\n this.stopPositioner();\n document.removeEventListener('keydown', this.boundHandleKeyDown);\n this.el.removeEventListener('focusout', this.boundHandleFocusOut);\n this.isVisible = false;\n this.open = false;\n const slotted = this.el.shadowRoot.querySelector('slot[name=\"trigger\"]') as HTMLSlotElement;\n const trigger = slotted.assignedElements({ flatten: true })[0] as HTMLElement;\n trigger?.focus?.();\n }\n\n componentWillLoad() {\n document.addEventListener('mousedown', this.boundHandleOutsideClick);\n }\n\n disconnectedCallback() {\n document.removeEventListener('mousedown', this.boundHandleOutsideClick);\n document.removeEventListener('keydown', this.boundHandleKeyDown);\n this.el.removeEventListener('focusout', this.boundHandleFocusOut);\n }\n\n handleHide() {\n this.open = false;\n this.trigger.focus();\n }\n\n render() {\n return (\n <div\n part=\"base\"\n class={{\n 'popover': true,\n 'popover--open': this.open,\n 'popover--disabled': this.disabled,\n }}\n >\n <span\n part=\"trigger\"\n class=\"popover__trigger\"\n ref={el => (this.trigger = el as HTMLElement)}\n onClick={() => {\n if (this.disabled) return;\n if (this.open) {\n this.hide();\n } else {\n setTimeout(() => {\n this.show();\n }, 0);\n }\n }}\n onKeyDown={e => this.handleTriggerKeyDown(e)}\n tabindex=\"0\"\n role=\"button\"\n aria-expanded={this.open ? 'true' : 'false'}\n aria-haspopup=\"dialog\"\n aria-label={__('Press Enter to open popover', 'surecart')}\n >\n <slot name=\"trigger\"></slot>\n </span>\n\n {/* Position the panel with a wrapper since the popover makes use of translate. This let's us add animations\n on the panel without interfering with the position. */}\n <div class=\"popover__positioner\" ref={el => (this.positioner = el as HTMLDivElement)}>\n <div\n part=\"panel\"\n class=\"popover__panel\"\n role=\"dialog\"\n aria-modal=\"false\"\n tabindex=\"-1\"\n ref={el => (this.panel = el as HTMLElement)}\n >\n <div class=\"popover__header\">\n <slot name=\"title\" />\n <button\n type=\"button\"\n class=\"popover__header-close-button\"\n onClick={() => this.handleHide()}\n onKeyDown={e => e.key === 'Enter' && this.handleHide()}\n aria-label={__('Close', 'surecart')}\n >\n <sc-icon class=\"popover__header-close-icon\" name=\"x\" />\n </button>\n </div>\n <slot name=\"content\"></slot>\n <div class=\"popover__footer\">\n <slot name=\"footer\"></slot>\n </div>\n </div>\n </div>\n </div>\n );\n }\n}\n"],"version":3}