@merkaly/nuxt 0.8.1 → 0.9.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/README.md +64 -0
- package/dist/module.d.mts +12 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +5 -0
- package/dist/runtime/components/format/FormatMoney.d.vue.ts +9 -5
- package/dist/runtime/components/format/FormatMoney.vue +11 -12
- package/dist/runtime/components/format/FormatMoney.vue.d.ts +9 -5
- package/dist/runtime/components/input/InputMoney.d.vue.ts +31 -9
- package/dist/runtime/components/input/InputMoney.vue +32 -8
- package/dist/runtime/components/input/InputMoney.vue.d.ts +31 -9
- package/dist/runtime/composables/useMoneyFormat.d.ts +24 -0
- package/dist/runtime/composables/useMoneyFormat.js +37 -0
- package/dist/runtime/utils/formatMoney.d.ts +32 -2
- package/dist/runtime/utils/formatMoney.js +42 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -21,3 +21,67 @@ A Nuxt module that provides Auth0 authentication integration and API utilities f
|
|
|
21
21
|
## Quick Setup
|
|
22
22
|
|
|
23
23
|
Install the module to your Nuxt application:
|
|
24
|
+
|
|
25
|
+
## Money formatting
|
|
26
|
+
|
|
27
|
+
Money in Merkaly is stored as **integer cents**. `MKFormatMoney`, `MKInputMoney`,
|
|
28
|
+
`formatMoney()` and `useMoneyFormat()` divide by 100 and format with
|
|
29
|
+
`Intl.NumberFormat(locale, { style: 'currency', currency })`, so `24969` with
|
|
30
|
+
`BRL` + `pt-BR` renders `R$ 249,69`.
|
|
31
|
+
|
|
32
|
+
Currency and locale are resolved in this order:
|
|
33
|
+
|
|
34
|
+
1. Component props: `<MKFormatMoney :value="24969" currency="BRL" locale="pt-BR" />`
|
|
35
|
+
2. App-level default set at runtime with `setMoneyDefaults()` (stored with `useState`)
|
|
36
|
+
3. Module option `merkaly.money` (runtime config)
|
|
37
|
+
4. Fallback `USD` / `en-US`
|
|
38
|
+
|
|
39
|
+
### Module option
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
export default defineNuxtConfig({
|
|
43
|
+
merkaly: {
|
|
44
|
+
money: {
|
|
45
|
+
currency: 'BRL', // ISO 4217
|
|
46
|
+
locale: 'pt-BR', // BCP 47
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
It lives in `runtimeConfig.public.merkaly.money`, so it can also be set with
|
|
53
|
+
`NUXT_PUBLIC_MERKALY_MONEY_CURRENCY` / `NUXT_PUBLIC_MERKALY_MONEY_LOCALE`.
|
|
54
|
+
|
|
55
|
+
### Runtime default (per organization)
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
const { setMoneyDefaults } = useMoneyFormat();
|
|
59
|
+
|
|
60
|
+
// after loading the organization
|
|
61
|
+
setMoneyDefaults({
|
|
62
|
+
currency: organization.localization.currency, // e.g. 'BRL'
|
|
63
|
+
locale: organization.localization.language, // e.g. 'pt' or 'pt-BR'
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`useMoneyFormat()` returns:
|
|
68
|
+
|
|
69
|
+
| Key | Description |
|
|
70
|
+
| --- | --- |
|
|
71
|
+
| `currency`, `locale` | Resolved defaults (computed) |
|
|
72
|
+
| `setMoneyDefaults({ currency?, locale? })` | Sets the app-level default (merged) |
|
|
73
|
+
| `resetMoneyDefaults()` | Clears the app-level default |
|
|
74
|
+
| `format(cents, options?)` | Formatted string using the resolved defaults |
|
|
75
|
+
| `formatParts(cents, options?)` | `{ prefix, amount, digits, suffix }` parts |
|
|
76
|
+
|
|
77
|
+
`setMoneyDefaults(defaults)` is also auto-imported as a standalone shortcut.
|
|
78
|
+
|
|
79
|
+
### Components
|
|
80
|
+
|
|
81
|
+
- `MKFormatMoney`: props `value` (cents), `currency`, `locale`, `base` (default `100`),
|
|
82
|
+
`mode`, `hideDecimal`, `tag`. `currency` also accepts a plain symbol (`$`) for
|
|
83
|
+
backward compatibility: the number keeps the resolved currency layout and the
|
|
84
|
+
symbol replaces the currency sign.
|
|
85
|
+
- `MKInputMoney`: `v-model` in cents; props `currency`, `locale`. `prefix`, `decimal`,
|
|
86
|
+
`thousands` and `placeholder` default to the resolved currency/locale and can still
|
|
87
|
+
be passed explicitly.
|
package/dist/module.d.mts
CHANGED
|
@@ -36,6 +36,18 @@ interface MerkalyModuleOptions {
|
|
|
36
36
|
*/
|
|
37
37
|
strategy?: Strategies;
|
|
38
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* Default currency/locale for `MKFormatMoney`, `MKInputMoney` and
|
|
41
|
+
* `useMoneyFormat()`. Apps can override it at runtime with
|
|
42
|
+
* `setMoneyDefaults()` (e.g. after loading the organization) and per
|
|
43
|
+
* component with the `currency` / `locale` props.
|
|
44
|
+
*/
|
|
45
|
+
money?: {
|
|
46
|
+
/** ISO 4217 code, e.g. `BRL`. Defaults to `USD`. */
|
|
47
|
+
currency?: string;
|
|
48
|
+
/** BCP 47 locale, e.g. `pt-BR`. Defaults to `en-US`. */
|
|
49
|
+
locale?: string;
|
|
50
|
+
};
|
|
39
51
|
plausible?: {
|
|
40
52
|
domain: string;
|
|
41
53
|
localhost: string;
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -30,6 +30,10 @@ const defaultOptions = {
|
|
|
30
30
|
locales: [],
|
|
31
31
|
strategy: "no_prefix"
|
|
32
32
|
},
|
|
33
|
+
money: {
|
|
34
|
+
currency: "USD",
|
|
35
|
+
locale: "en-US"
|
|
36
|
+
},
|
|
33
37
|
plausible: {
|
|
34
38
|
domain: "",
|
|
35
39
|
localhost: ""
|
|
@@ -133,6 +137,7 @@ function configureRuntimeConfig(nuxt, options) {
|
|
|
133
137
|
api: options.api,
|
|
134
138
|
auth0: options.auth0,
|
|
135
139
|
i18n: options.i18n,
|
|
140
|
+
money: options.money,
|
|
136
141
|
plausible: options.plausible,
|
|
137
142
|
sentry: {
|
|
138
143
|
dsn: options.sentry.dsn,
|
|
@@ -4,17 +4,19 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
4
4
|
type: NumberConstructor;
|
|
5
5
|
default: number;
|
|
6
6
|
};
|
|
7
|
+
/** ISO 4217 code (`BRL`) or, for backward compatibility, a symbol (`$`). Falls back to the app default. */
|
|
7
8
|
currency: {
|
|
8
9
|
type: StringConstructor;
|
|
9
|
-
default:
|
|
10
|
+
default: undefined;
|
|
10
11
|
};
|
|
11
12
|
hideDecimal: {
|
|
12
13
|
type: BooleanConstructor;
|
|
13
14
|
default: () => boolean;
|
|
14
15
|
};
|
|
16
|
+
/** BCP 47 locale (`pt-BR`). Falls back to the app default. */
|
|
15
17
|
locale: {
|
|
16
18
|
type: StringConstructor;
|
|
17
|
-
default:
|
|
19
|
+
default: undefined;
|
|
18
20
|
};
|
|
19
21
|
mode: {
|
|
20
22
|
type: PropType<Intl.NumberFormatOptionsStyle>;
|
|
@@ -33,17 +35,19 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
33
35
|
type: NumberConstructor;
|
|
34
36
|
default: number;
|
|
35
37
|
};
|
|
38
|
+
/** ISO 4217 code (`BRL`) or, for backward compatibility, a symbol (`$`). Falls back to the app default. */
|
|
36
39
|
currency: {
|
|
37
40
|
type: StringConstructor;
|
|
38
|
-
default:
|
|
41
|
+
default: undefined;
|
|
39
42
|
};
|
|
40
43
|
hideDecimal: {
|
|
41
44
|
type: BooleanConstructor;
|
|
42
45
|
default: () => boolean;
|
|
43
46
|
};
|
|
47
|
+
/** BCP 47 locale (`pt-BR`). Falls back to the app default. */
|
|
44
48
|
locale: {
|
|
45
49
|
type: StringConstructor;
|
|
46
|
-
default:
|
|
50
|
+
default: undefined;
|
|
47
51
|
};
|
|
48
52
|
mode: {
|
|
49
53
|
type: PropType<Intl.NumberFormatOptionsStyle>;
|
|
@@ -61,10 +65,10 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
61
65
|
mode: keyof Intl.NumberFormatOptionsStyleRegistry;
|
|
62
66
|
value: number;
|
|
63
67
|
currency: string;
|
|
68
|
+
locale: string;
|
|
64
69
|
base: number;
|
|
65
70
|
tag: string;
|
|
66
71
|
hideDecimal: boolean;
|
|
67
|
-
locale: string;
|
|
68
72
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
69
73
|
declare const _default: typeof __VLS_export;
|
|
70
74
|
export default _default;
|
|
@@ -1,33 +1,32 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed } from "vue";
|
|
3
|
-
import {
|
|
3
|
+
import { useMoneyFormat } from "../../composables/useMoneyFormat";
|
|
4
4
|
const props = defineProps({
|
|
5
5
|
base: { type: Number, default: 100 },
|
|
6
|
-
|
|
6
|
+
/** ISO 4217 code (`BRL`) or, for backward compatibility, a symbol (`$`). Falls back to the app default. */
|
|
7
|
+
currency: { type: String, default: void 0 },
|
|
7
8
|
hideDecimal: { type: Boolean, default: () => false },
|
|
8
|
-
|
|
9
|
+
/** BCP 47 locale (`pt-BR`). Falls back to the app default. */
|
|
10
|
+
locale: { type: String, default: void 0 },
|
|
9
11
|
mode: { type: String, default: "currency" },
|
|
10
12
|
tag: { type: String, default: "span" },
|
|
11
13
|
value: { type: Number, default: 0 }
|
|
12
14
|
});
|
|
13
|
-
const
|
|
15
|
+
const { formatParts } = useMoneyFormat();
|
|
16
|
+
const price = computed(() => formatParts(props.value, {
|
|
14
17
|
base: props.base,
|
|
15
18
|
currency: props.currency,
|
|
16
19
|
locale: props.locale,
|
|
17
20
|
mode: props.mode
|
|
18
21
|
}));
|
|
19
|
-
const price = computed(() => ({
|
|
20
|
-
currency: money.value[0],
|
|
21
|
-
amount: money.value.slice(1, -3),
|
|
22
|
-
digits: money.value.slice(-3)
|
|
23
|
-
}));
|
|
24
22
|
</script>
|
|
25
23
|
|
|
26
24
|
<template>
|
|
27
|
-
<component :is="tag" class="format-money">
|
|
28
|
-
<span class="currency" v-text="price.
|
|
25
|
+
<component :is="props.tag" class="format-money">
|
|
26
|
+
<span v-if="price.prefix" class="currency" v-text="price.prefix" />
|
|
29
27
|
<span class="value" v-text="price.amount" />
|
|
30
|
-
<sup v-if="!props.hideDecimal" class="digits" v-text="price.digits" />
|
|
28
|
+
<sup v-if="!props.hideDecimal && price.digits" class="digits" v-text="price.digits" />
|
|
29
|
+
<span v-if="price.suffix" class="currency" v-text="price.suffix" />
|
|
31
30
|
</component>
|
|
32
31
|
</template>
|
|
33
32
|
|
|
@@ -4,17 +4,19 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
4
4
|
type: NumberConstructor;
|
|
5
5
|
default: number;
|
|
6
6
|
};
|
|
7
|
+
/** ISO 4217 code (`BRL`) or, for backward compatibility, a symbol (`$`). Falls back to the app default. */
|
|
7
8
|
currency: {
|
|
8
9
|
type: StringConstructor;
|
|
9
|
-
default:
|
|
10
|
+
default: undefined;
|
|
10
11
|
};
|
|
11
12
|
hideDecimal: {
|
|
12
13
|
type: BooleanConstructor;
|
|
13
14
|
default: () => boolean;
|
|
14
15
|
};
|
|
16
|
+
/** BCP 47 locale (`pt-BR`). Falls back to the app default. */
|
|
15
17
|
locale: {
|
|
16
18
|
type: StringConstructor;
|
|
17
|
-
default:
|
|
19
|
+
default: undefined;
|
|
18
20
|
};
|
|
19
21
|
mode: {
|
|
20
22
|
type: PropType<Intl.NumberFormatOptionsStyle>;
|
|
@@ -33,17 +35,19 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
33
35
|
type: NumberConstructor;
|
|
34
36
|
default: number;
|
|
35
37
|
};
|
|
38
|
+
/** ISO 4217 code (`BRL`) or, for backward compatibility, a symbol (`$`). Falls back to the app default. */
|
|
36
39
|
currency: {
|
|
37
40
|
type: StringConstructor;
|
|
38
|
-
default:
|
|
41
|
+
default: undefined;
|
|
39
42
|
};
|
|
40
43
|
hideDecimal: {
|
|
41
44
|
type: BooleanConstructor;
|
|
42
45
|
default: () => boolean;
|
|
43
46
|
};
|
|
47
|
+
/** BCP 47 locale (`pt-BR`). Falls back to the app default. */
|
|
44
48
|
locale: {
|
|
45
49
|
type: StringConstructor;
|
|
46
|
-
default:
|
|
50
|
+
default: undefined;
|
|
47
51
|
};
|
|
48
52
|
mode: {
|
|
49
53
|
type: PropType<Intl.NumberFormatOptionsStyle>;
|
|
@@ -61,10 +65,10 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
61
65
|
mode: keyof Intl.NumberFormatOptionsStyleRegistry;
|
|
62
66
|
value: number;
|
|
63
67
|
currency: string;
|
|
68
|
+
locale: string;
|
|
64
69
|
base: number;
|
|
65
70
|
tag: string;
|
|
66
71
|
hideDecimal: boolean;
|
|
67
|
-
locale: string;
|
|
68
72
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
69
73
|
declare const _default: typeof __VLS_export;
|
|
70
74
|
export default _default;
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import type { Numberish } from 'bootstrap-vue-next/dist/src/types/CommonTypes';
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
3
|
+
/** ISO 4217 code (`BRL`). Falls back to the app default. */
|
|
4
|
+
currency: {
|
|
5
|
+
type: StringConstructor;
|
|
6
|
+
default: undefined;
|
|
7
|
+
};
|
|
3
8
|
decimal: {
|
|
4
9
|
type: StringConstructor;
|
|
5
|
-
default:
|
|
10
|
+
default: undefined;
|
|
11
|
+
};
|
|
12
|
+
/** BCP 47 locale (`pt-BR`). Falls back to the app default. */
|
|
13
|
+
locale: {
|
|
14
|
+
type: StringConstructor;
|
|
15
|
+
default: undefined;
|
|
6
16
|
};
|
|
7
17
|
max: {
|
|
8
18
|
type: NumberConstructor;
|
|
@@ -15,7 +25,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
15
25
|
};
|
|
16
26
|
placeholder: {
|
|
17
27
|
type: StringConstructor;
|
|
18
|
-
default:
|
|
28
|
+
default: undefined;
|
|
19
29
|
};
|
|
20
30
|
precision: {
|
|
21
31
|
type: NumberConstructor;
|
|
@@ -23,7 +33,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
23
33
|
};
|
|
24
34
|
prefix: {
|
|
25
35
|
type: StringConstructor;
|
|
26
|
-
default:
|
|
36
|
+
default: undefined;
|
|
27
37
|
};
|
|
28
38
|
suffix: {
|
|
29
39
|
type: StringConstructor;
|
|
@@ -31,15 +41,25 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
31
41
|
};
|
|
32
42
|
thousands: {
|
|
33
43
|
type: StringConstructor;
|
|
34
|
-
default:
|
|
44
|
+
default: undefined;
|
|
35
45
|
};
|
|
36
46
|
modelValue: Numberish;
|
|
37
47
|
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
38
48
|
"update:modelValue": (value: Numberish) => any;
|
|
39
49
|
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
50
|
+
/** ISO 4217 code (`BRL`). Falls back to the app default. */
|
|
51
|
+
currency: {
|
|
52
|
+
type: StringConstructor;
|
|
53
|
+
default: undefined;
|
|
54
|
+
};
|
|
40
55
|
decimal: {
|
|
41
56
|
type: StringConstructor;
|
|
42
|
-
default:
|
|
57
|
+
default: undefined;
|
|
58
|
+
};
|
|
59
|
+
/** BCP 47 locale (`pt-BR`). Falls back to the app default. */
|
|
60
|
+
locale: {
|
|
61
|
+
type: StringConstructor;
|
|
62
|
+
default: undefined;
|
|
43
63
|
};
|
|
44
64
|
max: {
|
|
45
65
|
type: NumberConstructor;
|
|
@@ -52,7 +72,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
52
72
|
};
|
|
53
73
|
placeholder: {
|
|
54
74
|
type: StringConstructor;
|
|
55
|
-
default:
|
|
75
|
+
default: undefined;
|
|
56
76
|
};
|
|
57
77
|
precision: {
|
|
58
78
|
type: NumberConstructor;
|
|
@@ -60,7 +80,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
60
80
|
};
|
|
61
81
|
prefix: {
|
|
62
82
|
type: StringConstructor;
|
|
63
|
-
default:
|
|
83
|
+
default: undefined;
|
|
64
84
|
};
|
|
65
85
|
suffix: {
|
|
66
86
|
type: StringConstructor;
|
|
@@ -68,15 +88,17 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
68
88
|
};
|
|
69
89
|
thousands: {
|
|
70
90
|
type: StringConstructor;
|
|
71
|
-
default:
|
|
91
|
+
default: undefined;
|
|
72
92
|
};
|
|
73
93
|
modelValue: Numberish;
|
|
74
94
|
}>> & Readonly<{
|
|
75
95
|
"onUpdate:modelValue"?: ((value: Numberish) => any) | undefined;
|
|
76
96
|
}>, {
|
|
97
|
+
decimal: string;
|
|
98
|
+
currency: string;
|
|
99
|
+
locale: string;
|
|
77
100
|
min: number;
|
|
78
101
|
max: number;
|
|
79
|
-
decimal: string;
|
|
80
102
|
placeholder: string;
|
|
81
103
|
precision: number;
|
|
82
104
|
prefix: string;
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { computed } from "vue";
|
|
3
3
|
import { Money3Component } from "v-money3";
|
|
4
|
+
import { useMoneyFormat } from "../../composables/useMoneyFormat";
|
|
5
|
+
import { isCurrencyCode } from "../../utils/formatMoney";
|
|
4
6
|
const money = defineModel({ type: null, ...{
|
|
5
7
|
default: () => 0,
|
|
6
8
|
get: (v) => v / 100,
|
|
@@ -8,21 +10,43 @@ const money = defineModel({ type: null, ...{
|
|
|
8
10
|
type: [String, Number]
|
|
9
11
|
} });
|
|
10
12
|
const props = defineProps({
|
|
11
|
-
|
|
13
|
+
/** ISO 4217 code (`BRL`). Falls back to the app default. */
|
|
14
|
+
currency: { type: String, default: void 0 },
|
|
15
|
+
decimal: { type: String, default: void 0 },
|
|
16
|
+
/** BCP 47 locale (`pt-BR`). Falls back to the app default. */
|
|
17
|
+
locale: { type: String, default: void 0 },
|
|
12
18
|
max: { type: Number, required: false, default: void 0 },
|
|
13
19
|
min: { type: Number, default: () => 0 },
|
|
14
|
-
placeholder: { type: String, default:
|
|
20
|
+
placeholder: { type: String, default: void 0 },
|
|
15
21
|
precision: { type: Number, default: () => 2 },
|
|
16
|
-
prefix: { type: String, default:
|
|
22
|
+
prefix: { type: String, default: void 0 },
|
|
17
23
|
suffix: { type: String, default: () => " " },
|
|
18
|
-
thousands: { type: String, default:
|
|
24
|
+
thousands: { type: String, default: void 0 }
|
|
25
|
+
});
|
|
26
|
+
const { resolve, formatParts } = useMoneyFormat();
|
|
27
|
+
const separators = computed(() => {
|
|
28
|
+
const options = resolve({ currency: props.currency, locale: props.locale });
|
|
29
|
+
const code = isCurrencyCode(options.currency) ? options.currency.toUpperCase() : options.symbolCurrency;
|
|
30
|
+
const parts = new Intl.NumberFormat(options.locale, { style: "currency", currency: code }).formatToParts(123456789e-2);
|
|
31
|
+
return {
|
|
32
|
+
decimal: parts.find((part) => part.type === "decimal")?.value ?? ".",
|
|
33
|
+
symbol: isCurrencyCode(options.currency) ? parts.find((part) => part.type === "currency")?.value ?? options.currency : options.currency,
|
|
34
|
+
thousands: parts.find((part) => part.type === "group")?.value ?? ","
|
|
35
|
+
};
|
|
36
|
+
});
|
|
37
|
+
const placeholder = computed(() => {
|
|
38
|
+
if (props.placeholder !== void 0) {
|
|
39
|
+
return props.placeholder;
|
|
40
|
+
}
|
|
41
|
+
const parts = formatParts(0, { currency: props.currency, locale: props.locale });
|
|
42
|
+
return parts.prefix + parts.amount + parts.digits + parts.suffix;
|
|
19
43
|
});
|
|
20
44
|
const config = computed(() => ({
|
|
21
|
-
decimal: props.decimal,
|
|
45
|
+
decimal: props.decimal ?? separators.value.decimal,
|
|
22
46
|
precision: props.precision,
|
|
23
|
-
prefix: props.prefix.concat(" "),
|
|
47
|
+
prefix: (props.prefix ?? separators.value.symbol).concat(" "),
|
|
24
48
|
suffix: props.suffix,
|
|
25
|
-
thousands: props.thousands
|
|
49
|
+
thousands: props.thousands ?? separators.value.thousands
|
|
26
50
|
}));
|
|
27
51
|
</script>
|
|
28
52
|
|
|
@@ -31,7 +55,7 @@ const config = computed(() => ({
|
|
|
31
55
|
v-model.number="money"
|
|
32
56
|
:max="props.max"
|
|
33
57
|
:min="props.min"
|
|
34
|
-
:placeholder="
|
|
58
|
+
:placeholder="placeholder"
|
|
35
59
|
class="form-control"
|
|
36
60
|
v-bind="config"
|
|
37
61
|
/>
|
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
import type { Numberish } from 'bootstrap-vue-next/dist/src/types/CommonTypes';
|
|
2
2
|
declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
|
3
|
+
/** ISO 4217 code (`BRL`). Falls back to the app default. */
|
|
4
|
+
currency: {
|
|
5
|
+
type: StringConstructor;
|
|
6
|
+
default: undefined;
|
|
7
|
+
};
|
|
3
8
|
decimal: {
|
|
4
9
|
type: StringConstructor;
|
|
5
|
-
default:
|
|
10
|
+
default: undefined;
|
|
11
|
+
};
|
|
12
|
+
/** BCP 47 locale (`pt-BR`). Falls back to the app default. */
|
|
13
|
+
locale: {
|
|
14
|
+
type: StringConstructor;
|
|
15
|
+
default: undefined;
|
|
6
16
|
};
|
|
7
17
|
max: {
|
|
8
18
|
type: NumberConstructor;
|
|
@@ -15,7 +25,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
15
25
|
};
|
|
16
26
|
placeholder: {
|
|
17
27
|
type: StringConstructor;
|
|
18
|
-
default:
|
|
28
|
+
default: undefined;
|
|
19
29
|
};
|
|
20
30
|
precision: {
|
|
21
31
|
type: NumberConstructor;
|
|
@@ -23,7 +33,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
23
33
|
};
|
|
24
34
|
prefix: {
|
|
25
35
|
type: StringConstructor;
|
|
26
|
-
default:
|
|
36
|
+
default: undefined;
|
|
27
37
|
};
|
|
28
38
|
suffix: {
|
|
29
39
|
type: StringConstructor;
|
|
@@ -31,15 +41,25 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
31
41
|
};
|
|
32
42
|
thousands: {
|
|
33
43
|
type: StringConstructor;
|
|
34
|
-
default:
|
|
44
|
+
default: undefined;
|
|
35
45
|
};
|
|
36
46
|
modelValue: Numberish;
|
|
37
47
|
}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
38
48
|
"update:modelValue": (value: Numberish) => any;
|
|
39
49
|
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
50
|
+
/** ISO 4217 code (`BRL`). Falls back to the app default. */
|
|
51
|
+
currency: {
|
|
52
|
+
type: StringConstructor;
|
|
53
|
+
default: undefined;
|
|
54
|
+
};
|
|
40
55
|
decimal: {
|
|
41
56
|
type: StringConstructor;
|
|
42
|
-
default:
|
|
57
|
+
default: undefined;
|
|
58
|
+
};
|
|
59
|
+
/** BCP 47 locale (`pt-BR`). Falls back to the app default. */
|
|
60
|
+
locale: {
|
|
61
|
+
type: StringConstructor;
|
|
62
|
+
default: undefined;
|
|
43
63
|
};
|
|
44
64
|
max: {
|
|
45
65
|
type: NumberConstructor;
|
|
@@ -52,7 +72,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
52
72
|
};
|
|
53
73
|
placeholder: {
|
|
54
74
|
type: StringConstructor;
|
|
55
|
-
default:
|
|
75
|
+
default: undefined;
|
|
56
76
|
};
|
|
57
77
|
precision: {
|
|
58
78
|
type: NumberConstructor;
|
|
@@ -60,7 +80,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
60
80
|
};
|
|
61
81
|
prefix: {
|
|
62
82
|
type: StringConstructor;
|
|
63
|
-
default:
|
|
83
|
+
default: undefined;
|
|
64
84
|
};
|
|
65
85
|
suffix: {
|
|
66
86
|
type: StringConstructor;
|
|
@@ -68,15 +88,17 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|
|
68
88
|
};
|
|
69
89
|
thousands: {
|
|
70
90
|
type: StringConstructor;
|
|
71
|
-
default:
|
|
91
|
+
default: undefined;
|
|
72
92
|
};
|
|
73
93
|
modelValue: Numberish;
|
|
74
94
|
}>> & Readonly<{
|
|
75
95
|
"onUpdate:modelValue"?: ((value: Numberish) => any) | undefined;
|
|
76
96
|
}>, {
|
|
97
|
+
decimal: string;
|
|
98
|
+
currency: string;
|
|
99
|
+
locale: string;
|
|
77
100
|
min: number;
|
|
78
101
|
max: number;
|
|
79
|
-
decimal: string;
|
|
80
102
|
placeholder: string;
|
|
81
103
|
precision: number;
|
|
82
104
|
prefix: string;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { type FormatMoneyOptions } from '../utils/formatMoney.js';
|
|
2
|
+
export interface MoneyDefaults {
|
|
3
|
+
/** ISO 4217 code, e.g. `BRL`. */
|
|
4
|
+
currency?: string;
|
|
5
|
+
/** BCP 47 locale, e.g. `pt-BR` (a bare language such as `pt` also works). */
|
|
6
|
+
locale?: string;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* App-level money defaults used by `MKFormatMoney` / `MKInputMoney`.
|
|
10
|
+
*
|
|
11
|
+
* Resolution order: component props > `setMoneyDefaults()` (runtime, per app) >
|
|
12
|
+
* `merkaly.money` module option (runtime config) > `USD` / `en-US`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const useMoneyFormat: () => {
|
|
15
|
+
currency: import("vue").ComputedRef<string>;
|
|
16
|
+
format: (value: number, options?: FormatMoneyOptions) => string;
|
|
17
|
+
formatParts: (value: number, options?: FormatMoneyOptions) => import("#imports").FormatMoneyParts;
|
|
18
|
+
locale: import("vue").ComputedRef<string>;
|
|
19
|
+
resetMoneyDefaults: () => void;
|
|
20
|
+
resolve: (options?: FormatMoneyOptions) => FormatMoneyOptions;
|
|
21
|
+
setMoneyDefaults: (defaults: MoneyDefaults) => void;
|
|
22
|
+
};
|
|
23
|
+
/** Shortcut for `useMoneyFormat().setMoneyDefaults(defaults)`. */
|
|
24
|
+
export declare const setMoneyDefaults: (defaults: MoneyDefaults) => void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { computed } from "vue";
|
|
2
|
+
import { useRuntimeConfig, useState } from "#imports";
|
|
3
|
+
import {
|
|
4
|
+
DEFAULT_MONEY_CURRENCY,
|
|
5
|
+
DEFAULT_MONEY_LOCALE,
|
|
6
|
+
formatMoney,
|
|
7
|
+
formatMoneyParts
|
|
8
|
+
} from "../utils/formatMoney.js";
|
|
9
|
+
const STATE_KEY = "merkaly:money";
|
|
10
|
+
export const useMoneyFormat = () => {
|
|
11
|
+
const state = useState(STATE_KEY, () => ({}));
|
|
12
|
+
const config = useRuntimeConfig().public.merkaly;
|
|
13
|
+
const currency = computed(() => state.value.currency || config?.money?.currency || DEFAULT_MONEY_CURRENCY);
|
|
14
|
+
const locale = computed(() => state.value.locale || config?.money?.locale || DEFAULT_MONEY_LOCALE);
|
|
15
|
+
const setMoneyDefaults2 = (defaults) => {
|
|
16
|
+
state.value = { ...state.value, ...defaults };
|
|
17
|
+
};
|
|
18
|
+
const resetMoneyDefaults = () => {
|
|
19
|
+
state.value = {};
|
|
20
|
+
};
|
|
21
|
+
const resolve = (options = {}) => ({
|
|
22
|
+
...options,
|
|
23
|
+
currency: options.currency || currency.value,
|
|
24
|
+
locale: options.locale || locale.value,
|
|
25
|
+
symbolCurrency: options.symbolCurrency || currency.value
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
currency,
|
|
29
|
+
format: (value, options) => formatMoney(value, resolve(options)),
|
|
30
|
+
formatParts: (value, options) => formatMoneyParts(value, resolve(options)),
|
|
31
|
+
locale,
|
|
32
|
+
resetMoneyDefaults,
|
|
33
|
+
resolve,
|
|
34
|
+
setMoneyDefaults: setMoneyDefaults2
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export const setMoneyDefaults = (defaults) => useMoneyFormat().setMoneyDefaults(defaults);
|
|
@@ -1,19 +1,49 @@
|
|
|
1
|
+
export declare const DEFAULT_MONEY_CURRENCY = "USD";
|
|
2
|
+
export declare const DEFAULT_MONEY_LOCALE = "en-US";
|
|
1
3
|
export interface FormatMoneyOptions {
|
|
2
4
|
base?: number;
|
|
5
|
+
/**
|
|
6
|
+
* ISO 4217 code (`BRL`, `USD`, ...). For backward compatibility a plain symbol
|
|
7
|
+
* (`$`, `R$`) is also accepted: the number is formatted with `symbolCurrency`
|
|
8
|
+
* (or USD) and the symbol replaces the currency sign.
|
|
9
|
+
*/
|
|
3
10
|
currency?: string;
|
|
4
11
|
locale?: string;
|
|
5
12
|
mode?: Intl.NumberFormatOptionsStyle;
|
|
6
13
|
notation?: Intl.NumberFormatOptions['notation'];
|
|
7
14
|
maximumFractionDigits?: number;
|
|
15
|
+
/** Currency used for the number layout when `currency` is a symbol. */
|
|
16
|
+
symbolCurrency?: string;
|
|
8
17
|
}
|
|
18
|
+
export interface FormatMoneyParts {
|
|
19
|
+
/** Everything before the integer part (sign, currency symbol, spacing). */
|
|
20
|
+
prefix: string;
|
|
21
|
+
/** Integer part with grouping separators. */
|
|
22
|
+
amount: string;
|
|
23
|
+
/** Decimal separator plus fraction digits (empty when there are none). */
|
|
24
|
+
digits: string;
|
|
25
|
+
/** Everything after the fraction (suffix currency symbols, compact units). */
|
|
26
|
+
suffix: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function isCurrencyCode(value?: string): value is string;
|
|
29
|
+
/**
|
|
30
|
+
* Splits a monetary value held as integer cents into display parts using
|
|
31
|
+
* `Intl.NumberFormat#formatToParts`, so multi-character symbols (`R$`) and
|
|
32
|
+
* locale separators (`249,69`) are preserved.
|
|
33
|
+
*/
|
|
34
|
+
export declare function formatMoneyParts(value: number, options?: FormatMoneyOptions): FormatMoneyParts;
|
|
9
35
|
/**
|
|
10
36
|
* Formats a monetary value held as an **integer in the minor unit (cents)**.
|
|
11
37
|
*
|
|
12
38
|
* Across Merkaly money is stored and transported as integer cents ($1.00 -> 100),
|
|
13
39
|
* so this helper divides by `base` (default 100) before formatting. Pass cents in,
|
|
14
|
-
* get a currency string out: `formatMoney(100)` -> `"$1.00"
|
|
40
|
+
* get a currency string out: `formatMoney(100)` -> `"$1.00"`,
|
|
41
|
+
* `formatMoney(24969, { currency: 'BRL', locale: 'pt-BR' })` -> `"R$ 249,69"`.
|
|
42
|
+
*
|
|
43
|
+
* This helper is pure (no app defaults). Inside components prefer
|
|
44
|
+
* `useMoneyFormat().format()`, which applies the app-level currency/locale.
|
|
15
45
|
*
|
|
16
46
|
* For non-currency numbers (counts, units, percentages) use `formatNumber` /
|
|
17
|
-
* `MKFormatNumber` instead
|
|
47
|
+
* `MKFormatNumber` instead, those do NOT divide and would show the raw cents.
|
|
18
48
|
*/
|
|
19
49
|
export declare function formatMoney(value: number, options?: FormatMoneyOptions): string;
|
|
@@ -1,8 +1,45 @@
|
|
|
1
|
-
export
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
export const DEFAULT_MONEY_CURRENCY = "USD";
|
|
2
|
+
export const DEFAULT_MONEY_LOCALE = "en-US";
|
|
3
|
+
const CURRENCY_CODE = /^[A-Z]{3}$/i;
|
|
4
|
+
export function isCurrencyCode(value) {
|
|
5
|
+
return Boolean(value && CURRENCY_CODE.test(value));
|
|
6
|
+
}
|
|
7
|
+
function toFormatter(options) {
|
|
8
|
+
const symbol = isCurrencyCode(options.currency) ? void 0 : options.currency;
|
|
9
|
+
const currency = symbol ? isCurrencyCode(options.symbolCurrency) ? options.symbolCurrency : DEFAULT_MONEY_CURRENCY : options.currency ?? DEFAULT_MONEY_CURRENCY;
|
|
10
|
+
const formatter = new Intl.NumberFormat(options.locale || DEFAULT_MONEY_LOCALE, {
|
|
11
|
+
currency: currency.toUpperCase(),
|
|
12
|
+
maximumFractionDigits: options.maximumFractionDigits,
|
|
5
13
|
notation: options.notation,
|
|
6
|
-
|
|
14
|
+
style: options.mode ?? "currency"
|
|
15
|
+
});
|
|
16
|
+
return { formatter, symbol };
|
|
17
|
+
}
|
|
18
|
+
export function formatMoneyParts(value, options = {}) {
|
|
19
|
+
const { formatter, symbol } = toFormatter(options);
|
|
20
|
+
const parts = formatter.formatToParts(value / (options.base ?? 100)).map((part) => symbol && part.type === "currency" ? { ...part, value: symbol } : part);
|
|
21
|
+
const result = { prefix: "", amount: "", digits: "", suffix: "" };
|
|
22
|
+
const firstNumeric = parts.findIndex((part) => part.type === "integer");
|
|
23
|
+
let lastNumeric = -1;
|
|
24
|
+
parts.forEach((part, index) => {
|
|
25
|
+
if (["integer", "group", "decimal", "fraction"].includes(part.type)) {
|
|
26
|
+
lastNumeric = index;
|
|
27
|
+
}
|
|
7
28
|
});
|
|
29
|
+
parts.forEach((part, index) => {
|
|
30
|
+
if (firstNumeric === -1 || index < firstNumeric) {
|
|
31
|
+
result.prefix += part.value;
|
|
32
|
+
} else if (index > lastNumeric) {
|
|
33
|
+
result.suffix += part.value;
|
|
34
|
+
} else if (part.type === "decimal" || part.type === "fraction") {
|
|
35
|
+
result.digits += part.value;
|
|
36
|
+
} else {
|
|
37
|
+
result.amount += part.value;
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
export function formatMoney(value, options = {}) {
|
|
43
|
+
const parts = formatMoneyParts(value, options);
|
|
44
|
+
return parts.prefix + parts.amount + parts.digits + parts.suffix;
|
|
8
45
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@merkaly/nuxt",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/merkaly-io/nuxt.git"
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@auth0/auth0-spa-js": "^2.29.0",
|
|
32
32
|
"@bootstrap-vue-next/nuxt": "^1.0.0",
|
|
33
|
-
"@nuxt/devtools": "^
|
|
33
|
+
"@nuxt/devtools": "^4.0.0",
|
|
34
34
|
"@nuxt/eslint": "1.17.0",
|
|
35
35
|
"@nuxt/eslint-config": "^1.17.0",
|
|
36
36
|
"@nuxt/fonts": "1.2.0",
|