@cisstech/nge
Version:
NG Essentials is a collection of libraries for Angular developers.
859 lines • 115 kB
JavaScript
import { FlatTreeControl } from '@angular/cdk/tree';
import { ChangeDetectionStrategy, Component, ContentChild, HostListener, Input, } from '@angular/core';
import { MatTreeFlatDataSource, MatTreeFlattener } from '@angular/material/tree';
import { BehaviorSubject } from 'rxjs';
import { CURRENT_VISIBLE_TREES } from './internal';
import { TreeNodeDirective } from './tree-node.directive';
import { TreeFilter, } from './tree.model';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
import * as i2 from "@angular/forms";
import * as i3 from "./autofocus.directive";
export class TreeComponent {
get treeHeight() {
return this.adapter?.itemHeight?.toString() || '100%';
}
constructor(elementRef, changeDetectorRef) {
this.elementRef = elementRef;
this.changeDetectorRef = changeDetectorRef;
this.nodes = [];
this.DATA_TREE_NODE_ID = 'data-tree-node-id';
this.nodesIndex = new Map();
this.parentsIndex = new Map();
this.hiddenNodes = new Map();
this.selectedNodes = new Map();
this.isEmpty = false;
this.isShiftKeyPressed = false;
this.editing = { text: '', node: undefined };
this.visibleNodes = new BehaviorSubject([]);
this.filter = new TreeFilter();
this.controler = new FlatTreeControl((node) => node.level, (node) => node.expandable, {
trackBy: (node) => node,
});
this.flattener = new MatTreeFlattener((node, level) => this.transformer(node, level), (node) => node.level, (node) => node.expandable, (node) => this.children(node));
this.dataSource = new MatTreeFlatDataSource(this.controler, this.flattener);
}
ngOnInit() {
if (!this.adapter.id?.trim()) {
throw new Error('@Input() adapter.id is required !');
}
CURRENT_VISIBLE_TREES.set(this.adapter.id, this);
}
ngOnChanges() {
if (!this.adapter) {
throw new Error('@Input() adapter is required !');
}
const requires = ['id', 'idProvider', 'nameProvider', 'isExpandable', 'childrenProvider'];
for (const key of requires) {
const value = this.adapter[key];
if (!value || (typeof value === 'string' && value.trim() === '')) {
throw new Error(`@Input() adapter.${key} is required !`);
}
}
this.adapter.itemHeight = this.adapter.itemHeight || 32;
this.adapter.treeHeight = this.adapter.treeHeight || '100%';
this.adapter.keepStateOnChangeNodes = this.adapter.keepStateOnChangeNodes ?? true;
let state;
if (this.adapter.keepStateOnChangeNodes) {
state = this.saveState();
}
this.buildIndexes();
if (state) {
this.restoreState(state);
}
else {
this.unselectAll(false);
this.render();
}
}
ngOnDestroy() {
if (this.adapter?.id) {
CURRENT_VISIBLE_TREES.delete(this.adapter.id);
}
}
//#region API
selections() {
return Array.from(this.selectedNodes.values()).map((e) => e.data);
}
focusedNode() {
return this.activeNode?.data;
}
isFocused(node) {
if (node == null) {
throw new ReferenceError('Argument "node" is required.');
}
if (!this.activeNode) {
return false;
}
return this.findHolder(node)?.id === this.activeNode.id;
}
isExpanded(node) {
if (node == null) {
throw new ReferenceError('Argument "node" is required.');
}
const holder = this.findHolder(node);
if (!holder?.expandable) {
return false;
}
return this.controler.isExpanded(holder);
}
isSelected(node) {
if (node == null) {
throw new ReferenceError('Argument "node" is required.');
}
const holder = this.findHolder(node);
if (!holder) {
return false;
}
return this.selectedNodes.has(holder.id);
}
focus(node, render = true) {
const holder = this.findHolder(node);
if (holder) {
if (this.activeNode) {
this.unselect(this.activeNode, false);
}
this.activeNode = holder;
this.select(node, false);
this.expandAncestors(holder);
if (render) {
this.render();
}
this.scrollInto(holder);
}
}
unfocus() {
this.activeNode = undefined;
this.changeDetectorRef.detectChanges();
}
expand(node, render = true) {
if (!node) {
return;
}
const holder = this.findHolder(node);
if (!holder) {
return;
}
if (holder.expandable && !this.controler.isExpanded(holder)) {
this.controler.expand(holder);
this.expandAncestors(holder);
if (render) {
this.render();
}
}
}
expandAll(render = true) {
this.controler.dataNodes?.forEach((node) => {
this.controler.expand(node);
});
// this.controler.expandAll(); // https://github.com/vmware/clarity/issues/4850
if (render) {
this.render();
}
}
collapse(node, render = true) {
if (!node) {
return;
}
const holder = this.findHolder(node);
if (!holder) {
return;
}
if (holder.expandable && this.controler.isExpanded(holder)) {
this.controler.collapse(holder);
if (this.adapter.onDidCollapse) {
this.adapter.onDidCollapse(holder.data);
}
if (render) {
this.render();
}
}
}
collapseAll(render = true) {
this.controler.collapseAll();
if (render) {
this.render();
}
}
toggle(node, render = true) {
if (!node) {
return;
}
const holder = this.findHolder(node);
if (holder?.expandable) {
if (this.controler.isExpanded(holder)) {
this.collapse(node, render);
}
else {
this.expand(node, render);
}
}
}
startEdition(node, creation) {
if (!this.adapter.onDidEditName)
return;
if (!node) {
throw new ReferenceError('Argument "node" is required.');
}
const holder = this.findHolder(node);
if (holder) {
this.unselectAll(false);
this.editing.node = holder.data;
this.editing.text = creation ? '' : holder.name;
this.editing.creation = creation;
holder.renaming = !creation;
holder.creating = creation;
if (holder.expandable && !this.isExpanded(holder)) {
this.expand(node);
}
}
this.changeDetectorRef.detectChanges();
}
endEdition() {
const holder = this.findHolder(this.editing.node);
if (holder) {
holder.renaming = false;
holder.creating = false;
}
this.editing = { text: '' };
this.changeDetectorRef.detectChanges();
}
search(filter) {
if (!this.filter.term) {
this.stateBeforeSearching = this.saveState();
}
this.filter.term = (filter.term || '').trim();
if (!this.filter.term) {
if (this.stateBeforeSearching) {
this.restoreState(this.stateBeforeSearching);
this.stateBeforeSearching = undefined;
}
else {
this.hiddenNodes.clear();
this.render();
}
return;
}
const pattern = this.buildSearchPattern();
if (pattern) {
this.activeNode = undefined;
this.hiddenNodes.clear();
this.selectedNodes.clear();
this.collapseAll(false);
const p = pattern;
const matches = new Set();
const nodes = this.controler.dataNodes || [];
const n = nodes.length - 1;
for (let i = n; i >= 0; i--) {
const node = nodes[i];
if (matches.has(node.id))
continue;
if (node.name.toLowerCase().match(p)) {
matches.add(node.id);
this.iterateAncestors(node, (e) => {
this.controler.expand(e);
matches.add(e.id);
});
}
else {
this.hiddenNodes.set(node.id, node);
}
}
this.render();
}
else {
this.changeDetectorRef.detectChanges();
}
}
saveState() {
const { term } = this.filter;
const dataNodes = this.controler.dataNodes || [];
const state = {
filter: { term },
active: this.activeNode ? this.activeNode.id : '',
expandedNodes: dataNodes
.filter((e) => {
return this.controler.isExpanded(e);
})
.map((e) => e.id),
};
return state;
}
restoreState(state) {
state = state || {
active: '',
filter: new TreeFilter(),
expandedNodes: [],
};
state.active = state.active || '';
state.filter = state.filter || new TreeFilter();
state.expandedNodes = state.expandedNodes || [];
this.hiddenNodes.clear();
this.selectedNodes.clear();
this.collapseAll(false);
const { active, filter, expandedNodes } = state;
if (filter.term) {
this.search(filter);
}
else {
expandedNodes.forEach((node) => this.expand(node, false));
this.render();
}
if (active) {
const activeNode = this.findHolder(active);
if (activeNode) {
this.focus(activeNode);
}
}
}
//#endregion
//#region CALLED FROM TEMPLATE
_onEdit(event) {
if (this.adapter.onDidEditName) {
event.stopPropagation();
const { node, text, creation } = this.editing;
if (!node) {
throw new Error('There is no focused node.');
}
const isBlur = event instanceof FocusEvent && event.type === 'blur';
const isEnter = event instanceof KeyboardEvent && event.key === 'Enter';
const isEscape = event instanceof KeyboardEvent && event.key === 'Escape';
if (isEscape) {
event.preventDefault();
this.endEdition();
}
else if (isBlur || isEnter) {
event.preventDefault();
const name = text?.trim() || '';
try {
if (name) {
this.adapter.onDidEditName({
node: node,
text: name,
creation,
});
}
}
finally {
this.focus(node);
this.endEdition();
}
}
}
}
_clearFilter() {
this.search({ term: '' });
}
_isRenaming(node) {
if (node == null) {
throw new ReferenceError('Argument "node" is required.');
}
if (!this.editing?.node) {
return false;
}
return !this.editing.creation && this.findHolder(node)?.id === this.adapter.idProvider(this.editing.node);
}
_isCreating(node) {
if (node == null) {
throw new ReferenceError('Argument "node" is required.');
}
if (!this.editing?.node) {
return false;
}
return !!this.editing.creation && this.findHolder(node)?.id === this.adapter.idProvider(this.editing.node);
}
_trackById(_, e) {
return e.id;
}
//#endregion
//#region EVENTS
keyup() {
this.isShiftKeyPressed = false;
}
keydown($event) {
this.isShiftKeyPressed = $event.shiftKey;
if (this.isTreeContainsEvent($event)) {
this.onKeyDown($event);
}
}
mousedown($event) {
this.changeDetectorRef.detach();
if (this.isTreeContainsEvent($event)) {
this.changeDetectorRef.reattach();
this.onMouseDown($event);
}
}
contextmenu($event) {
this.changeDetectorRef.detach();
if (this.isTreeContainsEvent($event)) {
this.changeDetectorRef.reattach();
this.onContextMenu($event);
}
}
onKeyDown(event) {
if (!this.activeNode && !this.isEmpty && !this.selectedNodes.size) {
this.focus(this.controler.dataNodes[0]);
}
const element = this.activeNode ? this.domNode(this.activeNode) : undefined;
if (element && this.activeNode) {
switch (event.key) {
case 'ArrowUp':
event.preventDefault();
event.stopPropagation();
this.navigate(element, 'up');
break;
case 'ArrowDown':
event.preventDefault();
event.stopPropagation();
this.navigate(element, 'down');
break;
case 'ArrowLeft':
if (!this.isShiftKeyPressed) {
event.preventDefault();
event.stopPropagation();
this.collapse(this.activeNode, true);
}
break;
case 'ArrowRight':
if (!this.isShiftKeyPressed) {
event.preventDefault();
event.stopPropagation();
this.expand(this.activeNode, true);
}
break;
default:
this.triggerKeyboardEvent(event);
this.triggerFilterEvent(event);
break;
}
}
else {
this.triggerFilterEvent(event);
}
if (event.key === 'Backspace') {
// prevent browser to navigate back if Backspace is pressed
event.preventDefault();
}
}
onMouseDown(event) {
const node = this.findHolderFromEvent(event);
if (!node) {
return;
}
if (this.isShiftKeyPressed && this.activeNode) {
const domStart = this.domNode(this.activeNode);
if (!domStart) {
this.select(node);
return;
}
const domEnd = this.domNode(node);
if (!domEnd) {
return;
}
// select all nodes between the focused and the target node.
this.unselectAll(false);
let cursor = domStart;
const y2 = domEnd.getClientRects().item(0).top;
const y1 = domStart.getClientRects().item(0).top;
if (y1 < y2) {
// traverse down
do {
this.select(cursor, false);
cursor = cursor.nextElementSibling;
} while (cursor && !cursor.isEqualNode(domEnd));
}
else if (y1 > y2) {
// traverse up
do {
this.select(cursor, false);
cursor = cursor.previousElementSibling;
} while (cursor && !cursor.isEqualNode(domEnd));
}
this.select(domEnd, false);
this.focus(node, true);
}
else {
this.unselectAll(false);
this.toggle(node, false);
this.focus(node, true);
const { actions } = this.adapter;
if (actions?.mouse?.click) {
actions.mouse.click({
node: node.data,
event: event,
});
}
}
}
onContextMenu(e) {
e.preventDefault();
e.stopPropagation();
const node = this.findHolderFromEvent(e);
if (node) {
if (!this.isSelected(node)) {
this.unselectAll(false);
}
this.focus(node, true);
}
const { actions } = this.adapter;
if (actions?.mouse?.rightClick) {
actions.mouse.rightClick({
node: node?.data,
event: e,
});
}
}
isTreeContainsEvent(event) {
return this.elementRef.nativeElement.contains(event.target);
}
triggerFilterEvent(e) {
if (e.defaultPrevented || !this.adapter.enableKeyboardFiltering) {
return;
}
// prevent browser to navigate back if Backspace is pressed
e.preventDefault();
e.stopPropagation();
const { term } = this.filter;
switch (e.key) {
case 'Backspace':
if (term) {
this.search({ term: term.slice(0, -1) });
}
break;
case ' ':
case 'Tab':
break;
default:
if (e.key.length === 1) {
this.search({ term: term + e.key });
}
break;
}
}
triggerKeyboardEvent(event) {
if (!this.activeNode) {
return;
}
const { actions } = this.adapter;
if (actions) {
const { keys } = actions;
if (keys) {
const action = keys[event.key];
if (action) {
action({
event: event,
node: this.activeNode.data,
});
}
}
}
}
//#endregion
//#region PRIVATE
render() {
const nodes = [];
const dataNodes = this.controler.dataNodes || [];
const expandedNodes = new Set(this.controler.expansionModel.selected.map((node) => node.id));
this.isEmpty = true;
dataNodes.forEach((node) => {
this.isEmpty = false;
if (this.hiddenNodes.has(node.id)) {
return;
}
node.focused = this.isFocused(node);
node.expanded = this.isExpanded(node);
node.renaming = this._isRenaming(node);
node.creating = this._isCreating(node);
node.selected = this.isSelected(node);
// root nodes are always visible
if (node.level === 0) {
nodes.push(node);
return;
}
let parent = this.findParent(node);
while (parent != null) {
// hide a node if any of its ancestors is not expanded
if (!expandedNodes.has(parent.id)) {
return;
}
if (parent.level === 0) {
break;
}
parent = this.findParent(parent);
}
nodes.push(node);
});
this.visibleNodes.next(nodes);
this.changeDetectorRef.detectChanges();
}
buildIndexes() {
this.nodesIndex.clear();
this.parentsIndex.clear();
this.dataSource.data = this.nodes;
this.controler.dataNodes?.forEach((node) => {
this.nodesIndex.set(node.id, node);
});
}
buildSearchPattern() {
let pattern;
try {
if (this.filter.term) {
const escape = (text) => {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
};
pattern = new RegExp(`(${escape(this.filter.term)})`, 'g');
}
}
catch (error) {
console.error(error);
}
return pattern;
}
/**
* Gets the dom element associated to the given node.
* @param e A node.
*/
domNode(e) {
const node = this.findHolder(e);
if (!node) {
throw new Error(e + ' is not a registered node');
}
return document.querySelector(`[${this.DATA_TREE_NODE_ID}="${node.id}"]`);
}
/**
* Adds the given node to the selected nodes.
* @param node The node to select.
*/
select(node, detectChanges = true) {
const holder = this.findHolder(node);
if (!holder) {
return;
}
this.selectedNodes.set(holder.id, holder);
if (detectChanges) {
this.changeDetectorRef.detectChanges();
}
}
/**
* Removes the given node to the selected nodes.
* @param node The node to unselect.
*/
unselect(node, detectChanges = true) {
const holder = this.findHolder(node);
if (!holder) {
return;
}
this.selectedNodes.delete(holder.id);
if (holder.id === this.activeNode?.id) {
this.activeNode = undefined;
}
if (detectChanges) {
this.changeDetectorRef.detectChanges();
}
}
/**
* Clears the selected nodes.
*/
unselectAll(detectChanges = true) {
this.activeNode = undefined;
this.selectedNodes.clear();
if (detectChanges) {
this.changeDetectorRef.detectChanges();
}
}
/**
* Expands the ancestors of the given node.
* @param node A node reference.
*/
expandAncestors(node) {
this.iterateAncestors(node, (e) => {
if (e.expandable && !this.controler.isExpanded(e)) {
this.controler.expand(e);
if (this.adapter.onDidExpand) {
this.adapter.onDidExpand(e.data);
}
}
});
}
/**
* Call the given `action` for the ancestors of the given node.
* @param node A node reference.
* @param action A function to call for each ancestor.
*/
iterateAncestors(node, action) {
const recursive = (e) => {
action(e);
const p = this.findParent(e);
if (p && p.level >= 0) {
recursive(p);
}
};
const parent = this.findParent(node);
if (parent) {
recursive(parent);
}
}
/**
* Moves the scrollbar to the given node.
* @param node The node to show.
*/
scrollInto(node) {
const holder = this.findHolder(node);
if (holder) {
const index = this.visibleNodes.value.indexOf(holder);
if (index == -1) {
return;
}
this.domNode(node)?.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}
/**
* Focus the node before of after `currEl` depending on the given `direction`.
* @param currEl Current element
* @param direction Navigation direction.
*/
navigate(currEl, direction) {
this.unselectAll();
const currNode = this.findHolderFromElement(currEl);
if (!currNode) {
return;
}
const prevEl = currEl.previousElementSibling;
const nextEl = currEl.nextElementSibling;
const targEl = direction === 'up' ? prevEl : nextEl;
if (!targEl) {
return;
}
const targNode = this.findHolderFromElement(targEl);
if (!targNode) {
this.focus(currNode);
return;
}
const prevNode = prevEl ? this.findHolderFromElement(prevEl) : undefined;
if (prevNode && this.isSelected(prevNode) && targEl.isEqualNode(prevEl)) {
this.unselect(currNode);
}
const nextNode = nextEl ? this.findHolderFromElement(nextEl) : undefined;
if (nextNode && this.isSelected(nextNode) && targEl.isEqualNode(nextEl)) {
this.unselect(currNode);
}
this.focus(targNode);
}
findParent(node) {
const holder = this.findHolder(node);
if (!holder) {
return;
}
const parentId = this.parentsIndex.get(holder.id);
if (parentId) {
return this.nodesIndex.get(parentId);
}
return undefined;
}
findHolderFromId(id) {
const { dataNodes } = this.controler;
if (!dataNodes) {
return undefined;
}
return dataNodes.find((n) => n.id === id);
}
findHolderFromData(data) {
const { dataNodes } = this.controler;
if (!dataNodes) {
return undefined;
}
return this.nodesIndex.get(this.adapter.idProvider(data));
}
findHolderFromEvent(event) {
const { dataNodes } = this.controler;
if (!dataNodes) {
return undefined;
}
const dataId = this.DATA_TREE_NODE_ID;
const fn = (target) => {
if (!target) {
return undefined;
}
const targetId = target.getAttribute(dataId);
return targetId ? this.nodesIndex.get(targetId) : fn(target.parentElement);
};
return fn(event.target);
}
findHolderFromElement(element) {
const { dataNodes } = this.controler;
if (!dataNodes) {
return undefined;
}
const id = element.getAttribute(this.DATA_TREE_NODE_ID);
if (!id) {
return undefined;
}
return this.nodesIndex.get(id);
}
findHolder(node) {
if (!node) {
return undefined;
}
if (!this.controler.dataNodes) {
return undefined;
}
if (typeof node === 'string') {
return this.findHolderFromId(node);
}
if (node instanceof Element) {
return this.findHolderFromElement(node);
}
// instanceof ITreeNodeHolder<T>
if ('data' in node) {
return node;
}
// instance of T
return this.findHolderFromData(node);
}
children(node) {
const children = this.adapter.childrenProvider(node) || [];
const parentId = this.adapter.idProvider(node);
children.forEach((child) => {
this.parentsIndex.set(this.adapter.idProvider(child), parentId);
});
return children;
}
transformer(node, level) {
const expandable = this.adapter.isExpandable(node);
return {
id: this.adapter.idProvider(node),
data: node,
name: this.adapter.nameProvider(node),
level: level,
padding: level * 12 + 'px',
tooltip: this.adapter.tooltipProvider?.(node),
expandable,
};
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: TreeComponent, deps: [{ token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.1", type: TreeComponent, selector: "ui-tree", inputs: { nodes: "nodes", adapter: "adapter" }, host: { listeners: { "document:keyup": "keyup()", "document:keydown": "keydown($event)", "document:click": "mousedown($event)", "document:contextmenu": "contextmenu($event)" } }, queries: [{ propertyName: "nodeDirective", first: true, predicate: TreeNodeDirective, descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"filter.term\">\n <div class=\"tree-filter\" title=\"Filter\">\n <span class=\"tree-filter__label\">{{ filter.term }}</span>\n <div class=\"tree-filter__commands\">\n <span class=\"command-clear\" role=\"button\" title=\"Clear\" (click)=\"_clearFilter()\">×</span>\n </div>\n </div>\n</ng-container>\n\n<div\n tabindex=\"0\"\n class=\"tree-component\"\n [class.editing]=\"editing.node != null\"\n [style.height]=\"treeHeight\">\n <ng-container *ngFor=\"let node of visibleNodes|async; trackBy: _trackById;\">\n <!-- RENAMING -->\n <ng-container *ngIf=\"node.renaming; else: nodeTemplate\">\n <div\n class=\"tree-node opaque focused selected tree-node--level-{{ node.level + 1 }}\"\n [attr.data-tree-node-id]=\"node.id\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"inputTemplate\" />\n </div>\n </div>\n </ng-container>\n\n <!-- NODE -->\n <ng-template #nodeTemplate>\n <div\n class=\"tree-node tree-node--level-{{ node.level }}\"\n [attr.data-tree-node-id]=\"node.id\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\"\n [ngClass]=\"{\n focused: node.focused,\n selected: node.selected,\n expanded: node.expanded\n }\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"nodeDirective.templateRef; context: { $implicit: node }\" />\n </div>\n </div>\n </ng-template>\n\n <!-- CREATING -->\n <ng-container *ngIf=\"node.creating\">\n <div\n class=\"tree-node opaque focused selected tree-node--level-{{ node.level + 1 }}\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"inputTemplate\" />\n </div>\n </div>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #inputTemplate>\n <span class=\"tree-input\">\n <input\n autofocus\n type=\"text\"\n placeholder=\"Press Enter to create ESC to cancel...\"\n (click)=\"$event.preventDefault(); $event.stopPropagation()\"\n [(ngModel)]=\"editing.text\"\n (keydown)=\"_onEdit($event)\"\n (blur)=\"_onEdit($event)\" />\n </span>\n</ng-template>\n", styles: [":host{position:relative;--tree-selection-color: #bae7ff}.tree-component{height:100%;background:transparent}.tree-component:hover{outline:none}.tree-component:hover .tree-node.focused,.tree-component:hover .tree-node.selected{background-color:var(--tree-selection-color)}.tree-component.editing .opaque{opacity:1!important}.tree-component.editing .tree-node{opacity:.4}.tree-node:hover,.tree-node.focused,.tree-node.selected{background-color:#4242420a}.tree-node,.tree-node__content{cursor:pointer;position:relative;width:100%;display:flex;overflow:hidden;align-items:center;box-sizing:border-box}.tree-node__content{padding:0 12px}.tree-input{display:flex;align-items:center;width:calc(100% - 4px);margin-right:4px}.tree-input input{width:100%;margin:0 0 0 8px;padding:.1rem .3rem;font-size:.8rem;line-height:1.5;background-clip:padding-box;border:1px solid #ced4da;border-radius:.15rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.tree-input input:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.tree-filter{background-color:#efc1ad;display:flex;align-items:center;position:absolute;border-radius:2px;padding:0 4px;max-width:calc(100% - 10px);text-overflow:ellipsis;overflow:hidden;text-align:right;box-sizing:border-box;cursor:all-scroll;font-size:13px;line-height:18px;height:20px;z-index:1;right:0;outline:rgba(0,0,0,0) solid 4px;transition:width .5s}.tree-filter:hover .tree-filter__commands{display:flex}.tree-filter .tree-filter__commands{display:none;display:flex;align-items:center}.tree-filter .tree-filter__commands span{cursor:pointer;font-size:18px;margin-left:4px}.tree-filter .command-filter{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}\n"], dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.AutofocusDirective, selector: "input[autofocus]" }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.1", ngImport: i0, type: TreeComponent, decorators: [{
type: Component,
args: [{ selector: 'ui-tree', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ng-container *ngIf=\"filter.term\">\n <div class=\"tree-filter\" title=\"Filter\">\n <span class=\"tree-filter__label\">{{ filter.term }}</span>\n <div class=\"tree-filter__commands\">\n <span class=\"command-clear\" role=\"button\" title=\"Clear\" (click)=\"_clearFilter()\">×</span>\n </div>\n </div>\n</ng-container>\n\n<div\n tabindex=\"0\"\n class=\"tree-component\"\n [class.editing]=\"editing.node != null\"\n [style.height]=\"treeHeight\">\n <ng-container *ngFor=\"let node of visibleNodes|async; trackBy: _trackById;\">\n <!-- RENAMING -->\n <ng-container *ngIf=\"node.renaming; else: nodeTemplate\">\n <div\n class=\"tree-node opaque focused selected tree-node--level-{{ node.level + 1 }}\"\n [attr.data-tree-node-id]=\"node.id\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"inputTemplate\" />\n </div>\n </div>\n </ng-container>\n\n <!-- NODE -->\n <ng-template #nodeTemplate>\n <div\n class=\"tree-node tree-node--level-{{ node.level }}\"\n [attr.data-tree-node-id]=\"node.id\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\"\n [ngClass]=\"{\n focused: node.focused,\n selected: node.selected,\n expanded: node.expanded\n }\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"nodeDirective.templateRef; context: { $implicit: node }\" />\n </div>\n </div>\n </ng-template>\n\n <!-- CREATING -->\n <ng-container *ngIf=\"node.creating\">\n <div\n class=\"tree-node opaque focused selected tree-node--level-{{ node.level + 1 }}\"\n [style.padding-left]=\"node.padding\"\n [style.height.px]=\"adapter.itemHeight\">\n <div class=\"tree-node__content\" [style.height.px]=\"adapter.itemHeight\">\n <ng-container *ngTemplateOutlet=\"inputTemplate\" />\n </div>\n </div>\n </ng-container>\n </ng-container>\n</div>\n\n<ng-template #inputTemplate>\n <span class=\"tree-input\">\n <input\n autofocus\n type=\"text\"\n placeholder=\"Press Enter to create ESC to cancel...\"\n (click)=\"$event.preventDefault(); $event.stopPropagation()\"\n [(ngModel)]=\"editing.text\"\n (keydown)=\"_onEdit($event)\"\n (blur)=\"_onEdit($event)\" />\n </span>\n</ng-template>\n", styles: [":host{position:relative;--tree-selection-color: #bae7ff}.tree-component{height:100%;background:transparent}.tree-component:hover{outline:none}.tree-component:hover .tree-node.focused,.tree-component:hover .tree-node.selected{background-color:var(--tree-selection-color)}.tree-component.editing .opaque{opacity:1!important}.tree-component.editing .tree-node{opacity:.4}.tree-node:hover,.tree-node.focused,.tree-node.selected{background-color:#4242420a}.tree-node,.tree-node__content{cursor:pointer;position:relative;width:100%;display:flex;overflow:hidden;align-items:center;box-sizing:border-box}.tree-node__content{padding:0 12px}.tree-input{display:flex;align-items:center;width:calc(100% - 4px);margin-right:4px}.tree-input input{width:100%;margin:0 0 0 8px;padding:.1rem .3rem;font-size:.8rem;line-height:1.5;background-clip:padding-box;border:1px solid #ced4da;border-radius:.15rem;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}.tree-input input:focus{border-color:#80bdff;outline:0;box-shadow:0 0 0 .2rem #007bff40}.tree-filter{background-color:#efc1ad;display:flex;align-items:center;position:absolute;border-radius:2px;padding:0 4px;max-width:calc(100% - 10px);text-overflow:ellipsis;overflow:hidden;text-align:right;box-sizing:border-box;cursor:all-scroll;font-size:13px;line-height:18px;height:20px;z-index:1;right:0;outline:rgba(0,0,0,0) solid 4px;transition:width .5s}.tree-filter:hover .tree-filter__commands{display:flex}.tree-filter .tree-filter__commands{display:none;display:flex;align-items:center}.tree-filter .tree-filter__commands span{cursor:pointer;font-size:18px;margin-left:4px}.tree-filter .command-filter{-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg)}\n"] }]
}], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.ChangeDetectorRef }], propDecorators: { nodes: [{
type: Input
}], adapter: [{
type: Input
}], nodeDirective: [{
type: ContentChild,
args: [TreeNodeDirective, { static: true }]
}], keyup: [{
type: HostListener,
args: ['document:keyup']
}], keydown: [{
type: HostListener,
args: ['document:keydown', ['$event']]
}], mousedown: [{
type: HostListener,
args: ['document:click', ['$event']]
}], contextmenu: [{
type: HostListener,
args: ['document:contextmenu', ['$event']]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ2UvdWkvdHJlZS9zcmMvdHJlZS5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9uZ2UvdWkvdHJlZS9zcmMvdHJlZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDbkQsT0FBTyxFQUNMLHVCQUF1QixFQUV2QixTQUFTLEVBQ1QsWUFBWSxFQUVaLFlBQVksRUFDWixLQUFLLEdBSU4sTUFBTSxlQUFlLENBQUE7QUFDdEIsT0FBTyxFQUFFLHFCQUFxQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sd0JBQXdCLENBQUE7QUFDaEYsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLE1BQU0sQ0FBQTtBQUN0QyxPQUFPLEVBQUUscUJBQXFCLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDbEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sdUJBQXVCLENBQUE7QUFDekQsT0FBTyxFQVFMLFVBQVUsR0FDWCxNQUFNLGNBQWMsQ0FBQTs7Ozs7QUFRckIsTUFBTSxPQUFPLGFBQWE7SUE0QnhCLElBQWMsVUFBVTtRQUN0QixPQUFPLElBQUksQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRSxJQUFJLE1BQU0sQ0FBQTtJQUN2RCxDQUFDO0lBRUQsWUFDbUIsVUFBbUMsRUFDbkMsaUJBQW9DO1FBRHBDLGVBQVUsR0FBVixVQUFVLENBQXlCO1FBQ25DLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBbUI7UUFqQzlDLFVBQUssR0FBUSxFQUFFLENBQUE7UUFNUCxzQkFBaUIsR0FBRyxtQkFBbUIsQ0FBQTtRQUt2QyxlQUFVLEdBQUcsSUFBSSxHQUFHLEVBQThCLENBQUE7UUFDbEQsaUJBQVksR0FBRyxJQUFJLEdBQUcs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