UNPKG

@postnord/web-components

Version:

PostNord Web Components

299 lines (298 loc) 11.8 kB
/*! * Built with Stencil * By PostNord. */ import { Host, h, forceUpdate } from "@stencil/core"; import { open_in_new } from "pn-design-assets/pn-assets/icons.js"; import { ripple } from "../../../globals/helpers"; /** * @slot illustration - Set a custom image/svg/illustration. */ export class PnTile { mo; hostElement; /** 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 is() { return "pn-tile"; } static get originalStyleUrls() { return { "$": ["pn-tile.scss"] }; } static get styleUrls() { return { "$": ["pn-tile.css"] }; } static get properties() { return { "label": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Headline of the card and label of the link" }, "getter": false, "setter": false, "attribute": "label", "reflect": false }, "illustration": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The SVG content of an illustration." }, "getter": false, "setter": false, "attribute": "illustration", "reflect": false }, "url": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The link of the tile" }, "getter": false, "setter": false, "attribute": "url", "reflect": false }, "horizontal": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "Force horizontal tile" }, "getter": false, "setter": false, "attribute": "horizontal", "reflect": false, "defaultValue": "false" }, "target": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The target attribute of the link" }, "getter": false, "setter": false, "attribute": "target", "reflect": false }, "rel": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The rel attribute of the link" }, "getter": false, "setter": false, "attribute": "rel", "reflect": false, "defaultValue": "'noopener'" } }; } static get states() { return { "simple": {}, "emInPx": {}, "longpress": {}, "timer": {}, "checkCardSize": {} }; } static get elementRef() { return "hostElement"; } } //# sourceMappingURL=pn-tile.js.map