UNPKG

@postnord/web-components

Version:

PostNord Web Components

201 lines (195 loc) 12.1 kB
/*! * Built with Stencil * By PostNord. */ import { proxyCustomElement, HTMLElement, createEvent, forceUpdate, h, Host } from '@stencil/core/internal/client'; import { r as reduceMotion, k as awaitTopbar, e as en } from './helpers.js'; import { c as close } from './close.js'; import { d as defineCustomElement$4 } from './pn-button2.js'; import { d as defineCustomElement$3 } from './pn-icon2.js'; import { d as defineCustomElement$2 } from './pn-spinner2.js'; const translations = { CLOSE_MODAL: { en: 'Close dialog', sv: 'Stäng dialogrutan', da: 'Luk dialogboks', fi: 'Sulje valintaikkuna', no: 'Lukk dialogboksen', }, }; const pnModalCss = "/* Global utility variables */\n/* Input styles */\n/* Transition variables */\npn-modal .pn-modal {\n --pn-modal-max-width: 45em;\n --pn-modal-overflow: hidden auto;\n z-index: 10000;\n position: fixed;\n top: 0;\n inset-block-start: 0;\n inset-block-end: 0;\n margin: auto;\n overflow: var(--pn-modal-overflow);\n max-width: var(--pn-modal-max-width);\n max-height: 85vh;\n padding: clamp(1em, 5vw, 1.5em) 0;\n border: 0.0625em solid #f3f2f2;\n border-radius: 0.5em;\n flex-direction: column;\n align-items: stretch;\n gap: 0.75em;\n box-shadow: 0 0.25em 0.875em rgba(0, 0, 0, 0.18), 0 1.625em 3.5em rgba(0, 0, 0, 0.22);\n background-color: #ffffff;\n display: none;\n opacity: 0;\n transform: translate(0%, 20%);\n outline: 0.2rem solid transparent;\n outline-offset: 0.2rem;\n transition-property: opacity, overlay, display, transform, outline-color;\n transition-duration: 0.4s;\n transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);\n transition-behavior: allow-discrete;\n}\npn-modal .pn-modal:focus-visible {\n outline-color: #ffffff;\n}\npn-modal .pn-modal::-webkit-scrollbar {\n background-color: #ffffff;\n width: 0.875em;\n border-radius: 0.5em;\n}\npn-modal .pn-modal::-webkit-scrollbar-track {\n background-color: #ffffff;\n border-radius: 0.5em;\n}\npn-modal .pn-modal::-webkit-scrollbar-thumb {\n cursor: pointer;\n background-color: #969087;\n border-radius: 1em;\n border: 0.25em solid #ffffff;\n}\npn-modal .pn-modal::-webkit-scrollbar-thumb:hover {\n background-color: #5e554a;\n}\npn-modal .pn-modal::-webkit-scrollbar-corner, pn-modal .pn-modal::-webkit-scrollbar-button {\n display: none;\n}\n@media (prefers-reduced-motion: reduce) {\n pn-modal .pn-modal {\n transition-duration: 0s;\n transition-delay: 0s;\n }\n}\npn-modal .pn-modal[data-sheet] {\n margin: 0 0 0 auto;\n height: 100%;\n max-height: unset;\n border-radius: 0.5em 0 0 0.5em;\n transform: translate(20%, 0%);\n}\npn-modal .pn-modal[open] {\n display: flex;\n opacity: 1;\n transform: translate(0%, 0%);\n}\n@starting-style {\n pn-modal .pn-modal[open] {\n display: flex;\n opacity: 0;\n transform: translate(0%, 20%);\n }\n}\npn-modal .pn-modal[open][data-sheet] {\n transform: translate(0%, 0%);\n}\n@starting-style {\n pn-modal .pn-modal[open][data-sheet] {\n transform: translate(20%, 0%);\n }\n}\npn-modal .pn-modal::backdrop {\n background-color: rgba(0, 0, 0, 0);\n transition-property: opacity, background-color, overlay, display;\n transition-duration: 0.4s;\n transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);\n transition-behavior: allow-discrete;\n}\n@media (prefers-reduced-motion: reduce) {\n pn-modal .pn-modal::backdrop {\n transition-duration: 0s;\n transition-delay: 0s;\n }\n}\npn-modal .pn-modal[open]::backdrop {\n background-color: rgba(0, 0, 0, 0.55);\n}\n@starting-style {\n pn-modal .pn-modal[open]::backdrop {\n background-color: rgba(0, 0, 0, 0);\n }\n}\npn-modal .pn-modal-close-button {\n position: absolute;\n right: 0.5em;\n top: 0.5em;\n}\npn-modal .pn-modal-header {\n display: flex;\n flex-direction: column;\n gap: 0.5em;\n padding: 0 clamp(1em, 5vw, 1.5em);\n}\npn-modal .pn-modal-label {\n line-height: 1.5;\n padding-right: 1.5em;\n margin: 0;\n}\npn-modal .pn-modal-text {\n margin: 0;\n}\npn-modal .pn-modal-content {\n padding: 0 clamp(1em, 5vw, 1.5em);\n}\npn-modal .pn-modal-buttons {\n background-color: #ffffff;\n border-top: 0.0625em solid #d3cecb;\n padding: clamp(1em, 5vw, 1.5em) clamp(1em, 5vw, 1.5em) 0;\n display: flex;\n justify-content: flex-end;\n gap: 0.5em;\n}\npn-modal .pn-modal-buttons [slot=buttons]:not(pn-button) {\n display: flex;\n justify-content: flex-end;\n gap: 0.5em;\n}\npn-modal .pn-modal-buttons:empty {\n display: none;\n}\n\n@media (max-width: 30em) {\n pn-modal .pn-modal {\n width: 100%;\n max-height: 95vh;\n margin-bottom: 0;\n bottom: 0;\n transform: translate(0%, 20%);\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n }\n}"; const PnModalStyle0 = pnModalCss; const PnModal$1 = /*@__PURE__*/ proxyCustomElement(class PnModal extends HTMLElement { constructor() { super(); this.__registerHost(); this.modalToggle = createEvent(this, "modalToggle", 7); this.modalVisiblity = createEvent(this, "modalVisiblity", 7); this.close = createEvent(this, "close", 7); this.isClosing = false; this.isOpening = false; this.label = undefined; this.helpertext = undefined; this.language = null; this.open = false; this.persistent = false; this.hideClose = false; this.allowOverflow = false; this.sheet = false; this.maxWidth = null; } mo; standardAnimationDuration = 400; animationDuration = this.standardAnimationDuration; modalTimeout; modalElement; get hostElement() { return this; } handleOpen() { if (this.open) this.openModal(); else { this.closeModal(); /** In the next update, we can remove this one so you can finally stack modals. */ this.close.emit(true); } this.handleOverflow(); clearTimeout(this.modalTimeout); this.isClosing = !this.open && true; if (reduceMotion()) this.animationDuration = 0; else this.animationDuration = this.standardAnimationDuration; this.modalTimeout = setTimeout(() => { this.isClosing = false; this.modalVisiblity.emit({ visible: this.open }); }, this.animationDuration); } handleMaxWidth() { const width = this.maxWidth || '45em'; this.modalElement.style.setProperty('--pn-modal-max-width', width); } /** This event is fired when the modal is toggled. */ modalToggle; /** This event is dispatched after the opening/closing animation has finished playing. */ modalVisiblity; /** * Event fired when the modal is closed, either by clicking on the dark background or by clicking on the close button. * @deprecated Use the new `modalToggle` event instead. */ close; connectedCallback() { this.mo = new MutationObserver(() => forceUpdate(this.hostElement)); this.mo.observe(this.hostElement, { childList: true, subtree: true }); } disconnectedCallback() { if (this.mo) this.mo.disconnect(); } async componentWillLoad() { if (this.language === null) await awaitTopbar(this.hostElement); } componentDidLoad() { this.handleMaxWidth(); if (this.open) this.openModal(); } translate(prop) { return translations?.[prop]?.[this.language || en] || prop; } handleOverflow() { if (!this.allowOverflow) return; const overflow = this.modalElement.scrollHeight > innerHeight * 0.85 ? 'hidden auto' : 'unset'; this.modalElement.style.setProperty('--pn-modal-overflow', overflow); } isSameModal(target) { return this.modalElement.isSameNode(target); } handleKeyboard(event) { if (event.key !== 'Escape') return; event.preventDefault(); event.stopImmediatePropagation(); if (!this.persistent) this.setModalClose(); } clickModalBackground(event) { const { clientY, clientX } = event; const notInsideAnyModal = event.target.localName !== this.modalElement.localName; const notThisModal = !this.isSameModal(event.target); if (notInsideAnyModal || notThisModal) return; const { top, left, height, width } = this.modalElement.getBoundingClientRect(); const isInModal = top <= clientY && clientY <= top + height && left <= clientX && clientX <= left + width; if (!isInModal && !this.persistent) this.toggleOpen(false); } setModalClose() { this.toggleOpen(false); } closeModal() { this.modalElement.close(); } openModal() { this.modalElement.showModal(); } toggleOpen(state) { this.open = state ?? !this.open; } render() { return (h(Host, { key: '6bf631cc88584b24782904a9918091736e27c3d6' }, h("dialog", { key: '543806f18626bd7f8f6983a5c3769f8bf0422544', class: "pn-modal", "data-closing": this.isClosing, "data-sheet": this.sheet, onClose: () => this.setModalClose(), onCancel: () => this.setModalClose(), onToggle: () => this.modalToggle.emit({ open: this.open }), onKeyDown: event => this.handleKeyboard(event), onClick: event => this.clickModalBackground(event), ref: el => (this.modalElement = el) }, !this.hideClose && (h("pn-button", { key: '60350dfcac19aa570b78e4fb82ca2a0a288de1b7', small: true, class: "pn-modal-close-button", icon: close, iconOnly: true, arialabel: this.translate('CLOSE_MODAL'), appearance: "light", variant: "borderless", type: "button", onPnClick: () => this.setModalClose() })), h("header", { key: 'ba3d857e5f0b57c9567b045843f3b3a1aee9f06d', class: "pn-modal-header" }, this.label && h("h2", { key: '524b36cbeb3f1e0274fb29a3656638c4c221cec9', class: "pn-modal-label" }, this.label), this.helpertext && h("p", { key: '330777c3c194177f7fc811eb45f2ee3a585894fc', class: "pn-modal-text" }, this.helpertext), h("slot", { key: '62dbf64100d4e62974a18752423a781db737333f', name: "header" })), h("section", { key: '57618a994095a9f24c7a142d86fa788cca531062', class: "pn-modal-content" }, h("slot", { key: '14f533135af35a88d1fb03b8e57cd133d3981629' })), h("nav", { key: 'd355d6c0024893a26b1e17bf187a7d0e3142b766', class: "pn-modal-buttons" }, h("slot", { key: '20020f7fd89b706bfaf5825090d6a0470e91b577', name: "buttons" }))))); } static get watchers() { return { "open": ["handleOpen"], "maxWidth": ["handleMaxWidth"] }; } static get style() { return PnModalStyle0; } }, [4, "pn-modal", { "label": [1], "helpertext": [1], "language": [1], "open": [1540], "persistent": [4], "hideClose": [4, "hide-close"], "allowOverflow": [4, "allow-overflow"], "sheet": [4], "maxWidth": [1, "max-width"], "isClosing": [32], "isOpening": [32] }, undefined, { "open": ["handleOpen"], "maxWidth": ["handleMaxWidth"] }]); function defineCustomElement$1() { if (typeof customElements === "undefined") { return; } const components = ["pn-modal", "pn-button", "pn-icon", "pn-spinner"]; components.forEach(tagName => { switch (tagName) { case "pn-modal": if (!customElements.get(tagName)) { customElements.define(tagName, PnModal$1); } break; case "pn-button": if (!customElements.get(tagName)) { defineCustomElement$4(); } break; case "pn-icon": if (!customElements.get(tagName)) { defineCustomElement$3(); } break; case "pn-spinner": if (!customElements.get(tagName)) { defineCustomElement$2(); } break; } }); } const PnModal = PnModal$1; const defineCustomElement = defineCustomElement$1; export { PnModal, defineCustomElement }; //# sourceMappingURL=pn-modal.js.map