@weasel-js/ui-input 0.0.0-stage → 1.19.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.
@@ -0,0 +1,619 @@
1
+ export { COARSE_STEPS } from '@weasel-js/quantity';
2
+
3
+ /** How a list that folds is read: which items are branches, which are open, and which item is whose child. */
4
+ interface TreeShape<T> {
5
+ /** Whether `item` can open, its children shown or not. */
6
+ isBranch(item: T): boolean;
7
+ isOpen(item: T): boolean;
8
+ /** Whether `child` is one of `parent`'s own children. */
9
+ isChildOf(child: T, parent: T): boolean;
10
+ /** Whether a branch can open or close now. A disabled one can't. Default: every branch. */
11
+ canToggle?(item: T): boolean;
12
+ /** The inline direction the rows read in. Under `'rtl'` Left opens and Right closes. Default `'ltr'`. */
13
+ dir?: 'ltr' | 'rtl';
14
+ }
15
+ /** What Right or Left does on one item of a tree: open or close it, move the highlight, or nothing (`handled` false).
16
+ * `at` null is a key the tree takes without moving. */
17
+ type TreeKeyResult = {
18
+ handled: false;
19
+ } | {
20
+ handled: true;
21
+ toggle: number;
22
+ } | {
23
+ handled: true;
24
+ at: number | null;
25
+ };
26
+ /**
27
+ * Right and Left on the item at `at`, the WAI-ARIA tree way: Right opens a closed branch, else steps to its first
28
+ * child; Left closes an open branch, else steps to the parent. Mirrored under `dir: 'rtl'`. `items` are the rows
29
+ * shown, in drawn order.
30
+ */
31
+ declare function treeKey<T>(items: readonly T[], at: number, key: string, shape: TreeShape<T>): TreeKeyResult;
32
+
33
+ /** How a list's items are read: which ones the highlight can land on, and which way its arrows run. */
34
+ interface ListShape<T> {
35
+ /** Whether the highlight can land on `item`. A separator or a heading can't. Default: every item. */
36
+ canStop?(item: T): boolean;
37
+ /** Which arrow keys move the highlight. `'both'` answers to all four, the way a radio group does. Default `'vertical'`. */
38
+ orientation?: 'vertical' | 'horizontal' | 'both';
39
+ /** The inline direction the items are laid out in. Under `'rtl'` Left steps forward and Right back. Default `'ltr'`. */
40
+ dir?: 'ltr' | 'rtl';
41
+ /** An arrow past either end comes round to the other. Default true. */
42
+ wrap?: boolean;
43
+ }
44
+ /** Index of the first item the highlight can land on, or null for a list with none. */
45
+ declare function firstStop<T>(items: readonly T[], shape?: ListShape<T>): number | null;
46
+ /** The next item the highlight can land on from `at` in direction `dir`; from `null`, or an index that names no
47
+ * item, the first or last. Without wrap, an end stays where it is. Null for a list with no such item. */
48
+ declare function stepStop<T>(items: readonly T[], at: number | null, dir: 1 | -1, shape?: ListShape<T>): number | null;
49
+ /** What one key does to a list's highlight. `handled` false for a key that is not the list's to move. */
50
+ type RovingResult = {
51
+ handled: false;
52
+ } | {
53
+ handled: true;
54
+ at: number | null;
55
+ };
56
+ /** Which way an arrow key steps a list of `shape`: 1, -1, or 0 for a key that is not one of its arrows. */
57
+ declare function arrowDir(key: string, shape: ListShape<unknown>): 1 | -1 | 0;
58
+ /** Move the highlight `at` by one key: the arrows along the list's orientation, Home and End. */
59
+ declare function rovingKey<T>(items: readonly T[], at: number | null, key: string, shape?: ListShape<T>): RovingResult;
60
+ /** A key as {@link rowKey} reads it: the key and the modifiers held. */
61
+ interface KeyPress {
62
+ key: string;
63
+ shiftKey?: boolean;
64
+ ctrlKey?: boolean;
65
+ metaKey?: boolean;
66
+ altKey?: boolean;
67
+ }
68
+ /** A list of rows, and which of the keys past the arrows its caller answers. */
69
+ interface RowKeysShape<T> extends ListShape<T> {
70
+ /** Set for a list that folds: Right and Left open, close, and walk it ({@link treeKey}). */
71
+ tree?: TreeShape<T>;
72
+ /** Cmd/Ctrl+A selects every row. */
73
+ selectAll?: boolean;
74
+ /** Enter and Space activate a row. */
75
+ activate?: boolean;
76
+ /** Typing a character searches the rows' text. */
77
+ typeahead?: boolean;
78
+ }
79
+ /** What one key on a row asks for, for the caller to carry out. */
80
+ type RowKeyAction =
81
+ /** Select every row. */
82
+ {
83
+ kind: 'selectAll';
84
+ }
85
+ /** Move to row `at`, extending a range from the anchor when `extend`. `at` null takes the key without moving. */
86
+ | {
87
+ kind: 'move';
88
+ at: number | null;
89
+ extend: boolean;
90
+ }
91
+ /** Open or close the branch at `at`. */
92
+ | {
93
+ kind: 'toggle';
94
+ at: number;
95
+ } | {
96
+ kind: 'activate';
97
+ }
98
+ /** Hand the key to typeahead. `held` when the key is the list's whether or not the search finds a row. */
99
+ | {
100
+ kind: 'type';
101
+ held: boolean;
102
+ };
103
+ /**
104
+ * What a key on row `at` of a list of rows does, in the order the keys are tried: Mod+A, the arrows with Home
105
+ * and End (Shift to extend), a tree's Right and Left, a space typed mid-search, Enter or Space to activate, then any
106
+ * other character to search. `searching` says a typeahead search is under way. `apple` says `mod` is Command, as
107
+ * `isApplePlatform` from `@weasel-js/gestures` reads it; otherwise it is Ctrl. Null for a key that is not the list's.
108
+ */
109
+ declare function rowKey<T>(items: readonly T[], at: number, press: KeyPress, shape?: RowKeysShape<T>, searching?: boolean, apple?: boolean): RowKeyAction | null;
110
+
111
+ /** How typeahead reads a list: its shape, and the text each item is found by. */
112
+ interface TypeaheadShape<T> extends Pick<ListShape<T>, 'canStop'> {
113
+ label(item: T): string;
114
+ }
115
+ /** How long typing can pause before the typeahead buffer starts over, in milliseconds. */
116
+ declare const TYPEAHEAD_RESET_MS = 500;
117
+ /** Whether `text` is one typed character, counted by code point: an emoji is one, though it takes two UTF-16 units. */
118
+ declare function isOneChar(text: string): boolean;
119
+ /** What has been typed so far, and when the last key came. */
120
+ interface TypeaheadBuffer {
121
+ text: string;
122
+ at: number;
123
+ }
124
+ /** A buffer nothing has been typed into. */
125
+ declare const EMPTY_TYPEAHEAD: TypeaheadBuffer;
126
+ /** The item a typed `query` lands on, searching forward from `at` with
127
+ * wrap. A one-letter query starts after the highlight so repeating a letter
128
+ * cycles; a longer one starts at it so typing on keeps the match. An index
129
+ * that names no item searches from the start. */
130
+ declare function typeaheadMatch<T>(items: readonly T[], at: number | null, query: string, shape: TypeaheadShape<T>): number | null;
131
+ /** One typed character: the new buffer and the item it lands on. A key that
132
+ * repeats the whole buffer searches that one letter, so it cycles. */
133
+ declare function typeaheadStep<T>(items: readonly T[], from: number | null, buffer: TypeaheadBuffer, key: string, now: number, shape: TypeaheadShape<T>, resetMs?: number): {
134
+ buffer: TypeaheadBuffer;
135
+ hit: number | null;
136
+ };
137
+
138
+ /** Tab order: targets that declare a place come first, ascending, then the rest in the order given. In the DOM a
139
+ * positive `tabindex` declares one and `0` does not. */
140
+ declare function tabSort<T>(targets: readonly T[], declared: (target: T) => number | undefined): T[];
141
+ /** The target one Tab step from `from` through `order`, or null past either end. From nothing, `'next'` is the
142
+ * first and `'prev'` the last. A `from` that is out of the order (hidden since it took focus, say) steps from where
143
+ * it sits, which `isBefore` says; without it, such a `from` steps as nothing does. */
144
+ declare function tabStep<T>(order: readonly T[], from: T | null, direction: 'next' | 'prev', isBefore?: (a: T, b: T) => boolean): T | null;
145
+
146
+ /** Steps an arrow key asks for along one axis: one, or {@link COARSE_STEPS} with Shift, positive
147
+ * toward ArrowRight and ArrowUp. Under `'rtl'` ArrowLeft and ArrowRight swap, as a native range
148
+ * input's do. `null` for any other key. A caller multiplies by its own step. */
149
+ declare function arrowSteps(key: string, shift: boolean, dir?: 'ltr' | 'rtl'): number | null;
150
+ /** Steps an arrow key asks for on a plane, in screen axes: `dy` is positive toward ArrowDown.
151
+ * One step, or {@link COARSE_STEPS} with Shift; `null` for any other key. */
152
+ declare function arrowMove(key: string, shift: boolean): {
153
+ dx: number;
154
+ dy: number;
155
+ } | null;
156
+ /** What a key does along a range: {@link arrowSteps}, the Page keys ({@link COARSE_STEPS} steps),
157
+ * or Home and End (an end of the range). `null` for any other key. */
158
+ declare function rangeKey(key: string, shift: boolean, dir?: 'ltr' | 'rtl'): number | 'home' | 'end' | null;
159
+
160
+ /** A value on a slider's track the thumb can come to rest on, with whatever label draws under it. */
161
+ interface SliderStop<L = unknown> {
162
+ value: number;
163
+ label?: L;
164
+ }
165
+ /** The stops that are actually reachable: inside the range, deduped, ascending.
166
+ * A duplicate keeps the first label given for its value. */
167
+ declare function usableStops<L>(stops: readonly (number | SliderStop<L>)[] | undefined, min: number, max: number): SliderStop<L>[];
168
+ /** The two-way map between a value and its place along a track, as a fraction: 0 at one end, 1 at the other. */
169
+ interface TrackMap {
170
+ toFraction(v: number): number;
171
+ toValue(f: number): number;
172
+ }
173
+ /** The stop nearest `v`, or `v` itself when none lies within `tolerance`. With `toFraction` the distance is
174
+ * measured along the track and `tolerance` is a track fraction, so evenly spaced stops attract over the same
175
+ * distance; without it both are in `v`'s own units. */
176
+ declare function attract(v: number, stops: readonly number[], tolerance: number, toFraction?: (v: number) => number): number;
177
+ /** The map for a track its stops divide evenly, whatever their values: each gap between two stops takes the
178
+ * same length, and a value sits between its neighbors in proportion. Needs two stops, ascending. */
179
+ declare function evenMap(stops: readonly number[]): TrackMap;
180
+ /** What a pointer on a slider's track reads: how the track maps to values, and what has a say in the value picked. */
181
+ interface SliderAtShape extends TrackMap {
182
+ /** The least and greatest value a pointer can pick. Either may be infinite. */
183
+ min: number;
184
+ max: number;
185
+ step?: number;
186
+ /** Where the step grid starts. Default `min`. */
187
+ origin?: number;
188
+ /** Values the pointer is pulled onto. */
189
+ stops?: readonly number[];
190
+ /** How near a stop pulls, as a track fraction. Default 0: only a pointer exactly on a stop lands on it. */
191
+ pull?: number;
192
+ /** Only a stop can be picked: the nearest, however far. */
193
+ strict?: boolean;
194
+ /** Pass the stops by. Not read under `strict`. */
195
+ free?: boolean;
196
+ }
197
+ /** The value a pointer at track fraction `f` picks: the track's value there, on the step grid and inside
198
+ * `min` to `max`, then pulled onto a stop within reach. */
199
+ declare function sliderAt(f: number, shape: SliderAtShape): number;
200
+ /** Keep thumb `index` strictly between its neighbors: a step apart, or a thousandth of the span without one, and
201
+ * inside `min` to `max`. Neighbors too close for that hold it between them, or failing that inside `min` to `max`. */
202
+ declare function clampOrdered(v: number, thumbs: readonly {
203
+ value: number;
204
+ }[], index: number, min: number, max: number, step: number | undefined): number;
205
+ /** What a key press on one thumb of a slider reads. */
206
+ interface SliderKeyShape {
207
+ thumbs: readonly {
208
+ value: number;
209
+ }[];
210
+ /** The thumb the key went to. */
211
+ index: number;
212
+ /** The ends of the track. */
213
+ min: number;
214
+ max: number;
215
+ step?: number;
216
+ /** Usable stops, ascending. With any, a keystroke moves by whole stops rather than by value. */
217
+ stops?: readonly number[];
218
+ /** Keep the thumb between its neighbors. */
219
+ ordered?: boolean;
220
+ /** The finite range, where the track runs past it to an endless end's stop. Default the track. */
221
+ range?: readonly [number, number];
222
+ /** Under `'rtl'` the horizontal arrows are mirrored, as the values run from the right end. */
223
+ dir?: 'ltr' | 'rtl';
224
+ /** This thumb's own limits inside the track. Read only for a key the slider answers to. */
225
+ bounds?(): readonly [number, number];
226
+ /** Where the thumb lands `steps` presses away, for a track whose values aren't what the user counts in. */
227
+ keyStep?(steps: number): number;
228
+ }
229
+ /** The value one key moves thumb `index` to: arrows by a step (ten with Shift), the Page keys by ten,
230
+ * Home and End to the thumb's ends. `null` for a key the slider does not answer to. */
231
+ declare function sliderKey(key: string, shift: boolean, shape: SliderKeyShape): number | null;
232
+
233
+ /** A stretch of values: a track's whole range, or the part of it a track shows. */
234
+ interface Span {
235
+ from: number;
236
+ to: number;
237
+ }
238
+ /** Where `v` sits along `span`, as a fraction: 0 at `from`, 1 at `to`, and outside that past either end.
239
+ * 0 for an empty span. */
240
+ declare function spanPlace(span: Span, v: number): number;
241
+ /** The value at fraction `f` of `span`. */
242
+ declare function spanValue(span: Span, f: number): number;
243
+ /** A length as a fraction of `span`'s. Unlike {@link spanPlace} it measures no position, so `span.from` has no say. */
244
+ declare function spanShare(span: Span, length: number): number;
245
+ /** `span` laid linearly along a track: the map {@link sliderAt} and {@link attract} read. Unclamped, so a
246
+ * place off either end of the track maps to a value outside the span. */
247
+ declare function spanMap(span: Span): TrackMap;
248
+ /** `span` moved inside `bounds`, keeping its length, or shortened to `bounds` where it is the longer. */
249
+ declare function spanHold(span: Span, bounds: Span): Span;
250
+ /** `span` shifted by `by` inside `bounds`, keeping its length. */
251
+ declare function spanPan(span: Span, by: number, bounds: Span): Span;
252
+ /** `span` scaled by `factor` about `at`, which keeps its place along the track unless `bounds` push it.
253
+ * A `factor` below 1 narrows. The result is no shorter than `minLength` and no longer than `bounds`. */
254
+ declare function spanZoom(span: Span, at: number, factor: number, bounds: Span, minLength?: number): Span;
255
+
256
+ /** How a text field's edit ends: `'commit'` writes what was typed, `'cancel'` drops it and puts back what was there. */
257
+ type EditEnd = 'commit' | 'cancel';
258
+ /** What a field varies in how its edit ends: what Escape does (`'cancel'` by default), and whether the field holds
259
+ * more than one line, which leaves Shift+Enter to type a line break rather than commit. */
260
+ interface EditEndShape {
261
+ escape?: EditEnd;
262
+ multiline?: boolean;
263
+ }
264
+ /** What may end an edit: a key, with whether Shift is held, or the field losing focus. A key {@link imeKey} claims is
265
+ * the caller's to hold back. */
266
+ type EditCause = 'blur' | {
267
+ key: string;
268
+ shift?: boolean;
269
+ };
270
+ /** How `cause` ends a text field's edit, or null when it leaves the edit open. Enter and blur commit, Escape cancels
271
+ * unless `shape` says otherwise. */
272
+ declare function editEnd(cause: EditCause, shape?: EditEndShape): EditEnd | null;
273
+ /** A keydown as the platform reports it, enough to tell whether an input method owns it. */
274
+ interface KeySource {
275
+ key: string;
276
+ isComposing?: boolean;
277
+ keyCode?: number;
278
+ }
279
+ /** Whether a keydown belongs to an input method, which a field must leave alone: Enter there confirms a candidate and
280
+ * Escape dismisses them. Safari sends the Enter that ends a composition with `isComposing` already false, but with
281
+ * `keyCode` 229. */
282
+ declare function imeKey(e: KeySource): boolean;
283
+
284
+ /**
285
+ * Moving items within an ordered list. A destination is a gap, counted before anything is taken out: 0 before the
286
+ * first item, `length` after the last, and `i` between `items[i - 1]` and `items[i]` — the gap a UI marks while it
287
+ * carries something. The items moved are named by their indices, so a selection of several moves in one go.
288
+ */
289
+ /** `items` with the items at indices `at` taken out and put back, in their order, in gap `to`. An index outside
290
+ * `items`, or not a whole number, names nothing and is ignored; a gap past either end is that end. */
291
+ declare function moveItems<T>(items: readonly T[], at: readonly number[], to: number): T[];
292
+ /** The index the first of the items at `at` holds once {@link moveItems} has put them in gap `to`. */
293
+ declare function movedIndex(at: readonly number[], to: number): number;
294
+ /** Whether putting the items at `at` in gap `to` leaves them where they are: a contiguous run dropped in a gap at
295
+ * either of its ends or inside it. False for no items. */
296
+ declare function isNoopDrop(at: readonly number[], to: number): boolean;
297
+ /** The gap a one-place move sends the items at `at` to: before the item ahead of the first (`by` -1), or after the
298
+ * item past the last (`by` 1). Null where that runs off either end of a list `length` long, or for no items. */
299
+ declare function nudgeGap(at: readonly number[], by: -1 | 1, length: number): number | null;
300
+ /**
301
+ * The gap a point `p` along a line of items falls in, where each item splits at its middle: how many of the
302
+ * middles `mids`, given in item order, `p` has reached. A line whose middles run backward, as a right-to-left row
303
+ * does along x, counts the other way. For items that sit side by side — rows, tabs, chips.
304
+ */
305
+ declare function gapByMidpoint(mids: readonly number[], p: number): number;
306
+ /** Which of the gaps at positions `gaps` along a line is nearest `p`, as an index into `gaps`; -1 for none. For
307
+ * gaps drawn at places of their own, between items set apart however the layout put them: picking the nearest
308
+ * keeps the gap chosen the one whose mark is drawn closest. */
309
+ declare function nearestGap(gaps: readonly number[], p: number): number;
310
+ /**
311
+ * Which part of an item a pointer at fraction `f` along it is over: the leading `band` of it drops before, the
312
+ * trailing `band` after, and what lies between drops into it. The default `band` of a half leaves no middle, which
313
+ * is an item that cannot take a drop into it, split at its midpoint.
314
+ */
315
+ declare function dropBand(f: number, band?: number): 'before' | 'into' | 'after';
316
+ /** The keys and modifiers a nudge chord reads off a keystroke. */
317
+ interface NudgeKey {
318
+ key: string;
319
+ altKey: boolean;
320
+ ctrlKey: boolean;
321
+ metaKey: boolean;
322
+ }
323
+ /** Alt with neither Ctrl nor Cmd held: the chord that moves an item instead of moving focus. */
324
+ declare function isNudgeChord(e: NudgeKey): boolean;
325
+ /** Which way the nudge chord moves an item: `-1` for Alt+`back`, `1` for Alt+`on`, `null` for any other key.
326
+ * The keys are Up and Down unless named. */
327
+ declare function nudgeOf(e: NudgeKey, back?: string, on?: string): -1 | 1 | null;
328
+
329
+ /** A box on a surface, by its top-left corner and size. */
330
+ interface Box {
331
+ x: number;
332
+ y: number;
333
+ width: number;
334
+ height: number;
335
+ }
336
+
337
+ /** How near an edge a dragged pointer starts a scroll, in px, unless a caller says otherwise. */
338
+ declare const EDGE_SCROLL_MARGIN = 48;
339
+ /**
340
+ * How hard a pointer at `p` pushes `span` to scroll, from -1 toward `from` to 1 toward `to`: 0 while `p` is
341
+ * `margin` or more inside both ends, rising linearly to full strength at an end and holding it past there, so
342
+ * overshooting does not reverse the scroll. A span narrower than two margins scrolls toward the nearer end.
343
+ */
344
+ declare function edgePush(span: Span, p: number, margin?: number): number;
345
+ /** {@link edgePush} on both axes of a scrolling box: multiply by a top speed for how far to scroll. */
346
+ declare function edgeScroll(bounds: Box, point: {
347
+ x: number;
348
+ y: number;
349
+ }, margin?: number): {
350
+ x: number;
351
+ y: number;
352
+ };
353
+
354
+ /** A way to move across a surface, in its own x and y: y grows downward. */
355
+ type Heading = 'left' | 'right' | 'up' | 'down';
356
+ /** How much a unit of drift across a heading costs against a unit of travel along it. */
357
+ declare const HEADING_DRIFT = 2;
358
+ /** The heading an arrow key asks for, or null for any other key. */
359
+ declare function headingOf(key: string): Heading | null;
360
+ /**
361
+ * What it costs to go from `from` to `to` on `heading`, center to center: the travel along the heading plus
362
+ * `drift` times the distance across it, so a target straight ahead beats a nearer one off to the side. Null for
363
+ * a target that is not ahead at all.
364
+ */
365
+ declare function headingCost(from: Box, to: Box, heading: Heading, drift?: number): number | null;
366
+ /** Which of `targets` focus moves to from `from` on `heading`: the index of the cheapest by {@link headingCost},
367
+ * the earlier of two that tie, or -1 when none is ahead. A target with no box is passed over. */
368
+ declare function nearestToward(from: Box, targets: readonly (Box | null | undefined)[], heading: Heading, drift?: number): number;
369
+
370
+ /** Clock and timer, injected so tests and hosts control time. */
371
+ interface Scheduler {
372
+ now(): number;
373
+ /** Run `fn` after `ms`; returns a cancel. */
374
+ set(fn: () => void, ms: number): () => void;
375
+ }
376
+ /** The real-time scheduler: `Date.now` and `setTimeout`. */
377
+ declare const timerScheduler: Scheduler;
378
+
379
+ /** How long a held stepper waits before it repeats, in milliseconds. */
380
+ declare const REPEAT_DELAY_MS = 400;
381
+ /** How often a held stepper steps once it repeats, in milliseconds. */
382
+ declare const REPEAT_EVERY_MS = 60;
383
+ /** The timing of a {@link createStepRepeat}. Each is read when it is next used, so a getter can change it mid-hold. */
384
+ interface StepRepeatOptions {
385
+ /** Default {@link REPEAT_DELAY_MS}. */
386
+ delayMs?: number;
387
+ /** Default {@link REPEAT_EVERY_MS}. */
388
+ everyMs?: number;
389
+ /** Default {@link timerScheduler}. */
390
+ scheduler?: Pick<Scheduler, 'set'>;
391
+ }
392
+ /** A held stepper: {@link createStepRepeat}. */
393
+ interface StepRepeat<K> {
394
+ /** Step `key` once now, then after the delay once every interval until {@link stop}. Replaces any hold. */
395
+ start(key: K): void;
396
+ stop(): void;
397
+ /** The key being held, or null. */
398
+ held(): K | null;
399
+ }
400
+ /**
401
+ * Hold-to-repeat stepping, whatever draws the stepper: `step` moves the value by `key`, and `spent` says `key`
402
+ * has nowhere left to go, which ends the hold. Both are called at the moment of each step.
403
+ */
404
+ declare function createStepRepeat<K>(step: (key: K) => void, spent: (key: K) => boolean, opts?: StepRepeatOptions): StepRepeat<K>;
405
+
406
+ /**
407
+ * A parameter's domain, apart from how it is walked. A scrubber reads it
408
+ * continuously, one value at a time (`at`); a stepped sequence reads every
409
+ * step at once (`walk`). Time is one domain among others (`frames`).
410
+ */
411
+ interface Sweep<V> {
412
+ /** The value `u` of the way along, 0 to 1, clamped: a scrubber's reading. A
413
+ * domain of discrete steps answers its nearest step. */
414
+ at(u: number): V;
415
+ /** Every step in order: a sequence's reading. May never end; `stepsOf` caps it. */
416
+ walk(): Iterable<V>;
417
+ /** How a value reads in a caption or a readout. */
418
+ label(value: V): string;
419
+ }
420
+ /** How many steps `stepsOf` takes from a sweep that has not ended by then. */
421
+ declare const SWEEP_CAP = 256;
422
+ /** The first `cap` steps of `sweep`, and whether it had more. `cap` is a whole number, 0 or more. */
423
+ declare function stepsOf<V>(sweep: Sweep<V>, cap?: number): {
424
+ steps: V[];
425
+ capped: boolean;
426
+ };
427
+ /** What {@link range} walks: its ends, and either a `step` or a `count`. */
428
+ type RangeSpec = {
429
+ from: number;
430
+ /** May be `Infinity`, for a walk that only `until` or a cap ends. */
431
+ to: number;
432
+ label?: (value: number) => string;
433
+ } & ({
434
+ step: number;
435
+ count?: never;
436
+ } | {
437
+ count: number;
438
+ step?: never;
439
+ });
440
+ /**
441
+ * Numbers from `from` to `to`, either `step` apart (the last step at or before
442
+ * `to`) or `count` of them evenly spaced, both ends included. With `step`, `at`
443
+ * snaps to a step; with `count` it is continuous, as the steps are only samples.
444
+ */
445
+ declare function range(spec: RangeSpec): Sweep<number>;
446
+ /** The values of a list, in its order; `at` snaps to the nearest. */
447
+ declare function values<V>(list: readonly V[], label?: (value: V) => string): Sweep<V>;
448
+ /** What `frames` reads of a clock's declaration; a `ClockSpec` is one. */
449
+ interface FrameSpan {
450
+ /** ms per pass; omitted, the run never ends. */
451
+ duration?: number;
452
+ /** Passes: `true` endless, `false` one, `n` that many. */
453
+ loop?: boolean | number;
454
+ /** The time elapsed 0 is shown as, for the labels. */
455
+ origin?: number;
456
+ }
457
+ /** How {@link frames} walks a clock's run. */
458
+ interface FrameOptions {
459
+ /** ms between frames. */
460
+ every: number;
461
+ /** `'first'`, the default, walks one pass; `'all'` walks the whole run, which
462
+ * for an endless loop never ends. */
463
+ passes?: 'first' | 'all';
464
+ label?: (elapsed: number) => string;
465
+ }
466
+ /**
467
+ * The frames of a clock's run, as elapsed ms, `every` apart from 0. A run that
468
+ * ends shows its last frame; a pass that loops back stops short of its end,
469
+ * which is the next pass's start. `at` is continuous over the span walked.
470
+ */
471
+ declare function frames(span: FrameSpan, options: FrameOptions): Sweep<number>;
472
+ /** `sweep` walked only as far as the step before the first one `done` accepts:
473
+ * "every frame until it repeats". `at` is the inner sweep's. */
474
+ declare function until<V>(sweep: Sweep<V>, done: (value: V, index: number) => boolean): Sweep<V>;
475
+
476
+ /** Where a last row shorter than the rest sits: at the start, centered, at the end, or with its items stretched
477
+ * across the whole row. */
478
+ type LastRow = 'start' | 'center' | 'end' | 'fill';
479
+ /** How a run of items tiles. */
480
+ interface Tiling {
481
+ /** Items per row: a whole number, one for anything below one, and at most 2^24. */
482
+ columns: number;
483
+ /** Where a last row shorter than `columns` sits. Default `'start'`. */
484
+ lastRow?: LastRow;
485
+ }
486
+ /** How far in, in columns, a row of `length` items sits in a grid `columns` across, aligned `align`. A
487
+ * stretched (`'fill'`) row starts at the start. */
488
+ declare function rowOffset(length: number, columns: number, align?: LastRow): number;
489
+ /** Where a tiling's items sit on its tracks. */
490
+ interface TileGrid {
491
+ /** Tracks across: twice `columns`, so a short row can sit a half column in, or enough for both a full row and a
492
+ * stretched one to divide evenly. */
493
+ tracks: number;
494
+ /** Tracks a full row's item spans. */
495
+ span: number;
496
+ /** Tracks a stretched last row's item spans. */
497
+ fillSpan: number;
498
+ /** How far an offset last row sits from the start, in tracks; 0 for one at the start, stretched, or none. */
499
+ lead: number;
500
+ /** Index of the last row's first item. */
501
+ lastStart: number;
502
+ /** Whether item `i` is in a stretched last row. */
503
+ stretched(i: number): boolean;
504
+ /** The grid's outer corners item `i` sits on: `ss` top-left, `se` top-right, `es` bottom-left, `ee` bottom-right,
505
+ * in the inline direction. */
506
+ corners(i: number): ('ss' | 'se' | 'es' | 'ee')[];
507
+ }
508
+ /** How `count` items tile under `spec`. */
509
+ declare function tileGrid(count: number, spec: Tiling): TileGrid;
510
+ /** How a grid's rows sit for {@link rovingGridTarget}. */
511
+ interface GridLayout {
512
+ dir?: 'ltr' | 'rtl';
513
+ /** How many columns in each row's first item sits, by row: a short row centered in an even gap sits a half
514
+ * column in. Omitted rows start at column 0. */
515
+ offsets?: readonly number[];
516
+ /** How many columns wide each row's items are, by row: a stretched last row's are wider than one. Omitted
517
+ * rows' items are one column wide. */
518
+ widths?: readonly number[];
519
+ }
520
+ /** The rows of `count` items `columns` across, as item indices in reading order. */
521
+ declare function tileRows(count: number, across: number): number[][];
522
+ /** Where `key` takes focus from `current` among `count` items tiled by `spec`, by {@link rovingGridTarget}: null
523
+ * if it does not move it. Every item is enabled unless `enabled` says otherwise. */
524
+ declare function tileKey(current: number, key: string, count: number, spec: Tiling, opts?: {
525
+ dir?: 'ltr' | 'rtl';
526
+ enabled?: readonly boolean[];
527
+ }): number | null;
528
+ /** The layout of `rows` in a grid `columns` across whose short rows sit as `lastRow` says. */
529
+ declare function gridLayout(rows: readonly (readonly number[])[], across: number, lastRow?: LastRow): GridLayout;
530
+ /** Where `key` takes focus from `current` in a grid whose `rows` list item indices in reading order, or null if
531
+ * it does not move it. Left and Right step through the enabled items in reading order (swapped under `'rtl'`),
532
+ * wrapping, and Home and End go to the first and last. Up and Down move to the item under this one in the next
533
+ * row, by where each row sits, or to that row's nearest end when none is under it; they pass over rows where that
534
+ * item is disabled, and stop at the first and last rows. */
535
+ declare function rovingGridTarget(current: number, key: string, enabled: readonly boolean[], rows: readonly (readonly number[])[], layout?: GridLayout): number | null;
536
+
537
+ /**
538
+ * Selection: which of a run of items are on. One spec answers what each item
539
+ * shows, what a click on it does, what the arrow keys do, and how a sweep
540
+ * sets several at once, so a component taking it cannot get one of them
541
+ * wrong. Build a model with {@link selection} (one value, or a list of them)
542
+ * or {@link selectionOfEach} (items that each own a boolean); {@link selectionKeys}
543
+ * says what the keyboard does with it.
544
+ */
545
+ /** An item's state: on, off, or mixed, where the sources it aggregates disagree. */
546
+ type SelectState = 'off' | 'on' | 'mixed';
547
+ /** At most one item on, held as its value or `null`. */
548
+ interface SingleSelection<V> {
549
+ mode?: 'single';
550
+ value: V | null;
551
+ onChange: (next: V | null) => void;
552
+ /** A click on the item that is on turns it off. Default false. */
553
+ allowDeselect?: boolean;
554
+ /** Values drawn mixed, where `value` holds none of them. A click on one chooses it. */
555
+ mixedValues?: readonly V[];
556
+ /** The arrow keys choose the item they land on, as a radio group's do. Default true; false moves focus only,
557
+ * and Space or Enter chooses. */
558
+ followsFocus?: boolean;
559
+ }
560
+ /** Any number of items on, held as a list of their values. */
561
+ interface MultipleSelection<V> {
562
+ mode: 'multiple';
563
+ value: readonly V[];
564
+ onChange: (next: V[]) => void;
565
+ /**
566
+ * Values that are neither on nor off: the sources this aggregates disagree (a text range bold in part of it, a
567
+ * multi-selection whose nodes differ). `value` wins where the two lists overlap. A click on one turns it on.
568
+ */
569
+ mixedValues?: readonly V[];
570
+ }
571
+ /** One spec for a run of items whose selection is one value or a list of them. */
572
+ type SelectionSpec<V> = SingleSelection<V> | MultipleSelection<V>;
573
+ /** One item that owns its own on/off state. */
574
+ interface OwnSelection {
575
+ selected: boolean;
576
+ onChange: (next: boolean) => void;
577
+ }
578
+ /** A run of changes to a selection, each from where the last left it: a sweep's. */
579
+ interface SelectionEdit {
580
+ /** Set item `index` on or off. */
581
+ set(index: number, on: boolean): void;
582
+ /** Put back what the edit started from. */
583
+ revert(): void;
584
+ }
585
+ /** A selection over items by index. */
586
+ interface SelectionModel {
587
+ /** At most one item on, or any number. */
588
+ readonly mode: 'single' | 'multiple';
589
+ stateOf(index: number): SelectState;
590
+ /** What a click on item `index` does: choose it, or flip it. */
591
+ press(index: number): void;
592
+ /** Start a run of changes. Each `set` reports as it happens, from the edit's own copy, so a run faster than
593
+ * the component re-renders loses none of them. */
594
+ edit(): SelectionEdit;
595
+ /** The arrow keys choose as they move. */
596
+ readonly followsFocus: boolean;
597
+ }
598
+ /** `spec`'s selection over `values`, one per item in order. */
599
+ declare function selection<V>(spec: SelectionSpec<V>, values: readonly V[]): SelectionModel;
600
+ /** The selection of items that each own their state: any number on, and nothing mixed. */
601
+ declare function selectionOfEach(items: readonly OwnSelection[]): SelectionModel;
602
+ /** A sweep over `model` from a press on item `from`: each item it `reach`es is set to the opposite of whether the
603
+ * pressed one was on, so a drag from an off or mixed item turns on everything it crosses and one from an on item
604
+ * turns it off. `revert` puts back what the sweep started from. */
605
+ declare function sweepFrom(model: SelectionModel, from: number): {
606
+ reach(index: number): void;
607
+ revert(): void;
608
+ };
609
+ /** What the keyboard does with `model`'s items. Where a single selection follows focus, the tab stop sits on the
610
+ * chosen item and an arrow landing on one chooses it; otherwise the arrows only move focus, and Space or Enter
611
+ * presses. `enabled(i)` is false for an item nothing may choose. */
612
+ declare function selectionKeys(model: SelectionModel, count: number, enabled?: (index: number) => boolean): {
613
+ tabStop?: number;
614
+ landed?: (index: number) => void;
615
+ activate?: (index: number) => void;
616
+ };
617
+
618
+ export { EDGE_SCROLL_MARGIN, EMPTY_TYPEAHEAD, HEADING_DRIFT, REPEAT_DELAY_MS, REPEAT_EVERY_MS, SWEEP_CAP, TYPEAHEAD_RESET_MS, arrowDir, arrowMove, arrowSteps, attract, clampOrdered, createStepRepeat, dropBand, edgePush, edgeScroll, editEnd, evenMap, firstStop, frames, gapByMidpoint, gridLayout, headingCost, headingOf, imeKey, isNoopDrop, isNudgeChord, isOneChar, moveItems, movedIndex, nearestGap, nearestToward, nudgeGap, nudgeOf, range, rangeKey, rovingGridTarget, rovingKey, rowKey, rowOffset, selection, selectionKeys, selectionOfEach, sliderAt, sliderKey, spanHold, spanMap, spanPan, spanPlace, spanShare, spanValue, spanZoom, stepStop, stepsOf, sweepFrom, tabSort, tabStep, tileGrid, tileKey, tileRows, timerScheduler, treeKey, typeaheadMatch, typeaheadStep, until, usableStops, values };
619
+ export type { Box, EditCause, EditEnd, EditEndShape, FrameOptions, FrameSpan, GridLayout, Heading, KeyPress, KeySource, LastRow, ListShape, MultipleSelection, NudgeKey, OwnSelection, RangeSpec, RovingResult, RowKeyAction, RowKeysShape, Scheduler, SelectState, SelectionEdit, SelectionModel, SelectionSpec, SingleSelection, SliderAtShape, SliderKeyShape, SliderStop, Span, StepRepeat, StepRepeatOptions, Sweep, TileGrid, Tiling, TrackMap, TreeKeyResult, TreeShape, TypeaheadBuffer, TypeaheadShape };