Skip to content

Commit b84109e

Browse files
authored
fix: apply fraction digits formatting when the value doesn't have cents (#53)
* feat: apply fraction digits formatting when the value doesn't have cents REF #52 * chore: rename variables and add negative assertion * chore: less verbose and more specific
1 parent 86e2b1a commit b84109e

File tree

3 files changed

+37
-7
lines changed

3 files changed

+37
-7
lines changed

src/lib/CurrencyInput.svelte

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
<script lang="ts">
2+
import { onMount } from "svelte";
3+
24
const DEFAULT_LOCALE = 'en-US';
35
const DEFAULT_CURRENCY = 'USD';
46
const DEFAULT_NAME = 'total';
@@ -62,6 +64,13 @@
6264
event.preventDefault();
6365
};
6466
67+
// Formats the value when the input loses focus and sets the correct number of
68+
// fraction digits when the value is zero
69+
const handleOnBlur = () => setFormattedValue(true);
70+
71+
// Also set the correct fraction digits when the value is zero on initial load
72+
onMount(() => setFormattedValue(true));
73+
6574
let inputTarget: HTMLInputElement;
6675
const currencyDecimal = new Intl.NumberFormat(locale).format(1.1).charAt(1); // '.' or ','
6776
const isDecimalComma = currencyDecimal === ',';
@@ -126,13 +135,13 @@
126135
}
127136
};
128137
129-
const setFormattedValue = () => {
138+
const setFormattedValue = (hasMinFractionDigits?: boolean) => {
130139
// Previous caret position
131140
const startCaretPosition = inputTarget?.selectionStart || 0;
132141
const previousFormattedValueLength = formattedValue.length;
133142
134143
// Apply formatting to input
135-
formattedValue = isZero ? '' : formatCurrency(value, fractionDigits, 0);
144+
formattedValue = isZero ? '' : formatCurrency(value, fractionDigits, hasMinFractionDigits ? fractionDigits : 0);
136145
137146
// Update `value` after formatting
138147
setUnformattedValue();
@@ -187,7 +196,7 @@
187196
bind:value={formattedValue}
188197
on:keydown={handleKeyDown}
189198
on:keyup={setUnformattedValue}
190-
on:blur={setFormattedValue}
199+
on:blur={handleOnBlur}
191200
/>
192201
</div>
193202

src/routes/+page.svelte

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
}
6565
}}
6666
/>
67+
<CurrencyInput name="rupees" value={678} locale="hi-IN" currency="INR" fractionDigits={3} />
6768
</div>
6869

6970
<nav class="demoForm__output">

tests/svelte-currency-input.test.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ test.describe('CurrencyInput', () => {
3434
await expect(yenUnformattedInput).toHaveAttribute('type', 'hidden');
3535
await expect(yenUnformattedInput).toHaveValue('5678.9');
3636
await expect(yenFormattedInput).not.toBeDisabled();
37-
await expect(yenFormattedInput).toHaveValue('¥5,678.9');
37+
await expect(yenFormattedInput).toHaveValue('¥5,678.90');
3838
await expect(yenFormattedInput).toHaveAttribute('type', 'text');
3939
await expect(yenFormattedInput).toHaveAttribute('placeholder', '¥0.00');
4040
await expect(yenFormattedInput).toHaveClass(/currencyInput__formatted--positive/);
@@ -87,13 +87,15 @@ test.describe('CurrencyInput', () => {
8787
bitcoin: '0.87654321',
8888
'formatted-bitcoin': '฿0.87654321',
8989
yen: '5678.9',
90-
'formatted-yen': '¥5,678.9',
90+
'formatted-yen': '¥5,678.90',
9191
euro: '-42069.69',
9292
'formatted-euro': '€ -42.069,69',
9393
won: '0',
9494
'formatted-won': '',
9595
pesos: '999',
96-
'formatted-pesos': '$ 999',
96+
'formatted-pesos': '$ 999,00',
97+
rupees: '678',
98+
'formatted-rupees': '₹678.000',
9799
},
98100
null,
99101
2
@@ -293,7 +295,7 @@ test.describe('CurrencyInput', () => {
293295
// Tabbing in Webkit is broken: https://github.com/Canutin/svelte-currency-input/issues/40
294296
if (testInfo.project.name !== 'webkit') {
295297
const formattedInputs = page.locator('.currencyInput__formatted');
296-
expect(await formattedInputs.count()).toBe(9);
298+
expect(await formattedInputs.count()).toBe(10);
297299

298300
await formattedInputs.first().focus();
299301
await expect(formattedInputs.nth(0)).toBeFocused();
@@ -352,6 +354,24 @@ test.describe('CurrencyInput', () => {
352354
await expect(pesosFormattedInput).toHaveAttribute('autocomplete', 'off');
353355
});
354356

357+
test('A value with zero cents and more than 1 fraction digits gets formatted on blur', async ({ page }) => {
358+
const rupeesFormattedInput = page.locator('.currencyInput__formatted[name="formatted-rupees"]');
359+
const rupeesUnformattedInput = page.locator('.currencyInput__unformatted[name="rupees"]');
360+
await expect(rupeesFormattedInput).toHaveValue('₹678.000');
361+
await expect(rupeesUnformattedInput).toHaveValue('678');
362+
363+
await rupeesFormattedInput.focus();
364+
await selectAll(page);
365+
await page.keyboard.press('Backspace');
366+
await page.keyboard.type('123');
367+
await expect(rupeesFormattedInput).toHaveValue('₹123');
368+
await expect(rupeesFormattedInput).not.toHaveValue('₹123.000');
369+
370+
await page.locator('body').click(); // Click outside the input to trigger formatting
371+
await expect(rupeesFormattedInput).toHaveValue('₹123.000');
372+
await expect(rupeesUnformattedInput).toHaveValue('123');
373+
});
374+
355375
test.skip('Updating chained inputs have the correct behavior', async () => {
356376
// TODO
357377
});

0 commit comments

Comments
 (0)