@canutin/svelte-currency-input 0.11.3 → 0.11.5

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # svelte-currency-input
2
2
 
3
- A form input that converts numbers to localized currency formats as you type
3
+ A masked form input that converts numbers to localized currency formats as you type
4
4
 
5
5
  [<img width="962" alt="image" src="https://user-images.githubusercontent.com/1434675/190873948-c0385747-6fa9-4077-8bd5-717e4d1124a0.png">](https://svelte.dev/repl/d8f7d22e5b384555b430f62b157ac503?version=3.50.1)
6
6
 
@@ -1,18 +1,21 @@
1
- <script>import { onMount } from "svelte";
2
- const DEFAULT_LOCALE = "en-US";
3
- const DEFAULT_CURRENCY = "USD";
4
- const DEFAULT_NAME = "total";
5
- const DEFAULT_VALUE = 0;
6
- const DEFAULT_FRACTION_DIGITS = 2;
7
- const DEFAULT_CLASS_WRAPPER = "currencyInput";
8
- const DEFAULT_CLASS_UNFORMATTED = "currencyInput__unformatted";
9
- const DEFAULT_CLASS_FORMATTED = "currencyInput__formatted";
10
- const DEFAULT_CLASS_FORMATTED_POSITIVE = "currencyInput__formatted--positive";
11
- const DEFAULT_CLASS_FORMATTED_NEGATIVE = "currencyInput__formatted--negative";
12
- const DEFAULT_CLASS_FORMATTED_ZERO = "currencyInput__formatted--zero";
1
+ <script>import {
2
+ DEFAULT_LOCALE,
3
+ DEFAULT_CURRENCY,
4
+ DEFAULT_NAME,
5
+ DEFAULT_VALUE,
6
+ DEFAULT_FRACTION_DIGITS,
7
+ DEFAULT_CLASS_WRAPPER,
8
+ DEFAULT_CLASS_UNFORMATTED,
9
+ DEFAULT_CLASS_FORMATTED,
10
+ DEFAULT_CLASS_FORMATTED_POSITIVE,
11
+ DEFAULT_CLASS_FORMATTED_NEGATIVE,
12
+ DEFAULT_CLASS_FORMATTED_ZERO
13
+ } from "./constants";
14
+ import { onMount } from "svelte";
13
15
  export let value = DEFAULT_VALUE;
14
16
  export let locale = DEFAULT_LOCALE;
15
17
  export let currency = DEFAULT_CURRENCY;
18
+ export let fractionDigits = DEFAULT_FRACTION_DIGITS;
16
19
  export let name = DEFAULT_NAME;
17
20
  export let required = false;
18
21
  export let disabled = false;
@@ -20,65 +23,70 @@ export let placeholder = DEFAULT_VALUE;
20
23
  export let autocomplete = void 0;
21
24
  export let isNegativeAllowed = true;
22
25
  export let isZeroNullish = false;
23
- export let fractionDigits = DEFAULT_FRACTION_DIGITS;
24
26
  export let inputClasses = null;
25
27
  export let onValueChange = () => {
26
28
  };
27
- const formatCurrency = (value2, maximumFractionDigits, minimumFractionDigits) => {
29
+ let inputElement;
30
+ let inputTarget;
31
+ let formattedValue = "";
32
+ $: isNegative = value < 0;
33
+ $: isPositive = value > 0;
34
+ $: isZero = !isNegative && !isPositive;
35
+ $: value, setFormattedValue();
36
+ onMount(() => {
37
+ setFormattedValue();
38
+ });
39
+ function formatCurrency(value2, maximumFractionDigits, minimumFractionDigits) {
28
40
  return new Intl.NumberFormat(locale, {
29
41
  currency,
30
42
  style: "currency",
31
43
  maximumFractionDigits: maximumFractionDigits || 0,
32
44
  minimumFractionDigits: minimumFractionDigits || 0
33
45
  }).format(value2);
34
- };
35
- const handleKeyDown = (event) => {
46
+ }
47
+ function handleKeyDown(event) {
36
48
  const isDeletion = event.key === "Backspace" || event.key === "Delete";
37
49
  const isModifier = event.metaKey || event.altKey || event.ctrlKey;
38
50
  const isArrowKey = event.key === "ArrowLeft" || event.key === "ArrowRight";
39
51
  const isTab = event.key === "Tab";
40
52
  const isInvalidCharacter = !/^\d|,|\.|-$/g.test(event.key);
41
- const isPunctuationDuplicated = () => {
42
- if (event.key !== "," && event.key !== ".")
43
- return false;
44
- if (isDecimalComma)
45
- return formattedValue.split(",").length >= 2;
46
- if (!isDecimalComma)
47
- return formattedValue.split(".").length >= 2;
53
+ function isPunctuationDuplicated() {
54
+ if (event.key !== "," && event.key !== ".") return false;
55
+ if (isDecimalComma) return formattedValue.split(",").length >= 2;
56
+ if (!isDecimalComma) return formattedValue.split(".").length >= 2;
48
57
  return false;
49
- };
58
+ }
50
59
  if (isPunctuationDuplicated() || !isDeletion && !isModifier && !isArrowKey && isInvalidCharacter && !isTab)
51
60
  event.preventDefault();
52
- };
53
- const handleOnBlur = () => setFormattedValue(true);
54
- onMount(() => setFormattedValue(true));
55
- let inputTarget;
61
+ }
62
+ function handlePlaceholder(placeholder2) {
63
+ if (typeof placeholder2 === "number")
64
+ return formatCurrency(placeholder2, fractionDigits, fractionDigits);
65
+ if (placeholder2 === null) return "";
66
+ return placeholder2;
67
+ }
56
68
  const currencyDecimal = new Intl.NumberFormat(locale).format(1.1).charAt(1);
57
69
  const isDecimalComma = currencyDecimal === ",";
58
70
  const currencySymbol = formatCurrency(0, 0).replace("0", "").replace(/\u00A0/, "");
59
- const setUnformattedValue = (event) => {
71
+ function setUnformattedValue(event) {
60
72
  if (event) {
61
- if (event.key === currencyDecimal)
62
- return;
73
+ if (event.key === currencyDecimal) return;
63
74
  if (isDecimalComma && event.key === ".")
64
75
  formattedValue = formattedValue.replace(/\.([^.]*)$/, currencyDecimal + "$1");
65
76
  if (!isDecimalComma && event.key === ",")
66
77
  formattedValue = formattedValue.replace(/\,([^,]*)$/, currencyDecimal + "$1");
67
78
  const ignoreSymbols = [currencySymbol, `-${currencySymbol}`, "-"];
68
79
  const strippedUnformattedValue = formattedValue.replace(" ", "");
69
- if (ignoreSymbols.includes(strippedUnformattedValue))
70
- return;
80
+ if (ignoreSymbols.includes(strippedUnformattedValue)) return;
71
81
  inputTarget = event.target;
72
- if (isNegativeAllowed && event.key === "-")
73
- value = value * -1;
82
+ if (isNegativeAllowed && event.key === "-") value = value * -1;
74
83
  }
75
84
  let unformattedValue = isNegativeAllowed ? formattedValue.replace(/[^0-9,.-]/g, "") : formattedValue.replace(/[^0-9,.]/g, "");
76
85
  if (Number.isNaN(parseFloat(unformattedValue))) {
77
86
  value = 0;
78
87
  } else {
79
88
  unformattedValue = unformattedValue.replace(isDecimalComma ? /\./g : /\,/g, "");
80
- if (isDecimalComma)
81
- unformattedValue = unformattedValue.replace(",", ".");
89
+ if (isDecimalComma) unformattedValue = unformattedValue.replace(",", ".");
82
90
  const previousValue = value;
83
91
  value = parseFloat(unformattedValue);
84
92
  if (event && previousValue === value) {
@@ -87,37 +95,25 @@ const setUnformattedValue = (event) => {
87
95
  }
88
96
  }
89
97
  }
90
- };
91
- const setFormattedValue = (hasMinFractionDigits) => {
92
- const startCaretPosition = inputTarget?.selectionStart || 0;
98
+ }
99
+ function setFormattedValue() {
100
+ if (!inputElement) return;
101
+ const startCaretPosition = inputElement.selectionStart || 0;
93
102
  const previousFormattedValueLength = formattedValue.length;
94
- formattedValue = isZero && !isZeroNullish ? "" : formatCurrency(value, fractionDigits, hasMinFractionDigits ? fractionDigits : 0);
103
+ formattedValue = isZero && !isZeroNullish ? "" : formatCurrency(
104
+ value,
105
+ fractionDigits,
106
+ document.activeElement === inputElement ? 0 : fractionDigits
107
+ );
95
108
  setUnformattedValue();
96
109
  let retries = 0;
97
- while (previousFormattedValueLength === formattedValue.length && retries < 10)
98
- retries++;
110
+ while (previousFormattedValueLength === formattedValue.length && retries < 10) retries++;
99
111
  if (previousFormattedValueLength !== formattedValue.length) {
100
112
  const endCaretPosition = startCaretPosition + formattedValue.length - previousFormattedValueLength;
101
- inputTarget?.setSelectionRange(endCaretPosition, endCaretPosition);
113
+ inputElement?.setSelectionRange(endCaretPosition, endCaretPosition);
102
114
  }
103
115
  onValueChange(value);
104
- };
105
- const handlePlaceholder = (placeholder2) => {
106
- if (typeof placeholder2 === "number")
107
- return formatCurrency(placeholder2, fractionDigits, fractionDigits);
108
- if (placeholder2 === null)
109
- return "";
110
- return placeholder2;
111
- };
112
- let formattedValue = "";
113
- $:
114
- isNegative = value < 0;
115
- $:
116
- isPositive = value > 0;
117
- $:
118
- isZero = !isNegative && !isPositive;
119
- $:
120
- value, setFormattedValue();
116
+ }
121
117
  </script>
122
118
 
123
119
  <div class={inputClasses?.wrapper ?? DEFAULT_CLASS_WRAPPER}>
@@ -140,16 +136,17 @@ $:
140
136
  : ''}
141
137
  "
142
138
  type="text"
143
- inputmode={fractionDigits > 0 ? "decimal" : "numeric"}
139
+ inputmode={fractionDigits > 0 ? 'decimal' : 'numeric'}
144
140
  name={`formatted-${name}`}
145
141
  required={required && !isZero}
146
142
  placeholder={handlePlaceholder(placeholder)}
147
143
  {autocomplete}
148
144
  {disabled}
145
+ bind:this={inputElement}
149
146
  bind:value={formattedValue}
150
147
  on:keydown={handleKeyDown}
151
148
  on:keyup={setUnformattedValue}
152
- on:blur={handleOnBlur}
149
+ on:blur={setFormattedValue}
153
150
  />
154
151
  </div>
155
152
 
@@ -1,9 +1,11 @@
1
1
  import { SvelteComponentTyped } from "svelte";
2
+ import type { InputClasses, Callback } from './types';
2
3
  declare const __propDef: {
3
4
  props: {
4
5
  value?: number | undefined;
5
6
  locale?: string | undefined;
6
7
  currency?: string | undefined;
8
+ fractionDigits?: number | undefined;
7
9
  name?: string | undefined;
8
10
  required?: boolean | undefined;
9
11
  disabled?: boolean | undefined;
@@ -11,16 +13,8 @@ declare const __propDef: {
11
13
  autocomplete?: string | null | undefined;
12
14
  isNegativeAllowed?: boolean | undefined;
13
15
  isZeroNullish?: boolean | undefined;
14
- fractionDigits?: number | undefined;
15
- inputClasses?: {
16
- wrapper?: string | undefined;
17
- unformatted?: string | undefined;
18
- formatted?: string | undefined;
19
- formattedPositive?: string | undefined;
20
- formattedNegative?: string | undefined;
21
- formattedZero?: string | undefined;
22
- } | null | undefined;
23
- onValueChange?: ((value: number) => any) | undefined;
16
+ inputClasses?: InputClasses | null | undefined;
17
+ onValueChange?: Callback | undefined;
24
18
  };
25
19
  events: {
26
20
  [evt: string]: CustomEvent<any>;
@@ -0,0 +1,11 @@
1
+ export declare const DEFAULT_LOCALE = "en-US";
2
+ export declare const DEFAULT_CURRENCY = "USD";
3
+ export declare const DEFAULT_NAME = "total";
4
+ export declare const DEFAULT_VALUE = 0;
5
+ export declare const DEFAULT_FRACTION_DIGITS = 2;
6
+ export declare const DEFAULT_CLASS_WRAPPER = "currencyInput";
7
+ export declare const DEFAULT_CLASS_UNFORMATTED = "currencyInput__unformatted";
8
+ export declare const DEFAULT_CLASS_FORMATTED = "currencyInput__formatted";
9
+ export declare const DEFAULT_CLASS_FORMATTED_POSITIVE = "currencyInput__formatted--positive";
10
+ export declare const DEFAULT_CLASS_FORMATTED_NEGATIVE = "currencyInput__formatted--negative";
11
+ export declare const DEFAULT_CLASS_FORMATTED_ZERO = "currencyInput__formatted--zero";
@@ -0,0 +1,11 @@
1
+ export const DEFAULT_LOCALE = 'en-US';
2
+ export const DEFAULT_CURRENCY = 'USD';
3
+ export const DEFAULT_NAME = 'total';
4
+ export const DEFAULT_VALUE = 0;
5
+ export const DEFAULT_FRACTION_DIGITS = 2;
6
+ export const DEFAULT_CLASS_WRAPPER = 'currencyInput';
7
+ export const DEFAULT_CLASS_UNFORMATTED = 'currencyInput__unformatted';
8
+ export const DEFAULT_CLASS_FORMATTED = 'currencyInput__formatted';
9
+ export const DEFAULT_CLASS_FORMATTED_POSITIVE = 'currencyInput__formatted--positive';
10
+ export const DEFAULT_CLASS_FORMATTED_NEGATIVE = 'currencyInput__formatted--negative';
11
+ export const DEFAULT_CLASS_FORMATTED_ZERO = 'currencyInput__formatted--zero';
@@ -0,0 +1,9 @@
1
+ export interface InputClasses {
2
+ wrapper?: string;
3
+ unformatted?: string;
4
+ formatted?: string;
5
+ formattedPositive?: string;
6
+ formattedNegative?: string;
7
+ formattedZero?: string;
8
+ }
9
+ export type Callback = (value: number) => any;
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@canutin/svelte-currency-input",
3
- "version": "0.11.3",
3
+ "version": "0.11.5",
4
4
  "scripts": {
5
5
  "dev": "vite dev",
6
6
  "build": "vite build",
@@ -25,10 +25,11 @@
25
25
  ],
26
26
  "devDependencies": {
27
27
  "@playwright/test": "^1.39.0",
28
- "@sveltejs/adapter-auto": "^2.0.0",
29
- "@sveltejs/adapter-cloudflare": "^2.3.3",
30
- "@sveltejs/kit": "^1.26.0",
28
+ "@sveltejs/adapter-auto": "^3.2.0",
29
+ "@sveltejs/adapter-cloudflare": "^4.4.0",
30
+ "@sveltejs/kit": "^2.0.0",
31
31
  "@sveltejs/package": "^2.2.2",
32
+ "@sveltejs/vite-plugin-svelte": "^3.0.0",
32
33
  "@types/node": "^20.8.7",
33
34
  "@typescript-eslint/eslint-plugin": "^6.0.0",
34
35
  "@typescript-eslint/parser": "^6.0.0",
@@ -40,11 +41,16 @@
40
41
  "prettier-plugin-svelte": "^2.10.1",
41
42
  "publint": "^0.2.5",
42
43
  "sass": "^1.69.0",
43
- "semantic-release": "^19.0.5",
44
+ "semantic-release": "^24.1.1",
45
+ "svelte": "^4.2.19",
44
46
  "svelte-check": "^3.4.3",
45
47
  "tslib": "^2.4.1",
46
48
  "typescript": "^5.0.0",
47
- "vite": "^4.4.2"
49
+ "vite": "^5.0.0"
50
+ },
51
+ "optionalDependencies": {
52
+ "@cloudflare/workerd-linux-64": "^1.20240909.0",
53
+ "@rollup/rollup-linux-x64-gnu": "^4.21.3"
48
54
  },
49
55
  "svelte": "./dist/index.js",
50
56
  "types": "./dist/index.d.ts",