@kws3/ui 1.7.4 → 1.8.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
+ ## 1.8.0
2
+ - `Modal`, `CardModal` and `ActionSheet` components now play an outro transition instead of abruptly disappearing.
3
+ - Usability fixes for `SearchableSelect` and `MultiSelect`.
4
+ - `SearchableSelect` and `MultiSelect` now support loading options via an async function.
5
+ - `SearchableSelect` and `MultiSelect` now match results using a fuzzy `search_strategy`. This can be changed to old behaviour by specifying `search_strategy="strict"`.
6
+
1
7
  ## 1.7.4
2
8
  - Update ApexCharts to version 3.33.2
3
9
  - Added support for subscribing to chart events
@@ -28,7 +28,6 @@
28
28
  <p class="control">
29
29
  {#if _confirm}
30
30
  <button
31
- role="button"
32
31
  class="button is-success is-light is-shadowless is-{size} {button_class}"
33
32
  type="button"
34
33
  on:click|preventDefault|stopPropagation={cancel}>
@@ -38,7 +37,6 @@
38
37
  </p>
39
38
  <p class="control is-expanded">
40
39
  <button
41
- role="button"
42
40
  class="button is-{size} {_doing
43
41
  ? main_color + ' is-loading'
44
42
  : _error
@@ -28,7 +28,6 @@ This will be overridden if `min` is higher, or `max` is lower, Default: `0`
28
28
  <div class="field has-addons">
29
29
  <div class="control">
30
30
  <button
31
- role="button"
32
31
  type="button"
33
32
  class="button is-{size} is-{minus_button_color}"
34
33
  style="box-shadow:none;"
@@ -58,7 +57,6 @@ This will be overridden if `min` is higher, or `max` is lower, Default: `0`
58
57
  </div>
59
58
  <div class="control">
60
59
  <button
61
- role="button"
62
60
  type="button"
63
61
  class="button is-{size} is-{plus_button_color}"
64
62
  style="box-shadow:none;"
@@ -16,6 +16,12 @@ Used to populate the list of options in the dropdown, Default: `[]`
16
16
  this property of each object will be searched, Default: `"name"`
17
17
  @param {string} [value_key="id"] - If `options` is an array of objects,
18
18
  this property of each object will be returned as the value, Default: `"id"`
19
+ @param {function|null} [search=null] - Async function to fetch options
20
+
21
+ Only send this prop if you want to fetch `options` asynchronously.
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.
24
+ Fuzzy match will not work if `search` function is set, as the backend service is meant to do the matching., Default: `"fuzzy"`
19
25
  @param {''|'small'|'medium'|'large'} [size=""] - Size of the input, Default: `""`
20
26
  @param {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Color of the input, Default: `""`
21
27
  @param {string} [style=""] - Inline CSS for input container, Default: `""`
@@ -24,6 +30,7 @@ this property of each object will be returned as the value, Default: `"id"`
24
30
  @param {string} [selected_icon="check"] - Icon used to mark selected items in dropdown list, Default: `"check"`
25
31
  @param {boolean} [summary_mode=false] - Shows only the number of items selected, instead of listing all the selected items in the input., Default: `false`
26
32
  @param {string} [no_options_msg="No matching options"] - Message to display when no matching options are found, Default: `"No matching options"`
33
+ @param {string} [async_search_prompt="Start typing to search..."] - Message to display in dropdown when async search can be performed, Default: `"Start typing to search..."`
27
34
  @param {string} [remove_btn_tip="Remove"] - Tooltip text for Remove Item button. This `string` will precede the selected Item Name in the tooltip., Default: `"Remove"`
28
35
  @param {string} [remove_all_tip="Remove all"] - Tooltip text for the Clear All button, Default: `"Remove all"`
29
36
  @param {HTMLElement|string} [dropdown_portal=undefined] - Where to render the dropdown list.
@@ -75,7 +82,6 @@ Default value: `<span>{option[search_key] || option}</span>`
75
82
  {#if !readonly && !disabled}
76
83
  <button
77
84
  on:click|self|stopPropagation={() => remove(tag)}
78
- role="button"
79
85
  type="button"
80
86
  class="delete is-small"
81
87
  data-tooltip="{remove_btn_tip} {tag[used_search_key]}" />
@@ -84,6 +90,7 @@ Default value: `<span>{option[search_key] || option}</span>`
84
90
  {/each}
85
91
  {/if}
86
92
  {/if}
93
+ {#if single}<span>{singleVisibleValue}</span>{/if}
87
94
  <input
88
95
  class="input is-{size}"
89
96
  bind:this={input}
@@ -98,9 +105,13 @@ Default value: `<span>{option[search_key] || option}</span>`
98
105
  on:blur={() => setOptionsVisible(false)}
99
106
  placeholder={_placeholder} />
100
107
  </ul>
101
- {#if !readonly && !disabled}
108
+ {#if search && options_loading}
109
+ <button
110
+ type="button"
111
+ style="border: none;"
112
+ class="button is-paddingless delete is-medium is-loading" />
113
+ {:else if !readonly && !disabled}
102
114
  <button
103
- role="button"
104
115
  type="button"
105
116
  class="remove-all delete is-small"
106
117
  data-tooltip={remove_all_tip}
@@ -133,7 +144,11 @@ Default value: `<span>{option[search_key] || option}</span>`
133
144
  {option}>{option[used_search_key] || option}</slot>
134
145
  </li>
135
146
  {:else}
136
- <li class="no-options">{no_options_msg}</li>
147
+ {#if !options_loading}
148
+ <li class="no-options">
149
+ {searchText ? no_options_msg : async_search_prompt}
150
+ </li>
151
+ {/if}
137
152
  {/each}
138
153
  </ul>
139
154
  </div>
@@ -142,8 +157,10 @@ Default value: `<span>{option[search_key] || option}</span>`
142
157
 
143
158
  <script>
144
159
  import { Icon, portal } from "@kws3/ui";
145
- import { createEventDispatcher, onMount } from "svelte";
160
+ import { debounce } from "@kws3/ui/utils";
161
+ import { createEventDispatcher, onMount, tick } from "svelte";
146
162
  import { createPopper } from "@popperjs/core";
163
+ import fuzzysearch from "fuzzysearch";
147
164
 
148
165
  const sameWidthPopperModifier = {
149
166
  name: "sameWidth",
@@ -196,6 +213,22 @@ Default value: `<span>{option[search_key] || option}</span>`
196
213
  * this property of each object will be returned as the value
197
214
  */
198
215
  export let value_key = "id";
216
+ /**
217
+ * Async function to fetch options
218
+ *
219
+ * Only send this prop if you want to fetch `options` asynchronously.
220
+ * `options` prop will be ignored if this prop is set.
221
+ *
222
+ * @type {function|null}
223
+ */
224
+ export let search = null;
225
+
226
+ /**
227
+ * Filtered options to be displayed strictly based on search text or perform a fuzzy match.
228
+ * Fuzzy match will not work if `search` function is set, as the backend service is meant to do the matching.
229
+ * @type {'fuzzy'|'strict'}
230
+ */
231
+ export let search_strategy = "fuzzy";
199
232
  /**
200
233
  * Size of the input
201
234
  * @type {''|'small'|'medium'|'large'}
@@ -230,6 +263,10 @@ Default value: `<span>{option[search_key] || option}</span>`
230
263
  * Message to display when no matching options are found
231
264
  */
232
265
  export let no_options_msg = "No matching options";
266
+ /**
267
+ * Message to display in dropdown when async search can be performed
268
+ */
269
+ export let async_search_prompt = "Start typing to search...";
233
270
  /**
234
271
  * Tooltip text for Remove Item button. This `string` will precede the selected Item Name in the tooltip.
235
272
  * */
@@ -254,7 +291,8 @@ Default value: `<span>{option[search_key] || option}</span>`
254
291
  let klass = "";
255
292
  export { klass as class };
256
293
 
257
- if (!options || !options.length) console.error(`Missing options`);
294
+ if (!search && (!options || !options.length))
295
+ console.error(`Missing options`);
258
296
 
259
297
  if (max !== null && max < 0) {
260
298
  throw new TypeError(`max must be null or positive integer, got ${max}`);
@@ -281,9 +319,11 @@ Default value: `<span>{option[search_key] || option}</span>`
281
319
  showOptions = false,
282
320
  filteredOptions = [], //list of options filtered by search query
283
321
  normalisedOptions = [], //list of options normalised
284
- selectedOptions = []; //list of options that are selected
322
+ selectedOptions = [], //list of options that are selected
323
+ options_loading = false; //indictaes whether async search function is running
285
324
 
286
325
  $: single = max === 1;
326
+ $: asyncMode = search && typeof search === "function";
287
327
  $: hasValue = single
288
328
  ? value !== null && typeof value != "undefined"
289
329
  ? true
@@ -324,6 +364,13 @@ Default value: `<span>{option[search_key] || option}</span>`
324
364
  else return value.some((v) => matchesValue(v, option));
325
365
  };
326
366
 
367
+ $: singleVisibleValue =
368
+ !searching && single && hasValue && selectedOptions && selectedOptions[0]
369
+ ? selectedOptions[0][used_search_key]
370
+ : "";
371
+
372
+ $: allow_fuzzy_match = !search && search_strategy === "fuzzy";
373
+
327
374
  //convert arrays of strings into normalised arrays of objects
328
375
  function normaliseOptions() {
329
376
  let _items = options || [];
@@ -332,15 +379,7 @@ Default value: `<span>{option[search_key] || option}</span>`
332
379
  return;
333
380
  }
334
381
 
335
- normalisedOptions = _items.slice().map((item) => {
336
- if (typeof item === "object") {
337
- return item;
338
- }
339
- let __obj = {};
340
- __obj[used_search_key] = item;
341
- __obj[used_value_key] = item;
342
- return __obj;
343
- });
382
+ normalisedOptions = normaliseArraysToObjects(_items);
344
383
  }
345
384
 
346
385
  function updateFilteredOptions() {
@@ -353,29 +392,27 @@ Default value: `<span>{option[search_key] || option}</span>`
353
392
  } else {
354
393
  filter = searchText.toLowerCase();
355
394
  }
356
-
357
- filteredOptions = normalisedOptions.slice().filter((item) => {
358
- // filter out items that don't match `filter`
359
- if (typeof item === "object") {
360
- if (used_search_key) {
361
- if (
362
- typeof item[used_search_key] === "string" &&
363
- item[used_search_key].toLowerCase().indexOf(filter) > -1
364
- )
365
- return true;
366
- } else {
367
- for (var key in item) {
368
- if (
369
- typeof item[key] === "string" &&
370
- item[key].toLowerCase().indexOf(filter) > -1
371
- )
372
- return true;
395
+ if (asyncMode && searching) {
396
+ debouncedTriggerSearch(filter);
397
+ } else {
398
+ filteredOptions = normalisedOptions.slice().filter((item) => {
399
+ // filter out items that don't match `filter`
400
+ if (typeof item === "object") {
401
+ if (used_search_key) {
402
+ return (
403
+ typeof item[used_search_key] === "string" &&
404
+ match(filter, item[used_search_key])
405
+ );
406
+ } else {
407
+ for (var key in item) {
408
+ return typeof item[key] === "string" && match(filter, item[key]);
409
+ }
373
410
  }
411
+ } else {
412
+ return match(filter, item);
374
413
  }
375
- } else {
376
- return item.toLowerCase().indexOf(filter) > -1;
377
- }
378
- });
414
+ });
415
+ }
379
416
  }
380
417
 
381
418
  function fillSelectedOptions() {
@@ -383,9 +420,17 @@ Default value: `<span>{option[search_key] || option}</span>`
383
420
  selectedOptions = normalisedOptions.filter(
384
421
  (v) => `${v[used_value_key]}` === `${value}`
385
422
  );
386
- setSingleVisibleValue();
387
423
  } else {
388
- selectedOptions = normalisedOptions
424
+ let _normalisedOptions = asyncMode
425
+ ? [...selectedOptions, ...normalisedOptions].filter(
426
+ //de-dupe by `used_value_key` when in asyncMode
427
+ (value, idx, self) =>
428
+ idx ===
429
+ self.findIndex((v) => v[used_value_key] === value[used_value_key])
430
+ )
431
+ : normalisedOptions;
432
+
433
+ selectedOptions = _normalisedOptions
389
434
  .filter(
390
435
  (v) => value && value.some((vl) => `${v[used_value_key]}` === `${vl}`)
391
436
  )
@@ -398,6 +443,23 @@ Default value: `<span>{option[search_key] || option}</span>`
398
443
  POPPER && POPPER.update();
399
444
  }
400
445
 
446
+ function triggerSearch(filter) {
447
+ if (filter === "") {
448
+ //do not trigger async search if filter is empty
449
+ options = [];
450
+ searching = false;
451
+ return;
452
+ }
453
+ options_loading = true;
454
+ search(filter).then((_options) => {
455
+ options = _options;
456
+ searching = false;
457
+ options_loading = false;
458
+ });
459
+ }
460
+
461
+ const debouncedTriggerSearch = debounce(triggerSearch, 150, false);
462
+
401
463
  onMount(() => {
402
464
  POPPER = createPopper(el, dropdown, {
403
465
  strategy: "fixed",
@@ -406,10 +468,25 @@ Default value: `<span>{option[search_key] || option}</span>`
406
468
  });
407
469
 
408
470
  //normalize value for single versus multiselect
409
- if (value === null || typeof value == "undefined")
471
+ if (value === null || typeof value == "undefined") {
410
472
  value = single ? null : [];
473
+ }
411
474
 
412
- setSingleVisibleValue();
475
+ if (asyncMode) {
476
+ // initally on async mode options are empty
477
+ // so we need to fill selectedOptions with value if value is avaliable
478
+ options = value ? [...(single ? [value] : [...value])] : [];
479
+ searching = false;
480
+ tick().then(() => {
481
+ normaliseOptions();
482
+ value = normaliseArraysToObjects(options).map((v) => v[used_value_key]);
483
+ if (single && Array.isArray(value)) {
484
+ value = value[0];
485
+ }
486
+ fillSelectedOptions();
487
+ clearDropDownResults();
488
+ });
489
+ }
413
490
 
414
491
  return () => {
415
492
  POPPER.destroy();
@@ -424,24 +501,39 @@ Default value: `<span>{option[search_key] || option}</span>`
424
501
  let isAlreadySelected = isSelected(token);
425
502
 
426
503
  if (single) {
427
- if (isAlreadySelected) {
428
- setSingleVisibleValue();
429
- } else {
504
+ if (!isAlreadySelected) {
430
505
  value = token[used_value_key];
431
- input && input.blur();
432
- setOptionsVisible(false);
433
506
  fire("change", { token, type: `add` });
507
+ //clear dropdown results in asyncMode
508
+ if (asyncMode) {
509
+ clearDropDownResults();
510
+ }
434
511
  }
512
+ setOptionsVisible(false);
435
513
  }
436
514
 
437
515
  if (!isAlreadySelected && !single && (max === null || value.length < max)) {
438
- //attach to value array while filtering out invalid values
439
- value = [...value, token[used_value_key]].filter((v) => {
440
- return normalisedOptions.filter((nv) => nv[used_value_key] === v)
441
- .length;
442
- });
516
+ if (asyncMode) {
517
+ //Do not filter invalid options, as they are async and might not be invalid
518
+ //but ensure they are unique
519
+ value = [...value, token[used_value_key]].filter(
520
+ (v, i, a) => a.indexOf(v) === i
521
+ );
522
+ } else {
523
+ //attach to value array while filtering out invalid values
524
+ value = [...value, token[used_value_key]].filter((v) => {
525
+ return normalisedOptions.filter((nv) => nv[used_value_key] === v)
526
+ .length;
527
+ });
528
+ }
529
+
443
530
  searchText = ""; // reset search string on selection
444
531
 
532
+ //clear dropdown results in asyncMode
533
+ if (asyncMode) {
534
+ clearDropDownResults();
535
+ }
536
+
445
537
  if (value && value.length && value.length === max) {
446
538
  input && input.blur();
447
539
  setOptionsVisible(false);
@@ -460,6 +552,11 @@ Default value: `<span>{option[search_key] || option}</span>`
460
552
  value = value.filter
461
553
  ? value.filter((item) => !matchesValue(item, token))
462
554
  : value;
555
+
556
+ //clear dropdown results in asyncMode
557
+ if (asyncMode) {
558
+ clearDropDownResults();
559
+ }
463
560
  /**
464
561
  * Triggered when an item is removed from selected Items
465
562
  */
@@ -483,25 +580,16 @@ Default value: `<span>{option[search_key] || option}</span>`
483
580
  showOptions = show;
484
581
  if (show) {
485
582
  input && input.focus();
486
- }
487
- POPPER && POPPER.update();
488
- }
489
-
490
- function setSingleVisibleValue() {
491
- if (single && hasValue) {
492
- searchText =
493
- selectedOptions && selectedOptions[0]
494
- ? selectedOptions[0][used_search_key]
495
- : "";
583
+ } else {
584
+ searchText = "";
496
585
  searching = false;
497
586
  }
587
+ POPPER && POPPER.update();
498
588
  }
499
589
 
500
590
  function handleKeydown(event) {
501
591
  if (event.key === `Escape`) {
502
- if (!single) {
503
- searchText = "";
504
- }
592
+ searchText = "";
505
593
  } else {
506
594
  setOptionsVisible(true);
507
595
  }
@@ -510,9 +598,6 @@ Default value: `<span>{option[search_key] || option}</span>`
510
598
  event.preventDefault();
511
599
  if (activeOption) {
512
600
  handleOptionMouseDown(activeOption);
513
- if (!single) {
514
- searchText = "";
515
- }
516
601
  } else {
517
602
  // no active option means the options are closed in which case enter means open
518
603
  setOptionsVisible(true);
@@ -529,24 +614,31 @@ Default value: `<span>{option[search_key] || option}</span>`
529
614
  else activeOption = filteredOptions[newActiveIdx];
530
615
  }
531
616
  } else if (event.key === `Backspace`) {
532
- // only remove selected tags on backspace if there are any and no searchText characters remain
533
- if (searchText.length === 0) {
534
- if (single) {
535
- if (value) {
536
- value = null;
537
- }
538
- } else {
539
- if (value && value.length > 0) {
540
- value = value.slice(0, value.length - 1);
541
- }
617
+ if (single && hasValue) {
618
+ //for a single select
619
+ //if a value is already selected, backspace will clear the value
620
+ value = null;
621
+ searchText = "";
622
+ } else if (!single && searchText.length === 0) {
623
+ //for a multi select
624
+ // only remove selected tags on backspace if there are any and no searchText characters remain
625
+ if (value && value.length > 0) {
626
+ value = value.slice(0, value.length - 1);
542
627
  }
543
628
  } else {
544
- if (single) {
545
- searching = true;
546
- }
629
+ searching = true;
547
630
  }
548
631
  } else {
632
+ //for a single select
633
+ //if a value is already selected,
634
+ //ignore keys other than navigation, enter and backspace
549
635
  if (single) {
636
+ if (hasValue) {
637
+ event.preventDefault();
638
+ } else {
639
+ searching = true;
640
+ }
641
+ } else {
550
642
  searching = true;
551
643
  }
552
644
  }
@@ -565,6 +657,9 @@ Default value: `<span>{option[search_key] || option}</span>`
565
657
  fire("change", { token: value, type: `remove` });
566
658
  value = single ? null : [];
567
659
  searchText = "";
660
+ if (asyncMode) {
661
+ clearDropDownResults();
662
+ }
568
663
  };
569
664
 
570
665
  const matchesValue = (_value, _option) => {
@@ -575,4 +670,30 @@ Default value: `<span>{option[search_key] || option}</span>`
575
670
  `${_value[used_value_key] || _value}` === `${_option[used_value_key]}`
576
671
  );
577
672
  };
673
+
674
+ const match = (needle, haystack) => {
675
+ let _hayStack = haystack.toLowerCase();
676
+ return allow_fuzzy_match
677
+ ? fuzzysearch(needle, _hayStack)
678
+ : _hayStack.indexOf(needle) > -1;
679
+ };
680
+
681
+ const normaliseArraysToObjects = (arr) => {
682
+ return arr.slice().map((item) => {
683
+ if (typeof item === "object") {
684
+ return item;
685
+ }
686
+ let __obj = {};
687
+ __obj[used_search_key] = item;
688
+ __obj[used_value_key] = item;
689
+ return __obj;
690
+ });
691
+ };
692
+
693
+ const clearDropDownResults = () => {
694
+ tick().then(() => {
695
+ options = [];
696
+ searching = false;
697
+ });
698
+ };
578
699
  </script>
@@ -16,9 +16,16 @@ this property of each object will be returned as the value, Default: `"id"`
16
16
  @param {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Color of the input, Default: `""`
17
17
  @param {string} [style=""] - Inline CSS for input container, Default: `""`
18
18
  @param {boolean} [readonly=false] - Marks component as read-only, Default: `false`
19
+ @param {function|null} [search=null] - Async function to fetch options
20
+
21
+ Only send this prop if you want to fetch `options` asynchronously.
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.
24
+ Fuzzy match will not work if `search` function is set, as the backend service is meant to do the matching., Default: `"fuzzy"`
19
25
  @param {boolean} [disabled=false] - Disables the component, Default: `false`
20
26
  @param {string} [selected_icon="check"] - Icon used to mark selected items in dropdown list, Default: `"check"`
21
27
  @param {string} [no_options_msg="No matching options"] - Message to display when no matching options are found, Default: `"No matching options"`
28
+ @param {string} [async_search_prompt="Start typing to search..."] - Message to display in dropdown when async search can be performed, Default: `"Start typing to search..."`
22
29
  @param {string} [remove_all_tip="Clear Selection"] - Tooltip text for the Clear selection button, Default: `"Clear Selection"`
23
30
  @param {HTMLElement|string} [dropdown_portal=undefined] - Where to render the dropdown list.
24
31
  Can be a DOM element or a `string` with the CSS selector of the element.
@@ -44,13 +51,16 @@ Default value: `<span>{option[search_key] || option}</span>`
44
51
  {options}
45
52
  {search_key}
46
53
  {value_key}
54
+ {search_strategy}
47
55
  {size}
48
56
  {color}
49
57
  {style}
50
58
  {readonly}
51
59
  {disabled}
60
+ {search}
52
61
  {selected_icon}
53
62
  {remove_all_tip}
63
+ async_search_prompt={value ? "Backspace to clear" : async_search_prompt}
54
64
  {no_options_msg}
55
65
  {dropdown_portal}
56
66
  on:change={change}
@@ -118,6 +128,21 @@ Default value: `<span>{option[search_key] || option}</span>`
118
128
  * Marks component as read-only
119
129
  */
120
130
  export let readonly = false;
131
+ /**
132
+ * Async function to fetch options
133
+ *
134
+ * Only send this prop if you want to fetch `options` asynchronously.
135
+ * `options` prop will be ignored if this prop is set.
136
+ *
137
+ * @type {function|null}
138
+ */
139
+ export let search = null;
140
+ /**
141
+ * Filtered options to be displayed strictly based on search text or perform a fuzzy match.
142
+ * Fuzzy match will not work if `search` function is set, as the backend service is meant to do the matching.
143
+ * @type {'fuzzy'|'strict'}
144
+ */
145
+ export let search_strategy = "fuzzy";
121
146
  /**
122
147
  * Disables the component
123
148
  */
@@ -130,6 +155,10 @@ Default value: `<span>{option[search_key] || option}</span>`
130
155
  * Message to display when no matching options are found
131
156
  */
132
157
  export let no_options_msg = "No matching options";
158
+ /**
159
+ * Message to display in dropdown when async search can be performed
160
+ */
161
+ export let async_search_prompt = "Start typing to search...";
133
162
  /**
134
163
  * Tooltip text for the Clear selection button
135
164
  */
@@ -19,7 +19,9 @@ If `false` , the component won't have a close button, and will not close on clic
19
19
 
20
20
  -->
21
21
 
22
- <div class="modal {klass} {is_active ? 'is-active' : ''}" {style}>
22
+ <div
23
+ class="modal kws-action-sheet-outer {klass} {is_active ? 'is-active' : ''}"
24
+ {style}>
23
25
  {#if is_active}<div
24
26
  transition:fade={{ duration: transitionDuration }}
25
27
  class="modal-background"
@@ -34,7 +34,6 @@ Only visible when the
34
34
  transition:fade={{ duration: transitionDuration }}
35
35
  class="modal-background"
36
36
  on:click={clickOutside} />
37
-
38
37
  <div
39
38
  transition:scale={{
40
39
  duration: transitionDuration,
@@ -83,6 +82,17 @@ Only visible when the
83
82
  </div>
84
83
 
85
84
  <style lang="scss">
85
+ .modal {
86
+ display: flex;
87
+ visibility: hidden;
88
+ &.is-active {
89
+ visibility: visible;
90
+ }
91
+ .modal-card,
92
+ .modal-background {
93
+ transition: all 0.3s;
94
+ }
95
+ }
86
96
  @media screen and (min-width: 769px), print {
87
97
  .modal-card {
88
98
  min-width: 640px;
@@ -12,6 +12,8 @@ function createDialog(msg, props) {
12
12
 
13
13
  dialog.$on("_done", ({ detail }) => {
14
14
  fulfil(detail);
15
+ //Does not outro out because of
16
+ //https://github.com/sveltejs/svelte/issues/4056
15
17
  dialog.$destroy();
16
18
  });
17
19
  });
@@ -26,7 +26,6 @@ Only programmatic closing is possible, Default: `true`
26
26
  transition:fade={{ duration: transitionDuration }}
27
27
  class="modal-background"
28
28
  on:click={clickOutside} />
29
-
30
29
  <div
31
30
  transition:scale={{
32
31
  duration: transitionDuration,
@@ -47,9 +46,19 @@ Only programmatic closing is possible, Default: `true`
47
46
  </div>
48
47
 
49
48
  <style lang="scss">
50
- @media screen and (min-width: 769px), print {
49
+ .modal {
50
+ display: flex;
51
+ visibility: hidden;
52
+ &.is-active {
53
+ visibility: visible;
54
+ }
51
55
  .modal-content,
52
- .modal-card {
56
+ .modal-background {
57
+ transition: all 0.3s;
58
+ }
59
+ }
60
+ @media screen and (min-width: 769px), print {
61
+ .modal-content {
53
62
  min-width: 640px;
54
63
  &.is-medium {
55
64
  width: 70%;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kws3/ui",
3
- "version": "1.7.4",
3
+ "version": "1.8.0",
4
4
  "description": "UI components for use with Svelte v3 applications.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -25,9 +25,10 @@
25
25
  "dependencies": {
26
26
  "apexcharts": "3.33.2",
27
27
  "flatpickr": "^4.5.2",
28
+ "fuzzysearch": "^1.0.3",
28
29
  "svelte-portal": "^2.1.2",
29
30
  "text-mask-core": "^5.1.2",
30
31
  "tippy.js": "^6.3.1"
31
32
  },
32
- "gitHead": "fefd40197784db6665d8f74c358931cc5e8becaf"
33
+ "gitHead": "8da0698c240f93ae1b371a9279d2473409646b10"
33
34
  }
@@ -2,6 +2,16 @@ $kws-actionsheet-background: $background !default;
2
2
  $kws-actionsheet-box-shadow: $card-shadow !default;
3
3
  $kws-actionsheet-box-radius: $radius !default;
4
4
 
5
+ .kws-action-sheet-outer {
6
+ display: flex;
7
+ visibility: hidden;
8
+ &.is-active {
9
+ visibility: visible;
10
+ }
11
+ .modal-background {
12
+ transition: all 0.3s;
13
+ }
14
+ }
5
15
  .kws-action-sheet {
6
16
  border-radius: $kws-actionsheet-box-radius $kws-actionsheet-box-radius 0 0;
7
17
  box-shadow: $kws-actionsheet-box-shadow;