@jax-data-science/sci-image-visualizer 0.9.0 → 0.11.0

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.
Files changed (149) hide show
  1. package/esm2022/index.mjs +10 -1
  2. package/esm2022/lib/contracts/image.contract.mjs +1 -1
  3. package/esm2022/lib/contracts/ports/region-io.port.mjs +1 -1
  4. package/esm2022/lib/contracts/region-editor-api.contract.mjs +1 -1
  5. package/esm2022/lib/contracts/region-store.contract.mjs +1 -1
  6. package/esm2022/lib/contracts/section-view.contract.mjs +2 -0
  7. package/esm2022/lib/contracts/visualizer.contract.mjs +1 -1
  8. package/esm2022/lib/contracts/viz-config.mjs +1 -1
  9. package/esm2022/lib/geometry/loft.mjs +128 -0
  10. package/esm2022/lib/geometry/polylabel.mjs +156 -0
  11. package/esm2022/lib/geometry/reconstruct.mjs +315 -0
  12. package/esm2022/lib/geometry/reslice-image.mjs +57 -0
  13. package/esm2022/lib/geometry/section.mjs +215 -0
  14. package/esm2022/lib/implementations/napari-js/napari-loading-badge.mjs +11 -7
  15. package/esm2022/lib/implementations/napari-js/napari-loading-state.mjs +20 -3
  16. package/esm2022/lib/implementations/napari-js/napari-region-mesh-pointer.mjs +100 -0
  17. package/esm2022/lib/implementations/napari-js/napari-region-overlay.mjs +28 -5
  18. package/esm2022/lib/implementations/napari-js/napari-scene.mjs +1 -1
  19. package/esm2022/lib/implementations/napari-js/napari-spatial-hover.mjs +9 -2
  20. package/esm2022/lib/implementations/napari-js/napari-tool-bridge.mjs +5 -2
  21. package/esm2022/lib/implementations/napari-js/napari-visualizer.service.mjs +81 -1
  22. package/esm2022/lib/implementations/napari-js/napari-volume-region-meshes.mjs +129 -0
  23. package/esm2022/lib/implementations/napari-js/napari-volume-scene.mjs +115 -4
  24. package/esm2022/lib/implementations/napari-js/napari-volume-slice-planes.mjs +103 -0
  25. package/esm2022/lib/implementations/napari-js/region-overlay/region-svg-renderer.mjs +15 -3
  26. package/esm2022/lib/implementations/osd/openseadragon-viewer-options.mjs +18 -2
  27. package/esm2022/lib/implementations/osd/openseadragon-visualizer.service.mjs +9 -1
  28. package/esm2022/lib/implementations/osd/osd-region-overlay-draw.mjs +18 -7
  29. package/esm2022/lib/implementations/osd/osd-region-overlay.mjs +38 -8
  30. package/esm2022/lib/implementations/osd/osd-tile-loading.mjs +71 -0
  31. package/esm2022/lib/implementations/osd/osd-viewer-like.mjs +1 -1
  32. package/esm2022/lib/implementations/osd/slice-cache.mjs +35 -6
  33. package/esm2022/lib/implementations/tile-server/tile-protocol.mjs +1 -1
  34. package/esm2022/lib/models/class-preset.mjs +1 -1
  35. package/esm2022/lib/models/polygon-factory.mjs +17 -1
  36. package/esm2022/lib/models/region-geojson.mjs +44 -6
  37. package/esm2022/lib/models/region.mjs +1 -1
  38. package/esm2022/lib/region-editor/class-tree/class-tree.component.mjs +156 -0
  39. package/esm2022/lib/region-editor/class-tree/class-tree.mjs +108 -0
  40. package/esm2022/lib/region-editor/classes-panel/classes-panel.component.mjs +77 -13
  41. package/esm2022/lib/region-editor/region-editor.component.mjs +670 -42
  42. package/esm2022/lib/region-editor/region-metrics.mjs +20 -2
  43. package/esm2022/lib/region-editor/region-persistence.service.mjs +44 -10
  44. package/esm2022/lib/region-editor/region-table/region-table.component.mjs +24 -8
  45. package/esm2022/lib/region-import/label-classes.mjs +149 -0
  46. package/esm2022/lib/region-import/label-volume.mjs +194 -0
  47. package/esm2022/lib/region-import/region-import.mjs +71 -0
  48. package/esm2022/lib/region-overlay/region-geometry.mjs +3 -3
  49. package/esm2022/lib/region-overlay/region-source-layer.mjs +378 -0
  50. package/esm2022/lib/region-overlay/region-style.mjs +97 -0
  51. package/esm2022/lib/region-source/http-region-source.mjs +104 -0
  52. package/esm2022/lib/region-source/region-source-ops.mjs +53 -0
  53. package/esm2022/lib/region-source/region-source-worker.mjs +10 -0
  54. package/esm2022/lib/region-source/region-source.mjs +67 -0
  55. package/esm2022/lib/region-source/region-tiles.mjs +708 -0
  56. package/esm2022/lib/region-source/worker-region-source.mjs +229 -0
  57. package/esm2022/lib/routing-visualizer.service.mjs +510 -22
  58. package/esm2022/lib/section-pane/section-pane.component.mjs +299 -0
  59. package/esm2022/lib/store/class-color.util.mjs +10 -5
  60. package/esm2022/lib/store/class-signatures.mjs +63 -0
  61. package/esm2022/lib/store/region-scope-cache.mjs +5 -1
  62. package/esm2022/lib/store/region-source-scope.mjs +186 -0
  63. package/esm2022/lib/store/region-store.service.mjs +774 -12
  64. package/esm2022/lib/store/visualizer-store.service.mjs +33 -6
  65. package/esm2022/lib/toolbar/region-tools/region-tools.component.mjs +8 -2
  66. package/esm2022/lib/toolbar/stack-controls/stack-controls.component.mjs +55 -15
  67. package/esm2022/lib/toolbar/toolbar.component.mjs +19 -5
  68. package/esm2022/lib/visualizer/region-load.mjs +67 -4
  69. package/esm2022/lib/visualizer/volume-sections.mjs +175 -0
  70. package/esm2022/lib/visualizer.component.mjs +155 -7
  71. package/fesm2022/{jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs → jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BELcx0jv.mjs} +9851 -2904
  72. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-BELcx0jv.mjs.map +1 -0
  73. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs → jax-data-science-sci-image-visualizer-onnx-sam-session-DEDSm_NL.mjs} +4 -4
  74. package/fesm2022/{jax-data-science-sci-image-visualizer-onnx-sam-session-Bkujqg7m.mjs.map → jax-data-science-sci-image-visualizer-onnx-sam-session-DEDSm_NL.mjs.map} +1 -1
  75. package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs +12 -0
  76. package/fesm2022/jax-data-science-sci-image-visualizer-region-source-worker-CAqBjM5L.mjs.map +1 -0
  77. package/fesm2022/jax-data-science-sci-image-visualizer.mjs +3 -3
  78. package/fesm2022/region-source.worker.js +1067 -0
  79. package/index.d.ts +12 -0
  80. package/lib/contracts/image.contract.d.ts +4 -0
  81. package/lib/contracts/ports/region-io.port.d.ts +24 -0
  82. package/lib/contracts/region-editor-api.contract.d.ts +102 -0
  83. package/lib/contracts/region-store.contract.d.ts +22 -0
  84. package/lib/contracts/section-view.contract.d.ts +44 -0
  85. package/lib/contracts/visualizer.contract.d.ts +10 -0
  86. package/lib/contracts/viz-config.d.ts +8 -0
  87. package/lib/geometry/loft.d.ts +22 -0
  88. package/lib/geometry/polylabel.d.ts +23 -0
  89. package/lib/geometry/reconstruct.d.ts +54 -0
  90. package/lib/geometry/reslice-image.d.ts +33 -0
  91. package/lib/geometry/section.d.ts +52 -0
  92. package/lib/implementations/napari-js/napari-loading-badge.d.ts +4 -2
  93. package/lib/implementations/napari-js/napari-loading-state.d.ts +8 -1
  94. package/lib/implementations/napari-js/napari-region-mesh-pointer.d.ts +32 -0
  95. package/lib/implementations/napari-js/napari-region-overlay.d.ts +6 -1
  96. package/lib/implementations/napari-js/napari-scene.d.ts +33 -0
  97. package/lib/implementations/napari-js/napari-spatial-hover.d.ts +3 -1
  98. package/lib/implementations/napari-js/napari-visualizer.service.d.ts +48 -0
  99. package/lib/implementations/napari-js/napari-volume-region-meshes.d.ts +66 -0
  100. package/lib/implementations/napari-js/napari-volume-scene.d.ts +45 -1
  101. package/lib/implementations/napari-js/napari-volume-slice-planes.d.ts +43 -0
  102. package/lib/implementations/osd/openseadragon-viewer-options.d.ts +2 -0
  103. package/lib/implementations/osd/openseadragon-visualizer.service.d.ts +2 -0
  104. package/lib/implementations/osd/osd-region-overlay-draw.d.ts +4 -3
  105. package/lib/implementations/osd/osd-region-overlay.d.ts +10 -3
  106. package/lib/implementations/osd/osd-tile-loading.d.ts +43 -0
  107. package/lib/implementations/osd/osd-viewer-like.d.ts +14 -0
  108. package/lib/implementations/osd/slice-cache.d.ts +13 -3
  109. package/lib/implementations/tile-server/tile-protocol.d.ts +3 -0
  110. package/lib/models/class-preset.d.ts +7 -0
  111. package/lib/models/polygon-factory.d.ts +5 -0
  112. package/lib/models/region-geojson.d.ts +40 -0
  113. package/lib/models/region.d.ts +19 -0
  114. package/lib/region-editor/class-tree/class-tree.component.d.ts +78 -0
  115. package/lib/region-editor/class-tree/class-tree.d.ts +31 -0
  116. package/lib/region-editor/classes-panel/classes-panel.component.d.ts +36 -6
  117. package/lib/region-editor/region-editor.component.d.ts +159 -17
  118. package/lib/region-editor/region-metrics.d.ts +8 -0
  119. package/lib/region-editor/region-persistence.service.d.ts +17 -5
  120. package/lib/region-editor/region-table/region-table.component.d.ts +10 -4
  121. package/lib/region-import/label-classes.d.ts +39 -0
  122. package/lib/region-import/label-volume.d.ts +31 -0
  123. package/lib/region-import/region-import.d.ts +46 -0
  124. package/lib/region-overlay/region-geometry.d.ts +4 -3
  125. package/lib/region-overlay/region-source-layer.d.ts +96 -0
  126. package/lib/region-overlay/region-style.d.ts +52 -0
  127. package/lib/region-source/http-region-source.d.ts +45 -0
  128. package/lib/region-source/region-source-ops.d.ts +89 -0
  129. package/lib/region-source/region-source-worker.d.ts +7 -0
  130. package/lib/region-source/region-source.d.ts +82 -0
  131. package/lib/region-source/region-tiles.d.ts +289 -0
  132. package/lib/region-source/worker-region-source.d.ts +65 -0
  133. package/lib/routing-visualizer.service.d.ts +168 -1
  134. package/lib/section-pane/section-pane.component.d.ts +47 -0
  135. package/lib/store/class-color.util.d.ts +6 -3
  136. package/lib/store/class-signatures.d.ts +11 -0
  137. package/lib/store/region-scope-cache.d.ts +2 -0
  138. package/lib/store/region-source-scope.d.ts +74 -0
  139. package/lib/store/region-store.service.d.ts +216 -2
  140. package/lib/store/visualizer-store.service.d.ts +10 -0
  141. package/lib/toolbar/region-tools/region-tools.component.d.ts +3 -1
  142. package/lib/toolbar/stack-controls/stack-controls.component.d.ts +20 -9
  143. package/lib/toolbar/toolbar.component.d.ts +9 -2
  144. package/lib/visualizer/region-load.d.ts +23 -4
  145. package/lib/visualizer/volume-sections.d.ts +64 -0
  146. package/lib/visualizer.component.d.ts +40 -0
  147. package/package.json +2 -2
  148. package/src/lib/assets/slice.svg +23 -0
  149. package/fesm2022/jax-data-science-sci-image-visualizer-jax-data-science-sci-image-visualizer-Csxlnq7I.mjs.map +0 -1
@@ -0,0 +1,156 @@
1
+ import { ChangeDetectionStrategy, Component, ElementRef, EventEmitter, Input, Output, } from '@angular/core';
2
+ import { CommonModule } from '@angular/common';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { InputTextModule } from 'primeng/inputtext';
5
+ import { TooltipModule } from 'primeng/tooltip';
6
+ import { HexColorPickerComponent } from '../../hex-color-picker/hex-color-picker.component';
7
+ import { ancestors, buildClassTree, subtree, visibleRows } from './class-tree';
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "@angular/common";
10
+ import * as i2 from "@angular/forms";
11
+ import * as i3 from "primeng/inputtext";
12
+ import * as i4 from "primeng/tooltip";
13
+ /**
14
+ * The Region Editor's classes as a hierarchy (a brain atlas's ontology), as the Allen atlas viewer
15
+ * shows it: collapsible, each class with its colour, name and long name, and the regions it and
16
+ * its subclasses have on this slice; a class with none is greyed. Picking a class selects all its
17
+ * regions and its subclasses' (the editor does the selecting). Search by name or long name. A
18
+ * class's swatch recolours it, as the class list's does; its eye hides it and its subclasses.
19
+ */
20
+ export class ClassTreeComponent {
21
+ constructor(el) {
22
+ this.el = el;
23
+ /** The hierarchy. */
24
+ this.nodes = [];
25
+ /** Regions per class on this slice (the regions and the region source's). */
26
+ this.counts = new Map();
27
+ /** A class's colour (a new function when the colours change, so the rows repaint). */
28
+ this.colorOf = () => '#999999';
29
+ /** The class picked last (highlighted, its path expanded, scrolled into view). */
30
+ this.picked = null;
31
+ /** Classes with a selected region (marked). */
32
+ this.marked = new Set();
33
+ /** Whether a volume view is on screen: each class can then be shown in 3D. */
34
+ this.volume = false;
35
+ /** The classes shown in 3D. */
36
+ this.shown3d = new Set();
37
+ /** The classes hidden from view. */
38
+ this.hidden = new Set();
39
+ this.pick = new EventEmitter();
40
+ /** A class's swatch picked a new colour. */
41
+ this.recolor = new EventEmitter();
42
+ /** A class's 3D toggle: it with every class under it. */
43
+ this.toggle3d = new EventEmitter();
44
+ /** A class's eye: hide (or show) it with every class under it. */
45
+ this.toggleHidden = new EventEmitter();
46
+ this.tree = buildClassTree([], new Map());
47
+ this.rows = [];
48
+ /** Each row's visibility (a row absent: shown). */
49
+ this.visibility = new Map();
50
+ this.query = '';
51
+ this.expanded = new Set();
52
+ this.trackRow = (_, r) => r.name;
53
+ }
54
+ ngOnChanges(changes) {
55
+ const fresh = !!changes['nodes'];
56
+ if (fresh || changes['counts'])
57
+ this.tree = buildClassTree(this.nodes, this.counts);
58
+ // A new hierarchy opens with its roots expanded, as the atlas viewer does.
59
+ if (fresh)
60
+ this.expanded = new Set(this.tree.roots);
61
+ if (changes['picked'] && this.picked)
62
+ for (const a of ancestors(this.tree, this.picked))
63
+ this.expanded.add(a);
64
+ this.refresh();
65
+ // A pick from elsewhere (a surface clicked in 3D) may be off screen: bring its row into view.
66
+ if (changes['picked'] && this.picked)
67
+ setTimeout(() => scrollToPicked(this.el.nativeElement, '.tree-row.picked'));
68
+ }
69
+ node(name) {
70
+ return this.tree.node.get(name);
71
+ }
72
+ total(name) {
73
+ return this.tree.total.get(name) ?? 0;
74
+ }
75
+ toggle(row, event) {
76
+ event.stopPropagation();
77
+ if (this.expanded.has(row.name))
78
+ this.expanded.delete(row.name);
79
+ else
80
+ this.expanded.add(row.name);
81
+ this.refresh();
82
+ }
83
+ choose(name, event) {
84
+ const e = event;
85
+ this.pick.emit({ name, classes: subtree(this.tree, name), additive: e.shiftKey || e.metaKey || e.ctrlKey });
86
+ }
87
+ /** The eye: a class hidden (wholly) is shown again with its subclasses; otherwise they are hidden. */
88
+ flipHidden(name, event) {
89
+ event.stopPropagation();
90
+ const hidden = this.visibility.get(name) !== 'hidden';
91
+ this.toggleHidden.emit({ classes: subtree(this.tree, name), hidden });
92
+ }
93
+ flip3d(name, event) {
94
+ event.stopPropagation();
95
+ this.toggle3d.emit({ name, classes: subtree(this.tree, name) });
96
+ }
97
+ onQuery(value) {
98
+ this.query = value;
99
+ this.refresh();
100
+ }
101
+ /** Enter in the search box picks the first match. */
102
+ pickFirstMatch(event) {
103
+ const q = this.query.trim().toLowerCase();
104
+ const hit = this.rows.find((r) => r.name.toLowerCase().includes(q) || (this.node(r.name)?.title ?? '').toLowerCase().includes(q));
105
+ if (hit)
106
+ this.choose(hit.name, event);
107
+ }
108
+ refresh() {
109
+ this.rows = visibleRows(this.tree, this.expanded, this.query);
110
+ this.visibility = new Map();
111
+ if (!this.hidden.size)
112
+ return;
113
+ for (const row of this.rows) {
114
+ const classes = subtree(this.tree, row.name);
115
+ const off = classes.filter((c) => this.hidden.has(c)).length;
116
+ if (off)
117
+ this.visibility.set(row.name, off === classes.length ? 'hidden' : 'partial');
118
+ }
119
+ }
120
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: ClassTreeComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component }); }
121
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.9", type: ClassTreeComponent, isStandalone: true, selector: "region-class-tree", inputs: { nodes: "nodes", counts: "counts", colorOf: "colorOf", picked: "picked", marked: "marked", volume: "volume", shown3d: "shown3d", hidden: "hidden" }, outputs: { pick: "pick", recolor: "recolor", toggle3d: "toggle3d", toggleHidden: "toggleHidden" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"class-tree\">\n <div class=\"tree-header\" *ngIf=\"picked as p\">\n <span class=\"tree-picked\">\n <b>{{ p }}</b\n ><span *ngIf=\"node(p)?.title as t\"> \u00B7 {{ t }}</span>\n </span>\n </div>\n <input\n type=\"text\"\n pInputText\n class=\"p-inputtext-sm tree-search\"\n placeholder=\"Search by name\"\n aria-label=\"Search the classes\"\n [ngModel]=\"query\"\n (ngModelChange)=\"onQuery($event)\"\n (keydown.enter)=\"pickFirstMatch($event)\"\n />\n <div class=\"tree-body\" role=\"tree\">\n <div\n *ngFor=\"let row of rows; trackBy: trackRow\"\n class=\"tree-row\"\n role=\"treeitem\"\n tabindex=\"0\"\n [attr.aria-expanded]=\"row.hasChildren ? row.expanded : null\"\n [class.absent]=\"total(row.name) === 0\"\n [class.picked]=\"row.name === picked\"\n [class.marked]=\"marked.has(row.name)\"\n [class.hidden-class]=\"visibility.get(row.name) === 'hidden'\"\n [style.padding-left.rem]=\"0.35 + row.depth * 0.9\"\n [pTooltip]=\"node(row.name)?.title || row.name\"\n tooltipPosition=\"left\"\n [showDelay]=\"600\"\n (click)=\"choose(row.name, $event)\"\n (keydown.enter)=\"choose(row.name, $event)\"\n >\n <i\n class=\"pi tree-toggle\"\n [class.pi-minus-circle]=\"row.hasChildren && row.expanded\"\n [class.pi-plus-circle]=\"row.hasChildren && !row.expanded\"\n [attr.aria-label]=\"row.expanded ? 'Collapse' : 'Expand'\"\n (click)=\"row.hasChildren && toggle(row, $event)\"\n ></i>\n <i\n class=\"pi tree-eye\"\n [ngClass]=\"visibility.get(row.name) === 'hidden' ? 'pi-eye-slash' : 'pi-eye'\"\n [class.partial]=\"visibility.get(row.name) === 'partial'\"\n role=\"button\"\n [attr.aria-pressed]=\"visibility.get(row.name) !== 'hidden'\"\n [attr.aria-label]=\"(visibility.get(row.name) === 'hidden' ? 'Show ' : 'Hide ') + row.name\"\n [pTooltip]=\"\n (visibility.get(row.name) === 'hidden' ? 'Show' : 'Hide') +\n (row.hasChildren ? ' it and its subclasses' : '') +\n (visibility.get(row.name) === 'partial' ? ' (some are hidden)' : '')\n \"\n tooltipPosition=\"left\"\n (click)=\"flipHidden(row.name, $event)\"\n (keydown.enter)=\"flipHidden(row.name, $event)\"\n ></i>\n <span class=\"tree-swatch\" (click)=\"$event.stopPropagation()\" (keydown.enter)=\"$event.stopPropagation()\">\n <hex-color-picker\n [color]=\"colorOf(row.name)\"\n (colorChange)=\"recolor.emit({ name: row.name, color: $event })\"\n >\n </hex-color-picker>\n </span>\n <span class=\"tree-name\">{{ row.name }}</span>\n <span class=\"tree-long\">{{ node(row.name)?.title }}</span>\n <span class=\"tree-count\" *ngIf=\"total(row.name) > 0\">{{ total(row.name) }}</span>\n <i\n *ngIf=\"volume\"\n class=\"pi pi-box tree-3d\"\n [class.on]=\"shown3d.has(row.name)\"\n role=\"button\"\n [attr.aria-pressed]=\"shown3d.has(row.name)\"\n [attr.aria-label]=\"'Show ' + row.name + ' in 3D'\"\n pTooltip=\"Show in the volume, in 3D\"\n tooltipPosition=\"left\"\n (click)=\"flip3d(row.name, $event)\"\n ></i>\n </div>\n <div *ngIf=\"!rows.length\" class=\"tree-empty\">No class matches.</div>\n </div>\n</div>\n", styles: [":host{display:block;flex:0 0 auto}.class-tree{display:flex;flex-direction:column;padding-top:.25rem}.tree-header{display:flex;align-items:baseline;gap:.5rem;padding:0 .5rem .25rem}.tree-picked{font-size:.8rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-search{margin:0 .5rem .25rem}.tree-body{height:14rem;min-height:3rem;max-height:70vh;overflow:auto;resize:vertical;padding-bottom:.25rem}.tree-row{display:flex;align-items:center;gap:.35rem;padding-top:.05rem;padding-bottom:.05rem;padding-right:.5rem;cursor:pointer;font-size:.8rem;white-space:nowrap}.tree-row:hover,.tree-row:focus-visible{background:var(--surface-hover, rgba(0, 0, 0, .04))}.tree-row.picked{background:var(--highlight-bg, rgba(51, 153, 255, .15))}.tree-row.marked{box-shadow:inset 3px 0 0 var(--primary-color)}.tree-row.absent{color:var(--text-color-secondary, #8a8a8a);font-style:italic;opacity:.7}.tree-toggle{flex:0 0 .9rem;font-size:.75rem;color:var(--text-color-secondary)}.tree-swatch{flex:0 0 auto;display:inline-flex}::ng-deep region-class-tree .tree-swatch .hex-picker-swatch{width:.8rem;height:.8rem;border-width:1px;border-radius:0}.tree-name{font-weight:700}.absent .tree-name{font-weight:400}.tree-long{min-width:0;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto}.tree-count{flex:0 0 auto;font-size:.7rem;color:var(--text-color-secondary)}.tree-empty{padding:.5rem;font-size:.8rem;color:var(--text-color-secondary)}.tree-3d{flex:0 0 auto;font-size:.8rem;opacity:.35;cursor:pointer}.tree-3d:hover{opacity:.8}.tree-3d.on{opacity:1;color:var(--primary-color)}.tree-eye{flex:0 0 auto;font-size:.8rem;opacity:.4;cursor:pointer}.tree-eye:hover{opacity:.9}.tree-eye.partial{opacity:.7;color:var(--primary-color)}.tree-row.hidden-class .tree-eye{opacity:1}.tree-row.hidden-class .tree-swatch,.tree-row.hidden-class .tree-name,.tree-row.hidden-class .tree-long,.tree-row.hidden-class .tree-count{opacity:.45}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: InputTextModule }, { kind: "directive", type: i3.InputText, selector: "[pInputText]", inputs: ["variant"] }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i4.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "appendTo", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions"] }, { kind: "component", type: HexColorPickerComponent, selector: "hex-color-picker", inputs: ["color"], outputs: ["colorChange", "colorInput"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
122
+ }
123
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.9", ngImport: i0, type: ClassTreeComponent, decorators: [{
124
+ type: Component,
125
+ args: [{ selector: 'region-class-tree', standalone: true, imports: [CommonModule, FormsModule, InputTextModule, TooltipModule, HexColorPickerComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"class-tree\">\n <div class=\"tree-header\" *ngIf=\"picked as p\">\n <span class=\"tree-picked\">\n <b>{{ p }}</b\n ><span *ngIf=\"node(p)?.title as t\"> \u00B7 {{ t }}</span>\n </span>\n </div>\n <input\n type=\"text\"\n pInputText\n class=\"p-inputtext-sm tree-search\"\n placeholder=\"Search by name\"\n aria-label=\"Search the classes\"\n [ngModel]=\"query\"\n (ngModelChange)=\"onQuery($event)\"\n (keydown.enter)=\"pickFirstMatch($event)\"\n />\n <div class=\"tree-body\" role=\"tree\">\n <div\n *ngFor=\"let row of rows; trackBy: trackRow\"\n class=\"tree-row\"\n role=\"treeitem\"\n tabindex=\"0\"\n [attr.aria-expanded]=\"row.hasChildren ? row.expanded : null\"\n [class.absent]=\"total(row.name) === 0\"\n [class.picked]=\"row.name === picked\"\n [class.marked]=\"marked.has(row.name)\"\n [class.hidden-class]=\"visibility.get(row.name) === 'hidden'\"\n [style.padding-left.rem]=\"0.35 + row.depth * 0.9\"\n [pTooltip]=\"node(row.name)?.title || row.name\"\n tooltipPosition=\"left\"\n [showDelay]=\"600\"\n (click)=\"choose(row.name, $event)\"\n (keydown.enter)=\"choose(row.name, $event)\"\n >\n <i\n class=\"pi tree-toggle\"\n [class.pi-minus-circle]=\"row.hasChildren && row.expanded\"\n [class.pi-plus-circle]=\"row.hasChildren && !row.expanded\"\n [attr.aria-label]=\"row.expanded ? 'Collapse' : 'Expand'\"\n (click)=\"row.hasChildren && toggle(row, $event)\"\n ></i>\n <i\n class=\"pi tree-eye\"\n [ngClass]=\"visibility.get(row.name) === 'hidden' ? 'pi-eye-slash' : 'pi-eye'\"\n [class.partial]=\"visibility.get(row.name) === 'partial'\"\n role=\"button\"\n [attr.aria-pressed]=\"visibility.get(row.name) !== 'hidden'\"\n [attr.aria-label]=\"(visibility.get(row.name) === 'hidden' ? 'Show ' : 'Hide ') + row.name\"\n [pTooltip]=\"\n (visibility.get(row.name) === 'hidden' ? 'Show' : 'Hide') +\n (row.hasChildren ? ' it and its subclasses' : '') +\n (visibility.get(row.name) === 'partial' ? ' (some are hidden)' : '')\n \"\n tooltipPosition=\"left\"\n (click)=\"flipHidden(row.name, $event)\"\n (keydown.enter)=\"flipHidden(row.name, $event)\"\n ></i>\n <span class=\"tree-swatch\" (click)=\"$event.stopPropagation()\" (keydown.enter)=\"$event.stopPropagation()\">\n <hex-color-picker\n [color]=\"colorOf(row.name)\"\n (colorChange)=\"recolor.emit({ name: row.name, color: $event })\"\n >\n </hex-color-picker>\n </span>\n <span class=\"tree-name\">{{ row.name }}</span>\n <span class=\"tree-long\">{{ node(row.name)?.title }}</span>\n <span class=\"tree-count\" *ngIf=\"total(row.name) > 0\">{{ total(row.name) }}</span>\n <i\n *ngIf=\"volume\"\n class=\"pi pi-box tree-3d\"\n [class.on]=\"shown3d.has(row.name)\"\n role=\"button\"\n [attr.aria-pressed]=\"shown3d.has(row.name)\"\n [attr.aria-label]=\"'Show ' + row.name + ' in 3D'\"\n pTooltip=\"Show in the volume, in 3D\"\n tooltipPosition=\"left\"\n (click)=\"flip3d(row.name, $event)\"\n ></i>\n </div>\n <div *ngIf=\"!rows.length\" class=\"tree-empty\">No class matches.</div>\n </div>\n</div>\n", styles: [":host{display:block;flex:0 0 auto}.class-tree{display:flex;flex-direction:column;padding-top:.25rem}.tree-header{display:flex;align-items:baseline;gap:.5rem;padding:0 .5rem .25rem}.tree-picked{font-size:.8rem;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tree-search{margin:0 .5rem .25rem}.tree-body{height:14rem;min-height:3rem;max-height:70vh;overflow:auto;resize:vertical;padding-bottom:.25rem}.tree-row{display:flex;align-items:center;gap:.35rem;padding-top:.05rem;padding-bottom:.05rem;padding-right:.5rem;cursor:pointer;font-size:.8rem;white-space:nowrap}.tree-row:hover,.tree-row:focus-visible{background:var(--surface-hover, rgba(0, 0, 0, .04))}.tree-row.picked{background:var(--highlight-bg, rgba(51, 153, 255, .15))}.tree-row.marked{box-shadow:inset 3px 0 0 var(--primary-color)}.tree-row.absent{color:var(--text-color-secondary, #8a8a8a);font-style:italic;opacity:.7}.tree-toggle{flex:0 0 .9rem;font-size:.75rem;color:var(--text-color-secondary)}.tree-swatch{flex:0 0 auto;display:inline-flex}::ng-deep region-class-tree .tree-swatch .hex-picker-swatch{width:.8rem;height:.8rem;border-width:1px;border-radius:0}.tree-name{font-weight:700}.absent .tree-name{font-weight:400}.tree-long{min-width:0;overflow:hidden;text-overflow:ellipsis;flex:1 1 auto}.tree-count{flex:0 0 auto;font-size:.7rem;color:var(--text-color-secondary)}.tree-empty{padding:.5rem;font-size:.8rem;color:var(--text-color-secondary)}.tree-3d{flex:0 0 auto;font-size:.8rem;opacity:.35;cursor:pointer}.tree-3d:hover{opacity:.8}.tree-3d.on{opacity:1;color:var(--primary-color)}.tree-eye{flex:0 0 auto;font-size:.8rem;opacity:.4;cursor:pointer}.tree-eye:hover{opacity:.9}.tree-eye.partial{opacity:.7;color:var(--primary-color)}.tree-row.hidden-class .tree-eye{opacity:1}.tree-row.hidden-class .tree-swatch,.tree-row.hidden-class .tree-name,.tree-row.hidden-class .tree-long,.tree-row.hidden-class .tree-count{opacity:.45}\n"] }]
126
+ }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { nodes: [{
127
+ type: Input
128
+ }], counts: [{
129
+ type: Input
130
+ }], colorOf: [{
131
+ type: Input
132
+ }], picked: [{
133
+ type: Input
134
+ }], marked: [{
135
+ type: Input
136
+ }], volume: [{
137
+ type: Input
138
+ }], shown3d: [{
139
+ type: Input
140
+ }], hidden: [{
141
+ type: Input
142
+ }], pick: [{
143
+ type: Output
144
+ }], recolor: [{
145
+ type: Output
146
+ }], toggle3d: [{
147
+ type: Output
148
+ }], toggleHidden: [{
149
+ type: Output
150
+ }] } });
151
+ /** Scroll the row matching `selector` inside `host` into view, if it is out of it. */
152
+ export function scrollToPicked(host, selector) {
153
+ const row = host.querySelector(selector);
154
+ row?.scrollIntoView?.({ block: 'nearest' });
155
+ }
156
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3MtdHJlZS5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9zcmMvbGliL3JlZ2lvbi1lZGl0b3IvY2xhc3MtdHJlZS9jbGFzcy10cmVlLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvcmVnaW9uLWVkaXRvci9jbGFzcy10cmVlL2NsYXNzLXRyZWUuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLHVCQUF1QixFQUN2QixTQUFTLEVBQ1QsVUFBVSxFQUNWLFlBQVksRUFDWixLQUFLLEVBRUwsTUFBTSxHQUVQLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0MsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3BELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUdoRCxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSxtREFBbUQsQ0FBQztBQUM1RixPQUFPLEVBQTJCLFNBQVMsRUFBRSxjQUFjLEVBQUUsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGNBQWMsQ0FBQzs7Ozs7O0FBWXhHOzs7Ozs7R0FNRztBQVNILE1BQU0sT0FBTyxrQkFBa0I7SUFpQzdCLFlBQTZCLEVBQTJCO1FBQTNCLE9BQUUsR0FBRixFQUFFLENBQXlCO1FBaEN4RCxxQkFBcUI7UUFDWixVQUFLLEdBQStCLEVBQUUsQ0FBQztRQUNoRCw2RUFBNkU7UUFDcEUsV0FBTSxHQUFnQyxJQUFJLEdBQUcsRUFBRSxDQUFDO1FBQ3pELHNGQUFzRjtRQUM3RSxZQUFPLEdBQTZCLEdBQUcsRUFBRSxDQUFDLFNBQVMsQ0FBQztRQUM3RCxrRkFBa0Y7UUFDekUsV0FBTSxHQUFrQixJQUFJLENB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QUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsR0FBRyxLQUFLLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDeEYsQ0FBQztJQUNILENBQUM7OEdBeEdVLGtCQUFrQjtrR0FBbEIsa0JBQWtCLG1XQzVDL0IscTFHQW1GQSw0N0RENUNZLFlBQVksNlZBQUUsV0FBVyw4bUJBQUUsZUFBZSx3SEFBRSxhQUFhLHNYQUFFLHVCQUF1Qjs7MkZBS2pGLGtCQUFrQjtrQkFSOUIsU0FBUzsrQkFDRSxtQkFBbUIsY0FDakIsSUFBSSxXQUNQLENBQUMsWUFBWSxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFFLHVCQUF1QixDQUFDLG1CQUc1RSx1QkFBdUIsQ0FBQyxNQUFNOytFQUl0QyxLQUFLO3NCQUFiLEtBQUs7Z0JBRUcsTUFBTTtzQkFBZCxLQUFLO2dCQUVHLE9BQU87c0JBQWYsS0FBSztnQkFFRyxNQUFNO3NCQUFkLEtBQUs7Z0JBRUcsTUFBTTtzQkFBZCxLQUFLO2dCQUVHLE1BQU07c0JBQWQsS0FBSztnQkFFRyxPQUFPO3NCQUFmLEtBQUs7Z0JBRUcsTUFBTTtzQkFBZCxLQUFLO2dCQUVJLElBQUk7c0JBQWIsTUFBTTtnQkFFRyxPQUFPO3NCQUFoQixNQUFNO2dCQUVHLFFBQVE7c0JBQWpCLE1BQU07Z0JBRUcsWUFBWTtzQkFBckIsTUFBTTs7QUFtRlQsc0ZBQXNGO0FBQ3RGLE1BQU0sVUFBVSxjQUFjLENBQUMsSUFBaUIsRUFBRSxRQUFnQjtJQUNoRSxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBdUIsQ0FBQztJQUMvRCxHQUFHLEVBQUUsY0FBYyxFQUFFLENBQUMsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztBQUM5QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXG4gIENvbXBvbmVudCxcbiAgRWxlbWVudFJlZixcbiAgRXZlbnRFbWl0dGVyLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPdXRwdXQsXG4gIFNpbXBsZUNoYW5nZXMsXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcbmltcG9ydCB7IEZvcm1zTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgSW5wdXRUZXh0TW9kdWxlIH0gZnJvbSAncHJpbWVuZy9pbnB1dHRleHQnO1xuaW1wb3J0IHsgVG9vbHRpcE1vZHVsZSB9IGZyb20gJ3ByaW1lbmcvdG9vbHRpcCc7XG5cbmltcG9ydCB0eXBlIHsgUmVnaW9uQ2xhc3NOb2RlIH0gZnJvbSAnLi4vLi4vcmVnaW9uLXNvdXJjZS9yZWdpb24tdGlsZXMnO1xuaW1wb3J0IHsgSGV4Q29sb3JQaWNrZXJDb21wb25lbnQgfSBmcm9tICcuLi8uLi9oZXgtY29sb3ItcGlja2VyL2hleC1jb2xvci1waWNrZXIuY29tcG9uZW50JztcbmltcG9ydCB7IENsYXNzVHJlZSwgQ2xhc3NUcmVlUm93LCBhbmNlc3RvcnMsIGJ1aWxkQ2xhc3NUcmVlLCBzdWJ0cmVlLCB2aXNpYmxlUm93cyB9IGZyb20gJy4vY2xhc3MtdHJlZSc7XG5cbi8qKiBBIHBpY2sgaW4gdGhlIHRyZWU6IHRoZSBjbGFzcywgYW5kIGl0IHdpdGggZXZlcnkgY2xhc3MgdW5kZXIgaXQuICovXG5leHBvcnQgaW50ZXJmYWNlIENsYXNzVHJlZVBpY2sge1xuICBuYW1lOiBzdHJpbmc7XG4gIGNsYXNzZXM6IHN0cmluZ1tdO1xuICBhZGRpdGl2ZTogYm9vbGVhbjtcbn1cblxuLyoqIFdoZXRoZXIgYSBjbGFzcyBpcyBzaG93bjogaXQgYW5kIGl0cyBzdWJjbGFzc2VzIGFsbCwgbm9uZSAoJ2hpZGRlbicpLCBvciBvbmx5IHNvbWUgKCdwYXJ0aWFsJykuICovXG5leHBvcnQgdHlwZSBDbGFzc1Zpc2liaWxpdHkgPSAnc2hvd24nIHwgJ2hpZGRlbicgfCAncGFydGlhbCc7XG5cbi8qKlxuICogVGhlIFJlZ2lvbiBFZGl0b3IncyBjbGFzc2VzIGFzIGEgaGllcmFyY2h5IChhIGJyYWluIGF0bGFzJ3Mgb250b2xvZ3kpLCBhcyB0aGUgQWxsZW4gYXRsYXMgdmlld2VyXG4gKiBzaG93cyBpdDogY29sbGFwc2libGUsIGVhY2ggY2xhc3Mgd2l0aCBpdHMgY29sb3VyLCBuYW1lIGFuZCBsb25nIG5hbWUsIGFuZCB0aGUgcmVnaW9ucyBpdCBhbmRcbiAqIGl0cyBzdWJjbGFzc2VzIGhhdmUgb24gdGhpcyBzbGljZTsgYSBjbGFzcyB3aXRoIG5vbmUgaXMgZ3JleWVkLiBQaWNraW5nIGEgY2xhc3Mgc2VsZWN0cyBhbGwgaXRzXG4gKiByZWdpb25zIGFuZCBpdHMgc3ViY2xhc3NlcycgKHRoZSBlZGl0b3IgZG9lcyB0aGUgc2VsZWN0aW5nKS4gU2VhcmNoIGJ5IG5hbWUgb3IgbG9uZyBuYW1lLiBBXG4gKiBjbGFzcydzIHN3YXRjaCByZWNvbG91cnMgaXQsIGFzIHRoZSBjbGFzcyBsaXN0J3MgZG9lczsgaXRzIGV5ZSBoaWRlcyBpdCBhbmQgaXRzIHN1YmNsYXNzZXMuXG4gKi9cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ3JlZ2lvbi1jbGFzcy10cmVlJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgRm9ybXNNb2R1bGUsIElucHV0VGV4dE1vZHVsZSwgVG9vbHRpcE1vZHVsZSwgSGV4Q29sb3JQaWNrZXJDb21wb25lbnRdLFxuICB0ZW1wbGF0ZVVybDogJy4vY2xhc3MtdHJlZS5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL2NsYXNzLXRyZWUuY29tcG9uZW50LnNjc3MnXSxcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXG59KVxuZXhwb3J0IGNsYXNzIENsYXNzVHJlZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcyB7XG4gIC8qKiBUaGUgaGllcmFyY2h5LiAqL1xuICBASW5wdXQoKSBub2RlczogcmVhZG9ubHkgUmVnaW9uQ2xhc3NOb2RlW10gPSBbXTtcbiAgLyoqIFJlZ2lvbnMgcGVyIGNsYXNzIG9uIHRoaXMgc2xpY2UgKHRoZSByZWdpb25zIGFuZCB0aGUgcmVnaW9uIHNvdXJjZSdzKS4gKi9cbiAgQElucHV0KCkgY291bnRzOiBSZWFkb25seU1hcDxzdHJpbmcsIG51bWJlcj4gPSBuZXcgTWFwKCk7XG4gIC8qKiBBIGNsYXNzJ3MgY29sb3VyIChhIG5ldyBmdW5jdGlvbiB3aGVuIHRoZSBjb2xvdXJzIGNoYW5nZSwgc28gdGhlIHJvd3MgcmVwYWludCkuICovXG4gIEBJbnB1dCgpIGNvbG9yT2Y6IChuYW1lOiBzdHJpbmcpID0+IHN0cmluZyA9ICgpID0+ICcjOTk5OTk5JztcbiAgLyoqIFRoZSBjbGFzcyBwaWNrZWQgbGFzdCAoaGlnaGxpZ2h0ZWQsIGl0cyBwYXRoIGV4cGFuZGVkLCBzY3JvbGxlZCBpbnRvIHZpZXcpLiAqL1xuICBASW5wdXQoKSBwaWNrZWQ6IHN0cmluZyB8IG51bGwgPSBudWxsO1xuICAvKiogQ2xhc3NlcyB3aXRoIGEgc2VsZWN0ZWQgcmVnaW9uIChtYXJrZWQpLiAqL1xuICBASW5wdXQoKSBtYXJrZWQ6IFJlYWRvbmx5U2V0PHN0cmluZz4gPSBuZXcgU2V0KCk7XG4gIC8qKiBXaGV0aGVyIGEgdm9sdW1lIHZpZXcgaXMgb24gc2NyZWVuOiBlYWNoIGNsYXNzIGNhbiB0aGVuIGJlIHNob3duIGluIDNELiAqL1xuICBASW5wdXQoKSB2b2x1bWUgPSBmYWxzZTtcbiAgLyoqIFRoZSBjbGFzc2VzIHNob3duIGluIDNELiAqL1xuICBASW5wdXQoKSBzaG93bjNkOiBSZWFkb25seVNldDxzdHJpbmc+ID0gbmV3IFNldCgpO1xuICAvKiogVGhlIGNsYXNzZXMgaGlkZGVuIGZyb20gdmlldy4gKi9cbiAgQElucHV0KCkgaGlkZGVuOiBSZWFkb25seVNldDxzdHJpbmc+ID0gbmV3IFNldCgpO1xuXG4gIEBPdXRwdXQoKSBwaWNrID0gbmV3IEV2ZW50RW1pdHRlcjxDbGFzc1RyZWVQaWNrPigpO1xuICAvKiogQSBjbGFzcydzIHN3YXRjaCBwaWNrZWQgYSBuZXcgY29sb3VyLiAqL1xuICBAT3V0cHV0KCkgcmVjb2xvciA9IG5ldyBFdmVudEVtaXR0ZXI8eyBuYW1lOiBzdHJpbmc7IGNvbG9yOiBzdHJpbmcgfT4oKTtcbiAgLyoqIEEgY2xhc3MncyAzRCB0b2dnbGU6IGl0IHdpdGggZXZlcnkgY2xhc3MgdW5kZXIgaXQuICovXG4gIEBPdXRwdXQoKSB0b2dnbGUzZCA9IG5ldyBFdmVudEVtaXR0ZXI8eyBuYW1lOiBzdHJpbmc7IGNsYXNzZXM6IHN0cmluZ1tdIH0+KCk7XG4gIC8qKiBBIGNsYXNzJ3MgZXllOiBoaWRlIChvciBzaG93KSBpdCB3aXRoIGV2ZXJ5IGNsYXNzIHVuZGVyIGl0LiAqL1xuICBAT3V0cHV0KCkgdG9nZ2xlSGlkZGVuID0gbmV3IEV2ZW50RW1pdHRlcjx7IGNsYXNzZXM6IHN0cmluZ1tdOyBoaWRkZW46IGJvb2xlYW4gfT4oKTtcblxuICBwcm90ZWN0ZWQgdHJlZTogQ2xhc3NUcmVlID0gYnVpbGRDbGFzc1RyZWUoW10sIG5ldyBNYXAoKSk7XG4gIHByb3RlY3RlZCByb3dzOiBDbGFzc1RyZWVSb3dbXSA9IFtdO1xuICAvKiogRWFjaCByb3cncyB2aXNpYmlsaXR5IChhIHJvdyBhYnNlbnQ6IHNob3duKS4gKi9cbiAgcHJvdGVjdGVkIHZpc2liaWxpdHkgPSBuZXcgTWFwPHN0cmluZywgQ2xhc3NWaXNpYmlsaXR5PigpO1xuICBwcm90ZWN0ZWQgcXVlcnkgPSAnJztcbiAgcHJpdmF0ZSBleHBhbmRlZCA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgcmVhZG9ubHkgZWw6IEVsZW1lbnRSZWY8SFRNTEVsZW1lbnQ+KSB7fVxuXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcbiAgICBjb25zdCBmcmVzaCA9ICEhY2hhbmdlc1snbm9kZXMnXTtcbiAgICBpZiAoZnJlc2ggfHwgY2hhbmdlc1snY291bnRzJ10pIHRoaXMudHJlZSA9IGJ1aWxkQ2xhc3NUcmVlKHRoaXMubm9kZXMsIHRoaXMuY291bnRzKTtcbiAgICAvLyBBIG5ldyBoaWVyYXJjaHkgb3BlbnMgd2l0aCBpdHMgcm9vdHMgZXhwYW5kZWQsIGFzIHRoZSBhdGxhcyB2aWV3ZXIgZG9lcy5cbiAgICBpZiAoZnJlc2gpIHRoaXMuZXhwYW5kZWQgPSBuZXcgU2V0KHRoaXMudHJlZS5yb290cyk7XG4gICAgaWYgKGNoYW5nZXNbJ3BpY2tlZCddICYmIHRoaXMucGlja2VkKSBmb3IgKGNvbnN0IGEgb2YgYW5jZXN0b3JzKHRoaXMudHJlZSwgdGhpcy5waWNrZWQpKSB0aGlzLmV4cGFuZGVkLmFkZChhKTtcbiAgICB0aGlzLnJlZnJlc2goKTtcbiAgICAvLyBBIHBpY2sgZnJvbSBlbHNld2hlcmUgKGEgc3VyZmFjZSBjbGlja2VkIGluIDNEKSBtYXkgYmUgb2ZmIHNjcmVlbjogYnJpbmcgaXRzIHJvdyBpbnRvIHZpZXcuXG4gICAgaWYgKGNoYW5nZXNbJ3BpY2tlZCddICYmIHRoaXMucGlja2VkKVxuICAgICAgc2V0VGltZW91dCgoKSA9PiBzY3JvbGxUb1BpY2tlZCh0aGlzLmVsLm5hdGl2ZUVsZW1lbnQsICcudHJlZS1yb3cucGlja2VkJykpO1xuICB9XG5cbiAgcHJvdGVjdGVkIG5vZGUobmFtZTogc3RyaW5nKTogUmVnaW9uQ2xhc3NOb2RlIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy50cmVlLm5vZGUuZ2V0KG5hbWUpO1xuICB9XG5cbiAgcHJvdGVjdGVkIHRvdGFsKG5hbWU6IHN0cmluZyk6IG51bWJlciB7XG4gICAgcmV0dXJuIHRoaXMudHJlZS50b3RhbC5nZXQobmFtZSkgPz8gMDtcbiAgfVxuXG4gIHByb3RlY3RlZCB0b2dnbGUocm93OiBDbGFzc1RyZWVSb3csIGV2ZW50OiBFdmVudCk6IHZvaWQge1xuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIGlmICh0aGlzLmV4cGFuZGVkLmhhcyhyb3cubmFtZSkpIHRoaXMuZXhwYW5kZWQuZGVsZXRlKHJvdy5uYW1lKTtcbiAgICBlbHNlIHRoaXMuZXhwYW5kZWQuYWRkKHJvdy5uYW1lKTtcbiAgICB0aGlzLnJlZnJlc2goKTtcbiAgfVxuXG4gIHByb3RlY3RlZCBjaG9vc2UobmFtZTogc3RyaW5nLCBldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBlID0gZXZlbnQgYXMgTW91c2VFdmVudCB8IEtleWJvYXJkRXZlbnQ7XG4gICAgdGhpcy5waWNrLmVtaXQoeyBuYW1lLCBjbGFzc2VzOiBzdWJ0cmVlKHRoaXMudHJlZSwgbmFtZSksIGFkZGl0aXZlOiBlLnNoaWZ0S2V5IHx8IGUubWV0YUtleSB8fCBlLmN0cmxLZXkgfSk7XG4gIH1cblxuICAvKiogVGhlIGV5ZTogYSBjbGFzcyBoaWRkZW4gKHdob2xseSkgaXMgc2hvd24gYWdhaW4gd2l0aCBpdHMgc3ViY2xhc3Nlczsgb3RoZXJ3aXNlIHRoZXkgYXJlIGhpZGRlbi4gKi9cbiAgcHJvdGVjdGVkIGZsaXBIaWRkZW4obmFtZTogc3RyaW5nLCBldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICBjb25zdCBoaWRkZW4gPSB0aGlzLnZpc2liaWxpdHkuZ2V0KG5hbWUpICE9PSAnaGlkZGVuJztcbiAgICB0aGlzLnRvZ2dsZUhpZGRlbi5lbWl0KHsgY2xhc3Nlczogc3VidHJlZSh0aGlzLnRyZWUsIG5hbWUpLCBoaWRkZW4gfSk7XG4gIH1cblxuICBwcm90ZWN0ZWQgZmxpcDNkKG5hbWU6IHN0cmluZywgZXZlbnQ6IEV2ZW50KTogdm9pZCB7XG4gICAgZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgdGhpcy50b2dnbGUzZC5lbWl0KHsgbmFtZSwgY2xhc3Nlczogc3VidHJlZSh0aGlzLnRyZWUsIG5hbWUpIH0pO1xuICB9XG5cbiAgcHJvdGVjdGVkIG9uUXVlcnkodmFsdWU6IHN0cmluZyk6IHZvaWQge1xuICAgIHRoaXMucXVlcnkgPSB2YWx1ZTtcbiAgICB0aGlzLnJlZnJlc2goKTtcbiAgfVxuXG4gIC8qKiBFbnRlciBpbiB0aGUgc2VhcmNoIGJveCBwaWNrcyB0aGUgZmlyc3QgbWF0Y2guICovXG4gIHByb3RlY3RlZCBwaWNrRmlyc3RNYXRjaChldmVudDogRXZlbnQpOiB2b2lkIHtcbiAgICBjb25zdCBxID0gdGhpcy5xdWVyeS50cmltKCkudG9Mb3dlckNhc2UoKTtcbiAgICBjb25zdCBoaXQgPSB0aGlzLnJvd3MuZmluZChcbiAgICAgIChyKSA9PiByLm5hbWUudG9Mb3dlckNhc2UoKS5pbmNsdWRlcyhxKSB8fCAodGhpcy5ub2RlKHIubmFtZSk/LnRpdGxlID8/ICcnKS50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHEpLFxuICAgICk7XG4gICAgaWYgKGhpdCkgdGhpcy5jaG9vc2UoaGl0Lm5hbWUsIGV2ZW50KTtcbiAgfVxuXG4gIHByb3RlY3RlZCByZWFkb25seSB0cmFja1JvdyA9IChfOiBudW1iZXIsIHI6IENsYXNzVHJlZVJvdykgPT4gci5uYW1lO1xuXG4gIHByaXZhdGUgcmVmcmVzaCgpOiB2b2lkIHtcbiAgICB0aGlzLnJvd3MgPSB2aXNpYmxlUm93cyh0aGlzLnRyZWUsIHRoaXMuZXhwYW5kZWQsIHRoaXMucXVlcnkpO1xuICAgIHRoaXMudmlzaWJpbGl0eSA9IG5ldyBNYXAoKTtcbiAgICBpZiAoIXRoaXMuaGlkZGVuLnNpemUpIHJldHVybjtcbiAgICBmb3IgKGNvbnN0IHJvdyBvZiB0aGlzLnJvd3MpIHtcbiAgICAgIGNvbnN0IGNsYXNzZXMgPSBzdWJ0cmVlKHRoaXMudHJlZSwgcm93Lm5hbWUpO1xuICAgICAgY29uc3Qgb2ZmID0gY2xhc3Nlcy5maWx0ZXIoKGMpID0+IHRoaXMuaGlkZGVuLmhhcyhjKSkubGVuZ3RoO1xuICAgICAgaWYgKG9mZikgdGhpcy52aXNpYmlsaXR5LnNldChyb3cubmFtZSwgb2ZmID09PSBjbGFzc2VzLmxlbmd0aCA/ICdoaWRkZW4nIDogJ3BhcnRpYWwnKTtcbiAgICB9XG4gIH1cbn1cblxuLyoqIFNjcm9sbCB0aGUgcm93IG1hdGNoaW5nIGBzZWxlY3RvcmAgaW5zaWRlIGBob3N0YCBpbnRvIHZpZXcsIGlmIGl0IGlzIG91dCBvZiBpdC4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzY3JvbGxUb1BpY2tlZChob3N0OiBIVE1MRWxlbWVudCwgc2VsZWN0b3I6IHN0cmluZyk6IHZvaWQge1xuICBjb25zdCByb3cgPSBob3N0LnF1ZXJ5U2VsZWN0b3Ioc2VsZWN0b3IpIGFzIEhUTUxFbGVtZW50IHwgbnVsbDtcbiAgcm93Py5zY3JvbGxJbnRvVmlldz8uKHsgYmxvY2s6ICduZWFyZXN0JyB9KTtcbn1cbiIsIjxkaXYgY2xhc3M9XCJjbGFzcy10cmVlXCI+XG4gIDxkaXYgY2xhc3M9XCJ0cmVlLWhlYWRlclwiICpuZ0lmPVwicGlja2VkIGFzIHBcIj5cbiAgICA8c3BhbiBjbGFzcz1cInRyZWUtcGlja2VkXCI+XG4gICAgICA8Yj57eyBwIH19PC9iXG4gICAgICA+PHNwYW4gKm5nSWY9XCJub2RlKHApPy50aXRsZSBhcyB0XCI+IMK3IHt7IHQgfX08L3NwYW4+XG4gICAgPC9zcGFuPlxuICA8L2Rpdj5cbiAgPGlucHV0XG4gICAgdHlwZT1cInRleHRcIlxuICAgIHBJbnB1dFRleHRcbiAgICBjbGFzcz1cInAtaW5wdXR0ZXh0LXNtIHRyZWUtc2VhcmNoXCJcbiAgICBwbGFjZWhvbGRlcj1cIlNlYXJjaCBieSBuYW1lXCJcbiAgICBhcmlhLWxhYmVsPVwiU2VhcmNoIHRoZSBjbGFzc2VzXCJcbiAgICBbbmdNb2RlbF09XCJxdWVyeVwiXG4gICAgKG5nTW9kZWxDaGFuZ2UpPVwib25RdWVyeSgkZXZlbnQpXCJcbiAgICAoa2V5ZG93bi5lbnRlcik9XCJwaWNrRmlyc3RNYXRjaCgkZXZlbnQpXCJcbiAgLz5cbiAgPGRpdiBjbGFzcz1cInRyZWUtYm9keVwiIHJvbGU9XCJ0cmVlXCI+XG4gICAgPGRpdlxuICAgICAgKm5nRm9yPVwibGV0IHJvdyBvZiByb3dzOyB0cmFja0J5OiB0cmFja1Jvd1wiXG4gICAgICBjbGFzcz1cInRyZWUtcm93XCJcbiAgICAgIHJvbGU9XCJ0cmVlaXRlbVwiXG4gICAgICB0YWJpbmRleD1cIjBcIlxuICAgICAgW2F0dHIuYXJpYS1leHBhbmRlZF09XCJyb3cuaGFzQ2hpbGRyZW4gPyByb3cuZXhwYW5kZWQgOiBudWxsXCJcbiAgICAgIFtjbGFzcy5hYnNlbnRdPVwidG90YWwocm93Lm5hbWUpID09PSAwXCJcbiAgICAgIFtjbGFzcy5waWNrZWRdPVwicm93Lm5hbWUgPT09IHBpY2tlZFwiXG4gICAgICBbY2xhc3MubWFya2VkXT1cIm1hcmtlZC5oYXMocm93Lm5hbWUpXCJcbiAgICAgIFtjbGFzcy5oaWRkZW4tY2xhc3NdPVwidmlzaWJpbGl0eS5nZXQocm93Lm5hbWUpID09PSAnaGlkZGVuJ1wiXG4gICAgICBbc3R5bGUucGFkZGluZy1sZWZ0LnJlbV09XCIwLjM1ICsgcm93LmRlcHRoICogMC45XCJcbiAgICAgIFtwVG9vbHRpcF09XCJub2RlKHJvdy5uYW1lKT8udGl0bGUgfHwgcm93Lm5hbWVcIlxuICAgICAgdG9vbHRpcFBvc2l0aW9uPVwibGVmdFwiXG4gICAgICBbc2hvd0RlbGF5XT1cIjYwMFwiXG4gICAgICAoY2xpY2spPVwiY2hvb3NlKHJvdy5uYW1lLCAkZXZlbnQpXCJcbiAgICAgIChrZXlkb3duLmVudGVyKT1cImNob29zZShyb3cubmFtZSwgJGV2ZW50KVwiXG4gICAgPlxuICAgICAgPGlcbiAgICAgICAgY2xhc3M9XCJwaSB0cmVlLXRvZ2dsZVwiXG4gICAgICAgIFtjbGFzcy5waS1taW51cy1jaXJjbGVdPVwicm93Lmhhc0NoaWxkcmVuICYmIHJvdy5leHBhbmRlZFwiXG4gICAgICAgIFtjbGFzcy5waS1wbHVzLWNpcmNsZV09XCJyb3cuaGFzQ2hpbGRyZW4gJiYgIXJvdy5leHBhbmRlZFwiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwicm93LmV4cGFuZGVkID8gJ0NvbGxhcHNlJyA6ICdFeHBhbmQnXCJcbiAgICAgICAgKGNsaWNrKT1cInJvdy5oYXNDaGlsZHJlbiAmJiB0b2dnbGUocm93LCAkZXZlbnQpXCJcbiAgICAgID48L2k+XG4gICAgICA8aVxuICAgICAgICBjbGFzcz1cInBpIHRyZWUtZXllXCJcbiAgICAgICAgW25nQ2xhc3NdPVwidmlzaWJpbGl0eS5nZXQocm93Lm5hbWUpID09PSAnaGlkZGVuJyA/ICdwaS1leWUtc2xhc2gnIDogJ3BpLWV5ZSdcIlxuICAgICAgICBbY2xhc3MucGFydGlhbF09XCJ2aXNpYmlsaXR5LmdldChyb3cubmFtZSkgPT09ICdwYXJ0aWFsJ1wiXG4gICAgICAgIHJvbGU9XCJidXR0b25cIlxuICAgICAgICBbYXR0ci5hcmlhLXByZXNzZWRdPVwidmlzaWJpbGl0eS5nZXQocm93Lm5hbWUpICE9PSAnaGlkZGVuJ1wiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiKHZpc2liaWxpdHkuZ2V0KHJvdy5uYW1lKSA9PT0gJ2hpZGRlbicgPyAnU2hvdyAnIDogJ0hpZGUgJykgKyByb3cubmFtZVwiXG4gICAgICAgIFtwVG9vbHRpcF09XCJcbiAgICAgICAgICAodmlzaWJpbGl0eS5nZXQocm93Lm5hbWUpID09PSAnaGlkZGVuJyA/ICdTaG93JyA6ICdIaWRlJykgK1xuICAgICAgICAgIChyb3cuaGFzQ2hpbGRyZW4gPyAnIGl0IGFuZCBpdHMgc3ViY2xhc3NlcycgOiAnJykgK1xuICAgICAgICAgICh2aXNpYmlsaXR5LmdldChyb3cubmFtZSkgPT09ICdwYXJ0aWFsJyA/ICcgKHNvbWUgYXJlIGhpZGRlbiknIDogJycpXG4gICAgICAgIFwiXG4gICAgICAgIHRvb2x0aXBQb3NpdGlvbj1cImxlZnRcIlxuICAgICAgICAoY2xpY2spPVwiZmxpcEhpZGRlbihyb3cubmFtZSwgJGV2ZW50KVwiXG4gICAgICAgIChrZXlkb3duLmVudGVyKT1cImZsaXBIaWRkZW4ocm93Lm5hbWUsICRldmVudClcIlxuICAgICAgPjwvaT5cbiAgICAgIDxzcGFuIGNsYXNzPVwidHJlZS1zd2F0Y2hcIiAoY2xpY2spPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCIgKGtleWRvd24uZW50ZXIpPVwiJGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpXCI+XG4gICAgICAgIDxoZXgtY29sb3ItcGlja2VyXG4gICAgICAgICAgW2NvbG9yXT1cImNvbG9yT2Yocm93Lm5hbWUpXCJcbiAgICAgICAgICAoY29sb3JDaGFuZ2UpPVwicmVjb2xvci5lbWl0KHsgbmFtZTogcm93Lm5hbWUsIGNvbG9yOiAkZXZlbnQgfSlcIlxuICAgICAgICA+XG4gICAgICAgIDwvaGV4LWNvbG9yLXBpY2tlcj5cbiAgICAgIDwvc3Bhbj5cbiAgICAgIDxzcGFuIGNsYXNzPVwidHJlZS1uYW1lXCI+e3sgcm93Lm5hbWUgfX08L3NwYW4+XG4gICAgICA8c3BhbiBjbGFzcz1cInRyZWUtbG9uZ1wiPnt7IG5vZGUocm93Lm5hbWUpPy50aXRsZSB9fTwvc3Bhbj5cbiAgICAgIDxzcGFuIGNsYXNzPVwidHJlZS1jb3VudFwiICpuZ0lmPVwidG90YWwocm93Lm5hbWUpID4gMFwiPnt7IHRvdGFsKHJvdy5uYW1lKSB9fTwvc3Bhbj5cbiAgICAgIDxpXG4gICAgICAgICpuZ0lmPVwidm9sdW1lXCJcbiAgICAgICAgY2xhc3M9XCJwaSBwaS1ib3ggdHJlZS0zZFwiXG4gICAgICAgIFtjbGFzcy5vbl09XCJzaG93bjNkLmhhcyhyb3cubmFtZSlcIlxuICAgICAgICByb2xlPVwiYnV0dG9uXCJcbiAgICAgICAgW2F0dHIuYXJpYS1wcmVzc2VkXT1cInNob3duM2QuaGFzKHJvdy5uYW1lKVwiXG4gICAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ1Nob3cgJyArIHJvdy5uYW1lICsgJyBpbiAzRCdcIlxuICAgICAgICBwVG9vbHRpcD1cIlNob3cgaW4gdGhlIHZvbHVtZSwgaW4gM0RcIlxuICAgICAgICB0b29sdGlwUG9zaXRpb249XCJsZWZ0XCJcbiAgICAgICAgKGNsaWNrKT1cImZsaXAzZChyb3cubmFtZSwgJGV2ZW50KVwiXG4gICAgICA+PC9pPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgKm5nSWY9XCIhcm93cy5sZW5ndGhcIiBjbGFzcz1cInRyZWUtZW1wdHlcIj5ObyBjbGFzcyBtYXRjaGVzLjwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Build the tree of `nodes`, counting `counts` (regions per class) up through it. A node whose
3
+ * parent is not in the hierarchy is a root; siblings sort by `order`, then as listed.
4
+ */
5
+ export function buildClassTree(nodes, counts) {
6
+ const node = new Map();
7
+ for (const n of nodes)
8
+ if (!node.has(n.name))
9
+ node.set(n.name, n);
10
+ const children = new Map();
11
+ const parent = new Map();
12
+ const roots = [];
13
+ const position = new Map(nodes.map((n, i) => [n.name, i]));
14
+ for (const n of node.values()) {
15
+ const p = n.parent && node.has(n.parent) && n.parent !== n.name ? n.parent : null;
16
+ parent.set(n.name, p);
17
+ if (p) {
18
+ const list = children.get(p);
19
+ if (list)
20
+ list.push(n.name);
21
+ else
22
+ children.set(p, [n.name]);
23
+ }
24
+ else
25
+ roots.push(n.name);
26
+ }
27
+ const byOrder = (a, b) => (node.get(a)?.order ?? Infinity) - (node.get(b)?.order ?? Infinity) ||
28
+ (position.get(a) ?? 0) - (position.get(b) ?? 0);
29
+ roots.sort(byOrder);
30
+ for (const list of children.values())
31
+ list.sort(byOrder);
32
+ const total = new Map();
33
+ const visit = (name, seen) => {
34
+ const known = total.get(name);
35
+ if (known !== undefined)
36
+ return known;
37
+ if (seen.has(name))
38
+ return 0; // a cycle in a malformed file
39
+ seen.add(name);
40
+ let sum = counts.get(name) ?? 0;
41
+ for (const c of children.get(name) ?? [])
42
+ sum += visit(c, seen);
43
+ total.set(name, sum);
44
+ return sum;
45
+ };
46
+ for (const name of node.keys())
47
+ visit(name, new Set());
48
+ return { roots, node, children, parent, total };
49
+ }
50
+ /** `name` and every class under it. */
51
+ export function subtree(tree, name) {
52
+ const out = [];
53
+ const stack = [name];
54
+ const seen = new Set();
55
+ while (stack.length) {
56
+ const n = stack.pop();
57
+ if (seen.has(n))
58
+ continue;
59
+ seen.add(n);
60
+ out.push(n);
61
+ for (const c of tree.children.get(n) ?? [])
62
+ stack.push(c);
63
+ }
64
+ return out;
65
+ }
66
+ /** The classes from the root down to `name`'s parent. */
67
+ export function ancestors(tree, name) {
68
+ const out = [];
69
+ let p = tree.parent.get(name) ?? null;
70
+ while (p && !out.includes(p)) {
71
+ out.unshift(p);
72
+ p = tree.parent.get(p) ?? null;
73
+ }
74
+ return out;
75
+ }
76
+ /**
77
+ * The rows to draw: depth-first through the expanded nodes. With a `query`, only the nodes whose
78
+ * name or title contains it and their ancestors, all expanded.
79
+ */
80
+ export function visibleRows(tree, expanded, query = '') {
81
+ const q = query.trim().toLowerCase();
82
+ let keep = null;
83
+ if (q) {
84
+ keep = new Set();
85
+ for (const [name, n] of tree.node) {
86
+ if (name.toLowerCase().includes(q) || (n.title ?? '').toLowerCase().includes(q)) {
87
+ keep.add(name);
88
+ for (const a of ancestors(tree, name))
89
+ keep.add(a);
90
+ }
91
+ }
92
+ }
93
+ const rows = [];
94
+ const walk = (name, depth) => {
95
+ if (keep && !keep.has(name))
96
+ return;
97
+ const kids = tree.children.get(name) ?? [];
98
+ const open = keep ? true : expanded.has(name);
99
+ rows.push({ name, depth, hasChildren: kids.length > 0, expanded: open && kids.length > 0 });
100
+ if (open)
101
+ for (const c of kids)
102
+ walk(c, depth + 1);
103
+ };
104
+ for (const r of tree.roots)
105
+ walk(r, 0);
106
+ return rows;
107
+ }
108
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3MtdHJlZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3NyYy9saWIvcmVnaW9uLWVkaXRvci9jbGFzcy10cmVlL2NsYXNzLXRyZWUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBWUE7OztHQUdHO0FBQ0gsTUFBTSxVQUFVLGNBQWMsQ0FBQyxLQUFpQyxFQUFFLE1BQW1DO0lBQ25HLE1BQU0sSUFBSSxHQUFHLElBQUksR0FBRyxFQUEyQixDQUFDO0lBQ2hELEtBQUssTUFBTSxDQUFDLElBQUksS0FBSztRQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUM7WUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDbEUsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQW9CLENBQUM7SUFDN0MsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQXlCLENBQUM7SUFDaEQsTUFBTSxLQUFLLEdBQWEsRUFBRSxDQUFDO0lBQzNCLE1BQU0sUUFBUSxHQUFHLElBQUksR0FBRyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNELEtBQUssTUFBTSxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7UUFDOUIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztRQUNsRixNQUFNLENBQUMsR0FB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LENBQUMsQ0FBQztJQUNyRCxDQUFDLENBQUM7SUFDRixLQUFLLE1BQU0sQ0FBQyxJQUFJLElBQUksQ0FBQyxLQUFLO1FBQUUsSUFBSSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN2QyxPQUFPLElBQUksQ0FBQztBQUNkLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgdHlwZSB7IFJlZ2lvbkNsYXNzTm9kZSB9IGZyb20gJy4uLy4uL3JlZ2lvbi1zb3VyY2UvcmVnaW9uLXRpbGVzJztcblxuLyoqIEEgY2xhc3MgaGllcmFyY2h5IGFzIGEgdHJlZTogY2hpbGRyZW4gaW4gb3JkZXIsIHN1YnRyZWUgY291bnRzLCBkZXB0aHMuIFB1cmUuICovXG5leHBvcnQgaW50ZXJmYWNlIENsYXNzVHJlZSB7XG4gIHJvb3RzOiBzdHJpbmdbXTtcbiAgbm9kZTogTWFwPHN0cmluZywgUmVnaW9uQ2xhc3NOb2RlPjtcbiAgY2hpbGRyZW46IE1hcDxzdHJpbmcsIHN0cmluZ1tdPjtcbiAgcGFyZW50OiBNYXA8c3RyaW5nLCBzdHJpbmcgfCBudWxsPjtcbiAgLyoqIFJlZ2lvbnMgb2YgdGhlIGNsYXNzIGFuZCBldmVyeSBjbGFzcyB1bmRlciBpdC4gKi9cbiAgdG90YWw6IE1hcDxzdHJpbmcsIG51bWJlcj47XG59XG5cbi8qKlxuICogQnVpbGQgdGhlIHRyZWUgb2YgYG5vZGVzYCwgY291bnRpbmcgYGNvdW50c2AgKHJlZ2lvbnMgcGVyIGNsYXNzKSB1cCB0aHJvdWdoIGl0LiBBIG5vZGUgd2hvc2VcbiAqIHBhcmVudCBpcyBub3QgaW4gdGhlIGhpZXJhcmNoeSBpcyBhIHJvb3Q7IHNpYmxpbmdzIHNvcnQgYnkgYG9yZGVyYCwgdGhlbiBhcyBsaXN0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBidWlsZENsYXNzVHJlZShub2RlczogcmVhZG9ubHkgUmVnaW9uQ2xhc3NOb2RlW10sIGNvdW50czogUmVhZG9ubHlNYXA8c3RyaW5nLCBudW1iZXI+KTogQ2xhc3NUcmVlIHtcbiAgY29uc3Qgbm9kZSA9IG5ldyBNYXA8c3RyaW5nLCBSZWdpb25DbGFzc05vZGU+KCk7XG4gIGZvciAoY29uc3QgbiBvZiBub2RlcykgaWYgKCFub2RlLmhhcyhuLm5hbWUpKSBub2RlLnNldChuLm5hbWUsIG4pO1xuICBjb25zdCBjaGlsZHJlbiA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmdbXT4oKTtcbiAgY29uc3QgcGFyZW50ID0gbmV3IE1hcDxzdHJpbmcsIHN0cmluZyB8IG51bGw+KCk7XG4gIGNvbnN0IHJvb3RzOiBzdHJpbmdbXSA9IFtdO1xuICBjb25zdCBwb3NpdGlvbiA9IG5ldyBNYXAobm9kZXMubWFwKChuLCBpKSA9PiBbbi5uYW1lLCBpXSkpO1xuICBmb3IgKGNvbnN0IG4gb2Ygbm9kZS52YWx1ZXMoKSkge1xuICAgIGNvbnN0IHAgPSBuLnBhcmVudCAmJiBub2RlLmhhcyhuLnBhcmVudCkgJiYgbi5wYXJlbnQgIT09IG4ubmFtZSA/IG4ucGFyZW50IDogbnVsbDtcbiAgICBwYXJlbnQuc2V0KG4ubmFtZSwgcCk7XG4gICAgaWYgKHApIHtcbiAgICAgIGNvbnN0IGxpc3QgPSBjaGlsZHJlbi5nZXQocCk7XG4gICAgICBpZiAobGlzdCkgbGlzdC5wdXNoKG4ubmFtZSk7XG4gICAgICBlbHNlIGNoaWxkcmVuLnNldChwLCBbbi5uYW1lXSk7XG4gICAgfSBlbHNlIHJvb3RzLnB1c2gobi5uYW1lKTtcbiAgfVxuICBjb25zdCBieU9yZGVyID0gKGE6IHN0cmluZywgYjogc3RyaW5nKSA9PlxuICAgIChub2RlLmdldChhKT8ub3JkZXIgPz8gSW5maW5pdHkpIC0gKG5vZGUuZ2V0KGIpPy5vcmRlciA/PyBJbmZpbml0eSkgfHxcbiAgICAocG9zaXRpb24uZ2V0KGEpID8/IDApIC0gKHBvc2l0aW9uLmdldChiKSA/PyAwKTtcbiAgcm9vdHMuc29ydChieU9yZGVyKTtcbiAgZm9yIChjb25zdCBsaXN0IG9mIGNoaWxkcmVuLnZhbHVlcygpKSBsaXN0LnNvcnQoYnlPcmRlcik7XG5cbiAgY29uc3QgdG90YWwgPSBuZXcgTWFwPHN0cmluZywgbnVtYmVyPigpO1xuICBjb25zdCB2aXNpdCA9IChuYW1lOiBzdHJpbmcsIHNlZW46IFNldDxzdHJpbmc+KTogbnVtYmVyID0+IHtcbiAgICBjb25zdCBrbm93biA9IHRvdGFsLmdldChuYW1lKTtcbiAgICBpZiAoa25vd24gIT09IHVuZGVmaW5lZCkgcmV0dXJuIGtub3duO1xuICAgIGlmIChzZWVuLmhhcyhuYW1lKSkgcmV0dXJuIDA7IC8vIGEgY3ljbGUgaW4gYSBtYWxmb3JtZWQgZmlsZVxuICAgIHNlZW4uYWRkKG5hbWUpO1xuICAgIGxldCBzdW0gPSBjb3VudHMuZ2V0KG5hbWUpID8/IDA7XG4gICAgZm9yIChjb25zdCBjIG9mIGNoaWxkcmVuLmdldChuYW1lKSA/PyBbXSkgc3VtICs9IHZpc2l0KGMsIHNlZW4pO1xuICAgIHRvdGFsLnNldChuYW1lLCBzdW0pO1xuICAgIHJldHVybiBzdW07XG4gIH07XG4gIGZvciAoY29uc3QgbmFtZSBvZiBub2RlLmtleXMoKSkgdmlzaXQobmFtZSwgbmV3IFNldCgpKTtcbiAgcmV0dXJuIHsgcm9vdHMsIG5vZGUsIGNoaWxkcmVuLCBwYXJlbnQsIHRvdGFsIH07XG59XG5cbi8qKiBgbmFtZWAgYW5kIGV2ZXJ5IGNsYXNzIHVuZGVyIGl0LiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHN1YnRyZWUodHJlZTogQ2xhc3NUcmVlLCBuYW1lOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gIGNvbnN0IG91dDogc3RyaW5nW10gPSBbXTtcbiAgY29uc3Qgc3RhY2sgPSBbbmFtZV07XG4gIGNvbnN0IHNlZW4gPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgd2hpbGUgKHN0YWNrLmxlbmd0aCkge1xuICAgIGNvbnN0IG4gPSBzdGFjay5wb3AoKSBhcyBzdHJpbmc7XG4gICAgaWYgKHNlZW4uaGFzKG4pKSBjb250aW51ZTtcbiAgICBzZWVuLmFkZChuKTtcbiAgICBvdXQucHVzaChuKTtcbiAgICBmb3IgKGNvbnN0IGMgb2YgdHJlZS5jaGlsZHJlbi5nZXQobikgPz8gW10pIHN0YWNrLnB1c2goYyk7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqIFRoZSBjbGFzc2VzIGZyb20gdGhlIHJvb3QgZG93biB0byBgbmFtZWAncyBwYXJlbnQuICovXG5leHBvcnQgZnVuY3Rpb24gYW5jZXN0b3JzKHRyZWU6IENsYXNzVHJlZSwgbmFtZTogc3RyaW5nKTogc3RyaW5nW10ge1xuICBjb25zdCBvdXQ6IHN0cmluZ1tdID0gW107XG4gIGxldCBwID0gdHJlZS5wYXJlbnQuZ2V0KG5hbWUpID8/IG51bGw7XG4gIHdoaWxlIChwICYmICFvdXQuaW5jbHVkZXMocCkpIHtcbiAgICBvdXQudW5zaGlmdChwKTtcbiAgICBwID0gdHJlZS5wYXJlbnQuZ2V0KHApID8/IG51bGw7XG4gIH1cbiAgcmV0dXJuIG91dDtcbn1cblxuLyoqIE9uZSB2aXNpYmxlIHJvdyBvZiB0aGUgdHJlZS4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQ2xhc3NUcmVlUm93IHtcbiAgbmFtZTogc3RyaW5nO1xuICBkZXB0aDogbnVtYmVyO1xuICBoYXNDaGlsZHJlbjogYm9vbGVhbjtcbiAgZXhwYW5kZWQ6IGJvb2xlYW47XG59XG5cbi8qKlxuICogVGhlIHJvd3MgdG8gZHJhdzogZGVwdGgtZmlyc3QgdGhyb3VnaCB0aGUgZXhwYW5kZWQgbm9kZXMuIFdpdGggYSBgcXVlcnlgLCBvbmx5IHRoZSBub2RlcyB3aG9zZVxuICogbmFtZSBvciB0aXRsZSBjb250YWlucyBpdCBhbmQgdGhlaXIgYW5jZXN0b3JzLCBhbGwgZXhwYW5kZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB2aXNpYmxlUm93cyh0cmVlOiBDbGFzc1RyZWUsIGV4cGFuZGVkOiBSZWFkb25seVNldDxzdHJpbmc+LCBxdWVyeSA9ICcnKTogQ2xhc3NUcmVlUm93W10ge1xuICBjb25zdCBxID0gcXVlcnkudHJpbSgpLnRvTG93ZXJDYXNlKCk7XG4gIGxldCBrZWVwOiBTZXQ8c3RyaW5nPiB8IG51bGwgPSBudWxsO1xuICBpZiAocSkge1xuICAgIGtlZXAgPSBuZXcgU2V0KCk7XG4gICAgZm9yIChjb25zdCBbbmFtZSwgbl0gb2YgdHJlZS5ub2RlKSB7XG4gICAgICBpZiAobmFtZS50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHEpIHx8IChuLnRpdGxlID8/ICcnKS50b0xvd2VyQ2FzZSgpLmluY2x1ZGVzKHEpKSB7XG4gICAgICAgIGtlZXAuYWRkKG5hbWUpO1xuICAgICAgICBmb3IgKGNvbnN0IGEgb2YgYW5jZXN0b3JzKHRyZWUsIG5hbWUpKSBrZWVwLmFkZChhKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbiAgY29uc3Qgcm93czogQ2xhc3NUcmVlUm93W10gPSBbXTtcbiAgY29uc3Qgd2FsayA9IChuYW1lOiBzdHJpbmcsIGRlcHRoOiBudW1iZXIpID0+IHtcbiAgICBpZiAoa2VlcCAmJiAha2VlcC5oYXMobmFtZSkpIHJldHVybjtcbiAgICBjb25zdCBraWRzID0gdHJlZS5jaGlsZHJlbi5nZXQobmFtZSkgPz8gW107XG4gICAgY29uc3Qgb3BlbiA9IGtlZXAgPyB0cnVlIDogZXhwYW5kZWQuaGFzKG5hbWUpO1xuICAgIHJvd3MucHVzaCh7IG5hbWUsIGRlcHRoLCBoYXNDaGlsZHJlbjoga2lkcy5sZW5ndGggPiAwLCBleHBhbmRlZDogb3BlbiAmJiBraWRzLmxlbmd0aCA+IDAgfSk7XG4gICAgaWYgKG9wZW4pIGZvciAoY29uc3QgYyBvZiBraWRzKSB3YWxrKGMsIGRlcHRoICsgMSk7XG4gIH07XG4gIGZvciAoY29uc3QgciBvZiB0cmVlLnJvb3RzKSB3YWxrKHIsIDApO1xuICByZXR1cm4gcm93cztcbn1cbiJdfQ==