@canutin/svelte-currency-input 0.3.0 → 0.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canutin/svelte-currency-input",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "exports": {
5
5
  ".": "./index.js"
6
6
  },
@@ -1,17 +1,17 @@
1
1
  <script lang="ts">
2
- export let value: number = 0;
3
- export let locale: string = 'en-US';
4
- export let currency: string = 'USD';
5
- export let name: string = 'total';
2
+ const DEFAULT_LOCALE = 'en-US';
3
+ const DEFAULT_CURRENCY = 'USD';
4
+ const DEFAULT_NAME = 'total';
5
+ const DEFAULT_VALUE = 0;
6
+
7
+ export let value: number = DEFAULT_VALUE;
8
+ export let locale: string = DEFAULT_LOCALE;
9
+ export let currency: string = DEFAULT_CURRENCY;
10
+ export let name: string = DEFAULT_NAME;
6
11
  export let required: boolean = false;
7
12
  export let disabled: boolean = false;
8
13
  export let isNegativeAllowed: boolean = true;
9
14
 
10
- let formattedValue = '';
11
- $: isZero = value === 0;
12
- $: isNegative = value < 0;
13
- $: value, applyFormatting();
14
-
15
15
  // Formats value as: e.g. $1,523.00 | -$1,523.00
16
16
  const formatCurrency = (
17
17
  value: number,
@@ -26,18 +26,26 @@
26
26
  }).format(value);
27
27
  };
28
28
 
29
- const placeholder = formatCurrency(0, 2, 2); // e.g. '$0.00'
30
- const currencySymbol = formatCurrency(0, 0)
31
- .replace('0', '') // e.g. '$0' > '$'
32
- .replace(/\u00A0/, ''); // e.g '0 €' > '€'
33
- const currencyDecimal = new Intl.NumberFormat(locale).format(1.1).charAt(1); // '.' or ','
29
+ // Checks if the key pressed is allowed
30
+ const handleKeyDown = (event: KeyboardEvent) => {
31
+ const isDeletion = event.key === 'Backspace' || event.key === 'Delete';
32
+ const isModifier = event.metaKey || event.altKey || event.ctrlKey;
33
+ const isArrowKey = event.key === 'ArrowLeft' || event.key === 'ArrowRight';
34
+ const isInvalidCharacter = !/^\d|,|\.|-$/g.test(event.key); // Keys that are not a digit, comma, period or minus sign
35
+
36
+ if (!isDeletion && !isModifier && !isArrowKey && isInvalidCharacter) event.preventDefault();
37
+ };
34
38
 
35
39
  // Updates `value` by stripping away the currency formatting
36
- const setValue = (event?: KeyboardEvent) => {
37
- // Don't format if the user is typing a currencyDecimal point
38
- if (event?.key === currencyDecimal) return;
40
+ const setUnformattedValue = (event: KeyboardEvent) => {
41
+ // Don't format if the user is typing a `currencyDecimal` point
42
+ const currencyDecimal = new Intl.NumberFormat(locale).format(1.1).charAt(1); // '.' or ','
43
+ if (event.key === currencyDecimal) return;
39
44
 
40
45
  // If `formattedValue` is ['$', '-$', "-"] we don't need to continue
46
+ const currencySymbol = formatCurrency(0, 0)
47
+ .replace('0', '') // e.g. '$0' > '$'
48
+ .replace(/\u00A0/, ''); // e.g '0 €' > '€'
41
49
  const ignoreSymbols = [currencySymbol, `-${currencySymbol}`, '-'];
42
50
  const strippedUnformattedValue = formattedValue.replace(' ', '');
43
51
  if (ignoreSymbols.includes(strippedUnformattedValue)) return;
@@ -48,7 +56,7 @@
48
56
  : formattedValue.replace(/[^0-9,.]/g, '');
49
57
 
50
58
  // Reverse the value when minus is pressed
51
- if (isNegativeAllowed && event?.key === '-') value = value * -1;
59
+ if (isNegativeAllowed && event.key === '-') value = value * -1;
52
60
 
53
61
  // Finally set the value
54
62
  if (Number.isNaN(parseFloat(unformattedValue))) {
@@ -62,9 +70,16 @@
62
70
  }
63
71
  };
64
72
 
65
- const applyFormatting = () => {
73
+ const setFormattedValue = () => {
66
74
  formattedValue = isZero ? '' : formatCurrency(value, 2, 0);
67
75
  };
76
+
77
+ let formattedValue = '';
78
+ $: isZero = value === 0;
79
+ $: isNegative = value < 0;
80
+ $: value, setFormattedValue();
81
+
82
+ const placeholder = formatCurrency(DEFAULT_VALUE, 2, 2); // e.g. '$0.00'
68
83
  </script>
69
84
 
70
85
  <div class="currencyInput">
@@ -83,7 +98,8 @@
83
98
  {placeholder}
84
99
  {disabled}
85
100
  bind:value={formattedValue}
86
- on:keyup={setValue}
101
+ on:keydown={handleKeyDown}
102
+ on:keyup={setUnformattedValue}
87
103
  />
88
104
  </div>
89
105
 
@@ -136,6 +136,54 @@ test.describe('CurrencyInput', () => {
136
136
  await expect(rentUnformattedInput).toHaveValue('0');
137
137
  });
138
138
 
139
+ test("Incorrect characters can't be entered", async ({ page }) => {
140
+ await page.goto('/');
141
+
142
+ const isMacOs = process.platform === 'darwin';
143
+ const rentUnformattedInput = page.locator('.currencyInput__unformatted[name=rent]');
144
+ const rentFormattedInput = page.locator('.currencyInput__formatted[name="formatted-rent"]');
145
+
146
+ // Check the there is no value in the input
147
+ await expect(rentUnformattedInput).toHaveValue('0');
148
+ await expect(rentFormattedInput).toHaveValue('');
149
+
150
+ // Check typing letters doesn't do anything
151
+ await rentFormattedInput.focus();
152
+ await page.keyboard.type('abc');
153
+ await expect(rentUnformattedInput).toHaveValue('0');
154
+ await expect(rentFormattedInput).toHaveValue('');
155
+
156
+ // Check keyboard combinations don't do anything
157
+ await page.keyboard.press('Shift+A');
158
+ await expect(rentFormattedInput).toHaveValue('');
159
+
160
+ // Check keyboard shortcuts are allowed
161
+ await page.keyboard.type('420.69');
162
+ await expect(rentFormattedInput).toHaveValue('$420.69');
163
+ await expect(rentUnformattedInput).toHaveValue('420.69');
164
+
165
+ // Select all
166
+ isMacOs ? await page.keyboard.press('Meta+A') : await page.keyboard.press('Control+A');
167
+
168
+ // Check "Backspace" works
169
+ await page.keyboard.press('Backspace');
170
+ await expect(rentUnformattedInput).toHaveValue('0');
171
+ await expect(rentFormattedInput).toHaveValue('');
172
+
173
+ // Add data to the field again
174
+ await page.keyboard.type('-420.69');
175
+ await expect(rentFormattedInput).toHaveValue('-$420.69');
176
+ await expect(rentUnformattedInput).toHaveValue('-420.69');
177
+
178
+ // Select all
179
+ isMacOs ? await page.keyboard.press('Meta+A') : await page.keyboard.press('Control+A');
180
+
181
+ // Check "Delete" also works
182
+ await page.keyboard.press('Delete');
183
+ await expect(rentUnformattedInput).toHaveValue('0');
184
+ await expect(rentFormattedInput).toHaveValue('');
185
+ });
186
+
139
187
  test.skip('Updating chained inputs have the correct behavior', async () => {
140
188
  // TODO
141
189
  });