@gridkitjs/dom 0.3.3 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +99 -38
- package/dist/index.js +307 -158
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -69,13 +69,15 @@ function bodyRowFrom(target) {
|
|
|
69
69
|
// src/checklist/attachChecklist.ts
|
|
70
70
|
var ITEM = "[data-gridkit-checklist-item]";
|
|
71
71
|
var INDEX = "data-gridkit-checklist-index";
|
|
72
|
+
var SETTLED = { kind: "settled" };
|
|
73
|
+
var DETACHED = { kind: "detached" };
|
|
72
74
|
function indexOf(item) {
|
|
73
75
|
return Number(item.getAttribute(INDEX));
|
|
74
76
|
}
|
|
75
77
|
function attachChecklist(list, options) {
|
|
76
78
|
let count = 0;
|
|
77
79
|
let active = 0;
|
|
78
|
-
let
|
|
80
|
+
let state = SETTLED;
|
|
79
81
|
function items() {
|
|
80
82
|
return Array.from(list.querySelectorAll(ITEM));
|
|
81
83
|
}
|
|
@@ -102,7 +104,7 @@ function attachChecklist(list, options) {
|
|
|
102
104
|
}
|
|
103
105
|
}
|
|
104
106
|
function moveTo(index) {
|
|
105
|
-
if (count === 0) {
|
|
107
|
+
if (state.kind === "detached" || count === 0) {
|
|
106
108
|
return;
|
|
107
109
|
}
|
|
108
110
|
const target = Math.max(0, Math.min(index, count - 1));
|
|
@@ -111,9 +113,9 @@ function attachChecklist(list, options) {
|
|
|
111
113
|
options.scrollToIndex(target);
|
|
112
114
|
const item = itemAt(target);
|
|
113
115
|
if (item === null) {
|
|
114
|
-
|
|
116
|
+
state = { kind: "awaiting-item", index: target };
|
|
115
117
|
} else {
|
|
116
|
-
|
|
118
|
+
state = SETTLED;
|
|
117
119
|
item.focus({ preventScroll: true });
|
|
118
120
|
}
|
|
119
121
|
}
|
|
@@ -163,7 +165,7 @@ function attachChecklist(list, options) {
|
|
|
163
165
|
function onFocusIn(event) {
|
|
164
166
|
const item = itemOf(event.target);
|
|
165
167
|
if (item !== null) {
|
|
166
|
-
|
|
168
|
+
state = SETTLED;
|
|
167
169
|
makeActive(indexOf(item));
|
|
168
170
|
setTabStop();
|
|
169
171
|
}
|
|
@@ -175,17 +177,20 @@ function attachChecklist(list, options) {
|
|
|
175
177
|
item.focus({ preventScroll: true });
|
|
176
178
|
}
|
|
177
179
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
const item = pending === null ? null : itemAt(pending);
|
|
180
|
+
function focusAwaitedItemIfMounted() {
|
|
181
|
+
const item = state.kind === "awaiting-item" ? itemAt(state.index) : null;
|
|
181
182
|
if (item === null) {
|
|
182
183
|
return;
|
|
183
184
|
}
|
|
184
|
-
|
|
185
|
+
state = SETTLED;
|
|
185
186
|
const focused = document.activeElement;
|
|
186
187
|
if (focused === null || focused === document.body || list.contains(focused)) {
|
|
187
188
|
item.focus({ preventScroll: true });
|
|
188
189
|
}
|
|
190
|
+
}
|
|
191
|
+
const observer = new MutationObserver(() => {
|
|
192
|
+
setTabStop();
|
|
193
|
+
focusAwaitedItemIfMounted();
|
|
189
194
|
});
|
|
190
195
|
observer.observe(list, {
|
|
191
196
|
childList: true,
|
|
@@ -198,13 +203,23 @@ function attachChecklist(list, options) {
|
|
|
198
203
|
list.addEventListener("click", onClick);
|
|
199
204
|
return {
|
|
200
205
|
setCount(next) {
|
|
206
|
+
if (state.kind === "detached") {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
201
209
|
count = next;
|
|
202
210
|
active = Math.max(0, Math.min(active, count - 1));
|
|
211
|
+
if (state.kind === "awaiting-item") {
|
|
212
|
+
state = count === 0 ? SETTLED : {
|
|
213
|
+
kind: "awaiting-item",
|
|
214
|
+
index: Math.min(state.index, count - 1)
|
|
215
|
+
};
|
|
216
|
+
}
|
|
203
217
|
setTabStop();
|
|
218
|
+
focusAwaitedItemIfMounted();
|
|
204
219
|
},
|
|
205
220
|
focusItem: moveTo,
|
|
206
221
|
detach() {
|
|
207
|
-
|
|
222
|
+
state = DETACHED;
|
|
208
223
|
observer.disconnect();
|
|
209
224
|
list.removeEventListener("keydown", onKeyDown2);
|
|
210
225
|
list.removeEventListener("focusin", onFocusIn);
|
|
@@ -322,61 +337,79 @@ function attachContextMenuTrigger(root, options) {
|
|
|
322
337
|
import { applyColumnResize } from "@gridkitjs/core";
|
|
323
338
|
|
|
324
339
|
// src/pointerGesture.ts
|
|
325
|
-
function
|
|
326
|
-
return press.button === 0 && press.isPrimary;
|
|
340
|
+
function mayStartGesture(press, signal) {
|
|
341
|
+
return press.button === 0 && press.isPrimary && signal?.aborted !== true;
|
|
327
342
|
}
|
|
328
|
-
function startPointerGesture(element, pointerId, handlers) {
|
|
343
|
+
function startPointerGesture(element, pointerId, handlers, signal) {
|
|
329
344
|
element.setPointerCapture(pointerId);
|
|
330
345
|
function stop() {
|
|
331
346
|
element.removeEventListener("pointermove", move);
|
|
332
347
|
element.removeEventListener("pointerup", end);
|
|
333
348
|
element.removeEventListener("pointercancel", cancel);
|
|
334
349
|
window.removeEventListener("keydown", onKeyDown2);
|
|
350
|
+
signal?.removeEventListener("abort", abandon);
|
|
335
351
|
if (element.hasPointerCapture(pointerId)) {
|
|
336
352
|
element.releasePointerCapture(pointerId);
|
|
337
353
|
}
|
|
338
354
|
}
|
|
339
355
|
function move(event) {
|
|
340
|
-
|
|
356
|
+
if (event.pointerId === pointerId) {
|
|
357
|
+
handlers.onMove(event);
|
|
358
|
+
}
|
|
341
359
|
}
|
|
342
|
-
function end() {
|
|
343
|
-
|
|
344
|
-
|
|
360
|
+
function end(event) {
|
|
361
|
+
if (event.pointerId === pointerId) {
|
|
362
|
+
stop();
|
|
363
|
+
handlers.onEnd();
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function cancel(event) {
|
|
367
|
+
if (event.pointerId === pointerId) {
|
|
368
|
+
abandon();
|
|
369
|
+
}
|
|
345
370
|
}
|
|
346
|
-
function
|
|
371
|
+
function abandon() {
|
|
347
372
|
stop();
|
|
348
373
|
handlers.onCancel();
|
|
349
374
|
}
|
|
350
375
|
function onKeyDown2(event) {
|
|
351
376
|
if (event.key === "Escape") {
|
|
352
|
-
|
|
377
|
+
abandon();
|
|
353
378
|
}
|
|
354
379
|
}
|
|
355
380
|
element.addEventListener("pointermove", move);
|
|
356
381
|
element.addEventListener("pointerup", end);
|
|
357
382
|
element.addEventListener("pointercancel", cancel);
|
|
358
383
|
window.addEventListener("keydown", onKeyDown2);
|
|
384
|
+
signal?.addEventListener("abort", abandon);
|
|
359
385
|
}
|
|
360
386
|
|
|
361
387
|
// src/columnResize.ts
|
|
362
388
|
function startColumnResizeGesture(handle, press, session, handlers) {
|
|
363
|
-
if (!
|
|
389
|
+
if (!mayStartGesture(press, handlers.signal)) {
|
|
364
390
|
return false;
|
|
365
391
|
}
|
|
366
392
|
press.preventDefault();
|
|
367
393
|
let width = session.startWidth;
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
394
|
+
let resized = false;
|
|
395
|
+
startPointerGesture(
|
|
396
|
+
handle,
|
|
397
|
+
press.pointerId,
|
|
398
|
+
{
|
|
399
|
+
onMove(event) {
|
|
400
|
+
width = applyColumnResize(session, event.clientX);
|
|
401
|
+
resized ||= width !== session.startWidth;
|
|
402
|
+
handlers.onMove(width);
|
|
403
|
+
},
|
|
404
|
+
onEnd() {
|
|
405
|
+
handlers.onEnd(resized ? width : null);
|
|
406
|
+
},
|
|
407
|
+
onCancel() {
|
|
408
|
+
handlers.onCancel();
|
|
409
|
+
}
|
|
375
410
|
},
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
}
|
|
379
|
-
});
|
|
411
|
+
handlers.signal
|
|
412
|
+
);
|
|
380
413
|
return true;
|
|
381
414
|
}
|
|
382
415
|
function measureColumnContent(table, columnId) {
|
|
@@ -497,47 +530,46 @@ function downloadBlob(blob, fileName) {
|
|
|
497
530
|
|
|
498
531
|
// src/dragReorder.ts
|
|
499
532
|
var DRAG_THRESHOLD = 4;
|
|
500
|
-
var NO_DRAG = {
|
|
501
|
-
draggedId: null,
|
|
502
|
-
dropTarget: null,
|
|
503
|
-
ghostTransform: null
|
|
504
|
-
};
|
|
533
|
+
var NO_DRAG = { kind: "idle" };
|
|
505
534
|
function startDragReorder(id, grabElement, press, handlers) {
|
|
506
|
-
if (!
|
|
535
|
+
if (!mayStartGesture(press, handlers.signal)) {
|
|
507
536
|
return false;
|
|
508
537
|
}
|
|
509
|
-
const { pointerId, clientX: startX } = press;
|
|
538
|
+
const { pointerId, clientX: startX, clientY: startY } = press;
|
|
510
539
|
const grabX = startX - grabElement.getBoundingClientRect().left;
|
|
511
|
-
let
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
540
|
+
let phase = { kind: "pressed" };
|
|
541
|
+
startPointerGesture(
|
|
542
|
+
grabElement,
|
|
543
|
+
pointerId,
|
|
544
|
+
{
|
|
545
|
+
onMove(moveEvent) {
|
|
546
|
+
const { clientX, clientY } = moveEvent;
|
|
547
|
+
if (phase.kind === "pressed" && Math.hypot(clientX - startX, clientY - startY) < DRAG_THRESHOLD) {
|
|
518
548
|
return;
|
|
519
549
|
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
550
|
+
phase = {
|
|
551
|
+
kind: "dragging",
|
|
552
|
+
target: handlers.resolveTarget(clientX, clientY, id)
|
|
553
|
+
};
|
|
554
|
+
handlers.onState({
|
|
555
|
+
kind: "dragging",
|
|
556
|
+
draggedId: id,
|
|
557
|
+
dropTarget: phase.target,
|
|
558
|
+
ghostTransform: `translate(${String(clientX - grabX)}px, ${String(clientY)}px)`
|
|
559
|
+
});
|
|
560
|
+
},
|
|
561
|
+
onEnd() {
|
|
562
|
+
handlers.onState(NO_DRAG);
|
|
563
|
+
if (phase.kind === "dragging" && phase.target !== null) {
|
|
564
|
+
handlers.onDrop(phase.target, id);
|
|
565
|
+
}
|
|
566
|
+
},
|
|
567
|
+
onCancel() {
|
|
568
|
+
handlers.onState(NO_DRAG);
|
|
534
569
|
}
|
|
535
570
|
},
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
handlers.onState(NO_DRAG);
|
|
539
|
-
}
|
|
540
|
-
});
|
|
571
|
+
handlers.signal
|
|
572
|
+
);
|
|
541
573
|
return true;
|
|
542
574
|
}
|
|
543
575
|
|
|
@@ -594,7 +626,7 @@ function observeElementWidth(element, onWidth) {
|
|
|
594
626
|
// src/gridFocus.ts
|
|
595
627
|
import {
|
|
596
628
|
clampFocus,
|
|
597
|
-
|
|
629
|
+
headerFocus,
|
|
598
630
|
nextFocusForKey
|
|
599
631
|
} from "@gridkitjs/core";
|
|
600
632
|
var FALLBACK_PAGE = 10;
|
|
@@ -604,6 +636,12 @@ function cellIn(row, columnIndex) {
|
|
|
604
636
|
}
|
|
605
637
|
return row.cells[Math.min(columnIndex, row.cells.length - 1)] ?? null;
|
|
606
638
|
}
|
|
639
|
+
function sameCell(a, b) {
|
|
640
|
+
if (a.area === "body" && b.area === "body") {
|
|
641
|
+
return a.rowIndex === b.rowIndex && a.columnIndex === b.columnIndex;
|
|
642
|
+
}
|
|
643
|
+
return a.area === b.area && a.columnIndex === b.columnIndex;
|
|
644
|
+
}
|
|
607
645
|
function findBodyRow(bodyTable, rowIndex) {
|
|
608
646
|
return bodyTable?.tBodies[0]?.querySelector(
|
|
609
647
|
`:scope > tr[data-gridkit-row-index="${String(rowIndex)}"]`
|
|
@@ -621,7 +659,7 @@ function createGridFocus(initialOptions) {
|
|
|
621
659
|
let options = initialOptions;
|
|
622
660
|
let rows = null;
|
|
623
661
|
const listeners = /* @__PURE__ */ new Set();
|
|
624
|
-
let stored =
|
|
662
|
+
let stored = headerFocus(0);
|
|
625
663
|
let snapshot = {
|
|
626
664
|
stored,
|
|
627
665
|
rowCount: options.rowCount,
|
|
@@ -640,14 +678,28 @@ function createGridFocus(initialOptions) {
|
|
|
640
678
|
}
|
|
641
679
|
return snapshot.focus;
|
|
642
680
|
}
|
|
643
|
-
function
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
681
|
+
function dropPendingMove() {
|
|
682
|
+
pendingMove = null;
|
|
683
|
+
}
|
|
684
|
+
function listenForTakeover(root) {
|
|
685
|
+
function onFocusOut(event) {
|
|
686
|
+
const to = event.relatedTarget;
|
|
687
|
+
if (to instanceof Node && !root.contains(to)) {
|
|
688
|
+
dropPendingMove();
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
root.addEventListener("focusout", onFocusOut);
|
|
692
|
+
root.addEventListener("wheel", dropPendingMove, { passive: true });
|
|
693
|
+
root.addEventListener("pointerdown", dropPendingMove);
|
|
694
|
+
return () => {
|
|
695
|
+
root.removeEventListener("focusout", onFocusOut);
|
|
696
|
+
root.removeEventListener("wheel", dropPendingMove);
|
|
697
|
+
root.removeEventListener("pointerdown", dropPendingMove);
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
function focusCell(focus) {
|
|
701
|
+
const next = clampFocus(focus, options.rowCount, options.columnCount);
|
|
702
|
+
if (sameCell(next, getFocus())) {
|
|
651
703
|
return;
|
|
652
704
|
}
|
|
653
705
|
pendingMove = next;
|
|
@@ -681,12 +733,14 @@ function createGridFocus(initialOptions) {
|
|
|
681
733
|
if (next === null) {
|
|
682
734
|
return false;
|
|
683
735
|
}
|
|
684
|
-
focusCell(next
|
|
736
|
+
focusCell(next);
|
|
685
737
|
return true;
|
|
686
738
|
},
|
|
687
|
-
attach(next) {
|
|
739
|
+
attach(next, root) {
|
|
688
740
|
rows = next;
|
|
741
|
+
const stopListening = root == null ? void 0 : listenForTakeover(root);
|
|
689
742
|
return () => {
|
|
743
|
+
stopListening?.();
|
|
690
744
|
if (rows === next) {
|
|
691
745
|
rows = null;
|
|
692
746
|
}
|
|
@@ -697,7 +751,7 @@ function createGridFocus(initialOptions) {
|
|
|
697
751
|
return;
|
|
698
752
|
}
|
|
699
753
|
const cell = cellIn(
|
|
700
|
-
drawn.
|
|
754
|
+
drawn.area === "header" ? rows.getHeaderRow() : rows.getBodyRow(drawn.rowIndex),
|
|
701
755
|
drawn.columnIndex
|
|
702
756
|
);
|
|
703
757
|
if (cell !== null) {
|
|
@@ -706,7 +760,7 @@ function createGridFocus(initialOptions) {
|
|
|
706
760
|
return;
|
|
707
761
|
}
|
|
708
762
|
const range = options.virtualRange;
|
|
709
|
-
if (range != null && drawn.
|
|
763
|
+
if (range != null && drawn.area === "body" && (drawn.rowIndex < range.startIndex || drawn.rowIndex > range.endIndex)) {
|
|
710
764
|
range.scrollToIndex(drawn.rowIndex);
|
|
711
765
|
return;
|
|
712
766
|
}
|
|
@@ -716,20 +770,48 @@ function createGridFocus(initialOptions) {
|
|
|
716
770
|
}
|
|
717
771
|
|
|
718
772
|
// src/infiniteScroll.ts
|
|
773
|
+
var IDLE = { kind: "idle" };
|
|
774
|
+
var LOADING = { kind: "loading" };
|
|
775
|
+
var DETACHED2 = { kind: "detached" };
|
|
776
|
+
function afterUpdate(state, loading, hasMoreChanged) {
|
|
777
|
+
if (loading) {
|
|
778
|
+
return LOADING;
|
|
779
|
+
}
|
|
780
|
+
return state.kind === "loading" || hasMoreChanged ? IDLE : state;
|
|
781
|
+
}
|
|
782
|
+
function contentOffset(root, sentinel) {
|
|
783
|
+
return sentinel.getBoundingClientRect().top - root.getBoundingClientRect().top + root.scrollTop;
|
|
784
|
+
}
|
|
719
785
|
function attachInfiniteScroll(root, options) {
|
|
720
786
|
let latest = options;
|
|
721
787
|
let intersecting = false;
|
|
722
|
-
let
|
|
723
|
-
let wasLoading = options.isLoadingMore ?? false;
|
|
788
|
+
let state = options.isLoadingMore ?? false ? LOADING : IDLE;
|
|
724
789
|
let observer = null;
|
|
725
790
|
let observed = null;
|
|
726
791
|
function maybeLoadMore() {
|
|
727
|
-
if (
|
|
792
|
+
if (state.kind !== "idle" || !intersecting || observed === null || !latest.hasMore) {
|
|
728
793
|
return;
|
|
729
794
|
}
|
|
730
|
-
|
|
795
|
+
state = {
|
|
796
|
+
kind: "requested",
|
|
797
|
+
sentinelOffset: contentOffset(root, observed.sentinel)
|
|
798
|
+
};
|
|
731
799
|
latest.onLoadMore?.();
|
|
732
800
|
}
|
|
801
|
+
function requestAnswered() {
|
|
802
|
+
if (state.kind !== "requested" || observed === null) {
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
const moved = contentOffset(root, observed.sentinel) - state.sentinelOffset;
|
|
806
|
+
return Math.abs(moved) >= 1;
|
|
807
|
+
}
|
|
808
|
+
function report(isIntersecting) {
|
|
809
|
+
intersecting = isIntersecting;
|
|
810
|
+
if (!intersecting && state.kind === "requested") {
|
|
811
|
+
state = IDLE;
|
|
812
|
+
}
|
|
813
|
+
maybeLoadMore();
|
|
814
|
+
}
|
|
733
815
|
function disconnect() {
|
|
734
816
|
observer?.disconnect();
|
|
735
817
|
observer = null;
|
|
@@ -749,11 +831,9 @@ function attachInfiniteScroll(root, options) {
|
|
|
749
831
|
observer = new IntersectionObserver(
|
|
750
832
|
(entries) => {
|
|
751
833
|
const entry = entries[entries.length - 1];
|
|
752
|
-
if (entry
|
|
753
|
-
|
|
834
|
+
if (entry !== void 0) {
|
|
835
|
+
report(entry.isIntersecting);
|
|
754
836
|
}
|
|
755
|
-
intersecting = entry.isIntersecting;
|
|
756
|
-
maybeLoadMore();
|
|
757
837
|
},
|
|
758
838
|
{ root, rootMargin }
|
|
759
839
|
);
|
|
@@ -763,16 +843,24 @@ function attachInfiniteScroll(root, options) {
|
|
|
763
843
|
observe();
|
|
764
844
|
return {
|
|
765
845
|
update(next) {
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
if (wasLoading && !loading) {
|
|
769
|
-
fired = false;
|
|
770
|
-
maybeLoadMore();
|
|
846
|
+
if (state.kind === "detached") {
|
|
847
|
+
return;
|
|
771
848
|
}
|
|
772
|
-
|
|
849
|
+
const hasMoreChanged = next.hasMore !== latest.hasMore;
|
|
850
|
+
latest = next;
|
|
851
|
+
state = afterUpdate(state, next.isLoadingMore ?? false, hasMoreChanged);
|
|
773
852
|
observe();
|
|
853
|
+
if (requestAnswered()) {
|
|
854
|
+
state = IDLE;
|
|
855
|
+
disconnect();
|
|
856
|
+
observe();
|
|
857
|
+
}
|
|
858
|
+
maybeLoadMore();
|
|
774
859
|
},
|
|
775
|
-
detach
|
|
860
|
+
detach() {
|
|
861
|
+
disconnect();
|
|
862
|
+
state = DETACHED2;
|
|
863
|
+
}
|
|
776
864
|
};
|
|
777
865
|
}
|
|
778
866
|
|
|
@@ -792,6 +880,8 @@ var MOVES = {
|
|
|
792
880
|
Home: "first",
|
|
793
881
|
End: "last"
|
|
794
882
|
};
|
|
883
|
+
var IDLE2 = { kind: "idle" };
|
|
884
|
+
var AWAY = { kind: "away" };
|
|
795
885
|
function idOf(item) {
|
|
796
886
|
return item.getAttribute("data-gridkit-menu-item") ?? "";
|
|
797
887
|
}
|
|
@@ -809,10 +899,8 @@ function isTypeahead(event) {
|
|
|
809
899
|
return /^\S$/u.test(event.key) && !event.ctrlKey && !event.metaKey && !event.altKey;
|
|
810
900
|
}
|
|
811
901
|
function attachMenu(panel, options) {
|
|
812
|
-
let
|
|
813
|
-
let
|
|
814
|
-
let hovered = null;
|
|
815
|
-
let hoverTimer;
|
|
902
|
+
let typeahead = IDLE2;
|
|
903
|
+
let hover = AWAY;
|
|
816
904
|
function items() {
|
|
817
905
|
return Array.from(panel.querySelectorAll(ITEM2));
|
|
818
906
|
}
|
|
@@ -841,21 +929,58 @@ function attachMenu(panel, options) {
|
|
|
841
929
|
options.onActivate(idOf(item));
|
|
842
930
|
}
|
|
843
931
|
}
|
|
844
|
-
function
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
932
|
+
function endTyping() {
|
|
933
|
+
if (typeahead.kind === "typing") {
|
|
934
|
+
window.clearTimeout(typeahead.timer);
|
|
935
|
+
}
|
|
936
|
+
typeahead = IDLE2;
|
|
937
|
+
}
|
|
938
|
+
function endHover() {
|
|
939
|
+
if (hover.kind === "resting") {
|
|
940
|
+
window.clearTimeout(hover.timer);
|
|
941
|
+
}
|
|
942
|
+
hover = AWAY;
|
|
943
|
+
}
|
|
944
|
+
function type(key, all, from) {
|
|
945
|
+
const typed = (typeahead.kind === "typing" ? typeahead.typed : "") + key;
|
|
946
|
+
endTyping();
|
|
947
|
+
typeahead = {
|
|
948
|
+
kind: "typing",
|
|
949
|
+
typed,
|
|
950
|
+
timer: window.setTimeout(() => {
|
|
951
|
+
typeahead = IDLE2;
|
|
952
|
+
}, TYPEAHEAD_TIMEOUT)
|
|
953
|
+
};
|
|
850
954
|
const match = all[typeaheadIndex(all.map(labelOf), from, typed)];
|
|
851
955
|
if (match !== void 0) {
|
|
852
956
|
focus(match);
|
|
853
957
|
}
|
|
854
958
|
}
|
|
959
|
+
function rest(item) {
|
|
960
|
+
hover = {
|
|
961
|
+
kind: "resting",
|
|
962
|
+
item,
|
|
963
|
+
timer: window.setTimeout(() => {
|
|
964
|
+
hover = { kind: "rested", item };
|
|
965
|
+
if (opensSubmenu(item) && !isDisabled(item)) {
|
|
966
|
+
openSubmenu(item, "none");
|
|
967
|
+
} else {
|
|
968
|
+
options.onCollapseSubmenu?.();
|
|
969
|
+
}
|
|
970
|
+
}, HOVER_DELAY)
|
|
971
|
+
};
|
|
972
|
+
}
|
|
855
973
|
function onKeyDown2(event) {
|
|
856
|
-
if (event.isComposing) {
|
|
974
|
+
if (event.isComposing || !actOnKey(event)) {
|
|
857
975
|
return;
|
|
858
976
|
}
|
|
977
|
+
event.preventDefault();
|
|
978
|
+
endHover();
|
|
979
|
+
if (!isTypeahead(event)) {
|
|
980
|
+
endTyping();
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
function actOnKey(event) {
|
|
859
984
|
const all = items();
|
|
860
985
|
const item = itemOf(event.target);
|
|
861
986
|
const from = item === null ? -1 : all.indexOf(item);
|
|
@@ -882,11 +1007,11 @@ function attachMenu(panel, options) {
|
|
|
882
1007
|
} else if (event.key === "Tab") {
|
|
883
1008
|
options.onClose("tab");
|
|
884
1009
|
} else if (isTypeahead(event)) {
|
|
885
|
-
|
|
1010
|
+
type(event.key, all, from);
|
|
886
1011
|
} else {
|
|
887
|
-
return;
|
|
1012
|
+
return false;
|
|
888
1013
|
}
|
|
889
|
-
|
|
1014
|
+
return true;
|
|
890
1015
|
}
|
|
891
1016
|
function onFocusIn(event) {
|
|
892
1017
|
const item = itemOf(event.target);
|
|
@@ -908,24 +1033,16 @@ function attachMenu(panel, options) {
|
|
|
908
1033
|
if (item !== null && document.activeElement !== item) {
|
|
909
1034
|
focus(item);
|
|
910
1035
|
}
|
|
911
|
-
if (item ===
|
|
1036
|
+
if (hover.kind !== "away" && hover.item === item) {
|
|
912
1037
|
return;
|
|
913
1038
|
}
|
|
914
|
-
|
|
915
|
-
window.clearTimeout(hoverTimer);
|
|
1039
|
+
endHover();
|
|
916
1040
|
if (item !== null) {
|
|
917
|
-
|
|
918
|
-
if (opensSubmenu(item) && !isDisabled(item)) {
|
|
919
|
-
openSubmenu(item, "none");
|
|
920
|
-
} else {
|
|
921
|
-
options.onCollapseSubmenu?.();
|
|
922
|
-
}
|
|
923
|
-
}, HOVER_DELAY);
|
|
1041
|
+
rest(item);
|
|
924
1042
|
}
|
|
925
1043
|
}
|
|
926
1044
|
function onPointerLeave() {
|
|
927
|
-
|
|
928
|
-
window.clearTimeout(hoverTimer);
|
|
1045
|
+
endHover();
|
|
929
1046
|
}
|
|
930
1047
|
const focused = itemOf(document.activeElement);
|
|
931
1048
|
setTabStop(focused ?? items()[0]);
|
|
@@ -943,8 +1060,8 @@ function attachMenu(panel, options) {
|
|
|
943
1060
|
}
|
|
944
1061
|
},
|
|
945
1062
|
detach() {
|
|
946
|
-
|
|
947
|
-
|
|
1063
|
+
endTyping();
|
|
1064
|
+
endHover();
|
|
948
1065
|
panel.removeEventListener("keydown", onKeyDown2);
|
|
949
1066
|
panel.removeEventListener("focusin", onFocusIn);
|
|
950
1067
|
panel.removeEventListener("click", onClick);
|
|
@@ -1238,15 +1355,18 @@ function attachOverlay(anchor, panel, options) {
|
|
|
1238
1355
|
if (settlingFrame !== null) {
|
|
1239
1356
|
cancelAnimationFrame(settlingFrame);
|
|
1240
1357
|
}
|
|
1241
|
-
if (
|
|
1242
|
-
|
|
1358
|
+
if (!focusInside) {
|
|
1359
|
+
return;
|
|
1243
1360
|
}
|
|
1361
|
+
const target = returnFocusTo?.isConnected === true ? returnFocusTo : options.returnFocusFallback?.();
|
|
1362
|
+
target?.focus({ preventScroll: true });
|
|
1244
1363
|
}
|
|
1245
1364
|
return detach;
|
|
1246
1365
|
}
|
|
1247
1366
|
|
|
1248
1367
|
// src/rowVirtualizer.ts
|
|
1249
1368
|
import { visibleRange } from "@gridkitjs/core";
|
|
1369
|
+
var READY = { kind: "ready" };
|
|
1250
1370
|
function sameRange(a, b) {
|
|
1251
1371
|
return a.startIndex === b.startIndex && a.endIndex === b.endIndex && a.offsetBefore === b.offsetBefore && a.offsetAfter === b.offsetAfter;
|
|
1252
1372
|
}
|
|
@@ -1256,13 +1376,12 @@ function createRowVirtualizer(scrollElement, options) {
|
|
|
1256
1376
|
let scrollTop = scrollElement.scrollTop;
|
|
1257
1377
|
let viewportHeight = scrollElement.clientHeight;
|
|
1258
1378
|
let range = null;
|
|
1259
|
-
let
|
|
1260
|
-
let pendingScroll;
|
|
1379
|
+
let phase = READY;
|
|
1261
1380
|
const elements = /* @__PURE__ */ new Map();
|
|
1262
1381
|
const indexByElement = /* @__PURE__ */ new Map();
|
|
1263
1382
|
const refCallbacks = /* @__PURE__ */ new Map();
|
|
1264
1383
|
function recompute() {
|
|
1265
|
-
if (destroyed) {
|
|
1384
|
+
if (phase.kind === "destroyed") {
|
|
1266
1385
|
return;
|
|
1267
1386
|
}
|
|
1268
1387
|
const next = visibleRange(
|
|
@@ -1313,10 +1432,16 @@ function createRowVirtualizer(scrollElement, options) {
|
|
|
1313
1432
|
recompute();
|
|
1314
1433
|
return {
|
|
1315
1434
|
setRowCount(count) {
|
|
1435
|
+
if (phase.kind === "awaiting-row" && phase.index >= count) {
|
|
1436
|
+
phase = READY;
|
|
1437
|
+
}
|
|
1316
1438
|
heights = Array.from({ length: count }, (_, index) => heights[index]);
|
|
1317
1439
|
recompute();
|
|
1318
1440
|
},
|
|
1319
1441
|
resetHeights() {
|
|
1442
|
+
if (phase.kind === "awaiting-row") {
|
|
1443
|
+
phase = READY;
|
|
1444
|
+
}
|
|
1320
1445
|
heights = new Array(heights.length).fill(void 0);
|
|
1321
1446
|
recompute();
|
|
1322
1447
|
},
|
|
@@ -1330,15 +1455,15 @@ function createRowVirtualizer(scrollElement, options) {
|
|
|
1330
1455
|
indexByElement.delete(previous);
|
|
1331
1456
|
elements.delete(index);
|
|
1332
1457
|
}
|
|
1333
|
-
if (element === null || destroyed) {
|
|
1458
|
+
if (element === null || phase.kind === "destroyed") {
|
|
1334
1459
|
return;
|
|
1335
1460
|
}
|
|
1336
1461
|
elements.set(index, element);
|
|
1337
1462
|
indexByElement.set(element, index);
|
|
1338
1463
|
rowObserver.observe(element);
|
|
1339
|
-
if (
|
|
1340
|
-
element.scrollIntoView(
|
|
1341
|
-
|
|
1464
|
+
if (phase.kind === "awaiting-row" && phase.index === index) {
|
|
1465
|
+
element.scrollIntoView(phase.options);
|
|
1466
|
+
phase = READY;
|
|
1342
1467
|
}
|
|
1343
1468
|
};
|
|
1344
1469
|
refCallbacks.set(index, callback);
|
|
@@ -1346,21 +1471,21 @@ function createRowVirtualizer(scrollElement, options) {
|
|
|
1346
1471
|
return callback;
|
|
1347
1472
|
},
|
|
1348
1473
|
scrollToIndex(index, scrollOptions) {
|
|
1349
|
-
if (heights.length === 0) {
|
|
1474
|
+
if (phase.kind === "destroyed" || heights.length === 0) {
|
|
1350
1475
|
return;
|
|
1351
1476
|
}
|
|
1352
1477
|
const clamped = Math.max(0, Math.min(index, heights.length - 1));
|
|
1353
1478
|
const mounted = elements.get(clamped);
|
|
1354
1479
|
if (mounted !== void 0) {
|
|
1480
|
+
phase = READY;
|
|
1355
1481
|
mounted.scrollIntoView(scrollOptions);
|
|
1356
1482
|
return;
|
|
1357
1483
|
}
|
|
1358
|
-
|
|
1484
|
+
phase = { kind: "awaiting-row", index: clamped, options: scrollOptions };
|
|
1359
1485
|
scrollElement.scrollTop = estimateOffsetBefore(clamped);
|
|
1360
1486
|
},
|
|
1361
1487
|
destroy() {
|
|
1362
|
-
|
|
1363
|
-
pendingScroll = void 0;
|
|
1488
|
+
phase = { kind: "destroyed" };
|
|
1364
1489
|
scrollElement.removeEventListener("scroll", handleScroll);
|
|
1365
1490
|
viewportObserver.disconnect();
|
|
1366
1491
|
rowObserver.disconnect();
|
|
@@ -1573,6 +1698,7 @@ function observeToolbarOverflow(toolbar, options) {
|
|
|
1573
1698
|
|
|
1574
1699
|
// src/print/printDocument.ts
|
|
1575
1700
|
var RETURN_EVENTS = ["pointerdown", "keydown"];
|
|
1701
|
+
var FONTS_TIMEOUT_MS = 3e3;
|
|
1576
1702
|
var printing = false;
|
|
1577
1703
|
function createFrame(bodyHtml) {
|
|
1578
1704
|
const frame = document.createElement("iframe");
|
|
@@ -1589,17 +1715,26 @@ function createFrame(bodyHtml) {
|
|
|
1589
1715
|
}
|
|
1590
1716
|
function load(frame) {
|
|
1591
1717
|
return new Promise((resolve, reject) => {
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1718
|
+
const removal = new MutationObserver(() => {
|
|
1719
|
+
if (!frame.isConnected) {
|
|
1720
|
+
settle();
|
|
1721
|
+
reject(new Error("The print frame was removed before it loaded."));
|
|
1722
|
+
}
|
|
1723
|
+
});
|
|
1724
|
+
function loaded() {
|
|
1725
|
+
settle();
|
|
1726
|
+
if (frame.contentWindow === null) {
|
|
1727
|
+
reject(new Error("The print frame has no window."));
|
|
1728
|
+
} else {
|
|
1729
|
+
resolve(frame.contentWindow);
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
function settle() {
|
|
1733
|
+
removal.disconnect();
|
|
1734
|
+
frame.removeEventListener("load", loaded);
|
|
1735
|
+
}
|
|
1736
|
+
frame.addEventListener("load", loaded);
|
|
1737
|
+
removal.observe(document.body, { childList: true });
|
|
1603
1738
|
document.body.append(frame);
|
|
1604
1739
|
});
|
|
1605
1740
|
}
|
|
@@ -1610,7 +1745,18 @@ function fill(view, { title, styles }) {
|
|
|
1610
1745
|
style.textContent = styles;
|
|
1611
1746
|
frameDocument.head.append(style);
|
|
1612
1747
|
}
|
|
1613
|
-
function
|
|
1748
|
+
async function fontsLoaded(view) {
|
|
1749
|
+
let timer = 0;
|
|
1750
|
+
const timeout = new Promise((resolve) => {
|
|
1751
|
+
timer = window.setTimeout(resolve, FONTS_TIMEOUT_MS);
|
|
1752
|
+
});
|
|
1753
|
+
try {
|
|
1754
|
+
await Promise.race([view.document.fonts.ready, timeout]);
|
|
1755
|
+
} finally {
|
|
1756
|
+
window.clearTimeout(timer);
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
async function print(view) {
|
|
1614
1760
|
const listeners = [
|
|
1615
1761
|
[view, "afterprint"],
|
|
1616
1762
|
...RETURN_EVENTS.flatMap((type) => [
|
|
@@ -1618,19 +1764,22 @@ function print(view) {
|
|
|
1618
1764
|
[window, type]
|
|
1619
1765
|
])
|
|
1620
1766
|
];
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
target.addEventListener(type, done, { capture: true });
|
|
1630
|
-
}
|
|
1767
|
+
let done = () => void 0;
|
|
1768
|
+
const closed = new Promise((resolve) => {
|
|
1769
|
+
done = resolve;
|
|
1770
|
+
});
|
|
1771
|
+
for (const [target, type] of listeners) {
|
|
1772
|
+
target.addEventListener(type, done, { capture: true });
|
|
1773
|
+
}
|
|
1774
|
+
try {
|
|
1631
1775
|
view.focus();
|
|
1632
1776
|
view.print();
|
|
1633
|
-
|
|
1777
|
+
await closed;
|
|
1778
|
+
} finally {
|
|
1779
|
+
for (const [target, type] of listeners) {
|
|
1780
|
+
target.removeEventListener(type, done, { capture: true });
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1634
1783
|
}
|
|
1635
1784
|
async function printDocument(options) {
|
|
1636
1785
|
if (printing) {
|
|
@@ -1642,7 +1791,7 @@ async function printDocument(options) {
|
|
|
1642
1791
|
try {
|
|
1643
1792
|
const view = await load(frame);
|
|
1644
1793
|
fill(view, options);
|
|
1645
|
-
await view
|
|
1794
|
+
await fontsLoaded(view);
|
|
1646
1795
|
await print(view);
|
|
1647
1796
|
} finally {
|
|
1648
1797
|
frame.remove();
|