noph-ui 0.24.11 → 0.24.12

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.
@@ -74,6 +74,33 @@
74
74
  if (activeIndex >= displayOptions.length) {
75
75
  activeIndex = -1
76
76
  }
77
+
78
+ if (menuOpen && activeIndex >= 0) {
79
+ const id = `${uid}-opt-${activeIndex}`
80
+ const optEl = document.getElementById(id)
81
+ if (optEl) {
82
+ optEl.scrollIntoView({ block: 'nearest' })
83
+ } else if (useVirtualList && menuElement) {
84
+ const viewport = menuElement.querySelector(
85
+ 'svelte-virtual-list-viewport',
86
+ ) as HTMLElement | null
87
+ if (viewport) {
88
+ let rowHeight = 48
89
+ const firstRow = viewport.querySelector('[id^="' + uid + '-opt-"]') as HTMLElement | null
90
+ if (firstRow) {
91
+ rowHeight = firstRow.offsetHeight || rowHeight
92
+ }
93
+ const top = activeIndex * rowHeight
94
+ const bottom = top + rowHeight
95
+ const { scrollTop, clientHeight } = viewport
96
+ if (top < scrollTop) {
97
+ viewport.scrollTop = top
98
+ } else if (bottom > scrollTop + clientHeight) {
99
+ viewport.scrollTop = bottom - clientHeight
100
+ }
101
+ }
102
+ }
103
+ }
77
104
  })
78
105
  </script>
79
106
 
@@ -83,6 +110,7 @@
83
110
  softFocus={index === activeIndex}
84
111
  aria-selected={index === activeIndex}
85
112
  role="option"
113
+ tabindex={-1}
86
114
  onmousedown={(e) => {
87
115
  e.preventDefault()
88
116
  }}
@@ -165,7 +165,28 @@
165
165
  focusIndex = Math.min(Math.max(index, 0), options.length - 1)
166
166
  await tick()
167
167
  const el = document.getElementById(`${uid}-opt-${focusIndex}`)
168
- ;(el as HTMLElement | null)?.focus?.()
168
+ if (el) {
169
+ el.focus()
170
+ } else if (useVirtualList && menuElement) {
171
+ const viewport = menuElement.querySelector(
172
+ 'svelte-virtual-list-viewport',
173
+ ) as HTMLElement | null
174
+ if (viewport) {
175
+ let rowHeight = 48
176
+ const firstRow = viewport.querySelector('[id^="' + uid + '-opt-"]') as HTMLElement | null
177
+ if (firstRow) {
178
+ rowHeight = firstRow.offsetHeight || rowHeight
179
+ }
180
+ const top = focusIndex * rowHeight
181
+ const bottom = top + rowHeight
182
+ const { scrollTop, clientHeight } = viewport
183
+ if (top < scrollTop) {
184
+ viewport.scrollTop = top
185
+ } else if (bottom > scrollTop + clientHeight) {
186
+ viewport.scrollTop = bottom - clientHeight
187
+ }
188
+ }
189
+ }
169
190
  }
170
191
 
171
192
  const moveFocus = (delta: number) => {
@@ -572,9 +593,6 @@
572
593
  }
573
594
  if (idx < 0) idx = 0
574
595
  focusIndex = idx
575
- await tick()
576
- const el = document.getElementById(`${uid}-opt-${focusIndex}`)
577
- ;(el as HTMLElement | null)?.focus?.()
578
596
  } else {
579
597
  menuOpen = false
580
598
  focusIndex = -1
@@ -583,7 +601,17 @@
583
601
  bind:element={menuElement}
584
602
  >
585
603
  {#if useVirtualList}
586
- <VirtualList height="250px" itemHeight={48} items={options}>
604
+ <VirtualList
605
+ height="250px"
606
+ itemHeight={48}
607
+ items={options}
608
+ rendered={({ start, end }) => {
609
+ if (focusIndex >= start && focusIndex < end) {
610
+ const el = document.getElementById(`${uid}-opt-${focusIndex}`)
611
+ el?.focus()
612
+ }
613
+ }}
614
+ >
587
615
  {#snippet row(option, index)}
588
616
  {@render item(option, index)}
589
617
  {/snippet}
@@ -10,6 +10,7 @@
10
10
  end?: number
11
11
  row: Snippet<[T, number]>
12
12
  overscan?: number
13
+ rendered?: (event: { start: number; end: number }) => void
13
14
  }
14
15
 
15
16
  let {
@@ -19,7 +20,8 @@
19
20
  start = $bindable(0),
20
21
  end = $bindable(0),
21
22
  row,
22
- overscan = 4,
23
+ overscan = 0,
24
+ rendered,
23
25
  }: VirtualListProps = $props()
24
26
 
25
27
  let height_map: number[] = []
@@ -79,6 +81,8 @@
79
81
 
80
82
  bottom = remaining * average_height
81
83
  height_map.length = items.length
84
+
85
+ rendered?.({ start, end })
82
86
  }
83
87
 
84
88
  async function handle_scroll() {
@@ -151,6 +155,8 @@
151
155
  const d = actual_height - expected_height
152
156
  viewport.scrollTo(0, scrollTop + d)
153
157
  }
158
+ await tick()
159
+ rendered?.({ start, end })
154
160
  }
155
161
 
156
162
  onMount(() => {
@@ -9,6 +9,10 @@ declare function $$render<T>(): {
9
9
  end?: number;
10
10
  row: Snippet<[T, number]>;
11
11
  overscan?: number;
12
+ rendered?: (event: {
13
+ start: number;
14
+ end: number;
15
+ }) => void;
12
16
  };
13
17
  exports: {};
14
18
  bindings: "start" | "end";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "noph-ui",
3
- "version": "0.24.11",
3
+ "version": "0.24.12",
4
4
  "license": "MIT",
5
5
  "homepage": "https://noph.dev",
6
6
  "repository": {