diff --git a/src/lib/CurrencyInput.svelte b/src/lib/CurrencyInput.svelte index 22f596d..50dc34d 100644 --- a/src/lib/CurrencyInput.svelte +++ b/src/lib/CurrencyInput.svelte @@ -78,12 +78,20 @@ // Formats the value when the input loses focus and sets the correct number of // fraction digits when the value is zero - const handleOnBlur = () => setFormattedValue(true); + const handleOnBlur = () => setFormattedValue(); - // Also set the correct fraction digits when the value is zero on initial load - onMount(() => setFormattedValue(true)); + let dom: Document; + let inputElement: HTMLInputElement; - let inputTarget: HTMLInputElement; + onMount(() => { + // Set the document object as a variable so we know the page has mounted + dom = document; + + // Set the correct fraction digits when the value is zero on initial load + setFormattedValue(); + }); + + let inputTarget: EventTarget | null; const currencyDecimal = new Intl.NumberFormat(locale).format(1.1).charAt(1); // '.' or ',' const isDecimalComma = currencyDecimal === ','; const currencySymbol = formatCurrency(0, 0) @@ -110,7 +118,7 @@ if (ignoreSymbols.includes(strippedUnformattedValue)) return; // Set the starting caret positions - inputTarget = event.target as HTMLInputElement; + inputTarget = event.target; // Reverse the value when minus is pressed if (isNegativeAllowed && event.key === '-') value = value * -1; @@ -147,13 +155,23 @@ } }; - const setFormattedValue = (hasMinFractionDigits?: boolean) => { + const setFormattedValue = () => { + // Do nothing because the page hasn't mounted yet + if (!dom) return; + // Previous caret position - const startCaretPosition = inputTarget?.selectionStart || 0; + const startCaretPosition = inputElement?.selectionStart || 0; const previousFormattedValueLength = formattedValue.length; // Apply formatting to input - formattedValue = isZero && !isZeroNullish ? '' : formatCurrency(value, fractionDigits, hasMinFractionDigits ? fractionDigits : 0); + formattedValue = + isZero && !isZeroNullish + ? '' + : formatCurrency( + value, + fractionDigits, + dom.activeElement === inputElement ? 0 : fractionDigits + ); // Update `value` after formatting setUnformattedValue(); @@ -164,7 +182,7 @@ if (previousFormattedValueLength !== formattedValue.length) { const endCaretPosition = startCaretPosition + formattedValue.length - previousFormattedValueLength; - inputTarget?.setSelectionRange(endCaretPosition, endCaretPosition); + inputElement?.setSelectionRange(endCaretPosition, endCaretPosition); } // Run callback function when `value` changes @@ -172,8 +190,9 @@ }; const handlePlaceholder = (placeholder: string | number | null) => { - if (typeof placeholder === "number") return formatCurrency(placeholder, fractionDigits, fractionDigits); - if (placeholder === null) return ""; + if (typeof placeholder === 'number') + return formatCurrency(placeholder, fractionDigits, fractionDigits); + if (placeholder === null) return ''; return placeholder; }; @@ -204,12 +223,13 @@ : ''} " type="text" - inputmode={fractionDigits > 0 ? "decimal" : "numeric"} + inputmode={fractionDigits > 0 ? 'decimal' : 'numeric'} name={`formatted-${name}`} required={required && !isZero} placeholder={handlePlaceholder(placeholder)} {autocomplete} {disabled} + bind:this={inputElement} bind:value={formattedValue} on:keydown={handleKeyDown} on:keyup={setUnformattedValue} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 85ef1e8..b206ac5 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -12,6 +12,11 @@ }; let unchangedValue = 999; // Used for onValueChange() + let chainedValue = 9999.99; // Used for chained inputs + + const setChainedValue = () => { + chainedValue = 420.69; + };