diff --git a/v2/pink-sb/src/lib/input/Number.svelte b/v2/pink-sb/src/lib/input/Number.svelte index 254a417e3c..c84b066d8b 100644 --- a/v2/pink-sb/src/lib/input/Number.svelte +++ b/v2/pink-sb/src/lib/input/Number.svelte @@ -44,12 +44,15 @@ let bigintMode = false; let minAttr: NativeNumber = undefined; let maxAttr: NativeNumber = undefined; + let inputValue = ''; let input: HTMLInputElement; const dispatch = createEventDispatcher(); - $: if (typeof value === 'bigint' || typeof value === 'number') { - bigintMode = typeof value === 'bigint'; + $: bigintMode = typeof value === 'bigint'; + + function valueToDisplayString(v: ExtendedNumber): string { + return v === null || v === undefined ? '' : v.toString(); } function toNumberInputBound(raw: ExtendedNumber): NativeNumber { @@ -80,66 +83,64 @@ $: maxAttr = bigintMode ? undefined : toNumberInputBound(max); function fireOnChangeDispatch(next: ExtendedNumber) { - let current = next; - if (bigintMode) { - const parsed = parseBigIntValue(current); - value = parsed ?? current; + const parsed = parseBigIntValue(next); + value = parsed ?? value; + inputValue = valueToDisplayString(value); dispatch('change', parsed ?? undefined); return; } - const num = Number(current); - value = Number.isNaN(num) ? current : num; + const num = Number(next); + value = Number.isNaN(num) ? next : num; dispatch('change', Number.isNaN(num) ? undefined : num); } - function increment(): void { - if (bigintMode) { - const stepValue = parseBigIntStep(step); - const current = parseBigIntValue(value) ?? 0n; - const minValue = parseBigIntBound(min); - const maxValue = parseBigIntBound(max); - let next = current + stepValue; - - if (minValue !== null && next < minValue) { - next = minValue; - } + function clampBigInt(val: bigint, minVal: bigint | null, maxVal: bigint | null): bigint { + let result = val; + if (minVal !== null && result < minVal) result = minVal; + if (maxVal !== null && result > maxVal) result = maxVal; + return result; + } - if (maxValue !== null && next > maxValue) { - next = maxValue; - } + function stepBigInt(direction: 1 | -1): void { + const stepValue = parseBigIntStep(step); + const current = parseBigIntValue(value) ?? 0n; + const bounds = { min: parseBigIntBound(min), max: parseBigIntBound(max) }; + const next = clampBigInt( + current + (direction === 1 ? stepValue : -stepValue), + bounds.min, + bounds.max + ); + fireOnChangeDispatch(next); + } - fireOnChangeDispatch(next); + function increment(): void { + if (bigintMode) { + stepBigInt(1); return; } - input.stepUp(); fireOnChangeDispatch(input.value); } function decrement(): void { if (bigintMode) { - const stepValue = parseBigIntStep(step); - const current = parseBigIntValue(value) ?? 0n; - const minValue = parseBigIntBound(min); - const maxValue = parseBigIntBound(max); - let next = current - stepValue; - - if (minValue !== null && next < minValue) { - next = minValue; - } - - if (maxValue !== null && next > maxValue) { - next = maxValue; - } - - fireOnChangeDispatch(next); + stepBigInt(-1); return; } - input.stepDown(); fireOnChangeDispatch(input.value); } + + function handleBigIntInput(e: Event & { currentTarget: EventTarget & HTMLInputElement }) { + const raw = e.currentTarget.value; + fireOnChangeDispatch(raw); + inputValue = raw; + } + + $: if (bigintMode) { + inputValue = valueToDisplayString(value); + } @@ -161,7 +162,8 @@ on:invalid on:change={() => fireOnChangeDispatch(input.value)} bind:this={input} - bind:value + value={inputValue} + on:input={handleBigIntInput} type="text" inputmode="numeric" {disabled} @@ -206,7 +208,7 @@