nexa-runtime 0.7.3 → 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;
@@ -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/scheduler.js CHANGED
@@ -25,7 +25,7 @@ export function flushJobs() {
25
25
  const jobs = Array.from(pendingJobs).sort((a, b) => a.depth - b.depth);
26
26
  pendingJobs.clear();
27
27
  for (const instance of jobs) {
28
- if (instance.update && typeof instance.update.run === 'function') {
28
+ if (instance.update && typeof instance.update.run === 'function' && instance.update.active) {
29
29
  instance.update.run();
30
30
  }
31
31
  }
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
  }
@@ -110,7 +122,12 @@ export const domOptions = {
110
122
  }
111
123
  },
112
124
  insert(el, parent, anchor = null) {
113
- parent.insertBefore(el, anchor);
125
+ if (anchor && anchor.parentNode !== parent) {
126
+ parent.appendChild(el);
127
+ }
128
+ else {
129
+ parent.insertBefore(el, anchor);
130
+ }
114
131
  },
115
132
  remove(el) {
116
133
  const parent = el.parentNode;
@@ -137,7 +137,8 @@ function mountChildren(vnode, parent, options, anchor = null) {
137
137
  }
138
138
  function replaceNode(oldV, newV, parent, options, anchor) {
139
139
  unmount(oldV, parent, options);
140
- mount(newV, parent, options, anchor);
140
+ const safeAnchor = (anchor && anchor.parentNode === parent) ? anchor : null;
141
+ mount(newV, parent, options, safeAnchor);
141
142
  }
142
143
  function updateNode(vnode, options) {
143
144
  const { patchProp, setText } = options;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nexa-runtime",
3
- "version": "0.7.3",
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.3"
16
+ "nexa-reactivity": "0.7.5"
17
17
  },
18
18
  "files": [
19
19
  "dist"