@kws3/ui 2.2.4 → 2.3.0

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/CHANGELOG.mdx CHANGED
@@ -1,3 +1,9 @@
1
+ # 2.3.0
2
+ - New component `InfiniteList` Added
3
+
4
+ # 2.2.5
5
+ - `ScrollableList` - bugfixes, and add support for removing items without affecting scroll position
6
+
1
7
  # 2.2.4
2
8
  - `ToggleButtons` - add support for count tags, and fix css not applying
3
9
 
@@ -0,0 +1,136 @@
1
+ <!--
2
+ @component
3
+
4
+
5
+ @param {array} [items=[]] - Array of items, Default: `[]`
6
+ @param {object} [iteration_key=null] - Iteration key - by default it uses the index of the array inside the keyed each block, Default: `null`
7
+ @param {string} [height="100%"] - Height of the wrapper, CSS String, Default: `"100%"`
8
+ @param {number} [end_offset=400] - `end` event will be fired when the scroll position reaches this many pixels from the end of the list., Default: `400`
9
+ @param {string} [style=""] - Inline CSS for scroller container, Default: `""`
10
+ @param {string} [class=""] - CSS classes for scroller container, Default: `""`
11
+
12
+ ### Events
13
+ - `end` - Fired when the scroll position reaches `end_offset` pixels from the end of the list.
14
+
15
+ ### Slots
16
+ - `<slot name="default" {item} {index} />` - Default slot for list view items
17
+ - `<slot name="loader" />` - Optional slot to display a loading graphic at the bottom of the list
18
+ while more items are loading
19
+
20
+ -->
21
+ {#if hasResizeObserver}
22
+ <div
23
+ bind:this={viewport}
24
+ class="kws-scrollable-list kws-infinite-list with-resize-observer {klass}"
25
+ on:scroll={handle_scroll}
26
+ style="height:{height};{style}"
27
+ use:resizeObserver
28
+ on:resize={resize}>
29
+ <div bind:this={contents}>
30
+ {#each visible as item (item.index)}
31
+ <div class="row">
32
+ <!--Default slot for list view items-->
33
+ <slot item={item.data} index={item.index} />
34
+ </div>
35
+ {/each}
36
+ <!--Optional slot to display a loading graphic at the bottom of the list
37
+ while more items are loading-->
38
+ <slot name="loader" />
39
+ </div>
40
+ </div>
41
+ {:else}
42
+ <div
43
+ bind:this={viewport}
44
+ class="kws-scrollable-list kws-infinite-list {klass}"
45
+ on:scroll={handle_scroll}
46
+ style="height:{height};{style}"
47
+ bind:offsetHeight={viewport_height}>
48
+ <div bind:this={contents}>
49
+ {#each visible as item (item.index)}
50
+ <div class="row">
51
+ <!--Default slot for list view items-->
52
+ <slot item={item.data} index={item.index} />
53
+ </div>
54
+ {/each}
55
+ <!--Optional slot to display a loading graphic at the bottom of the list
56
+ while more items are loading-->
57
+ <slot name="loader" />
58
+ </div>
59
+ </div>
60
+ {/if}
61
+
62
+ <style>
63
+ .kws-infinite-list {
64
+ overflow: auto;
65
+ -webkit-overflow-scrolling: touch;
66
+ position: relative;
67
+ height: 100%;
68
+ }
69
+ </style>
70
+
71
+ <script>
72
+ import { hasResizeObserver, resizeObserver } from "@kws3/ui/resizeObserver";
73
+ import { createEventDispatcher } from "svelte";
74
+
75
+ const fire = createEventDispatcher();
76
+ /**
77
+ * Array of items
78
+ */
79
+ export let items = [],
80
+ /**
81
+ * Iteration key - by default it uses the index of the array inside the keyed each block
82
+ */
83
+ iteration_key = null,
84
+ /**
85
+ * Height of the wrapper, CSS String
86
+ */
87
+ height = "100%",
88
+ /**
89
+ * `end` event will be fired when the scroll position reaches this many pixels from the end of the list.
90
+ */
91
+ end_offset = 400,
92
+ /**
93
+ * Inline CSS for scroller container
94
+ */
95
+ style = "";
96
+
97
+ /**
98
+ * CSS classes for scroller container
99
+ */
100
+ let klass = "";
101
+ export { klass as class };
102
+
103
+ // local state
104
+ let viewport,
105
+ contents,
106
+ viewport_height = 0,
107
+ visible,
108
+ fired = false;
109
+
110
+ $: visible = items.slice().map((data, i) => ({
111
+ index: iteration_key ? data[iteration_key] : i,
112
+ data,
113
+ }));
114
+
115
+ function handle_scroll() {
116
+ const { scrollTop, scrollHeight } = viewport;
117
+ let offset = scrollHeight - viewport_height - scrollTop;
118
+ // fire on:end event if we scrolled past the end_offset
119
+ if (offset <= end_offset) {
120
+ if (!fired) {
121
+ /**
122
+ * Fired when the scroll position reaches `end_offset` pixels from the end of the list.
123
+ */
124
+ fire("end");
125
+ }
126
+ fired = true;
127
+ } else {
128
+ fired = false;
129
+ }
130
+ }
131
+
132
+ const resize = () => {
133
+ viewport_height = viewport.offsetHeight;
134
+ handle_scroll();
135
+ };
136
+ </script>
@@ -10,6 +10,7 @@
10
10
  @param {number} [end=0] - Last item index rendered inside viewport - readonly, Default: `0`
11
11
  @param {number} [end_threshold=10] - `end` event will be fired when the list reaches this many items before the end of the list., Default: `10`
12
12
  @param {number} [padding_threshold=5] - render 'n' number of items on outside the viewport (top and bottom) to avoid visible glitches on scrolling., Default: `5`
13
+ @param {number} [mutation_threshold=5] - Number of items that can be spliced in or out, before the scroll position resets, helpful for adding/removing list items in-place, Default: `5`
13
14
  @param {string} [style=""] - Inline CSS for scroller container, Default: `""`
14
15
  @param {string} [class=""] - CSS classes for scroller container, Default: `""`
15
16
 
@@ -81,9 +82,8 @@ while more items are loading
81
82
  </style>
82
83
 
83
84
  <script>
84
- import { onMount, tick } from "svelte";
85
- import { createEventDispatcher } from "svelte";
86
- import { resizeObserver, hasResizeObserver } from "@kws3/ui/resizeObserver";
85
+ import { hasResizeObserver, resizeObserver } from "@kws3/ui/resizeObserver";
86
+ import { createEventDispatcher, onMount, tick } from "svelte";
87
87
 
88
88
  const fire = createEventDispatcher();
89
89
  /**
@@ -119,6 +119,10 @@ while more items are loading
119
119
  * render 'n' number of items on outside the viewport (top and bottom) to avoid visible glitches on scrolling.
120
120
  */
121
121
  padding_threshold = 5,
122
+ /**
123
+ * Number of items that can be spliced in or out, before the scroll position resets, helpful for adding/removing list items in-place
124
+ */
125
+ mutation_threshold = 5,
122
126
  /**
123
127
  * Inline CSS for scroller container
124
128
  */
@@ -191,15 +195,16 @@ while more items are loading
191
195
  const row_height = height_map[i] || average_height;
192
196
  if (y + row_height > scrollTop) {
193
197
  start = i;
194
- top =
195
- y > row_height * padding_threshold
196
- ? y - row_height * padding_threshold
197
- : y;
198
+ let rhpt = row_height * padding_threshold;
199
+ let diff = y - rhpt;
200
+ top = y > rhpt && diff > i ? diff : y;
198
201
  break;
199
202
  }
200
203
  y += row_height;
201
204
  i += 1;
202
205
  }
206
+ i = 0;
207
+ y = 0;
203
208
  while (i < items.length) {
204
209
  y += height_map[i] || average_height;
205
210
  i += 1;
@@ -210,6 +215,7 @@ while more items are loading
210
215
  average_height = y / end;
211
216
  while (i < items.length) height_map[i++] = average_height;
212
217
  bottom = remaining * average_height;
218
+
213
219
  // prevent jumping if we scrolled up into unknown territory
214
220
  if (start < old_start) {
215
221
  await tick();
@@ -249,7 +255,11 @@ while more items are loading
249
255
 
250
256
  function reset() {
251
257
  if (!mounted) return;
252
- if (!items.length || items.length < items_count) {
258
+ if (
259
+ !items.length ||
260
+ (items.length < items_count &&
261
+ items_count - items.length > mutation_threshold)
262
+ ) {
253
263
  item_height = null;
254
264
  start = 0;
255
265
  end = 0;
package/index.d.ts CHANGED
@@ -16,6 +16,7 @@ export { default as TimelineHeader } from "./helpers/Timeline/TimelineHeader.sve
16
16
  export { default as Nl2br } from "./helpers/Nl2br.svelte";
17
17
  export { default as ClipboardCopier } from "./helpers/ClipboardCopier.svelte";
18
18
  export { default as ScrollableList } from "./helpers/ScrollableList.svelte";
19
+ export { default as InfiniteList } from "./helpers/InfiniteList.svelte";
19
20
  export { default as FloatingUIOutput } from "./helpers/FloatingUI/FloatingUIOutput.svelte";
20
21
  export { default as Floatie } from "./helpers/FloatingUI/Floatie.svelte";
21
22
  export { default as ConfirmButton } from "./buttons/ConfirmButton.svelte";
package/index.js CHANGED
@@ -18,6 +18,7 @@ export { default as TimelineHeader } from "./helpers/Timeline/TimelineHeader.sve
18
18
  export { default as Nl2br } from "./helpers/Nl2br.svelte";
19
19
  export { default as ClipboardCopier } from "./helpers/ClipboardCopier.svelte";
20
20
  export { default as ScrollableList } from "./helpers/ScrollableList.svelte";
21
+ export { default as InfiniteList } from "./helpers/InfiniteList.svelte";
21
22
  export {
22
23
  alert,
23
24
  confirm,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kws3/ui",
3
- "version": "2.2.4",
3
+ "version": "2.3.0",
4
4
  "description": "UI components for use with Svelte v3 applications.",
5
5
  "main": "index.js",
6
6
  "svelte": "index.js",
@@ -35,5 +35,5 @@
35
35
  "devDependencies": {
36
36
  "typescript": "^5.0.4"
37
37
  },
38
- "gitHead": "5c19da7cfb0c75ceb4e6ec2822e0a84b26fe272b"
38
+ "gitHead": "85d7e7534391508f6376907b57142d2eba457d7e"
39
39
  }