@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
@@ -48,6 +48,12 @@ This will be overridden if `min` is higher, or `max` is lower, Default: `0`
48
48
  <script>
49
49
  import { onMount } from "svelte";
50
50
 
51
+ /**
52
+ *
53
+ * @typedef {import('@kws3/ui/types').ColorOptions} ColorOptions
54
+ * @typedef {import('@kws3/ui/types').SizeOptions} SizeOptions
55
+ *
56
+ */
51
57
  /**
52
58
  * Minumum permitted value
53
59
  */
@@ -78,12 +84,12 @@ This will be overridden if `min` is higher, or `max` is lower, Default: `0`
78
84
  disabled = false,
79
85
  /**
80
86
  * Size of the Slider
81
- * @type {''|'small'|'medium'|'large'}
87
+ * @type {SizeOptions}
82
88
  */
83
89
  size = "",
84
90
  /**
85
91
  * Colour of the Slider
86
- * @type {''|'primary'|'warning'|'success'|'info'|'danger'|'dark'|'light'}
92
+ * @type {ColorOptions}
87
93
  */
88
94
  color = "",
89
95
  /**
@@ -37,6 +37,13 @@ This property can be bound to, to fetch the current value, Default: `false`
37
37
 
38
38
  <script>
39
39
  import { createEventDispatcher } from "svelte";
40
+
41
+ /**
42
+ *
43
+ * @typedef {import('@kws3/ui/types').ColorOptions} ColorOptions
44
+ * @typedef {import('@kws3/ui/types').SizeOptions} SizeOptions
45
+ *
46
+ */
40
47
  const fire = createEventDispatcher();
41
48
 
42
49
  /**
@@ -51,7 +58,7 @@ This property can be bound to, to fetch the current value, Default: `false`
51
58
  disabled = false,
52
59
  /**
53
60
  * Color of the Toggle
54
- * @type {''|'primary'|'warning'|'success'|'info'|'danger'|'dark'|'light'}
61
+ * @type {ColorOptions}
55
62
  */
56
63
  color = "",
57
64
  /**
@@ -64,7 +71,7 @@ This property can be bound to, to fetch the current value, Default: `false`
64
71
  off_text = "",
65
72
  /**
66
73
  * Size of the Toggle
67
- * @type {''|'small'|'medium'|'large'}
74
+ * @type {SizeOptions}
68
75
  */
69
76
  size = "",
70
77
  /**
@@ -33,7 +33,9 @@ This property can be bound to, to fetch the current value, Default: `null`
33
33
  <button
34
34
  type="button"
35
35
  {disabled}
36
- on:click={setValue(option.value)}
36
+ on:click={() => {
37
+ setValue(option.value);
38
+ }}
37
39
  class="button is-{size} {fullwidth ? 'is-fullwidth' : ''} {value ===
38
40
  option.value
39
41
  ? 'is-active ' +
@@ -44,7 +46,7 @@ This property can be bound to, to fetch the current value, Default: `null`
44
46
  style="height:auto">
45
47
  <span>
46
48
  {#if option.icon}
47
- <Icon icon={option.icon} size="small" icon_class="is-marginless" />
49
+ <Icon icon={option.icon} size="small" class="is-marginless" />
48
50
  {/if}
49
51
  <span class="is-block">{option.name}</span>
50
52
  {#if option.subtitle}
@@ -76,6 +78,11 @@ This property can be bound to, to fetch the current value, Default: `null`
76
78
  <script>
77
79
  import { createEventDispatcher } from "svelte";
78
80
  import { Icon } from "@kws3/ui";
81
+ /**
82
+ *
83
+ * @typedef {import('@kws3/ui/types').SizeOptions} SizeOptions
84
+ *
85
+ */
79
86
 
80
87
  const fire = createEventDispatcher();
81
88
  /**
@@ -119,7 +126,7 @@ This property can be bound to, to fetch the current value, Default: `null`
119
126
  inactive_class = "is-outlined",
120
127
  /**
121
128
  * Size of the Toggle Buttons
122
- * @type {''|'small'|'medium'|'large'}
129
+ * @type {SizeOptions}
123
130
  */
124
131
  size = "",
125
132
  /**
@@ -111,7 +111,7 @@
111
111
  */
112
112
  filter_label_map = {};
113
113
 
114
- let query = "",
114
+ let query = null,
115
115
  _filters = [],
116
116
  filterVals = {},
117
117
  filterWidthStyle = "";
@@ -26,14 +26,17 @@
26
26
  row = {},
27
27
  /**
28
28
  * Finds custom values for the column
29
+ * @type {object}
29
30
  */
30
31
  transforms = {},
31
32
  /**
32
33
  * Finds CSS class for the column
34
+ * @type {object}
33
35
  */
34
36
  classNames = {},
35
37
  /**
36
38
  * Finds CSS styles for the column
39
+ * @type {object}
37
40
  */
38
41
  styles = {};
39
42
  </script>
@@ -99,6 +99,11 @@
99
99
 
100
100
  const fire = createEventDispatcher();
101
101
 
102
+ /**
103
+ * @typedef {import('@kws3/ui/types').ColorOptions} ColorOptions
104
+ * @typedef {import('@kws3/ui/types').SizeOptions} SizeOptions
105
+ */
106
+
102
107
  /**
103
108
  * Row index value
104
109
  */
@@ -117,6 +122,7 @@
117
122
  activatedId = null,
118
123
  /**
119
124
  * Determines whether column is visible or not
125
+ * @type {object}
120
126
  */
121
127
  isVisible = {},
122
128
  /**
@@ -125,10 +131,12 @@
125
131
  clickableRows = false,
126
132
  /**
127
133
  * Contains all custom values for each columns
134
+ * @type {object}
128
135
  */
129
136
  transforms = {},
130
137
  /**
131
138
  * Contails all CSS class for each column
139
+ * @type {object}
132
140
  */
133
141
  classNames = {},
134
142
  /**
@@ -137,8 +145,12 @@
137
145
  transition = false,
138
146
  /**
139
147
  * Contains all CSS styles for each column
148
+ * @type {object}
140
149
  */
141
150
  styles = {},
151
+ /**
152
+ * Column keys
153
+ */
142
154
  column_keys = [],
143
155
  /**
144
156
  * Determines if selecting multiple rows and doing multiple actions is allowed
@@ -154,10 +166,12 @@
154
166
  selectedIds = [],
155
167
  /**
156
168
  * Selected checkbox color
169
+ * @type {Exclude<ColorOptions, 'success'>}
157
170
  */
158
171
  selectCheckboxColor = "info",
159
172
  /**
160
173
  * selected checkbox size
174
+ * @type {SizeOptions}
161
175
  */
162
176
  selectCheckboxSize = "medium",
163
177
  /**
@@ -166,6 +180,7 @@
166
180
  cellComponent = () => null;
167
181
 
168
182
  $: resolveComponent = (column, row) => {
183
+ // @ts-ignore
169
184
  return cellComponent(column, row) || GridCell;
170
185
  };
171
186
 
@@ -7,6 +7,7 @@
7
7
  @param {object} [columns={}] - Table column names. {db_field_name: column_name}, Default: `{}`
8
8
  @param {boolean} [transition=false] - Determines if a transition effect is used, Default: `false`
9
9
  @param {boolean} [is_striped=true] - Determines whether to use alternating row shading in the table view, Default: `true`
10
+ @param {boolean} [is_narrow=false] - Determines whether to display rows in a more compact manner, Default: `false`
10
11
  @param {boolean} [visualActivationOnClick=true] - Determines whether clickable rows activate visually on click, Default: `true`
11
12
  @param {boolean} [clickableRows=false] - Determines whether rows are clickable or not, Default: `false`
12
13
  @param {object} [activatedId=null] - Unique id of row that is activated, Default: `null`
@@ -22,6 +23,7 @@
22
23
  @param {object} [visibilityMap={}] - Contains list of columns which can be visible or not, Default: `{}`
23
24
  @param {object} [cellComponentMap={}] - Contains list of columns with its custom cell component, Default: `{}`
24
25
  @param {any} [rowComponent="GridRow"] - Contains a custom row component, Default: `"GridRow"`
26
+ @param {string} [class=""] - CSS classes for parent table, Default: `""`
25
27
 
26
28
  ### Events
27
29
  - `toggleSelectAll` - Fires an event every time the `select all` checkbox is toggled
@@ -32,9 +34,9 @@
32
34
  -->
33
35
  <div class="data-table" data-cy="data-table">
34
36
  <table
35
- class="table is-fullwidth {is_striped ? 'is-striped' : ''} {clickableRows
36
- ? 'is-hoverable'
37
- : ''} is-bordered">
37
+ class="table is-fullwidth {is_striped ? 'is-striped' : ''} {is_narrow
38
+ ? 'is-narrow'
39
+ : ''} {clickableRows ? 'is-hoverable' : ''} is-bordered {klass}">
38
40
  <thead>
39
41
  <tr>
40
42
  {#if bulk_actions}
@@ -91,6 +93,10 @@
91
93
 
92
94
  const fire = createEventDispatcher();
93
95
 
96
+ /**
97
+ * @typedef {import('@kws3/ui/types').ColorOptions} ColorOptions
98
+ */
99
+
94
100
  /**
95
101
  * Iteration key
96
102
  */
@@ -112,6 +118,11 @@
112
118
  * @link https://bulma.io/documentation/elements/table/#modifiers
113
119
  */
114
120
  is_striped = true,
121
+ /**
122
+ * Determines whether to display rows in a more compact manner
123
+ * @link https://bulma.io/documentation/elements/table/#modifiers
124
+ */
125
+ is_narrow = false,
115
126
  /**
116
127
  * Determines whether clickable rows activate visually on click
117
128
  */
@@ -138,6 +149,7 @@
138
149
  selectedIds = [],
139
150
  /**
140
151
  * Colour of the `select all` checkbox
152
+ * @type {Exclude<ColorOptions, 'success'>}
141
153
  */
142
154
  selectAllCheckboxColor = "primary",
143
155
  /**
@@ -174,6 +186,12 @@
174
186
  */
175
187
  rowComponent = GridRow;
176
188
 
189
+ /**
190
+ * CSS classes for parent table
191
+ */
192
+ let klass = "";
193
+ export { klass as class };
194
+
177
195
  $: mainRowComponent = rowComponent ? rowComponent : GridRow;
178
196
  $: column_keys = columns ? Object.keys(columns) : [];
179
197
 
@@ -189,7 +189,7 @@
189
189
  entityName = "entries",
190
190
  /**
191
191
  * Size of the pagination elements
192
- * @type {''|'small'|'medium'|'large'}
192
+ * @type {import('@kws3/ui/types').SizeOptions}
193
193
  */
194
194
  size = "small",
195
195
  /**
@@ -210,7 +210,7 @@
210
210
  perPageOptions = [20, 50, 100, 150, 200, 250];
211
211
 
212
212
  let pages = [],
213
- _perPageOptions = 0;
213
+ _perPageOptions = {};
214
214
 
215
215
  $: _total = total || meta.total || 0;
216
216
  $: _count = count || meta.count || 0;
@@ -303,7 +303,7 @@
303
303
 
304
304
  /**
305
305
  * Go to an arbitrary page number
306
- * @param {int} targetPage
306
+ * @param {number} targetPage
307
307
  */
308
308
  export function goto(targetPage) {
309
309
  let limit = _limit,
@@ -6,7 +6,12 @@
6
6
  @param {array} [data=[]] - Contains all the results to be listed, Default: `[]`
7
7
  @param {boolean} [transition=false] - Determines if a transition effect is used, Default: `false`
8
8
  @param {object} [tileItemComponent=null] - Contains a custom component, Default: `null`
9
- @param {number} [per_row=3] - Sets how many items to display in a row, Default: `3`
9
+ @param {number} [per_row=3] - Sets how many items to display in a row. This is ignored when `fluid_items_per_row` is `true`, Default: `3`
10
+ @param {boolean} [fluid_items_per_row=false] - When set to `true`, the number of items per row varies with available space, Default: `false`
11
+ @param {string} [min_width="unset"] - CSS string specifying minimum width, this is only applied when `fluid_items_per_row` is `true`, Default: `"unset"`
12
+ @param {string} [max_width="unset"] - CSS string specifying maximum width, this is only applied when `fluid_items_per_row` is `true`, Default: `"unset"`
13
+ @param {boolean} [grow=true] - Whether a tile can grow if there is space available, this is only applied when `fluid_items_per_row` is `true`, Default: `true`
14
+ @param {boolean} [shrink=true] - Whether a tile can shrink if there isn't enough space available, this is only applied when `fluid_items_per_row` is `true`, Default: `true`
10
15
  @param {object} [columns={}] - Column names for the displayed table {db_field_name: column_name}, Default: `{}`
11
16
  @param {boolean} [visualActivationOnClick=true] - Determines whether clickable rows activate visually on click, Default: `true`
12
17
  @param {boolean} [clickableRows=false] - Determines whether rows are clickable or not, Default: `false`
@@ -15,6 +20,7 @@
15
20
  @param {object} [classTransformers={}] - CSS class names for each column, Default: `{}`
16
21
  @param {object} [styleTransformers={}] - CSS styles for each column, Default: `{}`
17
22
  @param {object} [visibilityMap={}] - Contains list of columns which can be visible or not, Default: `{}`
23
+ @param {string} [class=""] - CSS classes for tiles wrapper, Default: `""`
18
24
 
19
25
  ### Events
20
26
  - `rowClick`
@@ -22,9 +28,9 @@
22
28
  - `_forwardEvent`
23
29
 
24
30
  -->
25
- <div class="columns is-multiline">
31
+ <div class="columns is-multiline {klass}">
26
32
  {#each data as row, row_index (row[iteration_key])}
27
- <div class="column is-{column_size}">
33
+ <div class="column is-{column_size}" style={fluid_css}>
28
34
  <Transition {transition} y={20} delay={20 * row_index}>
29
35
  <svelte:component
30
36
  this={mainTileComponent}
@@ -72,9 +78,29 @@
72
78
  */
73
79
  tileItemComponent = null,
74
80
  /**
75
- * Sets how many items to display in a row
81
+ * Sets how many items to display in a row. This is ignored when `fluid_items_per_row` is `true`
76
82
  */
77
83
  per_row = 3,
84
+ /**
85
+ * When set to `true`, the number of items per row varies with available space
86
+ */
87
+ fluid_items_per_row = false,
88
+ /**
89
+ * CSS string specifying minimum width, this is only applied when `fluid_items_per_row` is `true`
90
+ */
91
+ min_width = "unset",
92
+ /**
93
+ * CSS string specifying maximum width, this is only applied when `fluid_items_per_row` is `true`
94
+ */
95
+ max_width = "unset",
96
+ /**
97
+ * Whether a tile can grow if there is space available, this is only applied when `fluid_items_per_row` is `true`
98
+ */
99
+ grow = true,
100
+ /**
101
+ * Whether a tile can shrink if there isn't enough space available, this is only applied when `fluid_items_per_row` is `true`
102
+ */
103
+ shrink = true,
78
104
  /**
79
105
  * Column names for the displayed table {db_field_name: column_name}
80
106
  */
@@ -129,8 +155,23 @@
129
155
  */
130
156
  selectCheckboxSize = "medium";
131
157
 
158
+ /**
159
+ * CSS classes for tiles wrapper
160
+ */
161
+ let klass = "";
162
+ export { klass as class };
163
+
132
164
  $: mainTileComponent = tileItemComponent ? tileItemComponent : TileViewItem;
133
- $: column_size = per_row < 12 ? Math.floor(12 / per_row) : 12;
165
+ $: column_size = fluid_items_per_row
166
+ ? "fluid"
167
+ : per_row < 12
168
+ ? Math.floor(12 / per_row)
169
+ : 12;
170
+ $: fluid_css = fluid_items_per_row
171
+ ? `min-width:${min_width};max-width:${max_width};flex-shrink:${Number(
172
+ shrink
173
+ )};flex-grow:${Number(grow)};`
174
+ : "";
134
175
  $: column_keys = columns ? Object.keys(columns) : [];
135
176
 
136
177
  $: transforms = (column, row) => {
@@ -53,18 +53,22 @@
53
53
  clickableRows = false,
54
54
  /**
55
55
  * Returns whether a column can be visible or not
56
+ * @type {function}
56
57
  */
57
58
  isVisible = function () {},
58
59
  /**
59
60
  * Returns column custom value
61
+ * @type {function}
60
62
  */
61
63
  transforms = function () {},
62
64
  /**
63
65
  * Returns column custom CSS class
66
+ * @type {function}
64
67
  */
65
68
  classNames = function () {},
66
69
  /**
67
70
  * Returns column custom CSS styles
71
+ * @type {function}
68
72
  */
69
73
  styles = function () {},
70
74
  /**
package/form/index.js ADDED
@@ -0,0 +1,160 @@
1
+ import { cloneObject } from "../utils/index";
2
+ import { derived, get, writable } from "svelte/store";
3
+
4
+ const makeForms = (items) => {
5
+ var res = Array.isArray(items);
6
+ if (!res) {
7
+ return formMaker(items);
8
+ }
9
+
10
+ let ret = [];
11
+ if (items.length) {
12
+ items.forEach((item) => ret.push(formMaker(item)));
13
+ }
14
+ return ret;
15
+ };
16
+
17
+ const formMaker = (config) => {
18
+ let data = config.data || {};
19
+ let validators = config.validators || {};
20
+ let strictMode = config.strictMode || false;
21
+ let tracker_data = {
22
+ saving: false,
23
+ saved: false,
24
+ error: false,
25
+ };
26
+
27
+ const formData = writable(cloneObject(data));
28
+
29
+ const tracker = writable(cloneObject(tracker_data));
30
+
31
+ const touched = derived(formData, ($formData, set) => {
32
+ let fields = Object.keys($formData);
33
+ let res = fields.reduce((o, v) => ((o[v] = false), o), {});
34
+
35
+ let compare = (field, oldData, newData) => {
36
+ if (Array.isArray(newData[field])) {
37
+ if (
38
+ !Array.isArray(oldData[field]) ||
39
+ (Array.isArray(oldData[field]) &&
40
+ oldData[field].length !== newData[field].length)
41
+ ) {
42
+ return true;
43
+ }
44
+ } else if (
45
+ typeof newData[field] === "object" &&
46
+ newData[field] !== null
47
+ ) {
48
+ let ret = {};
49
+ for (let key in newData[field]) {
50
+ ret[key] = compare(key, oldData[field], newData[field]);
51
+ }
52
+ return ret;
53
+ } else {
54
+ if (!strictMode) {
55
+ if (
56
+ (oldData[field] === null &&
57
+ [0, "", false].indexOf(newData[field]) !== -1) ||
58
+ (oldData[field] === 0 && newData[field] === false) ||
59
+ (oldData[field] === 1 && newData[field] === true)
60
+ ) {
61
+ return false;
62
+ }
63
+ }
64
+
65
+ if (oldData[field] !== newData[field]) {
66
+ return true;
67
+ }
68
+ }
69
+ return false;
70
+ };
71
+
72
+ if (fields.length) {
73
+ fields.forEach((field) => {
74
+ res[field] = compare(field, data, $formData);
75
+ });
76
+ }
77
+
78
+ set(res);
79
+ });
80
+
81
+ const errors = derived(formData, ($formData, set) => {
82
+ let fields = Object.keys(validators) || [];
83
+ let res = fields.reduce((o, v) => ((o[v] = ""), o), {});
84
+ let validate = (field, validator) => {
85
+ let message = "";
86
+ if (validator || typeof validator !== "undefined") {
87
+ if (Array.isArray(validator)) {
88
+ for (let i = 0; i < validator.length; i++) {
89
+ message = validate(field, validator[i]);
90
+ if (message) {
91
+ break;
92
+ }
93
+ }
94
+ } else {
95
+ message = validator($formData[field], $formData);
96
+ }
97
+ }
98
+ return message;
99
+ };
100
+
101
+ if (fields.length) {
102
+ fields.forEach((field) => {
103
+ res[field] = validate(field, validators[field]);
104
+ });
105
+ }
106
+ set(res);
107
+ });
108
+
109
+ const isTouched = derived(touched, ($touched, set) => {
110
+ let find = (fields) =>
111
+ Object.values(fields).some((field) => {
112
+ if (typeof field === "object") {
113
+ return find(field);
114
+ } else {
115
+ return field === true;
116
+ }
117
+ });
118
+ set(find($touched));
119
+ });
120
+
121
+ const isValid = derived(errors, ($errors) =>
122
+ Object.values($errors).every((v) => v === "")
123
+ );
124
+
125
+ function update(newData) {
126
+ data = newData;
127
+ reset();
128
+ }
129
+
130
+ function setValidators(newValidators) {
131
+ validators = newValidators;
132
+ formData.set(get(formData));
133
+ }
134
+
135
+ function reset(e) {
136
+ e && e.preventDefault();
137
+ formData.set(cloneObject(data));
138
+ tracker.set(cloneObject(tracker_data));
139
+ }
140
+
141
+ return {
142
+ formData,
143
+ errors,
144
+ touched,
145
+ isValid,
146
+ isTouched,
147
+ tracker,
148
+ update,
149
+ reset,
150
+ setValidators,
151
+ };
152
+ };
153
+
154
+ const notEmpty = (v) => v && v.trim() !== "";
155
+
156
+ const noDigits = (v) => !/\d/.test(v);
157
+
158
+ const withMsg = (msg, fn) => (v, otherFields) => fn(v, otherFields) ? "" : msg;
159
+
160
+ export { makeForms, notEmpty, noDigits, withMsg };