UNPKG

@postnord/web-components

Version:
197 lines (192 loc) 13.6 kB
/*! * Built with Stencil * By PostNord. */ import { t as transformTag, r as registerInstance, c as createEvent, g as getElement, f as forceUpdate, h, a as Host } from './index-CAEP792y.js'; import { reduceMotion, awaitTopbar, en, isSmallScreen } from './index.js'; import { c as close } from './close-BvuWkoyY.js'; const translations = { CLOSE_MODAL: { en: 'Close dialog', sv: 'Stäng dialogrutan', da: 'Luk dialogboks', fi: 'Sulje valintaikkuna', no: 'Lukk dialogboksen', }, }; const pnModalCss = () => `${transformTag("pn-modal")} .pn-modal{--pn-modal-max-width:45em;z-index:10000;position:fixed;top:0;inset-block-start:0;inset-block-end:0;margin:auto;padding:0;max-width:var(--pn-modal-max-width);overflow:hidden;border:0;border-radius:1.5em;box-shadow:0 0.25em 0.875em rgba(0, 0, 0, 0.18), 0 1.625em 3.5em rgba(0, 0, 0, 0.22);background-color:#ffffff;display:none;opacity:0;transform:translate(0%, 20%);outline:0.2rem solid transparent;outline-offset:0.2rem}${transformTag("pn-modal")} .pn-modal:focus-visible{outline-color:#ffffff}${transformTag("pn-modal")} .pn-modal{transition-property:opacity, overlay, display, transform, outline-color, border-radius;transition-duration:0.4s;transition-timing-function:cubic-bezier(0.7, 0, 0.3, 1)}@media (prefers-reduced-motion: reduce){${transformTag("pn-modal")} .pn-modal{transition-duration:0s;transition-delay:0s}}${transformTag("pn-modal")} .pn-modal{transition-behavior:allow-discrete}${transformTag("pn-modal")} .pn-modal[data-allow-overflow]{overflow:unset}${transformTag("pn-modal")} .pn-modal[data-allow-overflow] .pn-modal-container{overflow:unset}${transformTag("pn-modal")} .pn-modal[data-allow-overflow] .pn-modal-picture{border-top-right-radius:1.5em}${transformTag("pn-modal")} .pn-modal[data-image]{padding-top:0}${transformTag("pn-modal")} .pn-modal[data-sheet]{margin:0 0 0 auto;height:100%;max-height:unset;border-radius:1.5em 0 0 1.5em;transform:translate(20%, 0%)}${transformTag("pn-modal")} .pn-modal[data-sheet] .pn-modal-container{max-height:unset}${transformTag("pn-modal")} .pn-modal[open]{display:flex;opacity:1;transform:translate(0%, 0%)}@starting-style{${transformTag("pn-modal")} .pn-modal[open]{display:flex;opacity:0;transform:translate(0%, 20%)}}${transformTag("pn-modal")} .pn-modal[open][data-sheet]{transform:translate(0%, 0%)}@starting-style{${transformTag("pn-modal")} .pn-modal[open][data-sheet]{transform:translate(20%, 0%)}}${transformTag("pn-modal")} .pn-modal::backdrop{background-color:rgba(0, 0, 0, 0);transition-property:opacity, background-color, overlay, display;transition-duration:0.4s;transition-timing-function:cubic-bezier(0.7, 0, 0.3, 1)}@media (prefers-reduced-motion: reduce){${transformTag("pn-modal")} .pn-modal::backdrop{transition-duration:0s;transition-delay:0s}}${transformTag("pn-modal")} .pn-modal::backdrop{transition-behavior:allow-discrete}${transformTag("pn-modal")} .pn-modal[open]::backdrop{background-color:rgba(0, 0, 0, 0.55)}@starting-style{${transformTag("pn-modal")} .pn-modal[open]::backdrop{background-color:rgba(0, 0, 0, 0)}}${transformTag("pn-modal")} .pn-modal-container{max-height:85vh;display:flex;flex-direction:column;align-items:stretch;overflow:hidden auto}${transformTag("pn-modal")} .pn-modal-container::-webkit-scrollbar{background-color:#ffffff;width:0.875em;border-radius:0.5em}${transformTag("pn-modal")} .pn-modal-container::-webkit-scrollbar-track{background-color:#ffffff;border-radius:0.5em}${transformTag("pn-modal")} .pn-modal-container::-webkit-scrollbar-thumb{cursor:pointer;background-color:#969087;border-radius:1em;border:0.25em solid #ffffff}${transformTag("pn-modal")} .pn-modal-container::-webkit-scrollbar-thumb:hover{background-color:#5e554a}${transformTag("pn-modal")} .pn-modal-container::-webkit-scrollbar-corner,${transformTag("pn-modal")} .pn-modal-container::-webkit-scrollbar-button{display:none}${transformTag("pn-modal")} .pn-modal-close-button{position:absolute;z-index:10;right:0.75em;top:0.75em}${transformTag("pn-modal")} .pn-modal-header{display:flex;flex-direction:column;gap:0.5em;padding:clamp(1em, 5vw, 1.5em)}${transformTag("pn-modal")} .pn-modal-header[hidden]{display:none}${transformTag("pn-modal")} .pn-modal-header:not([hidden])+.pn-modal-content:not([hidden]){padding-top:0}${transformTag("pn-modal")} .pn-modal-label{line-height:1.5;padding-right:1.5em;margin:0}${transformTag("pn-modal")} .pn-modal-text{margin:0}${transformTag("pn-modal")} .pn-modal-content{padding:clamp(1em, 5vw, 1.5em)}${transformTag("pn-modal")} .pn-modal-image{position:relative;display:flex;flex-direction:column}${transformTag("pn-modal")} .pn-modal-image[hidden]{display:none}${transformTag("pn-modal")} .pn-modal-picture{margin:0;padding:0;display:block;overflow:hidden;border-radius:1.5em 0 0 0}${transformTag("pn-modal")} .pn-modal-picture>*[slot=image]{display:block;height:100%;width:100%;object-fit:cover}${transformTag("pn-modal")} .pn-modal-buttons{background-color:#ffffff;border-top:0.0625em solid #d3cecb;padding:clamp(1em, 5vw, 1.5em);display:flex;justify-content:flex-end;gap:0.5em;border-radius:0 0 1.5em 1.5em}${transformTag("pn-modal")} .pn-modal-buttons>[slot=buttons]:not(${transformTag("pn-button")}){display:flex;justify-content:flex-end;gap:0.5em}${transformTag("pn-modal")} .pn-modal-buttons>[slot=buttons]:not(${transformTag("pn-button")})>[data-left]{margin-right:auto}${transformTag("pn-modal")} .pn-modal-buttons>[data-left]{margin-right:auto}${transformTag("pn-modal")} .pn-modal-buttons:empty{display:none}@media (max-width: 55em){${transformTag("pn-modal")} .pn-modal{max-height:95vh;margin-bottom:0;bottom:0;transform:translate(0%, 20%);border-bottom-left-radius:0;border-bottom-right-radius:0}}`; const PnModal = class { constructor(hostRef) { registerInstance(this, hostRef); this.modalToggle = createEvent(this, "modalToggle"); this.modalVisiblity = createEvent(this, "modalVisiblity"); this.close = createEvent(this, "close"); } mo; standardAnimationDuration = 400; animationDuration = this.standardAnimationDuration; modalTimeout; modalElement; modalContainer; modalPicture; get hostElement() { return getElement(this); } isClosing = false; isOpening = false; /** If true, the modal content will remove overflow CSS property. */ removeOverflow = false; /** Set a label for the modal. @since v7.14.0 */ label; /** Set a descriptive text for the modal. @since v7.14.0 */ helpertext; /** Set the language. @since v7.14.0 */ language = null; /** Bind to this property if you want to control the visibility of the modal from your own data. @category Features */ open = false; /** * Prevent users from closing the modal by clicking on the backdrop or the `ESC` key. * @since v7.14.0 * @category Features */ persistent = false; /** * Hide the close button. If you disable this, make sure you build your own cancel button. * @since v7.14.0 * @category Features */ hideClose = false; /** * Allow overflow if possible. When the modal opens, it will check scrollHeight > offsetHeight. * Do not use if you have a lot of conditional rendering inside the modal. * @since v7.14.0 */ allowOverflow = false; /** * Use the `sheet` visual. Aligns the modal to the right. * @since v7.14.0 * @category Visual */ sheet = false; /** * Define your own max width of the modal. Default is `45em`. * @category Visual * @since v7.14.0 */ maxWidth = null; 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); } handleOverflow() { if (this.allowOverflow) this.setOverflow(); } /** This event is fired when the modal is toggled. {@since v7.14.0} */ modalToggle; /** This event is dispatched after the opening/closing animation has finished playing. {@since v7.14.0} */ 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; } showImage() { return !!this.modalPicture?.innerHTML; } showHeader() { return !!(this.label || this.helpertext || this.hostElement.querySelector('[slot="header"]')?.textContent); } setOverflow() { this.removeOverflow = !this.hasOverflow(); } hasOverflow() { const multiplyWith = isSmallScreen() ? 0.95 : 0.85; return this.modalContainer?.scrollHeight > innerHeight * multiplyWith; } 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: 'd965a05833b311fed1f1f7ba245c9401ab77b765' }, h("dialog", { key: 'd60d253a75dd3f82b684fce659a9a917d6181c62', class: "pn-modal", "data-closing": this.isClosing, "data-sheet": this.sheet, "data-image": this.showImage(), "data-allow-overflow": this.removeOverflow, 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: '4d25a2e559a8aca6286a9fc7a94f82285bd8ad4e', 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("div", { key: '3953eef2505ccda4786177c01ae9af92874d65a1', class: "pn-modal-container", ref: el => (this.modalContainer = el) }, h("div", { key: 'de0730ef36d305f2ff2652510838df85bdbdee5e', class: "pn-modal-image", hidden: !this.showImage() }, h("picture", { key: 'c26ae160c243b630d7a1ba71a8d4cac523096cfd', class: "pn-modal-picture", ref: el => (this.modalPicture = el) }, h("slot", { key: '4d2425b17367b4ccd2215e54cfedbee6731a9daf', name: "image" }))), h("header", { key: '815bef72c5b9a2982b7dd62059314ef120221ee0', class: "pn-modal-header", hidden: !this.showHeader() }, this.label && h("h2", { key: '41ae0e9a7d8adca27764bf6be026d0bc59df9b90', class: "pn-modal-label" }, this.label), this.helpertext && h("p", { key: '4fac7c6daf49eaff4a56b7c217f49e7f0507299f', class: "pn-modal-text" }, this.helpertext), h("slot", { key: '8ce017defaa66a4bfec5ef38398b3104ed0ff7f9', name: "header" })), h("section", { key: '3ad1dc180db0ad42a4fa99dc6c9a17fc153af362', class: "pn-modal-content" }, h("slot", { key: 'bddef9aa3cd8b78be3facd5ebd3e88d72b9eb219' })), h("nav", { key: 'edc771b8ca813ed6c9b20f688847c9c22072f0a1', class: "pn-modal-buttons" }, h("slot", { key: '75dcf50e07c985f95836251881b8c214bc1b58c6', name: "buttons" })))))); } static get watchers() { return { "open": [{ "handleOpen": 0 }], "maxWidth": [{ "handleMaxWidth": 0 }] }; } }; PnModal.style = pnModalCss(); export { PnModal as pn_modal };