@lavalogic/scoria 0.38.11 → 0.38.12

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 (100) hide show
  1. package/README.md +58 -58
  2. package/dist/Components/AccordionGroup.svelte +46 -46
  3. package/dist/Components/AccordionGroupButton.svelte +76 -76
  4. package/dist/Components/Action.svelte +136 -136
  5. package/dist/Components/AppointmentCalendar/AppointmentCalendar.svelte +702 -702
  6. package/dist/Components/Base/BaseModal.svelte +125 -125
  7. package/dist/Components/Base/ContextWrapper.svelte +72 -72
  8. package/dist/Components/Base/Pagination.svelte +198 -198
  9. package/dist/Components/Base/Snippets.svelte +36 -36
  10. package/dist/Components/BigRadioSet.svelte +38 -38
  11. package/dist/Components/Bubble.svelte +101 -101
  12. package/dist/Components/Button.svelte +209 -209
  13. package/dist/Components/Checkbox.svelte +86 -86
  14. package/dist/Components/Contexts/ContextMenu.svelte +164 -164
  15. package/dist/Components/Contexts/ContextMenuDivider.svelte +15 -15
  16. package/dist/Components/Contexts/ContextMenuOption.svelte +60 -60
  17. package/dist/Components/Contexts/ToastContainer.svelte +65 -65
  18. package/dist/Components/Contexts/Tooltip.svelte +37 -37
  19. package/dist/Components/DataMatrixIcon.svelte +112 -112
  20. package/dist/Components/DateInput.svelte +148 -148
  21. package/dist/Components/DatePicker.svelte +300 -300
  22. package/dist/Components/DesktopModal.svelte +90 -90
  23. package/dist/Components/Dial.svelte +204 -204
  24. package/dist/Components/DimensionInput.svelte +170 -170
  25. package/dist/Components/DragMenu/DragMenuHolder.svelte +119 -119
  26. package/dist/Components/DragMenu/DraggableCard.svelte +77 -77
  27. package/dist/Components/FileCard.svelte +24 -24
  28. package/dist/Components/FileUpload.svelte +236 -236
  29. package/dist/Components/GridInputSet.svelte +29 -29
  30. package/dist/Components/HorizontalTabGroup.svelte +82 -82
  31. package/dist/Components/HorizontalTabGroupButton.svelte +44 -44
  32. package/dist/Components/Icon.svelte +128 -128
  33. package/dist/Components/Icons.js +357 -357
  34. package/dist/Components/LoadingAnimation.svelte +29 -29
  35. package/dist/Components/LoadingModal.svelte +45 -45
  36. package/dist/Components/LoadingOverlay.svelte +25 -25
  37. package/dist/Components/Modal.svelte +258 -258
  38. package/dist/Components/MultiSelect.svelte +220 -220
  39. package/dist/Components/Nav/NavServiceMenuList.svelte +43 -43
  40. package/dist/Components/Nav/NavTab.svelte +62 -62
  41. package/dist/Components/Nav/ServicesNav.svelte +80 -80
  42. package/dist/Components/NumberInput.svelte +157 -157
  43. package/dist/Components/PageHeading.svelte +25 -25
  44. package/dist/Components/PasswordInput.svelte +88 -88
  45. package/dist/Components/Portal.svelte +36 -36
  46. package/dist/Components/QuerySelect.svelte +366 -366
  47. package/dist/Components/SingleSelect.svelte +250 -250
  48. package/dist/Components/StepButton.svelte +70 -70
  49. package/dist/Components/StepForm.svelte +140 -140
  50. package/dist/Components/Switch.svelte +69 -69
  51. package/dist/Components/Table/Body/Rows/ColumnHighlight.svelte +51 -51
  52. package/dist/Components/Table/Body/Rows/ColumnList.svelte +59 -59
  53. package/dist/Components/Table/Body/Rows/Columns/AccessorComponent.svelte +79 -79
  54. package/dist/Components/Table/Body/Rows/Columns/ExpandCell.svelte +120 -120
  55. package/dist/Components/Table/Body/Rows/Columns/ProgressCell.svelte +105 -105
  56. package/dist/Components/Table/Body/Rows/Columns/TableAction.svelte +87 -87
  57. package/dist/Components/Table/Body/Rows/Columns/TableCheckbox.svelte +126 -126
  58. package/dist/Components/Table/Body/Rows/Columns/TableColumn.svelte +159 -159
  59. package/dist/Components/Table/Body/Rows/Columns/TableDatePicker.svelte +246 -246
  60. package/dist/Components/Table/Body/Rows/Columns/TableNumberInput.svelte +216 -216
  61. package/dist/Components/Table/Body/Rows/Columns/TableRowSelectionCheckbox.svelte +179 -179
  62. package/dist/Components/Table/Body/Rows/Columns/TableTextInput.svelte +197 -197
  63. package/dist/Components/Table/Body/Rows/Columns/ValidityCell.svelte +190 -190
  64. package/dist/Components/Table/Body/Rows/TableRow.svelte +290 -290
  65. package/dist/Components/Table/Headers/HighlightAllHeader.svelte +41 -41
  66. package/dist/Components/Table/Headers/SelectAllHeader.svelte +30 -30
  67. package/dist/Components/Table/Misc/FilterInput.svelte +37 -16
  68. package/dist/Components/Table/Misc/SidePanel.svelte +35 -35
  69. package/dist/Components/Table/Misc/ToolboxPanel.svelte +100 -100
  70. package/dist/Components/Table/Misc/ToolboxPanelModal.svelte +107 -107
  71. package/dist/Components/Test/TestContextConsumer.svelte +13 -13
  72. package/dist/Components/TextArea.svelte +130 -130
  73. package/dist/Components/TextInput.svelte +176 -176
  74. package/dist/Components/ThreeStateRadio.svelte +131 -131
  75. package/dist/Components/Touch/BoolCard.svelte +45 -45
  76. package/dist/Components/Touch/DateModal.svelte +209 -209
  77. package/dist/Components/Touch/EditCard.svelte +59 -59
  78. package/dist/Components/Touch/InfoCard.svelte +31 -31
  79. package/dist/Components/Touch/InfoTextCard.svelte +28 -28
  80. package/dist/Components/Touch/ModalExplanation.svelte +17 -17
  81. package/dist/Components/Touch/NumberKeyboard.svelte +225 -225
  82. package/dist/Components/Touch/NumberModal.svelte +79 -79
  83. package/dist/Components/Touch/PlusMinusCard.svelte +46 -46
  84. package/dist/Components/Touch/SummaryCard.svelte +93 -93
  85. package/dist/Components/Touch/TextAreaModal.svelte +95 -95
  86. package/dist/Components/Touch/TextModal.svelte +106 -106
  87. package/dist/Components/Touch/TouchCard.svelte +33 -33
  88. package/dist/Components/Touch/TouchModal.svelte +274 -274
  89. package/dist/Components/Touch/UtilityButton.svelte +109 -109
  90. package/dist/Components/VerticalTabGroup.svelte +79 -79
  91. package/dist/Components/VerticalTabGroupButton.svelte +58 -58
  92. package/dist/Helpers/Datamatrix.d.ts +19 -19
  93. package/dist/Helpers/Datamatrix.js +291 -291
  94. package/dist/Types/Examples/ExampleModal.svelte +35 -35
  95. package/dist/scss/_basics.scss +12 -12
  96. package/dist/scss/_colours.scss +134 -134
  97. package/dist/scss/_motion.scss +57 -57
  98. package/dist/scss/_sizing.scss +85 -85
  99. package/dist/scss/_transitions.scss +8 -8
  100. package/package.json +1 -1
@@ -1,19 +1,19 @@
1
- <svelte:options runes />
2
-
3
- <script lang="ts">
4
- import type { ModalExplanationProps } from './ModalExplanationProps.js';
5
-
6
- let { width, children, nowrap }: ModalExplanationProps = $props();
7
- </script>
8
-
9
- <p
10
- class:nowrap
11
- style:--width={width}
12
- style:--padding="0"
13
- >
14
- {@render children()}
15
- </p>
16
-
1
+ <svelte:options runes />
2
+
3
+ <script lang="ts">
4
+ import type { ModalExplanationProps } from './ModalExplanationProps.js';
5
+
6
+ let { width, children, nowrap }: ModalExplanationProps = $props();
7
+ </script>
8
+
9
+ <p
10
+ class:nowrap
11
+ style:--width={width}
12
+ style:--padding="0"
13
+ >
14
+ {@render children()}
15
+ </p>
16
+
17
17
  <style>p {
18
18
  padding: var(--padding);
19
19
  color: #3a4952;
@@ -21,4 +21,4 @@
21
21
  }
22
22
  p.nowrap {
23
23
  white-space: pre-line;
24
- }</style>
24
+ }</style>
@@ -1,227 +1,227 @@
1
- <svelte:options runes />
2
-
3
- <script
4
- module
5
- lang="ts"
6
- >
7
- import { devCatch, passthrough } from '../../Helpers/Helpers.svelte.js';
8
- import { InputVariant } from '../../Types/Internal/InputVariant.js';
9
- import { tick, untrack } from 'svelte';
10
- import Icon from '../Icon.svelte';
11
- import TextInput from '../TextInput.svelte';
12
- import type { NumberKeyboardProps } from './NumberKeyboardProps.js';
13
-
14
- const DIGITS = Object.freeze([1, 2, 3, 4, 5, 6, 7, 8, 9] as const);
15
- </script>
16
-
17
- <script lang="ts">
18
- let {
19
- value = $bindable(null),
20
- label,
21
- labelRight,
22
- placeholder,
23
- min,
24
- max,
25
- decimal = false,
26
- inputRef = $bindable(),
27
- coerceValue = false,
28
- }: NumberKeyboardProps = $props();
29
-
30
- let _value: string = $derived(
31
- value != null && value % 1 == 0 ? value.toString() : getDecimalValue()
32
- );
33
-
34
- function getDecimalPlaces(value: number): number {
35
- const str = value.toString();
36
- if (!str.includes('.')) {
37
- return decimal ? 2 : 0;
38
- }
39
- return str.split('.')[1].length;
40
- }
41
-
42
- const decimalPlaces = $derived(
43
- min != null ? getDecimalPlaces(min) : max != null ? getDecimalPlaces(max) : decimal ? 2 : 0
44
- );
45
-
46
- function getDecimalValue(): string {
47
- // Use toFixed to bound decimal places, then parseFloat to drop trailing
48
- // zeros without re-introducing scientific notation. There is no built-in
49
- // "as many decimals as requested but no more" formatter.
50
- return value ? parseFloat(value.toFixed(decimalPlaces)).toString() : '';
51
- }
52
-
53
- const newValue = $derived.by(() => {
54
- const v = decimal ? parseFloat(_value) : parseInt(_value);
55
- if (isNaN(v)) {
56
- return null;
57
- }
58
- return v;
59
- });
60
-
61
- $effect(() => {
62
- if (coerceValue) {
63
- const v =
64
- min != undefined && newValue != null && min > newValue
65
- ? min
66
- : max != undefined && newValue != null && max < newValue
67
- ? max
68
- : newValue;
69
-
70
- value = v;
71
- } else {
72
- value = newValue;
73
- }
74
- });
75
-
76
- function refocus() {
77
- tick()
78
- .then(() => {
79
- if (inputRef && document.activeElement !== inputRef) {
80
- inputRef.focus();
81
- }
82
- })
83
- .catch(devCatch);
84
- }
85
-
86
- function getPrevValue() {
87
- if (inputRef) {
88
- if (
89
- (inputRef.selectionStart === 0 && inputRef.selectionEnd === _value.length) ||
90
- (inputRef.selectionEnd === 0 && inputRef.selectionStart === _value.length)
91
- ) {
92
- return '';
93
- }
94
- }
95
- return _value;
96
- }
97
-
98
- function addDecimal() {
99
- _value = getPrevValue() + '.';
100
- untrack(refocus);
101
- }
102
-
103
- /* due to the fact that number inputs won't allow a leading dot, we have to use a text input
104
- this doesn't add a number, but concatenated the digit to the end of the string
105
- */
106
- function addDigit(digit: string) {
107
- const prevValue = getPrevValue();
108
- _value = prevValue + digit;
109
- }
110
-
111
- function backspace() {
112
- const preVvalue = getPrevValue();
113
- const v = preVvalue && _value.slice(0, _value.length - 1);
114
- _value = v;
115
- untrack(refocus);
116
- }
117
-
118
- function minus() {
119
- const v = ((decimal ? parseFloat(_value) : parseInt(_value)) || 0) - 1;
120
-
121
- _value = (min != null ? Math.max(min, v) : v).toString();
122
- untrack(refocus);
123
- }
124
-
125
- function plus() {
126
- const v = ((decimal ? parseFloat(_value) : parseInt(_value)) || 0) + 1;
127
-
128
- _value = (max != null ? Math.min(max, v) : v).toString();
129
- untrack(refocus);
130
- }
131
-
132
- const lessThanMin = $derived(min != null && (value == null || value < min));
133
- const moreThanMax = $derived(max != null && (value == null || value > max));
134
-
135
- // Precompute disabled state per digit so the 10 buttons do not each evaluate
136
- // the same arithmetic on every render.
137
- const digitDisabled = $derived.by(() => {
138
- const out = new Array<boolean>(10);
139
- const base = (value ?? 0) * 10;
140
- for (let i = 0; i < 10; i++) {
141
- out[i] = max != null && base + i > max;
142
- }
143
- return out;
144
- });
145
-
146
- function onDigitClick(e: MouseEvent) {
147
- const digit = (e.currentTarget as HTMLButtonElement).dataset.digit;
148
- if (digit != null) {
149
- addDigit(digit);
150
- }
151
- }
152
- </script>
153
-
154
- <div class="number-input-wrapper">
155
- <div class="left-side">
156
- <div class="value-container">
157
- <!-- textInput is the only available option when you try to add a decimal point programmatically -->
158
- <TextInput
159
- labelTop={label}
160
- {placeholder}
161
- {labelRight}
162
- bind:inputRef
163
- bind:value={_value}
164
- variant={InputVariant.Modal}
165
- required
166
- invalid={lessThanMin || moreThanMax}
167
- />
168
- {#if max != undefined}
169
- <TextInput
170
- value={`${max}`}
171
- labelTop="Maximum"
172
- selectNone
173
- disabled
174
- variant={InputVariant.Modal}
175
- />
176
- {/if}
177
- </div>
178
- <div class="plus-minus">
179
- <button
180
- onkeydown={passthrough}
181
- type="button"
182
- disabled={value != null && min != null && value <= min}
183
- onclick={minus}><Icon name="minus" /></button
184
- >
185
- <button
186
- onkeydown={passthrough}
187
- type="button"
188
- disabled={value != null && max != null && value >= max}
189
- onclick={plus}><Icon name="plus" /></button
190
- >
191
- </div>
192
- </div>
193
- <div class="number-grid">
194
- {#each DIGITS as digit (digit)}
195
- <button
196
- onkeydown={passthrough}
197
- type="button"
198
- data-digit={digit}
199
- disabled={digitDisabled[digit]}
200
- onclick={onDigitClick}>{digit}</button
201
- >
202
- {/each}
203
- <button
204
- onkeydown={passthrough}
205
- type="button"
206
- disabled={!decimal || (value != null && value % 1 !== 0) || _value.endsWith('.')}
207
- onclick={addDecimal}>.</button
208
- >
209
- <button
210
- onkeydown={passthrough}
211
- type="button"
212
- data-digit="0"
213
- disabled={digitDisabled[0]}
214
- onclick={onDigitClick}>0</button
215
- >
216
- <button
217
- onkeydown={passthrough}
218
- type="button"
219
- disabled={_value.length === 0}
220
- onclick={backspace}>⌫</button
221
- >
222
- </div>
223
- </div>
224
-
1
+ <svelte:options runes />
2
+
3
+ <script
4
+ module
5
+ lang="ts"
6
+ >
7
+ import { devCatch, passthrough } from '../../Helpers/Helpers.svelte.js';
8
+ import { InputVariant } from '../../Types/Internal/InputVariant.js';
9
+ import { tick, untrack } from 'svelte';
10
+ import Icon from '../Icon.svelte';
11
+ import TextInput from '../TextInput.svelte';
12
+ import type { NumberKeyboardProps } from './NumberKeyboardProps.js';
13
+
14
+ const DIGITS = Object.freeze([1, 2, 3, 4, 5, 6, 7, 8, 9] as const);
15
+ </script>
16
+
17
+ <script lang="ts">
18
+ let {
19
+ value = $bindable(null),
20
+ label,
21
+ labelRight,
22
+ placeholder,
23
+ min,
24
+ max,
25
+ decimal = false,
26
+ inputRef = $bindable(),
27
+ coerceValue = false,
28
+ }: NumberKeyboardProps = $props();
29
+
30
+ let _value: string = $derived(
31
+ value != null && value % 1 == 0 ? value.toString() : getDecimalValue()
32
+ );
33
+
34
+ function getDecimalPlaces(value: number): number {
35
+ const str = value.toString();
36
+ if (!str.includes('.')) {
37
+ return decimal ? 2 : 0;
38
+ }
39
+ return str.split('.')[1].length;
40
+ }
41
+
42
+ const decimalPlaces = $derived(
43
+ min != null ? getDecimalPlaces(min) : max != null ? getDecimalPlaces(max) : decimal ? 2 : 0
44
+ );
45
+
46
+ function getDecimalValue(): string {
47
+ // Use toFixed to bound decimal places, then parseFloat to drop trailing
48
+ // zeros without re-introducing scientific notation. There is no built-in
49
+ // "as many decimals as requested but no more" formatter.
50
+ return value ? parseFloat(value.toFixed(decimalPlaces)).toString() : '';
51
+ }
52
+
53
+ const newValue = $derived.by(() => {
54
+ const v = decimal ? parseFloat(_value) : parseInt(_value);
55
+ if (isNaN(v)) {
56
+ return null;
57
+ }
58
+ return v;
59
+ });
60
+
61
+ $effect(() => {
62
+ if (coerceValue) {
63
+ const v =
64
+ min != undefined && newValue != null && min > newValue
65
+ ? min
66
+ : max != undefined && newValue != null && max < newValue
67
+ ? max
68
+ : newValue;
69
+
70
+ value = v;
71
+ } else {
72
+ value = newValue;
73
+ }
74
+ });
75
+
76
+ function refocus() {
77
+ tick()
78
+ .then(() => {
79
+ if (inputRef && document.activeElement !== inputRef) {
80
+ inputRef.focus();
81
+ }
82
+ })
83
+ .catch(devCatch);
84
+ }
85
+
86
+ function getPrevValue() {
87
+ if (inputRef) {
88
+ if (
89
+ (inputRef.selectionStart === 0 && inputRef.selectionEnd === _value.length) ||
90
+ (inputRef.selectionEnd === 0 && inputRef.selectionStart === _value.length)
91
+ ) {
92
+ return '';
93
+ }
94
+ }
95
+ return _value;
96
+ }
97
+
98
+ function addDecimal() {
99
+ _value = getPrevValue() + '.';
100
+ untrack(refocus);
101
+ }
102
+
103
+ /* due to the fact that number inputs won't allow a leading dot, we have to use a text input
104
+ this doesn't add a number, but concatenated the digit to the end of the string
105
+ */
106
+ function addDigit(digit: string) {
107
+ const prevValue = getPrevValue();
108
+ _value = prevValue + digit;
109
+ }
110
+
111
+ function backspace() {
112
+ const preVvalue = getPrevValue();
113
+ const v = preVvalue && _value.slice(0, _value.length - 1);
114
+ _value = v;
115
+ untrack(refocus);
116
+ }
117
+
118
+ function minus() {
119
+ const v = ((decimal ? parseFloat(_value) : parseInt(_value)) || 0) - 1;
120
+
121
+ _value = (min != null ? Math.max(min, v) : v).toString();
122
+ untrack(refocus);
123
+ }
124
+
125
+ function plus() {
126
+ const v = ((decimal ? parseFloat(_value) : parseInt(_value)) || 0) + 1;
127
+
128
+ _value = (max != null ? Math.min(max, v) : v).toString();
129
+ untrack(refocus);
130
+ }
131
+
132
+ const lessThanMin = $derived(min != null && (value == null || value < min));
133
+ const moreThanMax = $derived(max != null && (value == null || value > max));
134
+
135
+ // Precompute disabled state per digit so the 10 buttons do not each evaluate
136
+ // the same arithmetic on every render.
137
+ const digitDisabled = $derived.by(() => {
138
+ const out = new Array<boolean>(10);
139
+ const base = (value ?? 0) * 10;
140
+ for (let i = 0; i < 10; i++) {
141
+ out[i] = max != null && base + i > max;
142
+ }
143
+ return out;
144
+ });
145
+
146
+ function onDigitClick(e: MouseEvent) {
147
+ const digit = (e.currentTarget as HTMLButtonElement).dataset.digit;
148
+ if (digit != null) {
149
+ addDigit(digit);
150
+ }
151
+ }
152
+ </script>
153
+
154
+ <div class="number-input-wrapper">
155
+ <div class="left-side">
156
+ <div class="value-container">
157
+ <!-- textInput is the only available option when you try to add a decimal point programmatically -->
158
+ <TextInput
159
+ labelTop={label}
160
+ {placeholder}
161
+ {labelRight}
162
+ bind:inputRef
163
+ bind:value={_value}
164
+ variant={InputVariant.Modal}
165
+ required
166
+ invalid={lessThanMin || moreThanMax}
167
+ />
168
+ {#if max != undefined}
169
+ <TextInput
170
+ value={`${max}`}
171
+ labelTop="Maximum"
172
+ selectNone
173
+ disabled
174
+ variant={InputVariant.Modal}
175
+ />
176
+ {/if}
177
+ </div>
178
+ <div class="plus-minus">
179
+ <button
180
+ onkeydown={passthrough}
181
+ type="button"
182
+ disabled={value != null && min != null && value <= min}
183
+ onclick={minus}><Icon name="minus" /></button
184
+ >
185
+ <button
186
+ onkeydown={passthrough}
187
+ type="button"
188
+ disabled={value != null && max != null && value >= max}
189
+ onclick={plus}><Icon name="plus" /></button
190
+ >
191
+ </div>
192
+ </div>
193
+ <div class="number-grid">
194
+ {#each DIGITS as digit (digit)}
195
+ <button
196
+ onkeydown={passthrough}
197
+ type="button"
198
+ data-digit={digit}
199
+ disabled={digitDisabled[digit]}
200
+ onclick={onDigitClick}>{digit}</button
201
+ >
202
+ {/each}
203
+ <button
204
+ onkeydown={passthrough}
205
+ type="button"
206
+ disabled={!decimal || (value != null && value % 1 !== 0) || _value.endsWith('.')}
207
+ onclick={addDecimal}>.</button
208
+ >
209
+ <button
210
+ onkeydown={passthrough}
211
+ type="button"
212
+ data-digit="0"
213
+ disabled={digitDisabled[0]}
214
+ onclick={onDigitClick}>0</button
215
+ >
216
+ <button
217
+ onkeydown={passthrough}
218
+ type="button"
219
+ disabled={_value.length === 0}
220
+ onclick={backspace}>⌫</button
221
+ >
222
+ </div>
223
+ </div>
224
+
225
225
  <style>button {
226
226
  color: #3a4952;
227
227
  fill: #3a4952;
@@ -309,4 +309,4 @@ button {
309
309
  }
310
310
  .number-input-wrapper .number-grid {
311
311
  flex-grow: 2;
312
- }</style>
312
+ }</style>
@@ -1,81 +1,81 @@
1
- <svelte:options runes />
2
-
3
- <script lang="ts">
4
- import { useAsyncFlag } from '../../Helpers/AsyncFlag.svelte.js';
5
- import { passthrough } from '../../Helpers/Helpers.svelte.js';
6
- import NumberKeyboard from './NumberKeyboard.svelte';
7
- import type { NumberModalProps } from './NumberModalProps.js';
8
- import TouchModal from './TouchModal.svelte';
9
- let {
10
- coerceValue = false,
11
- header,
12
- value,
13
- label,
14
- placeholder,
15
- min,
16
- max,
17
- cancelEditing,
18
- confirm,
19
- decimal,
20
- isValid,
21
- explanation,
22
- }: NumberModalProps = $props();
23
-
24
- // Mirror external `value` snapshots into a writable derived. Reads from
25
- // `value` are tracked; writes happen through the assignment binding
26
- // fed back to `NumberKeyboard`.
27
- let tempValue: number | null = $derived(value);
28
-
29
- const isAcceptableValue = useAsyncFlag(
30
- () => (tempValue == null ? false : (isValid?.(tempValue) ?? true)),
31
- false
32
- );
33
- </script>
34
-
35
- <TouchModal
36
- onclose={() => {
37
- cancelEditing();
38
- }}
39
- {header}
40
- mandatory
41
- onsubmit={(e: SubmitEvent) => {
42
- e.preventDefault();
43
- if (tempValue == null) {
44
- return;
45
- }
46
- confirm(tempValue);
47
- }}
48
- {explanation}
49
- >
50
- <div class="number-input-wrapper">
51
- <NumberKeyboard
52
- {coerceValue}
53
- {min}
54
- {max}
55
- {label}
56
- {placeholder}
57
- bind:value={tempValue}
58
- {decimal}
59
- />
60
- </div>
61
- {#snippet footer()}
62
- <div class="modal-footer">
63
- <button
64
- onkeydown={passthrough}
65
- type="submit"
66
- disabled={!isAcceptableValue.value}>Confirm</button
67
- >
68
- <button
69
- onkeydown={passthrough}
70
- type="button"
71
- onclick={() => {
72
- cancelEditing();
73
- }}>Cancel</button
74
- >
75
- </div>
76
- {/snippet}
77
- </TouchModal>
78
-
1
+ <svelte:options runes />
2
+
3
+ <script lang="ts">
4
+ import { useAsyncFlag } from '../../Helpers/AsyncFlag.svelte.js';
5
+ import { passthrough } from '../../Helpers/Helpers.svelte.js';
6
+ import NumberKeyboard from './NumberKeyboard.svelte';
7
+ import type { NumberModalProps } from './NumberModalProps.js';
8
+ import TouchModal from './TouchModal.svelte';
9
+ let {
10
+ coerceValue = false,
11
+ header,
12
+ value,
13
+ label,
14
+ placeholder,
15
+ min,
16
+ max,
17
+ cancelEditing,
18
+ confirm,
19
+ decimal,
20
+ isValid,
21
+ explanation,
22
+ }: NumberModalProps = $props();
23
+
24
+ // Mirror external `value` snapshots into a writable derived. Reads from
25
+ // `value` are tracked; writes happen through the assignment binding
26
+ // fed back to `NumberKeyboard`.
27
+ let tempValue: number | null = $derived(value);
28
+
29
+ const isAcceptableValue = useAsyncFlag(
30
+ () => (tempValue == null ? false : (isValid?.(tempValue) ?? true)),
31
+ false
32
+ );
33
+ </script>
34
+
35
+ <TouchModal
36
+ onclose={() => {
37
+ cancelEditing();
38
+ }}
39
+ {header}
40
+ mandatory
41
+ onsubmit={(e: SubmitEvent) => {
42
+ e.preventDefault();
43
+ if (tempValue == null) {
44
+ return;
45
+ }
46
+ confirm(tempValue);
47
+ }}
48
+ {explanation}
49
+ >
50
+ <div class="number-input-wrapper">
51
+ <NumberKeyboard
52
+ {coerceValue}
53
+ {min}
54
+ {max}
55
+ {label}
56
+ {placeholder}
57
+ bind:value={tempValue}
58
+ {decimal}
59
+ />
60
+ </div>
61
+ {#snippet footer()}
62
+ <div class="modal-footer">
63
+ <button
64
+ onkeydown={passthrough}
65
+ type="submit"
66
+ disabled={!isAcceptableValue.value}>Confirm</button
67
+ >
68
+ <button
69
+ onkeydown={passthrough}
70
+ type="button"
71
+ onclick={() => {
72
+ cancelEditing();
73
+ }}>Cancel</button
74
+ >
75
+ </div>
76
+ {/snippet}
77
+ </TouchModal>
78
+
79
79
  <style>dialog {
80
80
  overflow: clip;
81
81
  background-color: #e9ecf1;
@@ -342,4 +342,4 @@ button {
342
342
  }
343
343
  .modal-footer button[type=submit]:not([disabled]):focus {
344
344
  outline-offset: -2px;
345
- }</style>
345
+ }</style>