@ngutil/layout 0.0.63 → 0.0.64

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.
@@ -1,36 +1,37 @@
1
- import { BehaviorSubject, map, shareReplay, ReplaySubject, combineLatest, switchMap, of, Subject, startWith, scan, tap, distinctUntilChanged, finalize } from 'rxjs';
1
+ import { BehaviorSubject, map, shareReplay, switchMap, Subject, scan, tap, distinctUntilChanged, finalize, of } from 'rxjs';
2
2
  import * as i0 from '@angular/core';
3
- import { Component, HostBinding, inject, ElementRef, ViewChild, Input, Output, ChangeDetectionStrategy, ContentChild, ContentChildren, NgModule, Injectable, TemplateRef, Directive, ViewContainerRef, Injector, signal, output, effect, contentChildren, input, computed } from '@angular/core';
4
- import { NumberWithUnit, Destructible, coerceBoolAttr, FastDOM } from '@ngutil/common';
3
+ import { Component, input, inject, ElementRef, model, computed, viewChild, contentChildren, NgModule, Injectable, TemplateRef, Directive, ViewContainerRef, Injector, signal, output, effect } from '@angular/core';
4
+ import { toObservable, takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
5
+ import { coerceBoolAttr, Destructible } from '@ngutil/common';
5
6
  import { DimensionWatcher, Duration, Ease } from '@ngutil/style';
6
7
  import { trigger, state, style, transition, animate } from '@angular/animations';
7
8
  import * as i1 from '@angular/common';
8
9
  import { CommonModule } from '@angular/common';
9
10
  import { clamp } from 'lodash';
10
11
 
11
- /**
12
- * -----------------------------------------------
13
- * | TOP:LEFT | TOP:CENTER | TOP:RIGHT |
14
- * -----------------------------------------------
15
- * | MIDDLE:LEFT | MIDDLE:CENTER | MIDDLE:RIGH |
16
- * -----------------------------------------------
17
- * | BOTTOMN:LEFT | BOTTOM:CENTER | BOTTOM:RIGHT |
18
- * -----------------------------------------------
19
- */
20
12
  const vertical = ["top", "middle", "bottom"];
21
13
  const horizontal = ["left", "center", "right"];
14
+ const L9GridTopLeft = { row: 1, col: 1 };
22
15
  class L9Cell {
23
16
  static coerce(value) {
24
- const [v, h] = value.split(":");
25
- if (vertical.includes(v) && horizontal.includes(h)) {
26
- return new L9Cell(v, h);
17
+ const [v1, v2] = value.split(":");
18
+ const v = vertical.includes(v1) ? v1 : v2;
19
+ const h = horizontal.includes(v1) ? v1 : v2;
20
+ if (v === h) {
21
+ throw new Error(`Invalid cell value: ${value}`);
27
22
  }
28
- throw new Error(`Invalid cell value: ${value}`);
23
+ return new L9Cell(v, h);
29
24
  }
30
25
  constructor(v, h) {
31
26
  this.v = v;
32
27
  this.h = h;
33
28
  }
29
+ intoGridArea(gridTopLeft = L9GridTopLeft) {
30
+ return `${gridTopLeft.row + vertical.indexOf(this.v)}/${gridTopLeft.col + horizontal.indexOf(this.h)}`;
31
+ }
32
+ isEq(other) {
33
+ return this.v === other.v && this.h === other.h;
34
+ }
34
35
  }
35
36
  class L9Range {
36
37
  static coerce(value) {
@@ -60,18 +61,40 @@ class L9Range {
60
61
  }
61
62
  return false;
62
63
  }
64
+ intoGridArea(gridTopLeft = L9GridTopLeft) {
65
+ const start = this.cells[0];
66
+ const end = this.cells[this.cells.length - 1];
67
+ const endTopLeft = { row: gridTopLeft.row + 1, col: gridTopLeft.col + 1 };
68
+ return `${start.intoGridArea(gridTopLeft)}/${end.intoGridArea(endTopLeft)}`;
69
+ }
70
+ intoRect() {
71
+ const start = this.cells[0];
72
+ const end = this.cells[this.cells.length - 1];
73
+ const x = horizontal.indexOf(start.h);
74
+ const y = vertical.indexOf(start.v);
75
+ return { x, y, width: horizontal.indexOf(end.h) - x + 1, height: vertical.indexOf(end.v) - y + 1 };
76
+ }
63
77
  #determineOrient() {
64
- const { v: sv, h: sh } = this.cells[0];
65
- const { v: ev, h: eh } = this.cells[this.cells.length - 1];
66
- if (sv === ev) {
78
+ const rect = this.intoRect();
79
+ if (rect.width === rect.height) {
80
+ // corner
81
+ if (rect.x === rect.y) {
82
+ return "vertical";
83
+ }
84
+ if (rect.x === 0 || rect.x === 2) {
85
+ return "vertical";
86
+ }
87
+ else if (rect.y === 0 || rect.y === 2) {
88
+ return "horizontal";
89
+ }
90
+ }
91
+ else if (rect.width > rect.height) {
67
92
  return "horizontal";
68
93
  }
69
- else if (sh === eh) {
94
+ else if (rect.height > rect.width) {
70
95
  return "vertical";
71
96
  }
72
- else {
73
- return "rect";
74
- }
97
+ return "vertical";
75
98
  }
76
99
  }
77
100
  function parse(value) {
@@ -139,400 +162,125 @@ class L9State {
139
162
 
140
163
  class DockingContentComponent {
141
164
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DockingContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
142
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.6", type: DockingContentComponent, isStandalone: true, selector: "nu-docking-content", exportAs: ["nuDockingContent"], ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, styles: [":host{display:flex;flex-flow:column nowrap;align-items:stretch;box-sizing:border-box;flex:1;overflow:hidden}\n"] }); }
165
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.6", type: DockingContentComponent, isStandalone: true, selector: "nu-docking-content", exportAs: ["nuDockingContent"], ngImport: i0, template: `<ng-content></ng-content>`, isInline: true, styles: [":host{grid-column:2;grid-row:2;display:grid;grid-template-columns:1fr;grid-template-rows:1fr;align-items:stretch;justify-items:stretch;overflow:hidden;position:relative;z-index:10}\n"] }); }
143
166
  }
144
167
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DockingContentComponent, decorators: [{
145
168
  type: Component,
146
- args: [{ standalone: true, selector: "nu-docking-content", exportAs: "nuDockingContent", template: `<ng-content></ng-content>`, styles: [":host{display:flex;flex-flow:column nowrap;align-items:stretch;box-sizing:border-box;flex:1;overflow:hidden}\n"] }]
169
+ args: [{ selector: "nu-docking-content", exportAs: "nuDockingContent", standalone: true, template: `<ng-content></ng-content>`, styles: [":host{grid-column:2;grid-row:2;display:grid;grid-template-columns:1fr;grid-template-rows:1fr;align-items:stretch;justify-items:stretch;overflow:hidden;position:relative;z-index:10}\n"] }]
147
170
  }] });
148
171
 
149
172
  class DockingBackdropComponent {
150
173
  constructor() {
151
- this.state = "hidden";
174
+ this.visible = input.required();
152
175
  }
153
176
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DockingBackdropComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
154
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.6", type: DockingBackdropComponent, isStandalone: true, selector: "nu-docking-backdrop", host: { properties: { "[attr.state]": "this.state" } }, ngImport: i0, template: ``, isInline: true, styles: [":host{display:flex;flex-direction:column;align-items:stretch;position:absolute;inset:0;transition:opacity var(---docking-layout-anim-duration) var(---docking-layout-anim-ease);z-index:-1;background-color:var(---docking-layout-backdrop-color)}:host[state=hidden]{animation:var(---docking-layout-anim-duration) var(---docking-layout-anim-ease) hide;animation-fill-mode:forwards;pointer-events:none;touch-action:none;opacity:0}:host[state=visible]{visibility:visible;opacity:.3}@keyframes hide{99%{visibility:visible}to{visibility:hidden}}\n"] }); }
177
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.6", type: DockingBackdropComponent, isStandalone: true, selector: "nu-docking-backdrop", inputs: { visible: { classPropertyName: "visible", publicName: "visible", isSignal: true, isRequired: true, transformFunction: null } }, host: { properties: { "attr.state": "visible() ? 'visible' : 'hidden'" } }, ngImport: i0, template: ``, isInline: true, styles: [":host{display:flex;flex-direction:column;align-items:stretch;position:absolute;inset:0;transition:opacity .2s cubic-bezier(0,0,.2,1);z-index:200;background-color:#000}:host[state=hidden]{animation:.2s cubic-bezier(0,0,.2,1) hide;animation-fill-mode:forwards;pointer-events:none;touch-action:none;opacity:0}:host[state=visible]{visibility:visible;opacity:.7}@keyframes hide{99%{visibility:visible}to{visibility:hidden}}\n"] }); }
155
178
  }
156
179
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DockingBackdropComponent, decorators: [{
157
180
  type: Component,
158
- args: [{ standalone: true, selector: "nu-docking-backdrop", template: ``, styles: [":host{display:flex;flex-direction:column;align-items:stretch;position:absolute;inset:0;transition:opacity var(---docking-layout-anim-duration) var(---docking-layout-anim-ease);z-index:-1;background-color:var(---docking-layout-backdrop-color)}:host[state=hidden]{animation:var(---docking-layout-anim-duration) var(---docking-layout-anim-ease) hide;animation-fill-mode:forwards;pointer-events:none;touch-action:none;opacity:0}:host[state=visible]{visibility:visible;opacity:.3}@keyframes hide{99%{visibility:visible}to{visibility:hidden}}\n"] }]
159
- }], propDecorators: { state: [{
160
- type: HostBinding,
161
- args: ["[attr.state]"]
162
- }] } });
181
+ args: [{ standalone: true, selector: "nu-docking-backdrop", host: {
182
+ "[attr.state]": "visible() ? 'visible' : 'hidden'"
183
+ }, template: ``, styles: [":host{display:flex;flex-direction:column;align-items:stretch;position:absolute;inset:0;transition:opacity .2s cubic-bezier(0,0,.2,1);z-index:200;background-color:#000}:host[state=hidden]{animation:.2s cubic-bezier(0,0,.2,1) hide;animation-fill-mode:forwards;pointer-events:none;touch-action:none;opacity:0}:host[state=visible]{visibility:visible;opacity:.7}@keyframes hide{99%{visibility:visible}to{visibility:hidden}}\n"] }]
184
+ }] });
163
185
 
164
186
  const DEFAULT_POSITION = L9Range.coerce("left");
165
- const HIDDEN_SIZE = new NumberWithUnit(0, "px");
166
- const AUTO_SIZE = NumberWithUnit.coerce("auto");
167
- class DockingPanelComponent extends Destructible {
168
- #dimWatcher;
169
- set positionInput(val) {
170
- const coerced = L9Range.coerce(val);
171
- if (coerced.orient === "rect") {
172
- throw new Error(`Invalid position value: ${val}`);
173
- }
174
- if (!this.position.value.isEq(coerced)) {
175
- this.position.next(coerced);
176
- }
177
- }
178
- set stateInput(val) {
179
- if (this.state.value !== val) {
180
- this.state.next(val);
181
- }
182
- }
183
- set modeInput(val) {
184
- if (this.mode.value !== val) {
185
- this.mode.next(val);
186
- }
187
- }
188
- set fullSizeInput(val) {
189
- const coerced = NumberWithUnit.coerce(val, "px");
190
- if (this.#fullSize.value !== coerced) {
191
- this.#fullSize.next(coerced);
192
- }
193
- }
194
- #fullSize;
195
- set miniSizeInput(val) {
196
- const coerced = NumberWithUnit.coerce(val, "px");
197
- if (this.#miniSize.value !== coerced) {
198
- this.#miniSize.next(coerced);
199
- }
200
- }
201
- #miniSize;
202
- set minimizable(val) {
203
- this.#minimizable = coerceBoolAttr(val);
204
- this.#minimizableAuto = false;
205
- }
206
- get minimizable() {
207
- return this.#minimizable;
208
- }
209
- #minimizable;
210
- #minimizableAuto;
211
- set backdrop(val) {
212
- this.#backdrop = coerceBoolAttr(val);
213
- }
214
- get backdrop() {
215
- return this.#backdrop;
216
- }
217
- #backdrop;
218
- #contentSize;
219
- #autoSize;
220
- // TODO: better animation handling in min -> hidden -> min -> full
187
+ class DockingPanelComponent {
221
188
  constructor() {
222
- super();
223
- this.el = inject((ElementRef));
224
189
  this.#dimWatcher = inject(DimensionWatcher);
225
- this.position = new BehaviorSubject(DEFAULT_POSITION);
226
- this.state = new BehaviorSubject("full");
227
- this.mode = new BehaviorSubject("rigid");
228
- this.#fullSize = new BehaviorSubject(AUTO_SIZE);
229
- this.#miniSize = new BehaviorSubject(HIDDEN_SIZE);
230
- this.#minimizable = false;
231
- this.#minimizableAuto = true;
232
- this.#backdrop = false;
233
- this.#contentSize = new ReplaySubject(1);
234
- this.#autoSize = combineLatest({
235
- dim: this.#contentSize,
236
- pos: this.position
237
- }).pipe(map(({ dim, pos }) => {
238
- if (pos.orient === "horizontal") {
239
- return dim.height;
240
- }
241
- else {
242
- return dim.width;
243
- }
244
- }), shareReplay(1));
245
- this.fullSize = this.#fullSize.pipe(switchMap(size => {
246
- if (size.unit === "auto") {
247
- return this.#autoSize;
248
- }
249
- else {
250
- return of(size);
251
- }
252
- }), shareReplay(1));
253
- this.miniSize = this.#miniSize.pipe(switchMap(size => {
254
- if (size.unit === "auto") {
255
- return this.#autoSize;
256
- }
257
- else {
258
- return of(size);
259
- }
260
- }), shareReplay(1));
261
- this.changes = combineLatest({
262
- position: this.position,
263
- state: this.state,
264
- mode: this.mode,
265
- fullSize: this.fullSize,
266
- miniSize: this.miniSize,
267
- contentSize: this.#contentSize
190
+ this.el = inject(ElementRef);
191
+ this.position = input(DEFAULT_POSITION, { transform: L9Range.coerce });
192
+ // TODO: linkedSignal
193
+ this.opened = model(false);
194
+ this._opened = computed(() => coerceBoolAttr(this.opened()));
195
+ this.mode = input("rigid");
196
+ this.maxSize = input(undefined);
197
+ this.backdrop = input(false);
198
+ this.gridArea = computed(() => this.position().intoGridArea());
199
+ this.orient = computed(() => this.position().orient);
200
+ this.side = computed(() => {
201
+ const pos = this.position();
202
+ return pos.orient === "horizontal" ? pos.cells[0].v : pos.cells[0].h;
268
203
  });
269
- this.d.sub(this.changes).subscribe(changes => {
270
- if (this.#minimizableAuto) {
271
- this.#minimizable = this.#miniSize.value.value !== 0;
272
- }
273
- FastDOM.setAttributes(this.el.nativeElement, {
274
- state: changes.state,
275
- orient: changes.position.orient,
276
- mode: changes.mode,
277
- side: changes.position.orient === "horizontal" ? changes.position.cells[0].v : changes.position.cells[0].h
278
- });
279
- const isHorizontal = changes.position.orient === "horizontal";
280
- let w = null;
281
- let h = null;
282
- // TODO: when change state from mini -> hidden, currently wrong behavior
283
- // the good behavior is to not gain fullSize ang go to hidden
284
- if (changes.state === "mini") {
285
- if (isHorizontal) {
286
- h = changes.miniSize.unit === "auto" ? changes.contentSize.height : changes.miniSize;
287
- }
288
- else {
289
- w = changes.miniSize.unit === "auto" ? changes.contentSize.width : changes.miniSize;
290
- }
291
- }
292
- else {
293
- if (isHorizontal) {
294
- h = changes.fullSize.unit === "auto" ? changes.contentSize.height : changes.fullSize;
295
- }
296
- else {
297
- w = changes.fullSize.unit === "auto" ? changes.contentSize.width : changes.fullSize;
298
- }
299
- }
300
- FastDOM.setStyle(this.el.nativeElement, {
301
- "--docking-panel-w": w != null ? `${w}` : null,
302
- "--docking-panel-h": h != null ? `${h}` : null,
303
- "--docking-panel-content-w": changes.contentSize.width,
304
- "--docking-panel-content-h": changes.contentSize.height
305
- }, () => FastDOM.setAttributes(this.el.nativeElement, { animate: "" }));
204
+ this.content = viewChild.required("content", { read: ElementRef });
205
+ this.dimension$ = toObservable(this.content).pipe(switchMap(content => this.#dimWatcher.watch(content, "border-box")), takeUntilDestroyed());
206
+ this.dimension = toSignal(this.dimension$);
207
+ this.contentSize = computed(() => {
208
+ const dim = this.dimension();
209
+ if (!dim) {
210
+ return 0;
211
+ }
212
+ return this.orient() === "horizontal" ? dim.height : dim.width;
306
213
  });
307
214
  }
308
- ngAfterViewInit() {
309
- this.d
310
- .sub(this.#dimWatcher.watch(this.content, "scroll-box"))
311
- .pipe(map(dim => {
312
- return {
313
- width: new NumberWithUnit(dim.width, "px"),
314
- height: new NumberWithUnit(dim.height, "px")
315
- };
316
- }))
317
- .subscribe(this.#contentSize);
318
- }
215
+ #dimWatcher;
216
+ // readonly backdropSize = computed(() => {
217
+ // const mode = this.backdrop()
218
+ // if (mode === true || mode === "full") {
219
+ // return L9Range.coerce("top:left-bottom:right").intoGridArea()
220
+ // } else if (mode === "panel-size") {
221
+ // const pos = this.position()
222
+ // if (pos.orient === "horizontal") {
223
+ // }
224
+ // return ""
225
+ // }
226
+ // return null
227
+ // })
319
228
  open() {
320
- this.state.next("full");
229
+ this.opened.set(true);
321
230
  }
322
231
  close() {
323
- this.state.next("hidden");
324
- }
325
- minimize() {
326
- if (this.minimizable) {
327
- this.state.next("mini");
328
- }
232
+ this.opened.set(false);
329
233
  }
330
234
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DockingPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
331
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.6", type: DockingPanelComponent, isStandalone: true, selector: "nu-docking-panel", inputs: { positionInput: ["position", "positionInput"], stateInput: ["state", "stateInput"], modeInput: ["mode", "modeInput"], fullSizeInput: ["fullSize", "fullSizeInput"], miniSizeInput: ["miniSize", "miniSizeInput"], minimizable: "minimizable", backdrop: "backdrop" }, outputs: { state: "stateChanges" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, read: ElementRef, static: true }], exportAs: ["nuDockingPanel"], usesInheritance: true, ngImport: i0, template: `
332
- <div class="nu-docking-wrapper" #content>
333
- <ng-content></ng-content>
334
- </div>
335
- `, isInline: true, styles: [":host{---docking-panel-t: var(--docking-panel-t, auto);---docking-panel-r: var(--docking-panel-r, auto);---docking-panel-b: var(--docking-panel-b, auto);---docking-panel-l: var(--docking-panel-l, auto);---docking-panel-w: var(--docking-panel-w, auto);---docking-panel-h: var(--docking-panel-h, auto);---docking-panel-content-w: var(--docking-panel-content-w, var(---docking-panel-w));---docking-panel-content-g: var(--docking-panel-content-g, var(---docking-panel-h));display:flex;flex-flow:column nowrap;align-items:stretch;position:absolute;box-sizing:border-box;overflow:hidden;top:var(---docking-panel-t);right:var(---docking-panel-r);bottom:var(---docking-panel-b);left:var(---docking-panel-l);width:var(---docking-panel-w);height:var(---docking-panel-h)}:host[animate]{transition:transform var(---docking-layout-anim-duration) var(---docking-layout-anim-ease),width var(---docking-layout-anim-duration) var(---docking-layout-anim-ease),height var(---docking-layout-anim-duration) var(---docking-layout-anim-ease)}:host[side=top],:host[side=left]{---docking-panel-t-hide: -100%;---docking-panel-t-visible: 0%}:host[side=bottom],:host[side=right]{---docking-panel-t-hide: 100%;---docking-panel-t-visible: 0%}:host[state=hidden]{animation:var(---docking-layout-anim-duration) var(---docking-layout-anim-ease) hide;animation-fill-mode:forwards}:host[state=hidden][orient=horizontal]{transform:translateY(var(---docking-panel-t-hide))}:host[state=hidden][orient=vertical]{transform:translate(var(---docking-panel-t-hide))}:host:not([state=hidden]){visibility:visible}:host:not([state=hidden])[orient=horizontal]{transform:translateY(var(---docking-panel-t-visible))}:host:not([state=hidden])[orient=vertical]{transform:translate(var(---docking-panel-t-visible))}:host .nu-docking-wrapper{display:flex;flex-direction:column;align-items:stretch}:host[orient=horizontal] .nu-docking-wrapper{width:100%;min-width:100%;max-width:100%}:host[orient=vertical] .nu-docking-wrapper{height:100%;min-height:100%;max-height:100%}@keyframes hide{99%{visibility:visible}to{visibility:hidden}}\n"] }); }
235
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "18.2.6", type: DockingPanelComponent, isStandalone: true, selector: "nu-docking-panel", inputs: { position: { classPropertyName: "position", publicName: "position", isSignal: true, isRequired: false, transformFunction: null }, opened: { classPropertyName: "opened", publicName: "opened", isSignal: true, isRequired: false, transformFunction: null }, mode: { classPropertyName: "mode", publicName: "mode", isSignal: true, isRequired: false, transformFunction: null }, maxSize: { classPropertyName: "maxSize", publicName: "maxSize", isSignal: true, isRequired: false, transformFunction: null }, backdrop: { classPropertyName: "backdrop", publicName: "backdrop", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { opened: "openedChange" }, host: { properties: { "style.grid-area": "gridArea()", "style.--nudp-content-size.px": "contentSize()", "attr.state": "_opened() ? 'opened' : 'closed'", "attr.orient": "orient()", "attr.side": "side()", "attr.mode": "mode()" } }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, read: ElementRef, isSignal: true }], exportAs: ["nuDockingPanel"], ngImport: i0, template: `<div class="wrapper" #content><ng-content /></div>`, isInline: true, styles: [":host{--nudp-tx: 0;--nudp-ty: 0;--nudp-t: auto;--nudp-r: auto;--nudp-b: auto;--nudp-l: auto;display:block;position:relative;z-index:100}:host .wrapper{all:inherit;display:grid;grid-template-columns:auto;grid-template-rows:auto;align-items:stretch;justify-items:stretch;position:absolute;top:var(--nudp-t);right:var(--nudp-r);bottom:var(--nudp-b);left:var(--nudp-l);width:auto;height:auto;transition:transform .2s cubic-bezier(0,0,.2,1);transform:translate(var(--nudp-tx),var(--nudp-ty))}:host[mode=rigid]{overflow:clip}:host[mode=rigid][orient=horizontal]{transition:height .2s cubic-bezier(0,0,.2,1);height:var(--nudp-content-size)}:host[mode=rigid][orient=horizontal][state=closed]{height:0px}:host[mode=rigid][orient=vertical]{transition:width .2s cubic-bezier(0,0,.2,1);width:var(--nudp-content-size)}:host[mode=rigid][orient=vertical][state=closed]{width:0}:host[mode=over]{z-index:300}:host[orient=horizontal]{--nudp-l: 0px;--nudp-r: 0px}:host[orient=horizontal][side=top]{--nudp-t: 0px}:host[orient=horizontal][side=top][state=closed]{--nudp-ty: -100%}:host[orient=horizontal][side=bottom]{--nudp-b: 0px}:host[orient=horizontal][side=bottom][state=closed]{--nudp-ty: 100%}:host[orient=horizontal]:not([mode=rigid]){height:0px}:host[orient=vertical]{--nudp-t: 0px;--nudp-b: 0px}:host[orient=vertical][side=left]{--nudp-l: 0px}:host[orient=vertical][side=left][state=closed]{--nudp-tx: -100%}:host[orient=vertical][side=right]{--nudp-r: 0px}:host[orient=vertical][side=right][state=closed]{--nudp-tx: 100%}:host[orient=vertical]:not([mode=rigid]){width:0px}\n"] }); }
336
236
  }
337
237
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DockingPanelComponent, decorators: [{
338
238
  type: Component,
339
- args: [{ standalone: true, selector: "nu-docking-panel", exportAs: "nuDockingPanel", template: `
340
- <div class="nu-docking-wrapper" #content>
341
- <ng-content></ng-content>
342
- </div>
343
- `, styles: [":host{---docking-panel-t: var(--docking-panel-t, auto);---docking-panel-r: var(--docking-panel-r, auto);---docking-panel-b: var(--docking-panel-b, auto);---docking-panel-l: var(--docking-panel-l, auto);---docking-panel-w: var(--docking-panel-w, auto);---docking-panel-h: var(--docking-panel-h, auto);---docking-panel-content-w: var(--docking-panel-content-w, var(---docking-panel-w));---docking-panel-content-g: var(--docking-panel-content-g, var(---docking-panel-h));display:flex;flex-flow:column nowrap;align-items:stretch;position:absolute;box-sizing:border-box;overflow:hidden;top:var(---docking-panel-t);right:var(---docking-panel-r);bottom:var(---docking-panel-b);left:var(---docking-panel-l);width:var(---docking-panel-w);height:var(---docking-panel-h)}:host[animate]{transition:transform var(---docking-layout-anim-duration) var(---docking-layout-anim-ease),width var(---docking-layout-anim-duration) var(---docking-layout-anim-ease),height var(---docking-layout-anim-duration) var(---docking-layout-anim-ease)}:host[side=top],:host[side=left]{---docking-panel-t-hide: -100%;---docking-panel-t-visible: 0%}:host[side=bottom],:host[side=right]{---docking-panel-t-hide: 100%;---docking-panel-t-visible: 0%}:host[state=hidden]{animation:var(---docking-layout-anim-duration) var(---docking-layout-anim-ease) hide;animation-fill-mode:forwards}:host[state=hidden][orient=horizontal]{transform:translateY(var(---docking-panel-t-hide))}:host[state=hidden][orient=vertical]{transform:translate(var(---docking-panel-t-hide))}:host:not([state=hidden]){visibility:visible}:host:not([state=hidden])[orient=horizontal]{transform:translateY(var(---docking-panel-t-visible))}:host:not([state=hidden])[orient=vertical]{transform:translate(var(---docking-panel-t-visible))}:host .nu-docking-wrapper{display:flex;flex-direction:column;align-items:stretch}:host[orient=horizontal] .nu-docking-wrapper{width:100%;min-width:100%;max-width:100%}:host[orient=vertical] .nu-docking-wrapper{height:100%;min-height:100%;max-height:100%}@keyframes hide{99%{visibility:visible}to{visibility:hidden}}\n"] }]
344
- }], ctorParameters: () => [], propDecorators: { content: [{
345
- type: ViewChild,
346
- args: ["content", { read: ElementRef, static: true }]
347
- }], positionInput: [{
348
- type: Input,
349
- args: ["position"]
350
- }], stateInput: [{
351
- type: Input,
352
- args: ["state"]
353
- }], state: [{
354
- type: Output,
355
- args: ["stateChanges"]
356
- }], modeInput: [{
357
- type: Input,
358
- args: ["mode"]
359
- }], fullSizeInput: [{
360
- type: Input,
361
- args: ["fullSize"]
362
- }], miniSizeInput: [{
363
- type: Input,
364
- args: ["miniSize"]
365
- }], minimizable: [{
366
- type: Input,
367
- args: ["minimizable"]
368
- }], backdrop: [{
369
- type: Input,
370
- args: ["backdrop"]
371
- }] } });
239
+ args: [{ selector: "nu-docking-panel", exportAs: "nuDockingPanel", standalone: true, host: {
240
+ "[style.grid-area]": "gridArea()",
241
+ "[style.--nudp-content-size.px]": "contentSize()",
242
+ "[attr.state]": "_opened() ? 'opened' : 'closed'",
243
+ "[attr.orient]": "orient()",
244
+ "[attr.side]": "side()",
245
+ "[attr.mode]": "mode()"
246
+ }, template: `<div class="wrapper" #content><ng-content /></div>`, styles: [":host{--nudp-tx: 0;--nudp-ty: 0;--nudp-t: auto;--nudp-r: auto;--nudp-b: auto;--nudp-l: auto;display:block;position:relative;z-index:100}:host .wrapper{all:inherit;display:grid;grid-template-columns:auto;grid-template-rows:auto;align-items:stretch;justify-items:stretch;position:absolute;top:var(--nudp-t);right:var(--nudp-r);bottom:var(--nudp-b);left:var(--nudp-l);width:auto;height:auto;transition:transform .2s cubic-bezier(0,0,.2,1);transform:translate(var(--nudp-tx),var(--nudp-ty))}:host[mode=rigid]{overflow:clip}:host[mode=rigid][orient=horizontal]{transition:height .2s cubic-bezier(0,0,.2,1);height:var(--nudp-content-size)}:host[mode=rigid][orient=horizontal][state=closed]{height:0px}:host[mode=rigid][orient=vertical]{transition:width .2s cubic-bezier(0,0,.2,1);width:var(--nudp-content-size)}:host[mode=rigid][orient=vertical][state=closed]{width:0}:host[mode=over]{z-index:300}:host[orient=horizontal]{--nudp-l: 0px;--nudp-r: 0px}:host[orient=horizontal][side=top]{--nudp-t: 0px}:host[orient=horizontal][side=top][state=closed]{--nudp-ty: -100%}:host[orient=horizontal][side=bottom]{--nudp-b: 0px}:host[orient=horizontal][side=bottom][state=closed]{--nudp-ty: 100%}:host[orient=horizontal]:not([mode=rigid]){height:0px}:host[orient=vertical]{--nudp-t: 0px;--nudp-b: 0px}:host[orient=vertical][side=left]{--nudp-l: 0px}:host[orient=vertical][side=left][state=closed]{--nudp-tx: -100%}:host[orient=vertical][side=right]{--nudp-r: 0px}:host[orient=vertical][side=right][state=closed]{--nudp-tx: 100%}:host[orient=vertical]:not([mode=rigid]){width:0px}\n"] }]
247
+ }] });
372
248
 
373
- const RIGID_ZINDEX = 100;
374
- const OVER_ZINDEX = RIGID_ZINDEX * 2;
375
- const BACKDROP_ZINDEX = 10000;
376
- class DockingLayoutComponent extends Destructible {
249
+ class DockingLayoutComponent {
377
250
  constructor() {
378
- super(...arguments);
379
- this.#el = inject((ElementRef));
380
- this.contentOnly = false;
381
- this.#reflow = new Subject();
382
- this.#backdropPanel = null;
383
- }
384
- #el;
385
- #reflow;
386
- #backdropPanel;
387
- ngAfterViewInit() {
388
- // eslint-disable-next-line prettier/prettier
389
- this.panels = this.dockingPanels.changes.pipe(startWith(null), map(() => this.dockingPanels.toArray()), shareReplay(1));
390
- this.d
391
- .sub(combineLatest({ panels: this.panels, reflow: this.#reflow.pipe(startWith(null)) }))
392
- .pipe(switchMap(({ panels }) => combineLatest(panels.map(panel => panel.changes.pipe(map(changes => {
393
- return { panel, changes };
394
- }))))))
395
- .subscribe(this.#layout.bind(this));
396
- }
397
- ngOnChanges(changes) {
398
- if ("contentOnly" in changes || "positionMode" in changes) {
399
- this.#reflow.next();
400
- }
401
- }
402
- #layout(entries) {
403
- let paddingTop = 0;
404
- let paddingRight = 0;
405
- let paddingBottom = 0;
406
- let paddingLeft = 0;
407
- let rigidZIndex = RIGID_ZINDEX;
408
- let overZIndex = OVER_ZINDEX;
409
- let backdropZIndex = -1;
410
- this.#backdropPanel = null;
411
- if (this.contentOnly) {
412
- // TODO:...
413
- }
414
- else {
415
- for (const entry of entries) {
416
- const panelState = entry.changes;
417
- const panelSize = panelState.state === "full"
418
- ? panelState.fullSize.value
419
- : panelState.state === "mini"
420
- ? panelState.miniSize.value
421
- : 0;
422
- const isHorizontal = panelState.position.orient === "horizontal";
423
- const isRigid = panelState.mode === "rigid";
424
- let panelTop = null;
425
- let panelRight = null;
426
- let panelBottom = null;
427
- let panelLeft = null;
428
- if (isHorizontal) {
429
- panelLeft = 0;
430
- panelRight = 0;
431
- if (panelState.position.cells[0].v === "top") {
432
- if (isRigid) {
433
- paddingTop = Math.max(paddingTop, panelSize);
434
- }
435
- panelTop = 0;
436
- }
437
- else if (panelState.position.cells[0].v === "bottom") {
438
- if (isRigid) {
439
- paddingBottom = Math.max(paddingBottom, panelSize);
440
- }
441
- panelBottom = 0;
442
- }
443
- }
444
- else {
445
- panelTop = 0;
446
- panelBottom = 0;
447
- if (panelState.position.cells[0].h === "left") {
448
- if (isRigid) {
449
- paddingLeft = Math.max(paddingLeft, panelSize);
450
- }
451
- panelLeft = 0;
452
- }
453
- else if (panelState.position.cells[0].h === "right") {
454
- if (isRigid) {
455
- paddingRight = Math.max(paddingRight, panelSize);
456
- }
457
- panelRight = 0;
458
- }
459
- }
460
- let panelZIndex = isRigid ? (rigidZIndex += 2) : (overZIndex += 2);
461
- if (panelState.state !== "hidden" && entry.panel.backdrop) {
462
- backdropZIndex = BACKDROP_ZINDEX;
463
- panelZIndex = backdropZIndex + 1;
464
- this.#backdropPanel = entry.panel;
465
- }
466
- FastDOM.setStyle(entry.panel.el.nativeElement, {
467
- "z-index": `${panelZIndex}`,
468
- "--docking-panel-t": panelTop != null ? `${panelTop}px` : null,
469
- "--docking-panel-r": panelRight != null ? `${panelRight}px` : null,
470
- "--docking-panel-b": panelBottom != null ? `${panelBottom}px` : null,
471
- "--docking-panel-l": panelLeft != null ? `${panelLeft}px` : null
472
- });
473
- }
474
- FastDOM.setStyle(this.#el.nativeElement, {
475
- "--docking-layout-top": `${paddingTop}px`,
476
- "--docking-layout-right": `${paddingRight}px`,
477
- "--docking-layout-bottom": `${paddingBottom}px`,
478
- "--docking-layout-left": `${paddingLeft}px`
479
- });
480
- if (this.backdropEl) {
481
- FastDOM.setAttributes(this.backdropEl.nativeElement, {
482
- state: backdropZIndex < 0 ? "hidden" : "visible"
483
- });
484
- FastDOM.setStyle(this.backdropEl.nativeElement, { "z-index": `${backdropZIndex}` });
485
- }
486
- }
251
+ /**
252
+ * True if u want to animate panel open/close with `mode="side"`
253
+ */
254
+ // readonly animateSide = input(false)
255
+ this.panels = contentChildren(DockingPanelComponent);
256
+ this.activeOverPanel = computed(() => {
257
+ const panels = this.panels();
258
+ return panels.find(panel => panel.mode() === "over" && panel.opened());
259
+ });
260
+ this.backdropVisible = computed(() => {
261
+ const active = this.activeOverPanel();
262
+ return active != null ? active.backdrop() !== false : false;
263
+ });
487
264
  }
488
- onHideBackdropPanel(event) {
489
- event.preventDefault();
490
- if (this.#backdropPanel) {
491
- this.#backdropPanel.close();
265
+ doCloseActiveOverPanel() {
266
+ const activePanel = this.activeOverPanel();
267
+ if (activePanel) {
268
+ activePanel.close();
492
269
  }
493
270
  }
494
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DockingLayoutComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
495
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.6", type: DockingLayoutComponent, isStandalone: true, selector: "nu-docking", inputs: { contentOnly: "contentOnly" }, queries: [{ propertyName: "contentComponent", first: true, predicate: DockingContentComponent, descendants: true }, { propertyName: "dockingPanels", predicate: DockingPanelComponent }], viewQueries: [{ propertyName: "backdropEl", first: true, predicate: ["backdrop"], descendants: true, read: ElementRef, static: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
496
- <ng-content select="nu-docking-panel"></ng-content>
497
-
498
- @if (!contentComponent) {
499
- <nu-docking-content>
500
- <ng-content></ng-content>
501
- </nu-docking-content>
502
- } @else {
503
- <ng-content select="nu-docking-content"></ng-content>
504
- }
505
-
506
- <nu-docking-backdrop #backdrop (click)="onHideBackdropPanel($event)" />
507
- `, isInline: true, styles: [":host{---docking-layout-top: var(--docking-layout-top, 0px);---docking-layout-right: var(--docking-layout-right, 0px);---docking-layout-bottom: var(--docking-layout-bottom, 0px);---docking-layout-left: var(--docking-layout-left, 0px);---docking-layout-anim-duration: var(--docking-layout-anim-duration, .3s);---docking-layout-anim-ease: var(--docking-layout-anim-ease, cubic-bezier(.4, 0, .2, 1));---docking-layout-backdrop-color: var(--docking-layout-backdrop-color, #000);display:flex;flex-flow:column nowrap;align-items:stretch;position:relative;overflow:hidden;box-sizing:border-box;z-index:0;padding:var(---docking-layout-top) var(---docking-layout-right) var(---docking-layout-bottom) var(---docking-layout-left);transition:padding var(---docking-layout-anim-duration) var(---docking-layout-anim-ease)}\n"], dependencies: [{ kind: "component", type: DockingContentComponent, selector: "nu-docking-content", exportAs: ["nuDockingContent"] }, { kind: "component", type: DockingBackdropComponent, selector: "nu-docking-backdrop" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
271
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DockingLayoutComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
272
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "18.2.6", type: DockingLayoutComponent, isStandalone: true, selector: "nu-docking", queries: [{ propertyName: "panels", predicate: DockingPanelComponent, isSignal: true }], exportAs: ["nuDocking"], ngImport: i0, template: `
273
+ <ng-content />
274
+ <nu-docking-backdrop [visible]="backdropVisible()" (click)="doCloseActiveOverPanel()"></nu-docking-backdrop>
275
+ `, isInline: true, styles: [":host{display:grid;grid-template-columns:auto 1fr auto;grid-template-rows:auto 1fr auto;position:relative;align-items:stretch;justify-items:stretch;overflow:clip}\n"], dependencies: [{ kind: "component", type: DockingBackdropComponent, selector: "nu-docking-backdrop", inputs: ["visible"] }] }); }
508
276
  }
509
277
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImport: i0, type: DockingLayoutComponent, decorators: [{
510
278
  type: Component,
511
- args: [{ selector: "nu-docking", standalone: true, imports: [DockingContentComponent, DockingBackdropComponent], template: `
512
- <ng-content select="nu-docking-panel"></ng-content>
513
-
514
- @if (!contentComponent) {
515
- <nu-docking-content>
516
- <ng-content></ng-content>
517
- </nu-docking-content>
518
- } @else {
519
- <ng-content select="nu-docking-content"></ng-content>
520
- }
521
-
522
- <nu-docking-backdrop #backdrop (click)="onHideBackdropPanel($event)" />
523
- `, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{---docking-layout-top: var(--docking-layout-top, 0px);---docking-layout-right: var(--docking-layout-right, 0px);---docking-layout-bottom: var(--docking-layout-bottom, 0px);---docking-layout-left: var(--docking-layout-left, 0px);---docking-layout-anim-duration: var(--docking-layout-anim-duration, .3s);---docking-layout-anim-ease: var(--docking-layout-anim-ease, cubic-bezier(.4, 0, .2, 1));---docking-layout-backdrop-color: var(--docking-layout-backdrop-color, #000);display:flex;flex-flow:column nowrap;align-items:stretch;position:relative;overflow:hidden;box-sizing:border-box;z-index:0;padding:var(---docking-layout-top) var(---docking-layout-right) var(---docking-layout-bottom) var(---docking-layout-left);transition:padding var(---docking-layout-anim-duration) var(---docking-layout-anim-ease)}\n"] }]
524
- }], propDecorators: { contentOnly: [{
525
- type: Input
526
- }], contentComponent: [{
527
- type: ContentChild,
528
- args: [DockingContentComponent]
529
- }], backdropEl: [{
530
- type: ViewChild,
531
- args: ["backdrop", { read: ElementRef, static: true }]
532
- }], dockingPanels: [{
533
- type: ContentChildren,
534
- args: [DockingPanelComponent]
535
- }] } });
279
+ args: [{ selector: "nu-docking", exportAs: "nuDocking", standalone: true, imports: [DockingBackdropComponent], template: `
280
+ <ng-content />
281
+ <nu-docking-backdrop [visible]="backdropVisible()" (click)="doCloseActiveOverPanel()"></nu-docking-backdrop>
282
+ `, styles: [":host{display:grid;grid-template-columns:auto 1fr auto;grid-template-rows:auto 1fr auto;position:relative;align-items:stretch;justify-items:stretch;overflow:clip}\n"] }]
283
+ }] });
536
284
 
537
285
  const members$1 = [DockingLayoutComponent, DockingPanelComponent, DockingContentComponent];
538
286
  class NuDockingLayout {
@@ -1007,5 +755,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.6", ngImpor
1007
755
  * Generated bundle index. Do not edit.
1008
756
  */
1009
757
 
1010
- export { DockingContentComponent, DockingLayoutComponent, DockingPanelComponent, L9Cell, L9Range, L9State, NuDockingLayout, NuSlidingLayout, SlidingComponent, SlidingItemDirective, SlotDef, SlotDirective, SlotOutletDirective, SlotsService };
758
+ export { DockingContentComponent, DockingLayoutComponent, DockingPanelComponent, L9Cell, L9GridTopLeft, L9Range, L9State, NuDockingLayout, NuSlidingLayout, SlidingComponent, SlidingItemDirective, SlotDef, SlotDirective, SlotOutletDirective, SlotsService };
1011
759
  //# sourceMappingURL=ngutil-layout.mjs.map