@ship-ui/core 0.22.12 → 0.22.15
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.
- package/README.md +46 -0
- package/assets/mcp/components.json +579 -2
- package/bin/src/scanner.zig +9 -18
- package/fesm2022/ship-ui-core-sh-form-field-experimental.mjs +17 -2
- package/fesm2022/ship-ui-core-sh-form-field-experimental.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-a11y-keybindings.mjs +433 -0
- package/fesm2022/ship-ui-core-ship-a11y-keybindings.mjs.map +1 -0
- package/fesm2022/ship-ui-core-ship-accordion.mjs +1 -0
- package/fesm2022/ship-ui-core-ship-accordion.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-alert.mjs +3 -2
- package/fesm2022/ship-ui-core-ship-alert.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-blueprint.mjs +14 -9
- package/fesm2022/ship-ui-core-ship-blueprint.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-checkbox.mjs +16 -14
- package/fesm2022/ship-ui-core-ship-checkbox.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-color-picker.mjs +3 -1
- package/fesm2022/ship-ui-core-ship-color-picker.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-datepicker.mjs +51 -29
- package/fesm2022/ship-ui-core-ship-datepicker.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-dialog.mjs +10 -5
- package/fesm2022/ship-ui-core-ship-dialog.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-divider.mjs +4 -2
- package/fesm2022/ship-ui-core-ship-divider.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-editor.mjs +2673 -0
- package/fesm2022/ship-ui-core-ship-editor.mjs.map +1 -0
- package/fesm2022/ship-ui-core-ship-icon.mjs +2 -2
- package/fesm2022/ship-ui-core-ship-icon.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-list.mjs +4 -2
- package/fesm2022/ship-ui-core-ship-list.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-menu.mjs +8 -5
- package/fesm2022/ship-ui-core-ship-menu.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-popover.mjs +10 -5
- package/fesm2022/ship-ui-core-ship-popover.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-progress-bar.mjs +5 -1
- package/fesm2022/ship-ui-core-ship-progress-bar.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-radio.mjs +16 -14
- package/fesm2022/ship-ui-core-ship-radio.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-select.mjs +9 -9
- package/fesm2022/ship-ui-core-ship-select.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-sidenav.mjs +2 -2
- package/fesm2022/ship-ui-core-ship-sidenav.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-spinner.mjs +3 -1
- package/fesm2022/ship-ui-core-ship-spinner.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-spotlight.mjs +77 -24
- package/fesm2022/ship-ui-core-ship-spotlight.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-table.mjs +139 -139
- package/fesm2022/ship-ui-core-ship-table.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-theme-toggle.mjs +2 -2
- package/fesm2022/ship-ui-core-ship-theme-toggle.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-toggle-card.mjs +24 -3
- package/fesm2022/ship-ui-core-ship-toggle-card.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-toggle.mjs +16 -14
- package/fesm2022/ship-ui-core-ship-toggle.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-tree.mjs +2 -2
- package/fesm2022/ship-ui-core-ship-tree.mjs.map +1 -1
- package/fesm2022/ship-ui-core-ship-virtual-scroll.mjs +2 -2
- package/fesm2022/ship-ui-core-ship-virtual-scroll.mjs.map +1 -1
- package/fesm2022/ship-ui-core.mjs +36 -23
- package/fesm2022/ship-ui-core.mjs.map +1 -1
- package/package.json +33 -2
- package/types/ship-ui-core-sh-form-field-experimental.d.ts +2 -0
- package/types/ship-ui-core-ship-a11y-keybindings.d.ts +102 -0
- package/types/ship-ui-core-ship-blueprint.d.ts +1 -1
- package/types/ship-ui-core-ship-checkbox.d.ts +2 -1
- package/types/ship-ui-core-ship-editor.d.ts +168 -0
- package/types/ship-ui-core-ship-radio.d.ts +2 -1
- package/types/ship-ui-core-ship-spotlight.d.ts +1 -1
- package/types/ship-ui-core-ship-table.d.ts +2 -0
- package/types/ship-ui-core-ship-toggle-card.d.ts +1 -0
- package/types/ship-ui-core-ship-toggle.d.ts +2 -1
- package/types/ship-ui-core.d.ts +3 -0
- package/bin/ship-fg-scanner +0 -0
|
@@ -169,13 +169,13 @@ class ShipTree {
|
|
|
169
169
|
return this.itemIconName() || 'file';
|
|
170
170
|
}
|
|
171
171
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipTree, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
172
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: ShipTree, isStandalone: true, selector: "sh-tree", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, sortableManager: { classPropertyName: "sortableManager", publicName: "sortableManager", isSignal: true, isRequired: false, transformFunction: null }, selectedId: { classPropertyName: "selectedId", publicName: "selectedId", isSignal: true, isRequired: false, transformFunction: null }, getId: { classPropertyName: "getId", publicName: "getId", isSignal: true, isRequired: false, transformFunction: null }, getName: { classPropertyName: "getName", publicName: "getName", isSignal: true, isRequired: false, transformFunction: null }, getParentId: { classPropertyName: "getParentId", publicName: "getParentId", isSignal: true, isRequired: false, transformFunction: null }, isFolder: { classPropertyName: "isFolder", publicName: "isFolder", isSignal: true, isRequired: false, transformFunction: null }, getIsOpen: { classPropertyName: "getIsOpen", publicName: "getIsOpen", isSignal: true, isRequired: false, transformFunction: null }, setIsOpen: { classPropertyName: "setIsOpen", publicName: "setIsOpen", isSignal: true, isRequired: false, transformFunction: null }, getIcon: { classPropertyName: "getIcon", publicName: "getIcon", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { items: "itemsChange", selectedId: "selectedIdChange", nodeClick: "nodeClick", nodeToggle: "nodeToggle" }, host: { properties: { "class.sh-tree": "true" } }, queries: [{ propertyName: "openIconDir", first: true, predicate: ShipTreeOpenIcon, descendants: true, isSignal: true }, { propertyName: "closedIconDir", first: true, predicate: ShipTreeClosedIcon, descendants: true, isSignal: true }, { propertyName: "itemIconDir", first: true, predicate: ShipTreeItemIcon, descendants: true, isSignal: true }, { propertyName: "nodeTemplate", first: true, predicate: ["nodeTemplate"], descendants: true, isSignal: true }, { propertyName: "dirTemplate", first: true, predicate: ["dirTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (sortableManager()) {\n <div\n class=\"sh-tree-container\"\n [shSortable]=\"sortableManager()\"\n [treeItems]=\"visibleNodes()\"\n sortingMode=\"tree\"\n >\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n draggable=\"true\"\n [attr.sortable-dir]=\"isFolder()(node) ? 'true' : null\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n} @else {\n <div class=\"sh-tree-container\">\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n}\n\n<ng-template #defaultTemplate let-node>\n <span class=\"node-name\">{{ getName()(node) }}</span>\n</ng-template>\n", styles: [".sh-sortable{position:relative}.sh-sortable.dragging [draggable],.sh-sortable.dragging .sortable-ghost{cursor:grabbing;transition:transform 40ms linear}.sh-sortable [draggable]{transform:translate(0);transition:none;z-index:2;-webkit-user-select:none;user-select:none}.sh-sortable:not(.sh-sortable-tree) [draggable]{background:var(--base-1)}.sh-sortable:not(.sh-sortable-tree) [draggable]:not(:has([sort-handle])){cursor:grab}.sh-sortable .sortable-ghost{opacity:.5;z-index:10}.sh-sortable.item-dragged-out .sortable-ghost{display:none}.sh-sortable [sort-handle]{cursor:grab}.sh-sortable.sh-sortable-tree [draggable]{transform:none!important;transition:none!important;z-index:auto}.sh-sortable.sh-sortable-tree .sortable-ghost{z-index:0!important}.sh-sortable.sh-sortable-tree .sortable-ghost.drop-before:before,.sh-sortable.sh-sortable-tree .sortable-ghost.drop-after:after{display:none!important}.sh-sortable.sh-sortable-tree .sortable-ghost.drop-inside{outline:none!important;background:inherit!important}.sh-sortable.sh-sortable-tree .drop-inside{background:var(--primary-3)!important;outline:2px solid var(--primary-8)!important;outline-offset:-.125rem;border-radius:var(--shape-1, 4px)}.sh-sortable.sh-sortable-tree .drop-inside .node-icon,.sh-sortable.sh-sortable-tree .drop-inside sh-tree-node .sh-tree-node-left sh-icon{color:var(--primary-8)!important}.sh-sortable.sh-sortable-tree .drop-before{position:relative;z-index:20}.sh-sortable.sh-sortable-tree .drop-before:before{content:\"\";position:absolute;top:-.1875rem;left:calc(var(--tree-padding-left, 12px) + var(--tree-depth, 0) * var(--tree-indent-step, 12px) + .375rem);right:var(--tree-padding-right, 6px);height:.375rem;background-image:radial-gradient(circle at 3px 3px,var(--primary-8) 3px,transparent 3px),linear-gradient(to right,var(--primary-8),var(--primary-8));background-repeat:no-repeat,no-repeat;background-position:left center,6px center;background-size:6px 6px,100% 2px;z-index:10;pointer-events:none}.sh-sortable.sh-sortable-tree .drop-after{position:relative;z-index:20}.sh-sortable.sh-sortable-tree .drop-after:after{content:\"\";position:absolute;bottom:-.1875rem;left:calc(var(--tree-padding-left, 12px) + var(--tree-depth, 0) * var(--tree-indent-step, 12px) + .375rem);right:var(--tree-padding-right, 6px);height:.375rem;background-image:radial-gradient(circle at 3px 3px,var(--primary-8) 3px,transparent 3px),linear-gradient(to right,var(--primary-8),var(--primary-8));background-repeat:no-repeat,no-repeat;background-position:left center,6px center;background-size:6px 6px,100% 2px;z-index:10;pointer-events:none}sh-tree{--tree-bg: var(--base-2);--tree-bc: var(--base-3);--tree-color: var(--base-12);--tree-hover-bg: var(--base-3);--tree-active-bg: var(--base-4);--tree-selected-bg: var(--base-4);--tree-guide-color: var(--base-4);--tree-caret-color: var(--base-9);--tree-caret-hover-color: var(--base-12);--tree-icon-color: var(--base-9);--tree-icon-folder-color: var(--primary-8);--tree-indent-step: .75rem;--tree-padding-left: .75rem;--tree-padding-right: .375rem;display:flex;flex-direction:column;width:100%;background:var(--tree-bg);border:1px solid var(--tree-bc);border-radius:var(--shape-2, .5rem);overflow:hidden;font-family:var(--font-family, sans-serif);box-shadow:var(--box-shadow-10)}sh-tree .sh-tree-container{flex:1;padding:.5rem 0;overflow-y:auto;position:relative}sh-tree .sh-tree-node{display:flex;align-items:center;height:2rem;position:relative;cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--tree-color);font:var(--paragraph-20, 14px sans-serif);gap:.375rem;transition:background .12s ease;padding-left:calc(var(--tree-padding-left) + var(--tree-depth, 0) * var(--tree-indent-step));padding-right:var(--tree-padding-right);background:var(--tree-bg)}sh-tree .sh-tree-node:hover{background:var(--tree-hover-bg)}sh-tree .sh-tree-node.is-selected{background:var(--tree-selected-bg)}sh-tree .sh-tree-node.sortable-ghost{opacity:.4;background:var(--tree-active-bg)}sh-tree .sh-tree-node .indent-guide{position:absolute;top:0;bottom:0;width:1px;border-left:1px solid var(--tree-guide-color);opacity:.5;left:calc(var(--tree-padding-left) + var(--tree-indent-step) / 2 + var(--guide-index, 0) * var(--tree-indent-step))}sh-tree .sh-tree-node .caret-container{display:flex;align-items:center;justify-content:center;width:var(--tree-indent-step);height:1rem;z-index:2}sh-tree .sh-tree-node .caret-container:has(+.node-icon){position:absolute;opacity:0;z-index:3;width:var(--tree-indent-step)}sh-tree .sh-tree-node .caret-container .caret-btn{background:none;border:none;padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--tree-caret-color);border-radius:var(--shape-1, 4px);width:100%;height:100%;position:relative;transition:background .15s ease,color .15s ease}sh-tree .sh-tree-node .caret-container .caret-btn:after{content:\"\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:1.5rem;height:1.5rem;z-index:1}sh-tree .sh-tree-node .caret-container .caret-btn:hover{color:var(--tree-caret-hover-color)}sh-tree .sh-tree-node .node-icon{color:var(--tree-icon-color);display:inline-flex;align-items:center;justify-content:center;width:var(--tree-indent-step)}sh-tree .sh-tree-node .node-icon.folder{color:var(--tree-icon-folder-color)}sh-tree .sh-tree-node .node-icon:has(~.node-content sh-tree-node sh-icon){display:none}sh-tree .sh-tree-node.is-folder sh-tree-node .sh-tree-node-left sh-icon{color:var(--tree-icon-folder-color)}sh-tree .sh-tree-node:not(.is-folder) sh-tree-node .sh-tree-node-left sh-icon{color:var(--tree-icon-color)}sh-tree .sh-tree-node .node-content{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;z-index:2;display:flex;align-items:center}sh-tree .sh-tree-node .node-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}sh-tree sh-tree-node{display:flex;align-items:center;width:100%;gap:.5rem;justify-content:space-between;min-width:0}sh-tree sh-tree-node .sh-tree-node-left{display:flex;align-items:center;gap:.25rem;padding-left:.25rem;overflow:hidden;min-width:0;flex:1}sh-tree sh-tree-node .sh-tree-node-left sh-icon{display:inline-flex;align-items:center;justify-content:center;width:var(--tree-indent-step)}sh-tree sh-tree-node .sh-tree-node-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}sh-tree sh-tree-node .sh-tree-node-label span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}sh-tree sh-tree-node .sh-tree-node-actions,sh-tree sh-tree-node sh-tree-node-actions{display:flex;align-items:center;gap:.5rem}sh-tree sh-tree-node .status-badge{font-size:.625rem;padding:.125rem .375rem;border-radius:var(--shape-1, 4px);text-transform:uppercase;font-weight:600}sh-tree sh-tree-node .status-badge.success{background:var(--success-3, #e6f4ea);color:var(--success-8, #137333)}sh-tree sh-tree-node .status-badge.warning{background:var(--warning-3, #fef7e0);color:var(--warning-8, #b06000)}sh-tree sh-tree-node .status-badge.error{background:var(--error-3, #fce8e6);color:var(--error-8, #c5221f)}sh-tree sh-tree-node .delete-btn{background:none;border:none;padding:.125rem;cursor:pointer;color:var(--base-9);border-radius:var(--shape-1, 4px);display:flex;opacity:0;transition:opacity .15s ease;align-items:center;justify-content:center}sh-tree sh-tree-node .delete-btn:hover{background:var(--base-4);color:var(--error-8, #c5221f)}sh-tree .sh-tree-node:hover .delete-btn{opacity:1}sh-tree .empty-state{padding:2rem;text-align:center;color:var(--tree-caret-color);font:var(--paragraph-20, 14px sans-serif)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ShipIcon, selector: "sh-icon", inputs: ["color", "size"] }, { kind: "directive", type: ShipSortable, selector: "[shSortable]", inputs: ["shSortable", "sortableGroup", "sortingMode", "treeItems"], outputs: ["treeItemsChange", "sortDrop", "afterDrop", "crossDrop", "treeDrop"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
172
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.0", type: ShipTree, isStandalone: true, selector: "sh-tree", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, sortableManager: { classPropertyName: "sortableManager", publicName: "sortableManager", isSignal: true, isRequired: false, transformFunction: null }, selectedId: { classPropertyName: "selectedId", publicName: "selectedId", isSignal: true, isRequired: false, transformFunction: null }, getId: { classPropertyName: "getId", publicName: "getId", isSignal: true, isRequired: false, transformFunction: null }, getName: { classPropertyName: "getName", publicName: "getName", isSignal: true, isRequired: false, transformFunction: null }, getParentId: { classPropertyName: "getParentId", publicName: "getParentId", isSignal: true, isRequired: false, transformFunction: null }, isFolder: { classPropertyName: "isFolder", publicName: "isFolder", isSignal: true, isRequired: false, transformFunction: null }, getIsOpen: { classPropertyName: "getIsOpen", publicName: "getIsOpen", isSignal: true, isRequired: false, transformFunction: null }, setIsOpen: { classPropertyName: "setIsOpen", publicName: "setIsOpen", isSignal: true, isRequired: false, transformFunction: null }, getIcon: { classPropertyName: "getIcon", publicName: "getIcon", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { items: "itemsChange", selectedId: "selectedIdChange", nodeClick: "nodeClick", nodeToggle: "nodeToggle" }, host: { properties: { "class.sh-tree": "true" } }, queries: [{ propertyName: "openIconDir", first: true, predicate: ShipTreeOpenIcon, descendants: true, isSignal: true }, { propertyName: "closedIconDir", first: true, predicate: ShipTreeClosedIcon, descendants: true, isSignal: true }, { propertyName: "itemIconDir", first: true, predicate: ShipTreeItemIcon, descendants: true, isSignal: true }, { propertyName: "nodeTemplate", first: true, predicate: ["nodeTemplate"], descendants: true, isSignal: true }, { propertyName: "dirTemplate", first: true, predicate: ["dirTemplate"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (sortableManager()) {\n <div\n class=\"sh-tree-container\"\n [shSortable]=\"sortableManager()\"\n [treeItems]=\"visibleNodes()\"\n sortingMode=\"tree\"\n role=\"tree\"\n >\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n draggable=\"true\"\n [attr.sortable-dir]=\"isFolder()(node) ? 'true' : null\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n role=\"treeitem\"\n [attr.aria-expanded]=\"isFolder()(node) ? getIsOpen()(node) : null\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n} @else {\n <div class=\"sh-tree-container\" role=\"tree\">\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n role=\"treeitem\"\n [attr.aria-expanded]=\"isFolder()(node) ? getIsOpen()(node) : null\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n}\n\n<ng-template #defaultTemplate let-node>\n <span class=\"node-name\">{{ getName()(node) }}</span>\n</ng-template>\n", styles: [".sh-sortable{position:relative}.sh-sortable.dragging [draggable],.sh-sortable.dragging .sortable-ghost{cursor:grabbing;transition:transform 40ms linear}.sh-sortable [draggable]{transform:translate(0);transition:none;z-index:2;-webkit-user-select:none;user-select:none}.sh-sortable:not(.sh-sortable-tree) [draggable]{background:var(--base-1)}.sh-sortable:not(.sh-sortable-tree) [draggable]:not(:has([sort-handle])){cursor:grab}.sh-sortable .sortable-ghost{opacity:.5;z-index:10}.sh-sortable.item-dragged-out .sortable-ghost{display:none}.sh-sortable [sort-handle]{cursor:grab}.sh-sortable.sh-sortable-tree [draggable]{transform:none!important;transition:none!important;z-index:auto}.sh-sortable.sh-sortable-tree .sortable-ghost{z-index:0!important}.sh-sortable.sh-sortable-tree .sortable-ghost.drop-before:before,.sh-sortable.sh-sortable-tree .sortable-ghost.drop-after:after{display:none!important}.sh-sortable.sh-sortable-tree .sortable-ghost.drop-inside{outline:none!important;background:inherit!important}.sh-sortable.sh-sortable-tree .drop-inside{background:var(--primary-3)!important;outline:2px solid var(--primary-8)!important;outline-offset:-.125rem;border-radius:var(--shape-1, 4px)}.sh-sortable.sh-sortable-tree .drop-inside .node-icon,.sh-sortable.sh-sortable-tree .drop-inside sh-tree-node .sh-tree-node-left sh-icon{color:var(--primary-8)!important}.sh-sortable.sh-sortable-tree .drop-before{position:relative;z-index:20}.sh-sortable.sh-sortable-tree .drop-before:before{content:\"\";position:absolute;top:-.1875rem;left:calc(var(--tree-padding-left, 12px) + var(--tree-depth, 0) * var(--tree-indent-step, 12px) + .375rem);right:var(--tree-padding-right, 6px);height:.375rem;background-image:radial-gradient(circle at 3px 3px,var(--primary-8) 3px,transparent 3px),linear-gradient(to right,var(--primary-8),var(--primary-8));background-repeat:no-repeat,no-repeat;background-position:left center,6px center;background-size:6px 6px,100% 2px;z-index:10;pointer-events:none}.sh-sortable.sh-sortable-tree .drop-after{position:relative;z-index:20}.sh-sortable.sh-sortable-tree .drop-after:after{content:\"\";position:absolute;bottom:-.1875rem;left:calc(var(--tree-padding-left, 12px) + var(--tree-depth, 0) * var(--tree-indent-step, 12px) + .375rem);right:var(--tree-padding-right, 6px);height:.375rem;background-image:radial-gradient(circle at 3px 3px,var(--primary-8) 3px,transparent 3px),linear-gradient(to right,var(--primary-8),var(--primary-8));background-repeat:no-repeat,no-repeat;background-position:left center,6px center;background-size:6px 6px,100% 2px;z-index:10;pointer-events:none}sh-tree{--tree-bg: var(--base-2);--tree-bc: var(--base-3);--tree-color: var(--base-12);--tree-hover-bg: var(--base-3);--tree-active-bg: var(--base-4);--tree-selected-bg: var(--base-4);--tree-guide-color: var(--base-4);--tree-caret-color: var(--base-9);--tree-caret-hover-color: var(--base-12);--tree-icon-color: var(--base-9);--tree-icon-folder-color: var(--primary-8);--tree-indent-step: .75rem;--tree-padding-left: .75rem;--tree-padding-right: .375rem;display:flex;flex-direction:column;width:100%;background:var(--tree-bg);border:1px solid var(--tree-bc);border-radius:var(--shape-2, .5rem);overflow:hidden;font-family:var(--font-family, sans-serif);box-shadow:var(--box-shadow-10)}sh-tree .sh-tree-container{flex:1;padding:.5rem 0;overflow-y:auto;position:relative}sh-tree .sh-tree-node{display:flex;align-items:center;height:2rem;position:relative;cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--tree-color);font:var(--paragraph-20, 14px sans-serif);gap:.375rem;transition:background .12s ease;padding-left:calc(var(--tree-padding-left) + var(--tree-depth, 0) * var(--tree-indent-step));padding-right:var(--tree-padding-right);background:var(--tree-bg)}sh-tree .sh-tree-node:hover{background:var(--tree-hover-bg)}sh-tree .sh-tree-node.is-selected{background:var(--tree-selected-bg)}sh-tree .sh-tree-node.sortable-ghost{opacity:.4;background:var(--tree-active-bg)}sh-tree .sh-tree-node .indent-guide{position:absolute;top:0;bottom:0;width:1px;border-left:1px solid var(--tree-guide-color);opacity:.5;left:calc(var(--tree-padding-left) + var(--tree-indent-step) / 2 + var(--guide-index, 0) * var(--tree-indent-step))}sh-tree .sh-tree-node .caret-container{display:flex;align-items:center;justify-content:center;width:var(--tree-indent-step);height:1rem;z-index:2}sh-tree .sh-tree-node .caret-container:has(+.node-icon){position:absolute;opacity:0;z-index:3;width:var(--tree-indent-step)}sh-tree .sh-tree-node .caret-container .caret-btn{background:none;border:none;padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--tree-caret-color);border-radius:var(--shape-1, 4px);width:100%;height:100%;position:relative;transition:background .15s ease,color .15s ease}sh-tree .sh-tree-node .caret-container .caret-btn:after{content:\"\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:1.5rem;height:1.5rem;z-index:1}sh-tree .sh-tree-node .caret-container .caret-btn:hover{color:var(--tree-caret-hover-color)}sh-tree .sh-tree-node .node-icon{color:var(--tree-icon-color);display:inline-flex;align-items:center;justify-content:center;width:var(--tree-indent-step)}sh-tree .sh-tree-node .node-icon.folder{color:var(--tree-icon-folder-color)}sh-tree .sh-tree-node .node-icon:has(~.node-content sh-tree-node sh-icon){display:none}sh-tree .sh-tree-node.is-folder sh-tree-node .sh-tree-node-left sh-icon{color:var(--tree-icon-folder-color)}sh-tree .sh-tree-node:not(.is-folder) sh-tree-node .sh-tree-node-left sh-icon{color:var(--tree-icon-color)}sh-tree .sh-tree-node .node-content{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;z-index:2;display:flex;align-items:center}sh-tree .sh-tree-node .node-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}sh-tree sh-tree-node{display:flex;align-items:center;width:100%;gap:.5rem;justify-content:space-between;min-width:0}sh-tree sh-tree-node .sh-tree-node-left{display:flex;align-items:center;gap:.25rem;padding-left:.25rem;overflow:hidden;min-width:0;flex:1}sh-tree sh-tree-node .sh-tree-node-left sh-icon{display:inline-flex;align-items:center;justify-content:center;width:var(--tree-indent-step)}sh-tree sh-tree-node .sh-tree-node-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}sh-tree sh-tree-node .sh-tree-node-label span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}sh-tree sh-tree-node .sh-tree-node-actions,sh-tree sh-tree-node sh-tree-node-actions{display:flex;align-items:center;gap:.5rem}sh-tree sh-tree-node .status-badge{font-size:.625rem;padding:.125rem .375rem;border-radius:var(--shape-1, 4px);text-transform:uppercase;font-weight:600}sh-tree sh-tree-node .status-badge.success{background:var(--success-3, #e6f4ea);color:var(--success-8, #137333)}sh-tree sh-tree-node .status-badge.warning{background:var(--warning-3, #fef7e0);color:var(--warning-8, #b06000)}sh-tree sh-tree-node .status-badge.error{background:var(--error-3, #fce8e6);color:var(--error-8, #c5221f)}sh-tree sh-tree-node .delete-btn{background:none;border:none;padding:.125rem;cursor:pointer;color:var(--base-9);border-radius:var(--shape-1, 4px);display:flex;opacity:0;transition:opacity .15s ease;align-items:center;justify-content:center}sh-tree sh-tree-node .delete-btn:hover{background:var(--base-4);color:var(--error-8, #c5221f)}sh-tree .sh-tree-node:hover .delete-btn{opacity:1}sh-tree .empty-state{padding:2rem;text-align:center;color:var(--tree-caret-color);font:var(--paragraph-20, 14px sans-serif)}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ShipIcon, selector: "sh-icon", inputs: ["color", "size"] }, { kind: "directive", type: ShipSortable, selector: "[shSortable]", inputs: ["shSortable", "sortableGroup", "sortingMode", "treeItems"], outputs: ["treeItemsChange", "sortDrop", "afterDrop", "crossDrop", "treeDrop"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
|
|
173
173
|
}
|
|
174
174
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipTree, decorators: [{
|
|
175
175
|
type: Component,
|
|
176
176
|
args: [{ selector: 'sh-tree', standalone: true, imports: [NgTemplateOutlet, ShipIcon, ShipSortable], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
177
177
|
'[class.sh-tree]': 'true',
|
|
178
|
-
}, template: "@if (sortableManager()) {\n <div\n class=\"sh-tree-container\"\n [shSortable]=\"sortableManager()\"\n [treeItems]=\"visibleNodes()\"\n sortingMode=\"tree\"\n >\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n draggable=\"true\"\n [attr.sortable-dir]=\"isFolder()(node) ? 'true' : null\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n} @else {\n <div class=\"sh-tree-container\">\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n}\n\n<ng-template #defaultTemplate let-node>\n <span class=\"node-name\">{{ getName()(node) }}</span>\n</ng-template>\n", styles: [".sh-sortable{position:relative}.sh-sortable.dragging [draggable],.sh-sortable.dragging .sortable-ghost{cursor:grabbing;transition:transform 40ms linear}.sh-sortable [draggable]{transform:translate(0);transition:none;z-index:2;-webkit-user-select:none;user-select:none}.sh-sortable:not(.sh-sortable-tree) [draggable]{background:var(--base-1)}.sh-sortable:not(.sh-sortable-tree) [draggable]:not(:has([sort-handle])){cursor:grab}.sh-sortable .sortable-ghost{opacity:.5;z-index:10}.sh-sortable.item-dragged-out .sortable-ghost{display:none}.sh-sortable [sort-handle]{cursor:grab}.sh-sortable.sh-sortable-tree [draggable]{transform:none!important;transition:none!important;z-index:auto}.sh-sortable.sh-sortable-tree .sortable-ghost{z-index:0!important}.sh-sortable.sh-sortable-tree .sortable-ghost.drop-before:before,.sh-sortable.sh-sortable-tree .sortable-ghost.drop-after:after{display:none!important}.sh-sortable.sh-sortable-tree .sortable-ghost.drop-inside{outline:none!important;background:inherit!important}.sh-sortable.sh-sortable-tree .drop-inside{background:var(--primary-3)!important;outline:2px solid var(--primary-8)!important;outline-offset:-.125rem;border-radius:var(--shape-1, 4px)}.sh-sortable.sh-sortable-tree .drop-inside .node-icon,.sh-sortable.sh-sortable-tree .drop-inside sh-tree-node .sh-tree-node-left sh-icon{color:var(--primary-8)!important}.sh-sortable.sh-sortable-tree .drop-before{position:relative;z-index:20}.sh-sortable.sh-sortable-tree .drop-before:before{content:\"\";position:absolute;top:-.1875rem;left:calc(var(--tree-padding-left, 12px) + var(--tree-depth, 0) * var(--tree-indent-step, 12px) + .375rem);right:var(--tree-padding-right, 6px);height:.375rem;background-image:radial-gradient(circle at 3px 3px,var(--primary-8) 3px,transparent 3px),linear-gradient(to right,var(--primary-8),var(--primary-8));background-repeat:no-repeat,no-repeat;background-position:left center,6px center;background-size:6px 6px,100% 2px;z-index:10;pointer-events:none}.sh-sortable.sh-sortable-tree .drop-after{position:relative;z-index:20}.sh-sortable.sh-sortable-tree .drop-after:after{content:\"\";position:absolute;bottom:-.1875rem;left:calc(var(--tree-padding-left, 12px) + var(--tree-depth, 0) * var(--tree-indent-step, 12px) + .375rem);right:var(--tree-padding-right, 6px);height:.375rem;background-image:radial-gradient(circle at 3px 3px,var(--primary-8) 3px,transparent 3px),linear-gradient(to right,var(--primary-8),var(--primary-8));background-repeat:no-repeat,no-repeat;background-position:left center,6px center;background-size:6px 6px,100% 2px;z-index:10;pointer-events:none}sh-tree{--tree-bg: var(--base-2);--tree-bc: var(--base-3);--tree-color: var(--base-12);--tree-hover-bg: var(--base-3);--tree-active-bg: var(--base-4);--tree-selected-bg: var(--base-4);--tree-guide-color: var(--base-4);--tree-caret-color: var(--base-9);--tree-caret-hover-color: var(--base-12);--tree-icon-color: var(--base-9);--tree-icon-folder-color: var(--primary-8);--tree-indent-step: .75rem;--tree-padding-left: .75rem;--tree-padding-right: .375rem;display:flex;flex-direction:column;width:100%;background:var(--tree-bg);border:1px solid var(--tree-bc);border-radius:var(--shape-2, .5rem);overflow:hidden;font-family:var(--font-family, sans-serif);box-shadow:var(--box-shadow-10)}sh-tree .sh-tree-container{flex:1;padding:.5rem 0;overflow-y:auto;position:relative}sh-tree .sh-tree-node{display:flex;align-items:center;height:2rem;position:relative;cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--tree-color);font:var(--paragraph-20, 14px sans-serif);gap:.375rem;transition:background .12s ease;padding-left:calc(var(--tree-padding-left) + var(--tree-depth, 0) * var(--tree-indent-step));padding-right:var(--tree-padding-right);background:var(--tree-bg)}sh-tree .sh-tree-node:hover{background:var(--tree-hover-bg)}sh-tree .sh-tree-node.is-selected{background:var(--tree-selected-bg)}sh-tree .sh-tree-node.sortable-ghost{opacity:.4;background:var(--tree-active-bg)}sh-tree .sh-tree-node .indent-guide{position:absolute;top:0;bottom:0;width:1px;border-left:1px solid var(--tree-guide-color);opacity:.5;left:calc(var(--tree-padding-left) + var(--tree-indent-step) / 2 + var(--guide-index, 0) * var(--tree-indent-step))}sh-tree .sh-tree-node .caret-container{display:flex;align-items:center;justify-content:center;width:var(--tree-indent-step);height:1rem;z-index:2}sh-tree .sh-tree-node .caret-container:has(+.node-icon){position:absolute;opacity:0;z-index:3;width:var(--tree-indent-step)}sh-tree .sh-tree-node .caret-container .caret-btn{background:none;border:none;padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--tree-caret-color);border-radius:var(--shape-1, 4px);width:100%;height:100%;position:relative;transition:background .15s ease,color .15s ease}sh-tree .sh-tree-node .caret-container .caret-btn:after{content:\"\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:1.5rem;height:1.5rem;z-index:1}sh-tree .sh-tree-node .caret-container .caret-btn:hover{color:var(--tree-caret-hover-color)}sh-tree .sh-tree-node .node-icon{color:var(--tree-icon-color);display:inline-flex;align-items:center;justify-content:center;width:var(--tree-indent-step)}sh-tree .sh-tree-node .node-icon.folder{color:var(--tree-icon-folder-color)}sh-tree .sh-tree-node .node-icon:has(~.node-content sh-tree-node sh-icon){display:none}sh-tree .sh-tree-node.is-folder sh-tree-node .sh-tree-node-left sh-icon{color:var(--tree-icon-folder-color)}sh-tree .sh-tree-node:not(.is-folder) sh-tree-node .sh-tree-node-left sh-icon{color:var(--tree-icon-color)}sh-tree .sh-tree-node .node-content{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;z-index:2;display:flex;align-items:center}sh-tree .sh-tree-node .node-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}sh-tree sh-tree-node{display:flex;align-items:center;width:100%;gap:.5rem;justify-content:space-between;min-width:0}sh-tree sh-tree-node .sh-tree-node-left{display:flex;align-items:center;gap:.25rem;padding-left:.25rem;overflow:hidden;min-width:0;flex:1}sh-tree sh-tree-node .sh-tree-node-left sh-icon{display:inline-flex;align-items:center;justify-content:center;width:var(--tree-indent-step)}sh-tree sh-tree-node .sh-tree-node-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}sh-tree sh-tree-node .sh-tree-node-label span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}sh-tree sh-tree-node .sh-tree-node-actions,sh-tree sh-tree-node sh-tree-node-actions{display:flex;align-items:center;gap:.5rem}sh-tree sh-tree-node .status-badge{font-size:.625rem;padding:.125rem .375rem;border-radius:var(--shape-1, 4px);text-transform:uppercase;font-weight:600}sh-tree sh-tree-node .status-badge.success{background:var(--success-3, #e6f4ea);color:var(--success-8, #137333)}sh-tree sh-tree-node .status-badge.warning{background:var(--warning-3, #fef7e0);color:var(--warning-8, #b06000)}sh-tree sh-tree-node .status-badge.error{background:var(--error-3, #fce8e6);color:var(--error-8, #c5221f)}sh-tree sh-tree-node .delete-btn{background:none;border:none;padding:.125rem;cursor:pointer;color:var(--base-9);border-radius:var(--shape-1, 4px);display:flex;opacity:0;transition:opacity .15s ease;align-items:center;justify-content:center}sh-tree sh-tree-node .delete-btn:hover{background:var(--base-4);color:var(--error-8, #c5221f)}sh-tree .sh-tree-node:hover .delete-btn{opacity:1}sh-tree .empty-state{padding:2rem;text-align:center;color:var(--tree-caret-color);font:var(--paragraph-20, 14px sans-serif)}\n"] }]
|
|
178
|
+
}, template: "@if (sortableManager()) {\n <div\n class=\"sh-tree-container\"\n [shSortable]=\"sortableManager()\"\n [treeItems]=\"visibleNodes()\"\n sortingMode=\"tree\"\n role=\"tree\"\n >\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n draggable=\"true\"\n [attr.sortable-dir]=\"isFolder()(node) ? 'true' : null\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n role=\"treeitem\"\n [attr.aria-expanded]=\"isFolder()(node) ? getIsOpen()(node) : null\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n} @else {\n <div class=\"sh-tree-container\" role=\"tree\">\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n role=\"treeitem\"\n [attr.aria-expanded]=\"isFolder()(node) ? getIsOpen()(node) : null\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n}\n\n<ng-template #defaultTemplate let-node>\n <span class=\"node-name\">{{ getName()(node) }}</span>\n</ng-template>\n", styles: [".sh-sortable{position:relative}.sh-sortable.dragging [draggable],.sh-sortable.dragging .sortable-ghost{cursor:grabbing;transition:transform 40ms linear}.sh-sortable [draggable]{transform:translate(0);transition:none;z-index:2;-webkit-user-select:none;user-select:none}.sh-sortable:not(.sh-sortable-tree) [draggable]{background:var(--base-1)}.sh-sortable:not(.sh-sortable-tree) [draggable]:not(:has([sort-handle])){cursor:grab}.sh-sortable .sortable-ghost{opacity:.5;z-index:10}.sh-sortable.item-dragged-out .sortable-ghost{display:none}.sh-sortable [sort-handle]{cursor:grab}.sh-sortable.sh-sortable-tree [draggable]{transform:none!important;transition:none!important;z-index:auto}.sh-sortable.sh-sortable-tree .sortable-ghost{z-index:0!important}.sh-sortable.sh-sortable-tree .sortable-ghost.drop-before:before,.sh-sortable.sh-sortable-tree .sortable-ghost.drop-after:after{display:none!important}.sh-sortable.sh-sortable-tree .sortable-ghost.drop-inside{outline:none!important;background:inherit!important}.sh-sortable.sh-sortable-tree .drop-inside{background:var(--primary-3)!important;outline:2px solid var(--primary-8)!important;outline-offset:-.125rem;border-radius:var(--shape-1, 4px)}.sh-sortable.sh-sortable-tree .drop-inside .node-icon,.sh-sortable.sh-sortable-tree .drop-inside sh-tree-node .sh-tree-node-left sh-icon{color:var(--primary-8)!important}.sh-sortable.sh-sortable-tree .drop-before{position:relative;z-index:20}.sh-sortable.sh-sortable-tree .drop-before:before{content:\"\";position:absolute;top:-.1875rem;left:calc(var(--tree-padding-left, 12px) + var(--tree-depth, 0) * var(--tree-indent-step, 12px) + .375rem);right:var(--tree-padding-right, 6px);height:.375rem;background-image:radial-gradient(circle at 3px 3px,var(--primary-8) 3px,transparent 3px),linear-gradient(to right,var(--primary-8),var(--primary-8));background-repeat:no-repeat,no-repeat;background-position:left center,6px center;background-size:6px 6px,100% 2px;z-index:10;pointer-events:none}.sh-sortable.sh-sortable-tree .drop-after{position:relative;z-index:20}.sh-sortable.sh-sortable-tree .drop-after:after{content:\"\";position:absolute;bottom:-.1875rem;left:calc(var(--tree-padding-left, 12px) + var(--tree-depth, 0) * var(--tree-indent-step, 12px) + .375rem);right:var(--tree-padding-right, 6px);height:.375rem;background-image:radial-gradient(circle at 3px 3px,var(--primary-8) 3px,transparent 3px),linear-gradient(to right,var(--primary-8),var(--primary-8));background-repeat:no-repeat,no-repeat;background-position:left center,6px center;background-size:6px 6px,100% 2px;z-index:10;pointer-events:none}sh-tree{--tree-bg: var(--base-2);--tree-bc: var(--base-3);--tree-color: var(--base-12);--tree-hover-bg: var(--base-3);--tree-active-bg: var(--base-4);--tree-selected-bg: var(--base-4);--tree-guide-color: var(--base-4);--tree-caret-color: var(--base-9);--tree-caret-hover-color: var(--base-12);--tree-icon-color: var(--base-9);--tree-icon-folder-color: var(--primary-8);--tree-indent-step: .75rem;--tree-padding-left: .75rem;--tree-padding-right: .375rem;display:flex;flex-direction:column;width:100%;background:var(--tree-bg);border:1px solid var(--tree-bc);border-radius:var(--shape-2, .5rem);overflow:hidden;font-family:var(--font-family, sans-serif);box-shadow:var(--box-shadow-10)}sh-tree .sh-tree-container{flex:1;padding:.5rem 0;overflow-y:auto;position:relative}sh-tree .sh-tree-node{display:flex;align-items:center;height:2rem;position:relative;cursor:pointer;-webkit-user-select:none;user-select:none;color:var(--tree-color);font:var(--paragraph-20, 14px sans-serif);gap:.375rem;transition:background .12s ease;padding-left:calc(var(--tree-padding-left) + var(--tree-depth, 0) * var(--tree-indent-step));padding-right:var(--tree-padding-right);background:var(--tree-bg)}sh-tree .sh-tree-node:hover{background:var(--tree-hover-bg)}sh-tree .sh-tree-node.is-selected{background:var(--tree-selected-bg)}sh-tree .sh-tree-node.sortable-ghost{opacity:.4;background:var(--tree-active-bg)}sh-tree .sh-tree-node .indent-guide{position:absolute;top:0;bottom:0;width:1px;border-left:1px solid var(--tree-guide-color);opacity:.5;left:calc(var(--tree-padding-left) + var(--tree-indent-step) / 2 + var(--guide-index, 0) * var(--tree-indent-step))}sh-tree .sh-tree-node .caret-container{display:flex;align-items:center;justify-content:center;width:var(--tree-indent-step);height:1rem;z-index:2}sh-tree .sh-tree-node .caret-container:has(+.node-icon){position:absolute;opacity:0;z-index:3;width:var(--tree-indent-step)}sh-tree .sh-tree-node .caret-container .caret-btn{background:none;border:none;padding:0;cursor:pointer;display:flex;align-items:center;justify-content:center;color:var(--tree-caret-color);border-radius:var(--shape-1, 4px);width:100%;height:100%;position:relative;transition:background .15s ease,color .15s ease}sh-tree .sh-tree-node .caret-container .caret-btn:after{content:\"\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:1.5rem;height:1.5rem;z-index:1}sh-tree .sh-tree-node .caret-container .caret-btn:hover{color:var(--tree-caret-hover-color)}sh-tree .sh-tree-node .node-icon{color:var(--tree-icon-color);display:inline-flex;align-items:center;justify-content:center;width:var(--tree-indent-step)}sh-tree .sh-tree-node .node-icon.folder{color:var(--tree-icon-folder-color)}sh-tree .sh-tree-node .node-icon:has(~.node-content sh-tree-node sh-icon){display:none}sh-tree .sh-tree-node.is-folder sh-tree-node .sh-tree-node-left sh-icon{color:var(--tree-icon-folder-color)}sh-tree .sh-tree-node:not(.is-folder) sh-tree-node .sh-tree-node-left sh-icon{color:var(--tree-icon-color)}sh-tree .sh-tree-node .node-content{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;z-index:2;display:flex;align-items:center}sh-tree .sh-tree-node .node-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}sh-tree sh-tree-node{display:flex;align-items:center;width:100%;gap:.5rem;justify-content:space-between;min-width:0}sh-tree sh-tree-node .sh-tree-node-left{display:flex;align-items:center;gap:.25rem;padding-left:.25rem;overflow:hidden;min-width:0;flex:1}sh-tree sh-tree-node .sh-tree-node-left sh-icon{display:inline-flex;align-items:center;justify-content:center;width:var(--tree-indent-step)}sh-tree sh-tree-node .sh-tree-node-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0}sh-tree sh-tree-node .sh-tree-node-label span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}sh-tree sh-tree-node .sh-tree-node-actions,sh-tree sh-tree-node sh-tree-node-actions{display:flex;align-items:center;gap:.5rem}sh-tree sh-tree-node .status-badge{font-size:.625rem;padding:.125rem .375rem;border-radius:var(--shape-1, 4px);text-transform:uppercase;font-weight:600}sh-tree sh-tree-node .status-badge.success{background:var(--success-3, #e6f4ea);color:var(--success-8, #137333)}sh-tree sh-tree-node .status-badge.warning{background:var(--warning-3, #fef7e0);color:var(--warning-8, #b06000)}sh-tree sh-tree-node .status-badge.error{background:var(--error-3, #fce8e6);color:var(--error-8, #c5221f)}sh-tree sh-tree-node .delete-btn{background:none;border:none;padding:.125rem;cursor:pointer;color:var(--base-9);border-radius:var(--shape-1, 4px);display:flex;opacity:0;transition:opacity .15s ease;align-items:center;justify-content:center}sh-tree sh-tree-node .delete-btn:hover{background:var(--base-4);color:var(--error-8, #c5221f)}sh-tree .sh-tree-node:hover .delete-btn{opacity:1}sh-tree .empty-state{padding:2rem;text-align:center;color:var(--tree-caret-color);font:var(--paragraph-20, 14px sans-serif)}\n"] }]
|
|
179
179
|
}], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }, { type: i0.Output, args: ["itemsChange"] }], sortableManager: [{ type: i0.Input, args: [{ isSignal: true, alias: "sortableManager", required: false }] }], selectedId: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedId", required: false }] }, { type: i0.Output, args: ["selectedIdChange"] }], getId: [{ type: i0.Input, args: [{ isSignal: true, alias: "getId", required: false }] }], getName: [{ type: i0.Input, args: [{ isSignal: true, alias: "getName", required: false }] }], getParentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "getParentId", required: false }] }], isFolder: [{ type: i0.Input, args: [{ isSignal: true, alias: "isFolder", required: false }] }], getIsOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "getIsOpen", required: false }] }], setIsOpen: [{ type: i0.Input, args: [{ isSignal: true, alias: "setIsOpen", required: false }] }], getIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "getIcon", required: false }] }], openIconDir: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ShipTreeOpenIcon), { isSignal: true }] }], closedIconDir: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ShipTreeClosedIcon), { isSignal: true }] }], itemIconDir: [{ type: i0.ContentChild, args: [i0.forwardRef(() => ShipTreeItemIcon), { isSignal: true }] }], nodeClick: [{ type: i0.Output, args: ["nodeClick"] }], nodeToggle: [{ type: i0.Output, args: ["nodeToggle"] }], nodeTemplate: [{ type: i0.ContentChild, args: ['nodeTemplate', { isSignal: true }] }], dirTemplate: [{ type: i0.ContentChild, args: ['dirTemplate', { isSignal: true }] }] } });
|
|
180
180
|
class ShipTreeNode {
|
|
181
181
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipTreeNode, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ship-ui-core-ship-tree.mjs","sources":["../../../projects/ship-ui/ship-tree/ship-tree.ts","../../../projects/ship-ui/ship-tree/ship-tree.html","../../../projects/ship-ui/ship-tree/ship-ui-core-ship-tree.ts"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n Directive,\n ElementRef,\n inject,\n input,\n model,\n output,\n TemplateRef,\n ViewEncapsulation,\n} from '@angular/core';\nimport { ShipIcon } from '@ship-ui/core/ship-icon';\nimport { ShipSortable } from '@ship-ui/core/ship-sortable';\n\n@Directive({ selector: 'sh-icon[openIcon]', standalone: true })\nexport class ShipTreeOpenIcon {\n readonly el = inject(ElementRef<HTMLElement>);\n}\n\n@Directive({ selector: 'sh-icon[closedIcon]', standalone: true })\nexport class ShipTreeClosedIcon {\n readonly el = inject(ElementRef<HTMLElement>);\n}\n\n@Directive({ selector: 'sh-icon[itemIcon]', standalone: true })\nexport class ShipTreeItemIcon {\n readonly el = inject(ElementRef<HTMLElement>);\n}\n\n@Component({\n selector: 'sh-tree',\n standalone: true,\n imports: [NgTemplateOutlet, ShipIcon, ShipSortable],\n templateUrl: './ship-tree.html',\n styleUrl: './ship-tree.scss',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class.sh-tree]': 'true',\n },\n})\nexport class ShipTree {\n /** The flat list of all tree nodes. */\n readonly items = model<any[]>([]);\n\n /** Optional Writable/Readable WritableSignal manager created by createTreeSortableManager. */\n readonly sortableManager = input<any>(null);\n\n /** Currently selected node ID. */\n readonly selectedId = model<string | null>(null);\n\n // Mappings\n readonly getId = input<(item: any) => string>((item) => item.id);\n readonly getName = input<(item: any) => string>((item) => item.name);\n readonly getParentId = input<(item: any) => string | null>((item) => item.parentId);\n readonly isFolder = input<(item: any) => boolean>((item) => item.type === 'dir');\n readonly getIsOpen = input<(item: any) => boolean>((item) => !!item.isOpen);\n readonly setIsOpen = input<(item: any, isOpen: boolean) => void>((item, open) => {\n item.isOpen = open;\n });\n\n /** Function returning a custom icon name for a node. */\n readonly getIcon = input<(item: any) => string | null>(() => null);\n\n // Read projected icons via lightweight directives\n readonly openIconDir = contentChild(ShipTreeOpenIcon);\n readonly closedIconDir = contentChild(ShipTreeClosedIcon);\n readonly itemIconDir = contentChild(ShipTreeItemIcon);\n\n openIconName = computed(() => this.openIconDir()?.el.nativeElement.textContent?.trim() || null);\n closedIconName = computed(() => this.closedIconDir()?.el.nativeElement.textContent?.trim() || null);\n itemIconName = computed(() => this.itemIconDir()?.el.nativeElement.textContent?.trim() || null);\n\n // Outputs\n readonly nodeClick = output<any>();\n readonly nodeToggle = output<{ node: any; isOpen: boolean }>();\n\n readonly nodeTemplate = contentChild<TemplateRef<any>>('nodeTemplate');\n readonly dirTemplate = contentChild<TemplateRef<any>>('dirTemplate');\n\n /** Filter the full flat array down to only visible nodes (whose parents are all expanded). */\n visibleNodes = computed(() => {\n const manager = this.sortableManager();\n if (manager && typeof manager.visibleNodes === 'function') {\n return manager.visibleNodes();\n }\n\n const list = this.items();\n const visible: any[] = [];\n\n const isNodeVisible = (node: any): boolean => {\n let currentParentId = this.getParentId()(node);\n while (currentParentId !== null && currentParentId !== undefined) {\n const parent = list.find((n) => this.getId()(n) === currentParentId);\n if (!parent || !this.getIsOpen()(parent)) {\n return false;\n }\n currentParentId = this.getParentId()(parent);\n }\n return true;\n };\n\n for (const node of list) {\n const parentId = this.getParentId()(node);\n if (parentId === null || parentId === undefined || isNodeVisible(node)) {\n visible.push(node);\n }\n }\n return visible;\n });\n\n toggleNode(node: any, event: MouseEvent) {\n event.stopPropagation();\n const open = !this.getIsOpen()(node);\n\n this.items.update((list) =>\n list.map((item) => {\n if (this.getId()(item) === this.getId()(node)) {\n const updated = { ...item };\n this.setIsOpen()(updated, open);\n return updated;\n }\n return item;\n })\n );\n\n this.nodeToggle.emit({ node, isOpen: open });\n }\n\n handleNodeClick(node: any, event: MouseEvent) {\n const target = event.target as HTMLElement;\n const isIconClick = !!target.closest('sh-icon') && !target.closest('.sh-tree-node-actions') && !target.closest('sh-tree-node-actions') && !target.closest('.caret-container');\n\n if (isIconClick && this.isFolder()(node)) {\n this.toggleNode(node, event);\n } else {\n this.selectNode(node);\n }\n }\n\n selectNode(node: any) {\n this.selectedId.set(this.getId()(node));\n this.nodeClick.emit(node);\n }\n\n getDepthArray(depth: number): number[] {\n return Array.from({ length: depth }, (_, i) => i);\n }\n\n getNodeDepth(node: any): number {\n const list = this.items();\n let depth = 0;\n let currentParentId = this.getParentId()(node);\n while (currentParentId !== null && currentParentId !== undefined) {\n const parent = list.find((n) => this.getId()(n) === currentParentId);\n if (!parent) break;\n depth++;\n currentParentId = this.getParentId()(parent);\n }\n return depth;\n }\n\n getNodeIcon(node: any): string | null {\n const customIcon = this.getIcon()(node);\n if (customIcon) return customIcon;\n\n if (this.isFolder()(node)) {\n const open = this.getIsOpen()(node);\n return open ? this.openIconName() : this.closedIconName();\n }\n return this.itemIconName() || 'file';\n }\n}\n\n@Component({\n selector: 'sh-tree-node',\n template: `\n <div class=\"sh-tree-node-left\">\n <ng-content select=\"sh-icon\" />\n <span class=\"sh-tree-node-label\">\n <ng-content />\n </span>\n </div>\n <div class=\"sh-tree-node-actions\">\n <ng-content select=\"[actions], sh-tree-node-actions\" />\n </div>\n `,\n host: {\n '[class.sh-tree-node-layout]': 'true',\n },\n})\nexport class ShipTreeNode {}\n\n@Component({\n selector: 'sh-tree-node-actions',\n template: `\n <ng-content />\n `,\n host: {\n '[class.sh-tree-node-actions]': 'true',\n },\n})\nexport class ShipTreeNodeActions {}\n","@if (sortableManager()) {\n <div\n class=\"sh-tree-container\"\n [shSortable]=\"sortableManager()\"\n [treeItems]=\"visibleNodes()\"\n sortingMode=\"tree\"\n >\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n draggable=\"true\"\n [attr.sortable-dir]=\"isFolder()(node) ? 'true' : null\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n} @else {\n <div class=\"sh-tree-container\">\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n}\n\n<ng-template #defaultTemplate let-node>\n <span class=\"node-name\">{{ getName()(node) }}</span>\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ship-ui-core-ship-tree.mjs","sources":["../../../projects/ship-ui/ship-tree/ship-tree.ts","../../../projects/ship-ui/ship-tree/ship-tree.html","../../../projects/ship-ui/ship-tree/ship-ui-core-ship-tree.ts"],"sourcesContent":["import { NgTemplateOutlet } from '@angular/common';\nimport {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n Directive,\n ElementRef,\n inject,\n input,\n model,\n output,\n TemplateRef,\n ViewEncapsulation,\n} from '@angular/core';\nimport { ShipIcon } from '@ship-ui/core/ship-icon';\nimport { ShipSortable } from '@ship-ui/core/ship-sortable';\n\n@Directive({ selector: 'sh-icon[openIcon]', standalone: true })\nexport class ShipTreeOpenIcon {\n readonly el = inject(ElementRef<HTMLElement>);\n}\n\n@Directive({ selector: 'sh-icon[closedIcon]', standalone: true })\nexport class ShipTreeClosedIcon {\n readonly el = inject(ElementRef<HTMLElement>);\n}\n\n@Directive({ selector: 'sh-icon[itemIcon]', standalone: true })\nexport class ShipTreeItemIcon {\n readonly el = inject(ElementRef<HTMLElement>);\n}\n\n@Component({\n selector: 'sh-tree',\n standalone: true,\n imports: [NgTemplateOutlet, ShipIcon, ShipSortable],\n templateUrl: './ship-tree.html',\n styleUrl: './ship-tree.scss',\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class.sh-tree]': 'true',\n },\n})\nexport class ShipTree {\n /** The flat list of all tree nodes. */\n readonly items = model<any[]>([]);\n\n /** Optional Writable/Readable WritableSignal manager created by createTreeSortableManager. */\n readonly sortableManager = input<any>(null);\n\n /** Currently selected node ID. */\n readonly selectedId = model<string | null>(null);\n\n // Mappings\n readonly getId = input<(item: any) => string>((item) => item.id);\n readonly getName = input<(item: any) => string>((item) => item.name);\n readonly getParentId = input<(item: any) => string | null>((item) => item.parentId);\n readonly isFolder = input<(item: any) => boolean>((item) => item.type === 'dir');\n readonly getIsOpen = input<(item: any) => boolean>((item) => !!item.isOpen);\n readonly setIsOpen = input<(item: any, isOpen: boolean) => void>((item, open) => {\n item.isOpen = open;\n });\n\n /** Function returning a custom icon name for a node. */\n readonly getIcon = input<(item: any) => string | null>(() => null);\n\n // Read projected icons via lightweight directives\n readonly openIconDir = contentChild(ShipTreeOpenIcon);\n readonly closedIconDir = contentChild(ShipTreeClosedIcon);\n readonly itemIconDir = contentChild(ShipTreeItemIcon);\n\n openIconName = computed(() => this.openIconDir()?.el.nativeElement.textContent?.trim() || null);\n closedIconName = computed(() => this.closedIconDir()?.el.nativeElement.textContent?.trim() || null);\n itemIconName = computed(() => this.itemIconDir()?.el.nativeElement.textContent?.trim() || null);\n\n // Outputs\n readonly nodeClick = output<any>();\n readonly nodeToggle = output<{ node: any; isOpen: boolean }>();\n\n readonly nodeTemplate = contentChild<TemplateRef<any>>('nodeTemplate');\n readonly dirTemplate = contentChild<TemplateRef<any>>('dirTemplate');\n\n /** Filter the full flat array down to only visible nodes (whose parents are all expanded). */\n visibleNodes = computed(() => {\n const manager = this.sortableManager();\n if (manager && typeof manager.visibleNodes === 'function') {\n return manager.visibleNodes();\n }\n\n const list = this.items();\n const visible: any[] = [];\n\n const isNodeVisible = (node: any): boolean => {\n let currentParentId = this.getParentId()(node);\n while (currentParentId !== null && currentParentId !== undefined) {\n const parent = list.find((n) => this.getId()(n) === currentParentId);\n if (!parent || !this.getIsOpen()(parent)) {\n return false;\n }\n currentParentId = this.getParentId()(parent);\n }\n return true;\n };\n\n for (const node of list) {\n const parentId = this.getParentId()(node);\n if (parentId === null || parentId === undefined || isNodeVisible(node)) {\n visible.push(node);\n }\n }\n return visible;\n });\n\n toggleNode(node: any, event: MouseEvent) {\n event.stopPropagation();\n const open = !this.getIsOpen()(node);\n\n this.items.update((list) =>\n list.map((item) => {\n if (this.getId()(item) === this.getId()(node)) {\n const updated = { ...item };\n this.setIsOpen()(updated, open);\n return updated;\n }\n return item;\n })\n );\n\n this.nodeToggle.emit({ node, isOpen: open });\n }\n\n handleNodeClick(node: any, event: MouseEvent) {\n const target = event.target as HTMLElement;\n const isIconClick = !!target.closest('sh-icon') && !target.closest('.sh-tree-node-actions') && !target.closest('sh-tree-node-actions') && !target.closest('.caret-container');\n\n if (isIconClick && this.isFolder()(node)) {\n this.toggleNode(node, event);\n } else {\n this.selectNode(node);\n }\n }\n\n selectNode(node: any) {\n this.selectedId.set(this.getId()(node));\n this.nodeClick.emit(node);\n }\n\n getDepthArray(depth: number): number[] {\n return Array.from({ length: depth }, (_, i) => i);\n }\n\n getNodeDepth(node: any): number {\n const list = this.items();\n let depth = 0;\n let currentParentId = this.getParentId()(node);\n while (currentParentId !== null && currentParentId !== undefined) {\n const parent = list.find((n) => this.getId()(n) === currentParentId);\n if (!parent) break;\n depth++;\n currentParentId = this.getParentId()(parent);\n }\n return depth;\n }\n\n getNodeIcon(node: any): string | null {\n const customIcon = this.getIcon()(node);\n if (customIcon) return customIcon;\n\n if (this.isFolder()(node)) {\n const open = this.getIsOpen()(node);\n return open ? this.openIconName() : this.closedIconName();\n }\n return this.itemIconName() || 'file';\n }\n}\n\n@Component({\n selector: 'sh-tree-node',\n template: `\n <div class=\"sh-tree-node-left\">\n <ng-content select=\"sh-icon\" />\n <span class=\"sh-tree-node-label\">\n <ng-content />\n </span>\n </div>\n <div class=\"sh-tree-node-actions\">\n <ng-content select=\"[actions], sh-tree-node-actions\" />\n </div>\n `,\n host: {\n '[class.sh-tree-node-layout]': 'true',\n },\n})\nexport class ShipTreeNode {}\n\n@Component({\n selector: 'sh-tree-node-actions',\n template: `\n <ng-content />\n `,\n host: {\n '[class.sh-tree-node-actions]': 'true',\n },\n})\nexport class ShipTreeNodeActions {}\n","@if (sortableManager()) {\n <div\n class=\"sh-tree-container\"\n [shSortable]=\"sortableManager()\"\n [treeItems]=\"visibleNodes()\"\n sortingMode=\"tree\"\n role=\"tree\"\n >\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n draggable=\"true\"\n [attr.sortable-dir]=\"isFolder()(node) ? 'true' : null\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n role=\"treeitem\"\n [attr.aria-expanded]=\"isFolder()(node) ? getIsOpen()(node) : null\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n} @else {\n <div class=\"sh-tree-container\" role=\"tree\">\n @for (node of visibleNodes(); track getId()(node)) {\n <div\n class=\"sh-tree-node\"\n [class.is-folder]=\"isFolder()(node)\"\n [class.is-expanded]=\"getIsOpen()(node)\"\n [class.is-selected]=\"selectedId() === getId()(node)\"\n [style.--tree-depth]=\"getNodeDepth(node)\"\n (click)=\"handleNodeClick(node, $event)\"\n role=\"treeitem\"\n [attr.aria-expanded]=\"isFolder()(node) ? getIsOpen()(node) : null\"\n >\n <!-- Indent guides -->\n @for (i of getDepthArray(getNodeDepth(node)); track i) {\n <div class=\"indent-guide\" [style.--guide-index]=\"i\"></div>\n }\n\n <!-- Folder Caret -->\n @if (isFolder()(node) && !dirTemplate()) {\n <span class=\"caret-container\">\n <button class=\"caret-btn\" (click)=\"toggleNode(node, $event)\" type=\"button\">\n @if (getIsOpen()(node)) {\n <sh-icon size=\"small\">caret-down</sh-icon>\n } @else {\n <sh-icon size=\"small\">caret-right</sh-icon>\n }\n </button>\n </span>\n }\n\n <!-- Node Icon -->\n @if (getNodeIcon(node)) {\n @if (getNodeIcon(node) === 'file') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">file</sh-icon>\n } @else if (getNodeIcon(node) === 'folder') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder</sh-icon>\n } @else if (getNodeIcon(node) === 'folder-open') {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">folder-open</sh-icon>\n } @else {\n <sh-icon class=\"node-icon\" [class.folder]=\"isFolder()(node)\" size=\"small\">\n {{ getNodeIcon(node) }}\n </sh-icon>\n }\n }\n\n <!-- Node Content -->\n <div class=\"node-content\">\n <ng-container *ngTemplateOutlet=\"isFolder()(node) && dirTemplate() ? dirTemplate() : (nodeTemplate() || defaultTemplate); context: { $implicit: node }\"></ng-container>\n </div>\n </div>\n } @empty {\n <div class=\"empty-state\">\n <ng-content select=\"[emptyState]\">\n No items in tree\n </ng-content>\n </div>\n }\n </div>\n}\n\n<ng-template #defaultTemplate let-node>\n <span class=\"node-name\">{{ getName()(node) }}</span>\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -158,7 +158,7 @@ class ShipVirtualScroll {
|
|
|
158
158
|
}
|
|
159
159
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipVirtualScroll, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
160
160
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.0", type: ShipVirtualScroll, isStandalone: true, selector: "sh-virtual-scroll", viewQueries: [{ propertyName: "viewportRef", first: true, predicate: ["viewport"], descendants: true, isSignal: true }, { propertyName: "itemElements", predicate: ["item"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
161
|
-
<div class="viewport" #viewport (scroll)="onScroll()">
|
|
161
|
+
<div class="viewport" #viewport tabindex="0" role="region" aria-label="Virtualized list" (scroll)="onScroll()">
|
|
162
162
|
<div class="total-height" [style.height]="totalHeight() + 'px'"></div>
|
|
163
163
|
<div class="items-container" [style.transform]="'translateY(' + translateY() + 'px)'">
|
|
164
164
|
<ng-content />
|
|
@@ -169,7 +169,7 @@ class ShipVirtualScroll {
|
|
|
169
169
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.0", ngImport: i0, type: ShipVirtualScroll, decorators: [{
|
|
170
170
|
type: Component,
|
|
171
171
|
args: [{ selector: 'sh-virtual-scroll', encapsulation: ViewEncapsulation.None, imports: [], template: `
|
|
172
|
-
<div class="viewport" #viewport (scroll)="onScroll()">
|
|
172
|
+
<div class="viewport" #viewport tabindex="0" role="region" aria-label="Virtualized list" (scroll)="onScroll()">
|
|
173
173
|
<div class="total-height" [style.height]="totalHeight() + 'px'"></div>
|
|
174
174
|
<div class="items-container" [style.transform]="'translateY(' + translateY() + 'px)'">
|
|
175
175
|
<ng-content />
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ship-ui-core-ship-virtual-scroll.mjs","sources":["../../../projects/ship-ui/ship-virtual-scroll/ship-virtual-scroll.component.ts","../../../projects/ship-ui/ship-virtual-scroll/ship-ui-core-ship-virtual-scroll.ts"],"sourcesContent":["import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, effect, ElementRef, inject, Renderer2, signal, viewChild, viewChildren, ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'sh-virtual-scroll',\n styleUrl: './ship-virtual-scroll.scss',\n encapsulation: ViewEncapsulation.None,\n imports: [],\n template: `\n <div class=\"viewport\" #viewport (scroll)=\"onScroll()\">\n <div class=\"total-height\" [style.height]=\"totalHeight() + 'px'\"></div>\n <div class=\"items-container\" [style.transform]=\"'translateY(' + translateY() + 'px)'\">\n <ng-content />\n </div>\n </div>\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ShipVirtualScroll {\n #changeRef = inject(ChangeDetectorRef);\n #renderer = inject(Renderer2);\n #hostElement = inject(ElementRef);\n\n viewportRef = viewChild.required<ElementRef<HTMLDivElement>>('viewport');\n itemElements = viewChildren<ElementRef>('item');\n\n bufferSize = signal(10);\n\n itemHeights = signal<number[]>([]);\n startIndex = signal(0);\n endIndex = signal(0);\n translateY = signal(0);\n totalHeight = computed(() => this.itemHeights().reduce((sum, height) => sum + height, 0));\n numberOfRenderedItems = signal(0);\n\n #resizeObserver: ResizeObserver | null = null;\n #hostResizeObserver: ResizeObserver | null = null;\n\n #itemHeightsEffect = effect(() => {\n const startIndex = this.startIndex();\n const endIndex = this.endIndex();\n const itemHeights = this.itemHeights();\n\n if (startIndex > 0 && endIndex > 0 && itemHeights.length > 0) {\n let newTranslateY = 0;\n for (let i = 0; i < startIndex; i++) {\n newTranslateY += itemHeights[i];\n }\n this.translateY.set(newTranslateY);\n }\n });\n\n #totalHeightEffect = effect(() => {\n const _ = this.totalHeight();\n this.#changeRef.detectChanges();\n });\n\n #itemElementsEffect = effect(() => {\n const itemElements = this.itemElements();\n\n if (this.#resizeObserver && itemElements) {\n this.#resizeObserver.disconnect();\n const heights = new Array(itemElements.length).fill(0);\n this.numberOfRenderedItems.set(itemElements.length);\n this.itemHeights.set(heights);\n\n for (let i = 0; i < itemElements.length; i++) {\n this.#resizeObserver.observe(itemElements[i].nativeElement);\n heights[i] = itemElements[i].nativeElement.offsetHeight;\n }\n\n this.itemHeights.set(heights);\n this.#calculateVisibleItems();\n }\n });\n\n ngAfterViewInit() {\n this.#setupHostResizeObserver();\n this.#setupResizeObserver();\n this.#changeRef.detectChanges();\n }\n\n onScroll() {\n this.#calculateVisibleItems();\n }\n\n #setupHostResizeObserver() {\n if (typeof ResizeObserver === 'undefined') return;\n this.#hostResizeObserver = new ResizeObserver((entries) => {\n const hostElement = entries[0];\n if (hostElement) {\n const newHeight = hostElement.contentRect.height;\n this.#renderer.setStyle(this.viewportRef().nativeElement, 'height', `${newHeight}px`);\n }\n });\n\n this.#hostResizeObserver.observe(this.#hostElement.nativeElement);\n }\n\n #setupResizeObserver() {\n if (typeof ResizeObserver === 'undefined') return;\n this.#resizeObserver = new ResizeObserver((entries) => {\n const newHeights = [...this.itemHeights()];\n\n let didUpdate = false;\n\n for (const entry of entries) {\n const index = this.itemElements().findIndex((el) => el.nativeElement === entry.target);\n\n if (index !== undefined && index !== -1) {\n const newHeight = entry.contentRect.height;\n if (newHeights[index] !== newHeight) {\n newHeights[index] = newHeight;\n didUpdate = true;\n }\n }\n }\n\n if (didUpdate) {\n this.itemHeights.set(newHeights);\n this.#calculateVisibleItems();\n }\n });\n }\n\n #cleanupResizeObserver() {\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n this.#resizeObserver = null;\n }\n }\n\n #cleanupHostResizeObserver() {\n if (this.#hostResizeObserver) {\n this.#hostResizeObserver.disconnect();\n this.#hostResizeObserver = null;\n }\n }\n\n #calculateVisibleItems() {\n const nativeElement = this.viewportRef();\n if (!nativeElement) return;\n\n const scrollTop = nativeElement.nativeElement.scrollTop;\n const viewportHeight = nativeElement.nativeElement.clientHeight;\n\n let accumulatedHeight = 0;\n let startIndex = -1;\n let endIndex = -1;\n\n for (let i = 0; i < this.itemHeights().length; i++) {\n const itemHeight = this.itemHeights()[i];\n\n if (startIndex === -1 && accumulatedHeight + itemHeight >= scrollTop - this.bufferSize()) {\n startIndex = i;\n }\n\n if (endIndex === -1 && accumulatedHeight >= scrollTop + viewportHeight + this.bufferSize()) {\n endIndex = i;\n break;\n }\n\n accumulatedHeight += itemHeight;\n }\n\n if (endIndex === -1) {\n endIndex = this.itemHeights().length - 1;\n }\n\n if (this.startIndex() !== startIndex) {\n this.startIndex.set(startIndex);\n }\n if (this.endIndex() !== endIndex) {\n this.endIndex.set(endIndex);\n }\n }\n\n ngOnDestroy() {\n this.#cleanupResizeObserver();\n this.#cleanupHostResizeObserver();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ship-ui-core-ship-virtual-scroll.mjs","sources":["../../../projects/ship-ui/ship-virtual-scroll/ship-virtual-scroll.component.ts","../../../projects/ship-ui/ship-virtual-scroll/ship-ui-core-ship-virtual-scroll.ts"],"sourcesContent":["import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, effect, ElementRef, inject, Renderer2, signal, viewChild, viewChildren, ViewEncapsulation } from '@angular/core';\n\n@Component({\n selector: 'sh-virtual-scroll',\n styleUrl: './ship-virtual-scroll.scss',\n encapsulation: ViewEncapsulation.None,\n imports: [],\n template: `\n <div class=\"viewport\" #viewport tabindex=\"0\" role=\"region\" aria-label=\"Virtualized list\" (scroll)=\"onScroll()\">\n <div class=\"total-height\" [style.height]=\"totalHeight() + 'px'\"></div>\n <div class=\"items-container\" [style.transform]=\"'translateY(' + translateY() + 'px)'\">\n <ng-content />\n </div>\n </div>\n `,\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ShipVirtualScroll {\n #changeRef = inject(ChangeDetectorRef);\n #renderer = inject(Renderer2);\n #hostElement = inject(ElementRef);\n\n viewportRef = viewChild.required<ElementRef<HTMLDivElement>>('viewport');\n itemElements = viewChildren<ElementRef>('item');\n\n bufferSize = signal(10);\n\n itemHeights = signal<number[]>([]);\n startIndex = signal(0);\n endIndex = signal(0);\n translateY = signal(0);\n totalHeight = computed(() => this.itemHeights().reduce((sum, height) => sum + height, 0));\n numberOfRenderedItems = signal(0);\n\n #resizeObserver: ResizeObserver | null = null;\n #hostResizeObserver: ResizeObserver | null = null;\n\n #itemHeightsEffect = effect(() => {\n const startIndex = this.startIndex();\n const endIndex = this.endIndex();\n const itemHeights = this.itemHeights();\n\n if (startIndex > 0 && endIndex > 0 && itemHeights.length > 0) {\n let newTranslateY = 0;\n for (let i = 0; i < startIndex; i++) {\n newTranslateY += itemHeights[i];\n }\n this.translateY.set(newTranslateY);\n }\n });\n\n #totalHeightEffect = effect(() => {\n const _ = this.totalHeight();\n this.#changeRef.detectChanges();\n });\n\n #itemElementsEffect = effect(() => {\n const itemElements = this.itemElements();\n\n if (this.#resizeObserver && itemElements) {\n this.#resizeObserver.disconnect();\n const heights = new Array(itemElements.length).fill(0);\n this.numberOfRenderedItems.set(itemElements.length);\n this.itemHeights.set(heights);\n\n for (let i = 0; i < itemElements.length; i++) {\n this.#resizeObserver.observe(itemElements[i].nativeElement);\n heights[i] = itemElements[i].nativeElement.offsetHeight;\n }\n\n this.itemHeights.set(heights);\n this.#calculateVisibleItems();\n }\n });\n\n ngAfterViewInit() {\n this.#setupHostResizeObserver();\n this.#setupResizeObserver();\n this.#changeRef.detectChanges();\n }\n\n onScroll() {\n this.#calculateVisibleItems();\n }\n\n #setupHostResizeObserver() {\n if (typeof ResizeObserver === 'undefined') return;\n this.#hostResizeObserver = new ResizeObserver((entries) => {\n const hostElement = entries[0];\n if (hostElement) {\n const newHeight = hostElement.contentRect.height;\n this.#renderer.setStyle(this.viewportRef().nativeElement, 'height', `${newHeight}px`);\n }\n });\n\n this.#hostResizeObserver.observe(this.#hostElement.nativeElement);\n }\n\n #setupResizeObserver() {\n if (typeof ResizeObserver === 'undefined') return;\n this.#resizeObserver = new ResizeObserver((entries) => {\n const newHeights = [...this.itemHeights()];\n\n let didUpdate = false;\n\n for (const entry of entries) {\n const index = this.itemElements().findIndex((el) => el.nativeElement === entry.target);\n\n if (index !== undefined && index !== -1) {\n const newHeight = entry.contentRect.height;\n if (newHeights[index] !== newHeight) {\n newHeights[index] = newHeight;\n didUpdate = true;\n }\n }\n }\n\n if (didUpdate) {\n this.itemHeights.set(newHeights);\n this.#calculateVisibleItems();\n }\n });\n }\n\n #cleanupResizeObserver() {\n if (this.#resizeObserver) {\n this.#resizeObserver.disconnect();\n this.#resizeObserver = null;\n }\n }\n\n #cleanupHostResizeObserver() {\n if (this.#hostResizeObserver) {\n this.#hostResizeObserver.disconnect();\n this.#hostResizeObserver = null;\n }\n }\n\n #calculateVisibleItems() {\n const nativeElement = this.viewportRef();\n if (!nativeElement) return;\n\n const scrollTop = nativeElement.nativeElement.scrollTop;\n const viewportHeight = nativeElement.nativeElement.clientHeight;\n\n let accumulatedHeight = 0;\n let startIndex = -1;\n let endIndex = -1;\n\n for (let i = 0; i < this.itemHeights().length; i++) {\n const itemHeight = this.itemHeights()[i];\n\n if (startIndex === -1 && accumulatedHeight + itemHeight >= scrollTop - this.bufferSize()) {\n startIndex = i;\n }\n\n if (endIndex === -1 && accumulatedHeight >= scrollTop + viewportHeight + this.bufferSize()) {\n endIndex = i;\n break;\n }\n\n accumulatedHeight += itemHeight;\n }\n\n if (endIndex === -1) {\n endIndex = this.itemHeights().length - 1;\n }\n\n if (this.startIndex() !== startIndex) {\n this.startIndex.set(startIndex);\n }\n if (this.endIndex() !== endIndex) {\n this.endIndex.set(endIndex);\n }\n }\n\n ngOnDestroy() {\n this.#cleanupResizeObserver();\n this.#cleanupHostResizeObserver();\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { signal, output, HostListener, Directive, inject, ElementRef, Renderer2, input, computed, TemplateRef, DOCUMENT, effect, ViewEncapsulation, Component, untracked, ViewContainerRef, EnvironmentInjector, DestroyRef, Injector, PLATFORM_ID, isSignal, assertInInjectionContext, InjectionToken, model, booleanAttribute } from '@angular/core';
|
|
3
3
|
import { NgTemplateOutlet, isPlatformServer } from '@angular/common';
|
|
4
|
+
import { ShipA11yKeybindingsService } from '@ship-ui/core/ship-a11y-keybindings';
|
|
4
5
|
|
|
5
6
|
class ShipFileDragDrop {
|
|
6
7
|
constructor() {
|
|
@@ -1009,11 +1010,13 @@ function shipComponentClasses(componentName, inputs) {
|
|
|
1009
1010
|
}
|
|
1010
1011
|
|
|
1011
1012
|
class ShipSelectionGroup {
|
|
1013
|
+
#keybindings;
|
|
1012
1014
|
constructor(itemSelector, activeClass, options) {
|
|
1013
1015
|
this.itemSelector = itemSelector;
|
|
1014
1016
|
this.activeClass = activeClass;
|
|
1015
1017
|
this.options = options;
|
|
1016
1018
|
this.hostElement = inject((ElementRef)).nativeElement;
|
|
1019
|
+
this.#keybindings = inject(ShipA11yKeybindingsService);
|
|
1017
1020
|
this.value = model(null, /* @ts-ignore */
|
|
1018
1021
|
...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
|
|
1019
1022
|
this.closable = input(false, { ...(ngDevMode ? { debugName: "closable" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
|
|
@@ -1030,6 +1033,10 @@ class ShipSelectionGroup {
|
|
|
1030
1033
|
const selectedValue = this.value();
|
|
1031
1034
|
const activeClass = this.activeClass;
|
|
1032
1035
|
const items = this.items();
|
|
1036
|
+
const activeAttr = this.options?.activeAttribute ||
|
|
1037
|
+
(this.options?.itemRole === 'tab' || this.options?.itemRole === 'option' ? 'aria-selected' :
|
|
1038
|
+
this.options?.itemRole === 'radio' ? 'aria-checked' :
|
|
1039
|
+
'aria-pressed');
|
|
1033
1040
|
let hasSelection = false;
|
|
1034
1041
|
items.forEach((item) => {
|
|
1035
1042
|
const itemValue = item.getAttribute('value');
|
|
@@ -1044,19 +1051,27 @@ class ShipSelectionGroup {
|
|
|
1044
1051
|
item.setAttribute('role', this.options.itemRole);
|
|
1045
1052
|
}
|
|
1046
1053
|
const itemValue = item.getAttribute('value');
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
item.
|
|
1054
|
+
const hasValueAttr = itemValue !== null || item.hasAttribute('value');
|
|
1055
|
+
let isSelected = false;
|
|
1056
|
+
if (hasValueAttr) {
|
|
1057
|
+
isSelected = itemValue === String(selectedValue) || (itemValue === '' && (selectedValue === null || selectedValue === ''));
|
|
1058
|
+
}
|
|
1059
|
+
else {
|
|
1060
|
+
isSelected = item.classList.contains(activeClass);
|
|
1061
|
+
}
|
|
1062
|
+
if (isSelected) {
|
|
1063
|
+
if (hasValueAttr) {
|
|
1064
|
+
item.classList.add(activeClass);
|
|
1065
|
+
}
|
|
1066
|
+
item.setAttribute(activeAttr, 'true');
|
|
1054
1067
|
item.setAttribute('tabindex', '0');
|
|
1055
1068
|
}
|
|
1056
1069
|
else {
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1070
|
+
if (hasValueAttr) {
|
|
1071
|
+
item.classList.remove(activeClass);
|
|
1072
|
+
}
|
|
1073
|
+
item.setAttribute(activeAttr, 'false');
|
|
1074
|
+
if (hasSelection || !hasValueAttr) {
|
|
1060
1075
|
item.setAttribute('tabindex', '-1');
|
|
1061
1076
|
}
|
|
1062
1077
|
else {
|
|
@@ -1085,11 +1100,12 @@ class ShipSelectionGroup {
|
|
|
1085
1100
|
}
|
|
1086
1101
|
onKeyDown(event) {
|
|
1087
1102
|
const targetEl = event.target;
|
|
1088
|
-
if (event
|
|
1103
|
+
if (this.#keybindings.matches(event, 'selection-group.select')) {
|
|
1089
1104
|
const item = targetEl?.closest?.(this.itemSelector);
|
|
1090
1105
|
if (item && this.hostElement.contains(item) && item.hasAttribute('value')) {
|
|
1091
1106
|
// Only prevent default for space to avoid scrolling, let enter naturally click if it's a link/button
|
|
1092
|
-
|
|
1107
|
+
const isSpace = event.key === ' ' || event.key === 'Spacebar';
|
|
1108
|
+
if (isSpace)
|
|
1093
1109
|
event.preventDefault();
|
|
1094
1110
|
const value = item.getAttribute('value');
|
|
1095
1111
|
if (this.closable() && String(this.value()) === String(value)) {
|
|
@@ -1111,17 +1127,14 @@ class ShipSelectionGroup {
|
|
|
1111
1127
|
if (activeIndex === -1)
|
|
1112
1128
|
activeIndex = 0;
|
|
1113
1129
|
let nextIndex = activeIndex;
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
break;
|
|
1123
|
-
default:
|
|
1124
|
-
return; // Let other keys propagate natively
|
|
1130
|
+
if (this.#keybindings.matches(event, 'selection-group.next')) {
|
|
1131
|
+
nextIndex = activeIndex >= items.length - 1 ? 0 : activeIndex + 1;
|
|
1132
|
+
}
|
|
1133
|
+
else if (this.#keybindings.matches(event, 'selection-group.prev')) {
|
|
1134
|
+
nextIndex = activeIndex <= 0 ? items.length - 1 : activeIndex - 1;
|
|
1135
|
+
}
|
|
1136
|
+
else {
|
|
1137
|
+
return; // Let other keys propagate natively
|
|
1125
1138
|
}
|
|
1126
1139
|
event.preventDefault();
|
|
1127
1140
|
const nextItem = items[nextIndex];
|