@aquera/nile-elements 1.8.0 → 1.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/index-6faafdf4.cjs.js +2 -0
- package/dist/index-6faafdf4.cjs.js.map +1 -0
- package/dist/index-9931b440.esm.js +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.esm.js +1 -1
- package/dist/index.js +283 -283
- package/dist/nile-combobox/index.cjs.js +1 -1
- package/dist/nile-combobox/index.esm.js +1 -1
- package/dist/nile-combobox/nile-combobox.cjs.js +1 -1
- package/dist/nile-combobox/nile-combobox.esm.js +1 -1
- package/dist/nile-context-menu/nile-context-menu.cjs.js +1 -1
- package/dist/nile-context-menu/nile-context-menu.cjs.js.map +1 -1
- package/dist/nile-context-menu/nile-context-menu.esm.js +2 -2
- package/dist/nile-context-menu-item/nile-context-menu-item.cjs.js +1 -1
- package/dist/nile-context-menu-item/nile-context-menu-item.cjs.js.map +1 -1
- package/dist/nile-context-menu-item/nile-context-menu-item.esm.js +3 -3
- package/dist/nile-context-submenu/nile-context-submenu.cjs.js +1 -1
- package/dist/nile-context-submenu/nile-context-submenu.cjs.js.map +1 -1
- package/dist/nile-context-submenu/nile-context-submenu.esm.js +2 -2
- package/dist/nile-detail/index.cjs.js +1 -1
- package/dist/nile-detail/index.esm.js +1 -1
- package/dist/nile-detail/nile-detail.cjs.js +1 -1
- package/dist/nile-detail/nile-detail.esm.js +1 -1
- package/dist/nile-floating-panel/nile-floating-panel.cjs.js +1 -1
- package/dist/nile-floating-panel/nile-floating-panel.cjs.js.map +1 -1
- package/dist/nile-floating-panel/nile-floating-panel.esm.js +1 -1
- package/dist/src/nile-context-menu/nile-context-menu.d.ts +10 -1
- package/dist/src/nile-context-menu/nile-context-menu.js +85 -5
- package/dist/src/nile-context-menu/nile-context-menu.js.map +1 -1
- package/dist/src/nile-context-menu-item/nile-context-menu-item.d.ts +1 -0
- package/dist/src/nile-context-menu-item/nile-context-menu-item.js +5 -1
- package/dist/src/nile-context-menu-item/nile-context-menu-item.js.map +1 -1
- package/dist/src/nile-context-submenu/nile-context-submenu.d.ts +9 -0
- package/dist/src/nile-context-submenu/nile-context-submenu.js +100 -16
- package/dist/src/nile-context-submenu/nile-context-submenu.js.map +1 -1
- package/dist/src/nile-floating-panel/nile-floating-panel.d.ts +2 -0
- package/dist/src/nile-floating-panel/nile-floating-panel.js +4 -0
- package/dist/src/nile-floating-panel/nile-floating-panel.js.map +1 -1
- package/dist/src/version.js +1 -1
- package/dist/src/version.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/nile-context-menu/nile-context-menu.ts +86 -8
- package/src/nile-context-menu-item/nile-context-menu-item.ts +3 -1
- package/src/nile-context-submenu/nile-context-submenu.ts +97 -12
- package/src/nile-floating-panel/nile-floating-panel.ts +5 -0
- package/vscode-html-custom-data.json +13 -3
- package/dist/index-644974d4.esm.js +0 -1
- package/dist/index-dd2af8ec.cjs.js +0 -2
- package/dist/index-dd2af8ec.cjs.js.map +0 -1
package/package.json
CHANGED
|
@@ -30,6 +30,7 @@ export interface NileContextMenuItemData {
|
|
|
30
30
|
iconMethod?: 'fill' | 'stroke' | string;
|
|
31
31
|
iconColor?: string;
|
|
32
32
|
submenu?: NileContextMenuData[];
|
|
33
|
+
open?: boolean;
|
|
33
34
|
}
|
|
34
35
|
|
|
35
36
|
export interface NileContextMenuGroupData {
|
|
@@ -93,7 +94,9 @@ export class NileContextMenu extends NileElement {
|
|
|
93
94
|
@property({ attribute: true, type: String, reflect: true }) skipOn = '';
|
|
94
95
|
|
|
95
96
|
@property({ attribute: true, type: Number, reflect: true }) zIndex = 9999;
|
|
96
|
-
|
|
97
|
+
|
|
98
|
+
@property({ attribute: true, type: Boolean, reflect: true }) open = false;
|
|
99
|
+
|
|
97
100
|
@property({ attribute: false }) public items: NileContextMenuData[] = [];
|
|
98
101
|
|
|
99
102
|
private get _isDataMode(): boolean {
|
|
@@ -102,9 +105,11 @@ export class NileContextMenu extends NileElement {
|
|
|
102
105
|
@query('nile-floating-panel') private _floatingPanel?: HTMLElement;
|
|
103
106
|
|
|
104
107
|
@state() private _items: NileContextMenuItem[] = [];
|
|
105
|
-
|
|
108
|
+
|
|
106
109
|
@state() private _open = false;
|
|
107
|
-
|
|
110
|
+
|
|
111
|
+
private _pinned = false;
|
|
112
|
+
|
|
108
113
|
protected _openContext: NileContextMenuOpenContext | null = null;
|
|
109
114
|
|
|
110
115
|
protected _targetEl: Element | null = null;
|
|
@@ -132,6 +137,15 @@ export class NileContextMenu extends NileElement {
|
|
|
132
137
|
this._relocateLightChildren();
|
|
133
138
|
});
|
|
134
139
|
this._lightObserver.observe(this, { childList: true });
|
|
140
|
+
// Restore a declaratively-opened menu after a disconnect/reconnect.
|
|
141
|
+
if (this.open && !this._open) {
|
|
142
|
+
this.updateComplete.then(() => {
|
|
143
|
+
if (this.isConnected && this.open && !this._open) {
|
|
144
|
+
this._pinned = true;
|
|
145
|
+
this._openAtTarget();
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
135
149
|
}
|
|
136
150
|
|
|
137
151
|
protected override updated(changed: PropertyValues): void {
|
|
@@ -154,8 +168,33 @@ export class NileContextMenu extends NileElement {
|
|
|
154
168
|
this._wasDataMode = false;
|
|
155
169
|
}
|
|
156
170
|
}
|
|
171
|
+
if (changed.has('open')) {
|
|
172
|
+
if (this.open && !this._open) {
|
|
173
|
+
this._pinned = true;
|
|
174
|
+
this._openAtTarget();
|
|
175
|
+
} else if (!this.open && this._open) {
|
|
176
|
+
this.close('programmatic');
|
|
177
|
+
}
|
|
178
|
+
}
|
|
157
179
|
}
|
|
158
180
|
|
|
181
|
+
/** Open anchored to the `for` target (used when the `open` property is set). */
|
|
182
|
+
private _openAtTarget(): void {
|
|
183
|
+
const rect = this._targetEl?.getBoundingClientRect();
|
|
184
|
+
this.openAt({
|
|
185
|
+
x: rect ? rect.left : 0,
|
|
186
|
+
y: rect ? rect.bottom : 0,
|
|
187
|
+
target: this._targetEl ?? undefined,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** Re-anchor a pinned menu to its target after layout changes. */
|
|
192
|
+
private _onPinnedReposition = (): void => {
|
|
193
|
+
if (!this._open || !this._pinned || !this._targetEl) return;
|
|
194
|
+
const rect = this._targetEl.getBoundingClientRect();
|
|
195
|
+
this._positionProxyAt(rect.left, rect.bottom);
|
|
196
|
+
};
|
|
197
|
+
|
|
159
198
|
private _resolveTarget(): void {
|
|
160
199
|
const value = this.for?.trim();
|
|
161
200
|
if (!value) {
|
|
@@ -196,7 +235,7 @@ export class NileContextMenu extends NileElement {
|
|
|
196
235
|
if (isInteractive(me.target as Element | null)) return;
|
|
197
236
|
me.preventDefault();
|
|
198
237
|
if (this._open) return;
|
|
199
|
-
this.
|
|
238
|
+
this.openAt({
|
|
200
239
|
x: me.clientX,
|
|
201
240
|
y: me.clientY,
|
|
202
241
|
target: (me.target as Element | null) ?? undefined,
|
|
@@ -219,7 +258,7 @@ export class NileContextMenu extends NileElement {
|
|
|
219
258
|
const handler = (e: Event) => {
|
|
220
259
|
const me = e as MouseEvent;
|
|
221
260
|
me.preventDefault();
|
|
222
|
-
this.
|
|
261
|
+
this.openAt({
|
|
223
262
|
x: me.clientX,
|
|
224
263
|
y: me.clientY,
|
|
225
264
|
target,
|
|
@@ -233,7 +272,7 @@ export class NileContextMenu extends NileElement {
|
|
|
233
272
|
if (wantsClick) {
|
|
234
273
|
const handler = (e: Event) => {
|
|
235
274
|
const me = e as MouseEvent;
|
|
236
|
-
this.
|
|
275
|
+
this.openAt({
|
|
237
276
|
x: me.clientX,
|
|
238
277
|
y: me.clientY,
|
|
239
278
|
target,
|
|
@@ -267,6 +306,7 @@ export class NileContextMenu extends NileElement {
|
|
|
267
306
|
document.removeEventListener('pointerdown', this._onOutsidePointer, true);
|
|
268
307
|
document.removeEventListener('keydown', this._onKeydown, true);
|
|
269
308
|
window.removeEventListener('scroll', this._onScroll, true);
|
|
309
|
+
window.removeEventListener('resize', this._onPinnedReposition);
|
|
270
310
|
this._proxyEl?.remove();
|
|
271
311
|
this._proxyEl = undefined;
|
|
272
312
|
}
|
|
@@ -312,8 +352,21 @@ export class NileContextMenu extends NileElement {
|
|
|
312
352
|
|
|
313
353
|
private _positionProxyAt(x: number, y: number): void {
|
|
314
354
|
if (!this._proxyEl) return;
|
|
355
|
+
if (this._pinned && this._targetEl) {
|
|
356
|
+
// menu attaches below it pinned menus (or flips cleanly above it)
|
|
357
|
+
const rect = this._targetEl.getBoundingClientRect();
|
|
358
|
+
this._proxyEl.style.position = 'absolute';
|
|
359
|
+
this._proxyEl.style.left = `${rect.left + window.scrollX}px`;
|
|
360
|
+
this._proxyEl.style.top = `${rect.top + window.scrollY}px`;
|
|
361
|
+
this._proxyEl.style.width = `${rect.width}px`;
|
|
362
|
+
this._proxyEl.style.height = `${rect.height}px`;
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
this._proxyEl.style.position = 'fixed';
|
|
315
366
|
this._proxyEl.style.left = `${x}px`;
|
|
316
367
|
this._proxyEl.style.top = `${y}px`;
|
|
368
|
+
this._proxyEl.style.width = '0';
|
|
369
|
+
this._proxyEl.style.height = '0';
|
|
317
370
|
}
|
|
318
371
|
|
|
319
372
|
private _relocateLightChildren(): void {
|
|
@@ -352,6 +405,7 @@ export class NileContextMenu extends NileElement {
|
|
|
352
405
|
if (data.id) item.id = data.id;
|
|
353
406
|
item.value = data.value ?? data.id ?? '';
|
|
354
407
|
if (data.disabled) item.disabled = true;
|
|
408
|
+
if (data.open) item.open = true;
|
|
355
409
|
if (data.icon) {
|
|
356
410
|
const glyph = document.createElement('nile-glyph');
|
|
357
411
|
glyph.setAttribute('slot', 'icon');
|
|
@@ -401,7 +455,7 @@ export class NileContextMenu extends NileElement {
|
|
|
401
455
|
return this._open;
|
|
402
456
|
}
|
|
403
457
|
|
|
404
|
-
public
|
|
458
|
+
public openAt(options: NileContextMenuOpenOptions): void {
|
|
405
459
|
if (this._open) return;
|
|
406
460
|
for (const other of NileContextMenu._openInstances) {
|
|
407
461
|
if (other !== this) other.close('programmatic');
|
|
@@ -416,11 +470,14 @@ export class NileContextMenu extends NileElement {
|
|
|
416
470
|
this._ensureProxy();
|
|
417
471
|
this._positionProxyAt(options.x, options.y);
|
|
418
472
|
this._open = true;
|
|
473
|
+
this.open = true;
|
|
419
474
|
NileContextMenu._openInstances.add(this);
|
|
420
475
|
document.addEventListener('pointerdown', this._onOutsidePointer, true);
|
|
421
476
|
document.addEventListener('keydown', this._onKeydown, true);
|
|
477
|
+
if (this._pinned) window.addEventListener('resize', this._onPinnedReposition);
|
|
422
478
|
requestAnimationFrame(() => {
|
|
423
479
|
if (this._open) window.addEventListener('scroll', this._onScroll, true);
|
|
480
|
+
requestAnimationFrame(() => this._openPinnedSubmenus());
|
|
424
481
|
});
|
|
425
482
|
this.emit('nile-change', { type: 'open', ...this._openContext });
|
|
426
483
|
}
|
|
@@ -428,6 +485,8 @@ export class NileContextMenu extends NileElement {
|
|
|
428
485
|
public close(reason: NileContextMenuCloseReason = 'programmatic'): void {
|
|
429
486
|
if (!this._open) return;
|
|
430
487
|
this._open = false;
|
|
488
|
+
this.open = false;
|
|
489
|
+
this._pinned = false;
|
|
431
490
|
this._openContext = null;
|
|
432
491
|
NileContextMenu._openInstances.delete(this);
|
|
433
492
|
const subs = this._menuContainerRef?.querySelectorAll(SUBMENU_TAG);
|
|
@@ -435,6 +494,7 @@ export class NileContextMenu extends NileElement {
|
|
|
435
494
|
document.removeEventListener('pointerdown', this._onOutsidePointer, true);
|
|
436
495
|
document.removeEventListener('keydown', this._onKeydown, true);
|
|
437
496
|
window.removeEventListener('scroll', this._onScroll, true);
|
|
497
|
+
window.removeEventListener('resize', this._onPinnedReposition);
|
|
438
498
|
const active = document.activeElement;
|
|
439
499
|
const focusInMenu =
|
|
440
500
|
active === this ||
|
|
@@ -533,7 +593,8 @@ export class NileContextMenu extends NileElement {
|
|
|
533
593
|
const sub = this._findSubmenuOwning(container);
|
|
534
594
|
if (!sub) return;
|
|
535
595
|
e.preventDefault();
|
|
536
|
-
|
|
596
|
+
// Pinned submenus (parent item has `open`) stay open; just move focus.
|
|
597
|
+
if (!sub.parentItem?.open) sub.closeSubmenu?.();
|
|
537
598
|
sub.parentItem?.focus();
|
|
538
599
|
return;
|
|
539
600
|
}
|
|
@@ -578,6 +639,10 @@ export class NileContextMenu extends NileElement {
|
|
|
578
639
|
|
|
579
640
|
private _onScroll = (e: Event): void => {
|
|
580
641
|
if (!this._open) return;
|
|
642
|
+
if (this._pinned) {
|
|
643
|
+
this._onPinnedReposition();
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
581
646
|
const path = e.composedPath();
|
|
582
647
|
// Scroll inside the root menu container?
|
|
583
648
|
if (this._menuContainerRef && path.includes(this._menuContainerRef)) return;
|
|
@@ -615,8 +680,21 @@ export class NileContextMenu extends NileElement {
|
|
|
615
680
|
|
|
616
681
|
private _onPanelShown = (e: Event): void => {
|
|
617
682
|
e.stopPropagation();
|
|
683
|
+
this._openPinnedSubmenus();
|
|
618
684
|
};
|
|
619
685
|
|
|
686
|
+
/** Open the submenu of every top-level item carrying the `open` attribute. */
|
|
687
|
+
private _openPinnedSubmenus(): void {
|
|
688
|
+
if (!this._open || !this._menuContainerRef) return;
|
|
689
|
+
for (const item of this._items) {
|
|
690
|
+
if (!item.open || item.disabled) continue;
|
|
691
|
+
const sub = item.querySelector(`:scope > ${SUBMENU_TAG}`) as
|
|
692
|
+
| (HTMLElement & { openSubmenu?: () => void })
|
|
693
|
+
| null;
|
|
694
|
+
sub?.openSubmenu?.();
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
620
698
|
private _onMenuMouseOver = (e: MouseEvent): void => {
|
|
621
699
|
const item = e
|
|
622
700
|
.composedPath()
|
|
@@ -41,6 +41,8 @@ export class NileContextMenuItem extends NileElement {
|
|
|
41
41
|
|
|
42
42
|
@property({ attribute: true, type: Boolean, reflect: true }) disabled = false;
|
|
43
43
|
|
|
44
|
+
@property({ attribute: true, type: Boolean, reflect: true }) open = false;
|
|
45
|
+
|
|
44
46
|
public onSelect?: NileContextMenuItemSelectHandler;
|
|
45
47
|
|
|
46
48
|
@state() private _hasSubmenu = false;
|
|
@@ -95,7 +97,7 @@ export class NileContextMenuItem extends NileElement {
|
|
|
95
97
|
<span part="label" class="label"><slot @slotchange=${this._onSlotChange}></slot></span>
|
|
96
98
|
${this._hasSubmenu
|
|
97
99
|
? html`<span part="chevron" class="chevron" aria-hidden="true">
|
|
98
|
-
<nile-glyph name="ng-chevron-right" size="16"></nile-glyph>
|
|
100
|
+
<nile-glyph name="ng-chevron-right" size="16" method="stroke"></nile-glyph>
|
|
99
101
|
</span>`
|
|
100
102
|
: ''}
|
|
101
103
|
</div>
|
|
@@ -47,6 +47,11 @@ export class NileContextSubmenu extends NileElement {
|
|
|
47
47
|
private _openTimer?: number;
|
|
48
48
|
private _closeTimer?: number;
|
|
49
49
|
private _setupDone = false;
|
|
50
|
+
private _parentObserver?: MutationObserver;
|
|
51
|
+
private _repositionQueued = false;
|
|
52
|
+
private get _pinnedOpen(): boolean {
|
|
53
|
+
return !!(this._parentItem?.open && !this._parentItem.disabled);
|
|
54
|
+
}
|
|
50
55
|
|
|
51
56
|
public override connectedCallback(): void {
|
|
52
57
|
super.connectedCallback();
|
|
@@ -59,10 +64,27 @@ export class NileContextSubmenu extends NileElement {
|
|
|
59
64
|
this._parentItem.addEventListener('mouseenter', this._onParentEnter);
|
|
60
65
|
this._parentItem.addEventListener('mouseleave', this._onParentLeave);
|
|
61
66
|
this._parentItem.addEventListener('click', this._onParentClick, true);
|
|
67
|
+
// Open/close the submenu when the parent item's `open` attribute changes.
|
|
68
|
+
this._parentObserver = new MutationObserver(() => {
|
|
69
|
+
if (this._pinnedOpen) {
|
|
70
|
+
if (this._isParentVisible()) this.openSubmenu();
|
|
71
|
+
} else if (this._open) {
|
|
72
|
+
this.closeSubmenu();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
this._parentObserver.observe(this._parentItem, {
|
|
76
|
+
attributes: true,
|
|
77
|
+
attributeFilter: ['open'],
|
|
78
|
+
});
|
|
62
79
|
}
|
|
63
80
|
this._ensureBodyPanel();
|
|
64
81
|
}
|
|
65
82
|
|
|
83
|
+
private _isParentVisible(): boolean {
|
|
84
|
+
const rect = this._parentItem?.getBoundingClientRect();
|
|
85
|
+
return !!rect && rect.width > 0 && rect.height > 0;
|
|
86
|
+
}
|
|
87
|
+
|
|
66
88
|
private _ensureProxy(): void {
|
|
67
89
|
if (this._proxyEl) return;
|
|
68
90
|
const el = document.createElement('div');
|
|
@@ -77,8 +99,16 @@ export class NileContextSubmenu extends NileElement {
|
|
|
77
99
|
private _syncProxyToParent(): void {
|
|
78
100
|
if (!this._proxyEl || !this._parentItem) return;
|
|
79
101
|
const rect = this._parentItem.getBoundingClientRect();
|
|
80
|
-
this.
|
|
81
|
-
|
|
102
|
+
if (this._pinnedOpen) {
|
|
103
|
+
// Pinned submenus anchor in document coordinates.
|
|
104
|
+
this._proxyEl.style.position = 'absolute';
|
|
105
|
+
this._proxyEl.style.left = `${rect.left + window.scrollX}px`;
|
|
106
|
+
this._proxyEl.style.top = `${rect.top + window.scrollY}px`;
|
|
107
|
+
} else {
|
|
108
|
+
this._proxyEl.style.position = 'fixed';
|
|
109
|
+
this._proxyEl.style.left = `${rect.left}px`;
|
|
110
|
+
this._proxyEl.style.top = `${rect.top}px`;
|
|
111
|
+
}
|
|
82
112
|
this._proxyEl.style.width = `${rect.width}px`;
|
|
83
113
|
this._proxyEl.style.height = `${rect.height}px`;
|
|
84
114
|
}
|
|
@@ -90,6 +120,8 @@ export class NileContextSubmenu extends NileElement {
|
|
|
90
120
|
this._parentItem.removeEventListener('mouseleave', this._onParentLeave);
|
|
91
121
|
this._parentItem.removeEventListener('click', this._onParentClick, true);
|
|
92
122
|
}
|
|
123
|
+
this._parentObserver?.disconnect();
|
|
124
|
+
this._parentObserver = undefined;
|
|
93
125
|
this._clearTimers();
|
|
94
126
|
if (this._open) this.closeSubmenu();
|
|
95
127
|
this._teardownBodyArtifacts();
|
|
@@ -172,6 +204,7 @@ export class NileContextSubmenu extends NileElement {
|
|
|
172
204
|
|
|
173
205
|
private _onParentLeave = (): void => {
|
|
174
206
|
if (this._openTimer != null) { clearTimeout(this._openTimer); this._openTimer = undefined; }
|
|
207
|
+
if (this._pinnedOpen) return;
|
|
175
208
|
if (this._open) {
|
|
176
209
|
this._closeTimer = window.setTimeout(() => this.closeSubmenu(), HOVER_CLOSE_DELAY);
|
|
177
210
|
}
|
|
@@ -181,15 +214,31 @@ export class NileContextSubmenu extends NileElement {
|
|
|
181
214
|
e.stopPropagation();
|
|
182
215
|
if (this._parentItem?.disabled) return;
|
|
183
216
|
this._clearTimers();
|
|
184
|
-
if (this._open)
|
|
185
|
-
|
|
217
|
+
if (this._open) {
|
|
218
|
+
if (!this._pinnedOpen) this.closeSubmenu();
|
|
219
|
+
} else {
|
|
220
|
+
this.openSubmenu();
|
|
221
|
+
}
|
|
186
222
|
};
|
|
187
223
|
|
|
188
224
|
private _onPanelEnter = (): void => {
|
|
189
225
|
this._clearTimers();
|
|
190
226
|
};
|
|
191
227
|
|
|
228
|
+
//Re-anchor to the parent item after scroll/resize
|
|
229
|
+
private _onReposition = (): void => {
|
|
230
|
+
if (this._repositionQueued || !this._open) return;
|
|
231
|
+
this._repositionQueued = true;
|
|
232
|
+
requestAnimationFrame(() => {
|
|
233
|
+
this._repositionQueued = false;
|
|
234
|
+
if (!this._open) return;
|
|
235
|
+
this._syncProxyToParent();
|
|
236
|
+
this._floatingPanelEl?.reposition();
|
|
237
|
+
});
|
|
238
|
+
};
|
|
239
|
+
|
|
192
240
|
private _onPanelLeave = (): void => {
|
|
241
|
+
if (this._pinnedOpen) return;
|
|
193
242
|
if (this._open) {
|
|
194
243
|
this._closeTimer = window.setTimeout(() => {
|
|
195
244
|
const hasOpenDescendant = NileContextSubmenu.openStack.some(
|
|
@@ -209,11 +258,50 @@ export class NileContextSubmenu extends NileElement {
|
|
|
209
258
|
this._ensureBodyPanel();
|
|
210
259
|
this._syncProxyToParent();
|
|
211
260
|
this._open = true;
|
|
212
|
-
if (this._floatingPanelEl)
|
|
261
|
+
if (this._floatingPanelEl) {
|
|
262
|
+
// open pinned descendants only once this panel is fully shown
|
|
263
|
+
this._floatingPanelEl.addEventListener(
|
|
264
|
+
'nile-after-show',
|
|
265
|
+
() => {
|
|
266
|
+
if (this._open) this._openPinnedDescendants();
|
|
267
|
+
},
|
|
268
|
+
{ once: true },
|
|
269
|
+
);
|
|
270
|
+
this._floatingPanelEl.open = true;
|
|
271
|
+
}
|
|
213
272
|
NileContextSubmenu.openStack.push(this);
|
|
273
|
+
window.addEventListener('scroll', this._onReposition, true);
|
|
274
|
+
window.addEventListener('resize', this._onReposition);
|
|
275
|
+
requestAnimationFrame(() => requestAnimationFrame(() => {
|
|
276
|
+
if (this._open) this._openPinnedDescendants();
|
|
277
|
+
}));
|
|
214
278
|
this._parentItem?.setSubmenuExpanded?.(true);
|
|
215
279
|
}
|
|
216
280
|
|
|
281
|
+
/** Open the submenu of every direct child item carrying the `open` attribute. */
|
|
282
|
+
private _openPinnedDescendants(): void {
|
|
283
|
+
if (!this._menuContainerRef) return;
|
|
284
|
+
const items = Array.from(
|
|
285
|
+
this._menuContainerRef.querySelectorAll(ITEM_TAG)
|
|
286
|
+
) as NileContextMenuItem[];
|
|
287
|
+
for (const item of items) {
|
|
288
|
+
if (!this._isDirectChildItem(item)) continue;
|
|
289
|
+
if (!item.open || item.disabled) continue;
|
|
290
|
+
const sub = item.querySelector(`:scope > ${SUBMENU_TAG}`) as NileContextSubmenu | null;
|
|
291
|
+
sub?.openSubmenu();
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/** True if `item` sits at this submenu's own level (not inside a deeper submenu). */
|
|
296
|
+
private _isDirectChildItem(item: Element): boolean {
|
|
297
|
+
let cur: Element | null = item.parentElement;
|
|
298
|
+
while (cur && cur !== this._menuContainerRef) {
|
|
299
|
+
if (cur.tagName.toLowerCase() === SUBMENU_TAG) return false;
|
|
300
|
+
cur = cur.parentElement;
|
|
301
|
+
}
|
|
302
|
+
return true;
|
|
303
|
+
}
|
|
304
|
+
|
|
217
305
|
public closeSubmenu(): void {
|
|
218
306
|
if (!this._open) return;
|
|
219
307
|
for (const sub of [...NileContextSubmenu.openStack]) {
|
|
@@ -223,6 +311,8 @@ export class NileContextSubmenu extends NileElement {
|
|
|
223
311
|
}
|
|
224
312
|
this._open = false;
|
|
225
313
|
if (this._floatingPanelEl) this._floatingPanelEl.open = false;
|
|
314
|
+
window.removeEventListener('scroll', this._onReposition, true);
|
|
315
|
+
window.removeEventListener('resize', this._onReposition);
|
|
226
316
|
NileContextSubmenu.openStack = NileContextSubmenu.openStack.filter(s => s !== this);
|
|
227
317
|
this._clearTimers();
|
|
228
318
|
this._parentItem?.setSubmenuExpanded?.(false);
|
|
@@ -248,13 +338,7 @@ export class NileContextSubmenu extends NileElement {
|
|
|
248
338
|
this._menuContainerRef.querySelectorAll(ITEM_TAG)
|
|
249
339
|
) as NileContextMenuItem[];
|
|
250
340
|
for (const item of items) {
|
|
251
|
-
|
|
252
|
-
let inDeeperSub = false;
|
|
253
|
-
while (cur && cur !== this._menuContainerRef) {
|
|
254
|
-
if (cur.tagName.toLowerCase() === SUBMENU_TAG) { inDeeperSub = true; break; }
|
|
255
|
-
cur = cur.parentElement;
|
|
256
|
-
}
|
|
257
|
-
if (inDeeperSub) continue;
|
|
341
|
+
if (!this._isDirectChildItem(item)) continue;
|
|
258
342
|
if (!item.disabled) { item.focus(); return; }
|
|
259
343
|
}
|
|
260
344
|
}
|
|
@@ -263,6 +347,7 @@ export class NileContextSubmenu extends NileElement {
|
|
|
263
347
|
const myLevel = this._parentLevel();
|
|
264
348
|
for (const sub of [...NileContextSubmenu.openStack]) {
|
|
265
349
|
if (sub === this) continue;
|
|
350
|
+
if (sub._pinnedOpen) continue;
|
|
266
351
|
if (sub._parentLevel() === myLevel) sub.closeSubmenu();
|
|
267
352
|
}
|
|
268
353
|
}
|
|
@@ -303,6 +303,11 @@ export class NileFloatingPanel extends NileElement {
|
|
|
303
303
|
this._attachTippy();
|
|
304
304
|
}
|
|
305
305
|
|
|
306
|
+
/** Recomputes the panel position against its anchor (e.g. after the anchor moved). */
|
|
307
|
+
public reposition(): void {
|
|
308
|
+
this.tippyInstance?.popperInstance?.update();
|
|
309
|
+
}
|
|
310
|
+
|
|
306
311
|
/** Returns the current resolved placement from Tippy/Popper. */
|
|
307
312
|
public getCurrentPlacement(): string {
|
|
308
313
|
const popper = this.tippyInstance?.popper;
|
|
@@ -1712,7 +1712,7 @@
|
|
|
1712
1712
|
},
|
|
1713
1713
|
{
|
|
1714
1714
|
"name": "nile-context-menu-item",
|
|
1715
|
-
"description": "Nile context-menu item. A clickable entry inside `nile-context-menu`.\n\nSlots:\n\n * ` ` {} - Default slot for the visible label.\n\n * `icon` {} - Optional leading icon (e.g. a `<nile-glyph slot=\"icon\">`).\n\nAttributes:\n\n * `value` {`string`} - \n\n * `disabled` {`boolean`} - \n\nProperties:\n\n * `value` {`string`} - \n\n * `disabled` {`boolean`} - \n\n * `onSelect` - \n\n * `_hasSubmenu` {`boolean`} - \n\n * `_hasIcon` {`boolean`} - \n\n * `_submenuExpanded` {`boolean`} - \n\n * `override` - \n\n * `hasSubmenu` {`boolean`} - \n\n * `_onSlotChange` - \n\n * `_onIconSlotChange` - \n\n * `BUBBLES` {`boolean`} - \n\n * `COMPOSED` {`boolean`} - \n\n * `CANCELABLE` {`boolean`} - ",
|
|
1715
|
+
"description": "Nile context-menu item. A clickable entry inside `nile-context-menu`.\n\nSlots:\n\n * ` ` {} - Default slot for the visible label.\n\n * `icon` {} - Optional leading icon (e.g. a `<nile-glyph slot=\"icon\">`).\n\nAttributes:\n\n * `value` {`string`} - \n\n * `disabled` {`boolean`} - \n\n * `open` {`boolean`} - \n\nProperties:\n\n * `value` {`string`} - \n\n * `disabled` {`boolean`} - \n\n * `open` {`boolean`} - \n\n * `onSelect` - \n\n * `_hasSubmenu` {`boolean`} - \n\n * `_hasIcon` {`boolean`} - \n\n * `_submenuExpanded` {`boolean`} - \n\n * `override` - \n\n * `hasSubmenu` {`boolean`} - \n\n * `_onSlotChange` - \n\n * `_onIconSlotChange` - \n\n * `BUBBLES` {`boolean`} - \n\n * `COMPOSED` {`boolean`} - \n\n * `CANCELABLE` {`boolean`} - ",
|
|
1716
1716
|
"attributes": [
|
|
1717
1717
|
{
|
|
1718
1718
|
"name": "value",
|
|
@@ -1722,12 +1722,17 @@
|
|
|
1722
1722
|
"name": "disabled",
|
|
1723
1723
|
"description": "`disabled` {`boolean`} - \n\nProperty: disabled\n\nDefault: false",
|
|
1724
1724
|
"valueSet": "v"
|
|
1725
|
+
},
|
|
1726
|
+
{
|
|
1727
|
+
"name": "open",
|
|
1728
|
+
"description": "`open` {`boolean`} - \n\nProperty: open\n\nDefault: false",
|
|
1729
|
+
"valueSet": "v"
|
|
1725
1730
|
}
|
|
1726
1731
|
]
|
|
1727
1732
|
},
|
|
1728
1733
|
{
|
|
1729
1734
|
"name": "nile-context-menu",
|
|
1730
|
-
"description": "Nile context-menu component.\n\nEvents:\n\n * `nile` {} - change Fired on menu lifecycle and selection. `detail.type` is one of\n`'open'`, `'click'`, or `'close'`; remaining fields depend on the type.\n\nSlots:\n\n * ` ` {} - Default menu content.\n\nAttributes:\n\n * `for` {`string`} - \n\n * `trigger` {`NileContextMenuTrigger`} - \n\n * `skipOn` {`string`} - \n\n * `zIndex` {`number`} - \n\nProperties:\n\n * `for` {`string`} - \n\n * `trigger` {`NileContextMenuTrigger`} - \n\n * `skipOn` {`string`} - \n\n * `zIndex` {`number`} - \n\n * `items` {`NileContextMenuGroupData[]`} - \n\n * `_isDataMode` {`boolean`} - \n\n * `_floatingPanel` {`HTMLElement | undefined`} - \n\n * `_items` {`NileContextMenuItem[]`} - \n\n * `_open` {`boolean`} - \n\n * `_openContext` {`NileContextMenuOpenContext | null`} - \n\n * `_targetEl` {`Element | null`} - \n\n * `_previouslyFocused` {`HTMLElement | null`} - \n\n * `_openInstances` {`Set<NileContextMenu>`} - \n\n * `_detachTriggers` - \n\n * `_lightObserver` {`MutationObserver | undefined`} - \n\n * `_menuObserver` {`MutationObserver | undefined`} - \n\n * `_proxyEl` {`HTMLDivElement | undefined`} - \n\n * `_proxyId` {`string`} - \n\n * `_wasDataMode` {`boolean`} - \n\n * `targetElement` {`Element | null`} - \n\n * `_menuContainerRef` {`HTMLDivElement | null`} - \n\n * `override` - \n\n * `menuItems` {`readonly NileContextMenuItem[]`} - \n\n * `isOpen` {`boolean`} - \n\n * `_onKeydown` - \n\n * `_onScroll` - \n\n * `_onOutsidePointer` - \n\n * `_onDescendantSelect` - \n\n * `_onPanelShown` - \n\n * `_onMenuMouseOver` - \n\n * `_onMenuClick` - \n\n * `BUBBLES` {`boolean`} - \n\n * `COMPOSED` {`boolean`} - \n\n * `CANCELABLE` {`boolean`} - ",
|
|
1735
|
+
"description": "Nile context-menu component.\n\nEvents:\n\n * `nile` {} - change Fired on menu lifecycle and selection. `detail.type` is one of\n`'open'`, `'click'`, or `'close'`; remaining fields depend on the type.\n\nSlots:\n\n * ` ` {} - Default menu content.\n\nAttributes:\n\n * `for` {`string`} - \n\n * `trigger` {`NileContextMenuTrigger`} - \n\n * `skipOn` {`string`} - \n\n * `zIndex` {`number`} - \n\n * `open` {`boolean`} - \n\nProperties:\n\n * `for` {`string`} - \n\n * `trigger` {`NileContextMenuTrigger`} - \n\n * `skipOn` {`string`} - \n\n * `zIndex` {`number`} - \n\n * `open` {`boolean`} - \n\n * `items` {`NileContextMenuGroupData[]`} - \n\n * `_isDataMode` {`boolean`} - \n\n * `_floatingPanel` {`HTMLElement | undefined`} - \n\n * `_items` {`NileContextMenuItem[]`} - \n\n * `_open` {`boolean`} - \n\n * `_pinned` {`boolean`} - \n\n * `_openContext` {`NileContextMenuOpenContext | null`} - \n\n * `_targetEl` {`Element | null`} - \n\n * `_previouslyFocused` {`HTMLElement | null`} - \n\n * `_openInstances` {`Set<NileContextMenu>`} - \n\n * `_detachTriggers` - \n\n * `_lightObserver` {`MutationObserver | undefined`} - \n\n * `_menuObserver` {`MutationObserver | undefined`} - \n\n * `_proxyEl` {`HTMLDivElement | undefined`} - \n\n * `_proxyId` {`string`} - \n\n * `_wasDataMode` {`boolean`} - \n\n * `_onPinnedReposition` - Re-anchor a pinned menu to its target after layout changes.\n\n * `targetElement` {`Element | null`} - \n\n * `_menuContainerRef` {`HTMLDivElement | null`} - \n\n * `override` - \n\n * `menuItems` {`readonly NileContextMenuItem[]`} - \n\n * `isOpen` {`boolean`} - \n\n * `_onKeydown` - \n\n * `_onScroll` - \n\n * `_onOutsidePointer` - \n\n * `_onDescendantSelect` - \n\n * `_onPanelShown` - \n\n * `_onMenuMouseOver` - \n\n * `_onMenuClick` - \n\n * `BUBBLES` {`boolean`} - \n\n * `COMPOSED` {`boolean`} - \n\n * `CANCELABLE` {`boolean`} - ",
|
|
1731
1736
|
"attributes": [
|
|
1732
1737
|
{
|
|
1733
1738
|
"name": "for",
|
|
@@ -1762,6 +1767,11 @@
|
|
|
1762
1767
|
"name": "zIndex",
|
|
1763
1768
|
"description": "`zIndex` {`number`} - \n\nProperty: zIndex\n\nDefault: 9999"
|
|
1764
1769
|
},
|
|
1770
|
+
{
|
|
1771
|
+
"name": "open",
|
|
1772
|
+
"description": "`open` {`boolean`} - \n\nProperty: open\n\nDefault: false",
|
|
1773
|
+
"valueSet": "v"
|
|
1774
|
+
},
|
|
1765
1775
|
{
|
|
1766
1776
|
"name": "onnile",
|
|
1767
1777
|
"description": "`nile` {} - change Fired on menu lifecycle and selection. `detail.type` is one of\n`'open'`, `'click'`, or `'close'`; remaining fields depend on the type."
|
|
@@ -1770,7 +1780,7 @@
|
|
|
1770
1780
|
},
|
|
1771
1781
|
{
|
|
1772
1782
|
"name": "nile-context-submenu",
|
|
1773
|
-
"description": "Nested submenu inside a `nile-context-menu-item`.\n\nAttributes:\n\n * `zIndex` {`number`} - \n\nProperties:\n\n * `zIndex` {`number`} - \n\n * `_open` {`boolean`} - \n\n * `openStack` {`NileContextSubmenu[]`} - \n\n * `_parentItem` - \n\n * `_proxyId` {`string`} - \n\n * `_proxyEl` {`HTMLDivElement | undefined`} - \n\n * `_floatingPanelEl` - \n\n * `_menuContainerRef` {`HTMLDivElement | null`} - \n\n * `_openTimer` {`number | undefined`} - \n\n * `_closeTimer` {`number | undefined`} - \n\n * `_setupDone` {`boolean`} - \n\n * `override` - \n\n * `_onParentEnter` - \n\n * `_onParentLeave` - \n\n * `_onParentClick` - \n\n * `_onPanelEnter` - \n\n * `_onPanelLeave` - \n\n * `isOpen` {`boolean`} - \n\n * `parentItem` - \n\n * `_onMenuMouseOver` - \n\n * `_onNestedSelect` - \n\n * `_onMenuClick` - \n\n * `BUBBLES` {`boolean`} - \n\n * `COMPOSED` {`boolean`} - \n\n * `CANCELABLE` {`boolean`} - ",
|
|
1783
|
+
"description": "Nested submenu inside a `nile-context-menu-item`.\n\nAttributes:\n\n * `zIndex` {`number`} - \n\nProperties:\n\n * `zIndex` {`number`} - \n\n * `_open` {`boolean`} - \n\n * `openStack` {`NileContextSubmenu[]`} - \n\n * `_parentItem` - \n\n * `_proxyId` {`string`} - \n\n * `_proxyEl` {`HTMLDivElement | undefined`} - \n\n * `_floatingPanelEl` - \n\n * `_menuContainerRef` {`HTMLDivElement | null`} - \n\n * `_openTimer` {`number | undefined`} - \n\n * `_closeTimer` {`number | undefined`} - \n\n * `_setupDone` {`boolean`} - \n\n * `_parentObserver` {`MutationObserver | undefined`} - \n\n * `_repositionQueued` {`boolean`} - \n\n * `_pinnedOpen` {`boolean`} - \n\n * `override` - \n\n * `_onParentEnter` - \n\n * `_onParentLeave` - \n\n * `_onParentClick` - \n\n * `_onPanelEnter` - \n\n * `_onReposition` - \n\n * `_onPanelLeave` - \n\n * `isOpen` {`boolean`} - \n\n * `parentItem` - \n\n * `_onMenuMouseOver` - \n\n * `_onNestedSelect` - \n\n * `_onMenuClick` - \n\n * `BUBBLES` {`boolean`} - \n\n * `COMPOSED` {`boolean`} - \n\n * `CANCELABLE` {`boolean`} - ",
|
|
1774
1784
|
"attributes": [
|
|
1775
1785
|
{
|
|
1776
1786
|
"name": "zIndex",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function t(t,s,i){let h,n=i.initialDeps??[],e=!0;function l(){const l=t();return l.length!==n.length||l.some(((t,s)=>n[s]!==t))?(n=l,h=s(...l),!(null==i?void 0:i.onChange)||e&&i.skipInitialOnChange||i.onChange(h),e=!1,h):h}return l.updateDeps=t=>{n=t},l}function s(t,s){if(void 0===t)throw new Error("Unexpected undefined"+(s?`: ${s}`:""));return t}const i=(t,s)=>Math.abs(t-s)<1.01,h=(t,s,i)=>{let h;return function(...n){t.clearTimeout(h),h=t.setTimeout((()=>s.apply(this,n)),i)}};let n;const e=()=>{if(void 0!==n)return n;if("undefined"==typeof navigator)return n=!1;if(/iP(hone|od|ad)/.test(navigator.userAgent))return n=!0;const t=navigator.maxTouchPoints;return n="MacIntel"===navigator.platform&&void 0!==t&&t>0},l=t=>{const{offsetWidth:s,offsetHeight:i}=t;return{width:s,height:i}},r=t=>t,o=t=>{const s=Math.max(t.startIndex-t.overscan,0),i=Math.min(t.endIndex+t.overscan,t.count-1)-s+1,h=new Array(i);for(let t=0;t<i;t++)h[t]=s+t;return h},u=(t,s)=>{const i=t.scrollElement;if(!i)return;const h=t.targetWindow;if(!h)return;const n=t=>{const{width:i,height:h}=t;s({width:Math.round(i),height:Math.round(h)})};if(n(l(i)),!h.ResizeObserver)return()=>{};const e=new h.ResizeObserver((s=>{const h=()=>{const t=s[0];if(null==t?void 0:t.borderBoxSize){const s=t.borderBoxSize[0];if(s)return void n({width:s.inlineSize,height:s.blockSize})}n(l(i))};t.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(h):h()}));return e.observe(i,{box:"border-box"}),()=>{e.unobserve(i)}},a={passive:!0},c="undefined"==typeof window||"onscrollend"in window,d=(t,s)=>((t,s,i)=>{const n=t.scrollElement;if(!n)return;const e=t.targetWindow;if(!e)return;const l=t.options.useScrollendEvent&&c;let r=0;const o=l?null:h(e,(()=>s(r,!1)),t.options.isScrollingResetDelay),u=t=>()=>{r=i(n),null==o||o(),s(r,t)},d=u(!0),f=u(!1);return n.addEventListener("scroll",d,a),l&&n.addEventListener("scrollend",f,a),()=>{n.removeEventListener("scroll",d),l&&n.removeEventListener("scrollend",f)}})(t,s,(s=>{const{horizontal:i,isRtl:h}=t.options;return i?s.scrollLeft*(h?-1:1):s.scrollTop})),f=(t,s,i)=>{if(null==s?void 0:s.borderBoxSize){const t=s.borderBoxSize[0];if(t){return Math.round(t[i.options.horizontal?"inlineSize":"blockSize"])}}return t[i.options.horizontal?"offsetWidth":"offsetHeight"]},v=(t,{adjustments:s=0,behavior:i},h)=>{var n,e;null==(e=null==(n=h.scrollElement)?void 0:n.scrollTo)||e.call(n,{[h.options.horizontal?"left":"top"]:t+s,behavior:i})};class b{constructor(h){this.unsubs=[],this.scrollElement=null,this.targetWindow=null,this.isScrolling=!1,this.scrollState=null,this.measurementsCache=[],this._flatMeasurements=null,this.itemSizeCache=new Map,this.itemSizeCacheVersion=0,this.laneAssignments=new Map,this.pendingMin=null,this.prevLanes=void 0,this.lanesChangedFlag=!1,this.lanesSettling=!1,this.pendingScrollAnchor=null,this.scrollRect=null,this.scrollOffset=null,this.scrollDirection=null,this.scrollAdjustments=0,this._iosDeferredAdjustment=0,this._iosTouching=!1,this._iosJustTouchEnded=!1,this._iosTouchEndTimerId=null,this._intendedScrollOffset=null,this.elementsCache=new Map,this.now=()=>{var t,s,i;return(null==(i=null==(s=null==(t=this.targetWindow)?void 0:t.performance)?void 0:s.now)?void 0:i.call(s))??Date.now()},this.observer=(()=>{let t=null;const s=()=>t||(this.targetWindow&&this.targetWindow.ResizeObserver?t=new this.targetWindow.ResizeObserver((t=>{t.forEach((t=>{const s=()=>{const s=t.target,i=this.indexFromElement(s);if(s.isConnected)this.shouldMeasureDuringScroll(i)&&this.resizeItem(i,this.options.measureElement(s,t,this));else{this.observer.unobserve(s);for(const[t,i]of this.elementsCache)if(i===s){this.elementsCache.delete(t);break}}};this.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(s):s()}))})):null);return{disconnect:()=>{var i;null==(i=s())||i.disconnect(),t=null},observe:t=>{var i;return null==(i=s())?void 0:i.observe(t,{box:"border-box"})},unobserve:t=>{var i;return null==(i=s())?void 0:i.unobserve(t)}}})(),this.range=null,this.setOptions=t=>{var s,i;const h={debug:!1,initialOffset:0,overscan:1,paddingStart:0,paddingEnd:0,scrollPaddingStart:0,scrollPaddingEnd:0,horizontal:!1,getItemKey:r,rangeExtractor:o,onChange:()=>{},measureElement:f,initialRect:{width:0,height:0},scrollMargin:0,gap:0,indexAttribute:"data-index",initialMeasurementsCache:[],lanes:1,anchorTo:"start",followOnAppend:!1,scrollEndThreshold:1,isScrollingResetDelay:150,enabled:!0,isRtl:!1,useScrollendEvent:!1,useAnimationFrameWithResizeObserver:!1,laneAssignmentMode:"estimate"};for(const s in t){const i=t[s];void 0!==i&&(h[s]=i)}const n=this.options;let e=null,l=null;if(void 0!==n&&n.enabled&&h.enabled&&"end"===h.anchorTo&&null!==this.scrollElement){const t=n.count,r=h.count,o=this.getMeasurements(),u=t>0?(null==(s=o[0])?void 0:s.key)??n.getItemKey(0):null,a=t>0?(null==(i=o[t-1])?void 0:i.key)??n.getItemKey(t-1):null;if(r!==t||t>0&&r>0&&(h.getItemKey(0)!==u||h.getItemKey(r-1)!==a)){const s=t>0?this.getVirtualItemForOffset(this.getScrollOffset())??o[0]:null;s&&(e=[s.key,this.getScrollOffset()-s.start]);const i=!0===h.followOnAppend?"auto":h.followOnAppend||null;i&&r>t&&this.isAtEnd(n.scrollEndThreshold)&&(0===t||h.getItemKey(r-1)!==a)&&(l=i)}}this.options=h,(e||l)&&(this.pendingScrollAnchor=[(null==e?void 0:e[0])??null,(null==e?void 0:e[1])??0,l])},this.notify=t=>{var s,i;null==(i=(s=this.options).onChange)||i.call(s,this,t)},this.maybeNotify=t((()=>(this.calculateRange(),[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null])),(t=>{this.notify(t)}),{key:!1,debug:()=>this.options.debug,initialDeps:[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]}),this.cleanup=()=>{this.unsubs.filter(Boolean).forEach((t=>t())),this.unsubs=[],this.observer.disconnect(),null!=this.rafId&&this.targetWindow&&(this.targetWindow.cancelAnimationFrame(this.rafId),this.rafId=null),this.scrollState=null,this.scrollElement=null,this.targetWindow=null},this._didMount=()=>()=>{this.cleanup()},this._willUpdate=()=>{var t;const s=this.options.enabled?this.options.getScrollElement():null;if(this.scrollElement!==s){if(this.cleanup(),!s)return void this.maybeNotify();if(this.scrollElement=s,this.scrollElement&&"ownerDocument"in this.scrollElement?this.targetWindow=this.scrollElement.ownerDocument.defaultView:this.targetWindow=(null==(t=this.scrollElement)?void 0:t.window)??null,this.elementsCache.forEach((t=>{this.observer.observe(t)})),this.unsubs.push(this.options.observeElementRect(this,(t=>{this.scrollRect=t,this.maybeNotify()}))),this.unsubs.push(this.options.observeElementOffset(this,((t,s)=>{null!==this._intendedScrollOffset&&Math.abs(t-this._intendedScrollOffset)<1.5&&(t=this._intendedScrollOffset),this._intendedScrollOffset=null,this.scrollAdjustments=0,this.scrollDirection=s?this.getScrollOffset()<t?"forward":"backward":null,this.scrollOffset=t,this.isScrolling=s,this._flushIosDeferredIfReady(),this.scrollState&&this.scheduleScrollReconcile(),this.maybeNotify()}))),"addEventListener"in this.scrollElement){const t=this.scrollElement,s=()=>{this._iosTouching=!0,this._iosJustTouchEnded=!1,null!==this._iosTouchEndTimerId&&null!=this.targetWindow&&(this.targetWindow.clearTimeout(this._iosTouchEndTimerId),this._iosTouchEndTimerId=null)},i=()=>{this._iosTouching=!1,e()&&null!=this.targetWindow&&(this._iosJustTouchEnded=!0,this._iosTouchEndTimerId=this.targetWindow.setTimeout((()=>{this._iosJustTouchEnded=!1,this._iosTouchEndTimerId=null,this._flushIosDeferredIfReady()}),150))};t.addEventListener("touchstart",s,a),t.addEventListener("touchend",i,a),this.unsubs.push((()=>{t.removeEventListener("touchstart",s),t.removeEventListener("touchend",i),null!==this._iosTouchEndTimerId&&null!=this.targetWindow&&(this.targetWindow.clearTimeout(this._iosTouchEndTimerId),this._iosTouchEndTimerId=null)}))}this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0})}const h=this.pendingScrollAnchor;if(this.pendingScrollAnchor=null,h&&this.scrollElement&&this.options.enabled){const[t,s,n]=h;if(null!==t){const{count:h,getItemKey:n}=this.options;let e=0;for(;e<h&&n(e)!==t;)e++;const l=e<h?this.getMeasurements()[e]:void 0;if(l){const t=l.start+s-this.getScrollOffset();i(t,0)||this.applyScrollAdjustment(t)}}n&&this.scrollToEnd({behavior:n})}},this._flushIosDeferredIfReady=()=>{if(0===this._iosDeferredAdjustment)return;if(this.isScrolling)return;if(this._iosTouching)return;if(this._iosJustTouchEnded)return;const t=this.getScrollOffset(),s=this.getMaxScrollOffset();if(t<0||t>s)return;const i=this._iosDeferredAdjustment;this._iosDeferredAdjustment=0,this._scrollToOffset(t,{adjustments:this.scrollAdjustments+=i,behavior:void 0})},this.rafId=null,this.getSize=()=>this.options.enabled?(this.scrollRect=this.scrollRect??this.options.initialRect,this.scrollRect[this.options.horizontal?"width":"height"]):(this.scrollRect=null,0),this.getScrollOffset=()=>this.options.enabled?(this.scrollOffset=this.scrollOffset??("function"==typeof this.options.initialOffset?this.options.initialOffset():this.options.initialOffset),this.scrollOffset):(this.scrollOffset=null,0),this.getFurthestMeasurement=(t,s)=>{const i=new Map,h=new Map;for(let n=s-1;n>=0;n--){const s=t[n];if(i.has(s.lane))continue;const e=h.get(s.lane);if(null==e||s.end>e.end?h.set(s.lane,s):s.end<e.end&&i.set(s.lane,!0),i.size===this.options.lanes)break}return h.size===this.options.lanes?Array.from(h.values()).sort(((t,s)=>t.end===s.end?t.index-s.index:t.end-s.end))[0]:void 0},this.getMeasurementOptions=t((()=>[this.options.count,this.options.paddingStart,this.options.scrollMargin,this.options.getItemKey,this.options.enabled,this.options.lanes,this.options.laneAssignmentMode]),((t,s,i,h,n,e,l)=>(void 0!==this.prevLanes&&this.prevLanes!==e&&(this.lanesChangedFlag=!0),this.prevLanes=e,this.pendingMin=null,{count:t,paddingStart:s,scrollMargin:i,getItemKey:h,enabled:n,lanes:e,laneAssignmentMode:l})),{key:!1}),this.getMeasurements=t((()=>[this.getMeasurementOptions(),this.itemSizeCacheVersion]),(({count:t,paddingStart:s,scrollMargin:i,getItemKey:h,enabled:n,lanes:e,laneAssignmentMode:l},r)=>{const o=this.itemSizeCache;if(!n)return this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),[];if(this.laneAssignments.size>t)for(const s of this.laneAssignments.keys())s>=t&&this.laneAssignments.delete(s);this.lanesChangedFlag&&(this.lanesChangedFlag=!1,this.lanesSettling=!0,this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),this.pendingMin=null),0!==this.measurementsCache.length||this.lanesSettling||(this.measurementsCache=this.options.initialMeasurementsCache,this.measurementsCache.forEach((t=>{this.itemSizeCache.set(t.key,t.size)})));const u=this.lanesSettling?0:this.pendingMin??0;if(this.pendingMin=null,this.lanesSettling&&this.measurementsCache.length===t&&(this.lanesSettling=!1),1===e){const n=this.options.gap,e=2*t;let l,r=this._flatMeasurements;if(!r||r.length<e){const t=new Float64Array(e);r&&u>0&&t.set(r.subarray(0,2*u)),r=t,this._flatMeasurements=r}if(0===u)l=s+i;else{const t=u-1;l=r[2*t]+r[2*t+1]+n}for(let s=u;s<t;s++){const t=h(s),i=o.get(t),e="number"==typeof i?i:this.options.estimateSize(s);r[2*s]=l,r[2*s+1]=e,l+=e+n}const a=function(t,s,i){const h=new Array(t);return new Proxy(h,{get(h,n,e){if("string"==typeof n){const e=n.charCodeAt(0);if(e>=48&&e<=57){const e=+n;if(Number.isInteger(e)&&e>=0&&e<t){let t=h[e];if(!t){const n=s[2*e];t=h[e]={index:e,key:i(e),start:n,size:s[2*e+1],end:n+s[2*e+1],lane:0}}return t}}if("length"===n)return t}return Reflect.get(h,n,e)}})}(t,r,h);return this.measurementsCache=a,a}const a=this.measurementsCache.slice(0,u),c=new Array(e).fill(void 0);for(let t=0;t<u;t++){const s=a[t];s&&(c[s.lane]=t)}for(let n=u;n<t;n++){const t=h(n),e=this.laneAssignments.get(n);let r,u;const d="estimate"===l||o.has(t);if(void 0!==e&&this.options.lanes>1){r=e;const t=c[r],h=void 0!==t?a[t]:void 0;u=h?h.end+this.options.gap:s+i}else{const t=1===this.options.lanes?a[n-1]:this.getFurthestMeasurement(a,n);u=t?t.end+this.options.gap:s+i,r=t?t.lane:n%this.options.lanes,this.options.lanes>1&&d&&this.laneAssignments.set(n,r)}const f=o.get(t),v="number"==typeof f?f:this.options.estimateSize(n),b=u+v;a[n]={index:n,start:u,size:v,end:b,key:t,lane:r},c[r]=n}return this.measurementsCache=a,a}),{key:!1,debug:()=>this.options.debug}),this.calculateRange=t((()=>[this.getMeasurements(),this.getSize(),this.getScrollOffset(),this.options.lanes]),((t,s,i,h)=>this.range=t.length>0&&s>0?function({measurements:t,outerSize:s,scrollOffset:i,lanes:h,flat:n}){const e=t.length-1,l=n?t=>n[2*t]:s=>t[s].start,r=n?t=>n[2*t]+n[2*t+1]:s=>t[s].end;if(t.length<=h)return{startIndex:0,endIndex:e};let o=g(0,e,l,i),u=o;if(1===h)for(;u<e&&r(u)<i+s;)u++;else if(h>1){const n=Array(h).fill(0);for(;u<e&&n.some((t=>t<i+s));){const s=t[u];n[s.lane]=s.end,u++}const l=Array(h).fill(i+s);for(;o>=0&&l.some((t=>t>=i));){const s=t[o];l[s.lane]=s.start,o--}o=Math.max(0,o-o%h),u=Math.min(e,u+(h-1-u%h))}return{startIndex:o,endIndex:u}}({measurements:t,outerSize:s,scrollOffset:i,lanes:h,flat:1===h&&null!=this._flatMeasurements?this._flatMeasurements:null}):null),{key:!1,debug:()=>this.options.debug}),this.getVirtualIndexes=t((()=>{let t=null,s=null;const i=this.calculateRange();return i&&(t=i.startIndex,s=i.endIndex),this.maybeNotify.updateDeps([this.isScrolling,t,s]),[this.options.rangeExtractor,this.options.overscan,this.options.count,t,s]}),((t,s,i,h,n)=>null===h||null===n?[]:t({startIndex:h,endIndex:n,overscan:s,count:i})),{key:!1,debug:()=>this.options.debug}),this.indexFromElement=t=>{const s=this.options.indexAttribute,i=t.getAttribute(s);return i?parseInt(i,10):(console.warn(`Missing attribute name '${s}={index}' on measured element.`),-1)},this.shouldMeasureDuringScroll=t=>{var s;if(!this.scrollState||"smooth"!==this.scrollState.behavior)return!0;const i=this.scrollState.index??(null==(s=this.getVirtualItemForOffset(this.scrollState.lastTargetOffset))?void 0:s.index);if(void 0!==i&&this.range){const s=Math.max(this.options.overscan,Math.ceil((this.range.endIndex-this.range.startIndex)/2)),h=Math.max(0,i-s),n=Math.min(this.options.count-1,i+s);return t>=h&&t<=n}return!0},this.measureElement=t=>{if(!t)return void this.elementsCache.forEach(((t,s)=>{t.isConnected||(this.observer.unobserve(t),this.elementsCache.delete(s))}));const s=this.indexFromElement(t),i=this.options.getItemKey(s),h=this.elementsCache.get(i);h!==t&&(h&&this.observer.unobserve(h),this.observer.observe(t),this.elementsCache.set(i,t)),this.isScrolling&&!this.scrollState||!this.shouldMeasureDuringScroll(s)||this.resizeItem(s,this.options.measureElement(t,void 0,this))},this.resizeItem=(t,s)=>{var i,h;if(t<0||t>=this.options.count)return;let n,e,l;const r=this._flatMeasurements;if(1===this.options.lanes&&null!==r)l=this.options.getItemKey(t),e=r[2*t],n=r[2*t+1];else{const s=this.measurementsCache[t];if(!s)return;l=s.key,e=s.start,n=s.size}const o=s-(this.itemSizeCache.get(l)??n);if(0!==o){const r="end"===this.options.anchorTo&&"smooth"!==(null==(i=this.scrollState)?void 0:i.behavior)&&this.getVirtualDistanceFromEnd()<=this.options.scrollEndThreshold,u=r?this.getTotalSize():0,a="smooth"!==(null==(h=this.scrollState)?void 0:h.behavior)&&(void 0!==this.shouldAdjustScrollPositionOnItemSizeChange?this.shouldAdjustScrollPositionOnItemSizeChange(this.measurementsCache[t]??{index:t,key:l,start:e,size:n,end:e+n,lane:0},o,this):e<this.getScrollOffset()+this.scrollAdjustments&&"backward"!==this.scrollDirection);(null===this.pendingMin||t<this.pendingMin)&&(this.pendingMin=t),this.itemSizeCache.set(l,s),this.itemSizeCacheVersion++,r?this.applyScrollAdjustment(this.getTotalSize()-u):a&&this.applyScrollAdjustment(o),this.notify(!1)}},this.getVirtualItems=t((()=>[this.getVirtualIndexes(),this.getMeasurements()]),((t,s)=>{const i=[];for(let h=0,n=t.length;h<n;h++){const n=s[t[h]];i.push(n)}return i}),{key:!1,debug:()=>this.options.debug}),this.getVirtualItemForOffset=t=>{const i=this.getMeasurements();if(0===i.length)return;const h=this._flatMeasurements,n=1===this.options.lanes&&null!=h,e=g(0,i.length-1,n?t=>h[2*t]:t=>s(i[t]).start,t);return s(i[e])},this.getMaxScrollOffset=()=>{if(!this.scrollElement)return 0;if("scrollHeight"in this.scrollElement)return this.options.horizontal?this.scrollElement.scrollWidth-this.scrollElement.clientWidth:this.scrollElement.scrollHeight-this.scrollElement.clientHeight;{const t=this.scrollElement.document.documentElement;return this.options.horizontal?t.scrollWidth-this.scrollElement.innerWidth:t.scrollHeight-this.scrollElement.innerHeight}},this.getVirtualDistanceFromEnd=()=>Math.max(this.getTotalSize()-this.getSize()-this.getScrollOffset(),0),this.getDistanceFromEnd=()=>Math.max(this.getMaxScrollOffset()-this.getScrollOffset(),0),this.isAtEnd=(t=this.options.scrollEndThreshold)=>this.getDistanceFromEnd()<=t,this.getOffsetForAlignment=(t,s,i=0)=>{if(!this.scrollElement)return 0;const h=this.getSize(),n=this.getScrollOffset();"auto"===s&&(s=t>=n+h?"end":"start"),"center"===s?t+=(i-h)/2:"end"===s&&(t-=h);const e=this.getMaxScrollOffset();return Math.max(Math.min(e,t),0)},this.getOffsetForIndex=(t,s="auto")=>{t=Math.max(0,Math.min(t,this.options.count-1));const i=this.getSize(),h=this.getScrollOffset(),n=this.measurementsCache[t];if(!n)return;if("auto"===s)if(n.end>=h+i-this.options.scrollPaddingEnd)s="end";else{if(!(n.start<=h+this.options.scrollPaddingStart))return[h,s];s="start"}if("end"===s&&t===this.options.count-1)return[this.getMaxScrollOffset(),s];const e="end"===s?n.end+this.options.scrollPaddingEnd:n.start-this.options.scrollPaddingStart;return[this.getOffsetForAlignment(e,s,n.size),s]},this.scrollToOffset=(t,{align:s="start",behavior:i="auto"}={})=>{const h=this.getOffsetForAlignment(t,s),n=this.now();this.scrollState={index:null,align:s,behavior:i,startedAt:n,lastTargetOffset:h,stableFrames:0},this._scrollToOffset(h,{adjustments:void 0,behavior:i}),this.scheduleScrollReconcile()},this.scrollToIndex=(t,{align:s="auto",behavior:i="auto"}={})=>{t=Math.max(0,Math.min(t,this.options.count-1));const h=this.getOffsetForIndex(t,s);if(!h)return;const[n,e]=h,l=this.now();this.scrollState={index:t,align:e,behavior:i,startedAt:l,lastTargetOffset:n,stableFrames:0},this._scrollToOffset(n,{adjustments:void 0,behavior:i}),this.scheduleScrollReconcile()},this.scrollBy=(t,{behavior:s="auto"}={})=>{const i=this.getScrollOffset()+t,h=this.now();this.scrollState={index:null,align:"start",behavior:s,startedAt:h,lastTargetOffset:i,stableFrames:0},this._scrollToOffset(i,{adjustments:void 0,behavior:s}),this.scheduleScrollReconcile()},this.scrollToEnd=({behavior:t="auto"}={})=>{this.options.count>0?this.scrollToIndex(this.options.count-1,{align:"end",behavior:t}):this.scrollToOffset(Math.max(this.getTotalSize()-this.getSize(),0),{behavior:t})},this.getTotalSize=()=>{var t;const s=this.getMeasurements();let i;if(0===s.length)i=this.options.paddingStart;else if(1===this.options.lanes){const h=s.length-1,n=this._flatMeasurements;i=null!=n?n[2*h]+n[2*h+1]:(null==(t=s[h])?void 0:t.end)??0}else{const t=Array(this.options.lanes).fill(null);let h=s.length-1;for(;h>=0&&t.some((t=>null===t));){const i=s[h];null===t[i.lane]&&(t[i.lane]=i.end),h--}i=Math.max(...t.filter((t=>null!==t)))}return Math.max(i-this.options.scrollMargin+this.options.paddingEnd,0)},this.takeSnapshot=()=>{const t=[];if(0===this.itemSizeCache.size)return t;const s=this.getMeasurements();for(const i of s)i&&this.itemSizeCache.has(i.key)&&t.push({index:i.index,key:i.key,start:i.start,size:i.size,end:i.end,lane:i.lane});return t},this._scrollToOffset=(t,{adjustments:s,behavior:i})=>{this._intendedScrollOffset=t+(s??0),this.options.scrollToFn(t,{behavior:i,adjustments:s},this)},this.measure=()=>{this.pendingMin=null,this.itemSizeCache.clear(),this.laneAssignments.clear(),this.itemSizeCacheVersion++,this.notify(!1)},this.setOptions(h)}applyScrollAdjustment(t,s){0!==t&&(e()&&(this.isScrolling||this._iosTouching||this._iosJustTouchEnded)?this._iosDeferredAdjustment+=t:this._scrollToOffset(this.getScrollOffset(),{adjustments:this.scrollAdjustments+=t,behavior:s}))}scheduleScrollReconcile(){this.targetWindow?null==this.rafId&&(this.rafId=this.targetWindow.requestAnimationFrame((()=>{this.rafId=null,this.reconcileScroll()}))):this.scrollState=null}reconcileScroll(){if(!this.scrollState)return;if(!this.scrollElement)return;if(this.now()-this.scrollState.startedAt>5e3)return void(this.scrollState=null);const t=null!=this.scrollState.index?this.getOffsetForIndex(this.scrollState.index,this.scrollState.align):void 0,s=t?t[0]:this.scrollState.lastTargetOffset,h=s!==this.scrollState.lastTargetOffset;if(!h&&i(s,this.getScrollOffset())){if(this.scrollState.stableFrames++,this.scrollState.stableFrames>=1)return this.getScrollOffset()!==s&&this._scrollToOffset(s,{adjustments:void 0,behavior:"auto"}),void(this.scrollState=null)}else if(this.scrollState.stableFrames=0,h){const t=this.getSize()||600,i=Math.abs(s-this.getScrollOffset()),h="smooth"===this.scrollState.behavior&&i>t;this.scrollState.lastTargetOffset=s,h||(this.scrollState.behavior="auto"),this._scrollToOffset(s,{adjustments:void 0,behavior:h?"smooth":"auto"})}this.scheduleScrollReconcile()}}const g=(t,s,i,h)=>{for(;t<=s;){const n=(t+s)/2|0,e=i(n);if(e<h)t=n+1;else{if(!(e>h))return n;s=n-1}}return t>0?t-1:0};class m{constructor(t,s){this.cleanup=()=>{};const i={...s,onChange:(t,i)=>{var h;this.host.updateComplete.then((()=>this.host.requestUpdate())),null==(h=s.onChange)||h.call(s,t,i)}};this.virtualizer=new b(i),(this.host=t).addController(this)}getVirtualizer(){return this.virtualizer}hostConnected(){this.cleanup=this.virtualizer._didMount()}hostUpdated(){this.virtualizer._willUpdate()}hostDisconnected(){this.cleanup()}}class M extends m{constructor(t,s){super(t,{observeElementRect:u,observeElementOffset:d,scrollToFn:v,...s})}}export{M as V};
|