nexa-runtime 0.7.4 → 0.7.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.
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type Signal } from 'nexa-reactivity';
|
|
2
|
+
export interface CurrencyOptions {
|
|
3
|
+
locale?: string;
|
|
4
|
+
currency?: string;
|
|
5
|
+
decimals?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare function vCurrency(el: HTMLInputElement, signal: Signal<number>, options?: CurrencyOptions): () => void;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { effect } from 'nexa-reactivity';
|
|
2
|
+
function getFormatter(options) {
|
|
3
|
+
const locale = options?.locale ?? 'en-US';
|
|
4
|
+
const currency = options?.currency ?? 'USD';
|
|
5
|
+
const decimals = options?.decimals ?? 2;
|
|
6
|
+
const formatter = new Intl.NumberFormat(locale, {
|
|
7
|
+
style: 'currency',
|
|
8
|
+
currency,
|
|
9
|
+
minimumFractionDigits: decimals,
|
|
10
|
+
maximumFractionDigits: decimals,
|
|
11
|
+
});
|
|
12
|
+
const parts = formatter.formatToParts(12345.67);
|
|
13
|
+
const decimalSep = parts.find(p => p.type === 'decimal')?.value ?? '.';
|
|
14
|
+
const groupSep = parts.find(p => p.type === 'group')?.value ?? ',';
|
|
15
|
+
const formatted = formatter.format(12345.67);
|
|
16
|
+
const digitStart = formatted.search(/\d/);
|
|
17
|
+
const rev = formatted.split('').reverse().join('');
|
|
18
|
+
const digitEnd = formatted.length - rev.search(/\d/);
|
|
19
|
+
const prefix = formatted.slice(0, digitStart);
|
|
20
|
+
const suffix = formatted.slice(digitEnd);
|
|
21
|
+
return {
|
|
22
|
+
format: (n) => formatter.format(n),
|
|
23
|
+
parse: (s) => {
|
|
24
|
+
let cleaned = s;
|
|
25
|
+
if (prefix && cleaned.startsWith(prefix))
|
|
26
|
+
cleaned = cleaned.slice(prefix.length);
|
|
27
|
+
if (suffix && cleaned.endsWith(suffix))
|
|
28
|
+
cleaned = cleaned.slice(0, -suffix.length);
|
|
29
|
+
cleaned = cleaned.replace(new RegExp(`\\${groupSep}`, 'g'), '');
|
|
30
|
+
cleaned = cleaned.replace(decimalSep, '.');
|
|
31
|
+
cleaned = cleaned.replace(/[^\d.-]/g, '');
|
|
32
|
+
const num = parseFloat(cleaned);
|
|
33
|
+
return isNaN(num) ? 0 : num;
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
export function vCurrency(el, signal, options) {
|
|
38
|
+
const fmt = getFormatter(options);
|
|
39
|
+
const onInput = () => {
|
|
40
|
+
const num = fmt.parse(el.value);
|
|
41
|
+
signal.value = num;
|
|
42
|
+
};
|
|
43
|
+
const onFocus = () => {
|
|
44
|
+
el.select();
|
|
45
|
+
};
|
|
46
|
+
const onBlur = () => {
|
|
47
|
+
el.value = fmt.format(signal.value);
|
|
48
|
+
};
|
|
49
|
+
el.addEventListener('input', onInput);
|
|
50
|
+
el.addEventListener('focus', onFocus);
|
|
51
|
+
el.addEventListener('blur', onBlur);
|
|
52
|
+
const e = effect(() => {
|
|
53
|
+
const val = signal.value;
|
|
54
|
+
if (document.activeElement !== el) {
|
|
55
|
+
el.value = fmt.format(val);
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
el.value = fmt.format(signal.peek());
|
|
59
|
+
return () => {
|
|
60
|
+
el.removeEventListener('input', onInput);
|
|
61
|
+
el.removeEventListener('focus', onFocus);
|
|
62
|
+
el.removeEventListener('blur', onBlur);
|
|
63
|
+
e.dispose();
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -2,5 +2,7 @@ import { type Signal } from 'nexa-reactivity';
|
|
|
2
2
|
import type { VNode } from '../vdom';
|
|
3
3
|
export declare function vIf(condition: boolean, thenVNode: () => VNode | null, elseVNode?: () => VNode | null): VNode | null;
|
|
4
4
|
export declare function vFor<T>(items: T[], render: (item: T, index: number) => VNode | null): (VNode | null)[];
|
|
5
|
+
export { vCurrency } from './currency';
|
|
6
|
+
export type { CurrencyOptions } from './currency';
|
|
5
7
|
export declare function vShow(el: HTMLElement, signal: Signal<boolean>): () => void;
|
|
6
8
|
export declare function vModel(el: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement, signal: Signal<string>): () => void;
|
package/dist/directives/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export function vIf(condition, thenVNode, elseVNode) {
|
|
|
5
5
|
export function vFor(items, render) {
|
|
6
6
|
return items.map((item, index) => render(item, index));
|
|
7
7
|
}
|
|
8
|
+
export { vCurrency } from './currency';
|
|
8
9
|
export function vShow(el, signal) {
|
|
9
10
|
const e = effect(() => {
|
|
10
11
|
el.style.display = signal.value ? '' : 'none';
|
package/dist/vdom/dom.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { effect } from 'nexa-reactivity';
|
|
2
|
+
import { vCurrency as _vCurrency } from '../directives/currency';
|
|
2
3
|
function normalizeClassValue(value) {
|
|
3
4
|
if (!value)
|
|
4
5
|
return '';
|
|
@@ -80,6 +81,17 @@ export const domOptions = {
|
|
|
80
81
|
delete el._vShowEffect;
|
|
81
82
|
}
|
|
82
83
|
}
|
|
84
|
+
else if (key === 'vCurrency') {
|
|
85
|
+
if (el._vCurrencyCleanup) {
|
|
86
|
+
el._vCurrencyCleanup();
|
|
87
|
+
}
|
|
88
|
+
if (nextValue) {
|
|
89
|
+
el._vCurrencyCleanup = _vCurrency(el, nextValue);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
delete el._vCurrencyCleanup;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
83
95
|
else if (key === 'checked') {
|
|
84
96
|
el.checked = !!nextValue;
|
|
85
97
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nexa-runtime",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.5",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.js",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
}
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"nexa-reactivity": "0.7.
|
|
16
|
+
"nexa-reactivity": "0.7.5"
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"dist"
|