@trendr/core 0.4.13 → 0.4.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trendr/core",
3
- "version": "0.4.13",
3
+ "version": "0.4.15",
4
4
  "description": "direct-mode TUI renderer with JSX, signals, and per-cell diffing",
5
5
  "license": "MIT",
6
6
  "author": "Jonathan Pyers",
package/src/diff-view.js CHANGED
@@ -148,7 +148,9 @@ export function Diff({
148
148
  // inside a scrolled container and would swallow wheel events meant for it
149
149
  if (!hitTest(event.x, event.y)) return
150
150
  if (event.direction !== 'up' && event.direction !== 'down') return
151
- setOffset(clamp(clamped + (event.direction === 'up' ? -3 : 3)))
151
+ const next = clamp(clamped + (event.direction === 'up' ? -3 : 3))
152
+ if (next === clamped) return
153
+ setOffset(next)
152
154
  event.stopPropagation()
153
155
  })
154
156
 
package/src/focus.js CHANGED
@@ -79,13 +79,14 @@ export function useFocus({ initial, cycle = 'tab' } = {}) {
79
79
  return state.items.filter(i => i.gen === state.gen).sort((a, b) => a.seq - b.seq)
80
80
  }
81
81
 
82
- function item(name) {
82
+ function item(name, layout) {
83
83
  const existing = state.items.find(i => i.name === name)
84
84
  if (existing) {
85
85
  existing.gen = state.gen
86
86
  existing.seq = state.seq++
87
+ existing.layout = layout
87
88
  } else {
88
- state.items.push({ name, type: 'item', gen: state.gen, seq: state.seq++ })
89
+ state.items.push({ name, type: 'item', gen: state.gen, seq: state.seq++, layout })
89
90
  }
90
91
  if (state.current() == null) state.setCurrent(name)
91
92
  }
@@ -157,6 +158,11 @@ export function useFocus({ initial, cycle = 'tab' } = {}) {
157
158
  return state.current()
158
159
  }
159
160
 
161
+ function currentLayout() {
162
+ const name = state.current()
163
+ return state.items.find(i => i.name === name)?.layout ?? null
164
+ }
165
+
160
166
  function findTopLevel(cur, items) {
161
167
  const parent = state.nameToParent.get(cur)
162
168
  if (parent) return items.findIndex(i => i.name === parent)
@@ -220,5 +226,5 @@ export function useFocus({ initial, cycle = 'tab' } = {}) {
220
226
  }
221
227
  })
222
228
 
223
- return { item, group, is, focus, push, pop, current }
229
+ return { item, group, is, focus, push, pop, current, currentLayout }
224
230
  }
package/src/scroll-box.js CHANGED
@@ -2,7 +2,7 @@ import { jsx, jsxs } from '../jsx-runtime.js'
2
2
  import { createSignal } from './signal.js'
3
3
  import { useInput, useMouse, useLayout, useTheme, useScrollDrag } from './hooks.js'
4
4
 
5
- export function ScrollBox({ children, focused = true, scrollOffset: offsetProp, onScroll, scrollbar = false, gap = 0, thumbChar = '\u2588', trackChar = '\u2502', style: userStyle }) {
5
+ export function ScrollBox({ children, focused = true, followFocus, focusPadding = 0, scrollOffset: offsetProp, onScroll, scrollbar = false, gap = 0, thumbChar = '\u2588', trackChar = '\u2502', style: userStyle }) {
6
6
  const { accent = 'cyan', muted = 'gray' } = useTheme()
7
7
  const [offsetInternal, setOffsetInternal] = createSignal(0)
8
8
  const layout = useLayout()
@@ -22,6 +22,21 @@ export function ScrollBox({ children, focused = true, scrollOffset: offsetProp,
22
22
  const clamp = (v) => Math.max(0, Math.min(maxOffset, v))
23
23
  const clamped = clamp(offset)
24
24
 
25
+ if (followFocus) {
26
+ const target = typeof followFocus === 'function' ? followFocus() : followFocus.currentLayout?.()
27
+ if (target && visibleH > 0) {
28
+ const top = target.y - layout.y + clamped
29
+ const bottom = top + Math.max(1, target.height ?? 1)
30
+ const padding = Math.max(0, focusPadding)
31
+ const next = top < clamped + padding
32
+ ? top - padding
33
+ : bottom > clamped + visibleH - padding
34
+ ? bottom - visibleH + padding
35
+ : clamped
36
+ if (clamp(next) !== clamped) setOffset(next)
37
+ }
38
+ }
39
+
25
40
  useInput(({ key, ctrl }) => {
26
41
  if (!focused) return
27
42
  if (contentH <= visibleH) return