@kws3/ui 1.9.3 → 2.0.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 +68 -48
- package/buttons/ConfirmButton.svelte +11 -3
- package/buttons/DeleteButton.svelte +2 -3
- package/buttons/ProcessButton.svelte +3 -4
- package/buttons/SubmitButton.svelte +11 -3
- package/charts/AreaChart.svelte +1 -1
- package/charts/BarChart.svelte +1 -1
- package/charts/Chart.svelte +1 -0
- package/charts/DonutChart.svelte +1 -1
- package/charts/LineChart.svelte +1 -1
- package/charts/MixedChart.svelte +1 -1
- package/charts/PieChart.svelte +1 -1
- package/charts/RadialChart.svelte +1 -1
- package/charts/utils.js +1 -0
- package/controls/Checkbox.svelte +10 -4
- package/controls/FileUpload.svelte +14 -8
- package/controls/NumberInput.svelte +19 -10
- package/controls/Radio.svelte +8 -2
- package/controls/RangeSlider.svelte +8 -2
- package/controls/Toggle.svelte +9 -2
- package/controls/ToggleButtons.svelte +10 -3
- package/datagrid/DataSearch/DataSearch.svelte +1 -1
- package/datagrid/GridView/GridCell.svelte +3 -0
- package/datagrid/GridView/GridRow.svelte +15 -0
- package/datagrid/GridView/GridView.svelte +21 -3
- package/datagrid/Pagination/Pagination.svelte +3 -3
- package/datagrid/TileView/TileView.svelte +46 -5
- package/datagrid/TileView/TileViewItem.svelte +4 -0
- package/form/index.js +160 -0
- package/forms/AutoComplete.svelte +67 -28
- package/forms/Datepicker.svelte +22 -5
- package/forms/PasswordValidator/PasswordValidator.svelte +8 -8
- package/forms/PasswordValidator/validatePassword.js +13 -2
- package/forms/SearchInput.svelte +180 -0
- package/forms/Timepicker.svelte +69 -4
- package/forms/actions.js +21 -15
- package/forms/colorpicker/Colorpicker.js +28 -3
- package/forms/colorpicker/Colorpicker.svelte +2 -2
- package/forms/select/MultiSelect.svelte +81 -28
- package/forms/select/SearchableSelect.svelte +6 -5
- package/helpers/CardModal.svelte +2 -1
- package/helpers/ClipboardCopier.svelte +4 -1
- package/helpers/Dialog/Dialog.svelte +13 -8
- package/helpers/Dialog/index.js +6 -0
- package/helpers/Divider.svelte +2 -2
- package/helpers/FloatingUI/Floatie.svelte +6 -6
- package/helpers/FloatingUI/index.js +2 -1
- package/helpers/Icon.svelte +25 -9
- package/helpers/Loader.svelte +10 -3
- package/helpers/Message.svelte +2 -2
- package/helpers/Modal.svelte +2 -1
- package/helpers/Notification.svelte +1 -1
- package/helpers/Popover.svelte +4 -4
- package/helpers/ScrollableList.svelte +12 -8
- package/helpers/Skeleton.svelte +4 -1
- package/helpers/Timeline/Timeline.svelte +1 -1
- package/helpers/Timeline/TimelineItem.svelte +5 -5
- package/helpers/Tooltip.js +1 -1
- package/index.js +10 -4
- package/{utils → internal}/fuzzy.js +1 -1
- package/internal/index.js +27 -0
- package/internal/scrollIntoActiveElement.js +22 -0
- package/keyboard/index.js +94 -0
- package/package.json +6 -3
- package/{utils/resizeObserver.js → resizeObserver/index.js} +0 -0
- package/search/index.js +52 -0
- package/settings.js +1 -1
- package/sliding-panes/SlidingPane.svelte +1 -4
- package/styles/AutoComplete.scss +2 -1
- package/styles/Datepicker.scss +1 -1
- package/styles/Grid.scss +14 -0
- package/styles/Select.scss +2 -1
- package/transitions/components/Scale.svelte +1 -0
- package/transitions/components/getEasing.js +18 -5
- package/types/ambient.d.ts +16 -0
- package/types/index.d.ts +46 -0
- package/types/type-defs/index.ts +14 -0
- package/utils/index.js +110 -9
- package/utils/fuzzysearch.js +0 -41
- package/utils/keyboard-events.js +0 -32
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
@component
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
@param {string} [value=
|
|
5
|
+
@param {?string} [value=] - Value of the Input
|
|
6
6
|
|
|
7
|
-
This property can be bound to, to fetch the current value, Default:
|
|
7
|
+
This property can be bound to, to fetch the current value, Default: ``
|
|
8
8
|
@param {string} [placeholder=""] - Placeholder text for the input, Default: `""`
|
|
9
9
|
@param {array} [options=[]] - Array of strings, or objects.
|
|
10
10
|
Used to populate the list of options in the dropdown, Default: `[]`
|
|
@@ -12,12 +12,12 @@ Used to populate the list of options in the dropdown, Default: `[]`
|
|
|
12
12
|
|
|
13
13
|
Only send this prop if you want to fetch `options` asynchronously.
|
|
14
14
|
`options` prop will be ignored if this prop is set., Default: `null`
|
|
15
|
-
@param {'fuzzy'|'strict'} [search_strategy="fuzzy"] - Filtered options to be displayed strictly based on search text or perform a fuzzy match.
|
|
15
|
+
@param {string|'fuzzy'|'strict'} [search_strategy="fuzzy"] - Filtered options to be displayed strictly based on search text or perform a fuzzy match.
|
|
16
16
|
Fuzzy match will not work if `search` function is set, as the backend service is meant to do the matching., Default: `"fuzzy"`
|
|
17
17
|
@param {boolean} [highlighted_results=true] - Whether to show the highlighted or plain results in the dropdown., Default: `true`
|
|
18
18
|
@param {number} [scoreThreshold=5] - Score threshold for fuzzy search strategy, setting high score gives more fuzzy matches., Default: `5`
|
|
19
|
-
@param {''|'small'|'medium'|'large'} [size=""] - Size of the input, Default: `""`
|
|
20
|
-
@param {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Color of the input, Default: `""`
|
|
19
|
+
@param {string|''|'small'|'medium'|'large'} [size=""] - Size of the input, Default: `""`
|
|
20
|
+
@param {string|''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Color of the input, Default: `""`
|
|
21
21
|
@param {string} [style=""] - Inline CSS for input container, Default: `""`
|
|
22
22
|
@param {boolean} [readonly=false] - Marks component as read-only, Default: `false`
|
|
23
23
|
@param {boolean} [disabled=false] - Disables the component, Default: `false`
|
|
@@ -75,8 +75,22 @@ Default value: `<span>{option.label}</span>`
|
|
|
75
75
|
on:mousedown|preventDefault|stopPropagation={() =>
|
|
76
76
|
handleOptionMouseDown(option)}
|
|
77
77
|
on:mouseenter|preventDefault|stopPropagation={() => {
|
|
78
|
+
if (mouseTracker.preventSelect) return;
|
|
78
79
|
active_option = option;
|
|
79
80
|
}}
|
|
81
|
+
on:mousemove|preventDefault|stopPropagation={(e) => {
|
|
82
|
+
let { preventSelect, lastX, lastY } = mouseTracker;
|
|
83
|
+
if (
|
|
84
|
+
preventSelect &&
|
|
85
|
+
(lastX !== e.clientX || lastY !== e.clientY)
|
|
86
|
+
) {
|
|
87
|
+
mouseTracker.preventSelect = false;
|
|
88
|
+
active_option = option;
|
|
89
|
+
}
|
|
90
|
+
// mouse x,y is not in same position after the scrolling
|
|
91
|
+
mouseTracker.lastX = e.clientX;
|
|
92
|
+
mouseTracker.lastY = e.clientY;
|
|
93
|
+
}}
|
|
80
94
|
class="is-size-{list_text_size[size]}"
|
|
81
95
|
class:active={active_option === option}>
|
|
82
96
|
<!--
|
|
@@ -100,7 +114,8 @@ Default value: `<span>{option.label}</span>`
|
|
|
100
114
|
import { debounce } from "@kws3/ui/utils";
|
|
101
115
|
import { createEventDispatcher, onMount, tick } from "svelte";
|
|
102
116
|
import { createPopper } from "@popperjs/core";
|
|
103
|
-
import {
|
|
117
|
+
import { makeSearchEngine } from "@kws3/ui/search";
|
|
118
|
+
import { scrollIntoActiveElement } from "../internal";
|
|
104
119
|
|
|
105
120
|
const sameWidthPopperModifier = {
|
|
106
121
|
name: "sameWidth",
|
|
@@ -120,10 +135,16 @@ Default value: `<span>{option.label}</span>`
|
|
|
120
135
|
|
|
121
136
|
const rootContainerId = "kws-overlay-root";
|
|
122
137
|
|
|
138
|
+
/**
|
|
139
|
+
* @typedef {import('@kws3/ui/types').ColorOptions} ColorOptions
|
|
140
|
+
* @typedef {import('@kws3/ui/types').SizeOptions} SizeOptions
|
|
141
|
+
*/
|
|
142
|
+
|
|
123
143
|
/**
|
|
124
144
|
* Value of the Input
|
|
125
145
|
*
|
|
126
146
|
* This property can be bound to, to fetch the current value
|
|
147
|
+
* @type {?string}
|
|
127
148
|
*/
|
|
128
149
|
export let value = "";
|
|
129
150
|
|
|
@@ -149,7 +170,7 @@ Default value: `<span>{option.label}</span>`
|
|
|
149
170
|
/**
|
|
150
171
|
* Filtered options to be displayed strictly based on search text or perform a fuzzy match.
|
|
151
172
|
* Fuzzy match will not work if `search` function is set, as the backend service is meant to do the matching.
|
|
152
|
-
* @type {'fuzzy'|'strict'}
|
|
173
|
+
* @type {string|'fuzzy'|'strict'}
|
|
153
174
|
*/
|
|
154
175
|
export let search_strategy = "fuzzy";
|
|
155
176
|
|
|
@@ -160,16 +181,17 @@ Default value: `<span>{option.label}</span>`
|
|
|
160
181
|
|
|
161
182
|
/**
|
|
162
183
|
* Score threshold for fuzzy search strategy, setting high score gives more fuzzy matches.
|
|
184
|
+
* @type {number}
|
|
163
185
|
*/
|
|
164
186
|
export let scoreThreshold = 5;
|
|
165
187
|
/**
|
|
166
188
|
* Size of the input
|
|
167
|
-
* @type {''
|
|
189
|
+
* @type {import('@kws3/ui/types').SizeOptions}
|
|
168
190
|
*/
|
|
169
191
|
export let size = "";
|
|
170
192
|
/**
|
|
171
193
|
* Color of the input
|
|
172
|
-
* @type {''
|
|
194
|
+
* @type {import('@kws3/ui/types').ColorOptions}
|
|
173
195
|
*/
|
|
174
196
|
export let color = "";
|
|
175
197
|
/**
|
|
@@ -222,11 +244,16 @@ Default value: `<span>{option.label}</span>`
|
|
|
222
244
|
active_option = "",
|
|
223
245
|
searching = true,
|
|
224
246
|
show_options = false,
|
|
247
|
+
mouseTracker = {
|
|
248
|
+
lastX: 0,
|
|
249
|
+
lastY: 0, // to check actual mouse is moving or not, for WebKit compatibility,
|
|
250
|
+
preventSelect: false, //prevent select by mouse when up or down key is pressed
|
|
251
|
+
},
|
|
225
252
|
filtered_options = [], //list of options filtered by search query
|
|
226
253
|
normalised_options = [], //list of options normalised
|
|
227
254
|
options_loading = false, //indictaes whether async search function is running
|
|
228
255
|
mounted = false, //indicates whether component is mounted
|
|
229
|
-
|
|
256
|
+
fuzzysearch = null;
|
|
230
257
|
|
|
231
258
|
let list_text_size = {
|
|
232
259
|
small: "7",
|
|
@@ -277,19 +304,20 @@ Default value: `<span>{option.label}</span>`
|
|
|
277
304
|
return;
|
|
278
305
|
}
|
|
279
306
|
options_loading = true;
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
307
|
+
if (search) {
|
|
308
|
+
search(filters).then((_options) => {
|
|
309
|
+
searching = false;
|
|
310
|
+
options_loading = false;
|
|
311
|
+
tick().then(() => {
|
|
312
|
+
filtered_options = normaliseArraysToObjects(_options);
|
|
313
|
+
|
|
314
|
+
if (highlighted_results) {
|
|
315
|
+
filtered_options = highlightMatches(filtered_options, filters);
|
|
316
|
+
}
|
|
317
|
+
setOptionsVisible(true);
|
|
318
|
+
});
|
|
291
319
|
});
|
|
292
|
-
}
|
|
320
|
+
}
|
|
293
321
|
}
|
|
294
322
|
|
|
295
323
|
const debouncedTriggerSearch = debounce(triggerExternalSearch, 150, false);
|
|
@@ -298,11 +326,12 @@ Default value: `<span>{option.label}</span>`
|
|
|
298
326
|
POPPER = createPopper(el, dropdown, {
|
|
299
327
|
strategy: "fixed",
|
|
300
328
|
placement: "bottom-start",
|
|
329
|
+
// @ts-ignore
|
|
301
330
|
modifiers: [sameWidthPopperModifier],
|
|
302
331
|
});
|
|
303
332
|
|
|
304
333
|
if (allow_fuzzy_match) {
|
|
305
|
-
fuzzyOpts = {
|
|
334
|
+
let fuzzyOpts = {
|
|
306
335
|
analyzeSubTerms: true,
|
|
307
336
|
analyzeSubTermDepth: 10,
|
|
308
337
|
highlighting: {
|
|
@@ -314,6 +343,12 @@ Default value: `<span>{option.label}</span>`
|
|
|
314
343
|
fuzzyOpts.highlighting.before = `<span class="h">`;
|
|
315
344
|
fuzzyOpts.highlighting.after = "</span>";
|
|
316
345
|
}
|
|
346
|
+
let searchOptions = {
|
|
347
|
+
search_key: "label",
|
|
348
|
+
scoreThreshold,
|
|
349
|
+
fuzzyOpts,
|
|
350
|
+
};
|
|
351
|
+
fuzzysearch = makeSearchEngine(searchOptions);
|
|
317
352
|
}
|
|
318
353
|
|
|
319
354
|
//normalize value
|
|
@@ -362,6 +397,14 @@ Default value: `<span>{option.label}</span>`
|
|
|
362
397
|
active_option = filtered_options[0];
|
|
363
398
|
else active_option = filtered_options[newActiveIdx];
|
|
364
399
|
}
|
|
400
|
+
|
|
401
|
+
tick().then(() => {
|
|
402
|
+
if (dropdown) {
|
|
403
|
+
mouseTracker.preventSelect = true;
|
|
404
|
+
let activeElem = dropdown.querySelector(".active");
|
|
405
|
+
scrollIntoActiveElement(dropdown, activeElem);
|
|
406
|
+
}
|
|
407
|
+
});
|
|
365
408
|
} else {
|
|
366
409
|
active_option = "";
|
|
367
410
|
searching = true;
|
|
@@ -433,11 +476,7 @@ Default value: `<span>{option.label}</span>`
|
|
|
433
476
|
// iterate over each word in the search query
|
|
434
477
|
let opts = [];
|
|
435
478
|
if (word) {
|
|
436
|
-
let result = fuzzysearch(word, options
|
|
437
|
-
search_key: "label",
|
|
438
|
-
scoreThreshold,
|
|
439
|
-
fuzzyOpts,
|
|
440
|
-
});
|
|
479
|
+
let result = fuzzysearch(word, options);
|
|
441
480
|
opts = result;
|
|
442
481
|
}
|
|
443
482
|
|
package/forms/Datepicker.svelte
CHANGED
|
@@ -8,10 +8,10 @@ In `range_mode`, the expected format is `yyyy-mm-dd to yyyy-mm-dd`
|
|
|
8
8
|
|
|
9
9
|
This property can be bound to, to fetch the selected date or date range. Output is in the same format as input., Default: `""`
|
|
10
10
|
@param {string} [style=""] - Inline CSS for the input, Default: `""`
|
|
11
|
-
@param {''|'primary'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Colour of the Date picker input, Default: `""`
|
|
11
|
+
@param {string|''|'primary'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Colour of the Date picker input, Default: `""`
|
|
12
12
|
@param {boolean} [disabled=false] - Disables the component, Default: `false`
|
|
13
13
|
@param {string} [placeholder="Select Date.."] - Placeholder text for the input, Default: `"Select Date.."`
|
|
14
|
-
@param {'primary'|'warning'|'info'|'danger'|'dark'|'light'} [calendar_color="primary"] - Colour of the Calendar, Default: `"primary"`
|
|
14
|
+
@param {string|'primary'|'warning'|'info'|'danger'|'dark'|'light'} [calendar_color="primary"] - Colour of the Calendar, Default: `"primary"`
|
|
15
15
|
@param {any} [min_date=null] - Set earliest selectable date as an object or string
|
|
16
16
|
|
|
17
17
|
**Example:** `"2021-06-06"` or `"(new Date('2021-01-01'))"`, Default: `null`
|
|
@@ -55,11 +55,15 @@ See: https://flatpickr.js.org/options/, Default: `{}`
|
|
|
55
55
|
on:yearChange={fireYearChange} />
|
|
56
56
|
|
|
57
57
|
<script>
|
|
58
|
-
import { datepicker } from "./actions";
|
|
59
58
|
import { createEventDispatcher } from "svelte";
|
|
59
|
+
import { datepicker } from "./actions";
|
|
60
60
|
|
|
61
61
|
const fire = createEventDispatcher();
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* @typedef {import('@kws3/ui/types').ColorOptions} ColorOptions
|
|
65
|
+
*/
|
|
66
|
+
|
|
63
67
|
/**
|
|
64
68
|
* Accepts a date value in the format `yyyy-mm-dd`
|
|
65
69
|
*
|
|
@@ -74,20 +78,24 @@ See: https://flatpickr.js.org/options/, Default: `{}`
|
|
|
74
78
|
export let style = "";
|
|
75
79
|
/**
|
|
76
80
|
* Colour of the Date picker input
|
|
77
|
-
* @type {
|
|
81
|
+
* @type {ColorOptions} color
|
|
78
82
|
*/
|
|
79
83
|
export let color = "";
|
|
80
84
|
/**
|
|
81
85
|
* Disables the component
|
|
82
86
|
*/
|
|
83
87
|
export let disabled = false;
|
|
88
|
+
/**
|
|
89
|
+
* Make input value read-only
|
|
90
|
+
*/
|
|
91
|
+
export let readonly = false;
|
|
84
92
|
/**
|
|
85
93
|
* Placeholder text for the input
|
|
86
94
|
*/
|
|
87
95
|
export let placeholder = "Select Date..";
|
|
88
96
|
/**
|
|
89
97
|
* Colour of the Calendar
|
|
90
|
-
* @type {'
|
|
98
|
+
* @type {Exclude<ColorOptions, ''>}
|
|
91
99
|
*/
|
|
92
100
|
export let calendar_color = "primary";
|
|
93
101
|
/**
|
|
@@ -140,9 +148,13 @@ See: https://flatpickr.js.org/options/, Default: `{}`
|
|
|
140
148
|
min_date,
|
|
141
149
|
max_date,
|
|
142
150
|
options,
|
|
151
|
+
readonly,
|
|
143
152
|
fillOptions();
|
|
144
153
|
|
|
145
154
|
function fillOptions() {
|
|
155
|
+
/**
|
|
156
|
+
* @type {object}
|
|
157
|
+
*/
|
|
146
158
|
let _opts = Object.assign(
|
|
147
159
|
{
|
|
148
160
|
color: calendar_color,
|
|
@@ -164,6 +176,11 @@ See: https://flatpickr.js.org/options/, Default: `{}`
|
|
|
164
176
|
if (max_date) {
|
|
165
177
|
_opts.maxDate = max_date;
|
|
166
178
|
}
|
|
179
|
+
|
|
180
|
+
_opts.clickOpens = true;
|
|
181
|
+
if (readonly) {
|
|
182
|
+
_opts.clickOpens = false;
|
|
183
|
+
}
|
|
167
184
|
opts = _opts;
|
|
168
185
|
}
|
|
169
186
|
|
|
@@ -30,22 +30,22 @@ Should be used with `bind` from parent component, Default: `false`
|
|
|
30
30
|
<li>
|
|
31
31
|
<span class="help expanded">
|
|
32
32
|
<span
|
|
33
|
-
class="tag is-small is-normal is-light pv-identifier {opt
|
|
33
|
+
class="tag is-small is-normal is-light pv-identifier {opt['passed']
|
|
34
34
|
? 'is-success'
|
|
35
|
-
: 'is-danger'}">{opt
|
|
36
|
-
<span class="pv-text">{opt
|
|
35
|
+
: 'is-danger'}">{opt["identifier"]}</span>
|
|
36
|
+
<span class="pv-text">{opt["text"]}</span>
|
|
37
37
|
<Icon
|
|
38
38
|
class="pv-icon"
|
|
39
|
-
icon={opt
|
|
40
|
-
color={opt
|
|
39
|
+
icon={opt["passed"] ? "check" : "ban"}
|
|
40
|
+
color={opt["passed"] ? "success" : "danger"} />
|
|
41
41
|
</span>
|
|
42
42
|
<span class="summarized">
|
|
43
43
|
<span
|
|
44
|
-
data-tooltip={opt
|
|
44
|
+
data-tooltip={opt["text"]}
|
|
45
45
|
data-tippy-hideOnClick="false"
|
|
46
|
-
class="tag is-small is-normal is-light pv-identifier {opt
|
|
46
|
+
class="tag is-small is-normal is-light pv-identifier {opt['passed']
|
|
47
47
|
? 'is-success'
|
|
48
|
-
: 'is-danger'}">{opt
|
|
48
|
+
: 'is-danger'}">{opt["identifier"]}</span>
|
|
49
49
|
</span>
|
|
50
50
|
</li>
|
|
51
51
|
{/each}
|
|
@@ -4,11 +4,20 @@ export default function (password, options) {
|
|
|
4
4
|
overall: false,
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {import('@kws3/ui/types').ValidatePasswordOptions} ValidatePasswordOptions - contains ValidatePassword options
|
|
9
|
+
*/
|
|
10
|
+
|
|
7
11
|
result.items = (options || []).slice().map((_opt) => {
|
|
12
|
+
/** @type {ValidatePasswordOptions} */
|
|
8
13
|
const opt = Object.assign({}, _opt);
|
|
9
14
|
if (opt && opt.active) {
|
|
10
15
|
if (opt.name === "kws_pv_min_length") {
|
|
11
|
-
if (
|
|
16
|
+
if (
|
|
17
|
+
typeof opt.value != "undefined" &&
|
|
18
|
+
password &&
|
|
19
|
+
password.length >= opt.value
|
|
20
|
+
) {
|
|
12
21
|
opt.passed = true;
|
|
13
22
|
}
|
|
14
23
|
} else {
|
|
@@ -24,7 +33,9 @@ export default function (password, options) {
|
|
|
24
33
|
});
|
|
25
34
|
|
|
26
35
|
result.overall =
|
|
27
|
-
result.items.filter(
|
|
36
|
+
result.items.filter(
|
|
37
|
+
(/** @type {ValidatePasswordOptions} */ el) => el.passed
|
|
38
|
+
).length === result.items.length;
|
|
28
39
|
|
|
29
40
|
return result;
|
|
30
41
|
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
@component
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
@param {string|''|'small'|'medium'|'large'} [size="small"] - Size of the input, Default: `"small"`
|
|
6
|
+
@param {string|''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Color of the input, Default: `""`
|
|
7
|
+
@param {string} [placeholder="Search"] - Placeholder text for the input, Default: `"Search"`
|
|
8
|
+
@param {boolean} [readonly=false] - Marks component as read-only, Default: `false`
|
|
9
|
+
@param {boolean} [disabled=false] - Disables the component, Default: `false`
|
|
10
|
+
@param {array} [options=[]] - Array of objects., Default: `[]`
|
|
11
|
+
@param {array} [searchableKeys=[]] - array of object properties to search in., Default: `[]`
|
|
12
|
+
@param {boolean} [highlighted_results=true] - Whether to show the highlighted or plain results in the dropdown., Default: `true`
|
|
13
|
+
@param {number} [scoreThreshold=2] - Score threshold for fuzzy search strategy, setting high score gives more fuzzy matches., Default: `2`
|
|
14
|
+
@param {boolean} [word_match=false] - Whether to match against each word seperatly or whole sentence in flow., Default: `false`
|
|
15
|
+
@param {string} [style=""] - Inline CSS for the input, Default: `""`
|
|
16
|
+
@param {string} [class=""] - CSS classes for the input, Default: `""`
|
|
17
|
+
|
|
18
|
+
-->
|
|
19
|
+
<div
|
|
20
|
+
class="
|
|
21
|
+
field has-addons is-marginless
|
|
22
|
+
{readonly ? 'is-readonly' : ''}
|
|
23
|
+
{disabled ? 'is-disabled' : ''}
|
|
24
|
+
">
|
|
25
|
+
<div class="control is-expanded has-icons-left">
|
|
26
|
+
<input
|
|
27
|
+
class="input is-{size} is-{color} {klass}"
|
|
28
|
+
{placeholder}
|
|
29
|
+
{disabled}
|
|
30
|
+
{readonly}
|
|
31
|
+
{style}
|
|
32
|
+
bind:value={keywords}
|
|
33
|
+
on:keyup={debouncedSearch} />
|
|
34
|
+
<Icon icon="search" size="small" class="is-left" />
|
|
35
|
+
</div>
|
|
36
|
+
{#if keywords}
|
|
37
|
+
<div class="control">
|
|
38
|
+
<button class="button is-danger is-{size}" type="button" on:click={reset}>
|
|
39
|
+
<Icon icon="times" size="small" />
|
|
40
|
+
</button>
|
|
41
|
+
</div>
|
|
42
|
+
{/if}
|
|
43
|
+
</div>
|
|
44
|
+
|
|
45
|
+
<script>
|
|
46
|
+
import { Icon } from "@kws3/ui";
|
|
47
|
+
import { debounce } from "@kws3/ui/utils";
|
|
48
|
+
import { onDestroy, onMount } from "svelte";
|
|
49
|
+
import { makeSearchEngine } from "@kws3/ui/search";
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Size of the input
|
|
53
|
+
* @type {import('@kws3/ui/types').SizeOptions} size
|
|
54
|
+
*/
|
|
55
|
+
export let size = "small";
|
|
56
|
+
/**
|
|
57
|
+
* Color of the input
|
|
58
|
+
* @type {import('@kws3/ui/types').ColorOptions} color
|
|
59
|
+
*/
|
|
60
|
+
export let color = "";
|
|
61
|
+
/**
|
|
62
|
+
* Placeholder text for the input
|
|
63
|
+
*/
|
|
64
|
+
export let placeholder = "Search";
|
|
65
|
+
/**
|
|
66
|
+
* Marks component as read-only
|
|
67
|
+
*/
|
|
68
|
+
export let readonly = false;
|
|
69
|
+
/**
|
|
70
|
+
* Disables the component
|
|
71
|
+
*/
|
|
72
|
+
export let disabled = false;
|
|
73
|
+
/**
|
|
74
|
+
* Array of objects.
|
|
75
|
+
* @type {array}
|
|
76
|
+
*/
|
|
77
|
+
export let options = [];
|
|
78
|
+
/**
|
|
79
|
+
* array of object properties to search in.
|
|
80
|
+
* @type {array}
|
|
81
|
+
*/
|
|
82
|
+
export let searchableKeys = [];
|
|
83
|
+
/**
|
|
84
|
+
* Whether to show the highlighted or plain results in the dropdown.
|
|
85
|
+
*/
|
|
86
|
+
export let highlighted_results = true;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Score threshold for fuzzy search strategy, setting high score gives more fuzzy matches.
|
|
90
|
+
* @type {number}
|
|
91
|
+
*/
|
|
92
|
+
export let scoreThreshold = 2;
|
|
93
|
+
/**
|
|
94
|
+
* Whether to match against each word seperatly or whole sentence in flow.
|
|
95
|
+
*/
|
|
96
|
+
export let word_match = false;
|
|
97
|
+
/**
|
|
98
|
+
* Inline CSS for the input
|
|
99
|
+
*/
|
|
100
|
+
export let style = "";
|
|
101
|
+
/**
|
|
102
|
+
* CSS classes for the input
|
|
103
|
+
*/
|
|
104
|
+
let klass = "";
|
|
105
|
+
export { klass as class };
|
|
106
|
+
|
|
107
|
+
let keywords = "",
|
|
108
|
+
orginalItems = [],
|
|
109
|
+
fuzzysearch = null;
|
|
110
|
+
|
|
111
|
+
const debouncedSearch = debounce(search, 300);
|
|
112
|
+
|
|
113
|
+
const sanitizeValue = (v) =>
|
|
114
|
+
v && v.trim() ? v.toLowerCase().trim().split(/\s+/) : [];
|
|
115
|
+
|
|
116
|
+
onMount(() => {
|
|
117
|
+
let fuzzyOpts = {
|
|
118
|
+
analyzeSubTerms: true,
|
|
119
|
+
analyzeSubTermDepth: 10,
|
|
120
|
+
highlighting: {
|
|
121
|
+
after: "",
|
|
122
|
+
before: "",
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
if (highlighted_results) {
|
|
126
|
+
fuzzyOpts.highlighting.before = `<span class="h">`;
|
|
127
|
+
fuzzyOpts.highlighting.after = "</span>";
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
let searchOptions = {
|
|
131
|
+
search_key: searchableKeys,
|
|
132
|
+
scoreThreshold,
|
|
133
|
+
fuzzyOpts,
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
fuzzysearch = makeSearchEngine(searchOptions);
|
|
137
|
+
|
|
138
|
+
if (word_match) {
|
|
139
|
+
options.forEach((item, i) => {
|
|
140
|
+
item._uid = i;
|
|
141
|
+
});
|
|
142
|
+
orginalItems = [...options];
|
|
143
|
+
} else {
|
|
144
|
+
orginalItems = [...options];
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
onDestroy(reset);
|
|
149
|
+
|
|
150
|
+
function search() {
|
|
151
|
+
if (!keywords) {
|
|
152
|
+
reset();
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
let result = [];
|
|
156
|
+
|
|
157
|
+
if (word_match) {
|
|
158
|
+
let cache = {},
|
|
159
|
+
filters = sanitizeValue(keywords);
|
|
160
|
+
filters.forEach((word, idx) => {
|
|
161
|
+
// iterate over each word in the search query
|
|
162
|
+
let opts = [];
|
|
163
|
+
if (word) opts = fuzzysearch(word, orginalItems);
|
|
164
|
+
cache[idx] = opts; // storing options to current index on cache
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
result = Object.values(cache) // get values from cache
|
|
168
|
+
.flat()
|
|
169
|
+
.filter((v, i, self) => i === self.findIndex((t) => t._uid === v._uid)); // flatten array
|
|
170
|
+
} else {
|
|
171
|
+
result = fuzzysearch(keywords, orginalItems);
|
|
172
|
+
}
|
|
173
|
+
options = result;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function reset() {
|
|
177
|
+
keywords = "";
|
|
178
|
+
options = [...orginalItems];
|
|
179
|
+
}
|
|
180
|
+
</script>
|
package/forms/Timepicker.svelte
CHANGED
|
@@ -14,6 +14,10 @@ This property can be bound to, to fetch the selected time. Output is in the same
|
|
|
14
14
|
@param {'primary'|'warning'|'info'|'danger'|'dark'|'light'} [ui_color="primary"] - Colour of popup time selection UI, Default: `"primary"`
|
|
15
15
|
@param {boolean} [time_24hr=false] - Display time selection UI in 24hr format, Default: `false`
|
|
16
16
|
@param {object} [options={}] - Extended set of options as supported by Flatpicker
|
|
17
|
+
@param {any} [min_time=null] - Set earliest selectable time as string
|
|
18
|
+
**Example:** `"12:00 PM"` Default: `null`
|
|
19
|
+
@param {any} [max_time=null] - Set latest selectable time as string
|
|
20
|
+
**Example:** `"12:00 AM"` Default: `null`
|
|
17
21
|
|
|
18
22
|
See: https://flatpickr.js.org/options/, Default: `{}`
|
|
19
23
|
@param {string} [class=""] - CSS classes for the input, Default: `""`
|
|
@@ -43,11 +47,15 @@ See: https://flatpickr.js.org/options/, Default: `{}`
|
|
|
43
47
|
on:close={fireClose} />
|
|
44
48
|
|
|
45
49
|
<script>
|
|
46
|
-
import { timepicker } from "./actions";
|
|
47
50
|
import { createEventDispatcher } from "svelte";
|
|
51
|
+
import { timepicker } from "./actions";
|
|
48
52
|
|
|
49
53
|
const fire = createEventDispatcher();
|
|
50
54
|
|
|
55
|
+
/**
|
|
56
|
+
* @typedef {import('@kws3/ui/types').ColorOptions} ColorOptions
|
|
57
|
+
*/
|
|
58
|
+
|
|
51
59
|
/**
|
|
52
60
|
* Accepts a date value in the format `H:i`
|
|
53
61
|
*
|
|
@@ -62,7 +70,7 @@ See: https://flatpickr.js.org/options/, Default: `{}`
|
|
|
62
70
|
export let style = "";
|
|
63
71
|
/**
|
|
64
72
|
* Colour of the Time picker input
|
|
65
|
-
* @type {
|
|
73
|
+
* @type {ColorOptions} color
|
|
66
74
|
*/
|
|
67
75
|
export let color = "";
|
|
68
76
|
/**
|
|
@@ -75,7 +83,7 @@ See: https://flatpickr.js.org/options/, Default: `{}`
|
|
|
75
83
|
export let placeholder = "Select Time..";
|
|
76
84
|
/**
|
|
77
85
|
* Colour of popup time selection UI
|
|
78
|
-
* @type {'
|
|
86
|
+
* @type {Exclude<ColorOptions, ''>}
|
|
79
87
|
*/
|
|
80
88
|
export let ui_color = "primary";
|
|
81
89
|
|
|
@@ -84,23 +92,64 @@ See: https://flatpickr.js.org/options/, Default: `{}`
|
|
|
84
92
|
*/
|
|
85
93
|
export let time_24hr = false;
|
|
86
94
|
|
|
95
|
+
/**
|
|
96
|
+
* Set earliest selectable time as string
|
|
97
|
+
*
|
|
98
|
+
* **Example:** `"01:00 PM"` or "13:00"`
|
|
99
|
+
* @type {any}
|
|
100
|
+
*/
|
|
101
|
+
export let min_time = null;
|
|
102
|
+
/**
|
|
103
|
+
* Set latest selectable time as string
|
|
104
|
+
*
|
|
105
|
+
* **Example:** `"03:00 PM"` or "15:00"`
|
|
106
|
+
* @type {any}
|
|
107
|
+
*/
|
|
108
|
+
export let max_time = null;
|
|
109
|
+
|
|
87
110
|
/**
|
|
88
111
|
* Extended set of options as supported by Flatpicker
|
|
89
112
|
*
|
|
90
113
|
* See: https://flatpickr.js.org/options/
|
|
91
114
|
*/
|
|
92
115
|
export let options = {};
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Make input value read-only
|
|
119
|
+
*/
|
|
120
|
+
export let readonly = false;
|
|
121
|
+
|
|
93
122
|
/**
|
|
94
123
|
* CSS classes for the input
|
|
95
124
|
*/
|
|
125
|
+
|
|
96
126
|
let klass = "";
|
|
97
127
|
export { klass as class };
|
|
98
128
|
|
|
99
129
|
let opts;
|
|
100
130
|
|
|
101
|
-
$: ui_color, options, time_24hr, fillOptions();
|
|
131
|
+
$: ui_color, options, time_24hr, min_time, max_time, readonly, fillOptions();
|
|
132
|
+
|
|
133
|
+
const convertTime12to24 = (time12h) => {
|
|
134
|
+
const [time, modifier] = time12h.split(" ");
|
|
135
|
+
let [hours, minutes] = time.split(":");
|
|
136
|
+
if (hours === "12") {
|
|
137
|
+
hours = "00";
|
|
138
|
+
}
|
|
139
|
+
if (modifier === "PM") {
|
|
140
|
+
hours = parseInt(hours, 10) + 12;
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
hour: String(hours),
|
|
144
|
+
minute: String(minutes),
|
|
145
|
+
time: `${hours}:${minutes}`,
|
|
146
|
+
};
|
|
147
|
+
};
|
|
102
148
|
|
|
103
149
|
function fillOptions() {
|
|
150
|
+
/**
|
|
151
|
+
* @type {object}
|
|
152
|
+
*/
|
|
104
153
|
let _opts = Object.assign(
|
|
105
154
|
{
|
|
106
155
|
color: ui_color,
|
|
@@ -109,6 +158,22 @@ See: https://flatpickr.js.org/options/, Default: `{}`
|
|
|
109
158
|
options
|
|
110
159
|
);
|
|
111
160
|
|
|
161
|
+
if (min_time) {
|
|
162
|
+
let _minTime24 = convertTime12to24(min_time);
|
|
163
|
+
_opts.minTime = _minTime24.time;
|
|
164
|
+
_opts.defaultHour = _minTime24.hour;
|
|
165
|
+
_opts.defaultMinute = _minTime24.minute;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (max_time) {
|
|
169
|
+
let _maxTime24 = convertTime12to24(max_time);
|
|
170
|
+
_opts.maxTime = _maxTime24.time;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
_opts.clickOpens = true;
|
|
174
|
+
if (readonly) {
|
|
175
|
+
_opts.clickOpens = false;
|
|
176
|
+
}
|
|
112
177
|
opts = _opts;
|
|
113
178
|
}
|
|
114
179
|
|