@nexterajs/ui 0.0.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.
Files changed (50) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +16 -0
  3. package/README.md +64 -0
  4. package/fesm2022/nexterajs-ui-animations.mjs +184 -0
  5. package/fesm2022/nexterajs-ui-animations.mjs.map +1 -0
  6. package/fesm2022/nexterajs-ui-core.mjs +326 -0
  7. package/fesm2022/nexterajs-ui-core.mjs.map +1 -0
  8. package/fesm2022/nexterajs-ui-dropdowns.mjs +953 -0
  9. package/fesm2022/nexterajs-ui-dropdowns.mjs.map +1 -0
  10. package/fesm2022/nexterajs-ui-excel.mjs +779 -0
  11. package/fesm2022/nexterajs-ui-excel.mjs.map +1 -0
  12. package/fesm2022/nexterajs-ui-file-uploader.mjs +125 -0
  13. package/fesm2022/nexterajs-ui-file-uploader.mjs.map +1 -0
  14. package/fesm2022/nexterajs-ui-forms.mjs +1113 -0
  15. package/fesm2022/nexterajs-ui-forms.mjs.map +1 -0
  16. package/fesm2022/nexterajs-ui-grid.mjs +4145 -0
  17. package/fesm2022/nexterajs-ui-grid.mjs.map +1 -0
  18. package/fesm2022/nexterajs-ui-intl.mjs +377 -0
  19. package/fesm2022/nexterajs-ui-intl.mjs.map +1 -0
  20. package/fesm2022/nexterajs-ui-pivot.mjs +4739 -0
  21. package/fesm2022/nexterajs-ui-pivot.mjs.map +1 -0
  22. package/fesm2022/nexterajs-ui-styling.mjs +59 -0
  23. package/fesm2022/nexterajs-ui-styling.mjs.map +1 -0
  24. package/fesm2022/nexterajs-ui-tree-view.mjs +202 -0
  25. package/fesm2022/nexterajs-ui-tree-view.mjs.map +1 -0
  26. package/fesm2022/nexterajs-ui-validation.mjs +269 -0
  27. package/fesm2022/nexterajs-ui-validation.mjs.map +1 -0
  28. package/fesm2022/nexterajs-ui.mjs +23 -0
  29. package/fesm2022/nexterajs-ui.mjs.map +1 -0
  30. package/package.json +100 -0
  31. package/styles/_button-directives.scss +39 -0
  32. package/styles/_dropdown.scss +113 -0
  33. package/styles/_editor.scss +146 -0
  34. package/styles/_mixins.scss +2 -0
  35. package/styles/_tokens.scss +77 -0
  36. package/styles/_widget.scss +58 -0
  37. package/styles/index.scss +83 -0
  38. package/types/nexterajs-ui-animations.d.ts +22 -0
  39. package/types/nexterajs-ui-core.d.ts +328 -0
  40. package/types/nexterajs-ui-dropdowns.d.ts +334 -0
  41. package/types/nexterajs-ui-excel.d.ts +159 -0
  42. package/types/nexterajs-ui-file-uploader.d.ts +47 -0
  43. package/types/nexterajs-ui-forms.d.ts +296 -0
  44. package/types/nexterajs-ui-grid.d.ts +1485 -0
  45. package/types/nexterajs-ui-intl.d.ts +125 -0
  46. package/types/nexterajs-ui-pivot.d.ts +1470 -0
  47. package/types/nexterajs-ui-styling.d.ts +40 -0
  48. package/types/nexterajs-ui-tree-view.d.ts +69 -0
  49. package/types/nexterajs-ui-validation.d.ts +102 -0
  50. package/types/nexterajs-ui.d.ts +12 -0
@@ -0,0 +1,377 @@
1
+ import { DateTime } from 'luxon';
2
+ import { InjectionToken } from '@angular/core';
3
+
4
+ // DevExtreme LDML-style number format engine for nxe-number-box.
5
+ //
6
+ // Supports the patterns actually used in this codebase:
7
+ // #,##0.00 — grouping, exactly 2 fraction digits
8
+ // #,##0.00000 — grouping, exactly 5 fraction digits
9
+ // #,##0.#####'%' — grouping, 0–5 fraction digits, literal '%' suffix (NO ×100)
10
+ // #0 — integer, no grouping
11
+ // #,##0 — integer with grouping
12
+ // (empty) — raw number, no grouping
13
+ //
14
+ // Tokens: `#` optional digit, `0` required digit, `,` enable grouping (size 3), `.` decimal point
15
+ // (count of `0` after it = min fraction digits, count of `0`+`#` = max), `'…'` verbatim literal.
16
+ /** Parse an LDML pattern into a {@link NxeParsedNumberFormat}, or `null` for raw (no format). */
17
+ function parseNumberFormat(pattern) {
18
+ if (!pattern) {
19
+ return null;
20
+ }
21
+ let prefix = '';
22
+ let suffix = '';
23
+ let core = '';
24
+ let inQuote = false;
25
+ let seenCore = false;
26
+ for (const ch of pattern) {
27
+ if (ch === "'") {
28
+ inQuote = !inQuote;
29
+ continue;
30
+ }
31
+ const isToken = !inQuote && (ch === '#' || ch === '0' || ch === ',' || ch === '.');
32
+ if (isToken) {
33
+ core += ch;
34
+ seenCore = true;
35
+ }
36
+ else if (!seenCore) {
37
+ prefix += ch;
38
+ }
39
+ else {
40
+ suffix += ch;
41
+ }
42
+ }
43
+ if (!core) {
44
+ return null;
45
+ }
46
+ const dot = core.indexOf('.');
47
+ const intPart = dot === -1 ? core : core.slice(0, dot);
48
+ const fracPart = dot === -1 ? '' : core.slice(dot + 1);
49
+ const count = (s, re) => (s.match(re) || []).length;
50
+ // The grouping SIZE comes from the pattern, not from a constant 3: dx reads the digits after
51
+ // the last comma, so `#,##0` groups by 3 and `#,#0` groups by 2 (which renders 1234.5 as
52
+ // "12,34.5"). Several consumer columns use the latter, most likely by accident - but it is
53
+ // what their screens show today, so parity means reproducing it.
54
+ const useGrouping = intPart.includes(',');
55
+ const groupSize = useGrouping
56
+ ? Math.max(1, count(intPart.slice(intPart.lastIndexOf(',') + 1), /[#0]/g))
57
+ : 3;
58
+ return {
59
+ prefix,
60
+ suffix,
61
+ useGrouping,
62
+ groupSize,
63
+ minInt: Math.max(1, count(intPart, /0/g)),
64
+ minFrac: count(fracPart, /0/g),
65
+ maxFrac: count(fracPart, /[#0]/g),
66
+ };
67
+ }
68
+ /**
69
+ * Insert `sep` every `size` digits from the right.
70
+ *
71
+ * Written as a loop rather than a dynamic RegExp on purpose: the group size varies with the
72
+ * pattern, and building a regex by interpolating into a template literal puts `\B` and `\d` one
73
+ * missing backslash away from silently matching nothing.
74
+ */
75
+ function groupDigits(digits, size, sep) {
76
+ let out = '';
77
+ for (let i = 0; i < digits.length; i++) {
78
+ if (i > 0 && (digits.length - i) % size === 0) {
79
+ out += sep;
80
+ }
81
+ out += digits[i];
82
+ }
83
+ return out;
84
+ }
85
+ /**
86
+ * Render `value` with exactly `frac` fraction digits, from its SHORTEST decimal form.
87
+ *
88
+ * `toFixed` expands the binary value instead, so 1234567.891 at 14 digits becomes
89
+ * "1234567.89100000006147" — the true double, and not what dx prints. Taking `String(value)`
90
+ * (the shortest round-tripping decimal) and padding matches dx and is what a reader expects.
91
+ * Exponential notation, which `String` produces below 1e-6, falls back to `toFixed`.
92
+ */
93
+ function toDecimalString(value, frac) {
94
+ const s = String(value);
95
+ if (s.includes('e') || s.includes('E')) {
96
+ return value.toFixed(frac);
97
+ }
98
+ const dot = s.indexOf('.');
99
+ const intPart = dot === -1 ? s : s.slice(0, dot);
100
+ const fracPart = dot === -1 ? '' : s.slice(dot + 1);
101
+ return frac === 0 ? intPart : `${intPart}.${fracPart.slice(0, frac).padEnd(frac, '0')}`;
102
+ }
103
+ /** Round half-away-from-zero to `frac` fraction digits (DevExtreme rounding), fp-safe. */
104
+ function roundHalfAwayFromZero(value, frac) {
105
+ const factor = Math.pow(10, frac);
106
+ const rounded = Math.round(Math.abs(value) * factor + 1e-9) / factor;
107
+ return value < 0 ? -rounded : rounded;
108
+ }
109
+ /** DevExtreme's default, and this library's. */
110
+ const NXE_EN_US_SEPARATORS = { group: ',', decimal: '.' };
111
+ /** Indonesian house style, used by several of the consuming applications. */
112
+ const NXE_ID_SEPARATORS = { group: '.', decimal: ',' };
113
+ function formatNumber(value, fmt, separators = NXE_EN_US_SEPARATORS) {
114
+ if (value == null || typeof value !== 'number' || isNaN(value)) {
115
+ return '';
116
+ }
117
+ if (!fmt) {
118
+ return String(value);
119
+ }
120
+ const negative = value < 0;
121
+ const rounded = roundHalfAwayFromZero(Math.abs(value), fmt.maxFrac);
122
+ const fixed = toDecimalString(rounded, fmt.maxFrac);
123
+ const parts = fixed.split('.');
124
+ let intStr = parts[0];
125
+ let fracStr = parts[1] ?? '';
126
+ if (fmt.maxFrac > fmt.minFrac) {
127
+ fracStr = fracStr.replace(/0+$/, '');
128
+ while (fracStr.length < fmt.minFrac) {
129
+ fracStr += '0';
130
+ }
131
+ }
132
+ while (intStr.length < fmt.minInt) {
133
+ intStr = '0' + intStr;
134
+ }
135
+ if (fmt.useGrouping) {
136
+ intStr = groupDigits(intStr, fmt.groupSize ?? 3, separators.group);
137
+ }
138
+ const body = fracStr ? `${intStr}${separators.decimal}${fracStr}` : intStr;
139
+ return `${fmt.prefix}${negative ? '-' : ''}${body}${fmt.suffix}`;
140
+ }
141
+ /** Parse a (possibly formatted) string into a number; strips grouping/literals. Empty → `null`. */
142
+ function parseNumber(text, separators = NXE_EN_US_SEPARATORS) {
143
+ if (text == null) {
144
+ return null;
145
+ }
146
+ // Strip everything that is not a digit, a sign, or one of this locale's separators, then
147
+ // drop the group separator and normalise the decimal one to `.` for parseFloat.
148
+ const keep = new Set([separators.group, separators.decimal]);
149
+ let cleaned = '';
150
+ for (const ch of text) {
151
+ if ((ch >= '0' && ch <= '9') || ch === '-' || keep.has(ch)) {
152
+ cleaned += ch;
153
+ }
154
+ }
155
+ const normalized = cleaned
156
+ .split(separators.group)
157
+ .join('')
158
+ .replace(separators.decimal, '.');
159
+ if (normalized === '' || normalized === '-' || normalized === '.' || normalized === '-.') {
160
+ return null;
161
+ }
162
+ const num = parseFloat(normalized);
163
+ return isNaN(num) ? null : num;
164
+ }
165
+
166
+ // Luxon-based date parsing/formatting/serialization for nxe-date-box.
167
+ //
168
+ // The app sets a global DevExtreme `dateSerializationFormat: "yyyy-MM-ddTHH:mm:ss"`, so the value
169
+ // stored in the form control is an ISO-like wall-clock string (no zone, no millis). nxe-date-box
170
+ // preserves that contract: it accepts such strings (and tolerates Date / full-ISO-with-Z from the
171
+ // `defaultSystemSettings` directive) and emits the same `"yyyy-MM-ddTHH:mm:ss"` string.
172
+ /** The app-wide serialization format (matches DevExtreme `dateSerializationFormat`). */
173
+ const NXE_DATE_SERIALIZATION_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
174
+ /** DevExtreme global default `displayFormat` (`dxDateBox.defaultOptions`). */
175
+ const NXE_DEFAULT_DISPLAY_FORMAT = 'dd-MMM-yyyy';
176
+ /** Default `displayFormat` for `type="datetime"`. */
177
+ const NXE_DEFAULT_DATETIME_DISPLAY_FORMAT = 'dd-MMM-yyyy HH:mm';
178
+ /** Default `displayFormat` for `type="time"`. */
179
+ const NXE_DEFAULT_TIME_DISPLAY_FORMAT = 'HH:mm';
180
+ /** Parse a bound value (wall-clock ISO string, full ISO, Date, or DateTime) into a Luxon DateTime. */
181
+ function parseDateValue(value) {
182
+ if (value == null || value === '') {
183
+ return null;
184
+ }
185
+ // Passthrough rather than the null this used to return: hasTimeOfDay below is called both on
186
+ // raw row values and on values a caller has already parsed, and it must answer the same either way.
187
+ if (DateTime.isDateTime(value)) {
188
+ return value.isValid ? value : null;
189
+ }
190
+ if (value instanceof Date) {
191
+ const dt = DateTime.fromJSDate(value);
192
+ return dt.isValid ? dt : null;
193
+ }
194
+ if (typeof value === 'string') {
195
+ // Strip millis / trailing Z / numeric offset → treat as local wall-clock (date-preserving).
196
+ const cleaned = value
197
+ .replace(/\.\d+/, '')
198
+ .replace(/Z$/i, '')
199
+ .replace(/[+-]\d{2}:?\d{2}$/, '');
200
+ const dt = DateTime.fromISO(cleaned);
201
+ return dt.isValid ? dt : null;
202
+ }
203
+ return null;
204
+ }
205
+ /** Serialize a DateTime back to the `"yyyy-MM-ddTHH:mm:ss"` string the rest of the app expects. */
206
+ function serializeDate(dt) {
207
+ return dt.toFormat(NXE_DATE_SERIALIZATION_FORMAT);
208
+ }
209
+ /**
210
+ * Whether a value carries a real time of day.
211
+ *
212
+ * This is the one place that states what `00:00:00` MEANS in the app's serialization format: not
213
+ * "midnight", but "no time was chosen". Every date-only editor in the app writes exactly midnight,
214
+ * so the calendar's all-day-vs-timed split, the grid's display format and anything else that has to
215
+ * tell the two apart all read it from here and cannot drift.
216
+ */
217
+ function hasTimeOfDay(value) {
218
+ const dt = parseDateValue(value);
219
+ return !!dt && (dt.hour !== 0 || dt.minute !== 0 || dt.second !== 0 || dt.millisecond !== 0);
220
+ }
221
+ /**
222
+ * Whether a start/end pair describes a whole-day range.
223
+ *
224
+ * Deliberately "every end that is PRESENT is midnight", not "start is midnight AND end is midnight".
225
+ * Half-filled pairs are a supported shape — the calendar endpoint folds `start ?? end` and treats a
226
+ * row carrying only one of the two as a single-day event — and a rule that demanded both would call
227
+ * such a row timed on the strength of the end that is not there.
228
+ *
229
+ * A pair with neither end is all-day by this reading. Degenerate, and unreachable in practice: a row
230
+ * with no dates at all cannot overlap a window, so the endpoint never returns one.
231
+ */
232
+ function isAllDayRange(start, end) {
233
+ return !hasTimeOfDay(start) && !hasTimeOfDay(end);
234
+ }
235
+ /** Format a DateTime for display per `displayFormat` (DevExtreme tokens map 1:1 to Luxon). */
236
+ function formatDisplay(dt, displayFormat) {
237
+ if (!dt) {
238
+ return '';
239
+ }
240
+ return dt.toFormat(displayFormat || NXE_DEFAULT_DISPLAY_FORMAT);
241
+ }
242
+ /**
243
+ * Fixed-width tokens swapped for their variable-width twins in the lenient retry below. Luxon's
244
+ * `dd` demands exactly two digits and `HH` exactly two, so `1-Aug-2026` and `9:00` are both rejected
245
+ * outright by the strict pass — which is a parse failure the user has no way to diagnose.
246
+ *
247
+ * Month tokens are deliberately absent. Degrading `MM` to `M` mangles `MMM` — the very token every
248
+ * orbit format uses — so `dd-MMM-yyyy` would become `dd-MM-yyyy` and then fail to read a
249
+ * three-letter month name as a number. Numeric months stay strict; nothing in the app uses them.
250
+ */
251
+ const NXE_LENIENT_TOKENS = [
252
+ [/dd/g, 'd'],
253
+ [/HH/g, 'H'],
254
+ [/hh/g, 'h'],
255
+ [/mm/g, 'm'],
256
+ [/ss/g, 's'],
257
+ ];
258
+ function lenientFormat(format) {
259
+ return NXE_LENIENT_TOKENS.reduce((result, [token, replacement]) => result.replace(token, replacement), format);
260
+ }
261
+ /**
262
+ * The date-only head of a format carrying time tokens, or null when it carries none.
263
+ *
264
+ * Known limitation, stated rather than handled: quoted literals are not stripped before the scan, so
265
+ * a format like `d 'at' HH:mm` would cut at the `a`. No orbit format uses them.
266
+ */
267
+ function dateOnlyFormat(format) {
268
+ const match = /[Hhmsa]/.exec(format);
269
+ if (!match || match.index === 0) {
270
+ return null;
271
+ }
272
+ const head = format.slice(0, match.index).replace(/[\s,:/.\-]+$/, '');
273
+ return head || null;
274
+ }
275
+ /**
276
+ * Parse user-typed text, trying in order: the display format; a lenient variant of it; for a format
277
+ * carrying time tokens, its date-only head (keeping `base`'s time); then ISO.
278
+ *
279
+ * `base` is what stops a datetime field from being destructive. Without it, typing just the date
280
+ * into a `dd-MMM-yyyy HH:mm` box either resets the time to midnight or — because the strict pass
281
+ * rejects the text outright — nulls the whole field. Callers editing an existing value should pass
282
+ * it; the parameter is optional so the date-only call sites need no change.
283
+ */
284
+ function parseDisplay(text, displayFormat, base) {
285
+ const trimmed = (text ?? '').trim();
286
+ if (!trimmed) {
287
+ return null;
288
+ }
289
+ const format = displayFormat || NXE_DEFAULT_DISPLAY_FORMAT;
290
+ const lenient = lenientFormat(format);
291
+ for (const candidate of lenient === format ? [format] : [format, lenient]) {
292
+ const dt = DateTime.fromFormat(trimmed, candidate);
293
+ if (dt.isValid) {
294
+ return dt;
295
+ }
296
+ }
297
+ const dateOnly = dateOnlyFormat(format);
298
+ if (dateOnly) {
299
+ const lenientDateOnly = lenientFormat(dateOnly);
300
+ for (const candidate of lenientDateOnly === dateOnly ? [dateOnly] : [dateOnly, lenientDateOnly]) {
301
+ const dt = DateTime.fromFormat(trimmed, candidate);
302
+ if (dt.isValid) {
303
+ return base?.isValid ? dt.set({ hour: base.hour, minute: base.minute, second: base.second }) : dt;
304
+ }
305
+ }
306
+ }
307
+ const iso = DateTime.fromISO(trimmed);
308
+ return iso.isValid ? iso : null;
309
+ }
310
+ /**
311
+ * Build the 4×3 period grid for a zoomed-out calendar view (mirrors DevExtreme):
312
+ * `year` → Jan..Dec, `decade` → decadeStart−1..decadeStart+10, `century` → 12 decades
313
+ * from centuryStart−10, labelled `"2020 - 2029"`.
314
+ */
315
+ function buildPeriodCells(zoom, view) {
316
+ if (zoom === 'year') {
317
+ return Array.from({ length: 12 }, (_, i) => {
318
+ const anchor = view.set({ month: i + 1 }).startOf('month');
319
+ return { anchor, label: anchor.toFormat('MMM'), other: false };
320
+ });
321
+ }
322
+ if (zoom === 'decade') {
323
+ const start = view.year - (view.year % 10);
324
+ return Array.from({ length: 12 }, (_, i) => {
325
+ const year = start - 1 + i;
326
+ return { anchor: DateTime.local(year, 1, 1), label: String(year), other: year < start || year > start + 9 };
327
+ });
328
+ }
329
+ const start = view.year - (view.year % 100);
330
+ return Array.from({ length: 12 }, (_, i) => {
331
+ const year = start - 10 + i * 10;
332
+ return { anchor: DateTime.local(year, 1, 1), label: `${year} - ${year + 9}`, other: year < start || year > start + 90 };
333
+ });
334
+ }
335
+ /** Build the 6×7 day grid (Sunday-first) for the calendar popup of `viewMonth`. */
336
+ function buildCalendarWeeks(viewMonth) {
337
+ const firstOfMonth = viewMonth.startOf('month');
338
+ const offset = firstOfMonth.weekday % 7; // luxon: Mon=1..Sun=7 → Sunday-first offset
339
+ let cursor = firstOfMonth.minus({ days: offset }).startOf('day');
340
+ const weeks = [];
341
+ for (let w = 0; w < 6; w++) {
342
+ const days = [];
343
+ for (let d = 0; d < 7; d++) {
344
+ days.push(cursor);
345
+ cursor = cursor.plus({ days: 1 });
346
+ }
347
+ weeks.push(days);
348
+ }
349
+ return weeks;
350
+ }
351
+
352
+ /**
353
+ * The grouping and decimal characters every number editor renders with.
354
+ *
355
+ * DevExtreme solves this with a global `DevExpress.localization.locale()`; the Angular equivalent
356
+ * is a provider, so an application states it once at bootstrap:
357
+ *
358
+ * ```ts
359
+ * providers: [{ provide: NXE_NUMBER_SEPARATORS, useValue: NXE_ID_SEPARATORS }]
360
+ * ```
361
+ *
362
+ * This exists because the alternative already happened: with the separators hardcoded, an
363
+ * application that needed `1.250.000,50` instead of `1,234.50` forked the format engine to get
364
+ * them, and that single file is why its copy of the library could not be merged back.
365
+ *
366
+ * Defaults to en-US, which is DevExtreme's default and what the pattern language itself writes.
367
+ */
368
+ const NXE_NUMBER_SEPARATORS = new InjectionToken('NXE_NUMBER_SEPARATORS', { providedIn: 'root', factory: () => NXE_EN_US_SEPARATORS });
369
+
370
+ // @nexterajs/ui/intl — public API.
371
+
372
+ /**
373
+ * Generated bundle index. Do not edit.
374
+ */
375
+
376
+ export { NXE_DATE_SERIALIZATION_FORMAT, NXE_DEFAULT_DATETIME_DISPLAY_FORMAT, NXE_DEFAULT_DISPLAY_FORMAT, NXE_DEFAULT_TIME_DISPLAY_FORMAT, NXE_EN_US_SEPARATORS, NXE_ID_SEPARATORS, NXE_NUMBER_SEPARATORS, buildCalendarWeeks, buildPeriodCells, formatDisplay, formatNumber, hasTimeOfDay, isAllDayRange, parseDateValue, parseDisplay, parseNumber, parseNumberFormat, roundHalfAwayFromZero, serializeDate };
377
+ //# sourceMappingURL=nexterajs-ui-intl.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nexterajs-ui-intl.mjs","sources":["../../../projects/nextera-ui/intl/src/lib/number-box/nxe-number-format.ts","../../../projects/nextera-ui/intl/src/lib/date-box/nxe-date-format.ts","../../../projects/nextera-ui/intl/src/lib/number-box/nxe-number-locale.ts","../../../projects/nextera-ui/intl/src/public-api.ts","../../../projects/nextera-ui/intl/src/nexterajs-ui-intl.ts"],"sourcesContent":["// DevExtreme LDML-style number format engine for nxe-number-box.\r\n//\r\n// Supports the patterns actually used in this codebase:\r\n// #,##0.00 — grouping, exactly 2 fraction digits\r\n// #,##0.00000 — grouping, exactly 5 fraction digits\r\n// #,##0.#####'%' — grouping, 0–5 fraction digits, literal '%' suffix (NO ×100)\r\n// #0 — integer, no grouping\r\n// #,##0 — integer with grouping\r\n// (empty) — raw number, no grouping\r\n//\r\n// Tokens: `#` optional digit, `0` required digit, `,` enable grouping (size 3), `.` decimal point\r\n// (count of `0` after it = min fraction digits, count of `0`+`#` = max), `'…'` verbatim literal.\r\n\r\nexport interface NxeParsedNumberFormat {\r\n prefix: string;\r\n suffix: string;\r\n useGrouping: boolean;\r\n /**\r\n * Digits per group, read from the pattern: `#,##0` is 3, `#,#0` is 2. Optional because\r\n * callers construct this shape by hand as well as through {@link parseNumberFormat};\r\n * omitted means dx's usual 3.\r\n */\r\n groupSize?: number;\r\n minInt: number;\r\n minFrac: number;\r\n maxFrac: number;\r\n}\r\n\r\n/** Parse an LDML pattern into a {@link NxeParsedNumberFormat}, or `null` for raw (no format). */\r\nexport function parseNumberFormat(pattern: string | undefined | null): NxeParsedNumberFormat | null {\r\n if (!pattern) {\r\n return null;\r\n }\r\n let prefix = '';\r\n let suffix = '';\r\n let core = '';\r\n let inQuote = false;\r\n let seenCore = false;\r\n for (const ch of pattern) {\r\n if (ch === \"'\") {\r\n inQuote = !inQuote;\r\n continue;\r\n }\r\n const isToken = !inQuote && (ch === '#' || ch === '0' || ch === ',' || ch === '.');\r\n if (isToken) {\r\n core += ch;\r\n seenCore = true;\r\n } else if (!seenCore) {\r\n prefix += ch;\r\n } else {\r\n suffix += ch;\r\n }\r\n }\r\n if (!core) {\r\n return null;\r\n }\r\n const dot = core.indexOf('.');\r\n const intPart = dot === -1 ? core : core.slice(0, dot);\r\n const fracPart = dot === -1 ? '' : core.slice(dot + 1);\r\n const count = (s: string, re: RegExp) => (s.match(re) || []).length;\r\n // The grouping SIZE comes from the pattern, not from a constant 3: dx reads the digits after\r\n // the last comma, so `#,##0` groups by 3 and `#,#0` groups by 2 (which renders 1234.5 as\r\n // \"12,34.5\"). Several consumer columns use the latter, most likely by accident - but it is\r\n // what their screens show today, so parity means reproducing it.\r\n const useGrouping = intPart.includes(',');\r\n const groupSize = useGrouping\r\n ? Math.max(1, count(intPart.slice(intPart.lastIndexOf(',') + 1), /[#0]/g))\r\n : 3;\r\n return {\r\n prefix,\r\n suffix,\r\n useGrouping,\r\n groupSize,\r\n minInt: Math.max(1, count(intPart, /0/g)),\r\n minFrac: count(fracPart, /0/g),\r\n maxFrac: count(fracPart, /[#0]/g),\r\n };\r\n}\r\n\r\n/**\r\n * Insert `sep` every `size` digits from the right.\r\n *\r\n * Written as a loop rather than a dynamic RegExp on purpose: the group size varies with the\r\n * pattern, and building a regex by interpolating into a template literal puts `\\B` and `\\d` one\r\n * missing backslash away from silently matching nothing.\r\n */\r\nfunction groupDigits(digits: string, size: number, sep: string): string {\r\n let out = '';\r\n for (let i = 0; i < digits.length; i++) {\r\n if (i > 0 && (digits.length - i) % size === 0) {\r\n out += sep;\r\n }\r\n out += digits[i];\r\n }\r\n return out;\r\n}\r\n\r\n/**\r\n * Render `value` with exactly `frac` fraction digits, from its SHORTEST decimal form.\r\n *\r\n * `toFixed` expands the binary value instead, so 1234567.891 at 14 digits becomes\r\n * \"1234567.89100000006147\" — the true double, and not what dx prints. Taking `String(value)`\r\n * (the shortest round-tripping decimal) and padding matches dx and is what a reader expects.\r\n * Exponential notation, which `String` produces below 1e-6, falls back to `toFixed`.\r\n */\r\nfunction toDecimalString(value: number, frac: number): string {\r\n const s = String(value);\r\n if (s.includes('e') || s.includes('E')) {\r\n return value.toFixed(frac);\r\n }\r\n const dot = s.indexOf('.');\r\n const intPart = dot === -1 ? s : s.slice(0, dot);\r\n const fracPart = dot === -1 ? '' : s.slice(dot + 1);\r\n return frac === 0 ? intPart : `${intPart}.${fracPart.slice(0, frac).padEnd(frac, '0')}`;\r\n}\r\n\r\n/** Round half-away-from-zero to `frac` fraction digits (DevExtreme rounding), fp-safe. */\r\nexport function roundHalfAwayFromZero(value: number, frac: number): number {\r\n const factor = Math.pow(10, frac);\r\n const rounded = Math.round(Math.abs(value) * factor + 1e-9) / factor;\r\n return value < 0 ? -rounded : rounded;\r\n}\r\n\r\n/** Format a number with the parsed pattern. `null`/`NaN` → `''`. */\r\n/**\r\n * The characters that separate groups and the fraction.\r\n *\r\n * The LDML pattern always writes `,` for grouping and `.` for the decimal point — that is the\r\n * pattern language, not the output. Which characters actually get rendered is a locale decision,\r\n * and it is the one that split this file: one consuming app needs `1,234.50`, another needs\r\n * `1.250.000,50`, and hardcoding either forces the other to fork.\r\n */\r\nexport interface NxeNumberSeparators {\r\n readonly group: string;\r\n readonly decimal: string;\r\n}\r\n\r\n/** DevExtreme's default, and this library's. */\r\nexport const NXE_EN_US_SEPARATORS: NxeNumberSeparators = { group: ',', decimal: '.' };\r\n\r\n/** Indonesian house style, used by several of the consuming applications. */\r\nexport const NXE_ID_SEPARATORS: NxeNumberSeparators = { group: '.', decimal: ',' };\r\n\r\nexport function formatNumber(\r\n value: number | null | undefined,\r\n fmt: NxeParsedNumberFormat | null,\r\n separators: NxeNumberSeparators = NXE_EN_US_SEPARATORS,\r\n): string {\r\n if (value == null || typeof value !== 'number' || isNaN(value)) {\r\n return '';\r\n }\r\n if (!fmt) {\r\n return String(value);\r\n }\r\n const negative = value < 0;\r\n const rounded = roundHalfAwayFromZero(Math.abs(value), fmt.maxFrac);\r\n const fixed = toDecimalString(rounded, fmt.maxFrac);\r\n const parts = fixed.split('.');\r\n let intStr = parts[0];\r\n let fracStr = parts[1] ?? '';\r\n if (fmt.maxFrac > fmt.minFrac) {\r\n fracStr = fracStr.replace(/0+$/, '');\r\n while (fracStr.length < fmt.minFrac) {\r\n fracStr += '0';\r\n }\r\n }\r\n while (intStr.length < fmt.minInt) {\r\n intStr = '0' + intStr;\r\n }\r\n if (fmt.useGrouping) {\r\n intStr = groupDigits(intStr, fmt.groupSize ?? 3, separators.group);\r\n }\r\n const body = fracStr ? `${intStr}${separators.decimal}${fracStr}` : intStr;\r\n return `${fmt.prefix}${negative ? '-' : ''}${body}${fmt.suffix}`;\r\n}\r\n\r\n/** Parse a (possibly formatted) string into a number; strips grouping/literals. Empty → `null`. */\r\nexport function parseNumber(\r\n text: string | null | undefined,\r\n separators: NxeNumberSeparators = NXE_EN_US_SEPARATORS,\r\n): number | null {\r\n if (text == null) {\r\n return null;\r\n }\r\n // Strip everything that is not a digit, a sign, or one of this locale's separators, then\r\n // drop the group separator and normalise the decimal one to `.` for parseFloat.\r\n const keep = new Set([separators.group, separators.decimal]);\r\n let cleaned = '';\r\n for (const ch of text) {\r\n if ((ch >= '0' && ch <= '9') || ch === '-' || keep.has(ch)) {\r\n cleaned += ch;\r\n }\r\n }\r\n const normalized = cleaned\r\n .split(separators.group)\r\n .join('')\r\n .replace(separators.decimal, '.');\r\n\r\n if (normalized === '' || normalized === '-' || normalized === '.' || normalized === '-.') {\r\n return null;\r\n }\r\n const num = parseFloat(normalized);\r\n return isNaN(num) ? null : num;\r\n}\r\n","// Luxon-based date parsing/formatting/serialization for nxe-date-box.\r\n//\r\n// The app sets a global DevExtreme `dateSerializationFormat: \"yyyy-MM-ddTHH:mm:ss\"`, so the value\r\n// stored in the form control is an ISO-like wall-clock string (no zone, no millis). nxe-date-box\r\n// preserves that contract: it accepts such strings (and tolerates Date / full-ISO-with-Z from the\r\n// `defaultSystemSettings` directive) and emits the same `\"yyyy-MM-ddTHH:mm:ss\"` string.\r\n\r\nimport { DateTime } from 'luxon';\r\n\r\n/** The app-wide serialization format (matches DevExtreme `dateSerializationFormat`). */\r\nexport const NXE_DATE_SERIALIZATION_FORMAT = \"yyyy-MM-dd'T'HH:mm:ss\";\r\n/** DevExtreme global default `displayFormat` (`dxDateBox.defaultOptions`). */\r\nexport const NXE_DEFAULT_DISPLAY_FORMAT = 'dd-MMM-yyyy';\r\n/** Default `displayFormat` for `type=\"datetime\"`. */\r\nexport const NXE_DEFAULT_DATETIME_DISPLAY_FORMAT = 'dd-MMM-yyyy HH:mm';\r\n/** Default `displayFormat` for `type=\"time\"`. */\r\nexport const NXE_DEFAULT_TIME_DISPLAY_FORMAT = 'HH:mm';\r\n\r\n/** Parse a bound value (wall-clock ISO string, full ISO, Date, or DateTime) into a Luxon DateTime. */\r\nexport function parseDateValue(value: unknown): DateTime | null {\r\n if (value == null || value === '') {\r\n return null;\r\n }\r\n // Passthrough rather than the null this used to return: hasTimeOfDay below is called both on\r\n // raw row values and on values a caller has already parsed, and it must answer the same either way.\r\n if (DateTime.isDateTime(value)) {\r\n return value.isValid ? value : null;\r\n }\r\n if (value instanceof Date) {\r\n const dt = DateTime.fromJSDate(value);\r\n return dt.isValid ? dt : null;\r\n }\r\n if (typeof value === 'string') {\r\n // Strip millis / trailing Z / numeric offset → treat as local wall-clock (date-preserving).\r\n const cleaned = value\r\n .replace(/\\.\\d+/, '')\r\n .replace(/Z$/i, '')\r\n .replace(/[+-]\\d{2}:?\\d{2}$/, '');\r\n const dt = DateTime.fromISO(cleaned);\r\n return dt.isValid ? dt : null;\r\n }\r\n return null;\r\n}\r\n\r\n/** Serialize a DateTime back to the `\"yyyy-MM-ddTHH:mm:ss\"` string the rest of the app expects. */\r\nexport function serializeDate(dt: DateTime): string {\r\n return dt.toFormat(NXE_DATE_SERIALIZATION_FORMAT);\r\n}\r\n\r\n/**\r\n * Whether a value carries a real time of day.\r\n *\r\n * This is the one place that states what `00:00:00` MEANS in the app's serialization format: not\r\n * \"midnight\", but \"no time was chosen\". Every date-only editor in the app writes exactly midnight,\r\n * so the calendar's all-day-vs-timed split, the grid's display format and anything else that has to\r\n * tell the two apart all read it from here and cannot drift.\r\n */\r\nexport function hasTimeOfDay(value: unknown): boolean {\r\n const dt = parseDateValue(value);\r\n return !!dt && (dt.hour !== 0 || dt.minute !== 0 || dt.second !== 0 || dt.millisecond !== 0);\r\n}\r\n\r\n/**\r\n * Whether a start/end pair describes a whole-day range.\r\n *\r\n * Deliberately \"every end that is PRESENT is midnight\", not \"start is midnight AND end is midnight\".\r\n * Half-filled pairs are a supported shape — the calendar endpoint folds `start ?? end` and treats a\r\n * row carrying only one of the two as a single-day event — and a rule that demanded both would call\r\n * such a row timed on the strength of the end that is not there.\r\n *\r\n * A pair with neither end is all-day by this reading. Degenerate, and unreachable in practice: a row\r\n * with no dates at all cannot overlap a window, so the endpoint never returns one.\r\n */\r\nexport function isAllDayRange(start: unknown, end: unknown): boolean {\r\n return !hasTimeOfDay(start) && !hasTimeOfDay(end);\r\n}\r\n\r\n/** Format a DateTime for display per `displayFormat` (DevExtreme tokens map 1:1 to Luxon). */\r\nexport function formatDisplay(dt: DateTime | null, displayFormat: string): string {\r\n if (!dt) {\r\n return '';\r\n }\r\n return dt.toFormat(displayFormat || NXE_DEFAULT_DISPLAY_FORMAT);\r\n}\r\n\r\n/**\r\n * Fixed-width tokens swapped for their variable-width twins in the lenient retry below. Luxon's\r\n * `dd` demands exactly two digits and `HH` exactly two, so `1-Aug-2026` and `9:00` are both rejected\r\n * outright by the strict pass — which is a parse failure the user has no way to diagnose.\r\n *\r\n * Month tokens are deliberately absent. Degrading `MM` to `M` mangles `MMM` — the very token every\r\n * orbit format uses — so `dd-MMM-yyyy` would become `dd-MM-yyyy` and then fail to read a\r\n * three-letter month name as a number. Numeric months stay strict; nothing in the app uses them.\r\n */\r\nconst NXE_LENIENT_TOKENS: [RegExp, string][] = [\r\n [/dd/g, 'd'],\r\n [/HH/g, 'H'],\r\n [/hh/g, 'h'],\r\n [/mm/g, 'm'],\r\n [/ss/g, 's'],\r\n];\r\n\r\nfunction lenientFormat(format: string): string {\r\n return NXE_LENIENT_TOKENS.reduce((result, [token, replacement]) => result.replace(token, replacement), format);\r\n}\r\n\r\n/**\r\n * The date-only head of a format carrying time tokens, or null when it carries none.\r\n *\r\n * Known limitation, stated rather than handled: quoted literals are not stripped before the scan, so\r\n * a format like `d 'at' HH:mm` would cut at the `a`. No orbit format uses them.\r\n */\r\nfunction dateOnlyFormat(format: string): string | null {\r\n const match = /[Hhmsa]/.exec(format);\r\n if (!match || match.index === 0) {\r\n return null;\r\n }\r\n const head = format.slice(0, match.index).replace(/[\\s,:/.\\-]+$/, '');\r\n return head || null;\r\n}\r\n\r\n/**\r\n * Parse user-typed text, trying in order: the display format; a lenient variant of it; for a format\r\n * carrying time tokens, its date-only head (keeping `base`'s time); then ISO.\r\n *\r\n * `base` is what stops a datetime field from being destructive. Without it, typing just the date\r\n * into a `dd-MMM-yyyy HH:mm` box either resets the time to midnight or — because the strict pass\r\n * rejects the text outright — nulls the whole field. Callers editing an existing value should pass\r\n * it; the parameter is optional so the date-only call sites need no change.\r\n */\r\nexport function parseDisplay(text: string, displayFormat: string, base?: DateTime | null): DateTime | null {\r\n const trimmed = (text ?? '').trim();\r\n if (!trimmed) {\r\n return null;\r\n }\r\n\r\n const format = displayFormat || NXE_DEFAULT_DISPLAY_FORMAT;\r\n const lenient = lenientFormat(format);\r\n for (const candidate of lenient === format ? [format] : [format, lenient]) {\r\n const dt = DateTime.fromFormat(trimmed, candidate);\r\n if (dt.isValid) {\r\n return dt;\r\n }\r\n }\r\n\r\n const dateOnly = dateOnlyFormat(format);\r\n if (dateOnly) {\r\n const lenientDateOnly = lenientFormat(dateOnly);\r\n for (const candidate of lenientDateOnly === dateOnly ? [dateOnly] : [dateOnly, lenientDateOnly]) {\r\n const dt = DateTime.fromFormat(trimmed, candidate);\r\n if (dt.isValid) {\r\n return base?.isValid ? dt.set({ hour: base.hour, minute: base.minute, second: base.second }) : dt;\r\n }\r\n }\r\n }\r\n\r\n const iso = DateTime.fromISO(trimmed);\r\n return iso.isValid ? iso : null;\r\n}\r\n\r\n/** Calendar zoom level (DevExtreme `dxCalendar.zoomLevel`). */\r\nexport type NxeCalendarZoom = 'month' | 'year' | 'decade' | 'century';\r\n\r\nexport interface NxePeriodCell {\r\n /** First day of the period (month / year / decade). */\r\n anchor: DateTime;\r\n label: string;\r\n /** Belongs to the adjacent decade/century (rendered dimmed, DevExtreme `other-view`). */\r\n other: boolean;\r\n}\r\n\r\n/**\r\n * Build the 4×3 period grid for a zoomed-out calendar view (mirrors DevExtreme):\r\n * `year` → Jan..Dec, `decade` → decadeStart−1..decadeStart+10, `century` → 12 decades\r\n * from centuryStart−10, labelled `\"2020 - 2029\"`.\r\n */\r\nexport function buildPeriodCells(zoom: Exclude<NxeCalendarZoom, 'month'>, view: DateTime): NxePeriodCell[] {\r\n if (zoom === 'year') {\r\n return Array.from({ length: 12 }, (_, i) => {\r\n const anchor = view.set({ month: i + 1 }).startOf('month');\r\n return { anchor, label: anchor.toFormat('MMM'), other: false };\r\n });\r\n }\r\n if (zoom === 'decade') {\r\n const start = view.year - (view.year % 10);\r\n return Array.from({ length: 12 }, (_, i) => {\r\n const year = start - 1 + i;\r\n return { anchor: DateTime.local(year, 1, 1), label: String(year), other: year < start || year > start + 9 };\r\n });\r\n }\r\n const start = view.year - (view.year % 100);\r\n return Array.from({ length: 12 }, (_, i) => {\r\n const year = start - 10 + i * 10;\r\n return { anchor: DateTime.local(year, 1, 1), label: `${year} - ${year + 9}`, other: year < start || year > start + 90 };\r\n });\r\n}\r\n\r\n/** Build the 6×7 day grid (Sunday-first) for the calendar popup of `viewMonth`. */\r\nexport function buildCalendarWeeks(viewMonth: DateTime): DateTime[][] {\r\n const firstOfMonth = viewMonth.startOf('month');\r\n const offset = firstOfMonth.weekday % 7; // luxon: Mon=1..Sun=7 → Sunday-first offset\r\n let cursor = firstOfMonth.minus({ days: offset }).startOf('day');\r\n const weeks: DateTime[][] = [];\r\n for (let w = 0; w < 6; w++) {\r\n const days: DateTime[] = [];\r\n for (let d = 0; d < 7; d++) {\r\n days.push(cursor);\r\n cursor = cursor.plus({ days: 1 });\r\n }\r\n weeks.push(days);\r\n }\r\n return weeks;\r\n}\r\n","import { InjectionToken } from '@angular/core';\r\nimport { NXE_EN_US_SEPARATORS, type NxeNumberSeparators } from './nxe-number-format';\r\n\r\nexport { NXE_EN_US_SEPARATORS, NXE_ID_SEPARATORS } from './nxe-number-format';\r\nexport type { NxeNumberSeparators } from './nxe-number-format';\r\n\r\n/**\r\n * The grouping and decimal characters every number editor renders with.\r\n *\r\n * DevExtreme solves this with a global `DevExpress.localization.locale()`; the Angular equivalent\r\n * is a provider, so an application states it once at bootstrap:\r\n *\r\n * ```ts\r\n * providers: [{ provide: NXE_NUMBER_SEPARATORS, useValue: NXE_ID_SEPARATORS }]\r\n * ```\r\n *\r\n * This exists because the alternative already happened: with the separators hardcoded, an\r\n * application that needed `1.250.000,50` instead of `1,234.50` forked the format engine to get\r\n * them, and that single file is why its copy of the library could not be merged back.\r\n *\r\n * Defaults to en-US, which is DevExtreme's default and what the pattern language itself writes.\r\n */\r\nexport const NXE_NUMBER_SEPARATORS = new InjectionToken<NxeNumberSeparators>(\r\n 'NXE_NUMBER_SEPARATORS',\r\n { providedIn: 'root', factory: () => NXE_EN_US_SEPARATORS },\r\n);\r\n","// @nexterajs/ui/intl — public API.\r\nexport * from './lib/number-box/nxe-number-format';\r\nexport * from './lib/date-box/nxe-date-format';\r\nexport * from './lib/number-box/nxe-number-locale';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}