UNPKG

@postnord/web-components

Version:

PostNord Web Components

265 lines (264 loc) 9.96 kB
/*! * Built with Stencil * By PostNord. */ import { h, Host } from "@stencil/core"; import { angle_down } from "pn-design-assets/pn-assets/icons.js"; import { ripple } from "../../../../index"; /** * Use this row component inside a `pn-accordion` to create an accordion group. * * **Note**: you can use the `pn-accordion-row` without the parent accordion. * But you will have to style the gap between each row. * * @slot label - Include your own HTML as the label. * ``` * <h3 slot="label">Custom title</h3> * ``` */ export class PnAccordionRow { constructor() { this.isClosing = false; this.isExpanding = false; this.label = undefined; this.state = false; this.buttonid = undefined; this.contentid = undefined; this.transparent = false; } details; summary; content; animation; hostElement; /** Dispatched every time the row is toggled. Includes the row element and the boolean `state` prop. */ togglerow; /** Internal function for closing rows when using the `single` prop on the `pn-accordion`. */ handleRowState(event) { if (event.detail !== this.state) { this.details.style.overflow = 'hidden'; this.closeAccordion(); } } componentWillLoad() { const slottedLabel = !!this.hostElement.querySelector('[slot="label"]'); this.label = slottedLabel ? null : this.label; } toggleOpen(open) { const state = open ?? !this.state; if (this.state !== open) this.togglerow.emit({ element: this.details, state }); this.state = state; } clickHandler(e) { e.preventDefault(); this.details.style.overflow = 'hidden'; if (this.isClosing || !this.state) this.openAccordion(); else if (this.isClosing || this.state) this.closeAccordion(); const { x, width, y, top } = this.hostElement.getBoundingClientRect(); const clientCor = e.clientX === 0 && e.clientY === 0 ? { clientX: x + width - 24, clientY: y - top } : e; ripple(clientCor, this.hostElement, '.pn-accordion-row-text'); } openAccordion() { this.details.style.height = `${this.details.offsetHeight}px`; this.toggleOpen(true); window.requestAnimationFrame(() => { this.isExpanding = true; const startHeight = `${this.details.offsetHeight}px`; const endHeight = `${this.summary.offsetHeight + this.content.offsetHeight}px`; this.cancelAnimations(); this.animate(true, startHeight, endHeight); }); } closeAccordion() { this.isClosing = true; const startHeight = `${this.details.offsetHeight}px`; const endHeight = `${this.summary.offsetHeight}px`; this.cancelAnimations(); this.animate(false, startHeight, endHeight); } animate(open, startHeight, endHeight) { this.animation = this.details.animate({ height: [startHeight, endHeight], }, { duration: 400, easing: 'cubic-bezier(0.6, 0, 0.2, 1)', }); this.animation.onfinish = () => this.animationFinish(open); this.animation.oncancel = () => { if (open) this.isExpanding = false; else this.isClosing = false; }; } animationFinish(open) { this.toggleOpen(open); this.cancelAnimations(); this.isClosing = false; this.isExpanding = false; this.details.style.height = ''; this.details.style.overflow = ''; } cancelAnimations() { if (this.animation) this.animation.cancel(); } render() { return (h(Host, { key: 'ecbddc7a206d174ffaa74ce496442ce06ce1366e' }, h("details", { key: '3eb50627c300e21884113368dfae02084c9cda5a', class: "pn-accordion-row", open: this.state, ref: (el) => (this.details = el) }, h("summary", { key: '952bd7d0d346c153b7031991d1f3ab43c87b6ac1', id: this.buttonid, class: "pn-accordion-row-summary", onClick: e => this.clickHandler(e), ref: el => (this.summary = el) }, h("div", { key: '7d8922b5c71b5eb78d6b0813576650171797a303', class: "pn-accordion-row-text", "data-transparent": this.transparent }, this.label ? this.label : '', h("slot", { key: 'c23bad6c33b660e5553c7b9f6d1677a3223742cb', name: "label" }), h("pn-icon", { key: '374b09b90afd9ad2d836ecf480dd00317519a7e9', class: "pn-accordion-row-icon", icon: angle_down }))), h("div", { key: '06f253b1c9ca0488f3cd674f35c0eea6bd28c1da', id: this.contentid, class: "pn-accordion-row-content", ref: (el) => (this.content = el) }, h("slot", { key: '2cb8a8fdc7aab0f7009df63ec0e7eb0f9273dc1e' }))))); } static get is() { return "pn-accordion-row"; } static get originalStyleUrls() { return { "$": ["pn-accordion-row.scss"] }; } static get styleUrls() { return { "$": ["pn-accordion-row.css"] }; } static get properties() { return { "label": { "type": "string", "mutable": true, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "The label/title of the accordion row, you can also pass a slot with the name \"label\" if you want to put custom HTML content in there." }, "attribute": "label", "reflect": false }, "state": { "type": "boolean", "mutable": true, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": true, "docs": { "tags": [], "text": "The open/close status of the accordion row." }, "attribute": "state", "reflect": false, "defaultValue": "false" }, "buttonid": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "ID" }], "text": "Optional unique id for the `summary` element." }, "attribute": "buttonid", "reflect": false }, "contentid": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": false, "optional": true, "docs": { "tags": [{ "name": "category", "text": "ID" }], "text": "Optional unique id for the `div` element containing the content." }, "attribute": "contentid", "reflect": false }, "transparent": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "Optional prop that removes the default white background on the accordion row" }, "attribute": "transparent", "reflect": false, "defaultValue": "false" } }; } static get states() { return { "isClosing": {}, "isExpanding": {} }; } static get events() { return [{ "method": "togglerow", "name": "togglerow", "bubbles": true, "cancelable": true, "composed": true, "docs": { "tags": [], "text": "Dispatched every time the row is toggled. Includes the row element and the boolean `state` prop." }, "complexType": { "original": "{ element: HTMLElement; state: Boolean }", "resolved": "{ element: HTMLElement; state: Boolean; }", "references": { "HTMLElement": { "location": "global", "id": "global::HTMLElement" }, "Boolean": { "location": "global", "id": "global::Boolean" } } } }]; } static get elementRef() { return "hostElement"; } static get listeners() { return [{ "name": "rowstate", "method": "handleRowState", "target": undefined, "capture": false, "passive": false }]; } } //# sourceMappingURL=pn-accordion-row.js.map