UNPKG

@esri/calcite-components

Version:

Web Components for Esri's Calcite Design System.

352 lines (351 loc) • 10.6 kB
/*! * All material copyright ESRI, All Rights Reserved, unless otherwise specified. * See https://github.com/Esri/calcite-components/blob/master/LICENSE.md for details. * v1.5.0-next.4 */ import { h } from "@stencil/core"; import { focusElementInGroup, toAriaBoolean } from "../../utils/dom"; import { connectInteractive, disconnectInteractive, updateHostInteraction } from "../../utils/interactive"; import { createObserver } from "../../utils/observers"; import { componentLoaded, setComponentLoaded, setUpLoadableComponent } from "../../utils/loadable"; /** * @slot - A slot for adding one or more `calcite-chip`s. */ export class ChipGroup { constructor() { //-------------------------------------------------------------------------- // // Private Properties // //-------------------------------------------------------------------------- this.mutationObserver = createObserver("mutation", () => this.updateItems()); this.items = []; //-------------------------------------------------------------------------- // // Private Methods // //-------------------------------------------------------------------------- this.updateItems = (event) => { const target = event ? event.target : this.slotRefEl; this.items = target .assignedElements({ flatten: true }) .filter((el) => el?.matches("calcite-chip")); this.items.forEach((el) => { el.interactive = true; el.scale = this.scale; el.selectionMode = this.selectionMode; }); this.setSelectedItems(false); }; this.setSelectedItems = (emit, elToMatch) => { if (elToMatch) { this.items.forEach((el) => { const matchingEl = elToMatch === el; switch (this.selectionMode) { case "multiple": if (matchingEl) { el.selected = !el.selected; } break; case "single": el.selected = matchingEl ? !el.selected : false; break; case "single-persist": el.selected = !!matchingEl; break; } }); } this.selectedItems = this.items.filter((el) => el.selected); if (emit) { this.calciteChipGroupSelect.emit(); } }; this.disabled = false; this.label = undefined; this.scale = "m"; this.selectionMode = "none"; this.selectedItems = []; } onSelectionModeChange() { this.updateItems(); } //-------------------------------------------------------------------------- // // Lifecycle // //-------------------------------------------------------------------------- connectedCallback() { connectInteractive(this); this.mutationObserver?.observe(this.el, { childList: true, subtree: true }); } componentDidRender() { disconnectInteractive(this); updateHostInteraction(this); } componentDidLoad() { setComponentLoaded(this); } disconnectedCallback() { this.mutationObserver?.disconnect(); } async componentWillLoad() { setUpLoadableComponent(this); } //-------------------------------------------------------------------------- // // Event Listeners // //-------------------------------------------------------------------------- calciteInternalChipKeyEventListener(event) { if (event.composedPath().includes(this.el)) { const interactiveItems = this.items.filter((el) => !el.disabled); switch (event.detail.key) { case "ArrowRight": focusElementInGroup(interactiveItems, event.detail.target, "next"); break; case "ArrowLeft": focusElementInGroup(interactiveItems, event.detail.target, "previous"); break; case "Home": focusElementInGroup(interactiveItems, event.detail.target, "first"); break; case "End": focusElementInGroup(interactiveItems, event.detail.target, "last"); break; } } } calciteChipCloseListener(event) { const item = event.target; if (this.items.includes(item)) { if (this.items.indexOf(item) > 0) { focusElementInGroup(this.items, item, "previous"); } else if (this.items.indexOf(item) === 0) { focusElementInGroup(this.items, item, "next"); } else { focusElementInGroup(this.items, item, "first"); } } this.items = this.items.filter((el) => el !== item); } calciteChipSelectListener(event) { if (event.composedPath().includes(this.el)) { this.setSelectedItems(true, event.target); } } // -------------------------------------------------------------------------- // // Public Methods // // -------------------------------------------------------------------------- /** * Sets focus on the component's first focusable element. */ async setFocus() { await componentLoaded(this); if (!this.disabled) { (this.selectedItems[0] || this.items[0])?.setFocus(); } } //-------------------------------------------------------------------------- // // Render Methods // //-------------------------------------------------------------------------- render() { const role = this.selectionMode === "none" || this.selectionMode === "multiple" ? "group" : "radiogroup"; return (h("div", { "aria-disabled": toAriaBoolean(this.disabled), "aria-label": this.label, class: "container", role: role }, h("slot", { onSlotchange: this.updateItems, ref: (el) => (this.slotRefEl = el) }))); } static get is() { return "calcite-chip-group"; } static get encapsulation() { return "shadow"; } static get originalStyleUrls() { return { "$": ["chip-group.scss"] }; } static get styleUrls() { return { "$": ["chip-group.css"] }; } static get properties() { return { "disabled": { "type": "boolean", "mutable": false, "complexType": { "original": "boolean", "resolved": "boolean", "references": {} }, "required": false, "optional": false, "docs": { "tags": [], "text": "When `true`, interaction is prevented and the component is displayed with lower opacity." }, "attribute": "disabled", "reflect": true, "defaultValue": "false" }, "label": { "type": "string", "mutable": false, "complexType": { "original": "string", "resolved": "string", "references": {} }, "required": true, "optional": false, "docs": { "tags": [], "text": "Accessible name for the component." }, "attribute": "label", "reflect": false }, "scale": { "type": "string", "mutable": false, "complexType": { "original": "Scale", "resolved": "\"l\" | \"m\" | \"s\"", "references": { "Scale": { "location": "import", "path": "../interfaces" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Specifies the size of the component. Child `calcite-chip`s inherit the component's value." }, "attribute": "scale", "reflect": true, "defaultValue": "\"m\"" }, "selectionMode": { "type": "string", "mutable": false, "complexType": { "original": "Extract<\n \"multiple\" | \"single\" | \"single-persist\" | \"none\",\n SelectionMode\n >", "resolved": "\"multiple\" | \"none\" | \"single\" | \"single-persist\"", "references": { "Extract": { "location": "global" }, "SelectionMode": { "location": "import", "path": "../interfaces" } } }, "required": false, "optional": false, "docs": { "tags": [], "text": "Specifies the selection mode of the component." }, "attribute": "selection-mode", "reflect": true, "defaultValue": "\"none\"" }, "selectedItems": { "type": "unknown", "mutable": true, "complexType": { "original": "HTMLCalciteChipElement[]", "resolved": "HTMLCalciteChipElement[]", "references": { "HTMLCalciteChipElement": { "location": "global" } } }, "required": false, "optional": false, "docs": { "tags": [{ "name": "readonly", "text": undefined }], "text": "Specifies the component's selected items." }, "defaultValue": "[]" } }; } static get events() { return [{ "method": "calciteChipGroupSelect", "name": "calciteChipGroupSelect", "bubbles": true, "cancelable": false, "composed": true, "docs": { "tags": [], "text": "Emits when the component's selection changes." }, "complexType": { "original": "void", "resolved": "void", "references": {} } }]; } static get methods() { return { "setFocus": { "complexType": { "signature": "() => Promise<void>", "parameters": [], "references": { "Promise": { "location": "global" } }, "return": "Promise<void>" }, "docs": { "text": "Sets focus on the component's first focusable element.", "tags": [] } } }; } static get elementRef() { return "el"; } static get watchers() { return [{ "propName": "selectionMode", "methodName": "onSelectionModeChange" }]; } static get listeners() { return [{ "name": "calciteInternalChipKeyEvent", "method": "calciteInternalChipKeyEventListener", "target": undefined, "capture": false, "passive": false }, { "name": "calciteChipClose", "method": "calciteChipCloseListener", "target": undefined, "capture": false, "passive": false }, { "name": "calciteChipSelect", "method": "calciteChipSelectListener", "target": undefined, "capture": false, "passive": false }]; } }