anu-verzum 2.0.0 → 2.2.0
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
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
<h3>@author: <strong>Anubis-programmer</strong></h3>
|
|
6
6
|
<h3>@license: <strong>MIT</strong></h3>
|
|
7
|
-
<h3>@version: <strong>2.
|
|
7
|
+
<h3>@version: <strong>2.2.0</strong></h3>
|
|
8
8
|
|
|
9
9
|
<br>
|
|
10
10
|
|
|
@@ -88,6 +88,17 @@ module.exports = require('anu-verzum/webpack.config')(__dirname, {
|
|
|
88
88
|
});
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
Use `rules` to append additional webpack module rules after the built-in `babel-loader` rule. This is how you wire up CSS, LESS, images, or any other asset type:
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
module.exports = require('anu-verzum/webpack.config')(__dirname, {
|
|
95
|
+
rules: [
|
|
96
|
+
{ test: /\.css$/, use: ['style-loader', 'css-loader'] },
|
|
97
|
+
{ test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }
|
|
98
|
+
]
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
91
102
|
<h3 id="importing-in-your-files">Importing in your files</h3>
|
|
92
103
|
|
|
93
104
|
Every file that contains JSX must import `Anu`, because the JSX transform expands to `Anu.createElement(...)` calls at compile time:
|
|
@@ -185,6 +196,8 @@ The following types are exported from `anu-verzum` for use in consumer projects:
|
|
|
185
196
|
| `CreateSelectorFn` | Overloaded interface for `Anu.store.createSelector` — enables full type inference on transformation parameters |
|
|
186
197
|
| `ApiSuccessResponse<T>` | Successful HTTP response `{ status: number; response: T \| null }` |
|
|
187
198
|
| `ApiErrorResponse` | Error HTTP response `{ status: number; response: null }` |
|
|
199
|
+
| `FormatNumberOptions` | Options for `Anu.Intl.formatNumber` — `Intl.NumberFormatOptions` plus an optional `locale` |
|
|
200
|
+
| `ParseNumberOptions` | Options for `Anu.Intl.parseNumber` — `{ locale?: string }` |
|
|
188
201
|
|
|
189
202
|
#### Library development scripts
|
|
190
203
|
|
|
@@ -14,8 +14,16 @@ export interface AbbreviateNumberOptions {
|
|
|
14
14
|
decimalPlaces?: number;
|
|
15
15
|
decimalSign?: string;
|
|
16
16
|
}
|
|
17
|
+
export interface FormatNumberOptions extends Intl.NumberFormatOptions {
|
|
18
|
+
locale?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface ParseNumberOptions {
|
|
21
|
+
locale?: string;
|
|
22
|
+
}
|
|
17
23
|
declare const Intl: {
|
|
18
24
|
abbreviateNumber: (value: number, options?: AbbreviateNumberOptions) => string | number;
|
|
25
|
+
formatNumber: (value: number, options?: FormatNumberOptions) => string;
|
|
26
|
+
parseNumber: (text: string, options?: ParseNumberOptions) => number | null;
|
|
19
27
|
FormattedMessage: ({ id, values, defaultMessage }: FormattedMessageProps) => AnuElement;
|
|
20
28
|
formatMessage: (id: string, values?: Record<string, string | number>, defaultMessage?: string) => string;
|
|
21
29
|
Provider: ({ locale, messages, defaultLocale, children }: IntlProviderProps) => AnuElement | null;
|
|
@@ -11,6 +11,11 @@ let __messagesContext = {
|
|
|
11
11
|
locale: undefined,
|
|
12
12
|
messages: {}
|
|
13
13
|
};
|
|
14
|
+
|
|
15
|
+
// `Intl.NumberFormatOptions` here refers to the global ECMAScript Intl namespace
|
|
16
|
+
// (type space), not the local `Intl` API object declared at the bottom of this
|
|
17
|
+
// file — a `const` introduces only a value binding, so the type reference is safe.
|
|
18
|
+
|
|
14
19
|
const IntlProvider = ({
|
|
15
20
|
locale,
|
|
16
21
|
messages,
|
|
@@ -113,8 +118,15 @@ const formatMessage = (id, values, defaultMessage) => {
|
|
|
113
118
|
}
|
|
114
119
|
return textValue;
|
|
115
120
|
};
|
|
121
|
+
|
|
122
|
+
// Reduce any BCP 47 tag to its lowercase language subtag, e.g. 'hu-HU' / 'HU' → 'hu'.
|
|
123
|
+
// Used for the exact dictionary-key lookups below (UNITS / DECIMAL_SIGN), which key
|
|
124
|
+
// on the language only — so a Provider locale of 'hu', 'HU', or 'hu-HU' all resolve
|
|
125
|
+
// to the same Hungarian entry. (formatNumber/parseNumber keep the full tag, since the
|
|
126
|
+
// region subtag is meaningful to Intl.NumberFormat — e.g. en-US vs en-GB vs en-IN.)
|
|
127
|
+
const getLanguageSubtag = locale => locale ? locale.toLowerCase().split('-')[0] : undefined;
|
|
116
128
|
const abbreviateNumber = (value, options = {}) => {
|
|
117
|
-
const getByLocale = values => values[__messagesContext.locale || 'default'] || values['default'];
|
|
129
|
+
const getByLocale = values => values[getLanguageSubtag(__messagesContext.locale) || 'default'] || values['default'];
|
|
118
130
|
const UNITS = {
|
|
119
131
|
hu: ['E', 'm', 'M', 'b'],
|
|
120
132
|
default: ['K', 'M', 'B', 'T']
|
|
@@ -162,8 +174,70 @@ const abbreviateNumber = (value, options = {}) => {
|
|
|
162
174
|
}
|
|
163
175
|
return value;
|
|
164
176
|
};
|
|
177
|
+
|
|
178
|
+
// The local `Intl` object below shadows the global ECMAScript `Intl`, so number
|
|
179
|
+
// formatting/parsing must reach the real `Intl.NumberFormat` via `globalThis.Intl`.
|
|
180
|
+
const resolveLocale = locale => locale || __messagesContext.locale || undefined;
|
|
181
|
+
const formatNumber = (value, options = {}) => {
|
|
182
|
+
const {
|
|
183
|
+
locale,
|
|
184
|
+
...numberFormatOptions
|
|
185
|
+
} = options;
|
|
186
|
+
if (typeof value !== 'number' || isNaN(value)) {
|
|
187
|
+
return String(value);
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
return new globalThis.Intl.NumberFormat(resolveLocale(locale), numberFormatOptions).format(value);
|
|
191
|
+
} catch (err) {
|
|
192
|
+
console.error(err);
|
|
193
|
+
return String(value);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
const parseNumber = (text, options = {}) => {
|
|
197
|
+
if (typeof text !== 'string') {
|
|
198
|
+
return null;
|
|
199
|
+
}
|
|
200
|
+
try {
|
|
201
|
+
// Discover the locale's grouping/decimal/minus marks from a known sample,
|
|
202
|
+
// then normalize the input back into a plain JS-parseable number string.
|
|
203
|
+
const parts = new globalThis.Intl.NumberFormat(resolveLocale(options.locale)).formatToParts(-12345.6);
|
|
204
|
+
const groupSign = parts.find(p => p.type === 'group')?.value ?? '';
|
|
205
|
+
const decimalSign = parts.find(p => p.type === 'decimal')?.value ?? '.';
|
|
206
|
+
const minusSign = parts.find(p => p.type === 'minusSign')?.value ?? '-';
|
|
207
|
+
let normalized = text.trim();
|
|
208
|
+
const isNegative = normalized.indexOf('-') > -1 || !!minusSign && normalized.indexOf(minusSign) > -1;
|
|
209
|
+
|
|
210
|
+
// Drop grouping separators: the explicit locale group sign plus any
|
|
211
|
+
// whitespace (JS `\s` covers NBSP/NNBSP, which several locales group with).
|
|
212
|
+
if (groupSign) {
|
|
213
|
+
normalized = normalized.split(groupSign).join('');
|
|
214
|
+
}
|
|
215
|
+
normalized = normalized.replace(/\s/g, '');
|
|
216
|
+
|
|
217
|
+
// Convert the locale decimal sign to a dot.
|
|
218
|
+
if (decimalSign && decimalSign !== '.') {
|
|
219
|
+
normalized = normalized.split(decimalSign).join('.');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Keep only digits and the decimal dot; sign is reapplied from isNegative.
|
|
223
|
+
normalized = normalized.replace(/[^0-9.]/g, '');
|
|
224
|
+
if (normalized === '' || normalized === '.') {
|
|
225
|
+
return null;
|
|
226
|
+
}
|
|
227
|
+
const result = Number(normalized);
|
|
228
|
+
if (isNaN(result)) {
|
|
229
|
+
return null;
|
|
230
|
+
}
|
|
231
|
+
return isNegative ? -result : result;
|
|
232
|
+
} catch (err) {
|
|
233
|
+
console.error(err);
|
|
234
|
+
return null;
|
|
235
|
+
}
|
|
236
|
+
};
|
|
165
237
|
const Intl = {
|
|
166
238
|
abbreviateNumber,
|
|
239
|
+
formatNumber,
|
|
240
|
+
parseNumber,
|
|
167
241
|
FormattedMessage,
|
|
168
242
|
formatMessage,
|
|
169
243
|
Provider: IntlProvider
|
package/dist/index.d.ts
CHANGED
|
@@ -102,6 +102,8 @@ declare const Anu: {
|
|
|
102
102
|
};
|
|
103
103
|
Intl: {
|
|
104
104
|
abbreviateNumber: (value: number, options?: import(".").AbbreviateNumberOptions) => string | number;
|
|
105
|
+
formatNumber: (value: number, options?: import(".").FormatNumberOptions) => string;
|
|
106
|
+
parseNumber: (text: string, options?: import(".").ParseNumberOptions) => number | null;
|
|
105
107
|
FormattedMessage: ({ id, values, defaultMessage }: import("./core/components/Intl").FormattedMessageProps) => AnuElement;
|
|
106
108
|
formatMessage: (id: string, values?: Record<string, string | number>, defaultMessage?: string) => string;
|
|
107
109
|
Provider: ({ locale, messages, defaultLocale, children }: import("./core/components/Intl").IntlProviderProps) => AnuElement | null;
|
|
@@ -160,7 +162,7 @@ export type { ApiSuccessResponse, ApiErrorResponse } from './server-api/server-a
|
|
|
160
162
|
export { Component, Fragment, createElement, createRef, createPortal, createContext, render, goTo };
|
|
161
163
|
export { AnulyticsProvider, trackEvent };
|
|
162
164
|
export { store, ServerAPI, Utils, Connector, Feature, History, Intl };
|
|
163
|
-
export type { AbbreviateNumberOptions } from './core/components/Intl';
|
|
165
|
+
export type { AbbreviateNumberOptions, FormatNumberOptions, ParseNumberOptions } from './core/components/Intl';
|
|
164
166
|
declare global {
|
|
165
167
|
namespace JSX {
|
|
166
168
|
interface IntrinsicAttributes {
|
|
@@ -15,8 +15,12 @@ const queryAllByLabelText = (container, label) => {
|
|
|
15
15
|
}
|
|
16
16
|
const forAttr = labelEl.getAttribute('for');
|
|
17
17
|
if (forAttr) {
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
// The `for` attribute is already an element id, so resolve it with
|
|
19
|
+
// getElementById — no CSS.escape needed (jsdom omits the browser-only
|
|
20
|
+
// `CSS` global), and it handles any id characters. Scope to container.
|
|
21
|
+
const doc = container.ownerDocument ?? document;
|
|
22
|
+
const input = doc.getElementById(forAttr);
|
|
23
|
+
if (input && container.contains(input)) {
|
|
20
24
|
results.push(input);
|
|
21
25
|
}
|
|
22
26
|
return;
|
package/package.json
CHANGED