@nanahoshi/mona-ui 0.24.4 → 0.24.6

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 (80) hide show
  1. package/README.md +3 -0
  2. package/fesm2022/nanahoshi-mona-ui-auto-complete.mjs +95 -70
  3. package/fesm2022/nanahoshi-mona-ui-calendar.mjs +196 -137
  4. package/fesm2022/nanahoshi-mona-ui-combo-box.mjs +136 -89
  5. package/fesm2022/nanahoshi-mona-ui-date-input.mjs +164 -3
  6. package/fesm2022/nanahoshi-mona-ui-date-picker.mjs +124 -140
  7. package/fesm2022/nanahoshi-mona-ui-datetime-picker.mjs +205 -202
  8. package/fesm2022/nanahoshi-mona-ui-dropdown-list.mjs +108 -56
  9. package/fesm2022/nanahoshi-mona-ui-dropdowns.mjs +68 -59
  10. package/fesm2022/nanahoshi-mona-ui-editor.mjs +3 -3
  11. package/fesm2022/nanahoshi-mona-ui-filter.mjs +1 -1
  12. package/fesm2022/{nanahoshi-mona-ui-grid-grid-footer-row.component-DLOPRuFv.mjs → nanahoshi-mona-ui-grid-grid-footer-row.component-CD_ODHpU.mjs} +2 -2
  13. package/fesm2022/{nanahoshi-mona-ui-grid-grid-list.component-Dw5U9H0a.mjs → nanahoshi-mona-ui-grid-grid-list.component-0jN7I1jo.mjs} +4 -4
  14. package/fesm2022/{nanahoshi-mona-ui-grid-grid-row.component-D1kyAzD8.mjs → nanahoshi-mona-ui-grid-grid-row.component-BI_iE7pl.mjs} +3 -3
  15. package/fesm2022/{nanahoshi-mona-ui-grid-grid-virtual-list.component-ECK1_smx.mjs → nanahoshi-mona-ui-grid-grid-virtual-list.component-Sa1aAtJ-.mjs} +4 -4
  16. package/fesm2022/{nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-D4lUDbfx.mjs → nanahoshi-mona-ui-grid-nanahoshi-mona-ui-grid-BvUM9nPt.mjs} +8 -8
  17. package/fesm2022/nanahoshi-mona-ui-grid.mjs +1 -1
  18. package/fesm2022/nanahoshi-mona-ui-i18n-icu.mjs +2 -1
  19. package/fesm2022/nanahoshi-mona-ui-internal-indicator-icon.mjs +2 -2
  20. package/fesm2022/nanahoshi-mona-ui-internal.mjs +4 -2
  21. package/fesm2022/nanahoshi-mona-ui-locales-ar-sa.mjs +2 -1
  22. package/fesm2022/nanahoshi-mona-ui-locales-de-de.mjs +4 -1
  23. package/fesm2022/nanahoshi-mona-ui-locales-es-es.mjs +4 -1
  24. package/fesm2022/nanahoshi-mona-ui-locales-fr-fr.mjs +4 -1
  25. package/fesm2022/nanahoshi-mona-ui-locales-id-id.mjs +2 -1
  26. package/fesm2022/nanahoshi-mona-ui-locales-it-it.mjs +2 -1
  27. package/fesm2022/nanahoshi-mona-ui-locales-ja-jp.mjs +2 -1
  28. package/fesm2022/nanahoshi-mona-ui-locales-ko-kr.mjs +2 -1
  29. package/fesm2022/nanahoshi-mona-ui-locales-pt-br.mjs +2 -1
  30. package/fesm2022/nanahoshi-mona-ui-locales-ru-ru.mjs +2 -1
  31. package/fesm2022/nanahoshi-mona-ui-locales-tr-tr.mjs +2 -1
  32. package/fesm2022/nanahoshi-mona-ui-locales-zh-cn.mjs +2 -1
  33. package/fesm2022/nanahoshi-mona-ui-locales-zh-tw.mjs +2 -1
  34. package/fesm2022/nanahoshi-mona-ui-multi-select.mjs +118 -66
  35. package/fesm2022/nanahoshi-mona-ui-numeric-text-box.mjs +195 -122
  36. package/fesm2022/nanahoshi-mona-ui-pager.mjs +1 -1
  37. package/fesm2022/nanahoshi-mona-ui-time-picker.mjs +149 -167
  38. package/fesm2022/nanahoshi-mona-ui-time-selector.mjs +182 -137
  39. package/i18n/catalogs/en-US.messages.json +2 -1
  40. package/locales/ar-sa/ar-sa.messages.json +2 -1
  41. package/locales/de-de/de-de.messages.json +2 -1
  42. package/locales/es-es/es-es.messages.json +2 -1
  43. package/locales/fr-fr/fr-fr.messages.json +2 -1
  44. package/locales/id-id/id-id.messages.json +2 -1
  45. package/locales/it-it/it-it.messages.json +2 -1
  46. package/locales/ja-jp/ja-jp.messages.json +2 -1
  47. package/locales/ko-kr/ko-kr.messages.json +2 -1
  48. package/locales/pt-br/pt-br.messages.json +2 -1
  49. package/locales/ru-ru/ru-ru.messages.json +2 -1
  50. package/locales/tr-tr/tr-tr.messages.json +2 -1
  51. package/locales/zh-cn/zh-cn.messages.json +2 -1
  52. package/locales/zh-tw/zh-tw.messages.json +2 -1
  53. package/package.json +2 -2
  54. package/types/nanahoshi-mona-ui-auto-complete.d.ts +34 -20
  55. package/types/nanahoshi-mona-ui-calendar.d.ts +30 -11
  56. package/types/nanahoshi-mona-ui-combo-box.d.ts +42 -23
  57. package/types/nanahoshi-mona-ui-date-input.d.ts +74 -3
  58. package/types/nanahoshi-mona-ui-date-picker.d.ts +61 -33
  59. package/types/nanahoshi-mona-ui-datetime-picker.d.ts +79 -38
  60. package/types/nanahoshi-mona-ui-dropdown-list.d.ts +29 -15
  61. package/types/nanahoshi-mona-ui-dropdowns.d.ts +30 -19
  62. package/types/nanahoshi-mona-ui-i18n.d.ts +1 -0
  63. package/types/nanahoshi-mona-ui-internal.d.ts +3 -1
  64. package/types/nanahoshi-mona-ui-locales-ar-sa.d.ts +1 -0
  65. package/types/nanahoshi-mona-ui-locales-de-de.d.ts +1 -0
  66. package/types/nanahoshi-mona-ui-locales-es-es.d.ts +1 -0
  67. package/types/nanahoshi-mona-ui-locales-fr-fr.d.ts +1 -0
  68. package/types/nanahoshi-mona-ui-locales-id-id.d.ts +1 -0
  69. package/types/nanahoshi-mona-ui-locales-it-it.d.ts +1 -0
  70. package/types/nanahoshi-mona-ui-locales-ja-jp.d.ts +1 -0
  71. package/types/nanahoshi-mona-ui-locales-ko-kr.d.ts +1 -0
  72. package/types/nanahoshi-mona-ui-locales-pt-br.d.ts +1 -0
  73. package/types/nanahoshi-mona-ui-locales-ru-ru.d.ts +1 -0
  74. package/types/nanahoshi-mona-ui-locales-tr-tr.d.ts +1 -0
  75. package/types/nanahoshi-mona-ui-locales-zh-cn.d.ts +1 -0
  76. package/types/nanahoshi-mona-ui-locales-zh-tw.d.ts +1 -0
  77. package/types/nanahoshi-mona-ui-multi-select.d.ts +45 -21
  78. package/types/nanahoshi-mona-ui-numeric-text-box.d.ts +57 -16
  79. package/types/nanahoshi-mona-ui-time-picker.d.ts +72 -42
  80. package/types/nanahoshi-mona-ui-time-selector.d.ts +78 -46
@@ -1,9 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Directive, Pipe, Injectable } from '@angular/core';
3
- import { toImmutableSet, where, select, sequence } from '@mirei/ts-collections';
2
+ import { Directive, Pipe, Injectable, untracked, linkedSignal } from '@angular/core';
3
+ import { toImmutableSet, where, select, sequence, any } from '@mirei/ts-collections';
4
4
  import { cva } from 'class-variance-authority';
5
5
  import { themeOverlaySurfaceClasses } from '@nanahoshi/mona-ui/internal';
6
6
  import { Subject } from 'rxjs';
7
+ import { minDateError, maxDateError, transformedValue } from '@angular/forms/signals';
8
+ import { parseGregorianDate, gregorianDateTime } from '@nanahoshi/mona-ui/i18n';
7
9
 
8
10
  class DateInputPrefixTemplateDirective {
9
11
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.6", ngImport: i0, type: DateInputPrefixTemplateDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
@@ -121,9 +123,168 @@ const generateSecondSet = (step = 1) => {
121
123
  return select(sequence(0, 59, step), s => ({ value: s, viewValue: s })).toImmutableSet();
122
124
  };
123
125
 
126
+ /**
127
+ * The clock a locale uses by default: "12" for en-US, ja-JP and ko-KR, "24" for de-DE, fr-FR and tr-TR. Locales that
128
+ * mark the hour cycle explicitly (`en-US-u-hc-h23`) are honoured.
129
+ */
130
+ function getLocaleHourFormat(localeId) {
131
+ try {
132
+ const hourCycle = new Intl.DateTimeFormat(localeId, { hour: "numeric" }).resolvedOptions().hourCycle;
133
+ return hourCycle === "h11" || hourCycle === "h12" ? "12" : "24";
134
+ }
135
+ catch {
136
+ return "24";
137
+ }
138
+ }
139
+
140
+ const singleDigitTokens = new Set(["MM", "dd", "HH", "hh", "mm", "ss"]);
141
+ /**
142
+ * Relaxes a Luxon format for typing: two-digit tokens (`MM`, `dd`, `HH`, `hh`, `mm`, `ss`) also accept one digit, and
143
+ * with `twoDigitYear` the year is typed as two digits. Quoted literals are left alone.
144
+ */
145
+ function relaxFormat(format, twoDigitYear) {
146
+ return format
147
+ .split(/('(?:[^']|'')*')/)
148
+ .map((part, index) => {
149
+ if (index % 2 === 1) {
150
+ return part;
151
+ }
152
+ return part.replace(/([A-Za-z])\1*/g, run => {
153
+ if (singleDigitTokens.has(run)) {
154
+ return run[0];
155
+ }
156
+ return twoDigitYear && run === "yyyy" ? "yy" : run;
157
+ });
158
+ })
159
+ .join("");
160
+ }
161
+ /**
162
+ * Parses text typed into a picker. The input format is tried first, then the same format with one-digit months, days,
163
+ * hours, minutes and seconds ("1/5/2025", "9:05"), then with a two-digit year ("1/5/25"). Two-digit years up to 60
164
+ * read as 20xx, later ones as 19xx.
165
+ * @returns The parsed date, or null when the text isn't a date in any of these forms.
166
+ */
167
+ function parseTypedDate(text, format, localeId) {
168
+ const trimmed = text.trim();
169
+ if (!trimmed) {
170
+ return null;
171
+ }
172
+ const relaxed = relaxFormat(format, false);
173
+ const twoDigitYear = relaxFormat(format, true);
174
+ const candidates = [format, ...(relaxed === format ? [] : [relaxed])];
175
+ for (const candidate of candidates) {
176
+ const dateTime = parseGregorianDate(trimmed, candidate, localeId);
177
+ if (dateTime.isValid) {
178
+ return dateTime;
179
+ }
180
+ }
181
+ if (twoDigitYear !== relaxed) {
182
+ // Luxon's "yy" also takes three digits and keeps them as they are ("3/4/202" is the year 202); two digits
183
+ // always land in 1961-2060, and four were read by the formats above.
184
+ const dateTime = parseGregorianDate(trimmed, twoDigitYear, localeId);
185
+ if (dateTime.isValid && dateTime.year >= 1900) {
186
+ return dateTime;
187
+ }
188
+ }
189
+ return null;
190
+ }
191
+ /** Whether a date is one of `disabledDates`, compared by day. */
192
+ function isDateDisabled(date, disabledDates) {
193
+ if (!disabledDates) {
194
+ return false;
195
+ }
196
+ if (typeof disabledDates === "function") {
197
+ return disabledDates(date);
198
+ }
199
+ return any(disabledDates, disabled => disabled.getFullYear() === date.getFullYear() &&
200
+ disabled.getMonth() === date.getMonth() &&
201
+ disabled.getDate() === date.getDate());
202
+ }
203
+ /** The part of a date that min and max are compared on: the day, the full date and time, or the time of day. */
204
+ function comparable(date, unit) {
205
+ switch (unit) {
206
+ case "date":
207
+ return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();
208
+ case "time":
209
+ return ((date.getHours() * 60 + date.getMinutes()) * 60 + date.getSeconds()) * 1000 + date.getMilliseconds();
210
+ default:
211
+ return date.getTime();
212
+ }
213
+ }
214
+ /**
215
+ * Checks a typed date against a picker's min, max and `disabledDates`, the same limits its popup applies.
216
+ * @returns The error to report, or null when the date is allowed. Range errors are Angular's `minDate` and `maxDate`
217
+ * errors, so they read like the signal-forms validators.
218
+ */
219
+ function checkTypedDate(date, constraints) {
220
+ const { disabledDates, max, min, unit } = constraints;
221
+ const value = comparable(date, unit);
222
+ if (min && value < comparable(min, unit)) {
223
+ return minDateError(min);
224
+ }
225
+ if (max && value > comparable(max, unit)) {
226
+ return maxDateError(max);
227
+ }
228
+ if (unit !== "time" && isDateDisabled(date, disabledDates)) {
229
+ const error = { kind: "disabledDate", date };
230
+ return error;
231
+ }
232
+ return null;
233
+ }
234
+ /** The error reported for text that doesn't parse. */
235
+ function typedDateParseError() {
236
+ return { kind: "parse" };
237
+ }
238
+ /**
239
+ * The typed-input pipeline of the date, time and date-time pickers. Call it in an injection context: the errors are
240
+ * reported to the form field (signal forms, `ngModel` or a reactive form control) bound to the picker.
241
+ */
242
+ function createTypedDateInput(options) {
243
+ const { constraints, format, localeId, resolve, value } = options;
244
+ const formatValue = (date) => date ? gregorianDateTime(date, localeId()).toFormat(format()) : "";
245
+ const committed = transformedValue(value, {
246
+ format: formatValue,
247
+ parse: (raw) => {
248
+ const current = untracked(value);
249
+ if (!raw.trim()) {
250
+ return { value: null };
251
+ }
252
+ const parsed = untracked(() => parseTypedDate(raw, format(), localeId()));
253
+ if (!parsed) {
254
+ return { error: typedDateParseError() };
255
+ }
256
+ const date = resolve ? resolve(parsed, current) : parsed.toJSDate();
257
+ const error = untracked(() => checkTypedDate(date, constraints()));
258
+ if (error) {
259
+ return { error };
260
+ }
261
+ return current?.getTime() === date.getTime() ? {} : { value: date };
262
+ }
263
+ });
264
+ const text = linkedSignal(() => committed(), /* @ts-ignore */
265
+ ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
266
+ return {
267
+ commit: () => {
268
+ committed.set(untracked(text));
269
+ if (untracked(committed.parseErrors).length === 0) {
270
+ // Shows "1/5/2025" as "01/05/2025" even when it names the date already set.
271
+ text.set(untracked(() => formatValue(value())));
272
+ }
273
+ },
274
+ edit: (typed) => {
275
+ text.set(typed);
276
+ if (typed === "") {
277
+ committed.set("");
278
+ }
279
+ },
280
+ errors: committed.parseErrors,
281
+ text
282
+ };
283
+ }
284
+
124
285
  /**
125
286
  * Generated bundle index. Do not edit.
126
287
  */
127
288
 
128
- export { CalendarService, DateInputPrefixTemplateDirective, TimeLimiterPipe, TimeSelectorService, datePopupThemeVariants, generateHourSet, generateMinuteSet, generateSecondSet };
289
+ export { CalendarService, DateInputPrefixTemplateDirective, TimeLimiterPipe, TimeSelectorService, checkTypedDate, createTypedDateInput, datePopupThemeVariants, generateHourSet, generateMinuteSet, generateSecondSet, getLocaleHourFormat, isDateDisabled, parseTypedDate, typedDateParseError };
129
290
  //# sourceMappingURL=nanahoshi-mona-ui-date-input.mjs.map