123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520 |
- /*!
- * All material copyright ESRI, All Rights Reserved, unless otherwise specified.
- * See https://github.com/Esri/calcite-components/blob/master/LICENSE.md for details.
- * v1.0.0-beta.97
- */
- import { Host, h } from "@stencil/core";
- import { TreeSelectionMode } from "../tree/interfaces";
- import { nodeListToArray, getElementDir, filterDirectChildren, getSlotted, toAriaBoolean } from "../../utils/dom";
- import { CSS, SLOTS, ICONS } from "./resources";
- import { CSS_UTILITY } from "../../utils/resources";
- import { connectConditionalSlotComponent, disconnectConditionalSlotComponent } from "../../utils/conditionalSlot";
- import { updateHostInteraction } from "../../utils/interactive";
- /**
- * @slot - A slot for adding the component's content.
- * @slot children - A slot for adding nested `calcite-tree` elements.
- */
- export class TreeItem {
- constructor() {
- //--------------------------------------------------------------------------
- //
- // Properties
- //
- //--------------------------------------------------------------------------
- /**
- * When `true`, interaction is prevented and the component is displayed with lower opacity.
- */
- this.disabled = false;
- /** When `true`, the component is selected. */
- this.selected = false;
- /** When `true`, the component is expanded. */
- this.expanded = false;
- /**
- * @internal
- */
- this.parentExpanded = false;
- /**
- * @internal
- */
- this.depth = -1;
- /**
- * @internal
- */
- this.hasChildren = null;
- this.iconClickHandler = (event) => {
- event.stopPropagation();
- this.expanded = !this.expanded;
- };
- this.childrenClickHandler = (event) => event.stopPropagation();
- //--------------------------------------------------------------------------
- //
- // Private Methods
- //
- //--------------------------------------------------------------------------
- this.updateParentIsExpanded = (el, expanded) => {
- const items = getSlotted(el, SLOTS.children, {
- all: true,
- selector: "calcite-tree-item"
- });
- items.forEach((item) => (item.parentExpanded = expanded));
- };
- this.updateAncestorTree = () => {
- var _a;
- if (this.selected && this.selectionMode === TreeSelectionMode.Ancestors) {
- const ancestors = [];
- let parent = this.parentTreeItem;
- while (parent) {
- ancestors.push(parent);
- parent = (_a = parent.parentElement) === null || _a === void 0 ? void 0 : _a.closest("calcite-tree-item");
- }
- ancestors.forEach((item) => (item.indeterminate = true));
- return;
- }
- };
- }
- expandedHandler(newValue) {
- this.updateParentIsExpanded(this.el, newValue);
- }
- getselectionMode() {
- this.isSelectionMultiLike =
- this.selectionMode === TreeSelectionMode.Multi ||
- this.selectionMode === TreeSelectionMode.MultiChildren;
- }
- //--------------------------------------------------------------------------
- //
- // Lifecycle
- //
- //--------------------------------------------------------------------------
- connectedCallback() {
- var _a;
- this.parentTreeItem = (_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.closest("calcite-tree-item");
- if (this.parentTreeItem) {
- const { expanded } = this.parentTreeItem;
- this.updateParentIsExpanded(this.parentTreeItem, expanded);
- }
- connectConditionalSlotComponent(this);
- }
- disconnectedCallback() {
- disconnectConditionalSlotComponent(this);
- }
- componentWillRender() {
- var _a;
- this.hasChildren = !!this.el.querySelector("calcite-tree");
- this.depth = 0;
- let parentTree = this.el.closest("calcite-tree");
- if (!parentTree) {
- return;
- }
- this.selectionMode = parentTree.selectionMode;
- this.scale = parentTree.scale || "m";
- this.lines = parentTree.lines;
- let nextParentTree;
- while (parentTree) {
- nextParentTree = (_a = parentTree.parentElement) === null || _a === void 0 ? void 0 : _a.closest("calcite-tree");
- if (nextParentTree === parentTree) {
- break;
- }
- else {
- parentTree = nextParentTree;
- this.depth = this.depth + 1;
- }
- }
- }
- componentDidLoad() {
- this.updateAncestorTree();
- }
- componentDidRender() {
- updateHostInteraction(this, () => this.parentExpanded || this.depth === 1);
- }
- render() {
- const rtl = getElementDir(this.el) === "rtl";
- const showBulletPoint = this.selectionMode === TreeSelectionMode.Single ||
- this.selectionMode === TreeSelectionMode.Children;
- const showCheckmark = this.selectionMode === TreeSelectionMode.Multi ||
- this.selectionMode === TreeSelectionMode.MultiChildren;
- const showBlank = this.selectionMode === TreeSelectionMode.None && !this.hasChildren;
- const chevron = this.hasChildren ? (h("calcite-icon", { class: {
- [CSS.chevron]: true,
- [CSS_UTILITY.rtl]: rtl
- }, "data-test-id": "icon", icon: ICONS.chevronRight, onClick: this.iconClickHandler, scale: "s" })) : null;
- const defaultSlotNode = h("slot", { key: "default-slot" });
- const checkbox = this.selectionMode === TreeSelectionMode.Ancestors ? (h("label", { class: CSS.checkboxLabel, key: "checkbox-label" }, h("calcite-checkbox", { checked: this.selected, class: CSS.checkbox, "data-test-id": "checkbox", indeterminate: this.hasChildren && this.indeterminate, scale: this.scale, tabIndex: -1 }), defaultSlotNode)) : null;
- const selectedIcon = showBulletPoint
- ? ICONS.bulletPoint
- : showCheckmark
- ? ICONS.checkmark
- : showBlank
- ? ICONS.blank
- : null;
- const itemIndicator = selectedIcon ? (h("calcite-icon", { class: {
- [CSS.bulletPointIcon]: selectedIcon === ICONS.bulletPoint,
- [CSS.checkmarkIcon]: selectedIcon === ICONS.checkmark,
- [CSS_UTILITY.rtl]: rtl
- }, icon: selectedIcon, scale: "s" })) : null;
- const hidden = !(this.parentExpanded || this.depth === 1);
- return (h(Host, { "aria-expanded": this.hasChildren ? toAriaBoolean(this.expanded) : undefined, "aria-hidden": toAriaBoolean(hidden), "aria-selected": this.selected ? "true" : showCheckmark ? "false" : undefined, "calcite-hydrated-hidden": hidden, role: "treeitem" }, h("div", { class: {
- [CSS.nodeContainer]: true,
- [CSS_UTILITY.rtl]: rtl
- }, "data-selection-mode": this.selectionMode, ref: (el) => (this.defaultSlotWrapper = el) }, chevron, itemIndicator, checkbox ? checkbox : defaultSlotNode), h("div", { class: {
- [CSS.childrenContainer]: true,
- [CSS_UTILITY.rtl]: rtl
- }, "data-test-id": "calcite-tree-children", onClick: this.childrenClickHandler, ref: (el) => (this.childrenSlotWrapper = el), role: this.hasChildren ? "group" : undefined }, h("slot", { name: SLOTS.children }))));
- }
- //--------------------------------------------------------------------------
- //
- // Event Listeners
- //
- //--------------------------------------------------------------------------
- onClick(event) {
- // Solve for if the item is clicked somewhere outside the slotted anchor.
- // Anchor is triggered anywhere you click
- const [link] = filterDirectChildren(this.el, "a");
- if (link && event.composedPath()[0].tagName.toLowerCase() !== "a") {
- const target = link.target === "" ? "_self" : link.target;
- window.open(link.href, target);
- }
- this.calciteInternalTreeItemSelect.emit({
- modifyCurrentSelection: this.selectionMode === TreeSelectionMode.Ancestors || this.isSelectionMultiLike,
- forceToggle: false
- });
- }
- keyDownHandler(event) {
- let root;
- switch (event.key) {
- case " ":
- this.calciteInternalTreeItemSelect.emit({
- modifyCurrentSelection: this.isSelectionMultiLike,
- forceToggle: false
- });
- event.preventDefault();
- break;
- case "Enter":
- // activates a node, i.e., performs its default action. For parent nodes, one possible default action is to open or close the node. In single-select trees where selection does not follow focus (see note below), the default action is typically to select the focused node.
- const link = nodeListToArray(this.el.children).find((el) => el.matches("a"));
- if (link) {
- link.click();
- this.selected = true;
- }
- else {
- this.calciteInternalTreeItemSelect.emit({
- modifyCurrentSelection: this.isSelectionMultiLike,
- forceToggle: false
- });
- }
- event.preventDefault();
- break;
- case "Home":
- root = this.el.closest("calcite-tree:not([child])");
- const firstNode = root.querySelector("calcite-tree-item");
- firstNode === null || firstNode === void 0 ? void 0 : firstNode.focus();
- break;
- case "End":
- root = this.el.closest("calcite-tree:not([child])");
- let currentNode = root.children[root.children.length - 1]; // last child
- let currentTree = nodeListToArray(currentNode.children).find((el) => el.matches("calcite-tree"));
- while (currentTree) {
- currentNode = currentTree.children[root.children.length - 1];
- currentTree = nodeListToArray(currentNode.children).find((el) => el.matches("calcite-tree"));
- }
- currentNode === null || currentNode === void 0 ? void 0 : currentNode.focus();
- break;
- }
- }
- static get is() { return "calcite-tree-item"; }
- static get encapsulation() { return "shadow"; }
- static get originalStyleUrls() {
- return {
- "$": ["tree-item.scss"]
- };
- }
- static get styleUrls() {
- return {
- "$": ["tree-item.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"
- },
- "selected": {
- "type": "boolean",
- "mutable": true,
- "complexType": {
- "original": "boolean",
- "resolved": "boolean",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [],
- "text": "When `true`, the component is selected."
- },
- "attribute": "selected",
- "reflect": true,
- "defaultValue": "false"
- },
- "expanded": {
- "type": "boolean",
- "mutable": true,
- "complexType": {
- "original": "boolean",
- "resolved": "boolean",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [],
- "text": "When `true`, the component is expanded."
- },
- "attribute": "expanded",
- "reflect": true,
- "defaultValue": "false"
- },
- "parentExpanded": {
- "type": "boolean",
- "mutable": false,
- "complexType": {
- "original": "boolean",
- "resolved": "boolean",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [{
- "name": "internal",
- "text": undefined
- }],
- "text": ""
- },
- "attribute": "parent-expanded",
- "reflect": false,
- "defaultValue": "false"
- },
- "depth": {
- "type": "number",
- "mutable": true,
- "complexType": {
- "original": "number",
- "resolved": "number",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [{
- "name": "internal",
- "text": undefined
- }],
- "text": ""
- },
- "attribute": "depth",
- "reflect": true,
- "defaultValue": "-1"
- },
- "hasChildren": {
- "type": "boolean",
- "mutable": true,
- "complexType": {
- "original": "boolean",
- "resolved": "boolean",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [{
- "name": "internal",
- "text": undefined
- }],
- "text": ""
- },
- "attribute": "has-children",
- "reflect": true,
- "defaultValue": "null"
- },
- "lines": {
- "type": "boolean",
- "mutable": true,
- "complexType": {
- "original": "boolean",
- "resolved": "boolean",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [{
- "name": "internal",
- "text": undefined
- }],
- "text": ""
- },
- "attribute": "lines",
- "reflect": true
- },
- "inputEnabled": {
- "type": "boolean",
- "mutable": false,
- "complexType": {
- "original": "boolean",
- "resolved": "boolean",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [{
- "name": "internal",
- "text": undefined
- }, {
- "name": "deprecated",
- "text": "Use `selectionMode=\"ancestors\"` for checkbox input."
- }],
- "text": "Displays checkboxes (set on parent)."
- },
- "attribute": "input-enabled",
- "reflect": false
- },
- "scale": {
- "type": "string",
- "mutable": true,
- "complexType": {
- "original": "Scale",
- "resolved": "\"l\" | \"m\" | \"s\"",
- "references": {
- "Scale": {
- "location": "import",
- "path": "../interfaces"
- }
- }
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [{
- "name": "internal",
- "text": undefined
- }],
- "text": ""
- },
- "attribute": "scale",
- "reflect": true
- },
- "indeterminate": {
- "type": "boolean",
- "mutable": false,
- "complexType": {
- "original": "boolean",
- "resolved": "boolean",
- "references": {}
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [{
- "name": "internal",
- "text": undefined
- }],
- "text": "In ancestor selection mode, show as indeterminate when only some children are selected."
- },
- "attribute": "indeterminate",
- "reflect": true
- },
- "selectionMode": {
- "type": "string",
- "mutable": true,
- "complexType": {
- "original": "TreeSelectionMode",
- "resolved": "TreeSelectionMode.Ancestors | TreeSelectionMode.Children | TreeSelectionMode.Multi | TreeSelectionMode.MultiChildren | TreeSelectionMode.None | TreeSelectionMode.Single",
- "references": {
- "TreeSelectionMode": {
- "location": "import",
- "path": "../tree/interfaces"
- }
- }
- },
- "required": false,
- "optional": false,
- "docs": {
- "tags": [{
- "name": "internal",
- "text": undefined
- }],
- "text": ""
- },
- "attribute": "selection-mode",
- "reflect": true
- }
- };
- }
- static get events() {
- return [{
- "method": "calciteInternalTreeItemSelect",
- "name": "calciteInternalTreeItemSelect",
- "bubbles": true,
- "cancelable": false,
- "composed": true,
- "docs": {
- "tags": [{
- "name": "internal",
- "text": undefined
- }],
- "text": ""
- },
- "complexType": {
- "original": "TreeItemSelectDetail",
- "resolved": "TreeItemSelectDetail",
- "references": {
- "TreeItemSelectDetail": {
- "location": "import",
- "path": "./interfaces"
- }
- }
- }
- }];
- }
- static get elementRef() { return "el"; }
- static get watchers() {
- return [{
- "propName": "expanded",
- "methodName": "expandedHandler"
- }, {
- "propName": "selectionMode",
- "methodName": "getselectionMode"
- }];
- }
- static get listeners() {
- return [{
- "name": "click",
- "method": "onClick",
- "target": undefined,
- "capture": false,
- "passive": false
- }, {
- "name": "keydown",
- "method": "keyDownHandler",
- "target": undefined,
- "capture": false,
- "passive": false
- }];
- }
- }
|