@weasel-js/ui-input 0.0.0-stage → 1.18.2

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 orochi235
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,144 @@
1
- # Temporary Holding Version
1
+ # @weasel-js/ui-input
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ What a key or a pointer does to a control, as pure functions over numbers, keys and boxes: arrow steps, sliders
4
+ and windowed tracks, a list's roving highlight and typeahead, a tree's keys, selection, grid tiling, reorder and
5
+ drop gaps, edge scroll, focus order and directional focus, how a text field's edit ends. A DOM component and a
6
+ canvas-drawn widget run the same rule and each draws the result its own way. No React, no DOM.
7
+
8
+ Part of [weasel](https://github.com/orochi235/weasel), a domain-agnostic 2D
9
+ scene-graph canvas kit for React. See the
10
+ [API reference](https://orochi235.github.io/weasel/#pkg/ui-input).
11
+
12
+ ## Install
13
+
14
+ ```sh
15
+ npm install @weasel-js/ui-input
16
+ ```
17
+
18
+ ## Usage
19
+
20
+ ```ts
21
+ import { EMPTY_TYPEAHEAD, rovingKey, typeaheadStep } from '@weasel-js/ui-input';
22
+
23
+ type Row = { name: string; heading?: boolean };
24
+ const shape = { canStop: (r: Row) => !r.heading, label: (r: Row) => r.name };
25
+
26
+ let at: number | null = null;
27
+ let typed = EMPTY_TYPEAHEAD;
28
+
29
+ function onKey(rows: readonly Row[], key: string): void {
30
+ const r = rovingKey(rows, at, key, shape); // arrows, Home, End
31
+ if (r.handled) { at = r.at; return; }
32
+ if (key.length === 1) {
33
+ const t = typeaheadStep(rows, at, typed, key, Date.now(), shape);
34
+ typed = t.buffer;
35
+ if (t.hit !== null) at = t.hit;
36
+ }
37
+ }
38
+ ```
39
+
40
+ A list's shape says which items the highlight can land on (`canStop`), which arrows move it
41
+ (`orientation`, vertical by default, or `'both'` for all four), whether Left and Right swap for a
42
+ right-to-left layout (`dir`), and whether it wraps at the ends (`wrap`, on by default).
43
+ `@weasel-js/menu` runs every menu level on these.
44
+
45
+ ## Trees and rows
46
+
47
+ `treeKey` is a tree's Right and Left, the WAI-ARIA way: Right opens a closed branch or steps to
48
+ its first child, Left closes an open branch or steps to the parent. Its `TreeShape` says which
49
+ items are branches, which are open, and which is whose child.
50
+
51
+ `rowKey` is every key a list of rows answers, in one place: Cmd/Ctrl+A, the arrows with Home and
52
+ End (Shift extends), a tree's Right and Left, Enter and Space, and typeahead. It returns what the
53
+ key asks for (`selectAll`, `move`, `toggle`, `activate`, `type`) and the caller carries it out.
54
+ `@weasel-js/ui`'s `useRowNavigation` runs on it.
55
+
56
+ ## Focus
57
+
58
+ `tabSort(targets, declared)` is Tab order, targets that declare a place first, and `tabStep` is one Tab step
59
+ through it. `@weasel-js/ui-logic`'s `FocusScope` moves focus by them.
60
+
61
+ Targets placed freely, with no row or grid to walk, take the arrows by where they sit. `nearestToward(from, targets,
62
+ heading)` is the index of the target focus moves to: the cheapest by `headingCost`, which adds the travel along the
63
+ heading to twice the drift across it, so a target straight ahead beats a nearer one off to the side. `headingOf(key)`
64
+ reads the heading off an arrow key.
65
+
66
+ ## Selection and grids
67
+
68
+ `selection(spec, values)` is which of a run of items are on: one value or `null` (`mode: 'single'`, which may
69
+ `allowDeselect` and may not follow focus), or a list of them (`'multiple'`), either with `mixedValues`, where the
70
+ sources disagree. `selectionOfEach(items)` is the same over items that each own a boolean. The model says each
71
+ item's state (`'on'`, `'off'`, `'mixed'`), what a press does, and runs an `edit`, a run of changes from its own
72
+ copy that it can revert; `sweepFrom` is a sweep's, setting each item it reaches to the opposite of whether the
73
+ pressed one was on. `selectionKeys` says what the keyboard does with it.
74
+
75
+ `tileGrid(count, { columns, lastRow })` lays a run of same-size items out as a grid, a short last row at its start,
76
+ centered, at its end, or stretched across (`'fill'`): its tracks, each item's span, and which of the grid's outer
77
+ corners each item sits on. `rovingGridTarget` walks such a grid with the arrows, Up and Down landing on the item
78
+ drawn under this one, by `gridLayout`'s per-row offsets and widths; `tileKey` does the same for `count` items
79
+ tiled by a spec. `@weasel-js/ui`'s `ToggleBar`, `OptionsBar`,
80
+ `ButtonBar`, `SwatchGrid` and `ToolGroup` run on these.
81
+
82
+ ## Steps and sliders
83
+
84
+ `arrowSteps`, `arrowMove` and `rangeKey` are what an arrow key asks for: one step, or `COARSE_STEPS`
85
+ (ten) with Shift or a Page key, and Home and End for a range's ends. `sliderKey` turns one key into
86
+ a thumb's next value, by step or by whole stops, across an endless end and inside its neighbors;
87
+ `@weasel-js/ui`'s `Slider` runs on it.
88
+
89
+ `sliderAt(f, shape)` is the pointer's half: the value picked at fraction `f` of the track, on the
90
+ step grid, inside `min` to `max`, and pulled onto a stop within `pull` unless `free`. The shape
91
+ carries a `TrackMap`, the two-way map between a value and its place along the track, so the rule
92
+ does not care what the track is. `spanMap(span)` lays a `Span` along it linearly, `evenMap(stops)`
93
+ gives every gap between stops the same length, and a caller with a scale of its own writes the two
94
+ functions itself. `attract` is the pull alone: the nearest stop within a tolerance, measured along
95
+ the track with a map or in the value's own units without one.
96
+
97
+ A track need not show its whole range. A `Span` is a stretch of values, and a track that shows
98
+ one span of a longer range is a windowed track: `spanPan` and `spanZoom` move the window inside
99
+ its bounds, `spanZoom` about a value that keeps its place, and `spanPlace` and `spanShare` put a
100
+ value and a length at their fractions of it. Values outside the window map to places off the
101
+ track's ends, so a thumb can sit out of view and a drag can carry one there.
102
+
103
+ ```ts
104
+ const window = { from: 2000, to: 3000 };
105
+ const track = { min: 0, max: Infinity, ...spanMap(window) };
106
+ sliderAt(0.5, track); // 2500
107
+ sliderAt(0.52, { ...track, stops: [2510], pull: 6 / 400 }); // 2510, within 6px on a 400px track
108
+ spanZoom(window, 2500, 0.5, { from: 0, to: 10_000 }); // { from: 2250, to: 2750 }
109
+ ```
110
+
111
+ `@weasel-js/ui`'s `Timeline` runs its lanes and ruler on these: a lane is a track windowed onto the
112
+ timeline, its keys the thumbs and every other key's time a stop.
113
+
114
+ ## Text fields
115
+
116
+ `editEnd(cause, shape)` says how a text field's edit ends: Enter and blur commit, Escape cancels.
117
+ A field's shape can make Escape commit too, and a `multiline` one leaves Shift+Enter to type a
118
+ line break. Caret movement stays with each field: a DOM field gets it from the browser.
119
+
120
+ ## Reorder
121
+
122
+ Moving items within a list, whether it is drawn in the DOM or on a canvas. A destination is a gap counted before
123
+ anything is taken out: 0 before the first item, `length` after the last. `moveItems(items, at, to)` moves the items at
124
+ indices `at` into gap `to`; `isNoopDrop` says whether that leaves them where they are; `nudgeGap` is the gap a
125
+ one-place move takes them to, and `nudgeOf` reads the Alt+arrow chord that asks for one. A pointer finds its gap by
126
+ `gapByMidpoint`, for items side by side, each split at its middle, or by `nearestGap`, for gaps drawn at places of
127
+ their own. `dropBand(f, band)` says which part of one item the pointer is over: before it, after it, or, with a
128
+ `band` under a half, into it.
129
+
130
+ A drag near the edge of a scrolling box scrolls it. `edgePush(span, p, margin)` is how hard, from -1 to 1: nothing
131
+ until the pointer is within `margin` of an end, full strength at the end and past it. `edgeScroll(bounds, point)`
132
+ reads both axes of a box; multiply by a top speed.
133
+
134
+ ## Hold-to-repeat
135
+
136
+ `createStepRepeat(step, spent, opts)` is a held stepper: `start(key)` steps once, then after
137
+ `REPEAT_DELAY_MS` once every `REPEAT_EVERY_MS` until `stop()`, or until `spent(key)` says the value
138
+ has nowhere left to go. Time comes from a `Scheduler` (`now`, and `set` returning a cancel), by
139
+ default `timerScheduler`; pass your own to drive it from another clock or a test. `@weasel-js/ui`'s
140
+ number field steppers and `@weasel-js/hud`'s menu number chips both hold through it.
141
+
142
+ ## License
143
+
144
+ MIT