@jirawatpyk/aura-react 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +10 -0
  2. package/dist/aura.bundle.js +562 -183
  3. package/dist/cjs/index.cjs +562 -183
  4. package/dist/esm/AppShell.js +10 -2
  5. package/dist/esm/Avatar.js +4 -3
  6. package/dist/esm/BottomNav.js +2 -1
  7. package/dist/esm/Checkbox.js +3 -2
  8. package/dist/esm/Combobox.js +19 -19
  9. package/dist/esm/Command.js +1 -0
  10. package/dist/esm/DataTable.js +116 -29
  11. package/dist/esm/DatePicker.js +85 -22
  12. package/dist/esm/DropdownMenu.js +12 -0
  13. package/dist/esm/FileUpload.js +17 -1
  14. package/dist/esm/FormErrorSummary.js +19 -4
  15. package/dist/esm/Menu.js +20 -7
  16. package/dist/esm/NumberField.js +3 -1
  17. package/dist/esm/Pagination.js +3 -3
  18. package/dist/esm/Popover.js +26 -5
  19. package/dist/esm/RadioGroup.js +14 -1
  20. package/dist/esm/SideNav.js +2 -1
  21. package/dist/esm/Switch.js +1 -1
  22. package/dist/esm/Table.js +3 -2
  23. package/dist/esm/Tabs.js +11 -7
  24. package/dist/esm/TextField.js +2 -2
  25. package/dist/esm/Textarea.js +2 -2
  26. package/dist/esm/ThemeStyle.js +13 -3
  27. package/dist/esm/TimePicker.js +2 -1
  28. package/dist/esm/Toaster.js +1 -0
  29. package/dist/esm/Tooltip.js +54 -29
  30. package/dist/esm/colorScheme.js +7 -3
  31. package/dist/esm/colorSchemeScript.js +3 -3
  32. package/dist/esm/dates.js +34 -13
  33. package/dist/esm/internal.js +18 -7
  34. package/dist/esm/locale.js +6 -5
  35. package/dist/esm/strings.js +21 -0
  36. package/dist/esm/text.js +1 -0
  37. package/dist/esm/theme.js +3 -1
  38. package/dist/esm/useModal.js +31 -8
  39. package/dist/index.d.cts +1513 -0
  40. package/dist/index.d.ts +6 -1
  41. package/dist/server/index.cjs +51 -10
  42. package/dist/server/index.d.cts +182 -0
  43. package/dist/server/index.d.ts +6 -0
  44. package/dist/server/index.js +51 -10
  45. package/dist/styles.css +26 -5
  46. package/dist/styles.layer.css +26 -5
  47. package/package.json +19 -8
  48. package/scripts/aura-theme.mjs +31 -6
@@ -27,8 +27,8 @@ const Textarea = React.forwardRef(function Textarea2(props, ref) {
27
27
  className: "aura-input aura-textarea",
28
28
  placeholder: props.placeholder,
29
29
  required: props.required,
30
- "aria-invalid": props.error ? true : void 0,
31
- "aria-describedby": describedBy(id, props)
30
+ "aria-invalid": props.error ? true : rest["aria-invalid"],
31
+ "aria-describedby": [describedBy(id, props), rest["aria-describedby"]].filter(Boolean).join(" ") || void 0
32
32
  }
33
33
  )
34
34
  );
@@ -1,15 +1,25 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
3
  import { createTheme } from "./theme.js";
4
+ import { devWarnOnce } from "./internal.js";
4
5
  function ThemeStyle(props) {
5
6
  const css = React.useMemo(
6
7
  function() {
7
- return createTheme({ brand: props.brand, signal: props.signal, primary: props.primary, name: props.name }).css(
8
- props.selector
9
- );
8
+ try {
9
+ return createTheme({
10
+ brand: props.brand,
11
+ signal: props.signal,
12
+ primary: props.primary,
13
+ name: props.name
14
+ }).css(props.selector);
15
+ } catch (e) {
16
+ devWarnOnce("theme-style", "ThemeStyle ignored: " + e.message);
17
+ return null;
18
+ }
10
19
  },
11
20
  [props.brand, props.signal, props.primary, props.name, props.selector]
12
21
  );
22
+ if (css === null) return null;
13
23
  return /* @__PURE__ */ React.createElement("style", { "data-aura-theme": props.name || props.brand, dangerouslySetInnerHTML: { __html: css } });
14
24
  }
15
25
  export {
@@ -113,7 +113,8 @@ const TimePicker = React.forwardRef(function TimePicker2(props, ref) {
113
113
  return true;
114
114
  }
115
115
  if (blocked(v)) {
116
- errState[1](t.timeOutOfRange(fromMin(lo), fromMin(hi)));
116
+ const n = toMin(v);
117
+ errState[1](n != null && n >= lo && n <= hi ? t.timeUnavailable : t.timeOutOfRange(fromMin(lo), fromMin(hi)));
117
118
  return false;
118
119
  }
119
120
  errState[1](null);
@@ -158,6 +158,7 @@ function Toaster(props) {
158
158
  const s = React.useState(toastState.list);
159
159
  React.useEffect(function() {
160
160
  toastState.subs.push(s[1]);
161
+ s[1](toastState.list.slice());
161
162
  return function() {
162
163
  toastState.subs = toastState.subs.filter(function(f) {
163
164
  return f !== s[1];
@@ -1,11 +1,11 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
- import { uid, useIsoLayoutEffect, useMergedRef } from "./internal.js";
3
+ import { uid, useIsoLayoutEffect, useMergedRef, useMounted } from "./internal.js";
4
4
  import { createPortal } from "react-dom";
5
5
  const Tooltip = React.forwardRef(function Tooltip2(props, ref) {
6
6
  const id = uid(), st = React.useState(false), open = props.open !== void 0 ? props.open : st[0], set = st[1];
7
7
  const anchor = React.useRef(null), anchorMerged = useMergedRef(ref, anchor), tip = React.useRef(null), timer = React.useRef(void 0);
8
- const pos = React.useState(null);
8
+ const pos = React.useState(null), mounted = useMounted();
9
9
  function show(now) {
10
10
  clearTimeout(timer.current);
11
11
  timer.current = setTimeout(
@@ -19,34 +19,55 @@ const Tooltip = React.forwardRef(function Tooltip2(props, ref) {
19
19
  clearTimeout(timer.current);
20
20
  set(false);
21
21
  }
22
+ function hideSoon() {
23
+ clearTimeout(timer.current);
24
+ timer.current = setTimeout(function() {
25
+ set(false);
26
+ }, 120);
27
+ }
28
+ React.useEffect(function() {
29
+ return function() {
30
+ clearTimeout(timer.current);
31
+ };
32
+ }, []);
33
+ function place() {
34
+ if (!anchor.current || !tip.current) return;
35
+ const r = anchor.current.getBoundingClientRect(), t = tip.current.getBoundingClientRect();
36
+ const vw = window.innerWidth, vh = window.innerHeight, gap = 8, m = 8;
37
+ let side = props.side || "top";
38
+ if (side === "top" && r.top - t.height - gap < m && r.bottom + gap + t.height <= vh - m) side = "bottom";
39
+ else if (side === "bottom" && r.bottom + gap + t.height > vh - m && r.top - t.height - gap >= m) side = "top";
40
+ else if (side === "left" && r.left - t.width - gap < m && r.right + gap + t.width <= vw - m) side = "right";
41
+ else if (side === "right" && r.right + gap + t.width > vw - m && r.left - t.width - gap >= m) side = "left";
42
+ const clampX = function(x) {
43
+ return Math.max(m, Math.min(x, vw - t.width - m));
44
+ };
45
+ const clampY = function(y) {
46
+ return Math.max(m, Math.min(y, vh - t.height - m));
47
+ };
48
+ let top, left;
49
+ if (side === "top" || side === "bottom") {
50
+ top = clampY(side === "top" ? r.top - t.height - gap : r.bottom + gap);
51
+ left = clampX(r.left + r.width / 2 - t.width / 2);
52
+ } else {
53
+ left = side === "left" ? r.left - t.width - gap : r.right + gap;
54
+ left = clampX(left);
55
+ top = clampY(r.top + r.height / 2 - t.height / 2);
56
+ }
57
+ pos[1]({ top, left });
58
+ }
22
59
  useIsoLayoutEffect(
23
60
  function() {
24
- if (!open || !anchor.current || !tip.current) return;
25
- const r = anchor.current.getBoundingClientRect(), t = tip.current.getBoundingClientRect();
26
- const vw = window.innerWidth, vh = window.innerHeight, gap = 8, m = 8;
27
- let side = props.side || "top";
28
- if (side === "top" && r.top - t.height - gap < m && r.bottom + gap + t.height <= vh - m) side = "bottom";
29
- else if (side === "bottom" && r.bottom + gap + t.height > vh - m && r.top - t.height - gap >= m) side = "top";
30
- else if (side === "left" && r.left - t.width - gap < m && r.right + gap + t.width <= vw - m) side = "right";
31
- else if (side === "right" && r.right + gap + t.width > vw - m && r.left - t.width - gap >= m) side = "left";
32
- const clampX = function(x) {
33
- return Math.max(m, Math.min(x, vw - t.width - m));
34
- };
35
- const clampY = function(y) {
36
- return Math.max(m, Math.min(y, vh - t.height - m));
61
+ if (!open) return;
62
+ place();
63
+ window.addEventListener("scroll", place, true);
64
+ window.addEventListener("resize", place);
65
+ return function() {
66
+ window.removeEventListener("scroll", place, true);
67
+ window.removeEventListener("resize", place);
37
68
  };
38
- let top, left;
39
- if (side === "top" || side === "bottom") {
40
- top = clampY(side === "top" ? r.top - t.height - gap : r.bottom + gap);
41
- left = clampX(r.left + r.width / 2 - t.width / 2);
42
- } else {
43
- left = side === "left" ? r.left - t.width - gap : r.right + gap;
44
- left = clampX(left);
45
- top = clampY(r.top + r.height / 2 - t.height / 2);
46
- }
47
- pos[1]({ top, left });
48
69
  },
49
- [open]
70
+ [open, mounted]
50
71
  );
51
72
  React.useEffect(
52
73
  function() {
@@ -70,7 +91,7 @@ const Tooltip = React.forwardRef(function Tooltip2(props, ref) {
70
91
  onMouseEnter: function() {
71
92
  show(false);
72
93
  },
73
- onMouseLeave: hide,
94
+ onMouseLeave: hideSoon,
74
95
  onFocus: function() {
75
96
  show(true);
76
97
  },
@@ -78,14 +99,18 @@ const Tooltip = React.forwardRef(function Tooltip2(props, ref) {
78
99
  },
79
100
  React.cloneElement(child, { "aria-describedby": open ? id : child.props["aria-describedby"] })
80
101
  );
81
- return /* @__PURE__ */ React.createElement(React.Fragment, null, trigger, open ? createPortal(
102
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, trigger, open && mounted ? createPortal(
82
103
  /* @__PURE__ */ React.createElement(
83
104
  "div",
84
105
  {
85
106
  ref: tip,
86
107
  id,
87
108
  role: "tooltip",
88
- className: "aura-tooltip",
109
+ onMouseEnter: function() {
110
+ clearTimeout(timer.current);
111
+ },
112
+ onMouseLeave: hideSoon,
113
+ className: "aura-tooltip aura-tooltip--hoverable",
89
114
  style: { top: pos[0] ? pos[0].top : -9999, left: pos[0] ? pos[0].left : -9999 }
90
115
  },
91
116
  props.content
@@ -37,16 +37,20 @@ function useColorScheme(options) {
37
37
  if (readScheme(fallback) === "system") apply("system");
38
38
  cb();
39
39
  }
40
+ function onStorage(e) {
41
+ if (e.key === key) apply(valid(e.newValue) ? e.newValue : fallback);
42
+ cb();
43
+ }
40
44
  if (mq) mq.addEventListener("change", onSystem);
41
45
  window.addEventListener(EVENT, cb);
42
- window.addEventListener("storage", cb);
46
+ window.addEventListener("storage", onStorage);
43
47
  return function() {
44
48
  if (mq) mq.removeEventListener("change", onSystem);
45
49
  window.removeEventListener(EVENT, cb);
46
- window.removeEventListener("storage", cb);
50
+ window.removeEventListener("storage", onStorage);
47
51
  };
48
52
  },
49
- [fallback]
53
+ [fallback, key]
50
54
  );
51
55
  const snapshot = React.useSyncExternalStore(
52
56
  subscribe,
@@ -6,9 +6,9 @@ function valid(v) {
6
6
  return typeof v === "string" && SCHEMES.indexOf(v) >= 0;
7
7
  }
8
8
  function colorSchemeScript(options) {
9
- const key = JSON.stringify(options && options.storageKey || DEFAULT_KEY);
10
- const fallback = JSON.stringify(options && options.defaultScheme || "system");
11
- return "(function(){try{var s=localStorage.getItem(" + key + ");if(s!=='light'&&s!=='dark'&&s!=='system')s=" + fallback + `;var d=document.documentElement;d.setAttribute("data-theme",s);var dark=s==='dark'||(s==='system'&&window.matchMedia('(prefers-color-scheme: dark)').matches);d.classList.toggle("dark",dark);}catch(e){}})();`;
9
+ const key = JSON.stringify(options && options.storageKey || DEFAULT_KEY).replace(/</g, "\\u003c");
10
+ const fallback = JSON.stringify(options && options.defaultScheme || "system").replace(/</g, "\\u003c");
11
+ return "(function(){try{var s=localStorage.getItem(" + key + ");if(s!=='light'&&s!=='dark'&&s!=='system')s=" + fallback + `;var d=document.documentElement;d.setAttribute("data-theme",s);var m=window.matchMedia('(prefers-color-scheme: dark)');d.classList.toggle('dark',s==='dark'||(s==='system'&&m.matches));if(m.addEventListener)m.addEventListener('change',function(e){if(d.getAttribute('data-theme')==='system')d.classList.toggle('dark',e.matches)});}catch(e){}})();`;
12
12
  }
13
13
  export {
14
14
  DEFAULT_KEY,
package/dist/esm/dates.js CHANGED
@@ -4,20 +4,29 @@ const pad = function(n) {
4
4
  return (n < 10 ? "0" : "") + n;
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
  function addDays(d, n) {
15
- return new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);
24
+ return makeDate(d.getFullYear(), d.getMonth(), d.getDate() + n);
16
25
  }
17
26
  function addMonths(d, n) {
18
- const t = new Date(d.getFullYear(), d.getMonth() + n, 1);
19
- const last = new Date(t.getFullYear(), t.getMonth() + 1, 0).getDate();
20
- return new Date(t.getFullYear(), t.getMonth(), Math.min(d.getDate(), last));
27
+ const t = makeDate(d.getFullYear(), d.getMonth() + n, 1);
28
+ const last = makeDate(t.getFullYear(), t.getMonth() + 1, 0).getDate();
29
+ return makeDate(t.getFullYear(), t.getMonth(), Math.min(d.getDate(), last));
21
30
  }
22
31
  function same(a, b) {
23
32
  return !!a && !!b && a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
@@ -46,7 +55,8 @@ const DATE_TEXT = {
46
55
  rangePlaceholder: "\u0E27\u0E27/\u0E14\u0E14/\u0E1B\u0E1B\u0E1B\u0E1B \u2013 \u0E27\u0E27/\u0E14\u0E14/\u0E1B\u0E1B\u0E1B\u0E1B",
47
56
  clearDates: "\u0E25\u0E49\u0E32\u0E07\u0E0A\u0E48\u0E27\u0E07\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48",
48
57
  chooseStart: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E27\u0E31\u0E19\u0E40\u0E23\u0E34\u0E48\u0E21\u0E15\u0E49\u0E19",
49
- chooseEnd: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E27\u0E31\u0E19\u0E2A\u0E34\u0E49\u0E19\u0E2A\u0E38\u0E14"
58
+ chooseEnd: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E27\u0E31\u0E19\u0E2A\u0E34\u0E49\u0E19\u0E2A\u0E38\u0E14",
59
+ dateUnavailable: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E19\u0E35\u0E49\u0E44\u0E21\u0E48\u0E44\u0E14\u0E49 \u0E25\u0E2D\u0E07\u0E40\u0E1B\u0E34\u0E14\u0E1B\u0E0F\u0E34\u0E17\u0E34\u0E19\u0E14\u0E39\u0E27\u0E31\u0E19\u0E17\u0E35\u0E48\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E14\u0E49"
50
60
  },
51
61
  en: {
52
62
  prevYears: "Previous years",
@@ -63,7 +73,8 @@ const DATE_TEXT = {
63
73
  rangePlaceholder: "DD/MM/YYYY \u2013 DD/MM/YYYY",
64
74
  clearDates: "Clear dates",
65
75
  chooseStart: "Choose the start date",
66
- chooseEnd: "Choose the end date"
76
+ chooseEnd: "Choose the end date",
77
+ dateUnavailable: "That date can't be chosen. Open the calendar to see the dates you can pick."
67
78
  },
68
79
  sv: {
69
80
  prevYears: "Tidigare \xE5r",
@@ -80,7 +91,8 @@ const DATE_TEXT = {
80
91
  rangePlaceholder: "\xE5\xE5\xE5\xE5-mm-dd \u2013 \xE5\xE5\xE5\xE5-mm-dd",
81
92
  clearDates: "Rensa datumen",
82
93
  chooseStart: "V\xE4lj startdatum",
83
- chooseEnd: "V\xE4lj slutdatum"
94
+ chooseEnd: "V\xE4lj slutdatum",
95
+ dateUnavailable: "Det datumet g\xE5r inte att v\xE4lja. \xD6ppna kalendern f\xF6r att se vilka datum som g\xE5r."
84
96
  }
85
97
  };
86
98
  function dateText(locale) {
@@ -122,7 +134,15 @@ function monthIndex(word) {
122
134
  return MONTHS[k] != null ? MONTHS[k] : -1;
123
135
  }
124
136
  function parseDate(text) {
125
- const s = String(text || "").trim();
137
+ const raw = String(text || "").trim();
138
+ const gregorian = /ค\.ศ\.|\d\s*(AD|CE)\b|^\s*(AD|CE)\s/i.test(raw);
139
+ 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();
140
+ const eight = /^(\d{2})(\d{2})(\d{4})$/.exec(s);
141
+ if (eight) {
142
+ const a = +eight[3] >= 1e3 ? parseDate(eight[1] + "/" + eight[2] + "/" + eight[3] + (gregorian ? " \u0E04.\u0E28." : "")) : null;
143
+ if (a) return a;
144
+ s = s.slice(0, 4) + "-" + s.slice(4, 6) + "-" + s.slice(6);
145
+ }
126
146
  let m = /^(\d{4})-(\d{1,2})-(\d{1,2})$/.exec(s), y, mo, d;
127
147
  if (m) {
128
148
  y = +m[1];
@@ -132,13 +152,13 @@ function parseDate(text) {
132
152
  d = +m[1];
133
153
  mo = +m[2];
134
154
  y = +m[3];
135
- } else if ((m = /^(\d{1,2})\s+(\S+)\s+(\d{4})$/.exec(s.replace(ERA, "").trim())) && monthIndex(m[2]) >= 0) {
155
+ } else if ((m = /^(\d{1,2})\s+(\S+)\s+(\d{4})$/.exec(s)) && monthIndex(m[2]) >= 0) {
136
156
  d = +m[1];
137
157
  mo = monthIndex(m[2]) + 1;
138
158
  y = +m[3];
139
159
  } else return null;
140
- if (y >= 2400) y -= 543;
141
- const dt = new Date(y, mo - 1, d);
160
+ if (y >= 2400 && !gregorian) y -= 543;
161
+ const dt = makeDate(y, mo - 1, d);
142
162
  return dt.getMonth() === mo - 1 && dt.getDate() === d ? toISO(dt) : null;
143
163
  }
144
164
  function todayIn(timeZone) {
@@ -170,6 +190,7 @@ export {
170
190
  formatDate,
171
191
  fromISO,
172
192
  localeTag,
193
+ makeDate,
173
194
  monthIndex,
174
195
  pad,
175
196
  parseDate,
@@ -12,14 +12,21 @@ function omit(src, keys) {
12
12
  }
13
13
  function useMaybeControlled(value, initial, onChange) {
14
14
  const s = React.useState(initial);
15
+ const wasSet = React.useState(value !== void 0);
16
+ if (value !== void 0 && !wasSet[0]) wasSet[1](true);
17
+ else if (value === void 0 && wasSet[0]) {
18
+ wasSet[1](false);
19
+ s[1](initial);
20
+ }
15
21
  const controlled = value !== void 0;
16
- return [
17
- controlled ? value : s[0],
18
- function(next) {
19
- if (!controlled) s[1](next);
20
- if (onChange) onChange(next);
21
- }
22
- ];
22
+ const latest = React.useRef({ controlled, onChange, set: s[1] });
23
+ latest.current = { controlled, onChange, set: s[1] };
24
+ const set = React.useCallback(function(next) {
25
+ const l = latest.current;
26
+ if (!l.controlled) l.set(next);
27
+ if (l.onChange) l.onChange(next);
28
+ }, []);
29
+ return [controlled ? value : s[0], set];
23
30
  }
24
31
  const collator = typeof Intl !== "undefined" ? new Intl.Collator(["th", "en"], { numeric: true, sensitivity: "base" }) : null;
25
32
  function compare(a, b) {
@@ -84,6 +91,9 @@ function tone(t) {
84
91
  return TONES.indexOf(t) >= 0 ? t : "neutral";
85
92
  }
86
93
  const warned = {};
94
+ function plainClick(e) {
95
+ return !e.defaultPrevented && e.button === 0 && !e.metaKey && !e.ctrlKey && !e.shiftKey && !e.altKey;
96
+ }
87
97
  function devWarnOnce(key, message) {
88
98
  if (warned[key]) return;
89
99
  let dev = false;
@@ -103,6 +113,7 @@ export {
103
113
  cx,
104
114
  devWarnOnce,
105
115
  omit,
116
+ plainClick,
106
117
  tone,
107
118
  trapTab,
108
119
  uid,
@@ -8,17 +8,18 @@ function AuraProvider(props) {
8
8
  const timeZone = props.timeZone || outer && outer.timeZone || null;
9
9
  const value = React.useMemo(
10
10
  function() {
11
- const base = props.locale && STRINGS[props.locale] || STRINGS.en;
11
+ const own = !!props.locale || !outer || !outer.locale;
12
+ const base = own ? props.locale && STRINGS[props.locale] || STRINGS.en : outer.strings;
12
13
  return {
13
- locale: props.locale || "en",
14
- calendar: props.calendar || null,
14
+ locale: props.locale || outer && outer.locale || "en",
15
+ calendar: props.calendar || (own ? null : outer.calendar),
15
16
  strings: props.strings ? Object.assign({}, base, props.strings) : base,
16
- linkComponent: props.linkComponent || null,
17
+ linkComponent: props.linkComponent || outer && outer.linkComponent || null,
17
18
  density,
18
19
  timeZone
19
20
  };
20
21
  },
21
- [props.locale, props.calendar, props.strings, props.linkComponent, density, timeZone]
22
+ [props.locale, props.calendar, props.strings, props.linkComponent, density, timeZone, outer]
22
23
  );
23
24
  return /* @__PURE__ */ React.createElement(LocaleContext.Provider, { value }, props.density ? /* @__PURE__ */ React.createElement("div", { className: "aura-density", "data-density": props.density }, props.children) : props.children);
24
25
  }
@@ -74,6 +74,12 @@ const STRINGS = {
74
74
  page: function(p, total) {
75
75
  return "Page " + p + " of " + total;
76
76
  },
77
+ rangeOpen: function(a, b) {
78
+ return a + "\u2013" + b + " of many";
79
+ },
80
+ pageOpen: function(p) {
81
+ return "Page " + p;
82
+ },
77
83
  prevPage: "Previous page",
78
84
  nextPage: "Next page",
79
85
  totals: "Totals",
@@ -87,6 +93,7 @@ const STRINGS = {
87
93
  timeOutOfRange: function(a, b) {
88
94
  return "Choose a time between " + a + " and " + b;
89
95
  },
96
+ timeUnavailable: "That time isn't available. Choose another.",
90
97
  dropFiles: "Drag files here or",
91
98
  browse: "Choose files",
92
99
  browseOne: "Choose a file",
@@ -188,6 +195,12 @@ const STRINGS = {
188
195
  page: function(p, total) {
189
196
  return "\u0E2B\u0E19\u0E49\u0E32 " + p + " / " + total;
190
197
  },
198
+ rangeOpen: function(a, b) {
199
+ return a + "\u2013" + b + " \u0E08\u0E32\u0E01\u0E2B\u0E25\u0E32\u0E22\u0E23\u0E32\u0E22\u0E01\u0E32\u0E23";
200
+ },
201
+ pageOpen: function(p) {
202
+ return "\u0E2B\u0E19\u0E49\u0E32 " + p;
203
+ },
191
204
  prevPage: "\u0E2B\u0E19\u0E49\u0E32\u0E01\u0E48\u0E2D\u0E19\u0E2B\u0E19\u0E49\u0E32",
192
205
  nextPage: "\u0E2B\u0E19\u0E49\u0E32\u0E16\u0E31\u0E14\u0E44\u0E1B",
193
206
  totals: "\u0E23\u0E27\u0E21",
@@ -201,6 +214,7 @@ const STRINGS = {
201
214
  timeOutOfRange: function(a, b) {
202
215
  return "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E40\u0E27\u0E25\u0E32\u0E23\u0E30\u0E2B\u0E27\u0E48\u0E32\u0E07 " + a + "\u2013" + b + " \u0E19.";
203
216
  },
217
+ 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",
204
218
  dropFiles: "\u0E25\u0E32\u0E01\u0E44\u0E1F\u0E25\u0E4C\u0E21\u0E32\u0E27\u0E32\u0E07 \u0E2B\u0E23\u0E37\u0E2D",
205
219
  browse: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E1F\u0E25\u0E4C",
206
220
  browseOne: "\u0E40\u0E25\u0E37\u0E2D\u0E01\u0E44\u0E1F\u0E25\u0E4C",
@@ -302,6 +316,12 @@ const STRINGS = {
302
316
  page: function(p, total) {
303
317
  return "Sida " + p + " av " + total;
304
318
  },
319
+ rangeOpen: function(a, b) {
320
+ return a + "\u2013" + b + " av m\xE5nga";
321
+ },
322
+ pageOpen: function(p) {
323
+ return "Sida " + p;
324
+ },
305
325
  prevPage: "F\xF6reg\xE5ende sida",
306
326
  nextPage: "N\xE4sta sida",
307
327
  totals: "Summa",
@@ -315,6 +335,7 @@ const STRINGS = {
315
335
  timeOutOfRange: function(a, b) {
316
336
  return "V\xE4lj en tid mellan " + a + " och " + b;
317
337
  },
338
+ timeUnavailable: "Den tiden \xE4r inte ledig. V\xE4lj en annan.",
318
339
  dropFiles: "Dra filer hit eller",
319
340
  browse: "V\xE4lj filer",
320
341
  browseOne: "V\xE4lj en fil",
package/dist/esm/text.js CHANGED
@@ -19,6 +19,7 @@ function parseTime(text) {
19
19
  const m = /^(\d{1,2})(?:[:.](\d{2}))?$/.exec(s) || /^(\d{1,2})(\d{2})$/.exec(s);
20
20
  if (!m) return null;
21
21
  let hh = +m[1], mm = m[2] ? +m[2] : 0;
22
+ if ((am || pm) && (hh < 1 || hh > 12)) return null;
22
23
  if (pm && hh < 12) hh += 12;
23
24
  if (am && hh === 12) hh = 0;
24
25
  if (hh > 23 || mm > 59) return null;
package/dist/esm/theme.js CHANGED
@@ -245,6 +245,8 @@ function createTheme(opts) {
245
245
  }
246
246
  if (s) check("light", "ink", "accent-lime (signal)", 4.5, INK, s[200]);
247
247
  function css(selector) {
248
+ if (selector !== void 0 && /[<{};@\r\n]|\/\*|\*\//.test(selector))
249
+ throw new Error('createTheme: "' + selector + '" is not a plain CSS selector');
248
250
  const light = selector ? selector : ':root, [data-theme="light"]';
249
251
  const dark = selector ? selector + ".dark, .dark " + selector + ", " + selector + '[data-theme="dark"], [data-theme="dark"] ' + selector : '.dark, [data-theme="dark"]';
250
252
  const system = selector ? '[data-theme="system"] ' + selector + ", " + selector + '[data-theme="system"]' : '[data-theme="system"]';
@@ -253,7 +255,7 @@ function createTheme(opts) {
253
255
  return " --aura-" + k + ": " + m[k] + ";";
254
256
  }).join("\n") + "\n}";
255
257
  }
256
- return "/* AURA theme" + (o.name ? ' "' + o.name + '"' : "") + ": brand " + o.brand + (o.signal ? ", signal " + o.signal : "") + (o.primary === "brand" ? ", brand primary buttons" : "") + ". Load after aura.css. Generated by createTheme. */\n" + block(light, L) + "\n" + block(dark, D) + "\n@media (prefers-color-scheme: dark) {\n" + block(system, D) + "\n}\n";
258
+ return "/* AURA theme" + (o.name ? ' "' + String(o.name).replace(/[*/<>\\]/g, "") + '"' : "") + ": brand " + o.brand + (o.signal ? ", signal " + o.signal : "") + (o.primary === "brand" ? ", brand primary buttons" : "") + ". Load after aura.css. Generated by createTheme. */\n" + block(light, L) + "\n" + block(dark, D) + "\n@media (prefers-color-scheme: dark) {\n" + block(system, D) + "\n}\n";
257
259
  }
258
260
  return {
259
261
  name: o.name || null,
@@ -1,6 +1,29 @@
1
1
  'use client';
2
2
  import * as React from "react";
3
3
  import { FOCUSABLE, useMounted } from "./internal.js";
4
+ let locks = 0, savedOverflow = "";
5
+ function lockScroll() {
6
+ const body = document.body;
7
+ if (locks === 0) savedOverflow = body.style.overflow;
8
+ locks++;
9
+ body.style.overflow = "hidden";
10
+ let done = false;
11
+ return function() {
12
+ if (done) return;
13
+ done = true;
14
+ locks--;
15
+ if (locks === 0) body.style.overflow = savedOverflow;
16
+ };
17
+ }
18
+ function tabbable(el) {
19
+ const all = Array.prototype.filter.call(el.querySelectorAll(FOCUSABLE), function(c) {
20
+ return c.tabIndex >= 0;
21
+ });
22
+ const shown = all.filter(function(c) {
23
+ return c.getClientRects().length > 0;
24
+ });
25
+ return shown.length ? shown : all;
26
+ }
4
27
  function useModal(open, ref, opts) {
5
28
  const mounted = useMounted();
6
29
  const prev = React.useRef(null);
@@ -9,8 +32,7 @@ function useModal(open, ref, opts) {
9
32
  function() {
10
33
  if (!open || !mounted) return;
11
34
  prev.current = document.activeElement;
12
- const body = document.body, overflow = body.style.overflow;
13
- body.style.overflow = "hidden";
35
+ const unlock = lockScroll();
14
36
  const el = ref.current;
15
37
  const firstIn = function(scope) {
16
38
  if (!scope || !el) return null;
@@ -25,7 +47,7 @@ function useModal(open, ref, opts) {
25
47
  const target = el && (el.querySelector("[data-autofocus]") || firstIn(o.bodySelector) || firstIn(o.footSelector) || el);
26
48
  if (target && o.autoFocus !== false) target.focus();
27
49
  return function() {
28
- body.style.overflow = overflow;
50
+ unlock();
29
51
  if (prev.current && prev.current.focus) prev.current.focus();
30
52
  };
31
53
  },
@@ -37,17 +59,18 @@ function useModal(open, ref, opts) {
37
59
  if (o.onEscape) o.onEscape();
38
60
  return;
39
61
  }
40
- if (e.key !== "Tab" || !ref.current) return;
41
- const list = Array.prototype.slice.call(ref.current.querySelectorAll(FOCUSABLE));
62
+ if (e.key !== "Tab" || !ref.current || e.defaultPrevented) return;
63
+ if (!ref.current.contains(e.target)) return;
64
+ const list = tabbable(ref.current);
42
65
  if (!list.length) {
43
66
  e.preventDefault();
44
67
  return;
45
68
  }
46
- const first = list[0], last = list[list.length - 1];
47
- if (e.shiftKey && (document.activeElement === first || document.activeElement === ref.current)) {
69
+ const first = list[0], last = list[list.length - 1], active = document.activeElement, stray = active === ref.current;
70
+ if (e.shiftKey && (active === first || stray)) {
48
71
  e.preventDefault();
49
72
  last.focus();
50
- } else if (!e.shiftKey && document.activeElement === last) {
73
+ } else if (!e.shiftKey && (active === last || stray)) {
51
74
  e.preventDefault();
52
75
  first.focus();
53
76
  }