@jirawatpyk/aura-react 5.56.0 → 5.57.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/README.md +6 -0
- package/dist/aura.bundle.js +72 -20
- package/dist/cjs/index.cjs +72 -20
- package/dist/esm/Alert.js +4 -1
- package/dist/esm/Popover.js +11 -3
- package/dist/esm/display.js +20 -4
- package/dist/esm/internal.js +34 -2
- package/dist/esm/useModal.js +11 -12
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/server/index.cjs +20 -4
- package/dist/server/index.d.cts +5 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.js +20 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -186,6 +186,12 @@ DataTable with sort and page in the URL (4.17): `onStateChange={({ sort, page })
|
|
|
186
186
|
- **Time zone**: `timeZone` on AuraProvider, DatePicker, DateRangePicker and Calendar decides "today" (the marker, `min`/`max="today"`, the first month shown); or pass `today` as an ISO date. `todayIn('Asia/Bangkok')` is exported from the root and `/server`.
|
|
187
187
|
- **Toasts** queue past three instead of dropping: six in a row all show, in order, three at a time.
|
|
188
188
|
|
|
189
|
+
## 5.57 — Chamber-OS addenda 70–71 (#169, #170)
|
|
190
|
+
|
|
191
|
+
- **A Dialog or Drawer always opens with focus inside:** a control inside a closed `<details>` is no longer picked as the first control (Chromium reports it as focusable, but `focus()` on it did nothing, so focus stayed on the trigger and Escape didn't close the modal). The `<details>`'s own `<summary>` now counts as a control, so a body whose only control is a closed `<details>` opens on its summary. And focus is checked after each try: if a control doesn't take focus (or pass it on to a field inside it), the next one is tried, then the panel itself — focus is always in the modal, so Escape and the Tab trap work whatever the content. Command works the same way, and so does a Popover's first focus — which now also skips `tabindex="-1"` controls, so a Popover holding a SegmentedControl or Tabs opens on the selected item, as Tab would reach it. A summary is a control whether its `<details>` is open or closed, so a body that starts with an open `<details>` ("Advanced" above a form) now opens on its summary, the first Tab stop, rather than the first field.
|
|
192
|
+
- **The Tab trap skips closed `<details>` too:** Tab and Shift+Tab wrap between the controls you can see, the summary included, and never to a control in a closed `<details>`; opened, its controls are Tab stops again. Popover's and DatePicker's trap do the same and now count a summary as a stop, so Tab from it no longer leaves the popover. A workaround such as `closeProps={{ 'data-autofocus': true }}` can go.
|
|
193
|
+
- **A titled Alert is named by its title** (#170): an Alert with a `title` and a role (`alert`, `status`, `note` — the default is `alert` or `status` by tone) gets `aria-labelledby` pointing at the title, so a screen reader can say which notice it is when the banner takes focus or is read in browse mode. A passed `aria-label` or `aria-labelledby` wins; no title, or `role="none"`, stays unnamed. The title's id (set only when it names the Alert) is `titleId` if you pass one, else `id` + `-title`, else generated. The `/server` Alert can't generate ids: it uses `titleId` or `id` + `-title`, or for a plain-text title `aria-label`; give a rich title an `id` there. Drop a stand-in `aria-label={title}`.
|
|
194
|
+
|
|
189
195
|
## 5.56 — Chamber-OS addendum 69 (#168)
|
|
190
196
|
|
|
191
197
|
- **AppShell's menu button is a 44px touch target:** the "Open navigation" button AppShell draws below 1024px is now 44×44 below 640px or on a touch screen (`(pointer: coarse)`), whatever the density — the same box as an IconButton with `touchHeight` — so it matches the 44px search and account buttons beside it. From 640px with a mouse it keeps its 32px size; from 1024px it is hidden, as before. The bar keeps its 56px height; on a phone the `header` content is 12px narrower, so a long title truncates a little sooner. No new prop.
|
package/dist/aura.bundle.js
CHANGED
|
@@ -331,6 +331,34 @@ window.Aura = (() => {
|
|
|
331
331
|
return r2.current;
|
|
332
332
|
};
|
|
333
333
|
var FOCUSABLE = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
|
|
334
|
+
function inClosedDetails(el) {
|
|
335
|
+
for (let p = el.parentElement; p; p = p.parentElement) {
|
|
336
|
+
if (p.tagName !== "DETAILS" || p.open) continue;
|
|
337
|
+
let s = null;
|
|
338
|
+
for (let c = p.firstElementChild; c; c = c.nextElementSibling)
|
|
339
|
+
if (c.tagName === "SUMMARY") {
|
|
340
|
+
s = c;
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
if (!s || !(s === el || s.contains(el))) return true;
|
|
344
|
+
}
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
var TAB_STOPS = FOCUSABLE + ",details > summary";
|
|
348
|
+
function isTabStop(c, layoutless) {
|
|
349
|
+
return c.tabIndex >= 0 && (layoutless || c.getClientRects().length > 0) && !inClosedDetails(c);
|
|
350
|
+
}
|
|
351
|
+
function focusFirst(container, auto, lists, layoutless) {
|
|
352
|
+
const took = function(c) {
|
|
353
|
+
c.focus();
|
|
354
|
+
const a = document.activeElement;
|
|
355
|
+
return !!a && a !== container && container.contains(a);
|
|
356
|
+
};
|
|
357
|
+
if (auto && took(auto)) return true;
|
|
358
|
+
for (let l = 0; l < lists.length; l++)
|
|
359
|
+
for (let i = 0; i < lists[l].length; i++) if (isTabStop(lists[l][i], layoutless) && took(lists[l][i])) return true;
|
|
360
|
+
return false;
|
|
361
|
+
}
|
|
334
362
|
function noopSubscribe() {
|
|
335
363
|
return function() {
|
|
336
364
|
};
|
|
@@ -348,9 +376,9 @@ window.Aura = (() => {
|
|
|
348
376
|
function trapTab(e, container) {
|
|
349
377
|
if (e.key !== "Tab" || !container) return;
|
|
350
378
|
const list = Array.prototype.filter.call(
|
|
351
|
-
container.querySelectorAll(
|
|
379
|
+
container.querySelectorAll(TAB_STOPS),
|
|
352
380
|
function(el) {
|
|
353
|
-
return el.tabIndex >= 0 && el.offsetParent !== null;
|
|
381
|
+
return el.tabIndex >= 0 && el.offsetParent !== null && !inClosedDetails(el);
|
|
354
382
|
}
|
|
355
383
|
);
|
|
356
384
|
if (!list.length) return;
|
|
@@ -623,19 +651,35 @@ window.Aura = (() => {
|
|
|
623
651
|
warning: IconTriangleAlert,
|
|
624
652
|
danger: IconCircleAlert
|
|
625
653
|
};
|
|
626
|
-
function alertElement(props, ref, close) {
|
|
654
|
+
function alertElement(props, ref, close, autoId) {
|
|
627
655
|
const tone2 = props.tone || "info";
|
|
628
|
-
const rest = omit(props, [
|
|
656
|
+
const rest = omit(props, [
|
|
657
|
+
"tone",
|
|
658
|
+
"title",
|
|
659
|
+
"titleId",
|
|
660
|
+
"children",
|
|
661
|
+
"action",
|
|
662
|
+
"onDismiss",
|
|
663
|
+
"className",
|
|
664
|
+
"role",
|
|
665
|
+
"icon"
|
|
666
|
+
]);
|
|
667
|
+
const role = props.role || (tone2 === "danger" || tone2 === "warning" ? "alert" : "status");
|
|
668
|
+
const titled = !!props.title && role !== "none" && !props["aria-label"] && !props["aria-labelledby"];
|
|
669
|
+
const titleId = props.titleId || (props.id ? props.id + "-title" : autoId);
|
|
670
|
+
const text2 = typeof props.title === "string" || typeof props.title === "number" ? String(props.title) : void 0;
|
|
629
671
|
return /* @__PURE__ */ React4.createElement(
|
|
630
672
|
"div",
|
|
631
673
|
{
|
|
632
674
|
...rest,
|
|
633
675
|
ref,
|
|
634
676
|
className: cx("aura-alert", "aura-alert--" + tone2, props.className),
|
|
635
|
-
role
|
|
677
|
+
role,
|
|
678
|
+
"aria-labelledby": titled && titleId ? titleId : props["aria-labelledby"],
|
|
679
|
+
"aria-label": titled && !titleId && text2 ? text2 : props["aria-label"]
|
|
636
680
|
},
|
|
637
681
|
/* @__PURE__ */ React4.createElement(Icon, { name: props.icon || h2(ALERT_ICON[tone2]), className: "aura-alert__icon" }),
|
|
638
|
-
/* @__PURE__ */ React4.createElement("div", { className: "aura-alert__body" }, props.title ? /* @__PURE__ */ React4.createElement("p", { className: "aura-alert__title" }, props.title) : null, props.children ? /* @__PURE__ */ React4.createElement("div", { className: "aura-alert__text" }, props.children) : null, props.action ? /* @__PURE__ */ React4.createElement("div", { className: "aura-alert__action" }, props.action) : null),
|
|
682
|
+
/* @__PURE__ */ React4.createElement("div", { className: "aura-alert__body" }, props.title ? /* @__PURE__ */ React4.createElement("p", { className: "aura-alert__title", id: titled ? titleId : void 0 }, props.title) : null, props.children ? /* @__PURE__ */ React4.createElement("div", { className: "aura-alert__text" }, props.children) : null, props.action ? /* @__PURE__ */ React4.createElement("div", { className: "aura-alert__action" }, props.action) : null),
|
|
639
683
|
close
|
|
640
684
|
);
|
|
641
685
|
}
|
|
@@ -4307,10 +4351,12 @@ window.Aura = (() => {
|
|
|
4307
4351
|
var React23 = __toESM(require_react(), 1);
|
|
4308
4352
|
var Alert = React23.forwardRef(function Alert2(props, ref) {
|
|
4309
4353
|
const t = useStrings();
|
|
4354
|
+
const autoId = uid();
|
|
4310
4355
|
return alertElement(
|
|
4311
4356
|
props,
|
|
4312
4357
|
ref,
|
|
4313
|
-
props.onDismiss ? /* @__PURE__ */ React23.createElement(IconButton, { icon: /* @__PURE__ */ React23.createElement(IconX, null), label: t.dismiss, className: "aura-alert__close", onClick: props.onDismiss }) : null
|
|
4358
|
+
props.onDismiss ? /* @__PURE__ */ React23.createElement(IconButton, { icon: /* @__PURE__ */ React23.createElement(IconX, null), label: t.dismiss, className: "aura-alert__close", onClick: props.onDismiss }) : null,
|
|
4359
|
+
autoId
|
|
4314
4360
|
);
|
|
4315
4361
|
});
|
|
4316
4362
|
|
|
@@ -4793,8 +4839,8 @@ window.Aura = (() => {
|
|
|
4793
4839
|
};
|
|
4794
4840
|
}
|
|
4795
4841
|
function tabbable(el) {
|
|
4796
|
-
const all = Array.prototype.filter.call(el.querySelectorAll(
|
|
4797
|
-
return c.tabIndex >= 0;
|
|
4842
|
+
const all = Array.prototype.filter.call(el.querySelectorAll(TAB_STOPS), function(c) {
|
|
4843
|
+
return c.tabIndex >= 0 && !inClosedDetails(c);
|
|
4798
4844
|
});
|
|
4799
4845
|
const shown = all.filter(function(c) {
|
|
4800
4846
|
return c.getClientRects().length > 0;
|
|
@@ -4813,18 +4859,17 @@ window.Aura = (() => {
|
|
|
4813
4859
|
prev.current = document.activeElement;
|
|
4814
4860
|
const unlock = lockScroll();
|
|
4815
4861
|
const el = ref.current;
|
|
4816
|
-
const
|
|
4817
|
-
if (!scope || !el) return
|
|
4818
|
-
const sel =
|
|
4862
|
+
const inPart = function(scope) {
|
|
4863
|
+
if (!scope || !el) return [];
|
|
4864
|
+
const sel = TAB_STOPS.split(",").map(function(s) {
|
|
4819
4865
|
return scope + " " + s;
|
|
4820
4866
|
}).join(",");
|
|
4821
|
-
|
|
4822
|
-
for (let i = 0; i < list.length; i++)
|
|
4823
|
-
if (list[i].tabIndex >= 0 && list[i].getClientRects().length > 0) return list[i];
|
|
4824
|
-
return null;
|
|
4867
|
+
return el.querySelectorAll(sel);
|
|
4825
4868
|
};
|
|
4826
|
-
|
|
4827
|
-
|
|
4869
|
+
if (el && o.autoFocus !== false) {
|
|
4870
|
+
const auto = el.querySelector("[data-autofocus]");
|
|
4871
|
+
if (!focusFirst(el, auto, [inPart(o.bodySelector), inPart(o.footSelector)])) el.focus();
|
|
4872
|
+
}
|
|
4828
4873
|
return function() {
|
|
4829
4874
|
unlock();
|
|
4830
4875
|
const l = latest.current;
|
|
@@ -10391,8 +10436,15 @@ window.Aura = (() => {
|
|
|
10391
10436
|
function() {
|
|
10392
10437
|
if (!open || !mounted) return;
|
|
10393
10438
|
if (props.autoFocus !== false && pop.current) {
|
|
10394
|
-
const
|
|
10395
|
-
|
|
10439
|
+
const p = pop.current;
|
|
10440
|
+
const layoutless = document.documentElement.getClientRects().length === 0;
|
|
10441
|
+
if (!focusFirst(
|
|
10442
|
+
p,
|
|
10443
|
+
p.querySelector("[data-autofocus]"),
|
|
10444
|
+
[p.querySelectorAll(TAB_STOPS)],
|
|
10445
|
+
layoutless
|
|
10446
|
+
))
|
|
10447
|
+
p.focus();
|
|
10396
10448
|
}
|
|
10397
10449
|
let timer2;
|
|
10398
10450
|
function outside(e) {
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -313,6 +313,34 @@ var uid = React3.useId || function() {
|
|
|
313
313
|
return r2.current;
|
|
314
314
|
};
|
|
315
315
|
var FOCUSABLE = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
|
|
316
|
+
function inClosedDetails(el) {
|
|
317
|
+
for (let p = el.parentElement; p; p = p.parentElement) {
|
|
318
|
+
if (p.tagName !== "DETAILS" || p.open) continue;
|
|
319
|
+
let s = null;
|
|
320
|
+
for (let c = p.firstElementChild; c; c = c.nextElementSibling)
|
|
321
|
+
if (c.tagName === "SUMMARY") {
|
|
322
|
+
s = c;
|
|
323
|
+
break;
|
|
324
|
+
}
|
|
325
|
+
if (!s || !(s === el || s.contains(el))) return true;
|
|
326
|
+
}
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
var TAB_STOPS = FOCUSABLE + ",details > summary";
|
|
330
|
+
function isTabStop(c, layoutless) {
|
|
331
|
+
return c.tabIndex >= 0 && (layoutless || c.getClientRects().length > 0) && !inClosedDetails(c);
|
|
332
|
+
}
|
|
333
|
+
function focusFirst(container, auto, lists, layoutless) {
|
|
334
|
+
const took = function(c) {
|
|
335
|
+
c.focus();
|
|
336
|
+
const a = document.activeElement;
|
|
337
|
+
return !!a && a !== container && container.contains(a);
|
|
338
|
+
};
|
|
339
|
+
if (auto && took(auto)) return true;
|
|
340
|
+
for (let l = 0; l < lists.length; l++)
|
|
341
|
+
for (let i = 0; i < lists[l].length; i++) if (isTabStop(lists[l][i], layoutless) && took(lists[l][i])) return true;
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
316
344
|
function noopSubscribe() {
|
|
317
345
|
return function() {
|
|
318
346
|
};
|
|
@@ -330,9 +358,9 @@ var useIsoLayoutEffect = typeof window !== "undefined" ? React3.useLayoutEffect
|
|
|
330
358
|
function trapTab(e, container) {
|
|
331
359
|
if (e.key !== "Tab" || !container) return;
|
|
332
360
|
const list = Array.prototype.filter.call(
|
|
333
|
-
container.querySelectorAll(
|
|
361
|
+
container.querySelectorAll(TAB_STOPS),
|
|
334
362
|
function(el) {
|
|
335
|
-
return el.tabIndex >= 0 && el.offsetParent !== null;
|
|
363
|
+
return el.tabIndex >= 0 && el.offsetParent !== null && !inClosedDetails(el);
|
|
336
364
|
}
|
|
337
365
|
);
|
|
338
366
|
if (!list.length) return;
|
|
@@ -605,19 +633,35 @@ var ALERT_ICON = {
|
|
|
605
633
|
warning: IconTriangleAlert,
|
|
606
634
|
danger: IconCircleAlert
|
|
607
635
|
};
|
|
608
|
-
function alertElement(props, ref, close) {
|
|
636
|
+
function alertElement(props, ref, close, autoId) {
|
|
609
637
|
const tone2 = props.tone || "info";
|
|
610
|
-
const rest = omit(props, [
|
|
638
|
+
const rest = omit(props, [
|
|
639
|
+
"tone",
|
|
640
|
+
"title",
|
|
641
|
+
"titleId",
|
|
642
|
+
"children",
|
|
643
|
+
"action",
|
|
644
|
+
"onDismiss",
|
|
645
|
+
"className",
|
|
646
|
+
"role",
|
|
647
|
+
"icon"
|
|
648
|
+
]);
|
|
649
|
+
const role = props.role || (tone2 === "danger" || tone2 === "warning" ? "alert" : "status");
|
|
650
|
+
const titled = !!props.title && role !== "none" && !props["aria-label"] && !props["aria-labelledby"];
|
|
651
|
+
const titleId = props.titleId || (props.id ? props.id + "-title" : autoId);
|
|
652
|
+
const text2 = typeof props.title === "string" || typeof props.title === "number" ? String(props.title) : void 0;
|
|
611
653
|
return /* @__PURE__ */ React4.createElement(
|
|
612
654
|
"div",
|
|
613
655
|
{
|
|
614
656
|
...rest,
|
|
615
657
|
ref,
|
|
616
658
|
className: cx("aura-alert", "aura-alert--" + tone2, props.className),
|
|
617
|
-
role
|
|
659
|
+
role,
|
|
660
|
+
"aria-labelledby": titled && titleId ? titleId : props["aria-labelledby"],
|
|
661
|
+
"aria-label": titled && !titleId && text2 ? text2 : props["aria-label"]
|
|
618
662
|
},
|
|
619
663
|
/* @__PURE__ */ React4.createElement(Icon, { name: props.icon || h2(ALERT_ICON[tone2]), className: "aura-alert__icon" }),
|
|
620
|
-
/* @__PURE__ */ React4.createElement("div", { className: "aura-alert__body" }, props.title ? /* @__PURE__ */ React4.createElement("p", { className: "aura-alert__title" }, props.title) : null, props.children ? /* @__PURE__ */ React4.createElement("div", { className: "aura-alert__text" }, props.children) : null, props.action ? /* @__PURE__ */ React4.createElement("div", { className: "aura-alert__action" }, props.action) : null),
|
|
664
|
+
/* @__PURE__ */ React4.createElement("div", { className: "aura-alert__body" }, props.title ? /* @__PURE__ */ React4.createElement("p", { className: "aura-alert__title", id: titled ? titleId : void 0 }, props.title) : null, props.children ? /* @__PURE__ */ React4.createElement("div", { className: "aura-alert__text" }, props.children) : null, props.action ? /* @__PURE__ */ React4.createElement("div", { className: "aura-alert__action" }, props.action) : null),
|
|
621
665
|
close
|
|
622
666
|
);
|
|
623
667
|
}
|
|
@@ -4289,10 +4333,12 @@ var Combobox = React22.forwardRef(
|
|
|
4289
4333
|
var React23 = __toESM(require("react"), 1);
|
|
4290
4334
|
var Alert = React23.forwardRef(function Alert2(props, ref) {
|
|
4291
4335
|
const t = useStrings();
|
|
4336
|
+
const autoId = uid();
|
|
4292
4337
|
return alertElement(
|
|
4293
4338
|
props,
|
|
4294
4339
|
ref,
|
|
4295
|
-
props.onDismiss ? /* @__PURE__ */ React23.createElement(IconButton, { icon: /* @__PURE__ */ React23.createElement(IconX, null), label: t.dismiss, className: "aura-alert__close", onClick: props.onDismiss }) : null
|
|
4340
|
+
props.onDismiss ? /* @__PURE__ */ React23.createElement(IconButton, { icon: /* @__PURE__ */ React23.createElement(IconX, null), label: t.dismiss, className: "aura-alert__close", onClick: props.onDismiss }) : null,
|
|
4341
|
+
autoId
|
|
4296
4342
|
);
|
|
4297
4343
|
});
|
|
4298
4344
|
|
|
@@ -4775,8 +4821,8 @@ function lockScroll() {
|
|
|
4775
4821
|
};
|
|
4776
4822
|
}
|
|
4777
4823
|
function tabbable(el) {
|
|
4778
|
-
const all = Array.prototype.filter.call(el.querySelectorAll(
|
|
4779
|
-
return c.tabIndex >= 0;
|
|
4824
|
+
const all = Array.prototype.filter.call(el.querySelectorAll(TAB_STOPS), function(c) {
|
|
4825
|
+
return c.tabIndex >= 0 && !inClosedDetails(c);
|
|
4780
4826
|
});
|
|
4781
4827
|
const shown = all.filter(function(c) {
|
|
4782
4828
|
return c.getClientRects().length > 0;
|
|
@@ -4795,18 +4841,17 @@ function useModal(open, ref, opts) {
|
|
|
4795
4841
|
prev.current = document.activeElement;
|
|
4796
4842
|
const unlock = lockScroll();
|
|
4797
4843
|
const el = ref.current;
|
|
4798
|
-
const
|
|
4799
|
-
if (!scope || !el) return
|
|
4800
|
-
const sel =
|
|
4844
|
+
const inPart = function(scope) {
|
|
4845
|
+
if (!scope || !el) return [];
|
|
4846
|
+
const sel = TAB_STOPS.split(",").map(function(s) {
|
|
4801
4847
|
return scope + " " + s;
|
|
4802
4848
|
}).join(",");
|
|
4803
|
-
|
|
4804
|
-
for (let i = 0; i < list.length; i++)
|
|
4805
|
-
if (list[i].tabIndex >= 0 && list[i].getClientRects().length > 0) return list[i];
|
|
4806
|
-
return null;
|
|
4849
|
+
return el.querySelectorAll(sel);
|
|
4807
4850
|
};
|
|
4808
|
-
|
|
4809
|
-
|
|
4851
|
+
if (el && o.autoFocus !== false) {
|
|
4852
|
+
const auto = el.querySelector("[data-autofocus]");
|
|
4853
|
+
if (!focusFirst(el, auto, [inPart(o.bodySelector), inPart(o.footSelector)])) el.focus();
|
|
4854
|
+
}
|
|
4810
4855
|
return function() {
|
|
4811
4856
|
unlock();
|
|
4812
4857
|
const l = latest.current;
|
|
@@ -10373,8 +10418,15 @@ var Popover = React66.forwardRef(function Popover2(props, ref) {
|
|
|
10373
10418
|
function() {
|
|
10374
10419
|
if (!open || !mounted) return;
|
|
10375
10420
|
if (props.autoFocus !== false && pop.current) {
|
|
10376
|
-
const
|
|
10377
|
-
|
|
10421
|
+
const p = pop.current;
|
|
10422
|
+
const layoutless = document.documentElement.getClientRects().length === 0;
|
|
10423
|
+
if (!focusFirst(
|
|
10424
|
+
p,
|
|
10425
|
+
p.querySelector("[data-autofocus]"),
|
|
10426
|
+
[p.querySelectorAll(TAB_STOPS)],
|
|
10427
|
+
layoutless
|
|
10428
|
+
))
|
|
10429
|
+
p.focus();
|
|
10378
10430
|
}
|
|
10379
10431
|
let timer2;
|
|
10380
10432
|
function outside(e) {
|
package/dist/esm/Alert.js
CHANGED
|
@@ -2,15 +2,18 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { IconButton } from "./IconButton.js";
|
|
4
4
|
import { alertElement } from "./display.js";
|
|
5
|
+
import { uid } from "./internal.js";
|
|
5
6
|
import { useStrings } from "./locale.js";
|
|
6
7
|
import { IconX } from "./icons.js";
|
|
7
8
|
import { ALERT_ICON } from "./display.js";
|
|
8
9
|
const Alert = React.forwardRef(function Alert2(props, ref) {
|
|
9
10
|
const t = useStrings();
|
|
11
|
+
const autoId = uid();
|
|
10
12
|
return alertElement(
|
|
11
13
|
props,
|
|
12
14
|
ref,
|
|
13
|
-
props.onDismiss ? /* @__PURE__ */ React.createElement(IconButton, { icon: /* @__PURE__ */ React.createElement(IconX, null), label: t.dismiss, className: "aura-alert__close", onClick: props.onDismiss }) : null
|
|
15
|
+
props.onDismiss ? /* @__PURE__ */ React.createElement(IconButton, { icon: /* @__PURE__ */ React.createElement(IconX, null), label: t.dismiss, className: "aura-alert__close", onClick: props.onDismiss }) : null,
|
|
16
|
+
autoId
|
|
14
17
|
);
|
|
15
18
|
});
|
|
16
19
|
export {
|
package/dist/esm/Popover.js
CHANGED
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { IconButton } from "./IconButton.js";
|
|
4
4
|
import {
|
|
5
|
-
FOCUSABLE,
|
|
6
5
|
cx,
|
|
6
|
+
focusFirst,
|
|
7
|
+
TAB_STOPS,
|
|
7
8
|
trapTab,
|
|
8
9
|
uid,
|
|
9
10
|
useIsoLayoutEffect,
|
|
@@ -69,8 +70,15 @@ const Popover = React.forwardRef(function Popover2(props, ref) {
|
|
|
69
70
|
function() {
|
|
70
71
|
if (!open || !mounted) return;
|
|
71
72
|
if (props.autoFocus !== false && pop.current) {
|
|
72
|
-
const
|
|
73
|
-
|
|
73
|
+
const p = pop.current;
|
|
74
|
+
const layoutless = document.documentElement.getClientRects().length === 0;
|
|
75
|
+
if (!focusFirst(
|
|
76
|
+
p,
|
|
77
|
+
p.querySelector("[data-autofocus]"),
|
|
78
|
+
[p.querySelectorAll(TAB_STOPS)],
|
|
79
|
+
layoutless
|
|
80
|
+
))
|
|
81
|
+
p.focus();
|
|
74
82
|
}
|
|
75
83
|
let timer;
|
|
76
84
|
function outside(e) {
|
package/dist/esm/display.js
CHANGED
|
@@ -23,19 +23,35 @@ const ALERT_ICON = {
|
|
|
23
23
|
warning: IconTriangleAlert,
|
|
24
24
|
danger: IconCircleAlert
|
|
25
25
|
};
|
|
26
|
-
function alertElement(props, ref, close) {
|
|
26
|
+
function alertElement(props, ref, close, autoId) {
|
|
27
27
|
const tone = props.tone || "info";
|
|
28
|
-
const rest = omit(props, [
|
|
28
|
+
const rest = omit(props, [
|
|
29
|
+
"tone",
|
|
30
|
+
"title",
|
|
31
|
+
"titleId",
|
|
32
|
+
"children",
|
|
33
|
+
"action",
|
|
34
|
+
"onDismiss",
|
|
35
|
+
"className",
|
|
36
|
+
"role",
|
|
37
|
+
"icon"
|
|
38
|
+
]);
|
|
39
|
+
const role = props.role || (tone === "danger" || tone === "warning" ? "alert" : "status");
|
|
40
|
+
const titled = !!props.title && role !== "none" && !props["aria-label"] && !props["aria-labelledby"];
|
|
41
|
+
const titleId = props.titleId || (props.id ? props.id + "-title" : autoId);
|
|
42
|
+
const text = typeof props.title === "string" || typeof props.title === "number" ? String(props.title) : void 0;
|
|
29
43
|
return /* @__PURE__ */ React.createElement(
|
|
30
44
|
"div",
|
|
31
45
|
{
|
|
32
46
|
...rest,
|
|
33
47
|
ref,
|
|
34
48
|
className: cx("aura-alert", "aura-alert--" + tone, props.className),
|
|
35
|
-
role
|
|
49
|
+
role,
|
|
50
|
+
"aria-labelledby": titled && titleId ? titleId : props["aria-labelledby"],
|
|
51
|
+
"aria-label": titled && !titleId && text ? text : props["aria-label"]
|
|
36
52
|
},
|
|
37
53
|
/* @__PURE__ */ React.createElement(Icon, { name: props.icon || h(ALERT_ICON[tone]), className: "aura-alert__icon" }),
|
|
38
|
-
/* @__PURE__ */ React.createElement("div", { className: "aura-alert__body" }, props.title ? /* @__PURE__ */ React.createElement("p", { className: "aura-alert__title" }, props.title) : null, props.children ? /* @__PURE__ */ React.createElement("div", { className: "aura-alert__text" }, props.children) : null, props.action ? /* @__PURE__ */ React.createElement("div", { className: "aura-alert__action" }, props.action) : null),
|
|
54
|
+
/* @__PURE__ */ React.createElement("div", { className: "aura-alert__body" }, props.title ? /* @__PURE__ */ React.createElement("p", { className: "aura-alert__title", id: titled ? titleId : void 0 }, props.title) : null, props.children ? /* @__PURE__ */ React.createElement("div", { className: "aura-alert__text" }, props.children) : null, props.action ? /* @__PURE__ */ React.createElement("div", { className: "aura-alert__action" }, props.action) : null),
|
|
39
55
|
close
|
|
40
56
|
);
|
|
41
57
|
}
|
package/dist/esm/internal.js
CHANGED
|
@@ -33,6 +33,34 @@ const uid = React.useId || function() {
|
|
|
33
33
|
return r.current;
|
|
34
34
|
};
|
|
35
35
|
const FOCUSABLE = 'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])';
|
|
36
|
+
function inClosedDetails(el) {
|
|
37
|
+
for (let p = el.parentElement; p; p = p.parentElement) {
|
|
38
|
+
if (p.tagName !== "DETAILS" || p.open) continue;
|
|
39
|
+
let s = null;
|
|
40
|
+
for (let c = p.firstElementChild; c; c = c.nextElementSibling)
|
|
41
|
+
if (c.tagName === "SUMMARY") {
|
|
42
|
+
s = c;
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
if (!s || !(s === el || s.contains(el))) return true;
|
|
46
|
+
}
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
const TAB_STOPS = FOCUSABLE + ",details > summary";
|
|
50
|
+
function isTabStop(c, layoutless) {
|
|
51
|
+
return c.tabIndex >= 0 && (layoutless || c.getClientRects().length > 0) && !inClosedDetails(c);
|
|
52
|
+
}
|
|
53
|
+
function focusFirst(container, auto, lists, layoutless) {
|
|
54
|
+
const took = function(c) {
|
|
55
|
+
c.focus();
|
|
56
|
+
const a = document.activeElement;
|
|
57
|
+
return !!a && a !== container && container.contains(a);
|
|
58
|
+
};
|
|
59
|
+
if (auto && took(auto)) return true;
|
|
60
|
+
for (let l = 0; l < lists.length; l++)
|
|
61
|
+
for (let i = 0; i < lists[l].length; i++) if (isTabStop(lists[l][i], layoutless) && took(lists[l][i])) return true;
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
36
64
|
function noopSubscribe() {
|
|
37
65
|
return function() {
|
|
38
66
|
};
|
|
@@ -50,9 +78,9 @@ const useIsoLayoutEffect = typeof window !== "undefined" ? React.useLayoutEffect
|
|
|
50
78
|
function trapTab(e, container) {
|
|
51
79
|
if (e.key !== "Tab" || !container) return;
|
|
52
80
|
const list = Array.prototype.filter.call(
|
|
53
|
-
container.querySelectorAll(
|
|
81
|
+
container.querySelectorAll(TAB_STOPS),
|
|
54
82
|
function(el) {
|
|
55
|
-
return el.tabIndex >= 0 && el.offsetParent !== null;
|
|
83
|
+
return el.tabIndex >= 0 && el.offsetParent !== null && !inClosedDetails(el);
|
|
56
84
|
}
|
|
57
85
|
);
|
|
58
86
|
if (!list.length) return;
|
|
@@ -84,10 +112,14 @@ const FilterSheet = React.createContext(false);
|
|
|
84
112
|
export {
|
|
85
113
|
FOCUSABLE,
|
|
86
114
|
FilterSheet,
|
|
115
|
+
TAB_STOPS,
|
|
87
116
|
collator,
|
|
88
117
|
compare,
|
|
89
118
|
cx,
|
|
90
119
|
devWarnOnce,
|
|
120
|
+
focusFirst,
|
|
121
|
+
inClosedDetails,
|
|
122
|
+
isTabStop,
|
|
91
123
|
omit,
|
|
92
124
|
plainClick,
|
|
93
125
|
tone,
|
package/dist/esm/useModal.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import * as React from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { focusFirst, inClosedDetails, TAB_STOPS, useMounted } from "./internal.js";
|
|
4
4
|
let locks = 0, savedOverflow = "";
|
|
5
5
|
function lockScroll() {
|
|
6
6
|
const body = document.body;
|
|
@@ -16,8 +16,8 @@ function lockScroll() {
|
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
function tabbable(el) {
|
|
19
|
-
const all = Array.prototype.filter.call(el.querySelectorAll(
|
|
20
|
-
return c.tabIndex >= 0;
|
|
19
|
+
const all = Array.prototype.filter.call(el.querySelectorAll(TAB_STOPS), function(c) {
|
|
20
|
+
return c.tabIndex >= 0 && !inClosedDetails(c);
|
|
21
21
|
});
|
|
22
22
|
const shown = all.filter(function(c) {
|
|
23
23
|
return c.getClientRects().length > 0;
|
|
@@ -36,18 +36,17 @@ function useModal(open, ref, opts) {
|
|
|
36
36
|
prev.current = document.activeElement;
|
|
37
37
|
const unlock = lockScroll();
|
|
38
38
|
const el = ref.current;
|
|
39
|
-
const
|
|
40
|
-
if (!scope || !el) return
|
|
41
|
-
const sel =
|
|
39
|
+
const inPart = function(scope) {
|
|
40
|
+
if (!scope || !el) return [];
|
|
41
|
+
const sel = TAB_STOPS.split(",").map(function(s) {
|
|
42
42
|
return scope + " " + s;
|
|
43
43
|
}).join(",");
|
|
44
|
-
|
|
45
|
-
for (let i = 0; i < list.length; i++)
|
|
46
|
-
if (list[i].tabIndex >= 0 && list[i].getClientRects().length > 0) return list[i];
|
|
47
|
-
return null;
|
|
44
|
+
return el.querySelectorAll(sel);
|
|
48
45
|
};
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
if (el && o.autoFocus !== false) {
|
|
47
|
+
const auto = el.querySelector("[data-autofocus]");
|
|
48
|
+
if (!focusFirst(el, auto, [inPart(o.bodySelector), inPart(o.footSelector)])) el.focus();
|
|
49
|
+
}
|
|
51
50
|
return function() {
|
|
52
51
|
unlock();
|
|
53
52
|
const l = latest.current;
|
package/dist/index.d.cts
CHANGED
|
@@ -707,7 +707,12 @@ export interface AlertProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>,
|
|
|
707
707
|
role?: "alert" | "status" | "note" | "none" | undefined;
|
|
708
708
|
/** Replaces the tone's icon (5.8): a name or your own element; always hidden from screen readers. */
|
|
709
709
|
icon?: IconInput | undefined;
|
|
710
|
+
/** With a `role` other than `none`, the Alert is named by its title (5.57, Chamber-OS 170: `aria-labelledby`), unless
|
|
711
|
+
* you pass `aria-label` or `aria-labelledby`. */
|
|
710
712
|
title?: React$1.ReactNode | undefined;
|
|
713
|
+
/** id for the title element (default: generated, or `id` + `-title`). The server entry has no generated ids: pass
|
|
714
|
+
* `id` or `titleId` there for a title that isn't plain text. */
|
|
715
|
+
titleId?: string | undefined;
|
|
711
716
|
children?: React$1.ReactNode | undefined;
|
|
712
717
|
/** Usually a secondary Button. */
|
|
713
718
|
action?: React$1.ReactNode | undefined;
|
package/dist/index.d.ts
CHANGED
|
@@ -707,7 +707,12 @@ export interface AlertProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>,
|
|
|
707
707
|
role?: "alert" | "status" | "note" | "none" | undefined;
|
|
708
708
|
/** Replaces the tone's icon (5.8): a name or your own element; always hidden from screen readers. */
|
|
709
709
|
icon?: IconInput | undefined;
|
|
710
|
+
/** With a `role` other than `none`, the Alert is named by its title (5.57, Chamber-OS 170: `aria-labelledby`), unless
|
|
711
|
+
* you pass `aria-label` or `aria-labelledby`. */
|
|
710
712
|
title?: React$1.ReactNode | undefined;
|
|
713
|
+
/** id for the title element (default: generated, or `id` + `-title`). The server entry has no generated ids: pass
|
|
714
|
+
* `id` or `titleId` there for a title that isn't plain text. */
|
|
715
|
+
titleId?: string | undefined;
|
|
711
716
|
children?: React$1.ReactNode | undefined;
|
|
712
717
|
/** Usually a secondary Button. */
|
|
713
718
|
action?: React$1.ReactNode | undefined;
|
package/dist/server/index.cjs
CHANGED
|
@@ -1179,19 +1179,35 @@ var ALERT_ICON = {
|
|
|
1179
1179
|
warning: IconTriangleAlert,
|
|
1180
1180
|
danger: IconCircleAlert
|
|
1181
1181
|
};
|
|
1182
|
-
function alertElement(props, ref, close) {
|
|
1182
|
+
function alertElement(props, ref, close, autoId) {
|
|
1183
1183
|
const tone2 = props.tone || "info";
|
|
1184
|
-
const rest = omit(props, [
|
|
1184
|
+
const rest = omit(props, [
|
|
1185
|
+
"tone",
|
|
1186
|
+
"title",
|
|
1187
|
+
"titleId",
|
|
1188
|
+
"children",
|
|
1189
|
+
"action",
|
|
1190
|
+
"onDismiss",
|
|
1191
|
+
"className",
|
|
1192
|
+
"role",
|
|
1193
|
+
"icon"
|
|
1194
|
+
]);
|
|
1195
|
+
const role = props.role || (tone2 === "danger" || tone2 === "warning" ? "alert" : "status");
|
|
1196
|
+
const titled = !!props.title && role !== "none" && !props["aria-label"] && !props["aria-labelledby"];
|
|
1197
|
+
const titleId = props.titleId || (props.id ? props.id + "-title" : autoId);
|
|
1198
|
+
const text = typeof props.title === "string" || typeof props.title === "number" ? String(props.title) : void 0;
|
|
1185
1199
|
return /* @__PURE__ */ React3.createElement(
|
|
1186
1200
|
"div",
|
|
1187
1201
|
{
|
|
1188
1202
|
...rest,
|
|
1189
1203
|
ref,
|
|
1190
1204
|
className: cx("aura-alert", "aura-alert--" + tone2, props.className),
|
|
1191
|
-
role
|
|
1205
|
+
role,
|
|
1206
|
+
"aria-labelledby": titled && titleId ? titleId : props["aria-labelledby"],
|
|
1207
|
+
"aria-label": titled && !titleId && text ? text : props["aria-label"]
|
|
1192
1208
|
},
|
|
1193
1209
|
/* @__PURE__ */ React3.createElement(Icon, { name: props.icon || h2(ALERT_ICON[tone2]), className: "aura-alert__icon" }),
|
|
1194
|
-
/* @__PURE__ */ React3.createElement("div", { className: "aura-alert__body" }, props.title ? /* @__PURE__ */ React3.createElement("p", { className: "aura-alert__title" }, props.title) : null, props.children ? /* @__PURE__ */ React3.createElement("div", { className: "aura-alert__text" }, props.children) : null, props.action ? /* @__PURE__ */ React3.createElement("div", { className: "aura-alert__action" }, props.action) : null),
|
|
1210
|
+
/* @__PURE__ */ React3.createElement("div", { className: "aura-alert__body" }, props.title ? /* @__PURE__ */ React3.createElement("p", { className: "aura-alert__title", id: titled ? titleId : void 0 }, props.title) : null, props.children ? /* @__PURE__ */ React3.createElement("div", { className: "aura-alert__text" }, props.children) : null, props.action ? /* @__PURE__ */ React3.createElement("div", { className: "aura-alert__action" }, props.action) : null),
|
|
1195
1211
|
close
|
|
1196
1212
|
);
|
|
1197
1213
|
}
|
package/dist/server/index.d.cts
CHANGED
|
@@ -63,7 +63,12 @@ export interface AlertProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>,
|
|
|
63
63
|
role?: "alert" | "status" | "note" | "none" | undefined;
|
|
64
64
|
/** Replaces the tone's icon (5.8): a name or your own element; always hidden from screen readers. */
|
|
65
65
|
icon?: IconInput | undefined;
|
|
66
|
+
/** With a `role` other than `none`, the Alert is named by its title (5.57, Chamber-OS 170: `aria-labelledby`), unless
|
|
67
|
+
* you pass `aria-label` or `aria-labelledby`. */
|
|
66
68
|
title?: React$1.ReactNode | undefined;
|
|
69
|
+
/** id for the title element (default: generated, or `id` + `-title`). The server entry has no generated ids: pass
|
|
70
|
+
* `id` or `titleId` there for a title that isn't plain text. */
|
|
71
|
+
titleId?: string | undefined;
|
|
67
72
|
children?: React$1.ReactNode | undefined;
|
|
68
73
|
/** Usually a secondary Button. */
|
|
69
74
|
action?: React$1.ReactNode | undefined;
|
package/dist/server/index.d.ts
CHANGED
|
@@ -63,7 +63,12 @@ export interface AlertProps extends Omit<React$1.HTMLAttributes<HTMLDivElement>,
|
|
|
63
63
|
role?: "alert" | "status" | "note" | "none" | undefined;
|
|
64
64
|
/** Replaces the tone's icon (5.8): a name or your own element; always hidden from screen readers. */
|
|
65
65
|
icon?: IconInput | undefined;
|
|
66
|
+
/** With a `role` other than `none`, the Alert is named by its title (5.57, Chamber-OS 170: `aria-labelledby`), unless
|
|
67
|
+
* you pass `aria-label` or `aria-labelledby`. */
|
|
66
68
|
title?: React$1.ReactNode | undefined;
|
|
69
|
+
/** id for the title element (default: generated, or `id` + `-title`). The server entry has no generated ids: pass
|
|
70
|
+
* `id` or `titleId` there for a title that isn't plain text. */
|
|
71
|
+
titleId?: string | undefined;
|
|
67
72
|
children?: React$1.ReactNode | undefined;
|
|
68
73
|
/** Usually a secondary Button. */
|
|
69
74
|
action?: React$1.ReactNode | undefined;
|
package/dist/server/index.js
CHANGED
|
@@ -1114,19 +1114,35 @@ var ALERT_ICON = {
|
|
|
1114
1114
|
warning: IconTriangleAlert,
|
|
1115
1115
|
danger: IconCircleAlert
|
|
1116
1116
|
};
|
|
1117
|
-
function alertElement(props, ref, close) {
|
|
1117
|
+
function alertElement(props, ref, close, autoId) {
|
|
1118
1118
|
const tone2 = props.tone || "info";
|
|
1119
|
-
const rest = omit(props, [
|
|
1119
|
+
const rest = omit(props, [
|
|
1120
|
+
"tone",
|
|
1121
|
+
"title",
|
|
1122
|
+
"titleId",
|
|
1123
|
+
"children",
|
|
1124
|
+
"action",
|
|
1125
|
+
"onDismiss",
|
|
1126
|
+
"className",
|
|
1127
|
+
"role",
|
|
1128
|
+
"icon"
|
|
1129
|
+
]);
|
|
1130
|
+
const role = props.role || (tone2 === "danger" || tone2 === "warning" ? "alert" : "status");
|
|
1131
|
+
const titled = !!props.title && role !== "none" && !props["aria-label"] && !props["aria-labelledby"];
|
|
1132
|
+
const titleId = props.titleId || (props.id ? props.id + "-title" : autoId);
|
|
1133
|
+
const text = typeof props.title === "string" || typeof props.title === "number" ? String(props.title) : void 0;
|
|
1120
1134
|
return /* @__PURE__ */ React3.createElement(
|
|
1121
1135
|
"div",
|
|
1122
1136
|
{
|
|
1123
1137
|
...rest,
|
|
1124
1138
|
ref,
|
|
1125
1139
|
className: cx("aura-alert", "aura-alert--" + tone2, props.className),
|
|
1126
|
-
role
|
|
1140
|
+
role,
|
|
1141
|
+
"aria-labelledby": titled && titleId ? titleId : props["aria-labelledby"],
|
|
1142
|
+
"aria-label": titled && !titleId && text ? text : props["aria-label"]
|
|
1127
1143
|
},
|
|
1128
1144
|
/* @__PURE__ */ React3.createElement(Icon, { name: props.icon || h2(ALERT_ICON[tone2]), className: "aura-alert__icon" }),
|
|
1129
|
-
/* @__PURE__ */ React3.createElement("div", { className: "aura-alert__body" }, props.title ? /* @__PURE__ */ React3.createElement("p", { className: "aura-alert__title" }, props.title) : null, props.children ? /* @__PURE__ */ React3.createElement("div", { className: "aura-alert__text" }, props.children) : null, props.action ? /* @__PURE__ */ React3.createElement("div", { className: "aura-alert__action" }, props.action) : null),
|
|
1145
|
+
/* @__PURE__ */ React3.createElement("div", { className: "aura-alert__body" }, props.title ? /* @__PURE__ */ React3.createElement("p", { className: "aura-alert__title", id: titled ? titleId : void 0 }, props.title) : null, props.children ? /* @__PURE__ */ React3.createElement("div", { className: "aura-alert__text" }, props.children) : null, props.action ? /* @__PURE__ */ React3.createElement("div", { className: "aura-alert__action" }, props.action) : null),
|
|
1130
1146
|
close
|
|
1131
1147
|
);
|
|
1132
1148
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jirawatpyk/aura-react",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.57.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",
|