@jirawatpyk/aura-react 5.1.1 → 5.3.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/dist/index.d.cts CHANGED
@@ -417,9 +417,12 @@ export type SelectOption = string | {
417
417
  label: string;
418
418
  disabled?: boolean | undefined;
419
419
  };
420
+ /** 5.3: opens AURA's own list (light and dark alike) over a real `<select>`, which keeps `name`, `required`, the ref,
421
+ * `onChange`, react-hook-form `register` and form posts. `multiple` or `size > 1` keeps the native list box. */
420
422
  export interface SelectProps extends FieldProps, Omit<React$1.SelectHTMLAttributes<HTMLSelectElement>, "required"> {
421
- options: SelectOption[];
422
- /** A disabled first option shown in fg-tertiary until something is chosen. */
423
+ /** The choices; or pass `<option>` / `<optgroup>` children instead (5.3: optional). */
424
+ options?: SelectOption[] | undefined;
425
+ /** Shown in fg-tertiary on the closed field until something is chosen; not listed as a choice. */
423
426
  placeholder?: string | undefined;
424
427
  icon?: IconInput | undefined;
425
428
  }
@@ -1217,6 +1220,7 @@ export interface FieldComponentProps extends Omit<FieldPropsPublic, "label"> {
1217
1220
  export declare const Field: React$1.ForwardRefExoticComponent<FieldComponentProps & React$1.RefAttributes<HTMLDivElement>>;
1218
1221
  export declare const TextField: React$1.ForwardRefExoticComponent<TextFieldProps & React$1.RefAttributes<HTMLInputElement>>;
1219
1222
  export declare const Textarea: React$1.ForwardRefExoticComponent<TextareaProps & React$1.RefAttributes<HTMLTextAreaElement>>;
1223
+ /** A select field: a button that opens an AURA list (5.3), over a real <select> that keeps forms, refs and events. */
1220
1224
  export declare const Select: React$1.ForwardRefExoticComponent<SelectProps & React$1.RefAttributes<HTMLSelectElement>>;
1221
1225
  export declare const RadioGroup: React$1.ForwardRefExoticComponent<RadioGroupProps & React$1.RefAttributes<HTMLFieldSetElement>>;
1222
1226
  export declare const Switch: React$1.ForwardRefExoticComponent<SwitchProps & React$1.RefAttributes<HTMLButtonElement>>;
@@ -1381,6 +1385,9 @@ export interface AuraStrings {
1381
1385
  loadingRows: string;
1382
1386
  range: (a: number | string, b: number | string, total: number) => string;
1383
1387
  page: (p: number, total: number) => string;
1388
+ /** Server paging without totalRows (5.2): the range and page when the total isn't known. */
1389
+ rangeOpen: (a: number | string, b: number | string) => string;
1390
+ pageOpen: (p: number) => string;
1384
1391
  prevPage: string;
1385
1392
  nextPage: string;
1386
1393
  rowCount: (c: number) => string;
@@ -1390,6 +1397,8 @@ export interface AuraStrings {
1390
1397
  timePlaceholder: string;
1391
1398
  timeInvalid: string;
1392
1399
  timeOutOfRange: (a: number | string, b: number | string) => string;
1400
+ /** A time inside the range that isTimeDisabled refuses (5.2). */
1401
+ timeUnavailable: string;
1393
1402
  dropFiles: string;
1394
1403
  browse: string;
1395
1404
  browseOne: string;
package/dist/index.d.ts CHANGED
@@ -417,9 +417,12 @@ export type SelectOption = string | {
417
417
  label: string;
418
418
  disabled?: boolean | undefined;
419
419
  };
420
+ /** 5.3: opens AURA's own list (light and dark alike) over a real `<select>`, which keeps `name`, `required`, the ref,
421
+ * `onChange`, react-hook-form `register` and form posts. `multiple` or `size > 1` keeps the native list box. */
420
422
  export interface SelectProps extends FieldProps, Omit<React$1.SelectHTMLAttributes<HTMLSelectElement>, "required"> {
421
- options: SelectOption[];
422
- /** A disabled first option shown in fg-tertiary until something is chosen. */
423
+ /** The choices; or pass `<option>` / `<optgroup>` children instead (5.3: optional). */
424
+ options?: SelectOption[] | undefined;
425
+ /** Shown in fg-tertiary on the closed field until something is chosen; not listed as a choice. */
423
426
  placeholder?: string | undefined;
424
427
  icon?: IconInput | undefined;
425
428
  }
@@ -1217,6 +1220,7 @@ export interface FieldComponentProps extends Omit<FieldPropsPublic, "label"> {
1217
1220
  export declare const Field: React$1.ForwardRefExoticComponent<FieldComponentProps & React$1.RefAttributes<HTMLDivElement>>;
1218
1221
  export declare const TextField: React$1.ForwardRefExoticComponent<TextFieldProps & React$1.RefAttributes<HTMLInputElement>>;
1219
1222
  export declare const Textarea: React$1.ForwardRefExoticComponent<TextareaProps & React$1.RefAttributes<HTMLTextAreaElement>>;
1223
+ /** A select field: a button that opens an AURA list (5.3), over a real <select> that keeps forms, refs and events. */
1220
1224
  export declare const Select: React$1.ForwardRefExoticComponent<SelectProps & React$1.RefAttributes<HTMLSelectElement>>;
1221
1225
  export declare const RadioGroup: React$1.ForwardRefExoticComponent<RadioGroupProps & React$1.RefAttributes<HTMLFieldSetElement>>;
1222
1226
  export declare const Switch: React$1.ForwardRefExoticComponent<SwitchProps & React$1.RefAttributes<HTMLButtonElement>>;
@@ -1381,6 +1385,9 @@ export interface AuraStrings {
1381
1385
  loadingRows: string;
1382
1386
  range: (a: number | string, b: number | string, total: number) => string;
1383
1387
  page: (p: number, total: number) => string;
1388
+ /** Server paging without totalRows (5.2): the range and page when the total isn't known. */
1389
+ rangeOpen: (a: number | string, b: number | string) => string;
1390
+ pageOpen: (p: number) => string;
1384
1391
  prevPage: string;
1385
1392
  nextPage: string;
1386
1393
  rowCount: (c: number) => string;
@@ -1390,6 +1397,8 @@ export interface AuraStrings {
1390
1397
  timePlaceholder: string;
1391
1398
  timeInvalid: string;
1392
1399
  timeOutOfRange: (a: number | string, b: number | string) => string;
1400
+ /** A time inside the range that isTimeDisabled refuses (5.2). */
1401
+ timeUnavailable: string;
1393
1402
  dropFiles: string;
1394
1403
  browse: string;
1395
1404
  browseOne: string;
@@ -43,12 +43,21 @@ var pad = function(n2) {
43
43
  return (n2 < 10 ? "0" : "") + n2;
44
44
  };
45
45
  function toISO(d) {
46
- return d ? d.getFullYear() + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate()) : null;
46
+ if (!d) return null;
47
+ const y = String(d.getFullYear());
48
+ return ("000" + y).slice(-Math.max(4, y.length)) + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate());
49
+ }
50
+ function makeDate(y, monthIndex2, day) {
51
+ const d = new Date(2e3, 0, 1);
52
+ d.setFullYear(y, monthIndex2, day);
53
+ return d;
47
54
  }
48
55
  function fromISO(s) {
49
56
  if (!s) return null;
50
57
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
51
- return m ? new Date(+m[1], +m[2] - 1, +m[3]) : null;
58
+ if (!m) return null;
59
+ const d = makeDate(+m[1], +m[2] - 1, +m[3]);
60
+ return d.getMonth() === +m[2] - 1 && d.getDate() === +m[3] ? d : null;
52
61
  }
53
62
  var TAGS = { th: "th-TH", en: "en-GB", sv: "sv-SE" };
54
63
  function defaultCalendar(locale) {
@@ -94,7 +103,15 @@ function monthIndex(word) {
94
103
  return MONTHS[k] != null ? MONTHS[k] : -1;
95
104
  }
96
105
  function parseDate(text) {
97
- const s = String(text || "").trim();
106
+ const raw = String(text || "").trim();
107
+ const gregorian = /ค\.ศ\.|\d\s*(AD|CE)\b|^\s*(AD|CE)\s/i.test(raw);
108
+ let s = raw.replace(/พ\.ศ\.|ค\.ศ\./g, " ").replace(/(\d)\s*(BE|AD|CE)\b/gi, "$1 ").replace(/^\s*(BE|AD|CE)\s+/i, " ").replace(/\s+/g, " ").trim();
109
+ const eight = /^(\d{2})(\d{2})(\d{4})$/.exec(s);
110
+ if (eight) {
111
+ const a = +eight[3] >= 1e3 ? parseDate(eight[1] + "/" + eight[2] + "/" + eight[3] + (gregorian ? " \u0E04.\u0E28." : "")) : null;
112
+ if (a) return a;
113
+ s = s.slice(0, 4) + "-" + s.slice(4, 6) + "-" + s.slice(6);
114
+ }
98
115
  let m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(s), y, mo, d;
99
116
  if (m) {
100
117
  y = +m[1];
@@ -104,13 +121,13 @@ function parseDate(text) {
104
121
  d = +m[1];
105
122
  mo = +m[2];
106
123
  y = +m[3];
107
- } else if ((m = /^(\d{1,2})\s+(\S+)\s+(\d{4})$/.exec(s.replace(ERA, "").trim())) && monthIndex(m[2]) >= 0) {
124
+ } else if ((m = /^(\d{1,2})\s+(\S+)\s+(\d{4})$/.exec(s)) && monthIndex(m[2]) >= 0) {
108
125
  d = +m[1];
109
126
  mo = monthIndex(m[2]) + 1;
110
127
  y = +m[3];
111
128
  } else return null;
112
- if (y >= 2400) y -= 543;
113
- const dt = new Date(y, mo - 1, d);
129
+ if (y >= 2400 && !gregorian) y -= 543;
130
+ const dt = makeDate(y, mo - 1, d);
114
131
  return dt.getMonth() === mo - 1 && dt.getDate() === d ? toISO(dt) : null;
115
132
  }
116
133
  function todayIn(timeZone) {
@@ -149,6 +166,7 @@ function parseTime(text) {
149
166
  const m = /^(\d{1,2})(?:[:.](\d{2}))?$/.exec(s) || /^(\d{1,2})(\d{2})$/.exec(s);
150
167
  if (!m) return null;
151
168
  let hh = +m[1], mm = m[2] ? +m[2] : 0;
169
+ if ((am || pm) && (hh < 1 || hh > 12)) return null;
152
170
  if (pm && hh < 12) hh += 12;
153
171
  if (am && hh === 12) hh = 0;
154
172
  if (hh > 23 || mm > 59) return null;
@@ -244,6 +262,12 @@ var STRINGS = {
244
262
  page: function(p, total) {
245
263
  return "Page " + p + " of " + total;
246
264
  },
265
+ rangeOpen: function(a, b) {
266
+ return a + "\u2013" + b + " of many";
267
+ },
268
+ pageOpen: function(p) {
269
+ return "Page " + p;
270
+ },
247
271
  prevPage: "Previous page",
248
272
  nextPage: "Next page",
249
273
  totals: "Totals",
@@ -257,6 +281,7 @@ var STRINGS = {
257
281
  timeOutOfRange: function(a, b) {
258
282
  return "Choose a time between " + a + " and " + b;
259
283
  },
284
+ timeUnavailable: "That time isn't available. Choose another.",
260
285
  dropFiles: "Drag files here or",
261
286
  browse: "Choose files",
262
287
  browseOne: "Choose a file",
@@ -358,6 +383,12 @@ var STRINGS = {
358
383
  page: function(p, total) {
359
384
  return "\u0E2B\u0E19\u0E49\u0E32 " + p + " / " + total;
360
385
  },
386
+ rangeOpen: function(a, b) {
387
+ return a + "\u2013" + b + " \u0E08\u0E32\u0E01\u0E2B\u0E25\u0E32\u0E22\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23";
388
+ },
389
+ pageOpen: function(p) {
390
+ return "\u0E2B\u0E19\u0E49\u0E32 " + p;
391
+ },
361
392
  prevPage: "\u0E2B\u0E19\u0E49\u0E32\u0E01\u0E48\u0E2D\u0E19\u0E2B\u0E19\u0E49\u0E32",
362
393
  nextPage: "\u0E2B\u0E19\u0E49\u0E32\u0E16\u0E31\u0E14\u0E44\u0E1B",
363
394
  totals: "\u0E23\u0E27\u0E21",
@@ -371,6 +402,7 @@ var STRINGS = {
371
402
  timeOutOfRange: function(a, b) {
372
403
  return "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E40\u0E27\u0E25\u0E32\u0E23\u0E30\u0E2B\u0E27\u0E48\u0E32\u0E07 " + a + "\u2013" + b + " \u0E19.";
373
404
  },
405
+ timeUnavailable: "\u0E40\u0E27\u0E25\u0E32\u0E19\u0E35\u0E49\u0E44\u0E21\u0E48\u0E27\u0E48\u0E32\u0E07 \u0E40\u0E25\u0E37\u0E2D\u0E01\u0E40\u0E27\u0E25\u0E32\u0E2D\u0E37\u0E48\u0E19",
374
406
  dropFiles: "\u0E25\u0E32\u0E01\u0E44\u0E1F\u0E25\u0E4C\u0E21\u0E32\u0E27\u0E32\u0E07 \u0E2B\u0E23\u0E37\u0E2D",
375
407
  browse: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E1F\u0E25\u0E4C",
376
408
  browseOne: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E1F\u0E25\u0E4C",
@@ -472,6 +504,12 @@ var STRINGS = {
472
504
  page: function(p, total) {
473
505
  return "Sida " + p + " av " + total;
474
506
  },
507
+ rangeOpen: function(a, b) {
508
+ return a + "\u2013" + b + " av m\xE5nga";
509
+ },
510
+ pageOpen: function(p) {
511
+ return "Sida " + p;
512
+ },
475
513
  prevPage: "F\xF6reg\xE5ende sida",
476
514
  nextPage: "N\xE4sta sida",
477
515
  totals: "Summa",
@@ -485,6 +523,7 @@ var STRINGS = {
485
523
  timeOutOfRange: function(a, b) {
486
524
  return "V\xE4lj en tid mellan " + a + " och " + b;
487
525
  },
526
+ timeUnavailable: "Den tiden \xE4r inte ledig. V\xE4lj en annan.",
488
527
  dropFiles: "Dra filer hit eller",
489
528
  browse: "V\xE4lj filer",
490
529
  browseOne: "V\xE4lj en fil",
@@ -42,6 +42,7 @@ export type FormatDateOptions = DateDisplayOptions & {
42
42
  format?: "short" | "long" | "numeric" | Intl.DateTimeFormatOptions | undefined;
43
43
  };
44
44
  export declare function toISO(d: Date | null | undefined): ISODate | null;
45
+ /** ISO → local Date; null for text that isn't a real date ("2026-02-31" no longer rolls over into March, 5.2). */
45
46
  export declare function fromISO(s: ISODate | null | undefined): Date | null;
46
47
  /** Format an ISO date for display: "18 Sept 2026" by default (English, Gregorian — 5.0); `{ locale: 'th' }` gives
47
48
  * "18 ก.ย. 2569" (Buddhist era), `{ locale: 'sv' }` "18 sep. 2026". The same function from the package root and from
@@ -106,6 +107,9 @@ export interface AuraStrings {
106
107
  loadingRows: string;
107
108
  range: (a: number | string, b: number | string, total: number) => string;
108
109
  page: (p: number, total: number) => string;
110
+ /** Server paging without totalRows (5.2): the range and page when the total isn't known. */
111
+ rangeOpen: (a: number | string, b: number | string) => string;
112
+ pageOpen: (p: number) => string;
109
113
  prevPage: string;
110
114
  nextPage: string;
111
115
  rowCount: (c: number) => string;
@@ -115,6 +119,8 @@ export interface AuraStrings {
115
119
  timePlaceholder: string;
116
120
  timeInvalid: string;
117
121
  timeOutOfRange: (a: number | string, b: number | string) => string;
122
+ /** A time inside the range that isTimeDisabled refuses (5.2). */
123
+ timeUnavailable: string;
118
124
  dropFiles: string;
119
125
  browse: string;
120
126
  browseOne: string;
@@ -42,6 +42,7 @@ export type FormatDateOptions = DateDisplayOptions & {
42
42
  format?: "short" | "long" | "numeric" | Intl.DateTimeFormatOptions | undefined;
43
43
  };
44
44
  export declare function toISO(d: Date | null | undefined): ISODate | null;
45
+ /** ISO → local Date; null for text that isn't a real date ("2026-02-31" no longer rolls over into March, 5.2). */
45
46
  export declare function fromISO(s: ISODate | null | undefined): Date | null;
46
47
  /** Format an ISO date for display: "18 Sept 2026" by default (English, Gregorian — 5.0); `{ locale: 'th' }` gives
47
48
  * "18 ก.ย. 2569" (Buddhist era), `{ locale: 'sv' }` "18 sep. 2026". The same function from the package root and from
@@ -106,6 +107,9 @@ export interface AuraStrings {
106
107
  loadingRows: string;
107
108
  range: (a: number | string, b: number | string, total: number) => string;
108
109
  page: (p: number, total: number) => string;
110
+ /** Server paging without totalRows (5.2): the range and page when the total isn't known. */
111
+ rangeOpen: (a: number | string, b: number | string) => string;
112
+ pageOpen: (p: number) => string;
109
113
  prevPage: string;
110
114
  nextPage: string;
111
115
  rowCount: (c: number) => string;
@@ -115,6 +119,8 @@ export interface AuraStrings {
115
119
  timePlaceholder: string;
116
120
  timeInvalid: string;
117
121
  timeOutOfRange: (a: number | string, b: number | string) => string;
122
+ /** A time inside the range that isTimeDisabled refuses (5.2). */
123
+ timeUnavailable: string;
118
124
  dropFiles: string;
119
125
  browse: string;
120
126
  browseOne: string;
@@ -4,12 +4,21 @@ var pad = function(n2) {
4
4
  return (n2 < 10 ? "0" : "") + n2;
5
5
  };
6
6
  function toISO(d) {
7
- return d ? d.getFullYear() + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate()) : null;
7
+ if (!d) return null;
8
+ const y = String(d.getFullYear());
9
+ return ("000" + y).slice(-Math.max(4, y.length)) + "-" + pad(d.getMonth() + 1) + "-" + pad(d.getDate());
10
+ }
11
+ function makeDate(y, monthIndex2, day) {
12
+ const d = new Date(2e3, 0, 1);
13
+ d.setFullYear(y, monthIndex2, day);
14
+ return d;
8
15
  }
9
16
  function fromISO(s) {
10
17
  if (!s) return null;
11
18
  const m = /^(\d{4})-(\d{2})-(\d{2})$/.exec(s);
12
- return m ? new Date(+m[1], +m[2] - 1, +m[3]) : null;
19
+ if (!m) return null;
20
+ const d = makeDate(+m[1], +m[2] - 1, +m[3]);
21
+ return d.getMonth() === +m[2] - 1 && d.getDate() === +m[3] ? d : null;
13
22
  }
14
23
  var TAGS = { th: "th-TH", en: "en-GB", sv: "sv-SE" };
15
24
  function defaultCalendar(locale) {
@@ -55,7 +64,15 @@ function monthIndex(word) {
55
64
  return MONTHS[k] != null ? MONTHS[k] : -1;
56
65
  }
57
66
  function parseDate(text) {
58
- const s = String(text || "").trim();
67
+ const raw = String(text || "").trim();
68
+ const gregorian = /ค\.ศ\.|\d\s*(AD|CE)\b|^\s*(AD|CE)\s/i.test(raw);
69
+ let s = raw.replace(/พ\.ศ\.|ค\.ศ\./g, " ").replace(/(\d)\s*(BE|AD|CE)\b/gi, "$1 ").replace(/^\s*(BE|AD|CE)\s+/i, " ").replace(/\s+/g, " ").trim();
70
+ const eight = /^(\d{2})(\d{2})(\d{4})$/.exec(s);
71
+ if (eight) {
72
+ const a = +eight[3] >= 1e3 ? parseDate(eight[1] + "/" + eight[2] + "/" + eight[3] + (gregorian ? " \u0E04.\u0E28." : "")) : null;
73
+ if (a) return a;
74
+ s = s.slice(0, 4) + "-" + s.slice(4, 6) + "-" + s.slice(6);
75
+ }
59
76
  let m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(s), y, mo, d;
60
77
  if (m) {
61
78
  y = +m[1];
@@ -65,13 +82,13 @@ function parseDate(text) {
65
82
  d = +m[1];
66
83
  mo = +m[2];
67
84
  y = +m[3];
68
- } else if ((m = /^(\d{1,2})\s+(\S+)\s+(\d{4})$/.exec(s.replace(ERA, "").trim())) && monthIndex(m[2]) >= 0) {
85
+ } else if ((m = /^(\d{1,2})\s+(\S+)\s+(\d{4})$/.exec(s)) && monthIndex(m[2]) >= 0) {
69
86
  d = +m[1];
70
87
  mo = monthIndex(m[2]) + 1;
71
88
  y = +m[3];
72
89
  } else return null;
73
- if (y >= 2400) y -= 543;
74
- const dt = new Date(y, mo - 1, d);
90
+ if (y >= 2400 && !gregorian) y -= 543;
91
+ const dt = makeDate(y, mo - 1, d);
75
92
  return dt.getMonth() === mo - 1 && dt.getDate() === d ? toISO(dt) : null;
76
93
  }
77
94
  function todayIn(timeZone) {
@@ -110,6 +127,7 @@ function parseTime(text) {
110
127
  const m = /^(\d{1,2})(?:[:.](\d{2}))?$/.exec(s) || /^(\d{1,2})(\d{2})$/.exec(s);
111
128
  if (!m) return null;
112
129
  let hh = +m[1], mm = m[2] ? +m[2] : 0;
130
+ if ((am || pm) && (hh < 1 || hh > 12)) return null;
113
131
  if (pm && hh < 12) hh += 12;
114
132
  if (am && hh === 12) hh = 0;
115
133
  if (hh > 23 || mm > 59) return null;
@@ -205,6 +223,12 @@ var STRINGS = {
205
223
  page: function(p, total) {
206
224
  return "Page " + p + " of " + total;
207
225
  },
226
+ rangeOpen: function(a, b) {
227
+ return a + "\u2013" + b + " of many";
228
+ },
229
+ pageOpen: function(p) {
230
+ return "Page " + p;
231
+ },
208
232
  prevPage: "Previous page",
209
233
  nextPage: "Next page",
210
234
  totals: "Totals",
@@ -218,6 +242,7 @@ var STRINGS = {
218
242
  timeOutOfRange: function(a, b) {
219
243
  return "Choose a time between " + a + " and " + b;
220
244
  },
245
+ timeUnavailable: "That time isn't available. Choose another.",
221
246
  dropFiles: "Drag files here or",
222
247
  browse: "Choose files",
223
248
  browseOne: "Choose a file",
@@ -319,6 +344,12 @@ var STRINGS = {
319
344
  page: function(p, total) {
320
345
  return "\u0E2B\u0E19\u0E49\u0E32 " + p + " / " + total;
321
346
  },
347
+ rangeOpen: function(a, b) {
348
+ return a + "\u2013" + b + " \u0E08\u0E32\u0E01\u0E2B\u0E25\u0E32\u0E22\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23";
349
+ },
350
+ pageOpen: function(p) {
351
+ return "\u0E2B\u0E19\u0E49\u0E32 " + p;
352
+ },
322
353
  prevPage: "\u0E2B\u0E19\u0E49\u0E32\u0E01\u0E48\u0E2D\u0E19\u0E2B\u0E19\u0E49\u0E32",
323
354
  nextPage: "\u0E2B\u0E19\u0E49\u0E32\u0E16\u0E31\u0E14\u0E44\u0E1B",
324
355
  totals: "\u0E23\u0E27\u0E21",
@@ -332,6 +363,7 @@ var STRINGS = {
332
363
  timeOutOfRange: function(a, b) {
333
364
  return "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E40\u0E27\u0E25\u0E32\u0E23\u0E30\u0E2B\u0E27\u0E48\u0E32\u0E07 " + a + "\u2013" + b + " \u0E19.";
334
365
  },
366
+ timeUnavailable: "\u0E40\u0E27\u0E25\u0E32\u0E19\u0E35\u0E49\u0E44\u0E21\u0E48\u0E27\u0E48\u0E32\u0E07 \u0E40\u0E25\u0E37\u0E2D\u0E01\u0E40\u0E27\u0E25\u0E32\u0E2D\u0E37\u0E48\u0E19",
335
367
  dropFiles: "\u0E25\u0E32\u0E01\u0E44\u0E1F\u0E25\u0E4C\u0E21\u0E32\u0E27\u0E32\u0E07 \u0E2B\u0E23\u0E37\u0E2D",
336
368
  browse: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E1F\u0E25\u0E4C",
337
369
  browseOne: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E1F\u0E25\u0E4C",
@@ -433,6 +465,12 @@ var STRINGS = {
433
465
  page: function(p, total) {
434
466
  return "Sida " + p + " av " + total;
435
467
  },
468
+ rangeOpen: function(a, b) {
469
+ return a + "\u2013" + b + " av m\xE5nga";
470
+ },
471
+ pageOpen: function(p) {
472
+ return "Sida " + p;
473
+ },
436
474
  prevPage: "F\xF6reg\xE5ende sida",
437
475
  nextPage: "N\xE4sta sida",
438
476
  totals: "Summa",
@@ -446,6 +484,7 @@ var STRINGS = {
446
484
  timeOutOfRange: function(a, b) {
447
485
  return "V\xE4lj en tid mellan " + a + " och " + b;
448
486
  },
487
+ timeUnavailable: "Den tiden \xE4r inte ledig. V\xE4lj en annan.",
449
488
  dropFiles: "Dra filer hit eller",
450
489
  browse: "V\xE4lj filer",
451
490
  browseOne: "V\xE4lj en fil",
package/dist/styles.css CHANGED
@@ -424,7 +424,16 @@ a.aura-icon-btn { text-decoration: none; }
424
424
  .aura-select .aura-input__control { padding-right: calc(var(--aura-space-3) + var(--aura-icon-sm) + var(--aura-space-2)); cursor: pointer; }
425
425
  .aura-select__chevron { position: absolute; right: var(--aura-space-3); color: var(--aura-fg-secondary); pointer-events: none; }
426
426
  .aura-select select:invalid, .aura-select select:has(option[value=""]:checked) { color: var(--aura-fg-tertiary); }
427
+ /* 5.3: the field is a button over an invisible <select> (forms, refs, events); the list is AURA's, like Combobox. */
427
428
  .aura-select option { color: var(--aura-fg-primary); background: var(--aura-bg-input); }
429
+ .aura-select--custom { position: relative; }
430
+ .aura-select__native { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; opacity: 0; pointer-events: none; appearance: none; }
431
+ .aura-select__trigger { display: flex; align-items: center; text-align: start; background: none; border: 0; color: inherit; font: inherit; width: 100%; min-width: 0; }
432
+ .aura-select__trigger:disabled { cursor: not-allowed; }
433
+ .aura-select__value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
434
+ .aura-select__value.is-placeholder { color: var(--aura-fg-tertiary); }
435
+ .aura-select__group { padding: var(--aura-space-2) var(--aura-space-2) var(--aura-space-1); font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--aura-fg-tertiary); }
436
+ .aura-select.is-open .aura-select__chevron { transform: rotate(180deg); }
428
437
 
429
438
  .aura-radio-group > legend { margin-bottom: 6px; }
430
439
  .aura-radio-group__list { display: flex; flex-direction: column; gap: var(--aura-space-3); }
@@ -679,6 +688,8 @@ a.aura-tab { text-decoration: none; }
679
688
  .aura-avatar__status {
680
689
  position: absolute; right: -1px; bottom: -1px; width: 30%; height: 30%; min-width: 8px; min-height: 8px;
681
690
  border-radius: var(--aura-radius-full); background: var(--aura-accent-dot); box-shadow: 0 0 0 2px var(--aura-bg-surface);
691
+ /* 5.2: the lime fill is 1.2:1 on the white ring; the edge carries the 3:1 (WCAG 1.4.11). */
692
+ border: 1.5px solid var(--aura-fg-positive); box-sizing: border-box;
682
693
  }
683
694
 
684
695
  /* ---------- Combobox ---------- */
@@ -921,6 +932,8 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
921
932
  .aura-upload__thumb.is-icon { display: inline-flex; align-items: center; justify-content: center; color: var(--aura-fg-secondary); }
922
933
  .aura-upload__meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
923
934
  .aura-upload__name { font-size: 13px; font-weight: 500; color: var(--aura-fg-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
935
+ a.aura-upload__name { color: var(--aura-fg-accent); text-decoration: underline; text-underline-offset: 2px; border-radius: var(--aura-radius-xs); }
936
+ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
924
937
  .aura-upload__sub { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--aura-fg-secondary); }
925
938
  .aura-upload__item.is-error .aura-upload__sub { color: var(--aura-fg-danger); }
926
939
  .aura-upload__bar { display: block; height: 4px; border-radius: var(--aura-radius-full); background: var(--aura-progress-track); box-shadow: inset 0 0 0 1px var(--aura-progress-track-edge); overflow: hidden; }
@@ -1042,8 +1055,9 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
1042
1055
  position: fixed; z-index: var(--aura-z-menu); box-sizing: border-box; width: max-content; min-width: 200px; max-width: min(360px, calc(100vw - 16px));
1043
1056
  background: var(--aura-bg-surface); color: var(--aura-fg-primary); border: 1px solid var(--aura-border-default); border-radius: var(--aura-radius-lg);
1044
1057
  box-shadow: var(--aura-shadow-overlay); font-family: var(--font-sans); font-size: 14px; outline: none; animation: aura-fade-in var(--aura-duration-fast) var(--aura-ease);
1058
+ overflow-y: auto; overscroll-behavior: contain;
1045
1059
  }
1046
- .aura-popover__head { display: flex; align-items: center; justify-content: space-between; gap: var(--aura-space-2); padding: var(--aura-space-2) var(--aura-space-2) 0 var(--aura-space-4); }
1060
+ .aura-popover__head { display: flex; align-items: center; justify-content: space-between; gap: var(--aura-space-2); padding: var(--aura-space-2) var(--aura-space-2) 0 var(--aura-space-4); position: sticky; top: 0; z-index: 1; background: var(--aura-bg-surface); } /* 5.2: stays while a tall popover scrolls */
1047
1061
  .aura-popover__title { margin: 0; font-size: 14px; font-weight: 600; }
1048
1062
  .aura-popover__body { padding: var(--aura-space-4); }
1049
1063
  .aura-popover__head + .aura-popover__body { padding-top: var(--aura-space-2); }
@@ -1143,7 +1157,7 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1143
1157
  .aura-segmented.is-full .aura-segmented__option { flex: 1 1 0; min-width: 0; }
1144
1158
  .aura-segmented__option.is-icon { padding: 0; width: 36px; }
1145
1159
  .aura-segmented__option:hover:not(:disabled):not(.is-selected) { color: var(--aura-fg-primary); }
1146
- .aura-segmented__option.is-selected { background: var(--aura-bg-surface); color: var(--aura-fg-primary); box-shadow: var(--aura-shadow-enterprise); }
1160
+ .aura-segmented__option.is-selected { background: var(--aura-bg-surface); color: var(--aura-fg-primary); box-shadow: inset 0 0 0 1px var(--aura-border-control), var(--aura-shadow-enterprise); } /* 5.2: the edge marks the choice at 3:1; the fill alone was 1.04:1 on the track */
1147
1161
  .aura-segmented__option:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 1px; }
1148
1162
  .aura-segmented__option:disabled { opacity: var(--aura-disabled-opacity); cursor: default; }
1149
1163
  .aura-segmented--sm .aura-segmented__option { height: 24px; padding: 0 var(--aura-space-3); font-size: 12px; }
@@ -426,7 +426,16 @@ a.aura-icon-btn { text-decoration: none; }
426
426
  .aura-select .aura-input__control { padding-right: calc(var(--aura-space-3) + var(--aura-icon-sm) + var(--aura-space-2)); cursor: pointer; }
427
427
  .aura-select__chevron { position: absolute; right: var(--aura-space-3); color: var(--aura-fg-secondary); pointer-events: none; }
428
428
  .aura-select select:invalid, .aura-select select:has(option[value=""]:checked) { color: var(--aura-fg-tertiary); }
429
+ /* 5.3: the field is a button over an invisible <select> (forms, refs, events); the list is AURA's, like Combobox. */
429
430
  .aura-select option { color: var(--aura-fg-primary); background: var(--aura-bg-input); }
431
+ .aura-select--custom { position: relative; }
432
+ .aura-select__native { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; border: 0; opacity: 0; pointer-events: none; appearance: none; }
433
+ .aura-select__trigger { display: flex; align-items: center; text-align: start; background: none; border: 0; color: inherit; font: inherit; width: 100%; min-width: 0; }
434
+ .aura-select__trigger:disabled { cursor: not-allowed; }
435
+ .aura-select__value { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
436
+ .aura-select__value.is-placeholder { color: var(--aura-fg-tertiary); }
437
+ .aura-select__group { padding: var(--aura-space-2) var(--aura-space-2) var(--aura-space-1); font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: 0.04em; color: var(--aura-fg-tertiary); }
438
+ .aura-select.is-open .aura-select__chevron { transform: rotate(180deg); }
430
439
 
431
440
  .aura-radio-group > legend { margin-bottom: 6px; }
432
441
  .aura-radio-group__list { display: flex; flex-direction: column; gap: var(--aura-space-3); }
@@ -681,6 +690,8 @@ a.aura-tab { text-decoration: none; }
681
690
  .aura-avatar__status {
682
691
  position: absolute; right: -1px; bottom: -1px; width: 30%; height: 30%; min-width: 8px; min-height: 8px;
683
692
  border-radius: var(--aura-radius-full); background: var(--aura-accent-dot); box-shadow: 0 0 0 2px var(--aura-bg-surface);
693
+ /* 5.2: the lime fill is 1.2:1 on the white ring; the edge carries the 3:1 (WCAG 1.4.11). */
694
+ border: 1.5px solid var(--aura-fg-positive); box-sizing: border-box;
684
695
  }
685
696
 
686
697
  /* ---------- Combobox ---------- */
@@ -923,6 +934,8 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
923
934
  .aura-upload__thumb.is-icon { display: inline-flex; align-items: center; justify-content: center; color: var(--aura-fg-secondary); }
924
935
  .aura-upload__meta { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
925
936
  .aura-upload__name { font-size: 13px; font-weight: 500; color: var(--aura-fg-primary); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
937
+ a.aura-upload__name { color: var(--aura-fg-accent); text-decoration: underline; text-underline-offset: 2px; border-radius: var(--aura-radius-xs); }
938
+ a.aura-upload__name:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 2px; }
926
939
  .aura-upload__sub { display: inline-flex; align-items: center; gap: 4px; font-size: 12px; color: var(--aura-fg-secondary); }
927
940
  .aura-upload__item.is-error .aura-upload__sub { color: var(--aura-fg-danger); }
928
941
  .aura-upload__bar { display: block; height: 4px; border-radius: var(--aura-radius-full); background: var(--aura-progress-track); box-shadow: inset 0 0 0 1px var(--aura-progress-track-edge); overflow: hidden; }
@@ -1044,8 +1057,9 @@ button.aura-stat { font: inherit; width: 100%; cursor: pointer; }
1044
1057
  position: fixed; z-index: var(--aura-z-menu); box-sizing: border-box; width: max-content; min-width: 200px; max-width: min(360px, calc(100vw - 16px));
1045
1058
  background: var(--aura-bg-surface); color: var(--aura-fg-primary); border: 1px solid var(--aura-border-default); border-radius: var(--aura-radius-lg);
1046
1059
  box-shadow: var(--aura-shadow-overlay); font-family: var(--font-sans); font-size: 14px; outline: none; animation: aura-fade-in var(--aura-duration-fast) var(--aura-ease);
1060
+ overflow-y: auto; overscroll-behavior: contain;
1047
1061
  }
1048
- .aura-popover__head { display: flex; align-items: center; justify-content: space-between; gap: var(--aura-space-2); padding: var(--aura-space-2) var(--aura-space-2) 0 var(--aura-space-4); }
1062
+ .aura-popover__head { display: flex; align-items: center; justify-content: space-between; gap: var(--aura-space-2); padding: var(--aura-space-2) var(--aura-space-2) 0 var(--aura-space-4); position: sticky; top: 0; z-index: 1; background: var(--aura-bg-surface); } /* 5.2: stays while a tall popover scrolls */
1049
1063
  .aura-popover__title { margin: 0; font-size: 14px; font-weight: 600; }
1050
1064
  .aura-popover__body { padding: var(--aura-space-4); }
1051
1065
  .aura-popover__head + .aura-popover__body { padding-top: var(--aura-space-2); }
@@ -1145,7 +1159,7 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
1145
1159
  .aura-segmented.is-full .aura-segmented__option { flex: 1 1 0; min-width: 0; }
1146
1160
  .aura-segmented__option.is-icon { padding: 0; width: 36px; }
1147
1161
  .aura-segmented__option:hover:not(:disabled):not(.is-selected) { color: var(--aura-fg-primary); }
1148
- .aura-segmented__option.is-selected { background: var(--aura-bg-surface); color: var(--aura-fg-primary); box-shadow: var(--aura-shadow-enterprise); }
1162
+ .aura-segmented__option.is-selected { background: var(--aura-bg-surface); color: var(--aura-fg-primary); box-shadow: inset 0 0 0 1px var(--aura-border-control), var(--aura-shadow-enterprise); } /* 5.2: the edge marks the choice at 3:1; the fill alone was 1.04:1 on the track */
1149
1163
  .aura-segmented__option:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: 1px; }
1150
1164
  .aura-segmented__option:disabled { opacity: var(--aura-disabled-opacity); cursor: default; }
1151
1165
  .aura-segmented--sm .aura-segmented__option { height: 24px; padding: 0 var(--aura-space-3); font-size: 12px; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jirawatpyk/aura-react",
3
- "version": "5.1.1",
3
+ "version": "5.3.0",
4
4
  "description": "AURA Design System — React components (Enterprise Standard, Human Creative). Thai-first: Buddhist-era dates, Thai collation.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -5,17 +5,42 @@
5
5
  import fs from 'node:fs';
6
6
  import { createTheme } from '../dist/esm/theme.js';
7
7
 
8
+ const USAGE = 'Usage: aura-theme --brand "#0ea5e9" [--signal "#facc15"] [--primary ink|brand] [--name acme] [--selector .tenant] [--out theme.css]';
9
+ const KNOWN = ['brand', 'signal', 'primary', 'name', 'selector', 'out', 'help'];
10
+ function fail(msg) {
11
+ console.error('aura-theme: ' + msg + '\n' + USAGE);
12
+ process.exit(2);
13
+ }
14
+ /* --key value and --key=value (5.2); a value-taking option with no value is an error, not `true`. */
8
15
  const args = {};
9
16
  for (let i = 2; i < process.argv.length; i++) {
10
17
  const a = process.argv[i];
11
- if (a.startsWith('--')) { const k = a.slice(2); const v = process.argv[i + 1] && !process.argv[i + 1].startsWith('--') ? process.argv[++i] : true; args[k] = v; }
18
+ if (!a.startsWith('--')) fail('unexpected "' + a + '"');
19
+ const eq = a.indexOf('=');
20
+ const k = eq > 0 ? a.slice(2, eq) : a.slice(2);
21
+ if (KNOWN.indexOf(k) < 0) fail('unknown option --' + k);
22
+ if (k === 'help') { args.help = true; continue; }
23
+ const v = eq > 0 ? a.slice(eq + 1) : process.argv[i + 1] !== undefined && !process.argv[i + 1].startsWith('--') ? process.argv[++i] : undefined;
24
+ if (v === undefined || v === '') fail('--' + k + ' needs a value');
25
+ args[k] = v;
26
+ }
27
+ if (args.help) {
28
+ console.log(USAGE);
29
+ process.exit(0);
30
+ }
31
+ if (!args.brand) fail('--brand is required');
32
+ for (const k of ['brand', 'signal']) {
33
+ if (args[k] !== undefined && /^(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(args[k])) args[k] = '#' + args[k]; /* a shell ate the # */
34
+ if (args[k] !== undefined && !/^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i.test(args[k])) fail('--' + k + ' must be a #rgb or #rrggbb colour (got "' + args[k] + '"; quote it in the shell: --' + k + ' "#0ea5e9")');
12
35
  }
13
- if (!args.brand || args.help) {
14
- console.log('Usage: aura-theme --brand "#0ea5e9" [--signal "#facc15"] [--primary ink|brand] [--name acme] [--selector .tenant] [--out theme.css]');
15
- process.exit(args.help ? 0 : 1);
36
+ if (args.primary !== undefined && args.primary !== 'ink' && args.primary !== 'brand') fail('--primary is ink or brand');
37
+ let t, css;
38
+ try {
39
+ t = createTheme({ brand: args.brand, signal: args.signal, primary: args.primary, name: args.name });
40
+ css = t.css(args.selector);
41
+ } catch (e) {
42
+ fail(e.message);
16
43
  }
17
- const t = createTheme({ brand: args.brand, signal: args.signal, primary: args.primary, name: args.name });
18
- const css = t.css(args.selector);
19
44
  if (args.out) fs.writeFileSync(args.out, css); else process.stdout.write(css);
20
45
  const log = args.out ? console.log : console.error;
21
46
  log(`\nContrast checks (${t.checks.filter((c) => c.pass).length}/${t.checks.length} pass):`);