@kws3/ui 1.8.0 → 1.8.3

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,18 @@
1
+ ## 1.8.3
2
+ - Allow `clickableRows` and `bulk_actions` to work at the same time on `GridView`
3
+ - Various bugfixes on `GridRow`
4
+ - New `visualActivationOnClick` prop for `GridView` and `TileView`
5
+ - Change the way click activation works on `GridView` and `TileView` rows. Now only one row can be activated at a time
6
+
7
+ ## 1.8.2
8
+ - Usability fixes for `NumberInput`
9
+ - New `input_only`, `force_integer`, `style` and `class` props for `NumberInput`
10
+ - Forward `focus`, `blur` input events for `NumberInput`
11
+ - Use custom version of `fuzzysearch` for `SearchableSelect` and `MultiSelect`
12
+
13
+ ## 1.8.1
14
+ - New `ScrollableList` component
15
+
1
16
  ## 1.8.0
2
17
  - `Modal`, `CardModal` and `ActionSheet` components now play an outro transition instead of abruptly disappearing.
3
18
  - Usability fixes for `SearchableSelect` and `MultiSelect`.
@@ -20,52 +20,84 @@ This will be overridden if `min` is higher, or `max` is lower, Default: `0`
20
20
  @param {string} [plus_icon="plus"] - Name of the icon that is to be displayed in the plus button, Default: `"plus"`
21
21
  @param {''|'success'|'primary'|'warning'|'info'|'danger'|'dark'|'light'} [plus_icon_color="success"] - Color of the Plus Icon, Default: `"success"`
22
22
  @param {''|'success'|'primary'|'warning'|'info'|'danger'|'dark'|'light'} [plus_button_color=""] - Color of the Plus Button, Default: `""`
23
+ @param {boolean} [input_only=false] - Show input without controls, Default: `false`
24
+ @param {boolean} [force_integer=false] - Prevent decimal numbers such as `1.5`, Default: `false`
25
+ @param {string} [style=""] - Inline CSS for component, Default: `""`
26
+ @param {string} [class=""] - CSS classes for component, Default: `""`
23
27
 
24
28
  ### Events
25
29
  - `change` - Triggered when value changes
30
+ - `blur`
31
+ - `focus`
26
32
 
27
33
  -->
28
- <div class="field has-addons">
29
- <div class="control">
30
- <button
31
- type="button"
32
- class="button is-{size} is-{minus_button_color}"
33
- style="box-shadow:none;"
34
- on:click={count(-1)}
35
- disabled={disabled || value <= min}>
36
- <Icon
37
- icon={minus_icon}
38
- size="small"
39
- class="has-text-{minus_icon_color}" />
40
- </button>
34
+ {#if input_only}
35
+ <input
36
+ {style}
37
+ data-testid="input"
38
+ class="input has-text-centered {klass} is-{size} is-{value < min ||
39
+ value > max
40
+ ? 'danger'
41
+ : ''}"
42
+ type="number"
43
+ min
44
+ max
45
+ {step}
46
+ {disabled}
47
+ readonly={!typeable}
48
+ bind:value
49
+ on:blur={isBlurred}
50
+ on:blur
51
+ on:focus={isFocused}
52
+ on:focus />
53
+ {:else}
54
+ <div class="field has-addons {klass}" {style}>
55
+ <div class="control">
56
+ <button
57
+ type="button"
58
+ class="button is-{size} is-{minus_button_color}"
59
+ style="box-shadow:none;"
60
+ on:click={count(-1)}
61
+ disabled={disabled || value <= min}>
62
+ <Icon
63
+ icon={minus_icon}
64
+ size="small"
65
+ class="has-text-{minus_icon_color}" />
66
+ </button>
67
+ </div>
68
+ <div class="control is-{fullwidth ? 'expanded' : 'narrow'}">
69
+ <input
70
+ data-testid="input"
71
+ class="input has-text-centered is-{size} is-{value < min || value > max
72
+ ? 'danger'
73
+ : ''}"
74
+ type="number"
75
+ min
76
+ max
77
+ {step}
78
+ {disabled}
79
+ readonly={!typeable}
80
+ bind:value
81
+ on:blur={isBlurred}
82
+ on:blur
83
+ on:focus={isFocused}
84
+ on:focus />
85
+ </div>
86
+ <div class="control">
87
+ <button
88
+ type="button"
89
+ class="button is-{size} is-{plus_button_color}"
90
+ style="box-shadow:none;"
91
+ on:click|preventDefault={count(+1)}
92
+ disabled={disabled || value >= max}>
93
+ <Icon
94
+ icon={plus_icon}
95
+ size="small"
96
+ class="has-text-{plus_icon_color}" />
97
+ </button>
98
+ </div>
41
99
  </div>
42
- <div class="control is-{fullwidth ? 'expanded' : 'narrow'}">
43
- <input
44
- data-testid="input"
45
- class="input has-text-centered is-{size} is-{value < min || value > max
46
- ? 'danger'
47
- : ''}"
48
- type="number"
49
- min
50
- max
51
- step
52
- {disabled}
53
- readonly={!typeable}
54
- bind:value
55
- on:blur={isBlurred()}
56
- on:focus={isFocused()} />
57
- </div>
58
- <div class="control">
59
- <button
60
- type="button"
61
- class="button is-{size} is-{plus_button_color}"
62
- style="box-shadow:none;"
63
- on:click|preventDefault={count(+1)}
64
- disabled={disabled || value >= max}>
65
- <Icon icon={plus_icon} size="small" class="has-text-{plus_icon_color}" />
66
- </button>
67
- </div>
68
- </div>
100
+ {/if}
69
101
 
70
102
  <style>
71
103
  input[type="number"]::-webkit-inner-spin-button,
@@ -158,7 +190,25 @@ This will be overridden if `min` is higher, or `max` is lower, Default: `0`
158
190
  * Color of the Plus Button
159
191
  * @type {''|'success'|'primary'|'warning'|'info'|'danger'|'dark'|'light'}
160
192
  */
161
- plus_button_color = "";
193
+ plus_button_color = "",
194
+ /**
195
+ * Show input without controls
196
+ */
197
+ input_only = false,
198
+ /**
199
+ * Prevent decimal numbers such as `1.5`
200
+ */
201
+ force_integer = false,
202
+ /**
203
+ * Inline CSS for component
204
+ */
205
+ style = "";
206
+
207
+ /**
208
+ * CSS classes for component
209
+ */
210
+ let klass = "";
211
+ export { klass as class };
162
212
 
163
213
  let _has_focus = false,
164
214
  _old_value = null;
@@ -189,6 +239,8 @@ This will be overridden if `min` is higher, or `max` is lower, Default: `0`
189
239
 
190
240
  if (typeof value == "undefined" || value === null) value = min;
191
241
 
242
+ if (force_integer) value = Math.floor(Number(value));
243
+
192
244
  if (value < min) value = min;
193
245
  if (value > max) value = max;
194
246
 
@@ -4,7 +4,8 @@
4
4
 
5
5
  @param {number} [row_index=0] - Row index value, Default: `0`
6
6
  @param {object} [row={}] - Contains all the column values in a row, Default: `{}`
7
- @param {boolean} [rowActive=false] - Determines whether the row is selected or not, Default: `false`
7
+ @param {boolean} [visualActivationOnClick=true] - Determines whether clickable rows activate visually on click, Default: `true`
8
+ @param {object} [activatedId=null] - Unique id of row that is activated, Default: `null`
8
9
  @param {object} [isVisible={}] - Determines whether column is visible or not, Default: `{}`
9
10
  @param {boolean} [clickableRows=false] - Determines whether the row is clickable or not, Default: `false`
10
11
  @param {object} [transforms={}] - Contains all custom values for each columns, Default: `{}`
@@ -29,10 +30,14 @@
29
30
  <tr
30
31
  in:fly={{ x: 20, delay: 25 * row_index }}
31
32
  on:click|stopPropagation={rowClick}
32
- class:is-selected={rowActive}
33
+ class:is-selected={activated && visualActivationOnClick}
33
34
  class:is-checked={checked}>
34
35
  {#if bulk_actions}
35
- <td style="vertical-align:middle;">
36
+ <td
37
+ style="vertical-align:middle;"
38
+ on:click={(e) => {
39
+ clickableRows && e.stopImmediatePropagation();
40
+ }}>
36
41
  <Checkbox
37
42
  size={selectCheckboxSize}
38
43
  color={selectCheckboxColor}
@@ -58,7 +63,7 @@
58
63
  {:else}
59
64
  <tr
60
65
  on:click|stopPropagation={rowClick}
61
- class:is-selected={rowActive}
66
+ class:is-selected={activated && visualActivationOnClick}
62
67
  class:is-checked={checked}>
63
68
  {#if bulk_actions}
64
69
  <td style="vertical-align:middle;">
@@ -103,9 +108,13 @@
103
108
  */
104
109
  row = {},
105
110
  /**
106
- * Determines whether the row is selected or not
111
+ * Determines whether clickable rows activate visually on click
112
+ */
113
+ visualActivationOnClick = true,
114
+ /**
115
+ * Unique id of row that is activated
107
116
  */
108
- rowActive = false,
117
+ activatedId = null,
109
118
  /**
110
119
  * Determines whether column is visible or not
111
120
  */
@@ -161,6 +170,7 @@
161
170
  };
162
171
 
163
172
  $: selectedIds, setCheckedValue();
173
+ $: activated = activatedId === row.id;
164
174
 
165
175
  function setCheckedValue() {
166
176
  checked = false;
@@ -175,7 +185,6 @@
175
185
 
176
186
  function rowClick() {
177
187
  if (clickableRows) {
178
- rowActive = true;
179
188
  fire("rowClick", { row });
180
189
  }
181
190
  }
@@ -5,9 +5,11 @@
5
5
  @param {string} [iteration_key="id"] - Iteration key, Default: `"id"`
6
6
  @param {array} [data=[]] - Contains all the results that needs to be displayed, Default: `[]`
7
7
  @param {object} [columns={}] - Table column names. {db_field_name: column_name}, Default: `{}`
8
- @param {boolean} [transition=false] - Determines if a transision effect is used, Default: `false`
8
+ @param {boolean} [transition=false] - Determines if a transition effect is used, Default: `false`
9
9
  @param {boolean} [is_striped=true] - Determines whether to use alternating row shading in the table view, Default: `true`
10
+ @param {boolean} [visualActivationOnClick=true] - Determines whether clickable rows activate visually on click, Default: `true`
10
11
  @param {boolean} [clickableRows=false] - Determines whether rows are clickable or not, Default: `false`
12
+ @param {object} [activatedId=null] - Unique id of row that is activated, Default: `null`
11
13
  @param {boolean} [bulk_actions=false] - Determines if selecting multiple rows and doing multiple actions is allowed, Default: `false`
12
14
  @param {boolean} [selectAll=false] - Determines if all rows are selected, Default: `false`
13
15
  @param {array} [selectedIds=[]] - List of unique IDs of all the selected rows, Default: `[]`
@@ -64,6 +66,7 @@
64
66
  {transition}
65
67
  {column_keys}
66
68
  {clickableRows}
69
+ {visualActivationOnClick}
67
70
  {isVisible}
68
71
  {transforms}
69
72
  {classNames}
@@ -71,6 +74,7 @@
71
74
  {cellComponent}
72
75
  {row}
73
76
  {bulk_actions}
77
+ {activatedId}
74
78
  {selectedIds}
75
79
  {selectCheckboxColor}
76
80
  {selectCheckboxSize}
@@ -100,7 +104,7 @@
100
104
  */
101
105
  columns = {},
102
106
  /**
103
- * Determines if a transision effect is used
107
+ * Determines if a transition effect is used
104
108
  */
105
109
  transition = false,
106
110
  /**
@@ -108,10 +112,18 @@
108
112
  * @link https://bulma.io/documentation/elements/table/#modifiers
109
113
  */
110
114
  is_striped = true,
115
+ /**
116
+ * Determines whether clickable rows activate visually on click
117
+ */
118
+ visualActivationOnClick = true,
111
119
  /**
112
120
  * Determines whether rows are clickable or not
113
121
  */
114
122
  clickableRows = false,
123
+ /**
124
+ * Unique id of row that is activated
125
+ */
126
+ activatedId = null,
115
127
  /**
116
128
  * Determines if selecting multiple rows and doing multiple actions is allowed
117
129
  */
@@ -8,7 +8,9 @@
8
8
  @param {object} [tileItemComponent=null] - Contains a custom component, Default: `null`
9
9
  @param {number} [per_row=3] - Sets how many items to display in a row, Default: `3`
10
10
  @param {object} [columns={}] - Column names for the displayed table {db_field_name: column_name}, Default: `{}`
11
+ @param {boolean} [visualActivationOnClick=true] - Determines whether clickable rows activate visually on click, Default: `true`
11
12
  @param {boolean} [clickableRows=false] - Determines whether rows are clickable or not, Default: `false`
13
+ @param {object} [activatedId=null] - Unique id of row that is activated, Default: `null`
12
14
  @param {object} [valueTransformers={}] - Contains all custom values for each column, Default: `{}`
13
15
  @param {object} [classTransformers={}] - CSS class names for each column, Default: `{}`
14
16
  @param {object} [styleTransformers={}] - CSS styles for each column, Default: `{}`
@@ -31,6 +33,7 @@
31
33
  on:_forwardEvent
32
34
  {row_index}
33
35
  {column_keys}
36
+ {visualActivationOnClick}
34
37
  {clickableRows}
35
38
  {isVisible}
36
39
  {transforms}
@@ -38,6 +41,7 @@
38
41
  {styles}
39
42
  {row}
40
43
  {bulk_actions}
44
+ {activatedId}
41
45
  {selectedIds}
42
46
  {selectCheckboxColor}
43
47
  {selectCheckboxSize}
@@ -75,10 +79,18 @@
75
79
  * Column names for the displayed table {db_field_name: column_name}
76
80
  */
77
81
  columns = {},
82
+ /**
83
+ * Determines whether clickable rows activate visually on click
84
+ */
85
+ visualActivationOnClick = true,
78
86
  /**
79
87
  * Determines whether rows are clickable or not
80
88
  */
81
89
  clickableRows = false,
90
+ /**
91
+ * Unique id of row that is activated
92
+ */
93
+ activatedId = null,
82
94
  /**
83
95
  * Contains all custom values for each column
84
96
  */
@@ -3,7 +3,8 @@
3
3
 
4
4
 
5
5
  @param {object} [row={}] - List of all values in a row, Default: `{}`
6
- @param {boolean} [rowActive=false] - Determines whether the row is selected or not, Default: `false`
6
+ @param {boolean} [visualActivationOnClick=true] - Determines whether clickable rows activate visually on click, Default: `true`
7
+ @param {object} [activatedId=null] - Unique id of row that is activated, Default: `null`
7
8
  @param {boolean} [clickableRows=false] - Determines whether the row is clickable or not, Default: `false`
8
9
  @param {function} [isVisible()] - Returns whether a column can be visible or not
9
10
  @param {function} [transforms()] - Returns column custom value
@@ -16,7 +17,7 @@
16
17
 
17
18
  -->
18
19
  <div
19
- class:is-selected={rowActive}
20
+ class:is-selected={activated && visualActivationOnClick}
20
21
  class="box {clickableRows ? 'is-hoverable' : ''}"
21
22
  on:click|stopPropagation={rowClick}>
22
23
  {#each column_keys as column}
@@ -39,9 +40,13 @@
39
40
  */
40
41
  export let row = {},
41
42
  /**
42
- * Determines whether the row is selected or not
43
+ * Determines whether clickable rows activate visually on click
43
44
  */
44
- rowActive = false,
45
+ visualActivationOnClick = true,
46
+ /**
47
+ * Unique id of row that is activated
48
+ */
49
+ activatedId = null,
45
50
  /**
46
51
  * Determines whether the row is clickable or not
47
52
  */
@@ -67,9 +72,10 @@
67
72
  */
68
73
  column_keys = [];
69
74
 
75
+ $: activated = activatedId === row.id;
76
+
70
77
  function rowClick() {
71
78
  if (clickableRows) {
72
- rowActive = true;
73
79
  /**
74
80
  * Fires an event when a row is clicked
75
81
  */
@@ -160,7 +160,7 @@ Default value: `<span>{option[search_key] || option}</span>`
160
160
  import { debounce } from "@kws3/ui/utils";
161
161
  import { createEventDispatcher, onMount, tick } from "svelte";
162
162
  import { createPopper } from "@popperjs/core";
163
- import fuzzysearch from "fuzzysearch";
163
+ import fuzzysearch from "@kws3/ui/utils/fuzzysearch";
164
164
 
165
165
  const sameWidthPopperModifier = {
166
166
  name: "sameWidth",
@@ -0,0 +1,231 @@
1
+ <!--
2
+ @component
3
+
4
+
5
+ @param {array} [items=[]] - Array of items, Default: `[]`
6
+ @param {string} [height="100%"] - Height of the wrapper, CSS String, Default: `"100%"`
7
+ @param {number | null} [item_height=null] - Height of each list item. If not set, height will be calculated automatically based on each item's offsetHeight, Default: `null`
8
+ @param {number} [start=0] - First item index rendered inside viewport - readonly, Default: `0`
9
+ @param {number} [end=0] - Last item index rendered inside viewport - readonly, Default: `0`
10
+ @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`
11
+ @param {string} [style=""] - Inline CSS for scroller container, Default: `""`
12
+ @param {string} [class=""] - CSS classes for scroller container, Default: `""`
13
+
14
+ ### Events
15
+ - `end` - Fired when the list reaches `end_threshold` items before the end of the list.
16
+
17
+ ### Slots
18
+ - `<slot name="default" {item} {index} />` - Default slot for list view items
19
+ - `<slot name="loader" />` - Optional slot to display a loading graphic at the bottom of the list
20
+ while more items are loading
21
+
22
+ -->
23
+ {#if hasResizeObserver}
24
+ <div
25
+ bind:this={viewport}
26
+ class="kws-scrollable-list with-resize-observer {klass}"
27
+ on:scroll={handle_scroll}
28
+ style="height:{height};{style}"
29
+ use:resizeObserver
30
+ on:resize={resize}>
31
+ <div
32
+ bind:this={contents}
33
+ style="padding-top: {top}px; padding-bottom: {bottom}px;">
34
+ {#each visible as item (item.index)}
35
+ <div class="row">
36
+ <!--Default slot for list view items-->
37
+ <slot item={item.data} index={item.index} />
38
+ </div>
39
+ {/each}
40
+ <!--Optional slot to display a loading graphic at the bottom of the list
41
+ while more items are loading-->
42
+ <slot name="loader" />
43
+ </div>
44
+ </div>
45
+ {:else}
46
+ <div
47
+ bind:this={viewport}
48
+ class="kws-scrollable-list {klass}"
49
+ on:scroll={handle_scroll}
50
+ style="height:{height};{style}"
51
+ bind:offsetHeight={viewport_height}>
52
+ <div
53
+ bind:this={contents}
54
+ style="padding-top: {top}px; padding-bottom: {bottom}px;">
55
+ {#each visible as item (item.index)}
56
+ <div class="row">
57
+ <!--Default slot for list view items-->
58
+ <slot item={item.data} index={item.index} />
59
+ </div>
60
+ {/each}
61
+ <!--Optional slot to display a loading graphic at the bottom of the list
62
+ while more items are loading-->
63
+ <slot name="loader" />
64
+ </div>
65
+ </div>
66
+ {/if}
67
+
68
+ <style>
69
+ .kws-scrollable-list {
70
+ overflow: auto;
71
+ -webkit-overflow-scrolling: touch;
72
+ position: relative;
73
+ height: 100%;
74
+ }
75
+ </style>
76
+
77
+ <script>
78
+ import { onMount, tick } from "svelte";
79
+ import { createEventDispatcher } from "svelte";
80
+ import {
81
+ resizeObserver,
82
+ hasResizeObserver,
83
+ } from "@kws3/ui/utils/resizeObserver";
84
+
85
+ const fire = createEventDispatcher();
86
+ /**
87
+ * Array of items
88
+ */
89
+ export let items = [],
90
+ /**
91
+ * Height of the wrapper, CSS String
92
+ */
93
+ height = "100%",
94
+ /**
95
+ * Height of each list item. If not set, height will be calculated automatically based on each item's offsetHeight
96
+ * @type {number | null}
97
+ */
98
+ item_height = null,
99
+ /**
100
+ * First item index rendered inside viewport - readonly
101
+ */
102
+ start = 0,
103
+ /**
104
+ * Last item index rendered inside viewport - readonly
105
+ */
106
+ end = 0,
107
+ /**
108
+ * `end` event will be fired when the list reaches this many items before the end of the list.
109
+ */
110
+ end_threshold = 10,
111
+ /**
112
+ * Inline CSS for scroller container
113
+ */
114
+ style = "";
115
+
116
+ /**
117
+ * CSS classes for scroller container
118
+ */
119
+ let klass = "";
120
+ export { klass as class };
121
+
122
+ // local state
123
+ let height_map = [],
124
+ rows,
125
+ viewport,
126
+ contents,
127
+ viewport_height = 0,
128
+ visible,
129
+ mounted,
130
+ top = 0,
131
+ bottom = 0,
132
+ average_height,
133
+ items_count = 0;
134
+
135
+ $: visible = items.slice(start, end).map((data, i) => {
136
+ return { index: i + start, data };
137
+ });
138
+
139
+ // whenever `items` changes, invalidate the current heightmap
140
+ $: items, viewport_height, item_height, mounted, refresh();
141
+
142
+ async function refresh() {
143
+ if (!mounted) return;
144
+ const scrollTop = viewport.scrollTop;
145
+ await tick(); // wait until the DOM is up to date
146
+ let content_height = top - scrollTop;
147
+ let i = start;
148
+ while (content_height < viewport_height && i < items.length) {
149
+ let row = rows[i - start];
150
+ if (!row) {
151
+ end = i + 1;
152
+ await tick(); // render the newly visible row
153
+ row = rows[i - start];
154
+ }
155
+ const row_height = (height_map[i] =
156
+ item_height || (row ? row.offsetHeight : 0));
157
+ content_height += row_height;
158
+ i += 1;
159
+ }
160
+ end = i;
161
+ const remaining = items.length - end;
162
+ average_height = (top + content_height) / end;
163
+ bottom = remaining * average_height;
164
+ height_map.length = items.length;
165
+ }
166
+
167
+ async function handle_scroll() {
168
+ const scrollTop = viewport.scrollTop;
169
+ const old_start = start;
170
+ for (let v = 0; v < rows.length; v += 1) {
171
+ height_map[start + v] = item_height || rows[v].offsetHeight;
172
+ }
173
+ let i = 0;
174
+ let y = 0;
175
+ while (i < items.length) {
176
+ const row_height = height_map[i] || average_height;
177
+ if (y + row_height > scrollTop) {
178
+ start = i;
179
+ top = y;
180
+ break;
181
+ }
182
+ y += row_height;
183
+ i += 1;
184
+ }
185
+ while (i < items.length) {
186
+ y += height_map[i] || average_height;
187
+ i += 1;
188
+ if (y > scrollTop + viewport_height) break;
189
+ }
190
+ end = i;
191
+ const remaining = items.length - end;
192
+ average_height = y / end;
193
+ while (i < items.length) height_map[i++] = average_height;
194
+ bottom = remaining * average_height;
195
+ // prevent jumping if we scrolled up into unknown territory
196
+ if (start < old_start) {
197
+ await tick();
198
+ let expected_height = 0;
199
+ let actual_height = 0;
200
+ for (let i = start; i < old_start; i += 1) {
201
+ if (rows[i - start]) {
202
+ expected_height += height_map[i];
203
+ actual_height += item_height || rows[i - start].offsetHeight;
204
+ }
205
+ }
206
+ const d = actual_height - expected_height;
207
+ viewport.scrollTo(0, scrollTop + d);
208
+ }
209
+ // fire on:end event if we scrolled past the end of the list
210
+ if (end > items.length - end_threshold) {
211
+ if (items_count !== items.length) {
212
+ items_count = items.length;
213
+ await tick();
214
+ /**
215
+ * Fired when the list reaches `end_threshold` items before the end of the list.
216
+ */
217
+ fire("end", { start, end });
218
+ }
219
+ }
220
+ }
221
+
222
+ const resize = () => {
223
+ viewport_height = viewport.offsetHeight;
224
+ };
225
+
226
+ // trigger initial refresh
227
+ onMount(() => {
228
+ rows = contents.getElementsByClassName("row");
229
+ mounted = true;
230
+ });
231
+ </script>
package/index.js CHANGED
@@ -17,6 +17,7 @@ export { default as TimelineItem } from "./helpers/Timeline/TimelineItem.svelte"
17
17
  export { default as TimelineHeader } from "./helpers/Timeline/TimelineHeader.svelte";
18
18
  export { default as Nl2br } from "./helpers/Nl2br.svelte";
19
19
  export { default as ClipboardCopier } from "./helpers/ClipboardCopier.svelte";
20
+ export { default as ScrollableList } from "./helpers/ScrollableList.svelte";
20
21
  export { alert, confirm, prompt, default as Dialog } from "./helpers/Dialog";
21
22
  export {
22
23
  Notifications,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kws3/ui",
3
- "version": "1.8.0",
3
+ "version": "1.8.3",
4
4
  "description": "UI components for use with Svelte v3 applications.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -25,10 +25,9 @@
25
25
  "dependencies": {
26
26
  "apexcharts": "3.33.2",
27
27
  "flatpickr": "^4.5.2",
28
- "fuzzysearch": "^1.0.3",
29
28
  "svelte-portal": "^2.1.2",
30
29
  "text-mask-core": "^5.1.2",
31
30
  "tippy.js": "^6.3.1"
32
31
  },
33
- "gitHead": "8da0698c240f93ae1b371a9279d2473409646b10"
32
+ "gitHead": "b211043d95c9b0f3e4184624ccd84b0a99687e50"
34
33
  }
@@ -25,6 +25,8 @@ This will work only when `track_height` is set to `true`
25
25
  : ''} {h_center ? 'h-centered' : ''} {active ? 'is-active' : ''} {klass}"
26
26
  {style}>
27
27
  <div
28
+ use:resizeObserver
29
+ on:resize={debouncedFireSizeChange}
28
30
  bind:this={slideInner}
29
31
  class="sliding-pane-inner {v_center ? 'v-centered' : ''} {h_center
30
32
  ? 'h-centered'
@@ -52,6 +54,10 @@ This will work only when `track_height` is set to `true`
52
54
  <script>
53
55
  import { onMount, createEventDispatcher } from "svelte";
54
56
  import { debounce } from "@kws3/ui/utils";
57
+ import {
58
+ resizeObserver,
59
+ hasResizeObserver,
60
+ } from "@kws3/ui/utils/resizeObserver";
55
61
 
56
62
  const fire = createEventDispatcher();
57
63
 
@@ -76,8 +82,7 @@ This will work only when `track_height` is set to `true`
76
82
  */
77
83
  track_height = true;
78
84
 
79
- const hasResizeObserver = typeof window.ResizeObserver != "undefined";
80
- let _height, slideInner, Observer;
85
+ let _height, slideInner;
81
86
 
82
87
  /**
83
88
  * CSS classes for the panel
@@ -91,18 +96,22 @@ This will work only when `track_height` is set to `true`
91
96
  }
92
97
  }
93
98
 
99
+ const max_retries_for_render = 10;
100
+ let try_count = 0;
94
101
  function pollForRender() {
95
102
  if (slideInner && typeof slideInner != "undefined") {
96
103
  init();
97
104
  } else {
98
105
  setTimeout(() => {
99
- pollForRender();
106
+ try_count++;
107
+ if (try_count < max_retries_for_render) {
108
+ pollForRender();
109
+ }
100
110
  }, 50);
101
111
  }
102
112
  }
103
113
 
104
114
  function init() {
105
- setupResizeObserver();
106
115
  fireSizeChange();
107
116
  }
108
117
 
@@ -129,23 +138,7 @@ This will work only when `track_height` is set to `true`
129
138
 
130
139
  const debouncedFireSizeChange = debounce(fireSizeChange, 150, false);
131
140
 
132
- const setupResizeObserver = () => {
133
- if (hasResizeObserver) {
134
- if (!slideInner || typeof slideInner == "undefined") {
135
- pollForRender();
136
- } else {
137
- Observer = new ResizeObserver(() => {
138
- debouncedFireSizeChange();
139
- });
140
- Observer.observe(slideInner);
141
- }
142
- }
143
- };
144
-
145
141
  onMount(() => {
146
142
  pollForRender();
147
- return () => {
148
- Observer && Observer.disconnect();
149
- };
150
143
  });
151
144
  </script>
package/styles/Grid.scss CHANGED
@@ -51,6 +51,7 @@ $kws-gridview-checked-row-background: $primary-light !default;
51
51
  background-color: $kws-gridview-checked-row-background !important;
52
52
  td {
53
53
  background-color: $kws-gridview-checked-row-background !important;
54
+ color: findColorInvert($kws-gridview-checked-row-background) !important;
54
55
  }
55
56
  }
56
57
  }
@@ -0,0 +1,20 @@
1
+ export default function fuzzysearch(needle, haystack) {
2
+ var tlen = haystack.length;
3
+ var qlen = needle.length;
4
+ if (qlen > tlen) {
5
+ return false;
6
+ }
7
+ if (qlen === tlen) {
8
+ return needle === haystack;
9
+ }
10
+ outer: for (var i = 0, j = 0; i < qlen; i++) {
11
+ var nch = needle.charCodeAt(i);
12
+ while (j < tlen) {
13
+ if (haystack.charCodeAt(j++) === nch) {
14
+ continue outer;
15
+ }
16
+ }
17
+ return false;
18
+ }
19
+ return true;
20
+ }
@@ -0,0 +1,24 @@
1
+ export const hasResizeObserver = typeof window.ResizeObserver != "undefined";
2
+
3
+ /**
4
+ * Usage: `<div use:resizeObserver on:resize={resizeHandler}>`
5
+ * @param {HTMLElement} node
6
+ * @returns {Object}
7
+ */
8
+ export function resizeObserver(node) {
9
+ let ro;
10
+ if (hasResizeObserver) {
11
+ ro = new ResizeObserver(() => {
12
+ const e = new CustomEvent("resize", { bubbles: false });
13
+ node.dispatchEvent(e);
14
+ });
15
+
16
+ ro.observe(node);
17
+ }
18
+
19
+ return {
20
+ destroy() {
21
+ hasResizeObserver && ro.disconnect();
22
+ },
23
+ };
24
+ }