@kws3/ui 1.9.2 → 2.0.1

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.
Files changed (81) hide show
  1. package/CHANGELOG.mdx +74 -48
  2. package/buttons/ConfirmButton.svelte +11 -3
  3. package/buttons/DeleteButton.svelte +2 -3
  4. package/buttons/ProcessButton.svelte +3 -4
  5. package/buttons/SubmitButton.svelte +11 -3
  6. package/charts/AreaChart.svelte +1 -1
  7. package/charts/BarChart.svelte +1 -1
  8. package/charts/Chart.svelte +1 -0
  9. package/charts/DonutChart.svelte +1 -1
  10. package/charts/LineChart.svelte +1 -1
  11. package/charts/MixedChart.svelte +1 -1
  12. package/charts/PieChart.svelte +1 -1
  13. package/charts/RadialChart.svelte +1 -1
  14. package/charts/utils.js +1 -0
  15. package/controls/Checkbox.svelte +10 -4
  16. package/controls/FileUpload.svelte +14 -8
  17. package/controls/NumberInput.svelte +19 -10
  18. package/controls/Radio.svelte +8 -2
  19. package/controls/RangeSlider.svelte +8 -2
  20. package/controls/Toggle.svelte +9 -2
  21. package/controls/ToggleButtons.svelte +10 -3
  22. package/datagrid/DataSearch/DataSearch.svelte +1 -1
  23. package/datagrid/GridView/GridCell.svelte +3 -0
  24. package/datagrid/GridView/GridRow.svelte +15 -0
  25. package/datagrid/GridView/GridView.svelte +21 -3
  26. package/datagrid/Pagination/Pagination.svelte +3 -3
  27. package/datagrid/TileView/TileView.svelte +46 -5
  28. package/datagrid/TileView/TileViewItem.svelte +4 -0
  29. package/form/index.js +160 -0
  30. package/forms/AutoComplete.svelte +78 -33
  31. package/forms/Datepicker.svelte +22 -5
  32. package/forms/PasswordValidator/PasswordValidator.svelte +8 -8
  33. package/forms/PasswordValidator/validatePassword.js +13 -2
  34. package/forms/SearchInput.svelte +180 -0
  35. package/forms/Timepicker.svelte +69 -4
  36. package/forms/actions.js +21 -15
  37. package/forms/colorpicker/Colorpicker.js +28 -3
  38. package/forms/colorpicker/Colorpicker.svelte +2 -2
  39. package/forms/select/MultiSelect.svelte +89 -30
  40. package/forms/select/SearchableSelect.svelte +6 -5
  41. package/helpers/CardModal.svelte +2 -1
  42. package/helpers/ClipboardCopier.svelte +4 -1
  43. package/helpers/Dialog/Dialog.svelte +13 -8
  44. package/helpers/Dialog/index.js +6 -0
  45. package/helpers/Divider.svelte +2 -2
  46. package/helpers/FloatingUI/Floatie.svelte +6 -6
  47. package/helpers/FloatingUI/index.js +2 -1
  48. package/helpers/Icon.svelte +25 -9
  49. package/helpers/Loader.svelte +10 -3
  50. package/helpers/Message.svelte +2 -2
  51. package/helpers/Modal.svelte +2 -1
  52. package/helpers/Notification.svelte +1 -1
  53. package/helpers/Popover.svelte +4 -4
  54. package/helpers/ScrollableList.svelte +12 -8
  55. package/helpers/Skeleton.svelte +4 -1
  56. package/helpers/Timeline/Timeline.svelte +1 -1
  57. package/helpers/Timeline/TimelineItem.svelte +5 -5
  58. package/helpers/Tooltip.js +1 -1
  59. package/index.js +10 -4
  60. package/{utils → internal}/fuzzy.js +64 -65
  61. package/internal/index.js +27 -0
  62. package/internal/scrollIntoActiveElement.js +22 -0
  63. package/keyboard/index.js +94 -0
  64. package/package.json +6 -3
  65. package/{utils/resizeObserver.js → resizeObserver/index.js} +0 -0
  66. package/search/index.js +52 -0
  67. package/settings.js +1 -1
  68. package/sliding-panes/SlidingPane.svelte +1 -4
  69. package/styles/AutoComplete.scss +2 -1
  70. package/styles/Datepicker.scss +1 -1
  71. package/styles/Grid.scss +14 -0
  72. package/styles/Pagination.scss +8 -5
  73. package/styles/Select.scss +2 -1
  74. package/transitions/components/Scale.svelte +1 -0
  75. package/transitions/components/getEasing.js +18 -5
  76. package/types/ambient.d.ts +16 -0
  77. package/types/index.d.ts +46 -0
  78. package/types/type-defs/index.ts +14 -0
  79. package/utils/index.js +110 -9
  80. package/utils/fuzzysearch.js +0 -42
  81. package/utils/keyboard-events.js +0 -32
@@ -10,7 +10,6 @@
10
10
  @param {boolean} [light=false] - Inverted colors for notification box and contents, Default: `false`
11
11
  @param {boolean} [dismissable=true] - Determines if notification is dismissable, Default: `true`
12
12
  @param {boolean} [persistent=false] - A persistent notification without duration, stays till dismissed, Default: `false`
13
- @param {string} [context=""] - Context value, Default: `""`
14
13
  @param {object} [component=null] - Custom component, Default: `null`
15
14
  @param {function} [beforeClose(props)] - Callback function call before close event
16
15
  @param {function} [afterClose(props)] - Callback function call after close event
@@ -66,6 +65,10 @@
66
65
 
67
66
  const fire = createEventDispatcher();
68
67
 
68
+ /**
69
+ * @typedef {import('@kws3/ui/types').ColorOptions} ColorOptions
70
+ */
71
+
69
72
  /**
70
73
  * Title/Heading of the notification
71
74
  */
@@ -85,7 +88,7 @@
85
88
  duration = 3000,
86
89
  /**
87
90
  * Toast notification background color
88
- * @type {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'}
91
+ * @type {ColorOptions}
89
92
  */
90
93
  color = "primary",
91
94
  /**
@@ -100,10 +103,6 @@
100
103
  * A persistent notification without duration, stays till dismissed
101
104
  */
102
105
  persistent = false,
103
- /**
104
- * Context value
105
- */
106
- context = "",
107
106
  /**
108
107
  * Custom component
109
108
  */
@@ -131,6 +130,7 @@
131
130
  let defaults = { text: "Ok", color: "", click: () => {} },
132
131
  obj = b;
133
132
  if (typeof b == "string") {
133
+ // @ts-ignore
134
134
  obj = { text: b };
135
135
  }
136
136
  return Object.assign({}, defaults, obj);
@@ -1,4 +1,4 @@
1
- import { FloatingUIOutput } from "@kws3/ui";
1
+ import FloatingUIOutput from "./FloatingUIOutput.svelte";
2
2
  import { writable, get } from "svelte/store";
3
3
  import {
4
4
  defaultToastPlacement,
@@ -19,6 +19,7 @@ function ensureOutputIsOnPage() {
19
19
  return;
20
20
  }
21
21
 
22
+ //@ts-ignore
22
23
  OUTPUT_IS_ON_PAGE = new FloatingUIOutput({
23
24
  target: document.body,
24
25
  });
@@ -2,10 +2,10 @@
2
2
  @component
3
3
 
4
4
 
5
- @param {''|'small'|'medium'|'large'} [size=""] - Size of the Icon, Default: `""`
6
- @param {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Color of the Icon, Default: `""`
5
+ @param {string|''|'small'|'medium'|'large'} [size=""] - Size of the Icon, Default: `""`
6
+ @param {string|''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [color=""] - Color of the Icon, Default: `""`
7
7
  @param {string} [icon=""] - The name of the icon that is to be displayed, from the relevant icon family, Default: `""`
8
- @param {''|'fa'|'lar'|'las'|'gg'|'unicons'} [family=""] - Icon family, can be modified globally in framework settings
8
+ @param {string|''|'fa'|'lar'|'las'|'gg'|'unicons'|'material'} [family=""] - Icon family, can be modified globally in framework settings
9
9
 
10
10
  Ultimately defaults to `fa`, if family is not set anywhere, Default: `""`
11
11
  @param {string} [style=""] - Inline CSS for icon container, Default: `""`
@@ -18,7 +18,7 @@ Ultimately defaults to `fa`, if family is not set anywhere, Default: `""`
18
18
  <span class="icon is-{size} has-text-{color} {klass}" {style}>
19
19
  <i
20
20
  class="icon-i {familyClass}{icon} {internal_size} {inner_class}"
21
- style={inner_style} />
21
+ style={inner_style}>{inner_icon}</i>
22
22
  </span>
23
23
 
24
24
  <style>
@@ -47,6 +47,19 @@ Ultimately defaults to `fa`, if family is not set anywhere, Default: `""`
47
47
  .icon .uil.fa-3x {
48
48
  font-size: 3em;
49
49
  }
50
+
51
+ .icon .material-icons {
52
+ font-size: 1.25em;
53
+ }
54
+ .icon .material-icons.fa-lg {
55
+ font-size: 1.5em;
56
+ }
57
+ .icon .material-icons.fa-2x {
58
+ font-size: 2em;
59
+ }
60
+ .icon .material-icons.fa-3x {
61
+ font-size: 3em;
62
+ }
50
63
  </style>
51
64
 
52
65
  <script>
@@ -54,12 +67,12 @@ Ultimately defaults to `fa`, if family is not set anywhere, Default: `""`
54
67
 
55
68
  /**
56
69
  * Size of the Icon
57
- * @type {''|'small'|'medium'|'large'}
70
+ * @type {import('@kws3/ui/types').SizeOptions}
58
71
  */
59
72
  export let size = "",
60
73
  /**
61
74
  * Color of the Icon
62
- * @type {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'}
75
+ * @type {import('@kws3/ui/types').ColorOptions | 'grey'}
63
76
  */
64
77
  color = "",
65
78
  /**
@@ -70,7 +83,7 @@ Ultimately defaults to `fa`, if family is not set anywhere, Default: `""`
70
83
  * Icon family, can be modified globally in framework settings
71
84
  *
72
85
  * Ultimately defaults to `fa`, if family is not set anywhere
73
- * @type {''|'fa'|'lar'|'las'|'gg'|'unicons'}
86
+ * @type {string|''|'fa'|'lar'|'las'|'gg'|'unicons'|'material'}
74
87
  */
75
88
  family = "",
76
89
  /**
@@ -97,9 +110,9 @@ Ultimately defaults to `fa`, if family is not set anywhere, Default: `""`
97
110
  internal_size,
98
111
  usedFamily;
99
112
 
113
+ $: inner_icon = family === "material" ? icon : "";
100
114
  $: {
101
- usedFamily =
102
- family && family !== "" ? family : globalFamily ? globalFamily : "fa";
115
+ usedFamily = family !== "" ? family : globalFamily ? globalFamily : "fa";
103
116
 
104
117
  switch (usedFamily) {
105
118
  case "lar":
@@ -117,6 +130,9 @@ Ultimately defaults to `fa`, if family is not set anywhere, Default: `""`
117
130
  case "unicons":
118
131
  familyClass = "uil uil-";
119
132
  break;
133
+ case "material":
134
+ familyClass = "material-icons material-symbols-outlined ";
135
+ break;
120
136
  default:
121
137
  familyClass = "fa fa-";
122
138
  break;
@@ -31,20 +31,27 @@ The overlay is absolutely positioned. Ensure that the parent container is relati
31
31
  </div>
32
32
 
33
33
  <script>
34
+ /**
35
+
36
+ * @typedef {import('@kws3/ui/types').SpinnerColorOptions} SpinnerColorOptions
37
+ * @typedef {import('@kws3/ui/types').SizeOptions} SizeOptions
38
+ * @typedef {import('@kws3/ui/types').BGColorOptions} BGColorOptions
39
+ *
40
+ */
34
41
  /**
35
42
  * Color of the Spinner
36
43
  * @link https://bulma.io/documentation/helpers/color-helpers/
37
- * @type {'grey' | 'light' | 'warning' | 'info' | 'danger' | 'primary' | 'success'}
44
+ * @type {SpinnerColorOptions}
38
45
  */
39
46
  export let spinner_color = "grey",
40
47
  /**
41
48
  * Size of the Spinner
42
- * @type {'small'|'medium'|'large'}
49
+ * @type {SizeOptions}
43
50
  */
44
51
  spinner_size = "medium",
45
52
  /**
46
53
  * Backgound color of the Spinner container
47
- * @type {'transparent' | 'warning' | 'info' | 'danger' | 'primary' | 'success' | 'link'}
54
+ * @type {BGColorOptions}
48
55
  */
49
56
  background_color = "transparent",
50
57
  /**
@@ -70,12 +70,12 @@ The parent can then decide what to do with the component
70
70
 
71
71
  /**
72
72
  * Size of the Message
73
- * @type {''|'small'|'medium'|'large'}
73
+ * @type {import('@kws3/ui/types').SizeOptions}
74
74
  */
75
75
  export let size = "",
76
76
  /**
77
77
  * Color of the Message box
78
- * @type {''|'primary'|'warning'|'info'|'danger'|'dark'|'light'}
78
+ * @type {import('@kws3/ui/types').ColorOptions | 'grey'}
79
79
  */
80
80
  color = "info",
81
81
  /**
@@ -29,6 +29,7 @@ Only programmatic closing is possible, Default: `true`
29
29
  <div
30
30
  transition:scale={{
31
31
  duration: transitionDuration,
32
+ // @ts-ignore
32
33
  from: 0.8,
33
34
  to: 1,
34
35
  delay: transitionDelay,
@@ -75,7 +76,7 @@ Only programmatic closing is possible, Default: `true`
75
76
  import { hasTransitions } from "../settings";
76
77
  /**
77
78
  * Size of the modal
78
- * @type {'small'|'medium'|'large'}
79
+ * @type {import('@kws3/ui/types').SizeOptions}
79
80
  */
80
81
  export let size = "small",
81
82
  /**
@@ -35,7 +35,7 @@ The parent can then decide what to do with the component
35
35
 
36
36
  /**
37
37
  * Color of the Notification box
38
- * @type {''|'primary'|'success'|'warning'|'info'|'danger'|'light'|'dark'}
38
+ * @type {import('@kws3/ui/types').ColorOptions}
39
39
  */
40
40
  export let color = "info";
41
41
 
@@ -3,8 +3,8 @@
3
3
 
4
4
 
5
5
  @param {string} [icon="info-circle"] - Icon used when default slot has no content, Default: `"info-circle"`
6
- @param {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [icon_color="primary"] - Colour of the trigger icon displayed when default slot has no content, Default: `"primary"`
7
- @param {''|'small'|'medium'|'large'} [icon_size="small"] - Size of the trigger icon displayed when default slot has no content, Default: `"small"`
6
+ @param {string|''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'} [icon_color="primary"] - Colour of the trigger icon displayed when default slot has no content, Default: `"primary"`
7
+ @param {string|''|'small'|'medium'|'large'} [icon_size="small"] - Size of the trigger icon displayed when default slot has no content, Default: `"small"`
8
8
  @param {string} [trigger="click"] - Determines the events that cause the Popover to show. Multiple event names are separated by spaces.
9
9
 
10
10
  **Examples:** `click`, `mouseenter`, `mouseenter focus`
@@ -85,12 +85,12 @@ It can be any CSS value associated with `max-width` property, including `"none"`
85
85
  export let icon = "info-circle";
86
86
  /**
87
87
  * Colour of the trigger icon displayed when default slot has no content
88
- * @type {''|'primary'|'success'|'warning'|'info'|'danger'|'dark'|'light'}
88
+ * @type {import('@kws3/ui/types').ColorOptions | 'grey'}
89
89
  */
90
90
  export let icon_color = "primary";
91
91
  /**
92
92
  * Size of the trigger icon displayed when default slot has no content
93
- * @type {''|'small'|'medium'|'large'}
93
+ * @type {import('@kws3/ui/types').SizeOptions}
94
94
  */
95
95
  export let icon_size = "small";
96
96
  /**
@@ -8,6 +8,7 @@
8
8
  @param {number} [start=0] - First item index rendered inside viewport - readonly, Default: `0`
9
9
  @param {number} [end=0] - Last item index rendered inside viewport - readonly, Default: `0`
10
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 {number} [padding_threshold=5] - render 'n' number of items on outside the viewport (top and bottom) to avoid visible glitches on scrolling., Default: `5`
11
12
  @param {string} [style=""] - Inline CSS for scroller container, Default: `""`
12
13
  @param {string} [class=""] - CSS classes for scroller container, Default: `""`
13
14
 
@@ -77,10 +78,7 @@ while more items are loading
77
78
  <script>
78
79
  import { onMount, tick } from "svelte";
79
80
  import { createEventDispatcher } from "svelte";
80
- import {
81
- resizeObserver,
82
- hasResizeObserver,
83
- } from "@kws3/ui/utils/resizeObserver";
81
+ import { resizeObserver, hasResizeObserver } from "@kws3/ui/resizeObserver";
84
82
 
85
83
  const fire = createEventDispatcher();
86
84
  /**
@@ -108,6 +106,10 @@ while more items are loading
108
106
  * `end` event will be fired when the list reaches this many items before the end of the list.
109
107
  */
110
108
  end_threshold = 10,
109
+ /**
110
+ * render 'n' number of items on outside the viewport (top and bottom) to avoid visible glitches on scrolling.
111
+ */
112
+ padding_threshold = 5,
111
113
  /**
112
114
  * Inline CSS for scroller container
113
115
  */
@@ -132,9 +134,11 @@ while more items are loading
132
134
  average_height,
133
135
  items_count = 0;
134
136
 
135
- $: visible = items.slice(start, end).map((data, i) => {
136
- return { index: i + start, data };
137
- });
137
+ $: padStart = start > padding_threshold ? start - padding_threshold : start;
138
+ $: padEnd = end + padding_threshold;
139
+ $: visible = items
140
+ .slice(padStart, padEnd)
141
+ .map((data, i) => ({ index: i + padStart, data }));
138
142
 
139
143
  // whenever `items` changes, invalidate the current heightmap
140
144
  $: items, viewport_height, item_height, mounted, refresh();
@@ -176,7 +180,7 @@ while more items are loading
176
180
  const row_height = height_map[i] || average_height;
177
181
  if (y + row_height > scrollTop) {
178
182
  start = i;
179
- top = y;
183
+ top = y - row_height * padding_threshold;
180
184
  break;
181
185
  }
182
186
  y += row_height;
@@ -25,6 +25,9 @@ If this is set to `true`, the `radius` property will be ignored., Default: `fals
25
25
  {/each}
26
26
 
27
27
  <script>
28
+ /**
29
+ * @typedef {import('@kws3/ui/types').BGColorOptions} BGColorOptions
30
+ */
28
31
  export let /**
29
32
  * Number of lines of text to display.
30
33
  */
@@ -51,7 +54,7 @@ If this is set to `true`, the `radius` property will be ignored., Default: `fals
51
54
  circle = false,
52
55
  /**
53
56
  * Color of the Skeleton lines
54
- * @type {'' | 'transparent' | 'warning' | 'info' | 'danger' | 'primary' | 'success' | 'link'}
57
+ * @type {BGColorOptions}
55
58
  */
56
59
  color = "";
57
60
 
@@ -16,7 +16,7 @@
16
16
  <script>
17
17
  /**
18
18
  * Alignment of the Timeline child items
19
- * @type {'left'|'center'|'right'}
19
+ * @type {string|'left'|'center'|'right'}
20
20
  */
21
21
  export let align = "left";
22
22
 
@@ -3,8 +3,8 @@
3
3
 
4
4
 
5
5
  @param {''|'dark' | 'light' | 'warning' | 'info' | 'danger' | 'primary' | 'success'} [color="primary"] - Color of marker and border, Default: `"primary"`
6
- @param {string} [marker_icon="null"] - Any icon name accepted by the Icon component, icon will be placed inside the marker, Default: `"null"`
7
- @param {string} [marker_image="null"] - Any image URL, the image will be placed inside the marker, Default: `"null"`
6
+ @param {string} [marker_icon=""] - Any icon name accepted by the Icon component, icon will be placed inside the marker, Default: `"null"`
7
+ @param {string} [marker_image=""] - Any image URL, the image will be placed inside the marker, Default: `"null"`
8
8
  @param {string} [class=""] - CSS classes for the TimelineItem container, Default: `""`
9
9
 
10
10
  ### Slots
@@ -48,19 +48,19 @@
48
48
 
49
49
  /**
50
50
  * Color of marker and border
51
- * @type {''|'dark' | 'light' | 'warning' | 'info' | 'danger' | 'primary' | 'success'}
51
+ * @type {import('@kws3/ui/types').ColorOptions}
52
52
  */
53
53
  export let color = "primary";
54
54
  /**
55
55
  * Any icon name accepted by the Icon component, icon will be placed inside the marker
56
56
  * @type {string}
57
57
  */
58
- export let marker_icon = null;
58
+ export let marker_icon = "";
59
59
  /**
60
60
  * Any image URL, the image will be placed inside the marker
61
61
  * @type {string}
62
62
  */
63
- export let marker_image = null;
63
+ export let marker_image = "";
64
64
 
65
65
  /**
66
66
  * CSS classes for the TimelineItem container
@@ -5,7 +5,7 @@ import tippy, { delegate } from "tippy.js";
5
5
  * @param {string} container - CSS selector of container
6
6
  * @param {object} opts - tooltip options
7
7
  */
8
- export function activateTooltips(container, opts) {
8
+ export function activateTooltips(container, opts = {}) {
9
9
  let _opts = Object.assign(
10
10
  {
11
11
  target: "[data-tooltip]",
package/index.js CHANGED
@@ -1,6 +1,6 @@
1
- export { applySettings } from "./settings";
1
+ export { applySettings } from "./settings.js";
2
2
 
3
- export { activateTooltips, tooltip, popover } from "./helpers/Tooltip";
3
+ export { activateTooltips, tooltip, popover } from "./helpers/Tooltip.js";
4
4
  export { default as Popover } from "./helpers/Popover.svelte";
5
5
  export { default as Icon } from "./helpers/Icon.svelte";
6
6
  export { default as Message } from "./helpers/Message.svelte";
@@ -18,13 +18,18 @@ export { default as TimelineHeader } from "./helpers/Timeline/TimelineHeader.sve
18
18
  export { default as Nl2br } from "./helpers/Nl2br.svelte";
19
19
  export { default as ClipboardCopier } from "./helpers/ClipboardCopier.svelte";
20
20
  export { default as ScrollableList } from "./helpers/ScrollableList.svelte";
21
- export { alert, confirm, prompt, default as Dialog } from "./helpers/Dialog";
21
+ export {
22
+ alert,
23
+ confirm,
24
+ prompt,
25
+ default as Dialog,
26
+ } from "./helpers/Dialog/index.js";
22
27
  export {
23
28
  Notifications,
24
29
  Toasts,
25
30
  Snackbars,
26
31
  FloatiesStore,
27
- } from "./helpers/FloatingUI";
32
+ } from "./helpers/FloatingUI/index.js";
28
33
  export { default as FloatingUIOutput } from "./helpers/FloatingUI/FloatingUIOutput.svelte";
29
34
  export { default as Floatie } from "./helpers/FloatingUI/Floatie.svelte";
30
35
  export { portal } from "svelte-portal";
@@ -56,6 +61,7 @@ export { default as MaskedInput } from "./forms/MaskedInput.svelte";
56
61
  export { default as Colorpicker } from "./forms/colorpicker/Colorpicker.svelte";
57
62
  export { default as Datepicker } from "./forms/Datepicker.svelte";
58
63
  export { default as Timepicker } from "./forms/Timepicker.svelte";
64
+ export { default as SearchInput } from "./forms/SearchInput.svelte";
59
65
  export { datepicker as DatepickerAction } from "./forms/actions.js";
60
66
  export { timepicker as TimepickerAction } from "./forms/actions.js";
61
67
  export { default as PasswordValidator } from "./forms/PasswordValidator/PasswordValidator.svelte";
@@ -2,20 +2,59 @@
2
2
  * fuzzy.js v0.1.0
3
3
  * (c) 2016 Ben Ripkens
4
4
  * @license: MIT
5
+ * @params
6
+ * term : haystack
7
+ * query : needle
8
+ * opts: {
9
+ * analyzeSubTerms,
10
+ * analyzeSubTermDepth
11
+ * highlighting
12
+ * }
5
13
  */
6
14
  /**
7
15
  *
8
16
  * Adapted from fuzzy.js for @kws3/ui to work with vite prebundling
9
17
  */
10
18
 
11
- var fuzzy = function fuzzy(term, query) {
12
- var max = calcFuzzyScore(term, query);
13
- var termLength = term.length;
19
+ /*
20
+ * Whether or not fuzzy.js should analyze sub-terms, i.e. also
21
+ * check term starting positions != 0.
22
+ *
23
+ * Example:
24
+ * Given the term 'Halleluja' and query 'luja'
25
+ *
26
+ * Fuzzy.js scores this combination with an 8, when analyzeSubTerms is
27
+ * set to false, as the following matching string will be calculated:
28
+ * Ha[l]lel[uja]
29
+ *
30
+ * If you activate sub temr analysis though, the query will reach a score
31
+ * of 10, as the matching string looks as following:
32
+ * Halle[luja]
33
+ *
34
+ * Naturally, the second version is more expensive than the first one.
35
+ * You should therefore configure how many sub terms you which to analyse.
36
+ * This can be configured through opts.analyzeSubTermDepth = 10.
37
+ */
14
38
 
15
- if (fuzzy.analyzeSubTerms) {
16
- for (var i = 1; i < termLength && i < fuzzy.analyzeSubTermDepth; i++) {
17
- var subTerm = term.substring(i);
18
- var score = calcFuzzyScore(subTerm, query);
39
+ export function fuzzy(term, query, opts = {}) {
40
+ let analyzeSubTerms = opts.analyzeSubTerms ? opts.analyzeSubTerms : false;
41
+ let analyzeSubTermDepth = opts.analyzeSubTermDepth
42
+ ? opts.analyzeSubTermDepth
43
+ : 10;
44
+ let highlighting = opts.highlighting
45
+ ? opts.highlighting
46
+ : {
47
+ before: "<em>",
48
+ after: "</em>",
49
+ };
50
+
51
+ let max = calcFuzzyScore(term, query, highlighting);
52
+ let termLength = term.length;
53
+
54
+ if (analyzeSubTerms) {
55
+ for (let i = 1; i < termLength && i < analyzeSubTermDepth; i++) {
56
+ let subTerm = term.substring(i);
57
+ let score = calcFuzzyScore(subTerm, query, highlighting);
19
58
  if (score.score > max.score) {
20
59
  // we need to correct 'term' and 'matchedTerm', as calcFuzzyScore
21
60
  // does not now that it operates on a substring. Doing it only for
@@ -28,26 +67,26 @@ var fuzzy = function fuzzy(term, query) {
28
67
  }
29
68
 
30
69
  return max;
31
- };
32
-
33
- var calcFuzzyScore = function calcFuzzyScore(term, query) {
34
- var score = 0;
35
- var termLength = term.length;
36
- var queryLength = query.length;
37
- var highlighting = "";
38
- var ti = 0;
70
+ }
71
+
72
+ function calcFuzzyScore(term, query, highlighting) {
73
+ let score = 0;
74
+ let termLength = term.length;
75
+ let queryLength = query.length;
76
+ let _highlighting = "";
77
+ let ti = 0;
39
78
  // -1 would not work as this would break the calculations of bonus
40
79
  // points for subsequent character matches. Something like
41
80
  // Number.MIN_VALUE would be more appropriate, but unfortunately
42
81
  // Number.MIN_VALUE + 1 equals 1...
43
- var previousMatchingCharacter = -2;
82
+ let previousMatchingCharacter = -2;
44
83
 
45
- for (var qi = 0; qi < queryLength && ti < termLength; qi++) {
46
- var qc = query.charAt(qi);
47
- var lowerQc = qc.toLowerCase();
84
+ for (let qi = 0; qi < queryLength && ti < termLength; qi++) {
85
+ let qc = query.charAt(qi);
86
+ let lowerQc = qc.toLowerCase();
48
87
 
49
88
  for (; ti < termLength; ti++) {
50
- var tc = term.charAt(ti);
89
+ let tc = term.charAt(ti);
51
90
 
52
91
  if (lowerQc === tc.toLowerCase()) {
53
92
  score++;
@@ -56,62 +95,22 @@ var calcFuzzyScore = function calcFuzzyScore(term, query) {
56
95
  score += 2;
57
96
  }
58
97
 
59
- highlighting +=
60
- fuzzy.highlighting.before + tc + fuzzy.highlighting.after;
98
+ _highlighting += highlighting.before + tc + highlighting.after;
61
99
  previousMatchingCharacter = ti;
62
100
  ti++;
63
101
  break;
64
102
  } else {
65
- highlighting += tc;
103
+ _highlighting += tc;
66
104
  }
67
105
  }
68
106
  }
69
107
 
70
- highlighting += term.substring(ti, term.length);
108
+ _highlighting += term.substring(ti, term.length);
71
109
 
72
110
  return {
73
111
  score: score,
74
112
  term: term,
75
113
  query: query,
76
- highlightedTerm: highlighting,
114
+ highlightedTerm: _highlighting,
77
115
  };
78
- };
79
-
80
- fuzzy.matchComparator = function matchComparator(m1, m2) {
81
- return m2.score - m1.score !== 0
82
- ? m2.score - m1.score
83
- : m1.term.length - m2.term.length;
84
- };
85
-
86
- /*
87
- * Whether or not fuzzy.js should analyze sub-terms, i.e. also
88
- * check term starting positions != 0.
89
- *
90
- * Example:
91
- * Given the term 'Halleluja' and query 'luja'
92
- *
93
- * Fuzzy.js scores this combination with an 8, when analyzeSubTerms is
94
- * set to false, as the following matching string will be calculated:
95
- * Ha[l]lel[uja]
96
- *
97
- * If you activate sub temr analysis though, the query will reach a score
98
- * of 10, as the matching string looks as following:
99
- * Halle[luja]
100
- *
101
- * Naturally, the second version is more expensive than the first one.
102
- * You should therefore configure how many sub terms you which to analyse.
103
- * This can be configured through fuzzy.analyzeSubTermDepth = 10.
104
- */
105
- fuzzy.analyzeSubTerms = false;
106
-
107
- /*
108
- * How many sub terms should be analyzed.
109
- */
110
- fuzzy.analyzeSubTermDepth = 10;
111
-
112
- fuzzy.highlighting = {
113
- before: "<em>",
114
- after: "</em>",
115
- };
116
-
117
- export default fuzzy;
116
+ }
@@ -0,0 +1,27 @@
1
+ export { scrollIntoActiveElement } from "./scrollIntoActiveElement";
2
+ export { fuzzy } from "./fuzzy.js";
3
+
4
+ /**
5
+ * Detect whether a user has pressed Enter.
6
+ * @param {object} [e=[]] - Event object., Default: `[]`
7
+ */
8
+ export function isEnterKey(e) {
9
+ return e.keyCode && e.keyCode === 13;
10
+ }
11
+
12
+ /**
13
+ * Detect whether a user has pressed Escape key.
14
+ * @param {object} [e=[]] - Event object., Default: `[]`
15
+ */
16
+ export function isEscKey(e) {
17
+ return e.keyCode && e.keyCode === 27;
18
+ }
19
+
20
+ export const IS_MAC =
21
+ "navigator" in window
22
+ ? /mac/i.test(
23
+ window.navigator.userAgentData
24
+ ? window.navigator.userAgentData.platform
25
+ : window.navigator.platform
26
+ )
27
+ : false;
@@ -0,0 +1,22 @@
1
+ export function scrollIntoActiveElement(listElement, activeElelement) {
2
+ if (listElement && activeElelement) {
3
+ const dropdownRect = listElement.getBoundingClientRect();
4
+ const activeElemRect = activeElelement.getBoundingClientRect();
5
+ const overScroll = activeElelement.offsetHeight / 3;
6
+
7
+ if (activeElemRect.bottom + overScroll > dropdownRect.bottom) {
8
+ listElement.scrollTop = Math.min(
9
+ activeElelement.offsetTop +
10
+ activeElelement.clientHeight -
11
+ listElement.offsetHeight +
12
+ overScroll,
13
+ listElement.scrollHeight
14
+ );
15
+ } else if (activeElemRect.top - overScroll < dropdownRect.top) {
16
+ listElement.scrollTop = Math.max(
17
+ activeElelement.offsetTop - overScroll,
18
+ 0
19
+ );
20
+ }
21
+ }
22
+ }