intelliwaketssveltekitv25 1.0.21 → 1.0.22

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.
@@ -34,6 +34,8 @@
34
34
  let is_scrolling = false
35
35
  let is_refreshing = false
36
36
 
37
+ let previous_length = $state(0)
38
+
37
39
  let visible = $derived(
38
40
  items.slice(start, end).map((data, i) => ({
39
41
  index: i + start,
@@ -41,9 +43,44 @@
41
43
  }))
42
44
  )
43
45
 
44
- // whenever `items` changes, invalidate the current heightmap
46
+ // whenever `items` changes, reset if needed and refresh the window
45
47
  $effect(() => {
46
- if (mounted && !is_scrolling && !is_refreshing && viewport) {
48
+ if (!mounted || !viewport) return
49
+
50
+ const len = items.length
51
+
52
+ // list became empty → hard reset
53
+ if (len === 0) {
54
+ start = 0
55
+ end = 0
56
+ top = 0
57
+ bottom = 0
58
+ height_map = []
59
+ average_height = undefined
60
+ viewport.scrollTo(0, 0)
61
+ previous_length = len
62
+ return
63
+ }
64
+
65
+ // if the list shrank, or our window is now out of bounds, reset to top
66
+ if (
67
+ len < previous_length || // list shrank (likely filtering)
68
+ start >= len || // start is past end of list
69
+ end === 0 || // nothing visible
70
+ end > len // end beyond list
71
+ ) {
72
+ start = 0
73
+ end = 0
74
+ top = 0
75
+ bottom = 0
76
+ height_map = []
77
+ average_height = undefined
78
+ viewport.scrollTo(0, 0)
79
+ }
80
+
81
+ previous_length = len
82
+
83
+ if (!is_scrolling && !is_refreshing) {
47
84
  refresh(items, viewport_height, itemHeight)
48
85
  }
49
86
  })
@@ -80,7 +117,7 @@
80
117
  end = i
81
118
 
82
119
  const remaining = items.length - end
83
- average_height = Math.max((top + content_height) / end, min_row_height)
120
+ average_height = Math.round(Math.max((top + content_height) / end, min_row_height))
84
121
 
85
122
  bottom = remaining * average_height
86
123
  height_map.length = items.length
@@ -127,7 +164,7 @@
127
164
  end = i
128
165
 
129
166
  const remaining = items.length - end
130
- average_height = y / end
167
+ average_height = Math.round(y / end)
131
168
 
132
169
  while (i < items.length) height_map[i++] = average_height
133
170
  bottom = remaining * average_height
@@ -204,4 +241,4 @@
204
241
  .virtual-list-row {
205
242
  overflow: hidden;
206
243
  }
207
- </style>
244
+ </style>
@@ -33,7 +33,7 @@
33
33
  let height_map: number[] = $state([])
34
34
  let rows: HTMLCollectionOf<Element> | undefined = $state()
35
35
  let viewport: HTMLElement | undefined = $state()
36
- let contents: HTMLElement | undefined = $state()
36
+ let contents: HTMLTableElement | undefined = $state()
37
37
  let viewport_height = $state(0)
38
38
  let mounted = $state(false)
39
39
 
@@ -44,6 +44,8 @@
44
44
  let is_scrolling = false
45
45
  let is_refreshing = false
46
46
 
47
+ let previous_length = $state(0)
48
+
47
49
  let visible = $derived(
48
50
  items.slice(start, end).map((data, i) => ({
49
51
  index: i + start,
@@ -51,9 +53,44 @@
51
53
  }))
52
54
  )
53
55
 
54
- // whenever `items` changes, invalidate the current heightmap
56
+ // whenever `items` changes, reset if needed and refresh the window
55
57
  $effect(() => {
56
- if (mounted && !is_scrolling && !is_refreshing && viewport) {
58
+ if (!mounted || !viewport) return
59
+
60
+ const len = items.length
61
+
62
+ // list became empty → hard reset
63
+ if (len === 0) {
64
+ start = 0
65
+ end = 0
66
+ top = 0
67
+ bottom = 0
68
+ height_map = []
69
+ average_height = undefined
70
+ viewport.scrollTo(0, 0)
71
+ previous_length = len
72
+ return
73
+ }
74
+
75
+ // if the list shrank, or our window is now out of bounds, reset to top
76
+ if (
77
+ len < previous_length || // list shrank (likely filtering)
78
+ start >= len || // start is past end of list
79
+ end === 0 || // nothing visible
80
+ end > len // end beyond list
81
+ ) {
82
+ start = 0
83
+ end = 0
84
+ top = 0
85
+ bottom = 0
86
+ height_map = []
87
+ average_height = undefined
88
+ viewport.scrollTo(0, 0)
89
+ }
90
+
91
+ previous_length = len
92
+
93
+ if (!is_scrolling && !is_refreshing) {
57
94
  refresh(items, viewport_height, itemHeight)
58
95
  }
59
96
  })
@@ -119,7 +156,6 @@
119
156
  if (y + row_height > scrollTop) {
120
157
  start = i
121
158
  top = y
122
-
123
159
  break
124
160
  }
125
161
 
@@ -157,7 +193,9 @@
157
193
  }
158
194
 
159
195
  const d = actual_height - expected_height
160
- viewport.scrollTo(0, scrollTop + d)
196
+ if (d !== 0) {
197
+ viewport.scrollTo(0, scrollTop + d)
198
+ }
161
199
  }
162
200
 
163
201
  is_scrolling = false
@@ -188,10 +226,12 @@
188
226
  <tbody class="virtual-table-body">
189
227
  <tr class="virtual-table-spacer" style="height: {top}px;"></tr>
190
228
  {#each visible as item (item.index)}
191
- <tr class="virtual-table-row {classRow}"
192
- class:hover:bg-slate-100={!!onclick}
193
- class:cursor-pointer={!!onclick}
194
- onclick={(e) => onclick?.(item.data, item.index, e)}>
229
+ <tr
230
+ class="virtual-table-row {classRow}"
231
+ class:hover:bg-slate-100={!!onclick}
232
+ class:cursor-pointer={!!onclick}
233
+ onclick={(e) => onclick?.(item.data, item.index, e)}
234
+ >
195
235
  {@render tbody_tr(item.data, item.index)}
196
236
  </tr>
197
237
  {/each}
@@ -241,5 +281,4 @@
241
281
  .virtual-table-spacer {
242
282
  height: 0;
243
283
  }
244
-
245
- </style>
284
+ </style>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intelliwaketssveltekitv25",
3
- "version": "1.0.21",
3
+ "version": "1.0.22",
4
4
  "exports": {
5
5
  ".": {
6
6
  "types": "./dist/index.d.ts",