@kws3/ui 1.9.1 → 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 +76 -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 +126 -76
- 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 +103 -46
- 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/internal/fuzzy.js +116 -0
- package/internal/index.js +27 -0
- package/internal/scrollIntoActiveElement.js +22 -0
- package/keyboard/index.js +94 -0
- package/package.json +6 -4
- 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 -20
- package/utils/keyboard-events.js +0 -32
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
|
|
package/forms/actions.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import flatpickr from "flatpickr";
|
|
2
2
|
|
|
3
|
-
function createFlatpickrAction(defaultOpts, hooks) {
|
|
3
|
+
function createFlatpickrAction(defaultOpts, hooks, type) {
|
|
4
4
|
return function (
|
|
5
5
|
node,
|
|
6
6
|
// eslint-disable-next-line no-unused-vars
|
|
@@ -34,9 +34,9 @@ function createFlatpickrAction(defaultOpts, hooks) {
|
|
|
34
34
|
_opts["onChange"] = createFirer("dateChange");
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
let OPTS = Object.assign(defaultOpts, _opts, opts);
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
let picker = flatpickr(node, OPTS);
|
|
40
40
|
|
|
41
41
|
function createFirer(name) {
|
|
42
42
|
return (selectedDates, dateStr, instance) => {
|
|
@@ -72,6 +72,10 @@ function createFlatpickrAction(defaultOpts, hooks) {
|
|
|
72
72
|
|
|
73
73
|
return {
|
|
74
74
|
update({ opts, value, placeholder, klass, style, disabled, color }) {
|
|
75
|
+
if (!picker.isOpen) {
|
|
76
|
+
picker = flatpickr(node, Object.assign(OPTS, opts));
|
|
77
|
+
}
|
|
78
|
+
|
|
75
79
|
if (picker) {
|
|
76
80
|
picker.setDate(value);
|
|
77
81
|
if (opts) {
|
|
@@ -81,19 +85,19 @@ function createFlatpickrAction(defaultOpts, hooks) {
|
|
|
81
85
|
if (opts.mode) {
|
|
82
86
|
picker.set("mode", opts.mode);
|
|
83
87
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
picker.set("disable", opts.disable ? opts.disable : [() => false]);
|
|
88
|
-
picker.set("time_24hr", opts.time_24hr || false);
|
|
88
|
+
if (type === "time") {
|
|
89
|
+
picker.set("altFormat", opts.time_24hr ? "H:i" : "h:i K");
|
|
90
|
+
}
|
|
89
91
|
}
|
|
90
|
-
|
|
91
92
|
//respond reactively to props
|
|
93
|
+
/** @type {any} */
|
|
92
94
|
const visibleInput = picker.input.nextSibling;
|
|
93
|
-
visibleInput
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
95
|
+
if (visibleInput) {
|
|
96
|
+
visibleInput.className = `input is-${color} ${klass}`;
|
|
97
|
+
visibleInput.style = `${style}`;
|
|
98
|
+
visibleInput.disabled = disabled;
|
|
99
|
+
visibleInput.placeholder = placeholder;
|
|
100
|
+
}
|
|
97
101
|
}
|
|
98
102
|
},
|
|
99
103
|
destroy() {
|
|
@@ -109,7 +113,8 @@ export let datepicker = createFlatpickrAction(
|
|
|
109
113
|
altFormat: "d/m/Y",
|
|
110
114
|
dateFormat: "Y-m-d",
|
|
111
115
|
},
|
|
112
|
-
["onOpen", "onClose", "onMonthChange", "onYearChange", "onReady"]
|
|
116
|
+
["onOpen", "onClose", "onMonthChange", "onYearChange", "onReady"],
|
|
117
|
+
"date"
|
|
113
118
|
);
|
|
114
119
|
|
|
115
120
|
export let timepicker = createFlatpickrAction(
|
|
@@ -120,5 +125,6 @@ export let timepicker = createFlatpickrAction(
|
|
|
120
125
|
enableTime: true,
|
|
121
126
|
noCalendar: true,
|
|
122
127
|
},
|
|
123
|
-
["onOpen", "onClose", "onReady"]
|
|
128
|
+
["onOpen", "onClose", "onReady"],
|
|
129
|
+
"time"
|
|
124
130
|
);
|
|
@@ -77,7 +77,11 @@ export default (function (win, doc) {
|
|
|
77
77
|
(r = v), (g = p), (b = q);
|
|
78
78
|
break;
|
|
79
79
|
}
|
|
80
|
-
return [
|
|
80
|
+
return [
|
|
81
|
+
r !== undefined ? round(r * 255) : NaN,
|
|
82
|
+
g !== undefined ? round(g * 255) : NaN,
|
|
83
|
+
b !== undefined ? round(b * 255) : NaN,
|
|
84
|
+
];
|
|
81
85
|
}
|
|
82
86
|
|
|
83
87
|
function HSV2HEX(a) {
|
|
@@ -116,8 +120,8 @@ export default (function (win, doc) {
|
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
function RGB2HEX(a) {
|
|
119
|
-
var s = +a[2] | (+a[1] << 8) | (+a[0] << 16);
|
|
120
|
-
s = "000000" + s
|
|
123
|
+
var s = (+a[2] | (+a[1] << 8) | (+a[0] << 16)).toString(16);
|
|
124
|
+
s = "000000" + s;
|
|
121
125
|
return s.slice(-6);
|
|
122
126
|
}
|
|
123
127
|
|
|
@@ -166,12 +170,14 @@ export default (function (win, doc) {
|
|
|
166
170
|
|
|
167
171
|
return (function ($) {
|
|
168
172
|
// plugin version
|
|
173
|
+
//@ts-ignore
|
|
169
174
|
$.version = "1.3.2";
|
|
170
175
|
|
|
171
176
|
// collect all instance(s)
|
|
172
177
|
$[instance] = {};
|
|
173
178
|
|
|
174
179
|
// plug to all instance(s)
|
|
180
|
+
//@ts-ignore
|
|
175
181
|
$.each = function (fn, t) {
|
|
176
182
|
return (
|
|
177
183
|
delay(
|
|
@@ -189,27 +195,39 @@ export default (function (win, doc) {
|
|
|
189
195
|
};
|
|
190
196
|
|
|
191
197
|
// static method(s)
|
|
198
|
+
//@ts-ignore
|
|
192
199
|
$.parse = parse;
|
|
200
|
+
//@ts-ignore
|
|
193
201
|
$._HSV2RGB = HSV2RGB;
|
|
202
|
+
//@ts-ignore
|
|
194
203
|
$._HSV2HEX = HSV2HEX;
|
|
204
|
+
//@ts-ignore
|
|
195
205
|
$._RGB2HSV = RGB2HSV;
|
|
206
|
+
//@ts-ignore
|
|
196
207
|
$._HEX2HSV = HEX2HSV;
|
|
208
|
+
//@ts-ignore
|
|
197
209
|
$._HEX2RGB = function (a) {
|
|
198
210
|
return _2RGB_pri(HEX2RGB(a));
|
|
199
211
|
};
|
|
212
|
+
//@ts-ignore
|
|
200
213
|
$.HSV2RGB = function (a) {
|
|
201
214
|
return HSV2RGB(_2HSV_pri(a));
|
|
202
215
|
};
|
|
216
|
+
//@ts-ignore
|
|
203
217
|
$.HSV2HEX = function (a) {
|
|
204
218
|
return HSV2HEX(_2HSV_pri(a));
|
|
205
219
|
};
|
|
220
|
+
//@ts-ignore
|
|
206
221
|
$.RGB2HSV = function (a) {
|
|
207
222
|
return _2HSV_pub(RGB2HSV(a));
|
|
208
223
|
};
|
|
224
|
+
//@ts-ignore
|
|
209
225
|
$.RGB2HEX = RGB2HEX;
|
|
226
|
+
//@ts-ignore
|
|
210
227
|
$.HEX2HSV = function (s) {
|
|
211
228
|
return _2HSV_pub(HEX2HSV(s));
|
|
212
229
|
};
|
|
230
|
+
//@ts-ignore
|
|
213
231
|
$.HEX2RGB = HEX2RGB;
|
|
214
232
|
|
|
215
233
|
return $;
|
|
@@ -405,6 +423,7 @@ export default (function (win, doc) {
|
|
|
405
423
|
if (is_target) {
|
|
406
424
|
create();
|
|
407
425
|
} else {
|
|
426
|
+
//@ts-ignore
|
|
408
427
|
$.exit();
|
|
409
428
|
}
|
|
410
429
|
trigger(is_target ? "enter" : "exit", [$]);
|
|
@@ -416,13 +435,16 @@ export default (function (win, doc) {
|
|
|
416
435
|
if (events !== false) {
|
|
417
436
|
on(events, target, click);
|
|
418
437
|
}
|
|
438
|
+
//@ts-ignore
|
|
419
439
|
$.create = function () {
|
|
420
440
|
return create(1), trigger("create", [$]), $;
|
|
421
441
|
};
|
|
442
|
+
//@ts-ignore
|
|
422
443
|
$.destroy = function () {
|
|
423
444
|
if (events !== false) {
|
|
424
445
|
off(events, target, click);
|
|
425
446
|
}
|
|
447
|
+
//@ts-ignore
|
|
426
448
|
$.exit(), set_data(false);
|
|
427
449
|
return trigger("destroy", [$]), $;
|
|
428
450
|
};
|
|
@@ -435,8 +457,10 @@ export default (function (win, doc) {
|
|
|
435
457
|
SV_point.style.right = SV_W - SV_point_W / 2 - SV_W * +HSV[1] + "px";
|
|
436
458
|
SV_point.style.top = SV_H - SV_point_H / 2 - SV_H * +HSV[2] + "px";
|
|
437
459
|
};
|
|
460
|
+
//@ts-ignore
|
|
438
461
|
$.exit = function () {
|
|
439
462
|
if (visible()) {
|
|
463
|
+
//@ts-ignore
|
|
440
464
|
visible().removeChild(picker);
|
|
441
465
|
$.visible = false;
|
|
442
466
|
}
|
|
@@ -499,6 +523,7 @@ export default (function (win, doc) {
|
|
|
499
523
|
if (!is_target && !is_picker) {
|
|
500
524
|
// click outside the target or picker element to exit
|
|
501
525
|
if (visible() && events !== false)
|
|
526
|
+
//@ts-ignore
|
|
502
527
|
$.exit(), trigger("exit", [$]), trigger_(0, a);
|
|
503
528
|
} else {
|
|
504
529
|
if (is_picker) {
|
|
@@ -36,7 +36,7 @@ This property can be bound to, to fetch the current colour, Default: `"000000"`
|
|
|
36
36
|
on:focus={focused}
|
|
37
37
|
{disabled}
|
|
38
38
|
bind:value={color}
|
|
39
|
-
use:colorpicker
|
|
39
|
+
use:colorpicker />
|
|
40
40
|
{#if !mini}
|
|
41
41
|
<Icon icon="hashtag" class="is-left" inner_style="color:#{color}" />
|
|
42
42
|
{/if}
|
|
@@ -84,7 +84,7 @@ This property can be bound to, to fetch the current colour, Default: `"000000"`
|
|
|
84
84
|
disabled = false,
|
|
85
85
|
/**
|
|
86
86
|
* Size of the colour picker trigger
|
|
87
|
-
* @type {''
|
|
87
|
+
* @type {import('@kws3/ui/types').SizeOptions}
|
|
88
88
|
*/
|
|
89
89
|
size = "";
|
|
90
90
|
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
@component
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
@param {
|
|
5
|
+
@param {Array|?string} [value=undefined] - 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: `undefined`
|
|
8
8
|
@param {object} [max=null] - Maximum number of selectable items from dropdown list.
|
|
9
9
|
|
|
10
10
|
Accepts a `null` value for unlimited selected items.
|
|
@@ -20,11 +20,11 @@ this property of each object will be returned as the value, Default: `"id"`
|
|
|
20
20
|
|
|
21
21
|
Only send this prop if you want to fetch `options` asynchronously.
|
|
22
22
|
`options` prop will be ignored if this prop is set., Default: `null`
|
|
23
|
-
@param {'fuzzy'|'strict'} [search_strategy="fuzzy"] - Filtered options to be displayed strictly based on search text or perform a fuzzy match.
|
|
23
|
+
@param {string|'fuzzy'|'strict'} [search_strategy="fuzzy"] - Filtered options to be displayed strictly based on search text or perform a fuzzy match.
|
|
24
24
|
Fuzzy match will not work if `search` function is set, as the backend service is meant to do the matching., Default: `"fuzzy"`
|
|
25
25
|
@param {number} [scoreThreshold=3] - Score threshold for fuzzy search strategy, setting high score gives more fuzzy matches., Default: `3`
|
|
26
|
-
@param {''|'small'|'medium'|'large'} [size=""] - Size of the input, Default: `""`
|
|
27
|
-
@param {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Color of the input, Default: `""`
|
|
26
|
+
@param {string|''|'small'|'medium'|'large'} [size=""] - Size of the input, Default: `""`
|
|
27
|
+
@param {string|''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Color of the input, Default: `""`
|
|
28
28
|
@param {string} [style=""] - Inline CSS for input container, Default: `""`
|
|
29
29
|
@param {boolean} [readonly=false] - Marks component as read-only, Default: `false`
|
|
30
30
|
@param {boolean} [disabled=false] - Disables the component, Default: `false`
|
|
@@ -132,8 +132,22 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
132
132
|
on:mousedown|preventDefault|stopPropagation={() =>
|
|
133
133
|
handleOptionMouseDown(option)}
|
|
134
134
|
on:mouseenter|preventDefault|stopPropagation={() => {
|
|
135
|
+
if (mouseTracker.preventSelect) return;
|
|
135
136
|
activeOption = option;
|
|
136
137
|
}}
|
|
138
|
+
on:mousemove|preventDefault|stopPropagation={(e) => {
|
|
139
|
+
let { preventSelect, lastX, lastY } = mouseTracker;
|
|
140
|
+
if (
|
|
141
|
+
preventSelect &&
|
|
142
|
+
(lastX !== e.clientX || lastY !== e.clientY)
|
|
143
|
+
) {
|
|
144
|
+
mouseTracker.preventSelect = false;
|
|
145
|
+
activeOption = option;
|
|
146
|
+
}
|
|
147
|
+
// mouse x,y is not in same position after the scrolling
|
|
148
|
+
mouseTracker.lastX = e.clientX;
|
|
149
|
+
mouseTracker.lastY = e.clientY;
|
|
150
|
+
}}
|
|
137
151
|
class="is-size-{list_text_size[size]}"
|
|
138
152
|
class:selected={isSelected(option)}
|
|
139
153
|
class:active={activeOption === option}>
|
|
@@ -164,7 +178,8 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
164
178
|
import { debounce } from "@kws3/ui/utils";
|
|
165
179
|
import { createEventDispatcher, onMount, tick } from "svelte";
|
|
166
180
|
import { createPopper } from "@popperjs/core";
|
|
167
|
-
import
|
|
181
|
+
import { makeSearchEngine } from "@kws3/ui/search";
|
|
182
|
+
import { scrollIntoActiveElement } from "../../internal";
|
|
168
183
|
|
|
169
184
|
const sameWidthPopperModifier = {
|
|
170
185
|
name: "sameWidth",
|
|
@@ -184,10 +199,16 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
184
199
|
|
|
185
200
|
const rootContainerId = "kws-overlay-root";
|
|
186
201
|
|
|
202
|
+
/**
|
|
203
|
+
* @typedef {import('@kws3/ui/types').ColorOptions} ColorOptions
|
|
204
|
+
* @typedef {import('@kws3/ui/types').SizeOptions} SizeOptions
|
|
205
|
+
*/
|
|
206
|
+
|
|
187
207
|
/**
|
|
188
208
|
* Value of the Input
|
|
189
209
|
*
|
|
190
210
|
* This property can be bound to, to fetch the current value
|
|
211
|
+
* @type {Array|?string}
|
|
191
212
|
*/
|
|
192
213
|
export let value = [];
|
|
193
214
|
/**
|
|
@@ -195,6 +216,7 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
195
216
|
*
|
|
196
217
|
* Accepts a `null` value for unlimited selected items.
|
|
197
218
|
* Or a number value
|
|
219
|
+
* @type {?number}
|
|
198
220
|
*/
|
|
199
221
|
export let max = null;
|
|
200
222
|
/**
|
|
@@ -230,22 +252,23 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
230
252
|
/**
|
|
231
253
|
* Filtered options to be displayed strictly based on search text or perform a fuzzy match.
|
|
232
254
|
* Fuzzy match will not work if `search` function is set, as the backend service is meant to do the matching.
|
|
233
|
-
* @type {'fuzzy'|'strict'}
|
|
255
|
+
* @type {string|'fuzzy'|'strict'}
|
|
234
256
|
*/
|
|
235
257
|
export let search_strategy = "fuzzy";
|
|
236
258
|
|
|
237
259
|
/**
|
|
238
260
|
* Score threshold for fuzzy search strategy, setting high score gives more fuzzy matches.
|
|
261
|
+
* @type {number}
|
|
239
262
|
*/
|
|
240
263
|
export let scoreThreshold = 3;
|
|
241
264
|
/**
|
|
242
265
|
* Size of the input
|
|
243
|
-
* @type {''
|
|
266
|
+
* @type {import('@kws3/ui/types').SizeOptions}
|
|
244
267
|
*/
|
|
245
268
|
export let size = "";
|
|
246
269
|
/**
|
|
247
270
|
* Color of the input
|
|
248
|
-
*
|
|
271
|
+
* @type {import('@kws3/ui/types').ColorOptions}
|
|
249
272
|
*/
|
|
250
273
|
export let color = "";
|
|
251
274
|
/**
|
|
@@ -326,6 +349,12 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
326
349
|
searchText = "",
|
|
327
350
|
searching = false,
|
|
328
351
|
showOptions = false,
|
|
352
|
+
mouseTracker = {
|
|
353
|
+
lastX: 0,
|
|
354
|
+
lastY: 0, // to check actual mouse is moving or not, for WebKit compatibility,
|
|
355
|
+
preventSelect: false, //prevent select by mouse when up or down key is pressed
|
|
356
|
+
},
|
|
357
|
+
fuzzysearch = null,
|
|
329
358
|
filteredOptions = [], //list of options filtered by search query
|
|
330
359
|
normalisedOptions = [], //list of options normalised
|
|
331
360
|
selectedOptions = [], //list of options that are selected
|
|
@@ -368,11 +397,15 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
368
397
|
$: activeOption, searchText, filteredOptions, updateActiveOption();
|
|
369
398
|
|
|
370
399
|
//TODO: optimise isSelected function
|
|
400
|
+
/** @type {(option: array)=> boolean}*/
|
|
371
401
|
$: isSelected = (option) => {
|
|
372
402
|
if (single) return matchesValue(value, option);
|
|
373
403
|
if (!(value && value.length > 0) || value === "") return false;
|
|
374
404
|
// nothing is selected if `value` is the empty array or string
|
|
375
|
-
else
|
|
405
|
+
else
|
|
406
|
+
return Array.isArray(value)
|
|
407
|
+
? value.some((v) => matchesValue(v, option))
|
|
408
|
+
: false;
|
|
376
409
|
};
|
|
377
410
|
|
|
378
411
|
$: singleVisibleValue =
|
|
@@ -407,7 +440,7 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
407
440
|
debouncedTriggerSearch(filter);
|
|
408
441
|
} else {
|
|
409
442
|
if (allow_fuzzy_match) {
|
|
410
|
-
|
|
443
|
+
fuzzySearch(filter, [...normalisedOptions]);
|
|
411
444
|
} else {
|
|
412
445
|
filteredOptions = strictSearch(filter, [...normalisedOptions]);
|
|
413
446
|
}
|
|
@@ -416,7 +449,11 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
416
449
|
|
|
417
450
|
function updateActiveOption() {
|
|
418
451
|
if (
|
|
419
|
-
(activeOption &&
|
|
452
|
+
(activeOption &&
|
|
453
|
+
searching &&
|
|
454
|
+
!filteredOptions.some(
|
|
455
|
+
(fo) => fo[used_value_key] === activeOption[used_value_key]
|
|
456
|
+
)) ||
|
|
420
457
|
(!activeOption && searchText)
|
|
421
458
|
) {
|
|
422
459
|
activeOption = filteredOptions[0];
|
|
@@ -446,11 +483,15 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
446
483
|
|
|
447
484
|
selectedOptions = _normalisedOptions
|
|
448
485
|
.filter(
|
|
449
|
-
(v) =>
|
|
486
|
+
(v) =>
|
|
487
|
+
Array.isArray(value) &&
|
|
488
|
+
value.some((vl) => `${v[used_value_key]}` === `${vl}`)
|
|
450
489
|
)
|
|
451
490
|
.sort(
|
|
452
491
|
(a, b) =>
|
|
453
|
-
value
|
|
492
|
+
// tweak for 'value is nullable' type error
|
|
493
|
+
(value ? value.indexOf(a[used_value_key]) : 0) -
|
|
494
|
+
(value ? value.indexOf(b[used_value_key]) : 0)
|
|
454
495
|
);
|
|
455
496
|
}
|
|
456
497
|
|
|
@@ -465,11 +506,13 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
465
506
|
return;
|
|
466
507
|
}
|
|
467
508
|
options_loading = true;
|
|
468
|
-
search
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
509
|
+
if (search !== null) {
|
|
510
|
+
search(filter).then((_options) => {
|
|
511
|
+
options = _options;
|
|
512
|
+
searching = false;
|
|
513
|
+
options_loading = false;
|
|
514
|
+
});
|
|
515
|
+
}
|
|
473
516
|
}
|
|
474
517
|
|
|
475
518
|
const debouncedTriggerSearch = debounce(triggerSearch, 150, false);
|
|
@@ -478,12 +521,25 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
478
521
|
POPPER = createPopper(el, dropdown, {
|
|
479
522
|
strategy: "fixed",
|
|
480
523
|
placement: "bottom-start",
|
|
524
|
+
// @ts-ignore
|
|
481
525
|
modifiers: [sameWidthPopperModifier],
|
|
482
526
|
});
|
|
483
527
|
|
|
484
|
-
if (allow_fuzzy_match
|
|
485
|
-
|
|
486
|
-
|
|
528
|
+
if (allow_fuzzy_match) {
|
|
529
|
+
let fuzzyOpts = {
|
|
530
|
+
analyzeSubTerms: true,
|
|
531
|
+
analyzeSubTermDepth: 10,
|
|
532
|
+
highlighting: {
|
|
533
|
+
after: "",
|
|
534
|
+
before: "",
|
|
535
|
+
},
|
|
536
|
+
};
|
|
537
|
+
let searchOptions = {
|
|
538
|
+
search_key: used_search_key,
|
|
539
|
+
scoreThreshold,
|
|
540
|
+
fuzzyOpts,
|
|
541
|
+
};
|
|
542
|
+
fuzzysearch = makeSearchEngine(searchOptions);
|
|
487
543
|
}
|
|
488
544
|
|
|
489
545
|
//normalize value for single versus multiselect
|
|
@@ -531,16 +587,20 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
531
587
|
setOptionsVisible(false);
|
|
532
588
|
}
|
|
533
589
|
|
|
534
|
-
if (
|
|
590
|
+
if (
|
|
591
|
+
!isAlreadySelected &&
|
|
592
|
+
!single &&
|
|
593
|
+
(max === null || (value && value.length < max))
|
|
594
|
+
) {
|
|
535
595
|
if (asyncMode) {
|
|
536
596
|
//Do not filter invalid options, as they are async and might not be invalid
|
|
537
597
|
//but ensure they are unique
|
|
538
|
-
value = [...value, token[used_value_key]].filter(
|
|
598
|
+
value = [...(value ? value : []), token[used_value_key]].filter(
|
|
539
599
|
(v, i, a) => a.indexOf(v) === i
|
|
540
600
|
);
|
|
541
601
|
} else {
|
|
542
602
|
//attach to value array while filtering out invalid values
|
|
543
|
-
value = [...value, token[used_value_key]].filter((v) => {
|
|
603
|
+
value = [...(value ? value : []), token[used_value_key]].filter((v) => {
|
|
544
604
|
return normalisedOptions.filter((nv) => nv[used_value_key] === v)
|
|
545
605
|
.length;
|
|
546
606
|
});
|
|
@@ -568,7 +628,7 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
568
628
|
|
|
569
629
|
function remove(token) {
|
|
570
630
|
if (readonly || disabled || single) return;
|
|
571
|
-
value = value
|
|
631
|
+
value = Array.isArray(value)
|
|
572
632
|
? value.filter((item) => !matchesValue(item, token))
|
|
573
633
|
: value;
|
|
574
634
|
|
|
@@ -633,6 +693,14 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
633
693
|
activeOption = filteredOptions[0];
|
|
634
694
|
else activeOption = filteredOptions[newActiveIdx];
|
|
635
695
|
}
|
|
696
|
+
|
|
697
|
+
tick().then(() => {
|
|
698
|
+
if (dropdown) {
|
|
699
|
+
mouseTracker.preventSelect = true;
|
|
700
|
+
let activeElem = dropdown.querySelector(".active");
|
|
701
|
+
scrollIntoActiveElement(dropdown, activeElem);
|
|
702
|
+
}
|
|
703
|
+
});
|
|
636
704
|
} else if (event.key === `Backspace`) {
|
|
637
705
|
if (single && hasValue) {
|
|
638
706
|
//for a single select
|
|
@@ -716,27 +784,16 @@ Default value: `<span>{option[search_key] || option}</span>`
|
|
|
716
784
|
});
|
|
717
785
|
};
|
|
718
786
|
|
|
719
|
-
|
|
720
|
-
if (!filter) return options;
|
|
721
|
-
if (options.length) {
|
|
722
|
-
let OPTS = options.map((item) => {
|
|
723
|
-
let output = fuzzy(item[used_search_key], filter);
|
|
724
|
-
item = { ...output, original: item };
|
|
725
|
-
item.score =
|
|
726
|
-
!item.score || (item.score && item.score < output.score)
|
|
727
|
-
? output.score
|
|
728
|
-
: item.score || 0;
|
|
729
|
-
return item;
|
|
730
|
-
});
|
|
787
|
+
const fuzzySearch = debounce(searchInFuzzyMode, 200, false);
|
|
731
788
|
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
789
|
+
function searchInFuzzyMode(filter, options) {
|
|
790
|
+
if (!filter) {
|
|
791
|
+
filteredOptions = options;
|
|
792
|
+
return;
|
|
793
|
+
}
|
|
794
|
+
if (options.length) {
|
|
795
|
+
let result = fuzzysearch(filter, options);
|
|
796
|
+
filteredOptions = result;
|
|
740
797
|
}
|
|
741
798
|
}
|
|
742
799
|
|