@gridkitjs/dom 0.4.0 → 0.6.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 +47 -19
- package/dist/index.js +103 -44
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -96,7 +96,11 @@ interface AttachedChecklist {
|
|
|
96
96
|
* An item outside the mounted window is focused once it mounts.
|
|
97
97
|
*/
|
|
98
98
|
readonly focusItem: (index: number) => void;
|
|
99
|
-
/**
|
|
99
|
+
/**
|
|
100
|
+
* Removes every listener and observer. The items keep their `tabindex`.
|
|
101
|
+
* After it, `setCount` and `focusItem` do nothing: they neither scroll
|
|
102
|
+
* nor focus, and a move still waiting for its item is dropped.
|
|
103
|
+
*/
|
|
100
104
|
readonly detach: () => void;
|
|
101
105
|
}
|
|
102
106
|
/**
|
|
@@ -191,10 +195,11 @@ interface ColumnResizeGestureHandlers {
|
|
|
191
195
|
/** Every pointer move, with the width the column takes there. */
|
|
192
196
|
readonly onMove: (width: number) => void;
|
|
193
197
|
/**
|
|
194
|
-
* The pointer was released. `width` is the width to commit,
|
|
195
|
-
* it
|
|
196
|
-
*
|
|
197
|
-
* spurious resize on every
|
|
198
|
+
* The pointer was released. `width` is the width to commit, even when a
|
|
199
|
+
* drag brought it back to where it started, or `null` when the width never
|
|
200
|
+
* changed: a click on the handle — as each half of a double-click is — is
|
|
201
|
+
* not a resize, and reporting one would fire a spurious resize on every
|
|
202
|
+
* click.
|
|
198
203
|
*/
|
|
199
204
|
readonly onEnd: (width: number | null) => void;
|
|
200
205
|
/**
|
|
@@ -276,15 +281,22 @@ declare function writeClipboard(content: ClipboardContent): Promise<void>;
|
|
|
276
281
|
*/
|
|
277
282
|
declare function downloadBlob(blob: Blob, fileName: string): void;
|
|
278
283
|
|
|
279
|
-
/**
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
284
|
+
/**
|
|
285
|
+
* What a renderer draws for a reorder gesture: nothing while `idle`, which
|
|
286
|
+
* covers a press still short of the drag threshold, then while `dragging` the
|
|
287
|
+
* dragged item, where it would land and the ghost trailing the pointer.
|
|
288
|
+
*/
|
|
289
|
+
type DragReorderState<Target> = {
|
|
290
|
+
readonly kind: "idle";
|
|
291
|
+
} | {
|
|
292
|
+
readonly kind: "dragging";
|
|
293
|
+
/** The item being dragged. */
|
|
294
|
+
readonly draggedId: string;
|
|
283
295
|
/** Where it would land if released now, `null` for nowhere valid. */
|
|
284
296
|
readonly dropTarget: Target | null;
|
|
285
297
|
/** Where the element trailing the pointer sits, as a CSS `transform`. */
|
|
286
|
-
readonly ghostTransform: string
|
|
287
|
-
}
|
|
298
|
+
readonly ghostTransform: string;
|
|
299
|
+
};
|
|
288
300
|
/** The state while nothing is dragged — the one a drag reports when it ends. */
|
|
289
301
|
declare const NO_DRAG: DragReorderState<never>;
|
|
290
302
|
interface DragReorderHandlers<Target> {
|
|
@@ -434,7 +446,7 @@ interface GridFocusController {
|
|
|
434
446
|
* focused does nothing, which is what lets a cell's own `focus` event
|
|
435
447
|
* report a click through here without a loop.
|
|
436
448
|
*/
|
|
437
|
-
readonly focusCell: (
|
|
449
|
+
readonly focusCell: (focus: GridFocus) => void;
|
|
438
450
|
/**
|
|
439
451
|
* Moves the tab stop as `key` does — the arrows, Home, End, the page keys,
|
|
440
452
|
* with Ctrl for the grid's corners. Returns whether the key was one of
|
|
@@ -505,8 +517,9 @@ interface InfiniteScrollOptions {
|
|
|
505
517
|
/**
|
|
506
518
|
* Called at most once per approach: when the sentinel comes within
|
|
507
519
|
* `rootMargin` of the root's visible area. Not again until that load has
|
|
508
|
-
* finished (`isLoadingMore` back to `false`), `hasMore` has changed,
|
|
509
|
-
* the sentinel
|
|
520
|
+
* finished (`isLoadingMore` back to `false`), `hasMore` has changed, rows
|
|
521
|
+
* have been added or removed in front of the sentinel, or the sentinel has
|
|
522
|
+
* left `rootMargin` and come back.
|
|
510
523
|
*/
|
|
511
524
|
readonly onLoadMore?: (() => void) | undefined;
|
|
512
525
|
/** Whether a load `onLoadMore` started is still in flight. */
|
|
@@ -519,6 +532,8 @@ interface InfiniteScroll {
|
|
|
519
532
|
* Takes the current options. Cheap when nothing changed, so a renderer may
|
|
520
533
|
* call it after every render; a new sentinel or `rootMargin` restarts the
|
|
521
534
|
* observer, and a load finishing or `hasMore` changing re-checks at once.
|
|
535
|
+
* While a load it asked for has not reported `isLoadingMore`, it measures
|
|
536
|
+
* where the sentinel sits, to tell whether rows answered it.
|
|
522
537
|
*/
|
|
523
538
|
readonly update: (options: InfiniteScrollOptions) => void;
|
|
524
539
|
/** Stops watching for good: a later `update` does nothing. */
|
|
@@ -783,7 +798,11 @@ interface RowVirtualizerOptions {
|
|
|
783
798
|
interface RowVirtualizer {
|
|
784
799
|
/** How many rows there are. Measured heights of the rows that remain are kept. */
|
|
785
800
|
readonly setRowCount: (count: number) => void;
|
|
786
|
-
/**
|
|
801
|
+
/**
|
|
802
|
+
* Forgets every measured height, for rows that are no longer the ones
|
|
803
|
+
* measured. A `scrollToIndex` still waiting for its row is dropped too:
|
|
804
|
+
* the row it asked for is no longer at that index.
|
|
805
|
+
*/
|
|
787
806
|
readonly resetHeights: () => void;
|
|
788
807
|
/**
|
|
789
808
|
* A ref callback for the element of row `index` (its place among all the
|
|
@@ -792,12 +811,21 @@ interface RowVirtualizer {
|
|
|
792
811
|
* a renderer re-attaching it on every render costs nothing.
|
|
793
812
|
*/
|
|
794
813
|
readonly measureRow: (index: number) => (element: HTMLElement | null) => void;
|
|
814
|
+
/**
|
|
815
|
+
* Reads the heights of rows already laid out, each paired with its index
|
|
816
|
+
* among all the rows, and works out the window once for all of them: for
|
|
817
|
+
* rows drawn before this virtualizer existed, so its first window is the
|
|
818
|
+
* one on screen rather than one placed by `estimatedRowHeight`. Indices
|
|
819
|
+
* past the row count are skipped. It does not observe the rows;
|
|
820
|
+
* `measureRow` does that once the renderer hands them over.
|
|
821
|
+
*/
|
|
822
|
+
readonly measureRows: (rows: Iterable<readonly [index: number, element: Element]>) => void;
|
|
795
823
|
/**
|
|
796
824
|
* Scrolls so row `index` is in view. A mounted row is scrolled to directly;
|
|
797
825
|
* one outside the window is jumped to at its estimated offset, then
|
|
798
826
|
* scrolled to properly once it mounts and can be measured. A later call
|
|
799
|
-
* replaces one still waiting for its row
|
|
800
|
-
*
|
|
827
|
+
* replaces one still waiting for its row; a row count that no longer holds
|
|
828
|
+
* that row, or `resetHeights`, drops it.
|
|
801
829
|
*/
|
|
802
830
|
readonly scrollToIndex: (index: number, options?: ScrollIntoViewOptions) => void;
|
|
803
831
|
/**
|
|
@@ -912,8 +940,8 @@ interface PrintDocumentOptions {
|
|
|
912
940
|
* Prints a document through a hidden frame: its own page, holding only
|
|
913
941
|
* `bodyHtml` under `styles`, so what is printed is what was built — every
|
|
914
942
|
* row, not the slice of them a virtualised grid has drawn — and nothing of
|
|
915
|
-
* the page around it. The frame loads, waits for its fonts
|
|
916
|
-
* print dialog, and is removed once the dialog closes, when the promise
|
|
943
|
+
* the page around it. The frame loads, waits for its fonts (a few seconds
|
|
944
|
+
* at most), opens the print dialog, and is removed once the dialog closes, when the promise
|
|
917
945
|
* resolves; focus goes back where it was. A frame rather than a new window,
|
|
918
946
|
* which a popup blocker would stop.
|
|
919
947
|
*
|
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,12 +177,12 @@ function attachChecklist(list, options) {
|
|
|
175
177
|
item.focus({ preventScroll: true });
|
|
176
178
|
}
|
|
177
179
|
}
|
|
178
|
-
function
|
|
179
|
-
const item =
|
|
180
|
+
function focusAwaitedItemIfMounted() {
|
|
181
|
+
const item = state.kind === "awaiting-item" ? itemAt(state.index) : null;
|
|
180
182
|
if (item === null) {
|
|
181
183
|
return;
|
|
182
184
|
}
|
|
183
|
-
|
|
185
|
+
state = SETTLED;
|
|
184
186
|
const focused = document.activeElement;
|
|
185
187
|
if (focused === null || focused === document.body || list.contains(focused)) {
|
|
186
188
|
item.focus({ preventScroll: true });
|
|
@@ -188,7 +190,7 @@ function attachChecklist(list, options) {
|
|
|
188
190
|
}
|
|
189
191
|
const observer = new MutationObserver(() => {
|
|
190
192
|
setTabStop();
|
|
191
|
-
|
|
193
|
+
focusAwaitedItemIfMounted();
|
|
192
194
|
});
|
|
193
195
|
observer.observe(list, {
|
|
194
196
|
childList: true,
|
|
@@ -201,17 +203,23 @@ function attachChecklist(list, options) {
|
|
|
201
203
|
list.addEventListener("click", onClick);
|
|
202
204
|
return {
|
|
203
205
|
setCount(next) {
|
|
206
|
+
if (state.kind === "detached") {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
204
209
|
count = next;
|
|
205
210
|
active = Math.max(0, Math.min(active, count - 1));
|
|
206
|
-
if (
|
|
207
|
-
|
|
211
|
+
if (state.kind === "awaiting-item") {
|
|
212
|
+
state = count === 0 ? SETTLED : {
|
|
213
|
+
kind: "awaiting-item",
|
|
214
|
+
index: Math.min(state.index, count - 1)
|
|
215
|
+
};
|
|
208
216
|
}
|
|
209
217
|
setTabStop();
|
|
210
|
-
|
|
218
|
+
focusAwaitedItemIfMounted();
|
|
211
219
|
},
|
|
212
220
|
focusItem: moveTo,
|
|
213
221
|
detach() {
|
|
214
|
-
|
|
222
|
+
state = DETACHED;
|
|
215
223
|
observer.disconnect();
|
|
216
224
|
list.removeEventListener("keydown", onKeyDown2);
|
|
217
225
|
list.removeEventListener("focusin", onFocusIn);
|
|
@@ -333,11 +341,13 @@ function mayStartGesture(press, signal) {
|
|
|
333
341
|
return press.button === 0 && press.isPrimary && signal?.aborted !== true;
|
|
334
342
|
}
|
|
335
343
|
function startPointerGesture(element, pointerId, handlers, signal) {
|
|
344
|
+
const { ownerDocument } = element;
|
|
336
345
|
element.setPointerCapture(pointerId);
|
|
337
346
|
function stop() {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
347
|
+
ownerDocument.removeEventListener("pointermove", move, true);
|
|
348
|
+
ownerDocument.removeEventListener("pointerup", end, true);
|
|
349
|
+
ownerDocument.removeEventListener("pointercancel", cancel, true);
|
|
350
|
+
element.removeEventListener("lostpointercapture", recapture);
|
|
341
351
|
window.removeEventListener("keydown", onKeyDown2);
|
|
342
352
|
signal?.removeEventListener("abort", abandon);
|
|
343
353
|
if (element.hasPointerCapture(pointerId)) {
|
|
@@ -360,6 +370,11 @@ function startPointerGesture(element, pointerId, handlers, signal) {
|
|
|
360
370
|
abandon();
|
|
361
371
|
}
|
|
362
372
|
}
|
|
373
|
+
function recapture(event) {
|
|
374
|
+
if (event.pointerId === pointerId && element.isConnected) {
|
|
375
|
+
element.setPointerCapture(pointerId);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
363
378
|
function abandon() {
|
|
364
379
|
stop();
|
|
365
380
|
handlers.onCancel();
|
|
@@ -369,9 +384,10 @@ function startPointerGesture(element, pointerId, handlers, signal) {
|
|
|
369
384
|
abandon();
|
|
370
385
|
}
|
|
371
386
|
}
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
387
|
+
ownerDocument.addEventListener("pointermove", move, true);
|
|
388
|
+
ownerDocument.addEventListener("pointerup", end, true);
|
|
389
|
+
ownerDocument.addEventListener("pointercancel", cancel, true);
|
|
390
|
+
element.addEventListener("lostpointercapture", recapture);
|
|
375
391
|
window.addEventListener("keydown", onKeyDown2);
|
|
376
392
|
signal?.addEventListener("abort", abandon);
|
|
377
393
|
}
|
|
@@ -383,16 +399,18 @@ function startColumnResizeGesture(handle, press, session, handlers) {
|
|
|
383
399
|
}
|
|
384
400
|
press.preventDefault();
|
|
385
401
|
let width = session.startWidth;
|
|
402
|
+
let resized = false;
|
|
386
403
|
startPointerGesture(
|
|
387
404
|
handle,
|
|
388
405
|
press.pointerId,
|
|
389
406
|
{
|
|
390
407
|
onMove(event) {
|
|
391
408
|
width = applyColumnResize(session, event.clientX);
|
|
409
|
+
resized ||= width !== session.startWidth;
|
|
392
410
|
handlers.onMove(width);
|
|
393
411
|
},
|
|
394
412
|
onEnd() {
|
|
395
|
-
handlers.onEnd(
|
|
413
|
+
handlers.onEnd(resized ? width : null);
|
|
396
414
|
},
|
|
397
415
|
onCancel() {
|
|
398
416
|
handlers.onCancel();
|
|
@@ -520,11 +538,7 @@ function downloadBlob(blob, fileName) {
|
|
|
520
538
|
|
|
521
539
|
// src/dragReorder.ts
|
|
522
540
|
var DRAG_THRESHOLD = 4;
|
|
523
|
-
var NO_DRAG = {
|
|
524
|
-
draggedId: null,
|
|
525
|
-
dropTarget: null,
|
|
526
|
-
ghostTransform: null
|
|
527
|
-
};
|
|
541
|
+
var NO_DRAG = { kind: "idle" };
|
|
528
542
|
function startDragReorder(id, grabElement, press, handlers) {
|
|
529
543
|
if (!mayStartGesture(press, handlers.signal)) {
|
|
530
544
|
return false;
|
|
@@ -546,6 +560,7 @@ function startDragReorder(id, grabElement, press, handlers) {
|
|
|
546
560
|
target: handlers.resolveTarget(clientX, clientY, id)
|
|
547
561
|
};
|
|
548
562
|
handlers.onState({
|
|
563
|
+
kind: "dragging",
|
|
549
564
|
draggedId: id,
|
|
550
565
|
dropTarget: phase.target,
|
|
551
566
|
ghostTransform: `translate(${String(clientX - grabX)}px, ${String(clientY)}px)`
|
|
@@ -619,7 +634,7 @@ function observeElementWidth(element, onWidth) {
|
|
|
619
634
|
// src/gridFocus.ts
|
|
620
635
|
import {
|
|
621
636
|
clampFocus,
|
|
622
|
-
|
|
637
|
+
headerFocus,
|
|
623
638
|
nextFocusForKey
|
|
624
639
|
} from "@gridkitjs/core";
|
|
625
640
|
var FALLBACK_PAGE = 10;
|
|
@@ -629,6 +644,12 @@ function cellIn(row, columnIndex) {
|
|
|
629
644
|
}
|
|
630
645
|
return row.cells[Math.min(columnIndex, row.cells.length - 1)] ?? null;
|
|
631
646
|
}
|
|
647
|
+
function sameCell(a, b) {
|
|
648
|
+
if (a.area === "body" && b.area === "body") {
|
|
649
|
+
return a.rowIndex === b.rowIndex && a.columnIndex === b.columnIndex;
|
|
650
|
+
}
|
|
651
|
+
return a.area === b.area && a.columnIndex === b.columnIndex;
|
|
652
|
+
}
|
|
632
653
|
function findBodyRow(bodyTable, rowIndex) {
|
|
633
654
|
return bodyTable?.tBodies[0]?.querySelector(
|
|
634
655
|
`:scope > tr[data-gridkit-row-index="${String(rowIndex)}"]`
|
|
@@ -646,7 +667,7 @@ function createGridFocus(initialOptions) {
|
|
|
646
667
|
let options = initialOptions;
|
|
647
668
|
let rows = null;
|
|
648
669
|
const listeners = /* @__PURE__ */ new Set();
|
|
649
|
-
let stored =
|
|
670
|
+
let stored = headerFocus(0);
|
|
650
671
|
let snapshot = {
|
|
651
672
|
stored,
|
|
652
673
|
rowCount: options.rowCount,
|
|
@@ -684,14 +705,9 @@ function createGridFocus(initialOptions) {
|
|
|
684
705
|
root.removeEventListener("pointerdown", dropPendingMove);
|
|
685
706
|
};
|
|
686
707
|
}
|
|
687
|
-
function focusCell(
|
|
688
|
-
const next = clampFocus(
|
|
689
|
-
|
|
690
|
-
options.rowCount,
|
|
691
|
-
options.columnCount
|
|
692
|
-
);
|
|
693
|
-
const current = getFocus();
|
|
694
|
-
if (next.rowIndex === current.rowIndex && next.columnIndex === current.columnIndex) {
|
|
708
|
+
function focusCell(focus) {
|
|
709
|
+
const next = clampFocus(focus, options.rowCount, options.columnCount);
|
|
710
|
+
if (sameCell(next, getFocus())) {
|
|
695
711
|
return;
|
|
696
712
|
}
|
|
697
713
|
pendingMove = next;
|
|
@@ -725,7 +741,7 @@ function createGridFocus(initialOptions) {
|
|
|
725
741
|
if (next === null) {
|
|
726
742
|
return false;
|
|
727
743
|
}
|
|
728
|
-
focusCell(next
|
|
744
|
+
focusCell(next);
|
|
729
745
|
return true;
|
|
730
746
|
},
|
|
731
747
|
attach(next, root) {
|
|
@@ -743,7 +759,7 @@ function createGridFocus(initialOptions) {
|
|
|
743
759
|
return;
|
|
744
760
|
}
|
|
745
761
|
const cell = cellIn(
|
|
746
|
-
drawn.
|
|
762
|
+
drawn.area === "header" ? rows.getHeaderRow() : rows.getBodyRow(drawn.rowIndex),
|
|
747
763
|
drawn.columnIndex
|
|
748
764
|
);
|
|
749
765
|
if (cell !== null) {
|
|
@@ -752,7 +768,7 @@ function createGridFocus(initialOptions) {
|
|
|
752
768
|
return;
|
|
753
769
|
}
|
|
754
770
|
const range = options.virtualRange;
|
|
755
|
-
if (range != null && drawn.
|
|
771
|
+
if (range != null && drawn.area === "body" && (drawn.rowIndex < range.startIndex || drawn.rowIndex > range.endIndex)) {
|
|
756
772
|
range.scrollToIndex(drawn.rowIndex);
|
|
757
773
|
return;
|
|
758
774
|
}
|
|
@@ -763,15 +779,17 @@ function createGridFocus(initialOptions) {
|
|
|
763
779
|
|
|
764
780
|
// src/infiniteScroll.ts
|
|
765
781
|
var IDLE = { kind: "idle" };
|
|
766
|
-
var REQUESTED = { kind: "requested" };
|
|
767
782
|
var LOADING = { kind: "loading" };
|
|
768
|
-
var
|
|
783
|
+
var DETACHED2 = { kind: "detached" };
|
|
769
784
|
function afterUpdate(state, loading, hasMoreChanged) {
|
|
770
785
|
if (loading) {
|
|
771
786
|
return LOADING;
|
|
772
787
|
}
|
|
773
788
|
return state.kind === "loading" || hasMoreChanged ? IDLE : state;
|
|
774
789
|
}
|
|
790
|
+
function contentOffset(root, sentinel) {
|
|
791
|
+
return sentinel.getBoundingClientRect().top - root.getBoundingClientRect().top + root.scrollTop;
|
|
792
|
+
}
|
|
775
793
|
function attachInfiniteScroll(root, options) {
|
|
776
794
|
let latest = options;
|
|
777
795
|
let intersecting = false;
|
|
@@ -779,12 +797,22 @@ function attachInfiniteScroll(root, options) {
|
|
|
779
797
|
let observer = null;
|
|
780
798
|
let observed = null;
|
|
781
799
|
function maybeLoadMore() {
|
|
782
|
-
if (state.kind !== "idle" || !intersecting || !latest.hasMore) {
|
|
800
|
+
if (state.kind !== "idle" || !intersecting || observed === null || !latest.hasMore) {
|
|
783
801
|
return;
|
|
784
802
|
}
|
|
785
|
-
state =
|
|
803
|
+
state = {
|
|
804
|
+
kind: "requested",
|
|
805
|
+
sentinelOffset: contentOffset(root, observed.sentinel)
|
|
806
|
+
};
|
|
786
807
|
latest.onLoadMore?.();
|
|
787
808
|
}
|
|
809
|
+
function requestAnswered() {
|
|
810
|
+
if (state.kind !== "requested" || observed === null) {
|
|
811
|
+
return false;
|
|
812
|
+
}
|
|
813
|
+
const moved = contentOffset(root, observed.sentinel) - state.sentinelOffset;
|
|
814
|
+
return Math.abs(moved) >= 1;
|
|
815
|
+
}
|
|
788
816
|
function report(isIntersecting) {
|
|
789
817
|
intersecting = isIntersecting;
|
|
790
818
|
if (!intersecting && state.kind === "requested") {
|
|
@@ -830,11 +858,16 @@ function attachInfiniteScroll(root, options) {
|
|
|
830
858
|
latest = next;
|
|
831
859
|
state = afterUpdate(state, next.isLoadingMore ?? false, hasMoreChanged);
|
|
832
860
|
observe();
|
|
861
|
+
if (requestAnswered()) {
|
|
862
|
+
state = IDLE;
|
|
863
|
+
disconnect();
|
|
864
|
+
observe();
|
|
865
|
+
}
|
|
833
866
|
maybeLoadMore();
|
|
834
867
|
},
|
|
835
868
|
detach() {
|
|
836
869
|
disconnect();
|
|
837
|
-
state =
|
|
870
|
+
state = DETACHED2;
|
|
838
871
|
}
|
|
839
872
|
};
|
|
840
873
|
}
|
|
@@ -1414,6 +1447,9 @@ function createRowVirtualizer(scrollElement, options) {
|
|
|
1414
1447
|
recompute();
|
|
1415
1448
|
},
|
|
1416
1449
|
resetHeights() {
|
|
1450
|
+
if (phase.kind === "awaiting-row") {
|
|
1451
|
+
phase = READY;
|
|
1452
|
+
}
|
|
1417
1453
|
heights = new Array(heights.length).fill(void 0);
|
|
1418
1454
|
recompute();
|
|
1419
1455
|
},
|
|
@@ -1442,6 +1478,17 @@ function createRowVirtualizer(scrollElement, options) {
|
|
|
1442
1478
|
}
|
|
1443
1479
|
return callback;
|
|
1444
1480
|
},
|
|
1481
|
+
measureRows(rows) {
|
|
1482
|
+
if (phase.kind === "destroyed") {
|
|
1483
|
+
return;
|
|
1484
|
+
}
|
|
1485
|
+
for (const [index, element] of rows) {
|
|
1486
|
+
if (index >= 0 && index < heights.length) {
|
|
1487
|
+
heights[index] = element.getBoundingClientRect().height;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
recompute();
|
|
1491
|
+
},
|
|
1445
1492
|
scrollToIndex(index, scrollOptions) {
|
|
1446
1493
|
if (phase.kind === "destroyed" || heights.length === 0) {
|
|
1447
1494
|
return;
|
|
@@ -1670,6 +1717,7 @@ function observeToolbarOverflow(toolbar, options) {
|
|
|
1670
1717
|
|
|
1671
1718
|
// src/print/printDocument.ts
|
|
1672
1719
|
var RETURN_EVENTS = ["pointerdown", "keydown"];
|
|
1720
|
+
var FONTS_TIMEOUT_MS = 3e3;
|
|
1673
1721
|
var printing = false;
|
|
1674
1722
|
function createFrame(bodyHtml) {
|
|
1675
1723
|
const frame = document.createElement("iframe");
|
|
@@ -1716,6 +1764,17 @@ function fill(view, { title, styles }) {
|
|
|
1716
1764
|
style.textContent = styles;
|
|
1717
1765
|
frameDocument.head.append(style);
|
|
1718
1766
|
}
|
|
1767
|
+
async function fontsLoaded(view) {
|
|
1768
|
+
let timer = 0;
|
|
1769
|
+
const timeout = new Promise((resolve) => {
|
|
1770
|
+
timer = window.setTimeout(resolve, FONTS_TIMEOUT_MS);
|
|
1771
|
+
});
|
|
1772
|
+
try {
|
|
1773
|
+
await Promise.race([view.document.fonts.ready, timeout]);
|
|
1774
|
+
} finally {
|
|
1775
|
+
window.clearTimeout(timer);
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1719
1778
|
async function print(view) {
|
|
1720
1779
|
const listeners = [
|
|
1721
1780
|
[view, "afterprint"],
|
|
@@ -1751,7 +1810,7 @@ async function printDocument(options) {
|
|
|
1751
1810
|
try {
|
|
1752
1811
|
const view = await load(frame);
|
|
1753
1812
|
fill(view, options);
|
|
1754
|
-
await view
|
|
1813
|
+
await fontsLoaded(view);
|
|
1755
1814
|
await print(view);
|
|
1756
1815
|
} finally {
|
|
1757
1816
|
frame.remove();
|