@schukai/monster 4.11.1 → 4.13.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/CHANGELOG.md +26 -0
- package/package.json +1 -1
- package/source/components/content/camera-capture.mjs +389 -387
- package/source/components/data/metric-graph.mjs +3 -3
- package/source/components/data/metric.mjs +1 -1
- package/source/components/datatable/filter.mjs +22 -0
- package/source/components/form/message-state-button.mjs +26 -22
- package/source/components/layout/popper.mjs +75 -68
- package/source/dom/customelement.mjs +27 -3
- package/source/i18n/util.mjs +41 -0
- package/source/text/generate-range-comparison-expression.mjs +109 -39
- package/source/types/version.mjs +1 -1
- package/test/cases/monster.mjs +1 -1
- package/test/cases/text/generate-range-comparison-expression.mjs +94 -0
- package/test/cases/text/util.mjs +3 -3
- package/test/web/import.js +1 -0
- package/test/web/test.html +2 -2
- package/test/web/tests.js +238 -104
@@ -42,9 +42,9 @@ export const metricGraphControlElementSymbol = Symbol(
|
|
42
42
|
/**
|
43
43
|
* A MetricGraph
|
44
44
|
*
|
45
|
-
* @fragments /fragments/data/metric-graph/
|
45
|
+
* @fragments /fragments/components/data/metric-graph/
|
46
46
|
*
|
47
|
-
* @example /examples/data/metric-graph-simple
|
47
|
+
* @example /examples/components/data/metric-graph-simple
|
48
48
|
*
|
49
49
|
* @since 4.11.0
|
50
50
|
* @copyright schukai GmbH
|
@@ -60,7 +60,7 @@ class MetricGraph extends CustomElement {
|
|
60
60
|
}
|
61
61
|
|
62
62
|
/**
|
63
|
-
* @return {
|
63
|
+
* @return {MetricGraph}
|
64
64
|
*/
|
65
65
|
[assembleMethodSymbol]() {
|
66
66
|
super[assembleMethodSymbol]();
|
@@ -71,6 +71,7 @@ import "../form/context-error.mjs";
|
|
71
71
|
import "../form/message-state-button.mjs";
|
72
72
|
|
73
73
|
import { getLocaleOfDocument } from "../../dom/locale.mjs";
|
74
|
+
import { normalizeNumber } from "../../i18n/util.mjs";
|
74
75
|
|
75
76
|
export { Filter };
|
76
77
|
|
@@ -1259,6 +1260,27 @@ function collectSearchQueries() {
|
|
1259
1260
|
// return query as url encoded
|
1260
1261
|
return encodeURIComponent(query);
|
1261
1262
|
},
|
1263
|
+
"to-int-2": (value, key) => {
|
1264
|
+
const query = normalizeNumber(value);
|
1265
|
+
if (Number.isNaN(query)) {
|
1266
|
+
return key + " IS NULL";
|
1267
|
+
}
|
1268
|
+
return key + "=" + encodeURIComponent(Math.round(query * 100));
|
1269
|
+
},
|
1270
|
+
"to-int-3": (value, key) => {
|
1271
|
+
const query = normalizeNumber(value);
|
1272
|
+
if (Number.isNaN(query)) {
|
1273
|
+
return "";
|
1274
|
+
}
|
1275
|
+
return key + "=" + encodeURIComponent(Math.round(query * 1000));
|
1276
|
+
},
|
1277
|
+
"to-int-4": (value, key) => {
|
1278
|
+
const query = normalizeNumber(value);
|
1279
|
+
if (Number.isNaN(query)) {
|
1280
|
+
return "";
|
1281
|
+
}
|
1282
|
+
return key + "=" + encodeURIComponent(Math.round(query * 10000));
|
1283
|
+
},
|
1262
1284
|
},
|
1263
1285
|
});
|
1264
1286
|
|
@@ -35,19 +35,20 @@ export { MessageStateButton };
|
|
35
35
|
const buttonElementSymbol = Symbol("buttonElement");
|
36
36
|
|
37
37
|
/**
|
38
|
-
* A
|
38
|
+
* A specialized button component that combines state management with message display capabilities.
|
39
|
+
* It extends the Popper component to show messages in a popup overlay and can be used for form submissions
|
40
|
+
* or manual actions.
|
39
41
|
*
|
40
42
|
* @fragments /fragments/components/form/message-state-button/
|
41
|
-
*
|
42
43
|
* @example /examples/components/form/message-state-button-simple
|
43
44
|
*
|
44
45
|
* @since 2.11.0
|
45
46
|
* @copyright schukai GmbH
|
46
|
-
* @summary
|
47
|
-
* @fires monster-
|
48
|
-
* @fires monster-
|
49
|
-
* @fires monster-
|
50
|
-
* @fires monster-
|
47
|
+
* @summary Button component with integrated message display and state management
|
48
|
+
* @fires monster-state-changed - Fired when button state changes
|
49
|
+
* @fires monster-message-shown - Fired when message is displayed
|
50
|
+
* @fires monster-message-hidden - Fired when message is hidden
|
51
|
+
* @fires monster-click - Fired when button is clicked
|
51
52
|
*/
|
52
53
|
class MessageStateButton extends Popper {
|
53
54
|
/**
|
@@ -61,12 +62,12 @@ class MessageStateButton extends Popper {
|
|
61
62
|
}
|
62
63
|
|
63
64
|
/**
|
65
|
+
* Sets the state of the button which affects its visual appearance
|
64
66
|
*
|
65
|
-
* @param {string} state
|
66
|
-
* @param {number} timeout
|
67
|
-
* @return {MessageStateButton}
|
68
|
-
* @throws {TypeError}
|
69
|
-
* @throws {TypeError} value is not an instance
|
67
|
+
* @param {string} state - The state to set (e.g. 'success', 'error', 'loading')
|
68
|
+
* @param {number} timeout - Optional timeout in milliseconds after which state is removed
|
69
|
+
* @return {MessageStateButton} Returns the button instance for chaining
|
70
|
+
* @throws {TypeError} When state is not a string or timeout is not a number
|
70
71
|
*/
|
71
72
|
setState(state, timeout) {
|
72
73
|
return this[buttonElementSymbol].setState(state, timeout);
|
@@ -164,12 +165,13 @@ class MessageStateButton extends Popper {
|
|
164
165
|
}
|
165
166
|
|
166
167
|
/**
|
167
|
-
* Sets the message
|
168
|
+
* Sets the message content to be displayed in the popup overlay
|
168
169
|
*
|
169
|
-
* @param {string|HTMLElement}message
|
170
|
-
* @param {string} title
|
171
|
-
* @param {string} icon
|
172
|
-
* @return {MessageStateButton}
|
170
|
+
* @param {string|HTMLElement} message - The message content as string or HTML element
|
171
|
+
* @param {string} title - Optional title to show above the message
|
172
|
+
* @param {string} icon - Optional icon HTML to display next to the title
|
173
|
+
* @return {MessageStateButton} Returns the button instance for chaining
|
174
|
+
* @throws {TypeError} When message is empty or invalid type
|
173
175
|
*/
|
174
176
|
setMessage(message, title, icon) {
|
175
177
|
if (isString(message)) {
|
@@ -230,10 +232,10 @@ class MessageStateButton extends Popper {
|
|
230
232
|
}
|
231
233
|
|
232
234
|
/**
|
233
|
-
*
|
235
|
+
* Shows the message popup overlay with optional auto-hide timeout
|
234
236
|
*
|
235
|
-
* @param {number} timeout
|
236
|
-
* @return {MessageStateButton}
|
237
|
+
* @param {number} timeout - Optional time in milliseconds after which the message will auto-hide
|
238
|
+
* @return {MessageStateButton} Returns the button instance for chaining
|
237
239
|
*/
|
238
240
|
showMessage(timeout) {
|
239
241
|
this.showDialog.call(this);
|
@@ -248,7 +250,7 @@ class MessageStateButton extends Popper {
|
|
248
250
|
}
|
249
251
|
|
250
252
|
/**
|
251
|
-
* With this method you can show the popper.
|
253
|
+
* With this method, you can show the popper.
|
252
254
|
*
|
253
255
|
* @return {MessageStateButton}
|
254
256
|
*/
|
@@ -306,10 +308,12 @@ class MessageStateButton extends Popper {
|
|
306
308
|
}
|
307
309
|
|
308
310
|
/**
|
309
|
-
*
|
311
|
+
* Programmatically triggers a click event on the button
|
312
|
+
* Will not trigger if button is disabled
|
310
313
|
*
|
311
314
|
* @since 3.27.0
|
312
315
|
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click}
|
316
|
+
* @fires monster-click
|
313
317
|
*/
|
314
318
|
click() {
|
315
319
|
if (this.getOption("disabled") === true) {
|
@@ -34,53 +34,60 @@ import { isArray } from "../../types/is.mjs";
|
|
34
34
|
export { Popper };
|
35
35
|
|
36
36
|
/**
|
37
|
+
* Symbol for timer callback reference
|
37
38
|
* @private
|
38
39
|
* @type {symbol}
|
39
40
|
*/
|
40
41
|
const timerCallbackSymbol = Symbol("timerCallback");
|
41
42
|
|
42
43
|
/**
|
43
|
-
*
|
44
|
+
* Symbol for resize observer reference
|
44
45
|
* @private
|
45
46
|
* @type {symbol}
|
46
47
|
*/
|
47
48
|
const resizeObserverSymbol = Symbol("resizeObserver");
|
48
49
|
|
49
50
|
/**
|
50
|
-
*
|
51
|
+
* Symbol for close event handler reference
|
51
52
|
* @private
|
52
53
|
* @type {symbol}
|
53
54
|
*/
|
54
55
|
const closeEventHandler = Symbol("closeEventHandler");
|
55
56
|
|
56
57
|
/**
|
58
|
+
* Symbol for control element reference
|
57
59
|
* @private
|
58
60
|
* @type {symbol}
|
59
61
|
*/
|
60
62
|
const controlElementSymbol = Symbol("controlElement");
|
61
63
|
|
62
64
|
/**
|
65
|
+
* Symbol for button element reference
|
63
66
|
* @private
|
64
67
|
* @type {symbol}
|
65
68
|
*/
|
66
69
|
const buttonElementSymbol = Symbol("buttonElement");
|
67
70
|
|
68
71
|
/**
|
69
|
-
*
|
72
|
+
* Symbol for popper element reference
|
70
73
|
* @private
|
71
74
|
* @type {symbol}
|
72
75
|
*/
|
73
76
|
const popperElementSymbol = Symbol("popperElement");
|
74
77
|
|
75
78
|
/**
|
76
|
-
*
|
79
|
+
* Symbol for arrow element reference
|
77
80
|
* @private
|
78
81
|
* @type {symbol}
|
79
82
|
*/
|
80
83
|
const arrowElementSymbol = Symbol("arrowElement");
|
81
84
|
|
82
85
|
/**
|
83
|
-
*
|
86
|
+
* Popper component for displaying floating UI elements
|
87
|
+
*
|
88
|
+
* The Popper class creates a floating overlay element that can be shown/hidden
|
89
|
+
* and positioned relative to a trigger element. It supports different interaction
|
90
|
+
* modes like click, hover, focus etc.
|
84
91
|
*
|
85
92
|
* @fragments /fragments/components/layout/popper/
|
86
93
|
*
|
@@ -89,36 +96,34 @@ const arrowElementSymbol = Symbol("arrowElement");
|
|
89
96
|
*
|
90
97
|
* @since 1.65.0
|
91
98
|
* @copyright schukai GmbH
|
92
|
-
* @summary
|
93
|
-
* @fires monster-popper-hide
|
94
|
-
* @fires monster-popper-hidden
|
95
|
-
* @fires monster-popper-open
|
96
|
-
* @fires monster-popper-opened
|
99
|
+
* @summary Floating overlay component with flexible positioning and interaction modes
|
100
|
+
* @fires monster-popper-hide - Fired when popper starts hiding
|
101
|
+
* @fires monster-popper-hidden - Fired when popper is fully hidden
|
102
|
+
* @fires monster-popper-open - Fired when popper starts opening
|
103
|
+
* @fires monster-popper-opened - Fired when popper is fully opened
|
97
104
|
*/
|
98
105
|
class Popper extends CustomElement {
|
99
106
|
/**
|
100
|
-
*
|
101
|
-
* @return {symbol}
|
107
|
+
* Gets the instance symbol for type checking
|
108
|
+
* @return {symbol} The instance type symbol
|
102
109
|
*/
|
103
110
|
static get [instanceSymbol]() {
|
104
111
|
return Symbol.for("@schukai/monster/components/layout/popper@@instance");
|
105
112
|
}
|
106
113
|
|
107
114
|
/**
|
108
|
-
*
|
109
|
-
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
110
|
-
*
|
111
|
-
* The individual configuration values can be found in the table.
|
115
|
+
* Default configuration options for the popper
|
112
116
|
*
|
113
|
-
* @property {Object} templates
|
114
|
-
* @property {string} templates.main
|
115
|
-
* @property {string} mode
|
116
|
-
* @property {string} content
|
117
|
-
* @property {
|
118
|
-
* @property {string} popper.placement
|
119
|
-
* @property {
|
120
|
-
* @property {Object} features
|
121
|
-
* @property {boolean} features.preventOpenEventSent
|
117
|
+
* @property {Object} templates - Template configuration
|
118
|
+
* @property {string} templates.main - Main template HTML
|
119
|
+
* @property {string} mode - Interaction mode(s): click|enter|manual|focus|auto
|
120
|
+
* @property {string} content - Content template
|
121
|
+
* @property {Object} popper - Positioning options
|
122
|
+
* @property {string} popper.placement - Placement: top|bottom|left|right
|
123
|
+
* @property {Array} popper.middleware - Positioning middleware functions
|
124
|
+
* @property {Object} features - Feature flags
|
125
|
+
* @property {boolean} features.preventOpenEventSent - Prevent open event
|
126
|
+
* @returns {Object} Default options merged with parent defaults
|
122
127
|
*/
|
123
128
|
get defaults() {
|
124
129
|
return Object.assign({}, super.defaults, {
|
@@ -138,9 +143,9 @@ class Popper extends CustomElement {
|
|
138
143
|
}
|
139
144
|
|
140
145
|
/**
|
141
|
-
*
|
142
|
-
*
|
143
|
-
* @
|
146
|
+
* Initialize the component
|
147
|
+
* Called on first connection to DOM
|
148
|
+
* @private
|
144
149
|
*/
|
145
150
|
[assembleMethodSymbol]() {
|
146
151
|
super[assembleMethodSymbol]();
|
@@ -149,27 +154,24 @@ class Popper extends CustomElement {
|
|
149
154
|
}
|
150
155
|
|
151
156
|
/**
|
152
|
-
*
|
153
|
-
*
|
154
|
-
* @return {string}
|
157
|
+
* Gets the custom element tag name
|
158
|
+
* @return {string} The tag name
|
155
159
|
*/
|
156
160
|
static getTag() {
|
157
161
|
return "monster-popper";
|
158
162
|
}
|
159
163
|
|
160
164
|
/**
|
161
|
-
*
|
162
|
-
*
|
163
|
-
* @return {CSSStyleSheet[]}
|
165
|
+
* Gets component stylesheets
|
166
|
+
* @return {CSSStyleSheet[]} Array of stylesheets
|
164
167
|
*/
|
165
168
|
static getCSSStyleSheet() {
|
166
169
|
return [PopperStyleSheet];
|
167
170
|
}
|
168
171
|
|
169
172
|
/**
|
170
|
-
*
|
171
|
-
*
|
172
|
-
* @return {void}
|
173
|
+
* Lifecycle callback when element connects to DOM
|
174
|
+
* Sets up event listeners and initializes popper
|
173
175
|
*/
|
174
176
|
connectedCallback() {
|
175
177
|
super.connectedCallback();
|
@@ -177,7 +179,6 @@ class Popper extends CustomElement {
|
|
177
179
|
const document = getDocument();
|
178
180
|
|
179
181
|
for (const [, type] of Object.entries(["click", "touch"])) {
|
180
|
-
// close on outside ui-events
|
181
182
|
document.addEventListener(type, this[closeEventHandler]);
|
182
183
|
}
|
183
184
|
|
@@ -186,14 +187,12 @@ class Popper extends CustomElement {
|
|
186
187
|
}
|
187
188
|
|
188
189
|
/**
|
189
|
-
*
|
190
|
-
*
|
191
|
-
* @return {void}
|
190
|
+
* Lifecycle callback when element disconnects from DOM
|
191
|
+
* Cleans up event listeners and observers
|
192
192
|
*/
|
193
193
|
disconnectedCallback() {
|
194
194
|
super.disconnectedCallback();
|
195
195
|
|
196
|
-
// close on outside ui-events
|
197
196
|
for (const [, type] of Object.entries(["click", "touch"])) {
|
198
197
|
document.removeEventListener(type, this[closeEventHandler]);
|
199
198
|
}
|
@@ -202,9 +201,8 @@ class Popper extends CustomElement {
|
|
202
201
|
}
|
203
202
|
|
204
203
|
/**
|
205
|
-
*
|
206
|
-
*
|
207
|
-
* @return {Popper}
|
204
|
+
* Shows the popper element
|
205
|
+
* @return {Popper} The popper instance
|
208
206
|
*/
|
209
207
|
showDialog() {
|
210
208
|
show.call(this);
|
@@ -212,9 +210,8 @@ class Popper extends CustomElement {
|
|
212
210
|
}
|
213
211
|
|
214
212
|
/**
|
215
|
-
*
|
216
|
-
*
|
217
|
-
* @return {Popper}
|
213
|
+
* Hides the popper element
|
214
|
+
* @return {Popper} The popper instance
|
218
215
|
*/
|
219
216
|
hideDialog() {
|
220
217
|
hide.call(this);
|
@@ -222,9 +219,8 @@ class Popper extends CustomElement {
|
|
222
219
|
}
|
223
220
|
|
224
221
|
/**
|
225
|
-
*
|
226
|
-
*
|
227
|
-
* @return {Popper}
|
222
|
+
* Toggles popper visibility
|
223
|
+
* @return {Popper} The popper instance
|
228
224
|
*/
|
229
225
|
toggleDialog() {
|
230
226
|
if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
|
@@ -237,8 +233,9 @@ class Popper extends CustomElement {
|
|
237
233
|
}
|
238
234
|
|
239
235
|
/**
|
236
|
+
* Initializes event handlers for popper interactivity
|
240
237
|
* @private
|
241
|
-
* @return {Popper}
|
238
|
+
* @return {Popper} The popper instance
|
242
239
|
*/
|
243
240
|
function initEventHandler() {
|
244
241
|
this[closeEventHandler] = (event) => {
|
@@ -276,10 +273,11 @@ function initEventHandler() {
|
|
276
273
|
}
|
277
274
|
|
278
275
|
/**
|
276
|
+
* Sets up event handlers for specific interaction mode
|
279
277
|
* @private
|
280
|
-
* @param mode
|
281
|
-
* @return {Popper}
|
282
|
-
* @throws Error
|
278
|
+
* @param {string} mode - Interaction mode to initialize
|
279
|
+
* @return {Popper} The popper instance
|
280
|
+
* @throws {Error} For unknown modes
|
283
281
|
*/
|
284
282
|
function initEventHandlerByMode(mode) {
|
285
283
|
switch (mode) {
|
@@ -338,10 +336,10 @@ function initEventHandlerByMode(mode) {
|
|
338
336
|
}
|
339
337
|
|
340
338
|
/**
|
339
|
+
* Sets up resize observer for popper repositioning
|
341
340
|
* @private
|
342
341
|
*/
|
343
342
|
function attachResizeObserver() {
|
344
|
-
// against flickering
|
345
343
|
this[resizeObserverSymbol] = new ResizeObserver((entries) => {
|
346
344
|
if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
|
347
345
|
try {
|
@@ -369,6 +367,10 @@ function attachResizeObserver() {
|
|
369
367
|
});
|
370
368
|
}
|
371
369
|
|
370
|
+
/**
|
371
|
+
* Disconnects resize observer
|
372
|
+
* @private
|
373
|
+
*/
|
372
374
|
function disconnectResizeObserver() {
|
373
375
|
if (this[resizeObserverSymbol] instanceof ResizeObserver) {
|
374
376
|
this[resizeObserverSymbol].disconnect();
|
@@ -376,6 +378,7 @@ function disconnectResizeObserver() {
|
|
376
378
|
}
|
377
379
|
|
378
380
|
/**
|
381
|
+
* Hides the popper element
|
379
382
|
* @private
|
380
383
|
*/
|
381
384
|
function hide() {
|
@@ -396,6 +399,7 @@ function hide() {
|
|
396
399
|
}
|
397
400
|
|
398
401
|
/**
|
402
|
+
* Shows the popper element
|
399
403
|
* @private
|
400
404
|
*/
|
401
405
|
function show() {
|
@@ -427,6 +431,7 @@ function show() {
|
|
427
431
|
}
|
428
432
|
|
429
433
|
/**
|
434
|
+
* Updates popper positioning
|
430
435
|
* @private
|
431
436
|
*/
|
432
437
|
function updatePopper() {
|
@@ -447,8 +452,9 @@ function updatePopper() {
|
|
447
452
|
}
|
448
453
|
|
449
454
|
/**
|
455
|
+
* Initializes references to DOM elements
|
450
456
|
* @private
|
451
|
-
* @return {Popper}
|
457
|
+
* @return {Popper} The popper instance
|
452
458
|
*/
|
453
459
|
function initControlReferences() {
|
454
460
|
this[controlElementSymbol] = this.shadowRoot.querySelector(
|
@@ -467,22 +473,23 @@ function initControlReferences() {
|
|
467
473
|
}
|
468
474
|
|
469
475
|
/**
|
476
|
+
* Gets the main template HTML
|
470
477
|
* @private
|
471
|
-
* @return {string}
|
478
|
+
* @return {string} Template HTML
|
472
479
|
*/
|
473
480
|
function getTemplate() {
|
474
481
|
// language=HTML
|
475
482
|
return `
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
483
|
+
<div data-monster-role="control" part="control">
|
484
|
+
<slot name="button" data-monster-role="button"></slot>
|
485
|
+
|
486
|
+
<div data-monster-role="popper" part="popper" tabindex="-1" class="monster-color-primary-1">
|
487
|
+
<div data-monster-role="arrow"></div>
|
488
|
+
<div part="content" class="flex" data-monster-replace="path:content">
|
489
|
+
</div>
|
490
|
+
</div>
|
491
|
+
</div>
|
492
|
+
`;
|
486
493
|
}
|
487
494
|
|
488
495
|
registerCustomElement(Popper);
|
@@ -197,9 +197,22 @@ class CustomElement extends HTMLElement {
|
|
197
197
|
super();
|
198
198
|
|
199
199
|
this[attributeObserverSymbol] = {};
|
200
|
-
|
201
|
-
|
202
|
-
|
200
|
+
|
201
|
+
const options = initOptionsFromAttributes(this, extend({}, this.defaults));
|
202
|
+
if (!isObject(options)) {
|
203
|
+
throw new Error(
|
204
|
+
`The options are not defined correctly in the ${this.getTag()} element.`,
|
205
|
+
);
|
206
|
+
}
|
207
|
+
|
208
|
+
if (this.customization instanceof Map) {
|
209
|
+
const pathfinder = new Pathfinder(options);
|
210
|
+
this.customization.forEach((value, key) => {
|
211
|
+
pathfinder.setVia(key, value);
|
212
|
+
});
|
213
|
+
}
|
214
|
+
|
215
|
+
this[internalSymbol] = new ProxyObserver({ options });
|
203
216
|
this[initMethodSymbol]();
|
204
217
|
initOptionObserver.call(this);
|
205
218
|
this[scriptHostElementSymbol] = [];
|
@@ -249,6 +262,17 @@ class CustomElement extends HTMLElement {
|
|
249
262
|
return this;
|
250
263
|
}
|
251
264
|
|
265
|
+
/**
|
266
|
+
* The `customization` property allows overwriting the defaults.
|
267
|
+
* Unlike the defaults that expect an object, the customization is a Map.
|
268
|
+
* This also allows overwriting individual values in a deeper structure
|
269
|
+
* without having to redefine the entire structure and thus changing the defaults.
|
270
|
+
* @returns {Map}
|
271
|
+
*/
|
272
|
+
get customization() {
|
273
|
+
return new Map();
|
274
|
+
}
|
275
|
+
|
252
276
|
/**
|
253
277
|
* The `defaults` property defines the default values for a control. If you want to override these,
|
254
278
|
* you can use various methods, which are described in the documentation available at
|
package/source/i18n/util.mjs
CHANGED
@@ -14,6 +14,47 @@
|
|
14
14
|
|
15
15
|
import { languages } from "./map/languages.mjs";
|
16
16
|
|
17
|
+
/**
|
18
|
+
* Normalizes a number represented as a string by converting it into a valid floating-point number format,
|
19
|
+
* based on the provided or detected locale. It accounts for different decimal and a thousand separator conventions.
|
20
|
+
*
|
21
|
+
* @param {string} input - The string representation of the number to normalize. May include locale-specific formatting.
|
22
|
+
* @param {string} [locale=navigator.language] - The locale used to determine the decimal separator convention. Defaults to the user's browser locale.
|
23
|
+
* @return {number} The normalized number as a floating-point value. Returns NaN if the input is not a parsable number.
|
24
|
+
*/
|
25
|
+
export function normalizeNumber(input, locale = navigator.language) {
|
26
|
+
if (input === null || input === undefined) return NaN;
|
27
|
+
if (typeof input === "number") return input; // If input is already a number, return it directly
|
28
|
+
if (typeof input !== "string") return NaN;
|
29
|
+
|
30
|
+
const cleaned = input.trim().replace(/\s/g, "");
|
31
|
+
const decimalSeparator = getDecimalSeparator(locale);
|
32
|
+
let normalized = cleaned;
|
33
|
+
|
34
|
+
if (decimalSeparator === "," && cleaned.includes(".")) {
|
35
|
+
normalized = cleaned.replace(/\./g, "").replace(",", ".");
|
36
|
+
} else if (decimalSeparator === "." && cleaned.includes(",")) {
|
37
|
+
normalized = cleaned.replace(/,/g, "").replace(".", ".");
|
38
|
+
} else if (decimalSeparator === "," && cleaned.includes(",")) {
|
39
|
+
normalized = cleaned.replace(",", ".");
|
40
|
+
}
|
41
|
+
|
42
|
+
const result = parseFloat(normalized);
|
43
|
+
return Number.isNaN(result) ? NaN : result;
|
44
|
+
}
|
45
|
+
|
46
|
+
/**
|
47
|
+
* Retrieves the decimal separator for a given locale.
|
48
|
+
*
|
49
|
+
* @param {string} [locale=navigator.language] - The locale identifier to determine the decimal separator. Defaults to the user's current locale if not provided.
|
50
|
+
* @return {string} The decimal separator used in the specified locale.
|
51
|
+
*/
|
52
|
+
function getDecimalSeparator(locale = navigator.language) {
|
53
|
+
const numberWithDecimal = 1.1;
|
54
|
+
const formatted = new Intl.NumberFormat(locale).format(numberWithDecimal);
|
55
|
+
return formatted.replace(/\d/g, "")[0]; // z.B. "," oder "."
|
56
|
+
}
|
57
|
+
|
17
58
|
/**
|
18
59
|
* Determines the user's preferred language based on browser settings and available language options.
|
19
60
|
*
|