@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 CHANGED
@@ -87,7 +87,8 @@ interface AttachedChecklist {
87
87
  * How many items the whole list holds, mounted or not. Starts at 0, so a
88
88
  * renderer calls this straight after attaching, and again whenever the
89
89
  * list changes — a search narrowing it, say. A focused place past the new
90
- * end moves back to the last item.
90
+ * end moves back to the last item, and so does a move still waiting for
91
+ * an item past it.
91
92
  */
92
93
  readonly setCount: (count: number) => void;
93
94
  /**
@@ -95,7 +96,11 @@ interface AttachedChecklist {
95
96
  * An item outside the mounted window is focused once it mounts.
96
97
  */
97
98
  readonly focusItem: (index: number) => void;
98
- /** Removes every listener and observer. The items keep their `tabindex`. */
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
+ */
99
104
  readonly detach: () => void;
100
105
  }
101
106
  /**
@@ -190,20 +195,31 @@ interface ColumnResizeGestureHandlers {
190
195
  /** Every pointer move, with the width the column takes there. */
191
196
  readonly onMove: (width: number) => void;
192
197
  /**
193
- * The pointer was released. `width` is the width to commit, or `null` when
194
- * it ended where it started: a click on the handle — as each half of a
195
- * double-click is — is not a resize, and reporting one would fire a
196
- * spurious resize on every click.
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.
197
203
  */
198
204
  readonly onEnd: (width: number | null) => void;
199
- /** Escape, or a cancelled pointer: the column goes back to `session.startWidth`. */
205
+ /**
206
+ * Escape, a cancelled pointer or an aborted `signal`: the column goes back
207
+ * to `session.startWidth`.
208
+ */
200
209
  readonly onCancel: () => void;
210
+ /**
211
+ * Cancels the resize when aborted, as Escape does. For a renderer whose
212
+ * handle goes away mid-drag, so what it draws for the resize ends with it.
213
+ * Already aborted, no resize starts.
214
+ */
215
+ readonly signal?: AbortSignal;
201
216
  }
202
217
  /**
203
218
  * Drags a column's edge from `press` on its resize `handle`, turning pointer
204
219
  * positions into widths through `@gridkitjs/core`'s `session` — begun with
205
220
  * `beginColumnResize` — and reporting them. Returns whether a resize began:
206
- * only the primary button of the primary pointer starts one.
221
+ * only the primary button of the primary pointer starts one, and not once
222
+ * `handlers.signal` has aborted.
207
223
  *
208
224
  * Captures the pointer on `handle`, so the drag keeps reporting wherever the
209
225
  * pointer goes, and prevents the press's default, so it does not select the
@@ -265,15 +281,22 @@ declare function writeClipboard(content: ClipboardContent): Promise<void>;
265
281
  */
266
282
  declare function downloadBlob(blob: Blob, fileName: string): void;
267
283
 
268
- /** What a renderer draws while a reorder drag is open. */
269
- interface DragReorderState<Target> {
270
- /** The item being dragged, once the press has become a drag. */
271
- readonly draggedId: string | null;
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;
272
295
  /** Where it would land if released now, `null` for nowhere valid. */
273
296
  readonly dropTarget: Target | null;
274
297
  /** Where the element trailing the pointer sits, as a CSS `transform`. */
275
- readonly ghostTransform: string | null;
276
- }
298
+ readonly ghostTransform: string;
299
+ };
277
300
  /** The state while nothing is dragged — the one a drag reports when it ends. */
278
301
  declare const NO_DRAG: DragReorderState<never>;
279
302
  interface DragReorderHandlers<Target> {
@@ -289,18 +312,25 @@ interface DragReorderHandlers<Target> {
289
312
  readonly onState: (state: DragReorderState<Target>) => void;
290
313
  /** The pointer was released over a valid target. */
291
314
  readonly onDrop: (target: Target, id: string) => void;
315
+ /**
316
+ * Cancels the drag when aborted, as Escape does: `onState(NO_DRAG)`, no
317
+ * drop. For a renderer whose dragged element goes away mid-drag, so what
318
+ * it draws for the drag ends with it. Already aborted, no drag starts.
319
+ */
320
+ readonly signal?: AbortSignal;
292
321
  }
293
322
  /**
294
323
  * The pointer mechanics behind every drag-to-reorder gesture in the grid — a
295
324
  * column header dragged among the others or into the group-by bar, a
296
325
  * group-by chip dragged within it: capture, the drag threshold, and the ghost
297
326
  * trailing the pointer, holding the spot it was picked up by. Returns whether
298
- * a gesture began; only the main button of the primary pointer starts one.
327
+ * a gesture began; only the main button of the primary pointer starts one,
328
+ * and not once `handlers.signal` has aborted.
299
329
  *
300
330
  * The press is left to its default, so the pressed element still takes focus;
301
331
  * until the pointer has travelled `DRAG_THRESHOLD` pixels nothing is
302
- * reported, so a press that never moves stays a click. Escape, or a cancelled
303
- * pointer, leaves the order as it was.
332
+ * reported, so a press that never moves stays a click. Escape, a cancelled
333
+ * pointer or an aborted signal leaves the order as it was.
304
334
  *
305
335
  * Pointer events rather than HTML5 drag-and-drop: `dragenter`/`dragleave`
306
336
  * fire per descendant, so a dragged item's own inner markup would each report
@@ -416,7 +446,7 @@ interface GridFocusController {
416
446
  * focused does nothing, which is what lets a cell's own `focus` event
417
447
  * report a click through here without a loop.
418
448
  */
419
- readonly focusCell: (rowIndex: number, columnIndex: number) => void;
449
+ readonly focusCell: (focus: GridFocus) => void;
420
450
  /**
421
451
  * Moves the tab stop as `key` does — the arrows, Home, End, the page keys,
422
452
  * with Ctrl for the grid's corners. Returns whether the key was one of
@@ -428,8 +458,13 @@ interface GridFocusController {
428
458
  /**
429
459
  * Connects the tab stop to the rendered rows, which the browser's focus
430
460
  * then follows it among. Returns the function that disconnects them.
461
+ *
462
+ * `root`, the element holding every row, lets the user take over from a
463
+ * move still waiting for its row to be drawn: focus leaving `root`, or a
464
+ * wheel or a press inside it, drops the move, so a row mounting later
465
+ * neither scrolls back to itself nor pulls focus back into the grid.
431
466
  */
432
- readonly attach: (rows: GridFocusRows) => () => void;
467
+ readonly attach: (rows: GridFocusRows, root?: HTMLElement | null) => () => void;
433
468
  /**
434
469
  * Called by the renderer once it has drawn `drawn` — a value `getFocus`
435
470
  * returned — so the browser's focus follows a move to the cell now in the
@@ -481,8 +516,10 @@ interface InfiniteScrollOptions {
481
516
  readonly hasMore: boolean;
482
517
  /**
483
518
  * Called at most once per approach: when the sentinel comes within
484
- * `rootMargin` of the root's visible area, and not again until
485
- * `isLoadingMore` has gone from `true` back to `false`.
519
+ * `rootMargin` of the root's visible area. Not again until that load has
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.
486
523
  */
487
524
  readonly onLoadMore?: (() => void) | undefined;
488
525
  /** Whether a load `onLoadMore` started is still in flight. */
@@ -494,24 +531,26 @@ interface InfiniteScroll {
494
531
  /**
495
532
  * Takes the current options. Cheap when nothing changed, so a renderer may
496
533
  * call it after every render; a new sentinel or `rootMargin` restarts the
497
- * observer, and `isLoadingMore` going back to `false` re-checks at once.
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.
498
537
  */
499
538
  readonly update: (options: InfiniteScrollOptions) => void;
500
- /** Stops watching for good. */
539
+ /** Stops watching for good: a later `update` does nothing. */
501
540
  readonly detach: () => void;
502
541
  }
503
542
  /**
504
543
  * Turns a sentinel's approach to the bottom of the scrolling `root` into
505
- * `onLoadMore` calls, no more than one per "the sentinel is near and no load
506
- * is in flight since the last one finished".
544
+ * `onLoadMore` calls, no more than one per approach while no load is in
545
+ * flight.
507
546
  *
508
- * Three facts drive it: whether the sentinel is intersecting (as of the
509
- * observer's last report), whether `onLoadMore` has fired since the last
510
- * load finished, and whether a load was in flight at the last update. They
511
- * outlive the sentinel itself, which a renderer mounts and unmounts as
512
- * `hasMore` changes, so they live here rather than on any one observer.
547
+ * Two facts drive it: whether the sentinel is intersecting (as of the
548
+ * observer's last report), and the `LoadState`. Both outlive the sentinel
549
+ * itself, which a renderer mounts and unmounts as `hasMore` changes, so they
550
+ * live here rather than on any one observer.
513
551
  *
514
- * Off means off: with `hasMore` false, or no sentinel, no observer exists.
552
+ * Off means off: with `hasMore` false, no sentinel, or once detached, no
553
+ * observer exists.
515
554
  */
516
555
  declare function attachInfiniteScroll(root: Element, options: InfiniteScrollOptions): InfiniteScroll;
517
556
 
@@ -676,9 +715,19 @@ interface OverlayOptions extends OverlayPlacementOptions {
676
715
  readonly initialFocus?: OverlayInitialFocus | undefined;
677
716
  /**
678
717
  * Where focus goes when the overlay detaches. Defaults to the element that
679
- * had focus when it attached; `null` leaves focus alone.
718
+ * had focus when it attached; `null` leaves focus alone, unless
719
+ * `returnFocusFallback` names somewhere.
680
720
  */
681
721
  readonly returnFocusTo?: HTMLElement | null | undefined;
722
+ /**
723
+ * Where focus goes when there is nothing to return it to as the overlay
724
+ * detaches: `returnFocusTo` is `null`, or has left the page — the button a
725
+ * menu opened from, taken away by what the menu ran. Called then, so it
726
+ * can name what is on the page by that time; returning `null` leaves focus
727
+ * alone. Like the return itself, it applies only while focus is still in
728
+ * the panel, in an overlay above it, or nowhere.
729
+ */
730
+ readonly returnFocusFallback?: (() => HTMLElement | null) | undefined;
682
731
  /**
683
732
  * Whether a scroll outside the panel just after input inside it — an
684
733
  * `input` or `change` event, in the two animation frames that follow it —
@@ -728,6 +777,8 @@ interface OverlayOptions extends OverlayPlacementOptions {
728
777
  * Detaching removes every listener and returns focus, but only when focus is
729
778
  * still in the panel, in an overlay above it, or nowhere — a click that
730
779
  * dismissed it by landing on another control leaves focus on that control.
780
+ * Focus goes to `returnFocusFallback` instead when the element it would
781
+ * return to has left the page.
731
782
  * Any overlay still above it is dismissed with `"parent"` and detached first.
732
783
  */
733
784
  declare function attachOverlay(anchor: OverlayAnchor, panel: HTMLElement, options: OverlayOptions): () => void;
@@ -747,7 +798,11 @@ interface RowVirtualizerOptions {
747
798
  interface RowVirtualizer {
748
799
  /** How many rows there are. Measured heights of the rows that remain are kept. */
749
800
  readonly setRowCount: (count: number) => void;
750
- /** Forgets every measured height, for rows that are no longer the ones measured. */
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
+ */
751
806
  readonly resetHeights: () => void;
752
807
  /**
753
808
  * A ref callback for the element of row `index` (its place among all the
@@ -759,10 +814,15 @@ interface RowVirtualizer {
759
814
  /**
760
815
  * Scrolls so row `index` is in view. A mounted row is scrolled to directly;
761
816
  * one outside the window is jumped to at its estimated offset, then
762
- * scrolled to properly once it mounts and can be measured.
817
+ * scrolled to properly once it mounts and can be measured. A later call
818
+ * replaces one still waiting for its row; a row count that no longer holds
819
+ * that row, or `resetHeights`, drops it.
763
820
  */
764
821
  readonly scrollToIndex: (index: number, options?: ScrollIntoViewOptions) => void;
765
- /** Stops listening and measuring, for good. */
822
+ /**
823
+ * Stops listening, measuring and scrolling, for good: every method does
824
+ * nothing after it.
825
+ */
766
826
  readonly destroy: () => void;
767
827
  }
768
828
  /**
@@ -871,13 +931,14 @@ interface PrintDocumentOptions {
871
931
  * Prints a document through a hidden frame: its own page, holding only
872
932
  * `bodyHtml` under `styles`, so what is printed is what was built — every
873
933
  * row, not the slice of them a virtualised grid has drawn — and nothing of
874
- * the page around it. The frame loads, waits for its fonts, opens the
875
- * print dialog, and is removed once the dialog closes, when the promise
934
+ * the page around it. The frame loads, waits for its fonts (a few seconds
935
+ * at most), opens the print dialog, and is removed once the dialog closes, when the promise
876
936
  * resolves; focus goes back where it was. A frame rather than a new window,
877
937
  * which a popup blocker would stop.
878
938
  *
879
939
  * One print at a time: a call while a print is open resolves at once
880
- * without printing.
940
+ * without printing. Rejects, with the frame removed, if the frame is taken
941
+ * out of the page before it loads or the dialog fails to open.
881
942
  */
882
943
  declare function printDocument(options: PrintDocumentOptions): Promise<void>;
883
944