@m1z23r/ngx-ui 1.1.49 → 1.1.51

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -6710,21 +6710,17 @@ class TreeNodeComponent {
6710
6710
  node = input.required(...(ngDevMode ? [{ debugName: "node" }] : []));
6711
6711
  level = input(0, ...(ngDevMode ? [{ debugName: "level" }] : []));
6712
6712
  indent = input(16, ...(ngDevMode ? [{ debugName: "indent" }] : []));
6713
+ parentPath = input([], ...(ngDevMode ? [{ debugName: "parentPath" }] : []));
6713
6714
  nodeClick = output();
6714
6715
  nodeExpand = output();
6715
6716
  nodeCollapse = output();
6716
6717
  treeHost = inject(TREE_HOST);
6717
- _expanded = signal(null, ...(ngDevMode ? [{ debugName: "_expanded" }] : []));
6718
- isExpanded = computed(() => {
6719
- const manualState = this._expanded();
6720
- if (manualState !== null) {
6721
- return manualState;
6722
- }
6723
- return this.node().expanded ?? false;
6724
- }, ...(ngDevMode ? [{ debugName: "isExpanded" }] : []));
6718
+ contentRef = viewChild('contentRef', ...(ngDevMode ? [{ debugName: "contentRef" }] : []));
6719
+ path = computed(() => [...this.parentPath(), this.node()], ...(ngDevMode ? [{ debugName: "path" }] : []));
6720
+ isExpanded = computed(() => this.treeHost.isExpanded(this.node()), ...(ngDevMode ? [{ debugName: "isExpanded" }] : []));
6725
6721
  hasChildren = computed(() => {
6726
6722
  const children = this.node().children;
6727
- return children && children.length > 0;
6723
+ return !!children && children.length > 0;
6728
6724
  }, ...(ngDevMode ? [{ debugName: "hasChildren" }] : []));
6729
6725
  indentGuides = computed(() => {
6730
6726
  const lvl = this.level();
@@ -6732,24 +6728,26 @@ class TreeNodeComponent {
6732
6728
  }, ...(ngDevMode ? [{ debugName: "indentGuides" }] : []));
6733
6729
  isDraggable = computed(() => this.treeHost.draggable(), ...(ngDevMode ? [{ debugName: "isDraggable" }] : []));
6734
6730
  isDragging = computed(() => this.treeHost._dragNode() === this.node(), ...(ngDevMode ? [{ debugName: "isDragging" }] : []));
6731
+ isFlashing = computed(() => this.treeHost._flashNode() === this.node(), ...(ngDevMode ? [{ debugName: "isFlashing" }] : []));
6735
6732
  dropPosition = computed(() => {
6736
6733
  if (this.treeHost._dragOverNode() === this.node()) {
6737
6734
  return this.treeHost._dropPosition();
6738
6735
  }
6739
6736
  return null;
6740
6737
  }, ...(ngDevMode ? [{ debugName: "dropPosition" }] : []));
6738
+ ngAfterViewInit() {
6739
+ const el = this.contentRef()?.nativeElement;
6740
+ if (el)
6741
+ this.treeHost._registerNode(this.node(), el);
6742
+ }
6743
+ ngOnDestroy() {
6744
+ this.treeHost._unregisterNode(this.node());
6745
+ }
6741
6746
  toggle(event) {
6742
6747
  event.stopPropagation();
6743
6748
  if (!this.hasChildren())
6744
6749
  return;
6745
- const newState = !this.isExpanded();
6746
- this._expanded.set(newState);
6747
- if (newState) {
6748
- this.nodeExpand.emit(this.node());
6749
- }
6750
- else {
6751
- this.nodeCollapse.emit(this.node());
6752
- }
6750
+ this.treeHost.setExpanded(this.node(), !this.isExpanded());
6753
6751
  }
6754
6752
  onClick(event) {
6755
6753
  event.stopPropagation();
@@ -6764,6 +6762,13 @@ class TreeNodeComponent {
6764
6762
  this.toggle(event);
6765
6763
  }
6766
6764
  }
6765
+ onContextMenu(event) {
6766
+ if (!this.treeHost.contextMenu())
6767
+ return;
6768
+ event.preventDefault();
6769
+ event.stopPropagation();
6770
+ this.treeHost._openContextMenu(this.node(), this.path(), event.clientX, event.clientY);
6771
+ }
6767
6772
  onDragStart(event) {
6768
6773
  if (!this.isDraggable())
6769
6774
  return;
@@ -6782,7 +6787,6 @@ class TreeNodeComponent {
6782
6787
  const dragNode = this.treeHost._dragNode();
6783
6788
  if (!dragNode)
6784
6789
  return;
6785
- // Prevent dropping on self or own descendants
6786
6790
  if (dragNode === this.node() || isDescendantOf(this.node(), dragNode)) {
6787
6791
  return;
6788
6792
  }
@@ -6848,12 +6852,12 @@ class TreeNodeComponent {
6848
6852
  this.nodeCollapse.emit(node);
6849
6853
  }
6850
6854
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TreeNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6851
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: TreeNodeComponent, isStandalone: true, selector: "ui-tree-node", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, indent: { classPropertyName: "indent", publicName: "indent", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeClick: "nodeClick", nodeExpand: "nodeExpand", nodeCollapse: "nodeCollapse" }, ngImport: i0, template: "<div\n class=\"ui-tree-node\"\n [class.ui-tree-node--dragging]=\"isDragging()\"\n [attr.draggable]=\"isDraggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <div class=\"ui-tree-node__guides\">\n @for (guide of indentGuides(); track guide) {\n <span class=\"ui-tree-node__guide\" [style.width.px]=\"indent()\"></span>\n }\n </div>\n <div\n class=\"ui-tree-node__content\"\n [class.ui-tree-node__content--selected]=\"false\"\n [class.ui-tree-node__content--drop-before]=\"dropPosition() === 'before'\"\n [class.ui-tree-node__content--drop-after]=\"dropPosition() === 'after'\"\n [class.ui-tree-node__content--drop-inside]=\"dropPosition() === 'inside'\"\n [style.padding-left.px]=\"level() * indent() + 8\"\n (click)=\"onClick($event)\"\n (dblclick)=\"onDoubleClick($event)\"\n >\n @if (hasChildren()) {\n <button\n type=\"button\"\n class=\"ui-tree-node__toggle\"\n [class.ui-tree-node__toggle--expanded]=\"isExpanded()\"\n (click)=\"toggle($event)\"\n [attr.aria-expanded]=\"isExpanded()\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse' : 'Expand'\"\n >\n <svg\n class=\"ui-tree-node__chevron\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 4L10 8L6 12\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n @if (node().icon) {\n <span class=\"ui-tree-node__icon\">{{ node().icon }}</span>\n }\n <span class=\"ui-tree-node__label\">{{ node().label }}</span>\n </div>\n</div>\n@if (isExpanded() && hasChildren()) {\n @for (child of node().children; track child) {\n <ui-tree-node\n [node]=\"child\"\n [level]=\"level() + 1\"\n [indent]=\"indent()\"\n (nodeClick)=\"_onChildNodeClick($event)\"\n (nodeExpand)=\"_onChildNodeExpand($event)\"\n (nodeCollapse)=\"_onChildNodeCollapse($event)\"\n />\n }\n}\n", styles: [":host{display:block}.ui-tree-node{position:relative}.ui-tree-node__guides{position:absolute;top:0;bottom:0;left:0;display:flex;pointer-events:none}.ui-tree-node__guide{position:relative;flex-shrink:0}.ui-tree-node__guide:after{content:\"\";position:absolute;left:50%;top:0;bottom:0;width:1px;background-color:var(--ui-border-hover)}.ui-tree-node__content{display:flex;align-items:center;gap:var(--ui-spacing-xs);padding:var(--ui-spacing-xs) var(--ui-spacing-sm) var(--ui-spacing-xs) 0;border-radius:var(--ui-radius-sm);cursor:pointer;transition:background-color var(--ui-transition-fast)}.ui-tree-node__content:hover{background-color:var(--ui-bg-hover)}.ui-tree-node__content--selected{background-color:var(--ui-option-selected-bg);color:var(--ui-option-selected-text)}.ui-tree-node__toggle{display:flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;border-radius:var(--ui-radius-sm);background:transparent;color:var(--ui-text-muted);cursor:pointer;flex-shrink:0;transition:color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-tree-node__toggle:hover{background-color:var(--ui-bg-hover);color:var(--ui-text)}.ui-tree-node__toggle:focus-visible{outline:2px solid var(--ui-primary);outline-offset:-2px}.ui-tree-node__chevron{transition:transform var(--ui-transition-fast)}.ui-tree-node__toggle--expanded .ui-tree-node__chevron{transform:rotate(90deg)}.ui-tree-node__icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:18px;height:18px;font-size:var(--ui-font-sm);color:var(--ui-text-muted)}.ui-tree-node__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.4}.ui-tree-node--dragging{opacity:.4}.ui-tree-node__content--drop-before{position:relative}.ui-tree-node__content--drop-before:before{content:\"\";position:absolute;top:0;left:0;right:0;height:2px;background-color:var(--ui-primary);border-radius:1px;pointer-events:none}.ui-tree-node__content--drop-after{position:relative}.ui-tree-node__content--drop-after:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:2px;background-color:var(--ui-primary);border-radius:1px;pointer-events:none}.ui-tree-node__content--drop-inside{background-color:color-mix(in srgb,var(--ui-primary) 10%,transparent);outline:1px solid var(--ui-primary);outline-offset:-1px;border-radius:var(--ui-radius-sm)}\n"], dependencies: [{ kind: "component", type: TreeNodeComponent, selector: "ui-tree-node", inputs: ["node", "level", "indent"], outputs: ["nodeClick", "nodeExpand", "nodeCollapse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6855
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: TreeNodeComponent, isStandalone: true, selector: "ui-tree-node", inputs: { node: { classPropertyName: "node", publicName: "node", isSignal: true, isRequired: true, transformFunction: null }, level: { classPropertyName: "level", publicName: "level", isSignal: true, isRequired: false, transformFunction: null }, indent: { classPropertyName: "indent", publicName: "indent", isSignal: true, isRequired: false, transformFunction: null }, parentPath: { classPropertyName: "parentPath", publicName: "parentPath", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeClick: "nodeClick", nodeExpand: "nodeExpand", nodeCollapse: "nodeCollapse" }, viewQueries: [{ propertyName: "contentRef", first: true, predicate: ["contentRef"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n class=\"ui-tree-node\"\n [class.ui-tree-node--dragging]=\"isDragging()\"\n [attr.draggable]=\"isDraggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <div class=\"ui-tree-node__guides\">\n @for (guide of indentGuides(); track guide) {\n <span class=\"ui-tree-node__guide\" [style.width.px]=\"indent()\"></span>\n }\n </div>\n <div\n #contentRef\n class=\"ui-tree-node__content\"\n [class.ui-tree-node__content--selected]=\"false\"\n [class.ui-tree-node__content--flash]=\"isFlashing()\"\n [class.ui-tree-node__content--drop-before]=\"dropPosition() === 'before'\"\n [class.ui-tree-node__content--drop-after]=\"dropPosition() === 'after'\"\n [class.ui-tree-node__content--drop-inside]=\"dropPosition() === 'inside'\"\n [style.padding-left.px]=\"level() * indent() + 8\"\n (click)=\"onClick($event)\"\n (dblclick)=\"onDoubleClick($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n >\n @if (hasChildren()) {\n <button\n type=\"button\"\n class=\"ui-tree-node__toggle\"\n [class.ui-tree-node__toggle--expanded]=\"isExpanded()\"\n (click)=\"toggle($event)\"\n [attr.aria-expanded]=\"isExpanded()\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse' : 'Expand'\"\n >\n <svg\n class=\"ui-tree-node__chevron\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 4L10 8L6 12\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n @if (node().icon) {\n <span class=\"ui-tree-node__icon\">{{ node().icon }}</span>\n }\n <span class=\"ui-tree-node__label\">{{ node().label }}</span>\n </div>\n</div>\n@if (isExpanded() && hasChildren()) {\n @for (child of node().children; track child) {\n <ui-tree-node\n [node]=\"child\"\n [level]=\"level() + 1\"\n [indent]=\"indent()\"\n [parentPath]=\"path()\"\n (nodeClick)=\"_onChildNodeClick($event)\"\n (nodeExpand)=\"_onChildNodeExpand($event)\"\n (nodeCollapse)=\"_onChildNodeCollapse($event)\"\n />\n }\n}\n", styles: [":host{display:block}.ui-tree-node{position:relative}.ui-tree-node__guides{position:absolute;top:0;bottom:0;left:0;display:flex;pointer-events:none}.ui-tree-node__guide{position:relative;flex-shrink:0}.ui-tree-node__guide:after{content:\"\";position:absolute;left:50%;top:0;bottom:0;width:1px;background-color:var(--ui-border-hover)}.ui-tree-node__content{display:flex;align-items:center;gap:var(--ui-spacing-xs);padding:var(--ui-spacing-xs) var(--ui-spacing-sm) var(--ui-spacing-xs) 0;border-radius:var(--ui-radius-sm);cursor:pointer;transition:background-color var(--ui-transition-fast)}.ui-tree-node__content:hover{background-color:var(--ui-bg-hover)}.ui-tree-node__content--selected{background-color:var(--ui-option-selected-bg);color:var(--ui-option-selected-text)}.ui-tree-node__toggle{display:flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;border-radius:var(--ui-radius-sm);background:transparent;color:var(--ui-text-muted);cursor:pointer;flex-shrink:0;transition:color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-tree-node__toggle:hover{background-color:var(--ui-bg-hover);color:var(--ui-text)}.ui-tree-node__toggle:focus-visible{outline:2px solid var(--ui-primary);outline-offset:-2px}.ui-tree-node__chevron{transition:transform var(--ui-transition-fast)}.ui-tree-node__toggle--expanded .ui-tree-node__chevron{transform:rotate(90deg)}.ui-tree-node__icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:18px;height:18px;font-size:var(--ui-font-sm);color:var(--ui-text-muted)}.ui-tree-node__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.4}.ui-tree-node--dragging{opacity:.4}.ui-tree-node__content--drop-before{position:relative}.ui-tree-node__content--drop-before:before{content:\"\";position:absolute;top:0;left:0;right:0;height:2px;background-color:var(--ui-primary);border-radius:1px;pointer-events:none}.ui-tree-node__content--drop-after{position:relative}.ui-tree-node__content--drop-after:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:2px;background-color:var(--ui-primary);border-radius:1px;pointer-events:none}.ui-tree-node__content--drop-inside{background-color:color-mix(in srgb,var(--ui-primary) 10%,transparent);outline:1px solid var(--ui-primary);outline-offset:-1px;border-radius:var(--ui-radius-sm)}.ui-tree-node__content--flash{animation:ui-tree-node-flash 1s ease-out}@keyframes ui-tree-node-flash{0%{background-color:color-mix(in srgb,var(--ui-primary) 40%,transparent)}to{background-color:transparent}}\n"], dependencies: [{ kind: "component", type: TreeNodeComponent, selector: "ui-tree-node", inputs: ["node", "level", "indent", "parentPath"], outputs: ["nodeClick", "nodeExpand", "nodeCollapse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6852
6856
  }
6853
6857
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TreeNodeComponent, decorators: [{
6854
6858
  type: Component,
6855
- args: [{ selector: 'ui-tree-node', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ui-tree-node\"\n [class.ui-tree-node--dragging]=\"isDragging()\"\n [attr.draggable]=\"isDraggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <div class=\"ui-tree-node__guides\">\n @for (guide of indentGuides(); track guide) {\n <span class=\"ui-tree-node__guide\" [style.width.px]=\"indent()\"></span>\n }\n </div>\n <div\n class=\"ui-tree-node__content\"\n [class.ui-tree-node__content--selected]=\"false\"\n [class.ui-tree-node__content--drop-before]=\"dropPosition() === 'before'\"\n [class.ui-tree-node__content--drop-after]=\"dropPosition() === 'after'\"\n [class.ui-tree-node__content--drop-inside]=\"dropPosition() === 'inside'\"\n [style.padding-left.px]=\"level() * indent() + 8\"\n (click)=\"onClick($event)\"\n (dblclick)=\"onDoubleClick($event)\"\n >\n @if (hasChildren()) {\n <button\n type=\"button\"\n class=\"ui-tree-node__toggle\"\n [class.ui-tree-node__toggle--expanded]=\"isExpanded()\"\n (click)=\"toggle($event)\"\n [attr.aria-expanded]=\"isExpanded()\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse' : 'Expand'\"\n >\n <svg\n class=\"ui-tree-node__chevron\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 4L10 8L6 12\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n @if (node().icon) {\n <span class=\"ui-tree-node__icon\">{{ node().icon }}</span>\n }\n <span class=\"ui-tree-node__label\">{{ node().label }}</span>\n </div>\n</div>\n@if (isExpanded() && hasChildren()) {\n @for (child of node().children; track child) {\n <ui-tree-node\n [node]=\"child\"\n [level]=\"level() + 1\"\n [indent]=\"indent()\"\n (nodeClick)=\"_onChildNodeClick($event)\"\n (nodeExpand)=\"_onChildNodeExpand($event)\"\n (nodeCollapse)=\"_onChildNodeCollapse($event)\"\n />\n }\n}\n", styles: [":host{display:block}.ui-tree-node{position:relative}.ui-tree-node__guides{position:absolute;top:0;bottom:0;left:0;display:flex;pointer-events:none}.ui-tree-node__guide{position:relative;flex-shrink:0}.ui-tree-node__guide:after{content:\"\";position:absolute;left:50%;top:0;bottom:0;width:1px;background-color:var(--ui-border-hover)}.ui-tree-node__content{display:flex;align-items:center;gap:var(--ui-spacing-xs);padding:var(--ui-spacing-xs) var(--ui-spacing-sm) var(--ui-spacing-xs) 0;border-radius:var(--ui-radius-sm);cursor:pointer;transition:background-color var(--ui-transition-fast)}.ui-tree-node__content:hover{background-color:var(--ui-bg-hover)}.ui-tree-node__content--selected{background-color:var(--ui-option-selected-bg);color:var(--ui-option-selected-text)}.ui-tree-node__toggle{display:flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;border-radius:var(--ui-radius-sm);background:transparent;color:var(--ui-text-muted);cursor:pointer;flex-shrink:0;transition:color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-tree-node__toggle:hover{background-color:var(--ui-bg-hover);color:var(--ui-text)}.ui-tree-node__toggle:focus-visible{outline:2px solid var(--ui-primary);outline-offset:-2px}.ui-tree-node__chevron{transition:transform var(--ui-transition-fast)}.ui-tree-node__toggle--expanded .ui-tree-node__chevron{transform:rotate(90deg)}.ui-tree-node__icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:18px;height:18px;font-size:var(--ui-font-sm);color:var(--ui-text-muted)}.ui-tree-node__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.4}.ui-tree-node--dragging{opacity:.4}.ui-tree-node__content--drop-before{position:relative}.ui-tree-node__content--drop-before:before{content:\"\";position:absolute;top:0;left:0;right:0;height:2px;background-color:var(--ui-primary);border-radius:1px;pointer-events:none}.ui-tree-node__content--drop-after{position:relative}.ui-tree-node__content--drop-after:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:2px;background-color:var(--ui-primary);border-radius:1px;pointer-events:none}.ui-tree-node__content--drop-inside{background-color:color-mix(in srgb,var(--ui-primary) 10%,transparent);outline:1px solid var(--ui-primary);outline-offset:-1px;border-radius:var(--ui-radius-sm)}\n"] }]
6856
- }], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }], level: [{ type: i0.Input, args: [{ isSignal: true, alias: "level", required: false }] }], indent: [{ type: i0.Input, args: [{ isSignal: true, alias: "indent", required: false }] }], nodeClick: [{ type: i0.Output, args: ["nodeClick"] }], nodeExpand: [{ type: i0.Output, args: ["nodeExpand"] }], nodeCollapse: [{ type: i0.Output, args: ["nodeCollapse"] }] } });
6859
+ args: [{ selector: 'ui-tree-node', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n class=\"ui-tree-node\"\n [class.ui-tree-node--dragging]=\"isDragging()\"\n [attr.draggable]=\"isDraggable()\"\n (dragstart)=\"onDragStart($event)\"\n (dragend)=\"onDragEnd()\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <div class=\"ui-tree-node__guides\">\n @for (guide of indentGuides(); track guide) {\n <span class=\"ui-tree-node__guide\" [style.width.px]=\"indent()\"></span>\n }\n </div>\n <div\n #contentRef\n class=\"ui-tree-node__content\"\n [class.ui-tree-node__content--selected]=\"false\"\n [class.ui-tree-node__content--flash]=\"isFlashing()\"\n [class.ui-tree-node__content--drop-before]=\"dropPosition() === 'before'\"\n [class.ui-tree-node__content--drop-after]=\"dropPosition() === 'after'\"\n [class.ui-tree-node__content--drop-inside]=\"dropPosition() === 'inside'\"\n [style.padding-left.px]=\"level() * indent() + 8\"\n (click)=\"onClick($event)\"\n (dblclick)=\"onDoubleClick($event)\"\n (contextmenu)=\"onContextMenu($event)\"\n >\n @if (hasChildren()) {\n <button\n type=\"button\"\n class=\"ui-tree-node__toggle\"\n [class.ui-tree-node__toggle--expanded]=\"isExpanded()\"\n (click)=\"toggle($event)\"\n [attr.aria-expanded]=\"isExpanded()\"\n [attr.aria-label]=\"isExpanded() ? 'Collapse' : 'Expand'\"\n >\n <svg\n class=\"ui-tree-node__chevron\"\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M6 4L10 8L6 12\"\n stroke=\"currentColor\"\n stroke-width=\"1.5\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n }\n @if (node().icon) {\n <span class=\"ui-tree-node__icon\">{{ node().icon }}</span>\n }\n <span class=\"ui-tree-node__label\">{{ node().label }}</span>\n </div>\n</div>\n@if (isExpanded() && hasChildren()) {\n @for (child of node().children; track child) {\n <ui-tree-node\n [node]=\"child\"\n [level]=\"level() + 1\"\n [indent]=\"indent()\"\n [parentPath]=\"path()\"\n (nodeClick)=\"_onChildNodeClick($event)\"\n (nodeExpand)=\"_onChildNodeExpand($event)\"\n (nodeCollapse)=\"_onChildNodeCollapse($event)\"\n />\n }\n}\n", styles: [":host{display:block}.ui-tree-node{position:relative}.ui-tree-node__guides{position:absolute;top:0;bottom:0;left:0;display:flex;pointer-events:none}.ui-tree-node__guide{position:relative;flex-shrink:0}.ui-tree-node__guide:after{content:\"\";position:absolute;left:50%;top:0;bottom:0;width:1px;background-color:var(--ui-border-hover)}.ui-tree-node__content{display:flex;align-items:center;gap:var(--ui-spacing-xs);padding:var(--ui-spacing-xs) var(--ui-spacing-sm) var(--ui-spacing-xs) 0;border-radius:var(--ui-radius-sm);cursor:pointer;transition:background-color var(--ui-transition-fast)}.ui-tree-node__content:hover{background-color:var(--ui-bg-hover)}.ui-tree-node__content--selected{background-color:var(--ui-option-selected-bg);color:var(--ui-option-selected-text)}.ui-tree-node__toggle{display:flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;border-radius:var(--ui-radius-sm);background:transparent;color:var(--ui-text-muted);cursor:pointer;flex-shrink:0;transition:color var(--ui-transition-fast),background-color var(--ui-transition-fast)}.ui-tree-node__toggle:hover{background-color:var(--ui-bg-hover);color:var(--ui-text)}.ui-tree-node__toggle:focus-visible{outline:2px solid var(--ui-primary);outline-offset:-2px}.ui-tree-node__chevron{transition:transform var(--ui-transition-fast)}.ui-tree-node__toggle--expanded .ui-tree-node__chevron{transform:rotate(90deg)}.ui-tree-node__icon{display:flex;align-items:center;justify-content:center;flex-shrink:0;width:18px;height:18px;font-size:var(--ui-font-sm);color:var(--ui-text-muted)}.ui-tree-node__label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.4}.ui-tree-node--dragging{opacity:.4}.ui-tree-node__content--drop-before{position:relative}.ui-tree-node__content--drop-before:before{content:\"\";position:absolute;top:0;left:0;right:0;height:2px;background-color:var(--ui-primary);border-radius:1px;pointer-events:none}.ui-tree-node__content--drop-after{position:relative}.ui-tree-node__content--drop-after:after{content:\"\";position:absolute;bottom:0;left:0;right:0;height:2px;background-color:var(--ui-primary);border-radius:1px;pointer-events:none}.ui-tree-node__content--drop-inside{background-color:color-mix(in srgb,var(--ui-primary) 10%,transparent);outline:1px solid var(--ui-primary);outline-offset:-1px;border-radius:var(--ui-radius-sm)}.ui-tree-node__content--flash{animation:ui-tree-node-flash 1s ease-out}@keyframes ui-tree-node-flash{0%{background-color:color-mix(in srgb,var(--ui-primary) 40%,transparent)}to{background-color:transparent}}\n"] }]
6860
+ }], propDecorators: { node: [{ type: i0.Input, args: [{ isSignal: true, alias: "node", required: true }] }], level: [{ type: i0.Input, args: [{ isSignal: true, alias: "level", required: false }] }], indent: [{ type: i0.Input, args: [{ isSignal: true, alias: "indent", required: false }] }], parentPath: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentPath", required: false }] }], nodeClick: [{ type: i0.Output, args: ["nodeClick"] }], nodeExpand: [{ type: i0.Output, args: ["nodeExpand"] }], nodeCollapse: [{ type: i0.Output, args: ["nodeCollapse"] }], contentRef: [{ type: i0.ViewChild, args: ['contentRef', { isSignal: true }] }] } });
6857
6861
 
6858
6862
  const TREE_HOST = new InjectionToken('TREE_HOST');
6859
6863
  class TreeComponent {
@@ -6861,10 +6865,16 @@ class TreeComponent {
6861
6865
  indent = input(16, ...(ngDevMode ? [{ debugName: "indent" }] : []));
6862
6866
  draggable = input(false, ...(ngDevMode ? [{ debugName: "draggable" }] : []));
6863
6867
  expandOnClick = input(false, ...(ngDevMode ? [{ debugName: "expandOnClick" }] : []));
6868
+ contextMenu = input(false, ...(ngDevMode ? [{ debugName: "contextMenu" }] : []));
6869
+ pathSeparator = input(' / ', ...(ngDevMode ? [{ debugName: "pathSeparator" }] : []));
6870
+ valueFormatter = input(null, ...(ngDevMode ? [{ debugName: "valueFormatter" }] : []));
6871
+ pathFormatter = input(null, ...(ngDevMode ? [{ debugName: "pathFormatter" }] : []));
6872
+ objectFormatter = input(null, ...(ngDevMode ? [{ debugName: "objectFormatter" }] : []));
6864
6873
  nodeClick = output();
6865
6874
  nodeExpand = output();
6866
6875
  nodeCollapse = output();
6867
6876
  nodeDrop = output();
6877
+ nodeContextAction = output();
6868
6878
  /** @internal */
6869
6879
  _dragNode = signal(null, ...(ngDevMode ? [{ debugName: "_dragNode" }] : []));
6870
6880
  /** @internal */
@@ -6872,6 +6882,53 @@ class TreeComponent {
6872
6882
  /** @internal */
6873
6883
  _dropPosition = signal(null, ...(ngDevMode ? [{ debugName: "_dropPosition" }] : []));
6874
6884
  /** @internal */
6885
+ _flashNode = signal(null, ...(ngDevMode ? [{ debugName: "_flashNode" }] : []));
6886
+ /** @internal context-menu target — node and its path (root → node, inclusive) */
6887
+ _menuNode = signal(null, ...(ngDevMode ? [{ debugName: "_menuNode" }] : []));
6888
+ /** @internal */
6889
+ _menuPath = signal([], ...(ngDevMode ? [{ debugName: "_menuPath" }] : []));
6890
+ /** @internal whether the targeted node has children (drives expand/collapse-all visibility) */
6891
+ _menuHasChildren = computed(() => {
6892
+ const n = this._menuNode();
6893
+ return !!n?.children && n.children.length > 0;
6894
+ }, ...(ngDevMode ? [{ debugName: "_menuHasChildren" }] : []));
6895
+ /** @internal whether the targeted node has a parent (drives go-to/collapse-parent visibility) */
6896
+ _menuHasParent = computed(() => this._menuPath().length > 1, ...(ngDevMode ? [{ debugName: "_menuHasParent" }] : []));
6897
+ _expansion = signal(new Map(), ...(ngDevMode ? [{ debugName: "_expansion" }] : []));
6898
+ _nodeElements = new WeakMap();
6899
+ flashTimer = null;
6900
+ menu = viewChild('treeMenu', ...(ngDevMode ? [{ debugName: "menu" }] : []));
6901
+ isExpanded(node) {
6902
+ const override = this._expansion().get(node);
6903
+ return override ?? (node.expanded ?? false);
6904
+ }
6905
+ setExpanded(node, value) {
6906
+ const current = this.isExpanded(node);
6907
+ if (current === value)
6908
+ return;
6909
+ const next = new Map(this._expansion());
6910
+ next.set(node, value);
6911
+ this._expansion.set(next);
6912
+ if (value) {
6913
+ this.nodeExpand.emit(node);
6914
+ }
6915
+ else {
6916
+ this.nodeCollapse.emit(node);
6917
+ }
6918
+ }
6919
+ expandSubtree(node, value) {
6920
+ const next = new Map(this._expansion());
6921
+ const walk = (n) => {
6922
+ if (!n.children?.length)
6923
+ return;
6924
+ next.set(n, value);
6925
+ for (const c of n.children)
6926
+ walk(c);
6927
+ };
6928
+ walk(node);
6929
+ this._expansion.set(next);
6930
+ }
6931
+ /** @internal */
6875
6932
  _onNodeClick(node) {
6876
6933
  this.nodeClick.emit(node);
6877
6934
  }
@@ -6887,13 +6944,329 @@ class TreeComponent {
6887
6944
  _emitDrop(event) {
6888
6945
  this.nodeDrop.emit(event);
6889
6946
  }
6947
+ /** @internal */
6948
+ _registerNode(node, el) {
6949
+ this._nodeElements.set(node, el);
6950
+ }
6951
+ /** @internal */
6952
+ _unregisterNode(node) {
6953
+ this._nodeElements.delete(node);
6954
+ }
6955
+ /** @internal */
6956
+ _openContextMenu(node, path, x, y) {
6957
+ this._menuNode.set(node);
6958
+ this._menuPath.set(path);
6959
+ this.menu()?.openAt(x, y);
6960
+ }
6961
+ /** @internal */
6962
+ _runAction(action) {
6963
+ const node = this._menuNode();
6964
+ const path = this._menuPath();
6965
+ if (!node)
6966
+ return;
6967
+ switch (action) {
6968
+ case 'copyValue': {
6969
+ const text = this.valueFormatter()?.(node, path) ?? node.label;
6970
+ this.copyToClipboard(text);
6971
+ break;
6972
+ }
6973
+ case 'copyPath': {
6974
+ const text = this.pathFormatter()?.(node, path) ??
6975
+ path.map((n) => n.label).join(this.pathSeparator());
6976
+ this.copyToClipboard(text);
6977
+ break;
6978
+ }
6979
+ case 'copyObject': {
6980
+ const text = this.objectFormatter()?.(node, path) ?? this.serializeNode(node);
6981
+ this.copyToClipboard(text);
6982
+ break;
6983
+ }
6984
+ case 'expandAll':
6985
+ this.expandSubtree(node, true);
6986
+ break;
6987
+ case 'collapseAll':
6988
+ this.expandSubtree(node, false);
6989
+ break;
6990
+ case 'goToParent': {
6991
+ const parent = path[path.length - 2];
6992
+ if (parent)
6993
+ this.scrollAndFlash(parent);
6994
+ break;
6995
+ }
6996
+ case 'collapseParent': {
6997
+ const parent = path[path.length - 2];
6998
+ if (parent)
6999
+ this.setExpanded(parent, false);
7000
+ break;
7001
+ }
7002
+ }
7003
+ this.nodeContextAction.emit({ node, path, action });
7004
+ }
7005
+ serializeNode(node) {
7006
+ const value = node.data !== undefined ? node.data : this.sanitize(node);
7007
+ try {
7008
+ return JSON.stringify(value, null, 2);
7009
+ }
7010
+ catch {
7011
+ return String(value);
7012
+ }
7013
+ }
7014
+ sanitize(node) {
7015
+ return {
7016
+ label: node.label,
7017
+ ...(node.icon !== undefined ? { icon: node.icon } : {}),
7018
+ ...(node.children?.length ? { children: node.children.map((c) => this.sanitize(c)) } : {}),
7019
+ };
7020
+ }
7021
+ scrollAndFlash(node) {
7022
+ const el = this._nodeElements.get(node);
7023
+ if (el) {
7024
+ el.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
7025
+ }
7026
+ this._flashNode.set(node);
7027
+ if (this.flashTimer)
7028
+ clearTimeout(this.flashTimer);
7029
+ this.flashTimer = setTimeout(() => {
7030
+ this._flashNode.set(null);
7031
+ this.flashTimer = null;
7032
+ }, 1000);
7033
+ }
7034
+ copyToClipboard(text) {
7035
+ if (navigator.clipboard?.writeText) {
7036
+ navigator.clipboard.writeText(text).catch(() => this.execCommandCopy(text));
7037
+ }
7038
+ else {
7039
+ this.execCommandCopy(text);
7040
+ }
7041
+ }
7042
+ execCommandCopy(text) {
7043
+ const ta = document.createElement('textarea');
7044
+ ta.value = text;
7045
+ ta.setAttribute('readonly', '');
7046
+ ta.style.position = 'fixed';
7047
+ ta.style.opacity = '0';
7048
+ document.body.appendChild(ta);
7049
+ ta.select();
7050
+ try {
7051
+ document.execCommand('copy');
7052
+ }
7053
+ finally {
7054
+ document.body.removeChild(ta);
7055
+ }
7056
+ }
6890
7057
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
6891
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: TreeComponent, isStandalone: true, selector: "ui-tree", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null }, indent: { classPropertyName: "indent", publicName: "indent", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, expandOnClick: { classPropertyName: "expandOnClick", publicName: "expandOnClick", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeClick: "nodeClick", nodeExpand: "nodeExpand", nodeCollapse: "nodeCollapse", nodeDrop: "nodeDrop" }, providers: [{ provide: TREE_HOST, useExisting: TreeComponent }], ngImport: i0, template: "<div class=\"ui-tree\">\n @for (node of nodes(); track node) {\n <ui-tree-node\n [node]=\"node\"\n [level]=\"0\"\n [indent]=\"indent()\"\n (nodeClick)=\"_onNodeClick($event)\"\n (nodeExpand)=\"_onNodeExpand($event)\"\n (nodeCollapse)=\"_onNodeCollapse($event)\"\n />\n }\n</div>\n", styles: [":host{display:block}.ui-tree{font-size:var(--ui-font-sm);color:var(--ui-text);-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "component", type: TreeNodeComponent, selector: "ui-tree-node", inputs: ["node", "level", "indent"], outputs: ["nodeClick", "nodeExpand", "nodeCollapse"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7058
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.1", type: TreeComponent, isStandalone: true, selector: "ui-tree", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null }, indent: { classPropertyName: "indent", publicName: "indent", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, expandOnClick: { classPropertyName: "expandOnClick", publicName: "expandOnClick", isSignal: true, isRequired: false, transformFunction: null }, contextMenu: { classPropertyName: "contextMenu", publicName: "contextMenu", isSignal: true, isRequired: false, transformFunction: null }, pathSeparator: { classPropertyName: "pathSeparator", publicName: "pathSeparator", isSignal: true, isRequired: false, transformFunction: null }, valueFormatter: { classPropertyName: "valueFormatter", publicName: "valueFormatter", isSignal: true, isRequired: false, transformFunction: null }, pathFormatter: { classPropertyName: "pathFormatter", publicName: "pathFormatter", isSignal: true, isRequired: false, transformFunction: null }, objectFormatter: { classPropertyName: "objectFormatter", publicName: "objectFormatter", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeClick: "nodeClick", nodeExpand: "nodeExpand", nodeCollapse: "nodeCollapse", nodeDrop: "nodeDrop", nodeContextAction: "nodeContextAction" }, providers: [{ provide: TREE_HOST, useExisting: TreeComponent }], viewQueries: [{ propertyName: "menu", first: true, predicate: ["treeMenu"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"ui-tree\">\n @for (node of nodes(); track node) {\n <ui-tree-node\n [node]=\"node\"\n [level]=\"0\"\n [indent]=\"indent()\"\n [parentPath]=\"[]\"\n (nodeClick)=\"_onNodeClick($event)\"\n (nodeExpand)=\"_onNodeExpand($event)\"\n (nodeCollapse)=\"_onNodeCollapse($event)\"\n />\n }\n</div>\n\n@if (contextMenu()) {\n <ui-dropdown #treeMenu>\n <ui-dropdown-item (clicked)=\"_runAction('copyValue')\">Copy value</ui-dropdown-item>\n <ui-dropdown-item (clicked)=\"_runAction('copyPath')\">Copy path</ui-dropdown-item>\n <ui-dropdown-item (clicked)=\"_runAction('copyObject')\">Copy object</ui-dropdown-item>\n @if (_menuHasChildren()) {\n <ui-dropdown-divider />\n <ui-dropdown-item (clicked)=\"_runAction('expandAll')\">Expand all</ui-dropdown-item>\n <ui-dropdown-item (clicked)=\"_runAction('collapseAll')\">Collapse all</ui-dropdown-item>\n }\n @if (_menuHasParent()) {\n <ui-dropdown-divider />\n <ui-dropdown-item (clicked)=\"_runAction('goToParent')\">Go to parent</ui-dropdown-item>\n <ui-dropdown-item (clicked)=\"_runAction('collapseParent')\">Collapse parent</ui-dropdown-item>\n }\n </ui-dropdown>\n}\n", styles: [":host{display:block}.ui-tree{font-size:var(--ui-font-sm);color:var(--ui-text);-webkit-user-select:none;user-select:none}\n"], dependencies: [{ kind: "component", type: TreeNodeComponent, selector: "ui-tree-node", inputs: ["node", "level", "indent", "parentPath"], outputs: ["nodeClick", "nodeExpand", "nodeCollapse"] }, { kind: "component", type: DropdownComponent, selector: "ui-dropdown", inputs: ["position", "closeOnSelect", "matchTriggerWidth"] }, { kind: "component", type: DropdownItemComponent, selector: "ui-dropdown-item", inputs: ["disabled", "icon"], outputs: ["clicked"] }, { kind: "component", type: DropdownDividerComponent, selector: "ui-dropdown-divider" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
6892
7059
  }
6893
7060
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: TreeComponent, decorators: [{
6894
7061
  type: Component,
6895
- args: [{ selector: 'ui-tree', standalone: true, imports: [TreeNodeComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: TREE_HOST, useExisting: TreeComponent }], template: "<div class=\"ui-tree\">\n @for (node of nodes(); track node) {\n <ui-tree-node\n [node]=\"node\"\n [level]=\"0\"\n [indent]=\"indent()\"\n (nodeClick)=\"_onNodeClick($event)\"\n (nodeExpand)=\"_onNodeExpand($event)\"\n (nodeCollapse)=\"_onNodeCollapse($event)\"\n />\n }\n</div>\n", styles: [":host{display:block}.ui-tree{font-size:var(--ui-font-sm);color:var(--ui-text);-webkit-user-select:none;user-select:none}\n"] }]
6896
- }], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: false }] }], indent: [{ type: i0.Input, args: [{ isSignal: true, alias: "indent", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], expandOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandOnClick", required: false }] }], nodeClick: [{ type: i0.Output, args: ["nodeClick"] }], nodeExpand: [{ type: i0.Output, args: ["nodeExpand"] }], nodeCollapse: [{ type: i0.Output, args: ["nodeCollapse"] }], nodeDrop: [{ type: i0.Output, args: ["nodeDrop"] }] } });
7062
+ args: [{ selector: 'ui-tree', standalone: true, imports: [TreeNodeComponent, DropdownComponent, DropdownItemComponent, DropdownDividerComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [{ provide: TREE_HOST, useExisting: TreeComponent }], template: "<div class=\"ui-tree\">\n @for (node of nodes(); track node) {\n <ui-tree-node\n [node]=\"node\"\n [level]=\"0\"\n [indent]=\"indent()\"\n [parentPath]=\"[]\"\n (nodeClick)=\"_onNodeClick($event)\"\n (nodeExpand)=\"_onNodeExpand($event)\"\n (nodeCollapse)=\"_onNodeCollapse($event)\"\n />\n }\n</div>\n\n@if (contextMenu()) {\n <ui-dropdown #treeMenu>\n <ui-dropdown-item (clicked)=\"_runAction('copyValue')\">Copy value</ui-dropdown-item>\n <ui-dropdown-item (clicked)=\"_runAction('copyPath')\">Copy path</ui-dropdown-item>\n <ui-dropdown-item (clicked)=\"_runAction('copyObject')\">Copy object</ui-dropdown-item>\n @if (_menuHasChildren()) {\n <ui-dropdown-divider />\n <ui-dropdown-item (clicked)=\"_runAction('expandAll')\">Expand all</ui-dropdown-item>\n <ui-dropdown-item (clicked)=\"_runAction('collapseAll')\">Collapse all</ui-dropdown-item>\n }\n @if (_menuHasParent()) {\n <ui-dropdown-divider />\n <ui-dropdown-item (clicked)=\"_runAction('goToParent')\">Go to parent</ui-dropdown-item>\n <ui-dropdown-item (clicked)=\"_runAction('collapseParent')\">Collapse parent</ui-dropdown-item>\n }\n </ui-dropdown>\n}\n", styles: [":host{display:block}.ui-tree{font-size:var(--ui-font-sm);color:var(--ui-text);-webkit-user-select:none;user-select:none}\n"] }]
7063
+ }], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: false }] }], indent: [{ type: i0.Input, args: [{ isSignal: true, alias: "indent", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], expandOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandOnClick", required: false }] }], contextMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextMenu", required: false }] }], pathSeparator: [{ type: i0.Input, args: [{ isSignal: true, alias: "pathSeparator", required: false }] }], valueFormatter: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueFormatter", required: false }] }], pathFormatter: [{ type: i0.Input, args: [{ isSignal: true, alias: "pathFormatter", required: false }] }], objectFormatter: [{ type: i0.Input, args: [{ isSignal: true, alias: "objectFormatter", required: false }] }], nodeClick: [{ type: i0.Output, args: ["nodeClick"] }], nodeExpand: [{ type: i0.Output, args: ["nodeExpand"] }], nodeCollapse: [{ type: i0.Output, args: ["nodeCollapse"] }], nodeDrop: [{ type: i0.Output, args: ["nodeDrop"] }], nodeContextAction: [{ type: i0.Output, args: ["nodeContextAction"] }], menu: [{ type: i0.ViewChild, args: ['treeMenu', { isSignal: true }] }] } });
7064
+
7065
+ const IDENT_RE = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
7066
+ function isIdentifier(key) {
7067
+ return IDENT_RE.test(key);
7068
+ }
7069
+ function appendKey(path, key) {
7070
+ return isIdentifier(key) ? (path ? `${path}.${key}` : key) : `${path}[${JSON.stringify(key)}]`;
7071
+ }
7072
+ function appendIndex(path, i) {
7073
+ return `${path}[${i}]`;
7074
+ }
7075
+ function prettyPrimitive(v) {
7076
+ if (v === null)
7077
+ return 'null';
7078
+ if (v === undefined)
7079
+ return 'undefined';
7080
+ if (typeof v === 'string')
7081
+ return JSON.stringify(v);
7082
+ if (typeof v === 'number' || typeof v === 'boolean' || typeof v === 'bigint')
7083
+ return String(v);
7084
+ if (v instanceof Date)
7085
+ return JSON.stringify(v.toISOString());
7086
+ return String(v);
7087
+ }
7088
+ function safeStringify(v) {
7089
+ try {
7090
+ return JSON.stringify(v, replacer(), 2);
7091
+ }
7092
+ catch {
7093
+ return String(v);
7094
+ }
7095
+ }
7096
+ function replacer() {
7097
+ const seen = new WeakSet();
7098
+ return function (_key, value) {
7099
+ if (typeof value === 'bigint')
7100
+ return value.toString();
7101
+ if (typeof value === 'object' && value !== null) {
7102
+ if (seen.has(value))
7103
+ return '[Circular]';
7104
+ seen.add(value);
7105
+ }
7106
+ return value;
7107
+ };
7108
+ }
7109
+ function kindOf(v) {
7110
+ if (Array.isArray(v))
7111
+ return 'array';
7112
+ if (v !== null && typeof v === 'object')
7113
+ return 'object';
7114
+ return 'primitive';
7115
+ }
7116
+ function sizeLabel(kind, value) {
7117
+ if (kind === 'array')
7118
+ return `[${value.length}]`;
7119
+ if (kind === 'object')
7120
+ return `{${Object.keys(value).length}}`;
7121
+ return prettyPrimitive(value);
7122
+ }
7123
+ function makeLabel(keyPart, kind, value, isRoot) {
7124
+ const size = sizeLabel(kind, value);
7125
+ if (kind === 'primitive') {
7126
+ if (isRoot)
7127
+ return keyPart ? `${keyPart}: ${size}` : size;
7128
+ return keyPart ? `${keyPart}: ${size}` : size;
7129
+ }
7130
+ // object / array
7131
+ return keyPart ? `${keyPart} ${size}` : size;
7132
+ }
7133
+ /**
7134
+ * Convert an arbitrary JSON-shaped value into a TreeNode array suitable for
7135
+ * `<ui-tree [nodes]>`. Each generated node carries a `data: JsonNodeMeta`.
7136
+ *
7137
+ * Returns a single-element array containing the root node.
7138
+ */
7139
+ function jsonToTreeNodes(value, options = {}) {
7140
+ const rootLabel = options.rootLabel ?? '';
7141
+ const pathRoot = options.pathRoot ?? '';
7142
+ const expandDepth = options.expandDepth ?? 1;
7143
+ const ancestors = new WeakSet();
7144
+ const root = build(value, null, rootLabel, pathRoot, 0, expandDepth, ancestors, true);
7145
+ return [root];
7146
+ }
7147
+ function build(value, key, keyPart, path, depth, expandDepth, ancestors, isRoot) {
7148
+ // Detect cycles: only if `value` is one of our ancestors in this DFS path.
7149
+ if (value !== null && typeof value === 'object' && ancestors.has(value)) {
7150
+ const placeholder = '[Circular]';
7151
+ return {
7152
+ label: keyPart ? `${keyPart}: "${placeholder}"` : `"${placeholder}"`,
7153
+ data: {
7154
+ key,
7155
+ value: placeholder,
7156
+ kind: 'primitive',
7157
+ jsonPath: path,
7158
+ },
7159
+ };
7160
+ }
7161
+ const kind = kindOf(value);
7162
+ const label = makeLabel(keyPart, kind, value, isRoot);
7163
+ const expanded = isRoot ? true : depth <= expandDepth;
7164
+ const node = {
7165
+ label,
7166
+ expanded,
7167
+ data: { key, value, kind, jsonPath: path },
7168
+ };
7169
+ if (kind === 'object' || kind === 'array') {
7170
+ ancestors.add(value);
7171
+ if (kind === 'object') {
7172
+ const obj = value;
7173
+ const keys = Object.keys(obj);
7174
+ if (keys.length > 0) {
7175
+ node.children = keys.map((k) => build(obj[k], k, k, appendKey(path, k), depth + 1, expandDepth, ancestors, false));
7176
+ }
7177
+ }
7178
+ else {
7179
+ const arr = value;
7180
+ if (arr.length > 0) {
7181
+ node.children = arr.map((v, i) => build(v, i, `[${i}]`, appendIndex(path, i), depth + 1, expandDepth, ancestors, false));
7182
+ }
7183
+ }
7184
+ ancestors.delete(value);
7185
+ }
7186
+ return node;
7187
+ }
7188
+
7189
+ class JsonTreeComponent {
7190
+ json = input(undefined, ...(ngDevMode ? [{ debugName: "json" }] : []));
7191
+ rootLabel = input('', ...(ngDevMode ? [{ debugName: "rootLabel" }] : []));
7192
+ pathRoot = input('', ...(ngDevMode ? [{ debugName: "pathRoot" }] : []));
7193
+ expandDepth = input(1, ...(ngDevMode ? [{ debugName: "expandDepth" }] : []));
7194
+ indent = input(16, ...(ngDevMode ? [{ debugName: "indent" }] : []));
7195
+ draggable = input(false, ...(ngDevMode ? [{ debugName: "draggable" }] : []));
7196
+ expandOnClick = input(false, ...(ngDevMode ? [{ debugName: "expandOnClick" }] : []));
7197
+ contextMenu = input(true, ...(ngDevMode ? [{ debugName: "contextMenu" }] : []));
7198
+ nodeClick = output();
7199
+ nodeContextAction = output();
7200
+ nodes = computed(() => jsonToTreeNodes(this.json(), {
7201
+ rootLabel: this.rootLabel(),
7202
+ pathRoot: this.pathRoot(),
7203
+ expandDepth: this.expandDepth(),
7204
+ }), ...(ngDevMode ? [{ debugName: "nodes" }] : []));
7205
+ valueFmt = (node) => {
7206
+ const meta = node.data;
7207
+ if (!meta)
7208
+ return null;
7209
+ if (meta.kind === 'primitive') {
7210
+ const v = meta.value;
7211
+ if (v === null)
7212
+ return 'null';
7213
+ if (v === undefined)
7214
+ return 'undefined';
7215
+ if (typeof v === 'string')
7216
+ return v;
7217
+ if (typeof v === 'bigint')
7218
+ return v.toString();
7219
+ return String(v);
7220
+ }
7221
+ return safeStringify(meta.value);
7222
+ };
7223
+ pathFmt = (node) => {
7224
+ const meta = node.data;
7225
+ return meta ? meta.jsonPath : null;
7226
+ };
7227
+ objectFmt = (node) => {
7228
+ const meta = node.data;
7229
+ return meta ? safeStringify(meta.value) : null;
7230
+ };
7231
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: JsonTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
7232
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.1", type: JsonTreeComponent, isStandalone: true, selector: "ui-json-tree", inputs: { json: { classPropertyName: "json", publicName: "json", isSignal: true, isRequired: false, transformFunction: null }, rootLabel: { classPropertyName: "rootLabel", publicName: "rootLabel", isSignal: true, isRequired: false, transformFunction: null }, pathRoot: { classPropertyName: "pathRoot", publicName: "pathRoot", isSignal: true, isRequired: false, transformFunction: null }, expandDepth: { classPropertyName: "expandDepth", publicName: "expandDepth", isSignal: true, isRequired: false, transformFunction: null }, indent: { classPropertyName: "indent", publicName: "indent", isSignal: true, isRequired: false, transformFunction: null }, draggable: { classPropertyName: "draggable", publicName: "draggable", isSignal: true, isRequired: false, transformFunction: null }, expandOnClick: { classPropertyName: "expandOnClick", publicName: "expandOnClick", isSignal: true, isRequired: false, transformFunction: null }, contextMenu: { classPropertyName: "contextMenu", publicName: "contextMenu", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { nodeClick: "nodeClick", nodeContextAction: "nodeContextAction" }, ngImport: i0, template: `
7233
+ <ui-tree
7234
+ [nodes]="nodes()"
7235
+ [indent]="indent()"
7236
+ [draggable]="draggable()"
7237
+ [expandOnClick]="expandOnClick()"
7238
+ [contextMenu]="contextMenu()"
7239
+ [valueFormatter]="valueFmt"
7240
+ [pathFormatter]="pathFmt"
7241
+ [objectFormatter]="objectFmt"
7242
+ (nodeClick)="nodeClick.emit($event)"
7243
+ (nodeContextAction)="nodeContextAction.emit($event)"
7244
+ />
7245
+ `, isInline: true, dependencies: [{ kind: "component", type: TreeComponent, selector: "ui-tree", inputs: ["nodes", "indent", "draggable", "expandOnClick", "contextMenu", "pathSeparator", "valueFormatter", "pathFormatter", "objectFormatter"], outputs: ["nodeClick", "nodeExpand", "nodeCollapse", "nodeDrop", "nodeContextAction"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
7246
+ }
7247
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImport: i0, type: JsonTreeComponent, decorators: [{
7248
+ type: Component,
7249
+ args: [{
7250
+ selector: 'ui-json-tree',
7251
+ standalone: true,
7252
+ imports: [TreeComponent],
7253
+ template: `
7254
+ <ui-tree
7255
+ [nodes]="nodes()"
7256
+ [indent]="indent()"
7257
+ [draggable]="draggable()"
7258
+ [expandOnClick]="expandOnClick()"
7259
+ [contextMenu]="contextMenu()"
7260
+ [valueFormatter]="valueFmt"
7261
+ [pathFormatter]="pathFmt"
7262
+ [objectFormatter]="objectFmt"
7263
+ (nodeClick)="nodeClick.emit($event)"
7264
+ (nodeContextAction)="nodeContextAction.emit($event)"
7265
+ />
7266
+ `,
7267
+ changeDetection: ChangeDetectionStrategy.OnPush,
7268
+ }]
7269
+ }], propDecorators: { json: [{ type: i0.Input, args: [{ isSignal: true, alias: "json", required: false }] }], rootLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "rootLabel", required: false }] }], pathRoot: [{ type: i0.Input, args: [{ isSignal: true, alias: "pathRoot", required: false }] }], expandDepth: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandDepth", required: false }] }], indent: [{ type: i0.Input, args: [{ isSignal: true, alias: "indent", required: false }] }], draggable: [{ type: i0.Input, args: [{ isSignal: true, alias: "draggable", required: false }] }], expandOnClick: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandOnClick", required: false }] }], contextMenu: [{ type: i0.Input, args: [{ isSignal: true, alias: "contextMenu", required: false }] }], nodeClick: [{ type: i0.Output, args: ["nodeClick"] }], nodeContextAction: [{ type: i0.Output, args: ["nodeContextAction"] }] } });
6897
7270
 
6898
7271
  /** Directive to mark a custom variable popover template */
6899
7272
  class VariablePopoverDirective {
@@ -7294,5 +7667,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.1", ngImpor
7294
7667
  * Generated bundle index. Do not edit.
7295
7668
  */
7296
7669
 
7297
- export { AccordionComponent, AccordionHeaderDirective, AccordionItemComponent, AlertComponent, BadgeComponent, ButtonComponent, CardComponent, CellTemplateDirective, CellValuePipe, CheckboxComponent, ChipInputComponent, ChipTemplateDirective, CircularProgressComponent, ContentComponent, ContextMenuDirective, DIALOG_DATA, DIALOG_REF, DatepickerComponent, DatetimepickerComponent, DialogRef, DialogService, DropdownComponent, DropdownDividerComponent, DropdownItemComponent, DropdownTriggerDirective, DynamicTabsComponent, FileChooserComponent, FilePreviewPipe, FileSizePipe, FooterComponent, InputComponent, LOADABLE, LoadingDirective, LoadingService, ModalComponent, NavbarComponent, OptionComponent, OptionTemplateDirective, PaginationComponent, ProgressComponent, RadioComponent, RadioGroupComponent, RangeSliderComponent, SelectComponent, ShellComponent, SidebarComponent, SidebarService, SidebarToggleComponent, SliderComponent, SpinnerComponent, SplitComponent, SplitPaneComponent, SwitchComponent, TAB_DATA, TAB_REF, TREE_HOST, TabActivePipe, TabComponent, TabIconDirective, TabRef, TableComponent, TabsComponent, TabsService, TemplateInputComponent, TemplateInputSuffixDirective, TextareaComponent, TimepickerComponent, ToastRef, ToastService, TooltipDirective, TreeComponent, TreeNodeComponent, Validators, VariablePopoverDirective };
7670
+ export { AccordionComponent, AccordionHeaderDirective, AccordionItemComponent, AlertComponent, BadgeComponent, ButtonComponent, CardComponent, CellTemplateDirective, CellValuePipe, CheckboxComponent, ChipInputComponent, ChipTemplateDirective, CircularProgressComponent, ContentComponent, ContextMenuDirective, DIALOG_DATA, DIALOG_REF, DatepickerComponent, DatetimepickerComponent, DialogRef, DialogService, DropdownComponent, DropdownDividerComponent, DropdownItemComponent, DropdownTriggerDirective, DynamicTabsComponent, FileChooserComponent, FilePreviewPipe, FileSizePipe, FooterComponent, InputComponent, JsonTreeComponent, LOADABLE, LoadingDirective, LoadingService, ModalComponent, NavbarComponent, OptionComponent, OptionTemplateDirective, PaginationComponent, ProgressComponent, RadioComponent, RadioGroupComponent, RangeSliderComponent, SelectComponent, ShellComponent, SidebarComponent, SidebarService, SidebarToggleComponent, SliderComponent, SpinnerComponent, SplitComponent, SplitPaneComponent, SwitchComponent, TAB_DATA, TAB_REF, TREE_HOST, TabActivePipe, TabComponent, TabIconDirective, TabRef, TableComponent, TabsComponent, TabsService, TemplateInputComponent, TemplateInputSuffixDirective, TextareaComponent, TimepickerComponent, ToastRef, ToastService, TooltipDirective, TreeComponent, TreeNodeComponent, Validators, VariablePopoverDirective, jsonToTreeNodes };
7298
7671
  //# sourceMappingURL=m1z23r-ngx-ui.mjs.map