@happyvertical/smrt-ui 0.57.19 → 0.57.21
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/AGENTS.md +11 -1
- package/README.md +91 -0
- package/dist/components/display/DocumentViewer.svelte +443 -0
- package/dist/components/display/DocumentViewer.svelte.d.ts +24 -0
- package/dist/components/display/DocumentViewer.svelte.d.ts.map +1 -0
- package/dist/components/display/document-viewer-logic.d.ts +35 -0
- package/dist/components/display/document-viewer-logic.d.ts.map +1 -0
- package/dist/components/display/document-viewer-logic.js +56 -0
- package/dist/components/display/index.d.ts +5 -1
- package/dist/components/display/index.d.ts.map +1 -1
- package/dist/components/display/index.js +4 -0
- package/dist/components/display/pdf-opener.d.ts +44 -0
- package/dist/components/display/pdf-opener.d.ts.map +1 -0
- package/dist/components/display/pdf-opener.js +121 -0
- package/dist/components/display/pdf-types.d.ts +19 -0
- package/dist/components/display/pdf-types.d.ts.map +1 -0
- package/dist/components/display/pdf-types.js +7 -0
- package/dist/components/display/types.d.ts +19 -0
- package/dist/components/display/types.d.ts.map +1 -1
- package/dist/components/forms/NumericKeypad.svelte +511 -0
- package/dist/components/forms/NumericKeypad.svelte.d.ts +51 -0
- package/dist/components/forms/NumericKeypad.svelte.d.ts.map +1 -0
- package/dist/components/forms/index.d.ts +3 -1
- package/dist/components/forms/index.d.ts.map +1 -1
- package/dist/components/forms/index.js +2 -0
- package/dist/components/forms/numeric-keypad-logic.d.ts +68 -0
- package/dist/components/forms/numeric-keypad-logic.d.ts.map +1 -0
- package/dist/components/forms/numeric-keypad-logic.js +157 -0
- package/dist/components/forms/types.d.ts +17 -0
- package/dist/components/forms/types.d.ts.map +1 -1
- package/dist/i18n/strings.ui.d.ts +23 -0
- package/dist/i18n/strings.ui.d.ts.map +1 -1
- package/dist/i18n/strings.ui.js +25 -0
- package/dist/svelte/playground/TouchToolsPreview.svelte +47 -0
- package/dist/svelte/playground/TouchToolsPreview.svelte.d.ts +4 -0
- package/dist/svelte/playground/TouchToolsPreview.svelte.d.ts.map +1 -0
- package/dist/svelte/playground.d.ts.map +1 -1
- package/dist/svelte/playground.js +10 -0
- package/package.json +13 -2
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
On-screen number keypad for quantities and money, sized for gloved hands.
|
|
3
|
+
|
|
4
|
+
Typed text is the value: `value` ($bindable) holds exactly what was typed,
|
|
5
|
+
as a string (`"12.5"`). A 3x4 grid carries the digits, a decimal point
|
|
6
|
+
(only when `maxDecimals` > 0) and backspace; Clear sits beside the display
|
|
7
|
+
and an optional confirm key sits under the grid. All entry rules live in the
|
|
8
|
+
Svelte-free `numeric-keypad-logic.ts`.
|
|
9
|
+
|
|
10
|
+
`mode="money"` keeps integer minor units: the decimals allowed follow the
|
|
11
|
+
currency's ISO 4217 exponent, callbacks carry `minorUnits` computed by string
|
|
12
|
+
arithmetic (never a float), and a `name` posts that integer. In number mode a
|
|
13
|
+
`name` posts the typed text. Hardware keys work while focus is inside the
|
|
14
|
+
keypad: digits, `.` / `,` for the point, Backspace, Delete (clear) and Enter
|
|
15
|
+
(confirm, when the keypad itself rather than a key has focus).
|
|
16
|
+
|
|
17
|
+
Every key is at least 4rem square. The display is a polite live region.
|
|
18
|
+
This is a quantity/money pad, not a PIN pad: the value is shown as text.
|
|
19
|
+
|
|
20
|
+
smrt#3463.
|
|
21
|
+
-->
|
|
22
|
+
<script lang="ts">
|
|
23
|
+
import { M, useI18n } from '../../i18n/index.js';
|
|
24
|
+
import { renderTemplate } from '../../i18n/render.js';
|
|
25
|
+
import {
|
|
26
|
+
focusControl,
|
|
27
|
+
highlightControl,
|
|
28
|
+
revealControl,
|
|
29
|
+
} from './control-dom.js';
|
|
30
|
+
import type { ControlInteractionOptions } from './control-interaction.js';
|
|
31
|
+
import { tryGetControlInteractionContext } from './control-interaction-context.js';
|
|
32
|
+
import {
|
|
33
|
+
applyKey,
|
|
34
|
+
DEFAULT_MAX_LENGTH,
|
|
35
|
+
type EntryRules,
|
|
36
|
+
exceedsMax,
|
|
37
|
+
type KeypadKey,
|
|
38
|
+
keyFromKeyboard,
|
|
39
|
+
minorUnitExponent,
|
|
40
|
+
type NumericKeypadDetail,
|
|
41
|
+
normalizeText,
|
|
42
|
+
parseEntry,
|
|
43
|
+
textToMinorUnits,
|
|
44
|
+
validateEntry,
|
|
45
|
+
} from './numeric-keypad-logic.js';
|
|
46
|
+
import type { NumericKeypadLabels } from './types.js';
|
|
47
|
+
import { useControlRegistration } from './use-control-registration.svelte.js';
|
|
48
|
+
|
|
49
|
+
export interface Props {
|
|
50
|
+
/** Typed text; a number is accepted and re-written as text on the next key. */
|
|
51
|
+
value?: string | number | null;
|
|
52
|
+
/** `money` follows the currency's minor-unit exponent. Default `number`. */
|
|
53
|
+
mode?: 'number' | 'money';
|
|
54
|
+
/** Smallest acceptable value (major units); below it the keypad shows an error. */
|
|
55
|
+
min?: number;
|
|
56
|
+
/** Largest acceptable value (major units). */
|
|
57
|
+
max?: number;
|
|
58
|
+
/** Refuse a key press that would take the value above `max`. */
|
|
59
|
+
clampToMax?: boolean;
|
|
60
|
+
/** Digits after the point; 0 is integer-only. Default 0, or the currency's in money mode. */
|
|
61
|
+
maxDecimals?: number;
|
|
62
|
+
/** Longest typed text, counting the point. */
|
|
63
|
+
maxLength?: number;
|
|
64
|
+
/** ISO 4217 code for money mode (sets the minor-unit exponent). Default exponent 2. */
|
|
65
|
+
currency?: string;
|
|
66
|
+
/** Override the money minor-unit exponent. */
|
|
67
|
+
minorUnitExponent?: number;
|
|
68
|
+
/** Shown before the display value (a currency symbol). */
|
|
69
|
+
prefix?: string;
|
|
70
|
+
/** Shown after the display value (a unit such as `pcs`). */
|
|
71
|
+
unit?: string;
|
|
72
|
+
/** Accessible name; defaults to the `labels.region` text. */
|
|
73
|
+
label?: string;
|
|
74
|
+
/** Called after every change with the parsed entry. */
|
|
75
|
+
onChange?: (detail: NumericKeypadDetail) => void;
|
|
76
|
+
/** Called by the confirm key / Enter; supplying it shows the confirm key. */
|
|
77
|
+
onSubmit?: (detail: NumericKeypadDetail) => void;
|
|
78
|
+
/** Confirm key text; defaults to the catalog's "Confirm". */
|
|
79
|
+
submitLabel?: string;
|
|
80
|
+
/** Ignores input and disables every key. */
|
|
81
|
+
disabled?: boolean;
|
|
82
|
+
/** Field name: posts the typed text (number) or integer minor units (money). */
|
|
83
|
+
name?: string;
|
|
84
|
+
/** Text overrides; defaults come from the `ui` i18n catalog. */
|
|
85
|
+
labels?: Partial<NumericKeypadLabels>;
|
|
86
|
+
/** DOM id of the component root. */
|
|
87
|
+
id?: string;
|
|
88
|
+
/** CSS class to apply to the component root. */
|
|
89
|
+
class?: string;
|
|
90
|
+
/** Interaction options or false to disable registration. */
|
|
91
|
+
interaction?: ControlInteractionOptions | false;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
let {
|
|
95
|
+
value = $bindable(''),
|
|
96
|
+
mode = 'number',
|
|
97
|
+
min,
|
|
98
|
+
max,
|
|
99
|
+
clampToMax = false,
|
|
100
|
+
maxDecimals,
|
|
101
|
+
maxLength = DEFAULT_MAX_LENGTH,
|
|
102
|
+
currency,
|
|
103
|
+
minorUnitExponent: exponentOverride,
|
|
104
|
+
prefix,
|
|
105
|
+
unit,
|
|
106
|
+
label,
|
|
107
|
+
onChange,
|
|
108
|
+
onSubmit,
|
|
109
|
+
submitLabel,
|
|
110
|
+
disabled = false,
|
|
111
|
+
name,
|
|
112
|
+
labels,
|
|
113
|
+
id,
|
|
114
|
+
class: className = '',
|
|
115
|
+
interaction,
|
|
116
|
+
}: Props = $props();
|
|
117
|
+
|
|
118
|
+
const { t } = useI18n();
|
|
119
|
+
const text = $derived<NumericKeypadLabels>({
|
|
120
|
+
region: t(M['ui.numeric_keypad.region']),
|
|
121
|
+
display: t(M['ui.numeric_keypad.display']),
|
|
122
|
+
decimal: t(M['ui.numeric_keypad.decimal']),
|
|
123
|
+
backspace: t(M['ui.numeric_keypad.backspace']),
|
|
124
|
+
clear: t(M['ui.numeric_keypad.clear']),
|
|
125
|
+
submit: submitLabel ?? t(M['ui.numeric_keypad.submit']),
|
|
126
|
+
belowMin: t(M['ui.numeric_keypad.below_min']),
|
|
127
|
+
aboveMax: t(M['ui.numeric_keypad.above_max']),
|
|
128
|
+
invalidAmount: t(M['ui.numeric_keypad.invalid_amount']),
|
|
129
|
+
...labels,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const instanceId = $props.id();
|
|
133
|
+
const interactionContext = tryGetControlInteractionContext();
|
|
134
|
+
const resolvedId = $derived(id ?? `smrt-keypad-${instanceId}`);
|
|
135
|
+
const messageId = $derived(`${resolvedId}-message`);
|
|
136
|
+
const controlId = $derived(
|
|
137
|
+
interaction === false ? undefined : (interaction?.id ?? name ?? resolvedId),
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
const exponent = $derived(exponentOverride ?? minorUnitExponent(currency, 2));
|
|
141
|
+
const decimals = $derived(maxDecimals ?? (mode === 'money' ? exponent : 0));
|
|
142
|
+
// Money cannot carry more decimals than the currency has minor units.
|
|
143
|
+
const rules = $derived<EntryRules>({
|
|
144
|
+
maxDecimals: mode === 'money' ? Math.min(decimals, exponent) : decimals,
|
|
145
|
+
maxLength,
|
|
146
|
+
});
|
|
147
|
+
const typed = $derived(normalizeText(value, rules));
|
|
148
|
+
const validity = $derived(entryValidity(typed));
|
|
149
|
+
const showError = $derived(
|
|
150
|
+
validity === 'below' || validity === 'above' || validity === 'invalid',
|
|
151
|
+
);
|
|
152
|
+
const errorText = $derived(
|
|
153
|
+
validity === 'below'
|
|
154
|
+
? renderTemplate(text.belowMin, { min })
|
|
155
|
+
: validity === 'above'
|
|
156
|
+
? renderTemplate(text.aboveMax, { max })
|
|
157
|
+
: validity === 'invalid'
|
|
158
|
+
? text.invalidAmount
|
|
159
|
+
: '',
|
|
160
|
+
);
|
|
161
|
+
const minorUnits = $derived(
|
|
162
|
+
mode === 'money' ? textToMinorUnits(typed, exponent) : null,
|
|
163
|
+
);
|
|
164
|
+
const postedValue = $derived(
|
|
165
|
+
mode === 'money' ? (minorUnits === null ? '' : String(minorUnits)) : typed,
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
let rootEl = $state<HTMLDivElement | null>(null);
|
|
169
|
+
|
|
170
|
+
function entryValidity(next: string) {
|
|
171
|
+
const result = validateEntry(next, { min, max });
|
|
172
|
+
return result === 'ok' &&
|
|
173
|
+
mode === 'money' &&
|
|
174
|
+
textToMinorUnits(next, exponent) === null
|
|
175
|
+
? 'invalid'
|
|
176
|
+
: result;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function detail(next: string): NumericKeypadDetail {
|
|
180
|
+
return {
|
|
181
|
+
text: next,
|
|
182
|
+
number: parseEntry(next),
|
|
183
|
+
minorUnits: mode === 'money' ? textToMinorUnits(next, exponent) : null,
|
|
184
|
+
valid: entryValidity(next) === 'ok',
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function press(key: KeypadKey): void {
|
|
189
|
+
if (disabled) return;
|
|
190
|
+
const next = applyKey(typed, key, rules);
|
|
191
|
+
if (clampToMax && key.kind !== 'backspace' && key.kind !== 'clear') {
|
|
192
|
+
if (exceedsMax(next, max)) return;
|
|
193
|
+
}
|
|
194
|
+
if (next === typed && value === typed) return;
|
|
195
|
+
value = next;
|
|
196
|
+
onChange?.(detail(next));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function submit(): void {
|
|
200
|
+
if (disabled || !onSubmit || validity !== 'ok') return;
|
|
201
|
+
onSubmit(detail(typed));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function handleKeydown(event: KeyboardEvent): void {
|
|
205
|
+
if (disabled || event.defaultPrevented) return;
|
|
206
|
+
if (event.ctrlKey || event.metaKey || event.altKey) return;
|
|
207
|
+
// Enter on a focused key activates that key natively; only the keypad
|
|
208
|
+
// itself (focus on the root) confirms.
|
|
209
|
+
if (event.key === 'Enter') {
|
|
210
|
+
if (event.target === rootEl && onSubmit) {
|
|
211
|
+
event.preventDefault();
|
|
212
|
+
submit();
|
|
213
|
+
}
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const key = keyFromKeyboard(event.key);
|
|
217
|
+
if (!key) return;
|
|
218
|
+
event.preventDefault();
|
|
219
|
+
press(key);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function setFromOutside(next: unknown): void {
|
|
223
|
+
const prepared = prepareValue(next);
|
|
224
|
+
value = prepared as string;
|
|
225
|
+
onChange?.(detail(prepared as string));
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function prepareValue(next: unknown): unknown {
|
|
229
|
+
if (next === null || next === undefined || next === '') return '';
|
|
230
|
+
if (typeof next !== 'string' && typeof next !== 'number') {
|
|
231
|
+
throw new Error('staged_value_invalid');
|
|
232
|
+
}
|
|
233
|
+
const normalized = normalizeText(next, rules);
|
|
234
|
+
if (normalized === '') throw new Error('staged_value_invalid');
|
|
235
|
+
return normalized;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
useControlRegistration(() => {
|
|
239
|
+
const root = rootEl;
|
|
240
|
+
if (!root || interaction === false) return false;
|
|
241
|
+
return {
|
|
242
|
+
controlId,
|
|
243
|
+
subject: interaction?.subject,
|
|
244
|
+
metadata: {
|
|
245
|
+
kind: 'number',
|
|
246
|
+
label: label ?? text.region,
|
|
247
|
+
description: interaction?.description,
|
|
248
|
+
sensitivity: interaction?.sensitivity ?? 'public',
|
|
249
|
+
readable: interaction?.readable,
|
|
250
|
+
writable: interaction?.writable,
|
|
251
|
+
constraints: { min, max },
|
|
252
|
+
unit,
|
|
253
|
+
},
|
|
254
|
+
getValue: () => typed,
|
|
255
|
+
prepareValue,
|
|
256
|
+
setValue: setFromOutside,
|
|
257
|
+
clear: () => {
|
|
258
|
+
press({ kind: 'clear' });
|
|
259
|
+
return true;
|
|
260
|
+
},
|
|
261
|
+
focus: () => focusControl(root),
|
|
262
|
+
reveal: () => revealControl(root),
|
|
263
|
+
highlight: (durationMs) => highlightControl(root, durationMs),
|
|
264
|
+
validate: () => validity === 'ok' || validity === 'empty',
|
|
265
|
+
validateValue: (next) => {
|
|
266
|
+
try {
|
|
267
|
+
const outcome = entryValidity(String(prepareValue(next)));
|
|
268
|
+
return outcome === 'ok' || outcome === 'empty';
|
|
269
|
+
} catch {
|
|
270
|
+
return false;
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
getState: () => ({ disabled, valid: !showError }),
|
|
274
|
+
};
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
const DIGIT_ROWS = [
|
|
278
|
+
['1', '2', '3'],
|
|
279
|
+
['4', '5', '6'],
|
|
280
|
+
['7', '8', '9'],
|
|
281
|
+
] as const;
|
|
282
|
+
</script>
|
|
283
|
+
|
|
284
|
+
<!-- svelte-ignore a11y_no_noninteractive_element_interactions, a11y_no_noninteractive_tabindex (hardware keyboard entry: the group takes focus so typed digits work before any key is touched) -->
|
|
285
|
+
<div
|
|
286
|
+
bind:this={rootEl}
|
|
287
|
+
id={resolvedId}
|
|
288
|
+
class="numeric-keypad {className}"
|
|
289
|
+
class:disabled
|
|
290
|
+
role="group"
|
|
291
|
+
tabindex={disabled ? undefined : 0}
|
|
292
|
+
aria-label={label ?? text.region}
|
|
293
|
+
data-state={validity}
|
|
294
|
+
data-mode={mode}
|
|
295
|
+
data-smrt-control={controlId}
|
|
296
|
+
data-smrt-form={interactionContext?.formId}
|
|
297
|
+
data-smrt-subject-type={interaction === false ? undefined : interaction?.subject?.type}
|
|
298
|
+
data-smrt-subject-id={interaction === false ? undefined : interaction?.subject?.id}
|
|
299
|
+
data-smrt-component="NumericKeypad"
|
|
300
|
+
onkeydown={handleKeydown}
|
|
301
|
+
>
|
|
302
|
+
<div class="readout">
|
|
303
|
+
<output
|
|
304
|
+
class="display"
|
|
305
|
+
data-smrt-part="display"
|
|
306
|
+
data-empty={typed === '' ? 'true' : undefined}
|
|
307
|
+
aria-label={text.display}
|
|
308
|
+
aria-live="polite"
|
|
309
|
+
aria-atomic="true"
|
|
310
|
+
aria-describedby={showError ? messageId : undefined}
|
|
311
|
+
>
|
|
312
|
+
{#if prefix}<span class="affix" data-smrt-part="prefix">{prefix}</span>{/if}
|
|
313
|
+
<span class="entry">{typed === '' ? '0' : typed}</span>
|
|
314
|
+
{#if unit}<span class="affix" data-smrt-part="unit">{unit}</span>{/if}
|
|
315
|
+
</output>
|
|
316
|
+
<button
|
|
317
|
+
type="button"
|
|
318
|
+
class="key clear"
|
|
319
|
+
data-smrt-part="key"
|
|
320
|
+
data-key="clear"
|
|
321
|
+
aria-label={text.clear}
|
|
322
|
+
{disabled}
|
|
323
|
+
onclick={() => press({ kind: 'clear' })}
|
|
324
|
+
>
|
|
325
|
+
{text.clear}
|
|
326
|
+
</button>
|
|
327
|
+
</div>
|
|
328
|
+
|
|
329
|
+
<p id={messageId} class="message" data-smrt-part="message" role="status">{errorText}</p>
|
|
330
|
+
|
|
331
|
+
<div class="grid" data-smrt-part="grid">
|
|
332
|
+
{#each DIGIT_ROWS as row (row[0])}
|
|
333
|
+
{#each row as digit (digit)}
|
|
334
|
+
<button
|
|
335
|
+
type="button"
|
|
336
|
+
class="key digit"
|
|
337
|
+
data-smrt-part="key"
|
|
338
|
+
data-key={digit}
|
|
339
|
+
aria-label={digit}
|
|
340
|
+
{disabled}
|
|
341
|
+
onclick={() => press({ kind: 'digit', digit })}
|
|
342
|
+
>
|
|
343
|
+
{digit}
|
|
344
|
+
</button>
|
|
345
|
+
{/each}
|
|
346
|
+
{/each}
|
|
347
|
+
{#if rules.maxDecimals > 0}
|
|
348
|
+
<button
|
|
349
|
+
type="button"
|
|
350
|
+
class="key"
|
|
351
|
+
data-smrt-part="key"
|
|
352
|
+
data-key="decimal"
|
|
353
|
+
aria-label={text.decimal}
|
|
354
|
+
{disabled}
|
|
355
|
+
onclick={() => press({ kind: 'decimal' })}
|
|
356
|
+
>
|
|
357
|
+
.
|
|
358
|
+
</button>
|
|
359
|
+
{:else}
|
|
360
|
+
<span class="spacer" aria-hidden="true"></span>
|
|
361
|
+
{/if}
|
|
362
|
+
<button
|
|
363
|
+
type="button"
|
|
364
|
+
class="key digit"
|
|
365
|
+
data-smrt-part="key"
|
|
366
|
+
data-key="0"
|
|
367
|
+
aria-label="0"
|
|
368
|
+
{disabled}
|
|
369
|
+
onclick={() => press({ kind: 'digit', digit: '0' })}
|
|
370
|
+
>
|
|
371
|
+
0
|
|
372
|
+
</button>
|
|
373
|
+
<button
|
|
374
|
+
type="button"
|
|
375
|
+
class="key"
|
|
376
|
+
data-smrt-part="key"
|
|
377
|
+
data-key="backspace"
|
|
378
|
+
aria-label={text.backspace}
|
|
379
|
+
{disabled}
|
|
380
|
+
onclick={() => press({ kind: 'backspace' })}
|
|
381
|
+
>
|
|
382
|
+
<span aria-hidden="true">⌫</span>
|
|
383
|
+
</button>
|
|
384
|
+
</div>
|
|
385
|
+
|
|
386
|
+
{#if onSubmit}
|
|
387
|
+
<button
|
|
388
|
+
type="button"
|
|
389
|
+
class="key submit"
|
|
390
|
+
data-smrt-part="submit"
|
|
391
|
+
aria-label={text.submit}
|
|
392
|
+
disabled={disabled || validity !== 'ok'}
|
|
393
|
+
onclick={submit}
|
|
394
|
+
>
|
|
395
|
+
{text.submit}
|
|
396
|
+
</button>
|
|
397
|
+
{/if}
|
|
398
|
+
|
|
399
|
+
{#if name}
|
|
400
|
+
<input type="hidden" {name} value={postedValue} {disabled} data-smrt-keypad-field />
|
|
401
|
+
{/if}
|
|
402
|
+
</div>
|
|
403
|
+
|
|
404
|
+
<style>
|
|
405
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
406
|
+
@layer smrt.theme {
|
|
407
|
+
.numeric-keypad {
|
|
408
|
+
display: grid;
|
|
409
|
+
gap: var(--smrt-spacing-3);
|
|
410
|
+
width: 100%;
|
|
411
|
+
max-width: 24rem;
|
|
412
|
+
color: var(--smrt-color-on-surface);
|
|
413
|
+
}
|
|
414
|
+
.numeric-keypad:focus-visible {
|
|
415
|
+
outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
|
|
416
|
+
outline-offset: var(--smrt-focus-ring-offset);
|
|
417
|
+
}
|
|
418
|
+
.readout {
|
|
419
|
+
display: flex;
|
|
420
|
+
gap: var(--smrt-spacing-3);
|
|
421
|
+
align-items: stretch;
|
|
422
|
+
}
|
|
423
|
+
.display {
|
|
424
|
+
display: flex;
|
|
425
|
+
flex: 1 1 auto;
|
|
426
|
+
align-items: baseline;
|
|
427
|
+
justify-content: flex-end;
|
|
428
|
+
gap: var(--smrt-spacing-2);
|
|
429
|
+
min-width: 0;
|
|
430
|
+
min-height: 4rem;
|
|
431
|
+
padding: 0 var(--smrt-spacing-4);
|
|
432
|
+
border: var(--smrt-hairline-strong);
|
|
433
|
+
border-radius: var(--smrt-radius-medium);
|
|
434
|
+
background: var(--smrt-color-surface-container-lowest);
|
|
435
|
+
font: var(--smrt-typography-headline-large-font);
|
|
436
|
+
align-items: center;
|
|
437
|
+
overflow: hidden;
|
|
438
|
+
}
|
|
439
|
+
[data-state='below'] .display,
|
|
440
|
+
[data-state='above'] .display {
|
|
441
|
+
border-color: var(--smrt-color-error);
|
|
442
|
+
}
|
|
443
|
+
.display[data-empty='true'] .entry {
|
|
444
|
+
color: var(--smrt-color-on-surface-variant);
|
|
445
|
+
}
|
|
446
|
+
.entry {
|
|
447
|
+
overflow: hidden;
|
|
448
|
+
text-overflow: ellipsis;
|
|
449
|
+
white-space: nowrap;
|
|
450
|
+
font-variant-numeric: tabular-nums;
|
|
451
|
+
}
|
|
452
|
+
.affix {
|
|
453
|
+
color: var(--smrt-color-on-surface-variant);
|
|
454
|
+
font: var(--smrt-typography-title-large-font);
|
|
455
|
+
}
|
|
456
|
+
.message {
|
|
457
|
+
margin: 0;
|
|
458
|
+
color: var(--smrt-color-error);
|
|
459
|
+
font: var(--smrt-typography-body-medium-font);
|
|
460
|
+
}
|
|
461
|
+
.message:empty {
|
|
462
|
+
display: none;
|
|
463
|
+
}
|
|
464
|
+
.grid {
|
|
465
|
+
display: grid;
|
|
466
|
+
grid-template-columns: repeat(3, 1fr);
|
|
467
|
+
gap: var(--smrt-spacing-3);
|
|
468
|
+
}
|
|
469
|
+
.key {
|
|
470
|
+
/* Gloved hands: never below 4rem, whatever the density token says. */
|
|
471
|
+
min-width: max(4rem, var(--smrt-touch-target-min));
|
|
472
|
+
min-height: max(4rem, var(--smrt-touch-target-min));
|
|
473
|
+
padding: 0 var(--smrt-spacing-3);
|
|
474
|
+
border: var(--smrt-hairline-strong);
|
|
475
|
+
border-radius: var(--smrt-radius-medium);
|
|
476
|
+
background: var(--smrt-color-surface-container-highest);
|
|
477
|
+
color: var(--smrt-color-on-surface);
|
|
478
|
+
font: var(--smrt-typography-headline-large-font);
|
|
479
|
+
cursor: pointer;
|
|
480
|
+
touch-action: manipulation;
|
|
481
|
+
user-select: none;
|
|
482
|
+
}
|
|
483
|
+
.key.clear {
|
|
484
|
+
font: var(--smrt-typography-label-large-font);
|
|
485
|
+
}
|
|
486
|
+
.key:active:not(:disabled) {
|
|
487
|
+
background: var(--smrt-color-surface-container-high);
|
|
488
|
+
}
|
|
489
|
+
.key.submit {
|
|
490
|
+
border-color: var(--smrt-color-primary);
|
|
491
|
+
background: var(--smrt-color-primary);
|
|
492
|
+
color: var(--smrt-color-on-primary);
|
|
493
|
+
font: var(--smrt-typography-title-large-font);
|
|
494
|
+
}
|
|
495
|
+
.key:focus-visible {
|
|
496
|
+
outline: var(--smrt-focus-ring-width) solid var(--smrt-focus-ring-color);
|
|
497
|
+
outline-offset: var(--smrt-focus-ring-offset);
|
|
498
|
+
}
|
|
499
|
+
.key:disabled {
|
|
500
|
+
opacity: 0.5;
|
|
501
|
+
cursor: not-allowed;
|
|
502
|
+
}
|
|
503
|
+
.disabled .display {
|
|
504
|
+
opacity: 0.5;
|
|
505
|
+
}
|
|
506
|
+
:global(.numeric-keypad[data-smrt-highlighted='true']) {
|
|
507
|
+
outline: var(--smrt-focus-ring-width) solid var(--smrt-color-tertiary);
|
|
508
|
+
outline-offset: var(--smrt-focus-ring-offset);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
</style>
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { ControlInteractionOptions } from './control-interaction.js';
|
|
2
|
+
import { type NumericKeypadDetail } from './numeric-keypad-logic.js';
|
|
3
|
+
import type { NumericKeypadLabels } from './types.js';
|
|
4
|
+
export interface Props {
|
|
5
|
+
/** Typed text; a number is accepted and re-written as text on the next key. */
|
|
6
|
+
value?: string | number | null;
|
|
7
|
+
/** `money` follows the currency's minor-unit exponent. Default `number`. */
|
|
8
|
+
mode?: 'number' | 'money';
|
|
9
|
+
/** Smallest acceptable value (major units); below it the keypad shows an error. */
|
|
10
|
+
min?: number;
|
|
11
|
+
/** Largest acceptable value (major units). */
|
|
12
|
+
max?: number;
|
|
13
|
+
/** Refuse a key press that would take the value above `max`. */
|
|
14
|
+
clampToMax?: boolean;
|
|
15
|
+
/** Digits after the point; 0 is integer-only. Default 0, or the currency's in money mode. */
|
|
16
|
+
maxDecimals?: number;
|
|
17
|
+
/** Longest typed text, counting the point. */
|
|
18
|
+
maxLength?: number;
|
|
19
|
+
/** ISO 4217 code for money mode (sets the minor-unit exponent). Default exponent 2. */
|
|
20
|
+
currency?: string;
|
|
21
|
+
/** Override the money minor-unit exponent. */
|
|
22
|
+
minorUnitExponent?: number;
|
|
23
|
+
/** Shown before the display value (a currency symbol). */
|
|
24
|
+
prefix?: string;
|
|
25
|
+
/** Shown after the display value (a unit such as `pcs`). */
|
|
26
|
+
unit?: string;
|
|
27
|
+
/** Accessible name; defaults to the `labels.region` text. */
|
|
28
|
+
label?: string;
|
|
29
|
+
/** Called after every change with the parsed entry. */
|
|
30
|
+
onChange?: (detail: NumericKeypadDetail) => void;
|
|
31
|
+
/** Called by the confirm key / Enter; supplying it shows the confirm key. */
|
|
32
|
+
onSubmit?: (detail: NumericKeypadDetail) => void;
|
|
33
|
+
/** Confirm key text; defaults to the catalog's "Confirm". */
|
|
34
|
+
submitLabel?: string;
|
|
35
|
+
/** Ignores input and disables every key. */
|
|
36
|
+
disabled?: boolean;
|
|
37
|
+
/** Field name: posts the typed text (number) or integer minor units (money). */
|
|
38
|
+
name?: string;
|
|
39
|
+
/** Text overrides; defaults come from the `ui` i18n catalog. */
|
|
40
|
+
labels?: Partial<NumericKeypadLabels>;
|
|
41
|
+
/** DOM id of the component root. */
|
|
42
|
+
id?: string;
|
|
43
|
+
/** CSS class to apply to the component root. */
|
|
44
|
+
class?: string;
|
|
45
|
+
/** Interaction options or false to disable registration. */
|
|
46
|
+
interaction?: ControlInteractionOptions | false;
|
|
47
|
+
}
|
|
48
|
+
declare const NumericKeypad: import("svelte").Component<Props, {}, "value">;
|
|
49
|
+
type NumericKeypad = ReturnType<typeof NumericKeypad>;
|
|
50
|
+
export default NumericKeypad;
|
|
51
|
+
//# sourceMappingURL=NumericKeypad.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NumericKeypad.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/forms/NumericKeypad.svelte.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAE1E,OAAO,EAQL,KAAK,mBAAmB,EAKzB,MAAM,2BAA2B,CAAC;AACnC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAItD,MAAM,WAAW,KAAK;IACpB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC/B,4EAA4E;IAC5E,IAAI,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC;IAC1B,mFAAmF;IACnF,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,6FAA6F;IAC7F,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uFAAuF;IACvF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8CAA8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,0DAA0D;IAC1D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4DAA4D;IAC5D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,uDAAuD;IACvD,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACjD,6EAA6E;IAC7E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAC;IACjD,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,gFAAgF;IAChF,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,MAAM,CAAC,EAAE,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACtC,oCAAoC;IACpC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gDAAgD;IAChD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4DAA4D;IAC5D,WAAW,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAAC;CACjD;AAgQD,QAAA,MAAM,aAAa,gDAAwC,CAAC;AAC5D,KAAK,aAAa,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC;AACtD,eAAe,aAAa,CAAC"}
|
|
@@ -44,7 +44,9 @@ export { insertTextAtCursor } from './insert-text.js';
|
|
|
44
44
|
export { default as Listbox } from './Listbox.svelte';
|
|
45
45
|
export { createLongPress, LONG_PRESS_DEFAULT_DELAY_MS, LONG_PRESS_DEFAULT_MOVE_TOLERANCE_PX, type LongPressController, type LongPressDetail, type LongPressOptions, longPress, } from './long-press.js';
|
|
46
46
|
export { default as MultiSelect } from './MultiSelect.svelte';
|
|
47
|
+
export { default as NumericKeypad } from './NumericKeypad.svelte';
|
|
47
48
|
export { detectNativeFileFieldStrategy, type NativeFileFieldStrategy, } from './native-file-field.js';
|
|
49
|
+
export { applyKey as applyKeypadKey, type EntryValidity, type KeypadKey, minorUnitExponent, minorUnitsToText, type NumericKeypadDetail, textToMinorUnits, validateEntry as validateKeypadEntry, } from './numeric-keypad-logic.js';
|
|
48
50
|
export { default as ProvinceSelect } from './ProvinceSelect.svelte';
|
|
49
51
|
export { default as Radio } from './Radio.svelte';
|
|
50
52
|
export { default as RadioGroup } from './RadioGroup.svelte';
|
|
@@ -65,6 +67,6 @@ export { default as Textarea } from './Textarea.svelte';
|
|
|
65
67
|
export { default as TimePicker } from './TimePicker.svelte';
|
|
66
68
|
export { default as Toggle } from './Toggle.svelte';
|
|
67
69
|
export { default as ToggleButton } from './ToggleButton.svelte';
|
|
68
|
-
export type { CameraCaptureLabels, CameraCaptureState, CaptureResult, FormError, RangeSliderValue, RelationOption, SegmentedControlOption, SignaturePadLabels, SignaturePadState, } from './types.js';
|
|
70
|
+
export type { CameraCaptureLabels, CameraCaptureState, CaptureResult, FormError, NumericKeypadLabels, RangeSliderValue, RelationOption, SegmentedControlOption, SignaturePadLabels, SignaturePadState, } from './types.js';
|
|
69
71
|
export { type ControlRegistrationDescriptor, useControlRegistration, } from './use-control-registration.svelte.js';
|
|
70
72
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/forms/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EACL,wBAAwB,EACxB,0BAA0B,EAC1B,0BAA0B,EAC1B,mBAAmB,EACnB,yBAAyB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,4BAA4B,EACjC,KAAK,4BAA4B,EACjC,cAAc,EACd,KAAK,kBAAkB,EACvB,qBAAqB,GACtB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EACL,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,yBAAyB,EACzB,mBAAmB,EACnB,oBAAoB,EACpB,KAAK,gBAAgB,GACtB,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,gBAAgB,EAChB,kBAAkB,EAClB,mBAAmB,EACnB,mBAAmB,GACpB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACnB,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,eAAe,EACpB,KAAK,uBAAuB,EAC5B,KAAK,yBAAyB,EAC9B,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,eAAe,EACpB,KAAK,kBAAkB,EACvB,KAAK,uBAAuB,EAC5B,KAAK,cAAc,EACnB,KAAK,4BAA4B,EACjC,gCAAgC,EAChC,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,0BAA0B,CAAC;AAClC,OAAO,EACL,KAAK,8BAA8B,EACnC,4BAA4B,EAC5B,qBAAqB,EACrB,4BAA4B,EAC5B,+BAA+B,GAChC,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EACL,KAAK,sBAAsB,EAC3B,0BAA0B,EAC1B,yBAAyB,EACzB,qBAAqB,EACrB,uBAAuB,EACvB,mBAAmB,EACnB,kBAAkB,EAClB,KAAK,2BAA2B,EAChC,qBAAqB,GACtB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EACL,sBAAsB,EACtB,SAAS,EACT,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACnB,kBAAkB,GACnB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EACL,qBAAqB,EACrB,KAAK,mBAAmB,EACxB,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,GAC5B,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EACL,KAAK,qBAAqB,EAC1B,WAAW,EACX,mBAAmB,EACnB,sBAAsB,GACvB,MAAM,yBAAyB,CAAC;AAEjC,cAAc,uBAAuB,CAAC;AACtC,OAAO,EACL,mBAAmB,EACnB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,GACzB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,kBAAkB,CAAC;AACtD,OAAO,EACL,eAAe,EACf,2BAA2B,EAC3B,oCAAoC,EACpC,KAAK,mBAAmB,EACxB,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACrB,SAAS,GACV,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EACL,6BAA6B,EAC7B,KAAK,uBAAuB,GAC7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,OAAO,IAAI,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EACL,aAAa,EACb,cAAc,EACd,KAAK,gBAAgB,GACtB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EACL,qBAAqB,EACrB,uBAAuB,EACvB,KAAK,oBAAoB,GAC1B,MAAM,0BAA0B,CAAC;AAClC,YAAY,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAChE,YAAY,EACV,mBAAmB,EACnB,kBAAkB,EAClB,aAAa,EACb,SAAS,EACT,gBAAgB,EAChB,cAAc,EACd,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,6BAA6B,EAClC,sBAAsB,GACvB,MAAM,sCAAsC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/forms/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -45,7 +45,9 @@ export { insertTextAtCursor } from './insert-text.js';
|
|
|
45
45
|
export { default as Listbox } from './Listbox.svelte';
|
|
46
46
|
export { createLongPress, LONG_PRESS_DEFAULT_DELAY_MS, LONG_PRESS_DEFAULT_MOVE_TOLERANCE_PX, longPress, } from './long-press.js';
|
|
47
47
|
export { default as MultiSelect } from './MultiSelect.svelte';
|
|
48
|
+
export { default as NumericKeypad } from './NumericKeypad.svelte';
|
|
48
49
|
export { detectNativeFileFieldStrategy, } from './native-file-field.js';
|
|
50
|
+
export { applyKey as applyKeypadKey, minorUnitExponent, minorUnitsToText, textToMinorUnits, validateEntry as validateKeypadEntry, } from './numeric-keypad-logic.js';
|
|
49
51
|
export { default as ProvinceSelect } from './ProvinceSelect.svelte';
|
|
50
52
|
export { default as Radio } from './Radio.svelte';
|
|
51
53
|
export { default as RadioGroup } from './RadioGroup.svelte';
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/** One press on the keypad. */
|
|
2
|
+
export type KeypadKey = {
|
|
3
|
+
kind: 'digit';
|
|
4
|
+
digit: string;
|
|
5
|
+
} | {
|
|
6
|
+
kind: 'decimal';
|
|
7
|
+
} | {
|
|
8
|
+
kind: 'backspace';
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'clear';
|
|
11
|
+
};
|
|
12
|
+
/** What `NumericKeypad`'s `onChange` and `onSubmit` receive. */
|
|
13
|
+
export interface NumericKeypadDetail {
|
|
14
|
+
/** The typed text (`"12.5"`, `""` when empty). */
|
|
15
|
+
text: string;
|
|
16
|
+
/** Number value of the text, or null when empty. Not for money arithmetic. */
|
|
17
|
+
number: number | null;
|
|
18
|
+
/** Integer minor units in money mode; null otherwise or when empty. */
|
|
19
|
+
minorUnits: number | null;
|
|
20
|
+
/** True when the text is non-empty and inside `min` / `max`. */
|
|
21
|
+
valid: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Limits that shape what can be typed. */
|
|
24
|
+
export interface EntryRules {
|
|
25
|
+
/** Digits allowed after the point; 0 means integer-only. */
|
|
26
|
+
maxDecimals: number;
|
|
27
|
+
/** Longest typed text, counting the point. */
|
|
28
|
+
maxLength: number;
|
|
29
|
+
}
|
|
30
|
+
/** Outcome of checking typed text against `min` / `max`. */
|
|
31
|
+
export type EntryValidity = 'empty' | 'ok' | 'below' | 'above' | 'invalid';
|
|
32
|
+
/** Default longest typed text. */
|
|
33
|
+
export declare const DEFAULT_MAX_LENGTH = 12;
|
|
34
|
+
/** Minor-unit exponent of an ISO 4217 currency (USD 2, JPY 0, KWD 3). */
|
|
35
|
+
export declare function minorUnitExponent(currency: string | undefined, fallback?: number): number;
|
|
36
|
+
/** Map a hardware `KeyboardEvent.key` to a keypad key; `,` types a point. */
|
|
37
|
+
export declare function keyFromKeyboard(key: string): KeypadKey | null;
|
|
38
|
+
/**
|
|
39
|
+
* Coerce an outside value (a bound string, a number, junk) to well-formed
|
|
40
|
+
* typed text under `rules`; anything unrepresentable becomes `''`.
|
|
41
|
+
*/
|
|
42
|
+
export declare function normalizeText(raw: string | number | null | undefined, rules: EntryRules): string;
|
|
43
|
+
/** The text after pressing `key`; the same string when the press is refused. */
|
|
44
|
+
export declare function applyKey(text: string, key: KeypadKey, rules: EntryRules): string;
|
|
45
|
+
/** Number value of typed text, or `null` when empty. Display and range use only. */
|
|
46
|
+
export declare function parseEntry(text: string): number | null;
|
|
47
|
+
/** Check typed text against optional `min` / `max` (major units). */
|
|
48
|
+
export declare function validateEntry(text: string, limits: {
|
|
49
|
+
min?: number;
|
|
50
|
+
max?: number;
|
|
51
|
+
}): EntryValidity;
|
|
52
|
+
/** True when `text` is above `max`: the entry the "clamp" mode refuses. */
|
|
53
|
+
export declare function exceedsMax(text: string, max: number | undefined): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Typed text to integer minor units (`"12.5"` with exponent 2 is `1250`).
|
|
56
|
+
* `null` for empty or malformed text, more decimals than `exponent`, or a
|
|
57
|
+
* result beyond `Number.MAX_SAFE_INTEGER`.
|
|
58
|
+
*/
|
|
59
|
+
export declare function textToMinorUnits(text: string, exponent: number): number | null;
|
|
60
|
+
/**
|
|
61
|
+
* Integer minor units to typed text (`1250`, exponent 2 -> `"12.5"`). With
|
|
62
|
+
* `trim: false` the fraction is padded to `exponent` (`"12.50"`). `null` for a
|
|
63
|
+
* non-integer, negative, or unsafe amount.
|
|
64
|
+
*/
|
|
65
|
+
export declare function minorUnitsToText(minor: number, exponent: number, options?: {
|
|
66
|
+
trim?: boolean;
|
|
67
|
+
}): string | null;
|
|
68
|
+
//# sourceMappingURL=numeric-keypad-logic.d.ts.map
|