UNPKG

@postnord/web-components

Version:

PostNord Web Components

200 lines (195 loc) 11.8 kB
/*! * Built with Stencil * By PostNord. */ import { proxyCustomElement, HTMLElement, forceUpdate, h, Host } from '@stencil/core/internal/client'; import { o as open_in_new } from './open_in_new.js'; import { r as ripple } from './helpers.js'; import { d as defineCustomElement$2 } from './pn-icon2.js'; const pnTileCss = "pn-tile{position:relative;font-size:1em;}pn-tile a.pn-tile-link{position:absolute;top:0;left:0;height:100%;width:100%;pointer-events:none;opacity:0}pn-tile .pn-tile{border:0.1rem solid #d3cecb;outline:none;background:#ffffff;box-shadow:0 0.1rem 0.2rem rgba(0, 0, 0, 0.2);cursor:pointer;display:flex;flex-wrap:wrap;align-items:flex-start;justify-content:center;padding:1.5em;padding:min(7%, 1.5em);word-break:break-word;text-decoration:none;border-radius:0.8rem;transition:box-shadow 0.1s cubic-bezier(0.6, 0, 0.2, 1) 0.1s, background 0.2s linear, border 0.1s linear;position:relative;overflow:hidden;text-align:left;user-select:text;height:100%}pn-tile .pn-tile.vertical,pn-tile .pn-tile.simple{text-align:center}pn-tile .pn-tile.vertical h3,pn-tile .pn-tile.simple h3{font-size:1.5em;font-size:clamp(1em, var(--w) * 1.4, 1.5em)}pn-tile .pn-tile.vertical .tile-slot,pn-tile .pn-tile.simple .tile-slot{font-size:1em;font-size:clamp(1.2rem, var(--w), 1em)}pn-tile .pn-tile.vertical>*,pn-tile .pn-tile.simple>*{margin:0.5em 0}pn-tile .pn-tile.simple{flex-direction:column;align-items:center}pn-tile .pn-tile.simple .tile-slot{display:none}pn-tile .pn-tile.simple h3>pn-icon{margin-left:0.1em;vertical-align:bottom}pn-tile .pn-tile.simple>*{margin:0.5em}pn-tile .pn-tile.simple>.text-cont{margin:0.5em}pn-tile .pn-tile.simple>svg,pn-tile .pn-tile.simple>.tile-illustration-slot{max-width:clamp(3em, 70%, 10em)}pn-tile .pn-tile.simple>svg,pn-tile .pn-tile.simple>.tile-illustration-slot,pn-tile .pn-tile.simple>.text-cont{flex:auto}pn-tile .pn-tile.horizontal{flex-wrap:nowrap}pn-tile .pn-tile>*{margin:0.5em;z-index:2}pn-tile .pn-tile>svg,pn-tile .pn-tile>.tile-illustration-slot{width:100%;max-width:8em;flex:0.5 3 calc((32rem - 100%) * 999);z-index:2}pn-tile .pn-tile>.tile-illustration-slot{max-width:13em}pn-tile .pn-tile>.tile-illustration-slot>*{width:100%;display:block}pn-tile .pn-tile>.text-cont{flex:1 1 calc((32rem - 100%) * 999)}pn-tile .pn-tile>.text-cont.horizontal{flex:1 1 0}pn-tile .pn-tile>.text-cont.horizontal>h3{white-space:nowrap}pn-tile .pn-tile h3{color:#005d92;font-size:1.5em}pn-tile .pn-tile .tile-slot{color:#5e554a;margin-top:0.25em}pn-tile a:focus-visible+.pn-tile{box-shadow:0 0 0 0.3rem #ffffff, 0 0 0 0.6rem #005d92}pn-tile .pn-tile:hover,pn-tile a:focus-visible+.pn-tile{background:#effbff;border:0.1rem solid #8eddf9}pn-tile .pn-tile:hover.vertical .tile-circle,pn-tile .pn-tile:hover.simple .tile-circle,pn-tile a:focus-visible+.pn-tile.vertical .tile-circle,pn-tile a:focus-visible+.pn-tile.simple .tile-circle{transform:translate(-50%, -90%);transform:translate(-50%, calc(var(--w) * 2 - 90%));opacity:1}pn-tile .pn-tile .tile-circle{position:absolute;top:0;left:50%;width:40em;height:40em;margin:0;background-color:#005d92;border-radius:50%;z-index:1;transform:translate(-50%, -100%);transition:transform 0.5s cubic-bezier(0.7, 0, 0.3, 1), opacity 0.4s cubic-bezier(0.7, 0, 0.3, 1);opacity:0}pn-tile .pn-ripple{animation:ripple 0.4s cubic-bezier(0.7, 0, 0.3, 1);position:absolute;border-radius:50%;background:#005d92;transform:translate(-50%, -50%) scale(0);opacity:0.05}@keyframes ripple{to{transform:translate(-50%, -50%) scale(1);opacity:0}}"; const PnTileStyle0 = pnTileCss; const PnTile$1 = /*@__PURE__*/ proxyCustomElement(class PnTile extends HTMLElement { constructor() { super(); this.__registerHost(); } mo; get hostElement() { return this; } /** This is to keep track of whether the tile has a description or just a title */ simple = false; emInPx = 16; longpress = false; timer; /** Headline of the card and label of the link */ label; /** The SVG content of an illustration. */ illustration; /** The link of the tile */ url; /** Force horizontal tile */ horizontal = false; /** The target attribute of the link */ target; /** The rel attribute of the link */ rel = 'noopener'; checkCardSize = new ResizeObserver(cards => { const getCardWidth = (width) => { // CardWidth is the em equivalent to 10% of the width of the card const cardWidth = (width * 0.1) / this.emInPx; return `${cardWidth}em`; }; cards.forEach(card => { if (this.horizontal) return; const width = card.contentRect.width; card.target.classList.toggle('vertical', width < this.remToPx(31.99)); requestAnimationFrame(() => { card.target.style.setProperty('--w', getCardWidth(width)); }); }); }); setIllustration() { const illustrationElement = this.hostElement.querySelector('.tile-illustration'); if (!this.illustration) { illustrationElement.remove(); return; } const illustration = this.illustration; illustrationElement.outerHTML = illustration; } componentWillLoad() { const slottedIllustration = this.hostElement.querySelector('[slot="illustration"]'); this.illustration = slottedIllustration ? null : this.illustration; } componentDidLoad() { if (this.mo) this.mo.disconnect(); this.mo = new MutationObserver(() => forceUpdate(this.hostElement)); this.mo.observe(this.hostElement, { childList: true }); this.setIllustration(); const cardEl = this.hostElement.querySelector('.pn-tile'); const linkEl = this.hostElement.querySelector('.pn-tile-link'); this.checkCardSize.observe(cardEl); this.clickHandler([linkEl, cardEl], (e) => ripple(e, cardEl)); this.simple = !this.horizontal && !this.hostElement.querySelector('.tile-slot').textContent.trim(); this.emInPx = parseFloat(window.getComputedStyle(this.hostElement).fontSize); } remToPx(rem) { return rem * parseFloat(getComputedStyle(document.documentElement).fontSize); } /*---------------------------------------UTILS-------------------------------------------*/ clickHandler(elements, callback) { const events = ['mouseup', 'mousedown']; const excludedElements = ['pn-button', 'button', 'a', 'input', 'pn-checkbox', 'pn-radio-button']; /** * @description Stop the tile-link from being pressed if the user clicks a link or a button that exists on the tile * This is to allow the consumer to add external actions to the tile */ const isExcluded = (event) => excludedElements.some(element => event.target.closest(element)); /** * @description If this is a mousdown event, set state longpress to true after 200 milliseconds. */ const longPressTrigger = (event) => { if (event.type === 'mousedown') { this.longpress = false; this.timer = setTimeout(() => (this.longpress = true), 200); } }; /** * @description Loop through all elements and attach out event listeners. See `events` array. */ const loopAllElements = (element, eventName) => { element.addEventListener(eventName, (event) => { if (isExcluded(event)) return; longPressTrigger(event); if (event.type === 'mouseup') { clearTimeout(this.timer); // Stop clicks in case of: // * Long press // * Right mouse button is used if (this.longpress || event.button === 2) return; const link = event.target.closest('pn-tile').querySelector('a'); event.preventDefault(); callback(event); // Don't refocus if already in focus if (!link.matches(':focus')) link.focus(); // If the tile or link was clicked when the ctrl key, cmd key or middle mouse button // was pressed, open in a new window if (event.ctrlKey || event.metaKey || event.button === 1) { window.open(link.getAttribute('href'), '_blank'); return; } link.click(); } }); }; elements.forEach(element => { if (element.tagName === 'A') { element.addEventListener('click', event => callback(event)); return; } events.forEach(eventName => loopAllElements(element, eventName)); }); } /*---------------------------------------/UTILS-------------------------------------------*/ getClassNames() { let classNames = 'pn-tile '; if (this.simple) classNames += 'simple '; if (this.horizontal) classNames += 'horizontal '; return classNames; } getTextContClassNames() { let classNames = 'text-cont '; if (this.horizontal) classNames += 'horizontal '; return classNames; } render() { const linkAttributes = { href: this.url, target: this.target, rel: !this.rel && this.target === '_blank' ? 'noopener' : this.rel, }; return (h(Host, { key: 'ff4eb09a7bbe9b1fb48524adf400e61c137a22e1' }, h("a", { key: '9910f4f0ced66a1fb371610221f98358722256f4', class: "pn-tile-link", ...linkAttributes }, this.label), h("div", { key: '28dfbc275f37318f598d87e7259bc974d6f4e005', class: this.getClassNames() }, h("div", { key: '2a8c55b27898e42100991b2f66c26d1cc0b20360', class: "tile-circle" }), h("div", { key: '9d4c121e2d5fccdd83a1c1d3f84978e8006be483', class: "tile-illustration" }), !this.illustration && (h("div", { key: 'cd5abb9f8faeb36a8d9fad505fd691456bb2f69a', class: "tile-illustration-slot" }, h("slot", { key: 'd3f42654d23b220a9b5f8527e479e07f51c3b1ef', name: "illustration" }))), h("div", { key: '82fe3c9f45e968acb08945ae0a155eb595a57556', class: this.getTextContClassNames() }, h("h3", { key: '127bdf4704f51afb10d2b7057d176798035ac929' }, this.label, this.target === '_blank' ? h("pn-icon", { icon: open_in_new, small: true, color: "blue700" }) : null), h("div", { key: 'd27a02a87e368e88947569d511edee7e27659ed0', class: "tile-slot" }, h("slot", { key: '6a4de1735bc2e720c53afb3274b6ecf13e674a07' })))))); } static get style() { return PnTileStyle0; } }, [4, "pn-tile", { "label": [1], "illustration": [1025], "url": [1], "horizontal": [4], "target": [1], "rel": [1], "simple": [32], "emInPx": [32], "longpress": [32], "timer": [32], "checkCardSize": [32] }]); function defineCustomElement$1() { if (typeof customElements === "undefined") { return; } const components = ["pn-tile", "pn-icon"]; components.forEach(tagName => { switch (tagName) { case "pn-tile": if (!customElements.get(tagName)) { customElements.define(tagName, PnTile$1); } break; case "pn-icon": if (!customElements.get(tagName)) { defineCustomElement$2(); } break; } }); } const PnTile = PnTile$1; const defineCustomElement = defineCustomElement$1; export { PnTile, defineCustomElement }; //# sourceMappingURL=pn-tile.js.map