@eherve/angular-material-organigram 0.0.0-stage → 22.0.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.
package/CHANGELOG.md ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 22.0.0 — 2026-10-18
4
+
5
+ - Extract the reusable Angular 22 organigram from sésiO.
6
+ - Provide structural generic nodes, a standalone component and OrganigramModule.
7
+ - Preserve lazy loading, retry, immutable child arrays, keyboard and drag interactions.
8
+ - Highlight original ancestor connectors during layout animations, without SVG overlays.
9
+ - Add configurable messages, independent theme tokens, model and rendered component tests.
package/README.md CHANGED
@@ -1,3 +1,96 @@
1
- # Temporary Holding Version
1
+ # @eherve/angular-material-organigram
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Angular 22 template-driven organization trees with lazy branches, multi-row connectors,
4
+ keyboard activation, drag scrolling and ancestor highlighting.
5
+
6
+ ## Installation
7
+
8
+ ```sh
9
+ npm install @eherve/angular-material-organigram
10
+ ```
11
+
12
+ Import standalone `OrganigramComponent`, or `OrganigramModule` in an NgModule.
13
+ Configure Angular animations (`provideAnimations()` or `BrowserAnimationsModule`);
14
+ tests may use `NoopAnimationsModule`. Angular Core/Common/Animations 22 are peers.
15
+ The library requires no application model, router, Material theme, lodash or UUID package.
16
+
17
+ ```ts
18
+ import { Component } from '@angular/core';
19
+ import { OrganigramComponent, OrganigramTreeNode } from '@eherve/angular-material-organigram';
20
+
21
+ @Component({
22
+ selector: 'example-tree',
23
+ imports: [OrganigramComponent],
24
+ template: `
25
+ <app-organigram [tree]="tree" [nodeTmpl]="card" hideRoot />
26
+ <ng-template #card let-node="node"><div class="card">{{ node.entity?.name }}</div></ng-template>
27
+ `,
28
+ })
29
+ export class ExampleTree {
30
+ readonly tree = new OrganigramTreeNode<{ name: string }>({
31
+ type: 'root', children: [{ type: 'team', entity: { name: 'Team' } }],
32
+ });
33
+ }
34
+ ```
35
+
36
+ Style your projected `.card` yourself. The renderer owns connectors and spacing only.
37
+
38
+ ## Public API
39
+
40
+ - `tree`: a structural `OrganigramNode<T>`, `OrganigramTreeNode<T>`, null or undefined.
41
+ - `nodeTmpl`: Angular template receiving `{ node: OrganigramTreeNode<T> }`.
42
+ - `hideRoot`: attribute or boolean; false restores the root.
43
+ - `click`: optional async `(node) => Promise<unknown>` fallback action.
44
+
45
+ `OrganigramNode<T>` has `type`, optional `entity`, `children`, `hasChildren`,
46
+ `hideChildren`, `selected` and `onClick`. Existing structural objects are accepted.
47
+ `OrganigramTreeNode<T>` adds generated unique `id`, `parent`, `depth`, immutable
48
+ `addChild` and `getParent(index = 0)`. Positive indices walk from the nearest parent;
49
+ negative indices start at the root (-1). Wrapping input does not mutate it.
50
+ Entity data is retained by reference; callers own its immutability.
51
+
52
+ A node `onClick` takes precedence over `click`. It may return children to append and
53
+ open, an empty array to finish as a leaf, or void when it handles visibility itself.
54
+ The host owns API calls and caching: loaded callbacks should toggle their branch
55
+ rather than return the same children again. `hasChildren` advertises unloaded children.
56
+ Only one action per node runs at a time. Rejections show local retry UI. Replacement
57
+ and destruction ignore late results; already-started network requests are not aborted.
58
+ Root loading, filtering, root-error handling and preserving root state belong to the host.
59
+
60
+ Enter/Space activate focused nodes. Projected buttons, links, inputs and checkboxes keep
61
+ their interactions. Mouse movement below five pixels remains a click; dragging suppresses
62
+ activation and releases outside the chart. Scrolling runs after Angular rendering.
63
+ Hover colors only the original ancestor connectors, with layout-aware horizontal segments.
64
+
65
+ ## Theme and messages
66
+
67
+ Set these CSS variables on `app-organigram` or an ancestor:
68
+
69
+ | Token | Default |
70
+ | --- | --- |
71
+ | `--ngx-mat-organigram-node-width` | `200px` |
72
+ | `--ngx-mat-organigram-connector` | `#09293c` |
73
+ | `--ngx-mat-organigram-highlight` | `#e73452` |
74
+ | `--ngx-mat-organigram-focus` | `#09293c` |
75
+ | `--ngx-mat-organigram-error` | `#e9396b` |
76
+
77
+ Card width must be a CSS length, such as `250px`. Five children are grouped per row.
78
+ Messages are French by default. Inject `OrganigramIntl` and update its `messages` signal:
79
+
80
+ ```ts
81
+ intl.messages.set({ loadError: 'Loading failed.', retry: 'Retry' });
82
+ ```
83
+
84
+ ## Development
85
+
86
+ From the angular-material-extended repository (supported Angular CLI Node.js version):
87
+
88
+ ```sh
89
+ npm run test:organigram:model
90
+ npm run test:organigram
91
+ npm run build:organigram
92
+ ```
93
+
94
+ The model tests use Node's native TypeScript stripping. Browser specs use Jasmine/Karma
95
+ and cover asynchronous actions, rendered templates, multi-row layout and connector highlighting.
96
+ README and CHANGELOG are included in the built npm package.
@@ -0,0 +1,477 @@
1
+ import { animate, style, transition, trigger } from "@angular/animations";
2
+ import * as i1 from "@angular/common";
3
+ import { CommonModule } from "@angular/common";
4
+ import * as i0 from "@angular/core";
5
+ import { ChangeDetectionStrategy, Component, ElementRef, HostListener, Injectable, Injector, Input, NgModule, Pipe, ViewChild, afterNextRender, inject, signal } from "@angular/core";
6
+ let nextNodeId = 0;
7
+ var OrganigramTreeNode = class OrganigramTreeNode {
8
+ id;
9
+ type;
10
+ entity;
11
+ hasChildren;
12
+ hideChildren;
13
+ selected;
14
+ parent;
15
+ depth;
16
+ children = [];
17
+ onClick;
18
+ constructor(node, depth = 0) {
19
+ Object.assign(this, node);
20
+ this.id = `ngx-mat-organigram-node-${nextNodeId++}`;
21
+ this.type = node.type;
22
+ this.parent = void 0;
23
+ this.depth = depth;
24
+ this.children = [];
25
+ for (const child of node.children ?? []) this.addChild(child);
26
+ }
27
+ addChild(node) {
28
+ const child = node instanceof OrganigramTreeNode ? node : new OrganigramTreeNode(node, this.depth + 1);
29
+ child.parent = this;
30
+ child.setDepth(this.depth + 1);
31
+ this.children = [...this.children, child];
32
+ }
33
+ setDepth(depth) {
34
+ this.depth = depth;
35
+ for (const child of this.children) child.setDepth(depth + 1);
36
+ }
37
+ getParent(index = 0) {
38
+ const parents = [];
39
+ for (let parent = this.parent; parent; parent = parent.parent) parents.unshift(parent);
40
+ return parents[index < 0 ? Math.abs(index) - 1 : parents.length - 1 - index] ?? null;
41
+ }
42
+ };
43
+ var OrganigramRowsPipe = class OrganigramRowsPipe {
44
+ transform(nodes, size = 5) {
45
+ const rows = [];
46
+ for (let i = 0; i < nodes.length; i += size) rows.push(nodes.slice(i, i + size));
47
+ return rows;
48
+ }
49
+ static ɵfac = i0.ɵɵngDeclareFactory({
50
+ minVersion: "12.0.0",
51
+ version: "22.2.1",
52
+ ngImport: i0,
53
+ type: OrganigramRowsPipe,
54
+ deps: [],
55
+ target: i0.ɵɵFactoryTarget.Pipe
56
+ });
57
+ static ɵpipe = i0.ɵɵngDeclarePipe({
58
+ minVersion: "14.0.0",
59
+ version: "22.2.1",
60
+ ngImport: i0,
61
+ type: OrganigramRowsPipe,
62
+ isStandalone: true,
63
+ name: "organigramRows"
64
+ });
65
+ };
66
+ i0.ɵɵngDeclareClassMetadata({
67
+ minVersion: "12.0.0",
68
+ version: "22.2.1",
69
+ ngImport: i0,
70
+ type: OrganigramRowsPipe,
71
+ decorators: [{
72
+ type: Pipe,
73
+ args: [{ name: "organigramRows" }]
74
+ }]
75
+ });
76
+ var OrganigramIntl = class OrganigramIntl {
77
+ messages = signal({
78
+ loadError: "Impossible de charger cette rubrique.",
79
+ retry: "Réessayer"
80
+ }, ...ngDevMode ? [{ debugName: "messages" }] : /* istanbul ignore next */ []);
81
+ static ɵfac = i0.ɵɵngDeclareFactory({
82
+ minVersion: "12.0.0",
83
+ version: "22.2.1",
84
+ ngImport: i0,
85
+ type: OrganigramIntl,
86
+ deps: [],
87
+ target: i0.ɵɵFactoryTarget.Injectable
88
+ });
89
+ static ɵprov = i0.ɵɵngDeclareInjectable({
90
+ minVersion: "12.0.0",
91
+ version: "22.2.1",
92
+ ngImport: i0,
93
+ type: OrganigramIntl,
94
+ providedIn: "root"
95
+ });
96
+ };
97
+ i0.ɵɵngDeclareClassMetadata({
98
+ minVersion: "12.0.0",
99
+ version: "22.2.1",
100
+ ngImport: i0,
101
+ type: OrganigramIntl,
102
+ decorators: [{
103
+ type: Injectable,
104
+ args: [{ providedIn: "root" }]
105
+ }]
106
+ });
107
+ var OrganigramComponent = class OrganigramComponent {
108
+ intl = inject(OrganigramIntl);
109
+ dragging = false;
110
+ dragOrigin = null;
111
+ suppressClick = false;
112
+ destroyed = false;
113
+ treeVersion = 0;
114
+ scrollRender;
115
+ pendingNodes = signal(/* @__PURE__ */ new Set(), ...ngDevMode ? [{ debugName: "pendingNodes" }] : /* istanbul ignore next */ []);
116
+ nodeErrors = signal(/* @__PURE__ */ new Map(), ...ngDevMode ? [{ debugName: "nodeErrors" }] : /* istanbul ignore next */ []);
117
+ highlightedConnectors = /* @__PURE__ */ new Set();
118
+ pathObserver;
119
+ hoveredNode = null;
120
+ injector = inject(Injector);
121
+ host = inject(ElementRef);
122
+ onMouseDown(event) {
123
+ this.suppressClick = false;
124
+ if (event.button !== 0 || event.target.closest("button, input, a, mat-checkbox")) return;
125
+ this.dragOrigin = {
126
+ x: event.clientX,
127
+ y: event.clientY
128
+ };
129
+ }
130
+ onMouseMove(event) {
131
+ if (!this.dragOrigin) return;
132
+ if (!this.dragging && Math.hypot(event.clientX - this.dragOrigin.x, event.clientY - this.dragOrigin.y) < 5) return;
133
+ this.dragging = true;
134
+ this.suppressClick = true;
135
+ this.scrollRef?.nativeElement.scrollBy({
136
+ top: -event.movementY,
137
+ left: -event.movementX
138
+ });
139
+ event.preventDefault();
140
+ }
141
+ onMouseUp() {
142
+ this.dragOrigin = null;
143
+ this.dragging = false;
144
+ }
145
+ scrollRef;
146
+ set setHideRoot(hideRoot) {
147
+ this.hideRoot = hideRoot !== false;
148
+ }
149
+ hideRoot = false;
150
+ set setTree(tree) {
151
+ this.treeVersion++;
152
+ this.scrollRender?.destroy();
153
+ this.pendingNodes.set(/* @__PURE__ */ new Set());
154
+ this.nodeErrors.set(/* @__PURE__ */ new Map());
155
+ this.highlightParents(null);
156
+ this.tree = !tree ? null : tree instanceof OrganigramTreeNode ? tree : new OrganigramTreeNode(tree);
157
+ }
158
+ tree = null;
159
+ nodeTmpl;
160
+ clickHandler;
161
+ nbChildByRow = 5;
162
+ highlightParents(node) {
163
+ this.pathObserver?.disconnect();
164
+ this.hoveredNode = node;
165
+ this.paintParentPath();
166
+ if (!node) return;
167
+ this.pathObserver ??= new ResizeObserver(() => this.paintParentPath());
168
+ for (const connector of this.highlightedConnectors) this.pathObserver.observe(connector.parentElement);
169
+ }
170
+ paintParentPath() {
171
+ for (const element of this.highlightedConnectors) {
172
+ element.classList.remove("path-vertical");
173
+ element.style.removeProperty("--path-horizontal-color");
174
+ }
175
+ this.highlightedConnectors.clear();
176
+ for (let child = this.hoveredNode; child?.parent; child = child.parent) {
177
+ const childElement = document.getElementById(child.id);
178
+ const parentElement = document.getElementById(child.parent.id);
179
+ if (!childElement || !parentElement || !this.host.nativeElement.contains(parentElement) || !parentElement.offsetParent) break;
180
+ const row = childElement.closest(".node-block-children-row");
181
+ const group = row?.parentElement;
182
+ if (!row || !group) break;
183
+ const rows = Array.from(group.querySelectorAll(":scope > .node-block-children-row"));
184
+ const rowIndex = rows.indexOf(row);
185
+ const parentX = parentElement.getBoundingClientRect().left + parentElement.offsetWidth / 2;
186
+ const childX = childElement.getBoundingClientRect().left + childElement.offsetWidth / 2;
187
+ this.colorVertical(childElement.parentElement?.querySelector(":scope > .node-block-top"));
188
+ this.colorVertical(parentElement.querySelector(":scope > .node-container-bottom"));
189
+ const groupTop = group.querySelector(":scope > .node-block-children-top");
190
+ this.colorVertical(groupTop);
191
+ if (rowIndex === 0) {
192
+ this.colorRow(row, parentX, childX);
193
+ if (groupTop) this.colorHorizontal(groupTop, parentX, childX);
194
+ } else {
195
+ const railX = rows[0].getBoundingClientRect().left;
196
+ this.colorRow(rows[0], parentX, railX);
197
+ if (groupTop) this.colorHorizontal(groupTop, parentX, railX);
198
+ for (const previousRow of rows.slice(0, rowIndex)) this.colorVertical(previousRow.querySelector(":scope > .node-block > .node-block-left"));
199
+ this.colorRow(row, railX, childX);
200
+ }
201
+ }
202
+ }
203
+ colorVertical(element) {
204
+ if (!element) return;
205
+ element.classList.add("path-vertical");
206
+ this.highlightedConnectors.add(element);
207
+ }
208
+ colorRow(row, from, to) {
209
+ for (const element of row.querySelectorAll(":scope > .node-block > .node-block-top")) this.colorHorizontal(element, from, to);
210
+ }
211
+ colorHorizontal(element, from, to) {
212
+ const style = getComputedStyle(element, "::before");
213
+ if (style.content === "none") return;
214
+ const bounds = element.getBoundingClientRect();
215
+ const offset = style.left.endsWith("%") ? parseFloat(style.left) * bounds.width / 100 : parseFloat(style.left);
216
+ const width = parseFloat(style.width);
217
+ const start = Math.max(0, Math.min(from, to) - bounds.left - offset);
218
+ const end = Math.min(width, Math.max(from, to) - bounds.left - offset);
219
+ if (end <= start || !Number.isFinite(width)) return;
220
+ element.style.setProperty("--path-horizontal-color", `linear-gradient(to right,
221
+ var(--ngx-mat-organigram-connector, #09293c) ${start}px, var(--ngx-mat-organigram-highlight, #e73452) ${start}px,
222
+ var(--ngx-mat-organigram-highlight, #e73452) ${end}px, var(--ngx-mat-organigram-connector, #09293c) ${end}px)`);
223
+ this.highlightedConnectors.add(element);
224
+ }
225
+ ngOnDestroy() {
226
+ this.highlightParents(null);
227
+ this.destroyed = true;
228
+ this.treeVersion++;
229
+ this.scrollRender?.destroy();
230
+ }
231
+ onKeydown(event, node) {
232
+ if (event.target !== event.currentTarget || event.key !== "Enter" && event.key !== " ") return;
233
+ event.preventDefault();
234
+ this.onClick(node);
235
+ }
236
+ async onClick(node, event) {
237
+ if (event && (this.suppressClick || event.target.closest("button, input, a, mat-checkbox"))) return;
238
+ if (this.destroyed || this.pendingNodes().has(node)) return;
239
+ const version = this.treeVersion;
240
+ this.pendingNodes.update((pending) => /* @__PURE__ */ new Set([...pending, node]));
241
+ this.nodeErrors.update((errors) => {
242
+ const next = new Map(errors);
243
+ next.delete(node);
244
+ return next;
245
+ });
246
+ try {
247
+ if (node.onClick) {
248
+ const children = await node.onClick(node);
249
+ if (this.destroyed || version !== this.treeVersion) return;
250
+ if (Array.isArray(children)) {
251
+ for (const child of children) node.addChild(child);
252
+ node.hasChildren = node.children.length > 0;
253
+ node.hideChildren = false;
254
+ }
255
+ } else if (this.clickHandler) await this.clickHandler(node);
256
+ else if (node.hasChildren) node.hideChildren = !node.hideChildren;
257
+ if (this.destroyed || version !== this.treeVersion) return;
258
+ this.scrollToNode(node);
259
+ } catch {
260
+ if (!this.destroyed && version === this.treeVersion) this.nodeErrors.update((errors) => new Map(errors).set(node, this.intl.messages().loadError));
261
+ } finally {
262
+ if (!this.destroyed && version === this.treeVersion) this.pendingNodes.update((pending) => {
263
+ const next = new Set(pending);
264
+ next.delete(node);
265
+ return next;
266
+ });
267
+ }
268
+ }
269
+ scrollToNode(node) {
270
+ this.scrollRender?.destroy();
271
+ this.scrollRender = afterNextRender(() => {
272
+ if (this.destroyed) return;
273
+ if (this.hoveredNode) this.highlightParents(this.hoveredNode);
274
+ const element = document.getElementById(node.id);
275
+ if (element && this.host.nativeElement.contains(element)) element.scrollIntoView({
276
+ behavior: "smooth",
277
+ block: "nearest",
278
+ inline: "nearest"
279
+ });
280
+ }, { injector: this.injector });
281
+ }
282
+ static ɵfac = i0.ɵɵngDeclareFactory({
283
+ minVersion: "12.0.0",
284
+ version: "22.2.1",
285
+ ngImport: i0,
286
+ type: OrganigramComponent,
287
+ deps: [],
288
+ target: i0.ɵɵFactoryTarget.Component
289
+ });
290
+ static ɵcmp = i0.ɵɵngDeclareComponent({
291
+ minVersion: "17.0.0",
292
+ version: "22.2.1",
293
+ type: OrganigramComponent,
294
+ isStandalone: true,
295
+ selector: "app-organigram",
296
+ inputs: {
297
+ setHideRoot: ["hideRoot", "setHideRoot"],
298
+ setTree: ["tree", "setTree"],
299
+ nodeTmpl: "nodeTmpl",
300
+ clickHandler: ["click", "clickHandler"]
301
+ },
302
+ host: { listeners: {
303
+ "mousedown": "onMouseDown($event)",
304
+ "mousemove": "onMouseMove($event)",
305
+ "document:mouseup": "onMouseUp()",
306
+ "window:blur": "onMouseUp()"
307
+ } },
308
+ viewQueries: [{
309
+ propertyName: "scrollRef",
310
+ first: true,
311
+ predicate: ["scroll"],
312
+ descendants: true
313
+ }],
314
+ ngImport: i0,
315
+ template: "<!-- @format -->\n\n<div\n id=\"scroll\"\n #scroll\n [class.dragging]=\"dragging\">\n @if (tree) {\n <div id=\"container\" [class.hide-root]=\"hideRoot\">\n <ng-container\n *ngTemplateOutlet=\"\n nodeBlock;\n context: { depth: 0, node: tree, class: { top: true, bottom: true, left: true, right: true } }\n \"></ng-container>\n </div>\n }\n</div>\n\n<ng-template #nodeBlock let-depth=\"depth\" let-node=\"node\" let-class=\"class\">\n <div class=\"node-block\" [class.depth-even]=\"depth % 2\">\n <div class=\"node-block-top\" [class]=\"class\"></div>\n <div class=\"node-block-left\" [class]=\"class\"></div>\n <div\n [id]=\"node.id\"\n class=\"node-container\"\n [class]=\"class\"\n [attr.role]=\"node.hasChildren || node.onClick || clickHandler ? 'button' : null\"\n [attr.tabindex]=\"node.hasChildren || node.onClick || clickHandler ? 0 : null\"\n [attr.aria-expanded]=\"node.hasChildren ? !node.hideChildren : null\"\n [attr.aria-busy]=\"pendingNodes().has(node)\"\n (mouseenter)=\"highlightParents(node)\"\n (mouseleave)=\"highlightParents(null)\"\n (keydown)=\"onKeydown($event, node)\"\n (click)=\"onClick(node, $event)\">\n <ng-container *ngTemplateOutlet=\"nodeTmpl; context: { node: node }\"></ng-container>\n @if (!node.hideChildren && node.children?.length) {\n <div @toggleTreeNode class=\"node-container-bottom\" [class]=\"class\"></div>\n }\n </div>\n @if (nodeErrors().get(node); as message) {\n <div class=\"node-error\" role=\"alert\">\n <span>{{ message }}</span>\n <button type=\"button\" (click)=\"onClick(node)\">{{ intl.messages().retry }}</button>\n </div>\n }\n @if (!node.hideChildren && node.children?.length) {\n <div @toggleTreeNode class=\"node-block-children\" [class.depth-even]=\"depth % 2\">\n <div class=\"node-block-children-top\" [class]=\"class\" [class.multiple-row]=\"node.children.length > 4\"></div>\n @for (\n row of node.children | organigramRows: nbChildByRow;\n track row;\n let rowIndex = $index;\n let top = $first;\n let bottom = $last\n ) {\n <div class=\"node-block-children-row\" [class.top]=\"top\" [class.bottom]=\"bottom\">\n @for (child of row; track child; let index = $index; let left = $first; let right = $last) {\n <ng-container\n *ngTemplateOutlet=\"\n nodeBlock;\n context: {\n depth: depth + 1,\n node: child,\n class: {\n rowIndex: rowIndex,\n index: index,\n even: index % 2,\n top: top,\n bottom: bottom,\n left: left,\n right: right,\n },\n }\n \">\n </ng-container>\n }\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n",
316
+ styles: [":host{max-height:100%;max-width:100%;height:100%;width:100%}#scroll{display:flex;align-items:flex-start;justify-content:flex-start;position:relative;overflow:auto;height:100%;width:100%}#scroll.dragging{cursor:move!important}#scroll.dragging ::ng-deep *{cursor:move!important}#container{position:relative;padding:8px;margin:0 auto}#container.hide-root>.node-block{display:flex;flex-direction:column;align-items:center}#container.hide-root>.node-block>.node-container,#container.hide-root>.node-block>.node-block-top,#container.hide-root>.node-block>.node-block-left{display:none}#container.hide-root>.node-block>.node-block-children>.node-block-children-top{display:none}#container.hide-root>.node-block>.node-block-children>.node-block-children-row>.node-block>.node-block-top.left.right.top.bottom{display:none}.node-block{display:flex;flex-direction:column;align-items:center;position:relative}.node-block-top{position:absolute;top:0;left:0;right:0}.node-block-top:after{content:\"\";position:absolute;top:0;left:50%;width:1px;height:8px;background-color:var(--ngx-mat-organigram-connector, #09293c)}.node-block-top.left.right:after{top:0;height:8px}.node-block-top:not(.top.bottom.left.right):before{content:\"\";position:absolute;top:0;left:0;right:0;height:1px;background:var(--path-horizontal-color, var(--ngx-mat-organigram-connector, #09293c))}.node-block-top:not(.top.bottom.left.right).left.top.bottom:before{left:50%}.node-block-top:not(.top.bottom.left.right).right:before{right:50%}.node-block-left{position:absolute;top:0;left:0;bottom:0}.node-block-left.left:not(.bottom):before{content:\"\";position:absolute;top:0;left:0;bottom:0;width:1px;background-color:var(--ngx-mat-organigram-connector, #09293c)}.node-container{position:relative;padding:8px;width:calc(var(--ngx-mat-organigram-node-width, 200px) + 16px);box-sizing:content-box}.node-container:focus-visible{outline:2px solid var(--ngx-mat-organigram-focus, #09293c);outline-offset:-2px}.node-container-bottom{position:absolute;bottom:0;left:0;right:0;width:100%}.node-container-bottom:after{content:\"\";position:absolute;bottom:-8px;left:50%;width:1px;height:16px;background-color:var(--ngx-mat-organigram-connector, #09293c)}.node-block-children{position:relative;background-color:#fff;border-radius:8px;padding:8px;margin:8px;overflow:hidden}.node-block-children.depth-even{background-color:#f9f9f9}.node-block-children-top{position:absolute;top:0;left:0;right:0;width:100%}.node-block-children-top:after{content:\"\";position:absolute;top:0;left:50%;width:1px;height:8px;background-color:var(--ngx-mat-organigram-connector, #09293c)}.node-block-children-top.multiple-row:not(.bottom):before{content:\"\";position:absolute;top:8px;left:8px;right:50%;height:1px;background:var(--path-horizontal-color, var(--ngx-mat-organigram-connector, #09293c))}.node-error{max-width:var(--ngx-mat-organigram-node-width, 200px);padding:8px;display:flex;flex-direction:column;gap:8px;color:var(--ngx-mat-organigram-error, #e9396b)}.node-block-top.path-vertical:after,.node-container-bottom.path-vertical:after,.node-block-children-top.path-vertical:after,.node-block-left.path-vertical:before{background-color:var(--ngx-mat-organigram-highlight, #e73452)}.node-block-children-row{display:flex;flex-direction:row}\n"],
317
+ dependencies: [
318
+ {
319
+ kind: "ngmodule",
320
+ type: CommonModule
321
+ },
322
+ {
323
+ kind: "directive",
324
+ type: i1.NgTemplateOutlet,
325
+ selector: "[ngTemplateOutlet]",
326
+ inputs: [
327
+ "ngTemplateOutletContext",
328
+ "ngTemplateOutlet",
329
+ "ngTemplateOutletInjector"
330
+ ]
331
+ },
332
+ {
333
+ kind: "pipe",
334
+ type: OrganigramRowsPipe,
335
+ name: "organigramRows"
336
+ }
337
+ ],
338
+ animations: [trigger("toggleTreeNode", [transition(":enter", [
339
+ style({
340
+ height: 0,
341
+ width: 0,
342
+ opacity: 0
343
+ }),
344
+ animate("0.2s", style({
345
+ height: "*",
346
+ width: "*"
347
+ })),
348
+ animate("0.2s 0.2s", style({ opacity: 1 }))
349
+ ]), transition(":leave", [
350
+ style({
351
+ height: "*",
352
+ width: "*",
353
+ opacity: 1
354
+ }),
355
+ animate("0.2s", style({ opacity: 0 })),
356
+ animate("0.2s 0.2s", style({
357
+ height: 0,
358
+ width: 0
359
+ }))
360
+ ])])],
361
+ changeDetection: i0.ChangeDetectionStrategy.Eager
362
+ });
363
+ };
364
+ i0.ɵɵngDeclareClassMetadata({
365
+ minVersion: "12.0.0",
366
+ version: "22.2.1",
367
+ ngImport: i0,
368
+ type: OrganigramComponent,
369
+ decorators: [{
370
+ type: Component,
371
+ args: [{
372
+ selector: "app-organigram",
373
+ animations: [trigger("toggleTreeNode", [transition(":enter", [
374
+ style({
375
+ height: 0,
376
+ width: 0,
377
+ opacity: 0
378
+ }),
379
+ animate("0.2s", style({
380
+ height: "*",
381
+ width: "*"
382
+ })),
383
+ animate("0.2s 0.2s", style({ opacity: 1 }))
384
+ ]), transition(":leave", [
385
+ style({
386
+ height: "*",
387
+ width: "*",
388
+ opacity: 1
389
+ }),
390
+ animate("0.2s", style({ opacity: 0 })),
391
+ animate("0.2s 0.2s", style({
392
+ height: 0,
393
+ width: 0
394
+ }))
395
+ ])])],
396
+ changeDetection: ChangeDetectionStrategy.Eager,
397
+ imports: [CommonModule, OrganigramRowsPipe],
398
+ template: "<!-- @format -->\n\n<div\n id=\"scroll\"\n #scroll\n [class.dragging]=\"dragging\">\n @if (tree) {\n <div id=\"container\" [class.hide-root]=\"hideRoot\">\n <ng-container\n *ngTemplateOutlet=\"\n nodeBlock;\n context: { depth: 0, node: tree, class: { top: true, bottom: true, left: true, right: true } }\n \"></ng-container>\n </div>\n }\n</div>\n\n<ng-template #nodeBlock let-depth=\"depth\" let-node=\"node\" let-class=\"class\">\n <div class=\"node-block\" [class.depth-even]=\"depth % 2\">\n <div class=\"node-block-top\" [class]=\"class\"></div>\n <div class=\"node-block-left\" [class]=\"class\"></div>\n <div\n [id]=\"node.id\"\n class=\"node-container\"\n [class]=\"class\"\n [attr.role]=\"node.hasChildren || node.onClick || clickHandler ? 'button' : null\"\n [attr.tabindex]=\"node.hasChildren || node.onClick || clickHandler ? 0 : null\"\n [attr.aria-expanded]=\"node.hasChildren ? !node.hideChildren : null\"\n [attr.aria-busy]=\"pendingNodes().has(node)\"\n (mouseenter)=\"highlightParents(node)\"\n (mouseleave)=\"highlightParents(null)\"\n (keydown)=\"onKeydown($event, node)\"\n (click)=\"onClick(node, $event)\">\n <ng-container *ngTemplateOutlet=\"nodeTmpl; context: { node: node }\"></ng-container>\n @if (!node.hideChildren && node.children?.length) {\n <div @toggleTreeNode class=\"node-container-bottom\" [class]=\"class\"></div>\n }\n </div>\n @if (nodeErrors().get(node); as message) {\n <div class=\"node-error\" role=\"alert\">\n <span>{{ message }}</span>\n <button type=\"button\" (click)=\"onClick(node)\">{{ intl.messages().retry }}</button>\n </div>\n }\n @if (!node.hideChildren && node.children?.length) {\n <div @toggleTreeNode class=\"node-block-children\" [class.depth-even]=\"depth % 2\">\n <div class=\"node-block-children-top\" [class]=\"class\" [class.multiple-row]=\"node.children.length > 4\"></div>\n @for (\n row of node.children | organigramRows: nbChildByRow;\n track row;\n let rowIndex = $index;\n let top = $first;\n let bottom = $last\n ) {\n <div class=\"node-block-children-row\" [class.top]=\"top\" [class.bottom]=\"bottom\">\n @for (child of row; track child; let index = $index; let left = $first; let right = $last) {\n <ng-container\n *ngTemplateOutlet=\"\n nodeBlock;\n context: {\n depth: depth + 1,\n node: child,\n class: {\n rowIndex: rowIndex,\n index: index,\n even: index % 2,\n top: top,\n bottom: bottom,\n left: left,\n right: right,\n },\n }\n \">\n </ng-container>\n }\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n",
399
+ styles: [":host{max-height:100%;max-width:100%;height:100%;width:100%}#scroll{display:flex;align-items:flex-start;justify-content:flex-start;position:relative;overflow:auto;height:100%;width:100%}#scroll.dragging{cursor:move!important}#scroll.dragging ::ng-deep *{cursor:move!important}#container{position:relative;padding:8px;margin:0 auto}#container.hide-root>.node-block{display:flex;flex-direction:column;align-items:center}#container.hide-root>.node-block>.node-container,#container.hide-root>.node-block>.node-block-top,#container.hide-root>.node-block>.node-block-left{display:none}#container.hide-root>.node-block>.node-block-children>.node-block-children-top{display:none}#container.hide-root>.node-block>.node-block-children>.node-block-children-row>.node-block>.node-block-top.left.right.top.bottom{display:none}.node-block{display:flex;flex-direction:column;align-items:center;position:relative}.node-block-top{position:absolute;top:0;left:0;right:0}.node-block-top:after{content:\"\";position:absolute;top:0;left:50%;width:1px;height:8px;background-color:var(--ngx-mat-organigram-connector, #09293c)}.node-block-top.left.right:after{top:0;height:8px}.node-block-top:not(.top.bottom.left.right):before{content:\"\";position:absolute;top:0;left:0;right:0;height:1px;background:var(--path-horizontal-color, var(--ngx-mat-organigram-connector, #09293c))}.node-block-top:not(.top.bottom.left.right).left.top.bottom:before{left:50%}.node-block-top:not(.top.bottom.left.right).right:before{right:50%}.node-block-left{position:absolute;top:0;left:0;bottom:0}.node-block-left.left:not(.bottom):before{content:\"\";position:absolute;top:0;left:0;bottom:0;width:1px;background-color:var(--ngx-mat-organigram-connector, #09293c)}.node-container{position:relative;padding:8px;width:calc(var(--ngx-mat-organigram-node-width, 200px) + 16px);box-sizing:content-box}.node-container:focus-visible{outline:2px solid var(--ngx-mat-organigram-focus, #09293c);outline-offset:-2px}.node-container-bottom{position:absolute;bottom:0;left:0;right:0;width:100%}.node-container-bottom:after{content:\"\";position:absolute;bottom:-8px;left:50%;width:1px;height:16px;background-color:var(--ngx-mat-organigram-connector, #09293c)}.node-block-children{position:relative;background-color:#fff;border-radius:8px;padding:8px;margin:8px;overflow:hidden}.node-block-children.depth-even{background-color:#f9f9f9}.node-block-children-top{position:absolute;top:0;left:0;right:0;width:100%}.node-block-children-top:after{content:\"\";position:absolute;top:0;left:50%;width:1px;height:8px;background-color:var(--ngx-mat-organigram-connector, #09293c)}.node-block-children-top.multiple-row:not(.bottom):before{content:\"\";position:absolute;top:8px;left:8px;right:50%;height:1px;background:var(--path-horizontal-color, var(--ngx-mat-organigram-connector, #09293c))}.node-error{max-width:var(--ngx-mat-organigram-node-width, 200px);padding:8px;display:flex;flex-direction:column;gap:8px;color:var(--ngx-mat-organigram-error, #e9396b)}.node-block-top.path-vertical:after,.node-container-bottom.path-vertical:after,.node-block-children-top.path-vertical:after,.node-block-left.path-vertical:before{background-color:var(--ngx-mat-organigram-highlight, #e73452)}.node-block-children-row{display:flex;flex-direction:row}\n"]
400
+ }]
401
+ }],
402
+ propDecorators: {
403
+ onMouseDown: [{
404
+ type: HostListener,
405
+ args: ["mousedown", ["$event"]]
406
+ }],
407
+ onMouseMove: [{
408
+ type: HostListener,
409
+ args: ["mousemove", ["$event"]]
410
+ }],
411
+ onMouseUp: [{
412
+ type: HostListener,
413
+ args: ["document:mouseup"]
414
+ }, {
415
+ type: HostListener,
416
+ args: ["window:blur"]
417
+ }],
418
+ scrollRef: [{
419
+ type: ViewChild,
420
+ args: ["scroll"]
421
+ }],
422
+ setHideRoot: [{
423
+ type: Input,
424
+ args: ["hideRoot"]
425
+ }],
426
+ setTree: [{
427
+ type: Input,
428
+ args: ["tree"]
429
+ }],
430
+ nodeTmpl: [{ type: Input }],
431
+ clickHandler: [{
432
+ type: Input,
433
+ args: ["click"]
434
+ }]
435
+ }
436
+ });
437
+ var OrganigramModule = class OrganigramModule {
438
+ static ɵfac = i0.ɵɵngDeclareFactory({
439
+ minVersion: "12.0.0",
440
+ version: "22.2.1",
441
+ ngImport: i0,
442
+ type: OrganigramModule,
443
+ deps: [],
444
+ target: i0.ɵɵFactoryTarget.NgModule
445
+ });
446
+ static ɵmod = i0.ɵɵngDeclareNgModule({
447
+ minVersion: "14.0.0",
448
+ version: "22.2.1",
449
+ ngImport: i0,
450
+ type: OrganigramModule,
451
+ imports: [OrganigramComponent],
452
+ exports: [OrganigramComponent]
453
+ });
454
+ static ɵinj = i0.ɵɵngDeclareInjector({
455
+ minVersion: "12.0.0",
456
+ version: "22.2.1",
457
+ ngImport: i0,
458
+ type: OrganigramModule,
459
+ imports: [OrganigramComponent]
460
+ });
461
+ };
462
+ i0.ɵɵngDeclareClassMetadata({
463
+ minVersion: "12.0.0",
464
+ version: "22.2.1",
465
+ ngImport: i0,
466
+ type: OrganigramModule,
467
+ decorators: [{
468
+ type: NgModule,
469
+ args: [{
470
+ imports: [OrganigramComponent],
471
+ exports: [OrganigramComponent]
472
+ }]
473
+ }]
474
+ });
475
+ export { OrganigramComponent, OrganigramIntl, OrganigramModule, OrganigramTreeNode };
476
+
477
+ //# sourceMappingURL=eherve-angular-material-organigram.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"eherve-angular-material-organigram.mjs","names":[],"sources":["../../../projects/organigram/src/lib/organigram-tree-node.ts","../../../projects/organigram/src/lib/organigram-rows.pipe.ts","../../../projects/organigram/src/lib/organigram-intl.ts","../../../projects/organigram/src/lib/organigram.component.ts","../../../projects/organigram/src/lib/organigram.component.html","../../../projects/organigram/src/lib/organigram.module.ts"],"sourcesContent":["export interface OrganigramNode<T = unknown> {\n type: string;\n entity?: T | null;\n hasChildren?: boolean;\n children?: readonly OrganigramNode<T>[];\n hideChildren?: boolean;\n selected?: boolean;\n onClick?: (node: OrganigramTreeNode<T>) => Promise<readonly OrganigramNode<T>[] | void>;\n}\n\nlet nextNodeId = 0;\n\nexport class OrganigramTreeNode<T = unknown> implements OrganigramNode<T> {\n readonly id: string;\n type: string;\n entity?: T | null;\n hasChildren?: boolean;\n hideChildren?: boolean;\n selected?: boolean;\n parent?: OrganigramTreeNode<T>;\n depth: number;\n children: OrganigramTreeNode<T>[] = [];\n onClick?: (node: OrganigramTreeNode<T>) => Promise<readonly OrganigramNode<T>[] | void>;\n\n constructor(node: OrganigramNode<T>, depth = 0) {\n Object.assign(this, node);\n this.id = `ngx-mat-organigram-node-${nextNodeId++}`;\n this.type = node.type;\n this.parent = undefined;\n this.depth = depth;\n this.children = [];\n for (const child of node.children ?? []) this.addChild(child);\n }\n\n addChild(node: OrganigramNode<T>): void {\n const child = node instanceof OrganigramTreeNode ? node : new OrganigramTreeNode(node, this.depth + 1);\n child.parent = this;\n child.setDepth(this.depth + 1);\n this.children = [...this.children, child];\n }\n\n private setDepth(depth: number): void {\n this.depth = depth;\n for (const child of this.children) child.setDepth(depth + 1);\n }\n\n getParent(index = 0): OrganigramTreeNode<T> | null {\n const parents: OrganigramTreeNode<T>[] = [];\n for (let parent = this.parent; parent; parent = parent.parent) parents.unshift(parent);\n const position = index < 0 ? Math.abs(index) - 1 : parents.length - 1 - index;\n return parents[position] ?? null;\n }\n}\n","import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({ name: 'organigramRows' })\nexport class OrganigramRowsPipe implements PipeTransform {\n transform<T>(nodes: readonly T[], size = 5): T[][] {\n const rows: T[][] = [];\n for (let i = 0; i < nodes.length; i += size) rows.push(nodes.slice(i, i + size));\n return rows;\n }\n}\n","import { Injectable, signal } from '@angular/core';\n\nexport interface OrganigramMessages {\n loadError: string;\n retry: string;\n}\n\n@Injectable({ providedIn: 'root' })\nexport class OrganigramIntl {\n readonly messages = signal<OrganigramMessages>({\n loadError: 'Impossible de charger cette rubrique.',\n retry: 'Réessayer',\n });\n}\n","/** @format */\n\nimport { animate, style, transition, trigger } from '@angular/animations';\nimport { CommonModule } from '@angular/common';\nimport {\n afterNextRender,\n AfterRenderRef,\n Injector,\n signal,\n Component,\n ElementRef,\n HostListener,\n inject,\n Input,\n OnDestroy,\n TemplateRef,\n ViewChild,\n ChangeDetectionStrategy,\n} from '@angular/core';\nimport { OrganigramNode, OrganigramTreeNode } from './organigram-tree-node';\nimport { OrganigramRowsPipe } from './organigram-rows.pipe';\nimport { OrganigramIntl } from './organigram-intl';\n\n@Component({\n selector: 'app-organigram',\n templateUrl: './organigram.component.html',\n styleUrls: ['./organigram.component.scss'],\n animations: [\n trigger('toggleTreeNode', [\n transition(':enter', [\n style({ height: 0, width: 0, opacity: 0 }),\n animate('0.2s', style({ height: '*', width: '*' })),\n animate('0.2s 0.2s', style({ opacity: 1 })),\n ]),\n transition(':leave', [\n style({ height: '*', width: '*', opacity: 1 }),\n animate('0.2s', style({ opacity: 0 })),\n animate('0.2s 0.2s', style({ height: 0, width: 0 })),\n ]),\n ]),\n ],\n changeDetection: ChangeDetectionStrategy.Eager,\n imports: [CommonModule, OrganigramRowsPipe],\n})\nexport class OrganigramComponent<T = unknown> implements OnDestroy {\n readonly intl = inject(OrganigramIntl);\n dragging = false;\n private dragOrigin: { x: number; y: number } | null = null;\n private suppressClick = false;\n private destroyed = false;\n private treeVersion = 0;\n private scrollRender?: AfterRenderRef;\n readonly pendingNodes = signal<ReadonlySet<OrganigramTreeNode<T>>>(new Set());\n readonly nodeErrors = signal<ReadonlyMap<OrganigramTreeNode<T>, string>>(new Map());\n private readonly highlightedConnectors = new Set<HTMLElement>();\n private pathObserver?: ResizeObserver;\n private hoveredNode: OrganigramTreeNode<T> | null = null;\n private readonly injector = inject(Injector);\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n @HostListener('mousedown', ['$event'])\n onMouseDown(event: MouseEvent): void {\n this.suppressClick = false;\n if (event.button !== 0 || (event.target as HTMLElement).closest('button, input, a, mat-checkbox')) return;\n this.dragOrigin = { x: event.clientX, y: event.clientY };\n }\n\n @HostListener('mousemove', ['$event'])\n onMouseMove(event: MouseEvent): void {\n if (!this.dragOrigin) return;\n if (!this.dragging && Math.hypot(event.clientX - this.dragOrigin.x, event.clientY - this.dragOrigin.y) < 5) return;\n this.dragging = true;\n this.suppressClick = true;\n this.scrollRef?.nativeElement.scrollBy({ top: -event.movementY, left: -event.movementX });\n event.preventDefault();\n }\n\n @HostListener('document:mouseup')\n @HostListener('window:blur')\n onMouseUp(): void {\n this.dragOrigin = null;\n this.dragging = false;\n }\n\n @ViewChild('scroll')\n scrollRef?: ElementRef<HTMLElement>;\n\n @Input('hideRoot')\n set setHideRoot(hideRoot: unknown) {\n this.hideRoot = hideRoot !== false;\n }\n hideRoot = false;\n\n @Input('tree')\n set setTree(tree: OrganigramNode<T> | OrganigramTreeNode<T> | null | undefined) {\n this.treeVersion++;\n this.scrollRender?.destroy();\n this.pendingNodes.set(new Set());\n this.nodeErrors.set(new Map());\n this.highlightParents(null);\n this.tree = !tree ? null : tree instanceof OrganigramTreeNode ? tree : new OrganigramTreeNode<T>(tree);\n }\n tree: OrganigramTreeNode<T> | null = null;\n\n @Input()\n nodeTmpl!: TemplateRef<{ node: OrganigramTreeNode<T> }>;\n\n @Input('click')\n clickHandler?: (node: OrganigramTreeNode<T>) => Promise<unknown>;\n\n nbChildByRow = 5;\n\n highlightParents(node: OrganigramTreeNode<T> | null): void {\n this.pathObserver?.disconnect();\n this.hoveredNode = node;\n this.paintParentPath();\n if (!node) return;\n this.pathObserver ??= new ResizeObserver(() => this.paintParentPath());\n for (const connector of this.highlightedConnectors) {\n this.pathObserver.observe(connector.parentElement!);\n }\n }\n\n private paintParentPath(): void {\n for (const element of this.highlightedConnectors) {\n element.classList.remove('path-vertical');\n element.style.removeProperty('--path-horizontal-color');\n }\n this.highlightedConnectors.clear();\n for (let child = this.hoveredNode; child?.parent; child = child.parent) {\n const childElement = document.getElementById(child.id);\n const parentElement = document.getElementById(child.parent.id);\n if (!childElement || !parentElement || !this.host.nativeElement.contains(parentElement) ||\n !parentElement.offsetParent) break;\n const row = childElement.closest<HTMLElement>('.node-block-children-row');\n const group = row?.parentElement;\n if (!row || !group) break;\n const rows = Array.from(group.querySelectorAll<HTMLElement>(':scope > .node-block-children-row'));\n const rowIndex = rows.indexOf(row);\n const parentX = parentElement.getBoundingClientRect().left + parentElement.offsetWidth / 2;\n const childX = childElement.getBoundingClientRect().left + childElement.offsetWidth / 2;\n this.colorVertical(childElement.parentElement?.querySelector<HTMLElement>(':scope > .node-block-top'));\n this.colorVertical(parentElement.querySelector<HTMLElement>(':scope > .node-container-bottom'));\n const groupTop = group.querySelector<HTMLElement>(':scope > .node-block-children-top');\n this.colorVertical(groupTop);\n if (rowIndex === 0) {\n this.colorRow(row, parentX, childX);\n if (groupTop) this.colorHorizontal(groupTop, parentX, childX);\n } else {\n const railX = rows[0].getBoundingClientRect().left;\n this.colorRow(rows[0], parentX, railX);\n if (groupTop) this.colorHorizontal(groupTop, parentX, railX);\n for (const previousRow of rows.slice(0, rowIndex)) {\n this.colorVertical(previousRow.querySelector<HTMLElement>(':scope > .node-block > .node-block-left'));\n }\n this.colorRow(row, railX, childX);\n }\n }\n }\n\n private colorVertical(element: HTMLElement | null | undefined): void {\n if (!element) return;\n element.classList.add('path-vertical');\n this.highlightedConnectors.add(element);\n }\n\n private colorRow(row: HTMLElement, from: number, to: number): void {\n for (const element of row.querySelectorAll<HTMLElement>(':scope > .node-block > .node-block-top')) {\n this.colorHorizontal(element, from, to);\n }\n }\n\n private colorHorizontal(element: HTMLElement, from: number, to: number): void {\n const style = getComputedStyle(element, '::before');\n if (style.content === 'none') return;\n const bounds = element.getBoundingClientRect();\n const offset = style.left.endsWith('%') ? parseFloat(style.left) * bounds.width / 100 : parseFloat(style.left);\n const width = parseFloat(style.width);\n const start = Math.max(0, Math.min(from, to) - bounds.left - offset);\n const end = Math.min(width, Math.max(from, to) - bounds.left - offset);\n if (end <= start || !Number.isFinite(width)) return;\n element.style.setProperty('--path-horizontal-color', `linear-gradient(to right,\n var(--ngx-mat-organigram-connector, #09293c) ${start}px, var(--ngx-mat-organigram-highlight, #e73452) ${start}px,\n var(--ngx-mat-organigram-highlight, #e73452) ${end}px, var(--ngx-mat-organigram-connector, #09293c) ${end}px)`);\n this.highlightedConnectors.add(element);\n }\n\n ngOnDestroy(): void {\n this.highlightParents(null);\n this.destroyed = true;\n this.treeVersion++;\n this.scrollRender?.destroy();\n }\n\n onKeydown(event: KeyboardEvent, node: OrganigramTreeNode<T>): void {\n if (event.target !== event.currentTarget || (event.key !== 'Enter' && event.key !== ' ')) return;\n event.preventDefault();\n void this.onClick(node);\n }\n\n async onClick(node: OrganigramTreeNode<T>, event?: MouseEvent): Promise<void> {\n if (event && (this.suppressClick || (event.target as HTMLElement).closest('button, input, a, mat-checkbox'))) return;\n if (this.destroyed || this.pendingNodes().has(node)) return;\n const version = this.treeVersion;\n this.pendingNodes.update(pending => new Set([...pending, node]));\n this.nodeErrors.update(errors => { const next = new Map(errors); next.delete(node); return next; });\n try {\n if (node.onClick) {\n const children = await node.onClick(node);\n if (this.destroyed || version !== this.treeVersion) return;\n if (Array.isArray(children)) {\n for (const child of children) node.addChild(child);\n node.hasChildren = node.children.length > 0;\n node.hideChildren = false;\n }\n } else if (this.clickHandler) {\n await this.clickHandler(node);\n } else if (node.hasChildren) node.hideChildren = !node.hideChildren;\n if (this.destroyed || version !== this.treeVersion) return;\n this.scrollToNode(node);\n } catch {\n if (!this.destroyed && version === this.treeVersion) {\n this.nodeErrors.update(errors => new Map(errors).set(node, this.intl.messages().loadError));\n }\n } finally {\n if (!this.destroyed && version === this.treeVersion) {\n this.pendingNodes.update(pending => { const next = new Set(pending); next.delete(node); return next; });\n }\n }\n }\n\n private scrollToNode(node: OrganigramTreeNode<T>): void {\n this.scrollRender?.destroy();\n this.scrollRender = afterNextRender(() => {\n if (this.destroyed) return;\n if (this.hoveredNode) this.highlightParents(this.hoveredNode);\n const element = document.getElementById(node.id);\n if (element && this.host.nativeElement.contains(element)) {\n element.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'nearest' });\n }\n }, { injector: this.injector });\n }\n}\n","<!-- @format -->\n\n<div\n id=\"scroll\"\n #scroll\n [class.dragging]=\"dragging\">\n @if (tree) {\n <div id=\"container\" [class.hide-root]=\"hideRoot\">\n <ng-container\n *ngTemplateOutlet=\"\n nodeBlock;\n context: { depth: 0, node: tree, class: { top: true, bottom: true, left: true, right: true } }\n \"></ng-container>\n </div>\n }\n</div>\n\n<ng-template #nodeBlock let-depth=\"depth\" let-node=\"node\" let-class=\"class\">\n <div class=\"node-block\" [class.depth-even]=\"depth % 2\">\n <div class=\"node-block-top\" [class]=\"class\"></div>\n <div class=\"node-block-left\" [class]=\"class\"></div>\n <div\n [id]=\"node.id\"\n class=\"node-container\"\n [class]=\"class\"\n [attr.role]=\"node.hasChildren || node.onClick || clickHandler ? 'button' : null\"\n [attr.tabindex]=\"node.hasChildren || node.onClick || clickHandler ? 0 : null\"\n [attr.aria-expanded]=\"node.hasChildren ? !node.hideChildren : null\"\n [attr.aria-busy]=\"pendingNodes().has(node)\"\n (mouseenter)=\"highlightParents(node)\"\n (mouseleave)=\"highlightParents(null)\"\n (keydown)=\"onKeydown($event, node)\"\n (click)=\"onClick(node, $event)\">\n <ng-container *ngTemplateOutlet=\"nodeTmpl; context: { node: node }\"></ng-container>\n @if (!node.hideChildren && node.children?.length) {\n <div @toggleTreeNode class=\"node-container-bottom\" [class]=\"class\"></div>\n }\n </div>\n @if (nodeErrors().get(node); as message) {\n <div class=\"node-error\" role=\"alert\">\n <span>{{ message }}</span>\n <button type=\"button\" (click)=\"onClick(node)\">{{ intl.messages().retry }}</button>\n </div>\n }\n @if (!node.hideChildren && node.children?.length) {\n <div @toggleTreeNode class=\"node-block-children\" [class.depth-even]=\"depth % 2\">\n <div class=\"node-block-children-top\" [class]=\"class\" [class.multiple-row]=\"node.children.length > 4\"></div>\n @for (\n row of node.children | organigramRows: nbChildByRow;\n track row;\n let rowIndex = $index;\n let top = $first;\n let bottom = $last\n ) {\n <div class=\"node-block-children-row\" [class.top]=\"top\" [class.bottom]=\"bottom\">\n @for (child of row; track child; let index = $index; let left = $first; let right = $last) {\n <ng-container\n *ngTemplateOutlet=\"\n nodeBlock;\n context: {\n depth: depth + 1,\n node: child,\n class: {\n rowIndex: rowIndex,\n index: index,\n even: index % 2,\n top: top,\n bottom: bottom,\n left: left,\n right: right,\n },\n }\n \">\n </ng-container>\n }\n </div>\n }\n </div>\n }\n </div>\n</ng-template>\n","import { NgModule } from '@angular/core';\nimport { OrganigramComponent } from './organigram.component';\n\n@NgModule({ imports: [OrganigramComponent], exports: [OrganigramComponent] })\nexport class OrganigramModule {}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,34 @@
1
1
  {
2
2
  "name": "@eherve/angular-material-organigram",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "22.0.0",
4
+ "author": "Eric Herve <eric.herve.95@gmail.com>",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/eherve/angular-material-extended.git"
8
+ },
9
+ "private": false,
10
+ "publishConfig": {
11
+ "access": "public"
12
+ },
13
+ "peerDependencies": {
14
+ "@angular/animations": "^22.0.0",
15
+ "@angular/common": "^22.0.0",
16
+ "@angular/core": "^22.0.0"
17
+ },
18
+ "dependencies": {
19
+ "tslib": "^2.3.0"
20
+ },
21
+ "sideEffects": false,
22
+ "type": "module",
23
+ "module": "fesm2022/eherve-angular-material-organigram.mjs",
24
+ "typings": "types/eherve-angular-material-organigram.d.ts",
25
+ "exports": {
26
+ "./package.json": {
27
+ "default": "./package.json"
28
+ },
29
+ ".": {
30
+ "types": "./types/eherve-angular-material-organigram.d.ts",
31
+ "default": "./fesm2022/eherve-angular-material-organigram.mjs"
32
+ }
33
+ }
6
34
  }
@@ -0,0 +1,101 @@
1
+ import * as i0 from "@angular/core";
2
+ import { ElementRef, OnDestroy, TemplateRef } from "@angular/core";
3
+ export interface OrganigramNode<T = unknown> {
4
+ type: string;
5
+ entity?: T | null;
6
+ hasChildren?: boolean;
7
+ children?: readonly OrganigramNode<T>[];
8
+ hideChildren?: boolean;
9
+ selected?: boolean;
10
+ onClick?: (node: OrganigramTreeNode<T>) => Promise<readonly OrganigramNode<T>[] | void>;
11
+ }
12
+ export declare class OrganigramTreeNode<T = unknown> implements OrganigramNode<T> {
13
+ readonly id: string;
14
+ type: string;
15
+ entity?: T | null;
16
+ hasChildren?: boolean;
17
+ hideChildren?: boolean;
18
+ selected?: boolean;
19
+ parent?: OrganigramTreeNode<T>;
20
+ depth: number;
21
+ children: OrganigramTreeNode<T>[];
22
+ onClick?: (node: OrganigramTreeNode<T>) => Promise<readonly OrganigramNode<T>[] | void>;
23
+ constructor(node: OrganigramNode<T>, depth?: number);
24
+ addChild(node: OrganigramNode<T>): void;
25
+ private setDepth;
26
+ getParent(index?: number): OrganigramTreeNode<T> | null;
27
+ }
28
+ export interface OrganigramMessages {
29
+ loadError: string;
30
+ retry: string;
31
+ }
32
+ export declare class OrganigramIntl {
33
+ readonly messages: import("@angular/core").WritableSignal<OrganigramMessages>;
34
+ static ɵfac: i0.ɵɵFactoryDeclaration<OrganigramIntl, never>;
35
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
36
+ }
37
+ declare namespace organigram_component_d_exports {
38
+ export { OrganigramComponent };
39
+ }
40
+ export declare class OrganigramComponent<T = unknown> implements OnDestroy {
41
+ readonly intl: OrganigramIntl;
42
+ dragging: boolean;
43
+ private dragOrigin;
44
+ private suppressClick;
45
+ private destroyed;
46
+ private treeVersion;
47
+ private scrollRender?;
48
+ readonly pendingNodes: import("@angular/core").WritableSignal<ReadonlySet<OrganigramTreeNode<T>>>;
49
+ readonly nodeErrors: import("@angular/core").WritableSignal<ReadonlyMap<OrganigramTreeNode<T>, string>>;
50
+ private readonly highlightedConnectors;
51
+ private pathObserver?;
52
+ private hoveredNode;
53
+ private readonly injector;
54
+ private readonly host;
55
+ onMouseDown(event: MouseEvent): void;
56
+ onMouseMove(event: MouseEvent): void;
57
+ onMouseUp(): void;
58
+ scrollRef?: ElementRef<HTMLElement>;
59
+ set setHideRoot(hideRoot: unknown);
60
+ hideRoot: boolean;
61
+ set setTree(tree: OrganigramNode<T> | OrganigramTreeNode<T> | null | undefined);
62
+ tree: OrganigramTreeNode<T> | null;
63
+ nodeTmpl: TemplateRef<{
64
+ node: OrganigramTreeNode<T>;
65
+ }>;
66
+ clickHandler?: (node: OrganigramTreeNode<T>) => Promise<unknown>;
67
+ nbChildByRow: number;
68
+ highlightParents(node: OrganigramTreeNode<T> | null): void;
69
+ private paintParentPath;
70
+ private colorVertical;
71
+ private colorRow;
72
+ private colorHorizontal;
73
+ ngOnDestroy(): void;
74
+ onKeydown(event: KeyboardEvent, node: OrganigramTreeNode<T>): void;
75
+ onClick(node: OrganigramTreeNode<T>, event?: MouseEvent): Promise<void>;
76
+ private scrollToNode;
77
+ static ɵfac: i0.ɵɵFactoryDeclaration<OrganigramComponent<any>, never>;
78
+ static ɵcmp: i0.ɵɵComponentDeclaration<OrganigramComponent<any>, "app-organigram", never, {
79
+ "setHideRoot": {
80
+ "alias": "hideRoot";
81
+ "required": false;
82
+ };
83
+ "setTree": {
84
+ "alias": "tree";
85
+ "required": false;
86
+ };
87
+ "nodeTmpl": {
88
+ "alias": "nodeTmpl";
89
+ "required": false;
90
+ };
91
+ "clickHandler": {
92
+ "alias": "click";
93
+ "required": false;
94
+ };
95
+ }, {}, never, never, true, never>;
96
+ }
97
+ export declare class OrganigramModule {
98
+ static ɵfac: i0.ɵɵFactoryDeclaration<OrganigramModule, never>;
99
+ static ɵmod: i0.ɵɵNgModuleDeclaration<OrganigramModule, never, [typeof OrganigramComponent], [typeof OrganigramComponent]>;
100
+ static ɵinj: i0.ɵɵInjectorDeclaration<OrganigramModule>;
101
+ }