@postnord/web-components
Version:
PostNord Web Components
256 lines (255 loc) • 9.74 kB
JavaScript
/*!
* 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 {
details;
summary;
content;
animation;
hostElement;
isClosing = false;
isExpanding = false;
/** 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. */
label;
/** The open/close status of the accordion row. */
state = false;
/** Optional unique id for the `summary` element. @category ID */
buttonid;
/** Optional unique id for the `div` element containing the content. @category ID */
contentid;
/** 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: 'e98e506637a1303e493b529928435dceb965bc35' }, h("details", { key: '34fec5b0c944442f48e8c6d23ef7756366906023', class: "pn-accordion-row", open: this.state, ref: (el) => (this.details = el) }, h("summary", { key: '9f2359b4aa9c3e894a5b436968e1783ac3361c65', id: this.buttonid, class: "pn-accordion-row-summary", onClick: e => this.clickHandler(e), ref: el => (this.summary = el) }, h("div", { key: '261f053b904d2f6f50ea90a610176829cfc2bf89', class: "pn-accordion-row-text" }, this.label ? this.label : '', h("slot", { key: 'ba20d07bfa5af6b771b98b407b7688b65339f341', name: "label" }), h("pn-icon", { key: 'fea80322eb33a895fc5fce7a9245de98e9f28e2a', class: "pn-accordion-row-icon", icon: angle_down }))), h("div", { key: 'f3bf848e95eb68e3bcb268f3a35924709df0823e', id: this.contentid, class: "pn-accordion-row-content", ref: (el) => (this.content = el) }, h("slot", { key: 'd7c939e3ca67e430906c655b347c08c236f528fa' })))));
}
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."
},
"getter": false,
"setter": false,
"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."
},
"getter": false,
"setter": false,
"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."
},
"getter": false,
"setter": false,
"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."
},
"getter": false,
"setter": false,
"attribute": "contentid",
"reflect": 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