Skip to content

Commit 27993ae

Browse files
committed
add vertical scroll support
1 parent e9320f8 commit 27993ae

16 files changed

+1043
-245
lines changed

bun.lock

Lines changed: 2 additions & 16 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/components-and-styling.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@
33
## Constructors
44

55
```ts
6-
Box(input: BoxProps, children: Node[]): Node
7-
Column(input: Omit<BoxProps, "direction">, children: Node[]): Node
8-
Row(input: Omit<BoxProps, "direction">, children: Node[]): Node
6+
Box(input: BoxProps & BoxEventProps, children: Node[]): Node
7+
Column(input: Omit<BoxProps, "direction"> & BoxEventProps, children: Node[]): Node
8+
Row(input: Omit<BoxProps, "direction"> & BoxEventProps, children: Node[]): Node
99
Text(input: TextProps): Node
1010
Input(input: InputProps): Node
1111
Button(input: ButtonProps, children?: Node[]): Node
@@ -36,6 +36,11 @@ Button(input: ButtonProps, children?: Node[]): Node
3636
- optional: `direction` (`"row" | "column" | "rowReverse" | "columnReverse"`)
3737
- optional: all `StyleProps`
3838

39+
- `BoxEventProps`
40+
- optional: `onWheel(event)` for vertical wheel/trackpad handling
41+
- `event`: `{ x, y, deltaY, raw }`
42+
- return `true` to consume and stop bubbling; return `false`/`void` to bubble to parent container
43+
3944
## Shared style fields (`StyleProps`)
4045

4146
- `border`: `{ color: number; style: "square" | "rounded" }`
@@ -67,6 +72,19 @@ Button(input: ButtonProps, children?: Node[]): Node
6772
- `overflow`, scrolling, and other non-exported props are not part of the public API.
6873
- Prefer `Row` / `Column` for common cases; use `Box` when you need explicit `direction`, including reverse directions.
6974

75+
## Wheel Routing
76+
77+
- wheel routing targets the deepest container with `onWheel` under the cursor
78+
- events bubble up through parent containers until one handler returns `true`
79+
- horizontal wheel is deferred; current surface exposes vertical `deltaY` only
80+
81+
## Virtual List Notes
82+
83+
- `createVirtualListController(...)` uses row-based virtualization with stable slot nodes
84+
- avoid large overscan in normal-flow containers; it can increase container height and create layout feedback loops
85+
- runtime guard now disables overscan automatically when it detects repeated viewport-growth feedback
86+
- for high overscan, prefer a clipped/fixed-height viewport container so slot count does not affect layout height
87+
7088
## Colors
7189

7290
Use `COLORS` from the library.

docs/state-events-lifecycle.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ onKey(key: string, callback: () => void): void
7272
- Keyboard input routed to focused node first
7373
- If focused node consumes key event, global `onKey` handler does not run
7474

75+
## Wheel Routing Model
76+
77+
- wheel events use SGR mouse input and dispatch to `onWheel` on `Row`/`Column` containers
78+
- dispatch starts at deepest container under cursor with a wheel handler
79+
- if handler returns `true`, bubbling stops; otherwise event bubbles to parent containers
80+
- current payload: `{ x, y, deltaY, raw }` with vertical `deltaY` only
81+
7582
## Input behavior
7683

7784
For focused `Input` node:
@@ -111,3 +118,12 @@ onKey("q", quit);
111118

112119
- Keep long-lived nodes and mutate them with `setText`, `setStyle`, or signals
113120
- Rebuilding whole subtrees every tick changes tree shape and forces Rust tree rebuilds
121+
122+
## Virtualization Rule
123+
124+
- for large scrolling lists, keep a fixed slot pool (`setChildren` only on viewport-size changes)
125+
- bind slot content by updating text/style on stable nodes instead of creating/removing nodes per scroll tick
126+
- row-based slicing is done in JS by mapping scroll rows to visible line ranges
127+
- if virtualized rows are normal-flow children, overscan can feed back into layout (more slots -> taller viewport -> more slots)
128+
- virtual list now auto-disables overscan when this runaway growth pattern is detected and logs a warning
129+
- if you need overscan for smoothness, place virtualized slots in a clipped/fixed-height viewport container

dump/codex-screen.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
MODEL gpt-5.4 STATUS idle TOKENS 0 LAT — ──────────────────────────────────────────────────────────────────────────────────────────────────── │ Prompts ─────── │ … … │ … │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╭───────────────────────────────────────────────────────────╮ │ │ │ │ ╰───────────────────────────────────────────────────────────╯ │ … │ MODEL gpt-5.4STATUS idleTOKENS 0LAT —────────────────────────────────────────────────────────────────────────────────────────────────────Prompts───────│AI AGENT Ctrl+N new ↑↓ switch │ Submit a prompt to start the thread. ● New Thread 0 │Ctrl+N creates a new thread. │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │╭──────────────────────────────────────────────────────╮ │ │ █ │ │╰──────────────────────────────────────────────────────╯ │Enter send Tab focustyped█

dump/metrics.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
1200fps | 0.8ms avg (0.3-2.6, p99:2.5) | 35MB | 101 frames
2-
serialize: 0.2ms (0-1.1) [tree→rust]
3-
textSync: 0.2ms (0-1.1, p99:1.1) | ops:2.1 avg 50 max | bytes:63.2 avg 2483 max
4-
rust: 0.3ms (0.1-1.1) [layout+paint]
5-
sync: 0.1ms (0-0.3) [frames→JS]
6-
flush: 0.1ms (0-0.3) [terminal I/O]
1+
1212fps | 0.8ms avg (0.3-3.5, p99:1.9) | 10MB | 372 frames
2+
serialize: 0.1ms (0-0.7) [tree→rust]
3+
textSync: 0.1ms (0-0.7, p99:0.4) | ops:31.4 avg 82 max | bytes:736.1 avg 2003 max
4+
rust: 0.5ms (0.1-1.7) [layout+paint]
5+
sync: 0ms (0-0.2) [frames→JS]
6+
flush: 0.1ms (0-0.2) [terminal I/O]

0 commit comments

Comments
 (0)