@jirawatpyk/aura-react 5.5.0 → 5.7.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 +28 -2
- package/dist/aura.bundle.js +256 -69
- package/dist/cjs/index.cjs +256 -69
- package/dist/esm/AppShell.js +1 -1
- package/dist/esm/BottomNav.js +4 -1
- package/dist/esm/Breadcrumb.js +4 -1
- package/dist/esm/DataTable.js +34 -12
- package/dist/esm/Dialog.js +24 -2
- package/dist/esm/DropdownMenu.js +1 -0
- package/dist/esm/Menu.js +43 -27
- package/dist/esm/Toaster.js +148 -28
- package/dist/index.d.cts +48 -10
- package/dist/index.d.ts +48 -10
- package/dist/styles.css +37 -4
- package/dist/styles.layer.css +37 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -186,13 +186,39 @@ 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.7 — Chamber-OS addendum 5 (shell details)
|
|
190
|
+
|
|
191
|
+
- **DropdownMenu `header`**: content above the items, e.g. name, email and role in an account menu. It sits outside `role="menu"` (arrow keys, Home/End skip it; clicking it keeps focus on the item) and is the menu's accessible description (`aria-describedby`). Screen readers differ in whether they speak a menu's description on open; keep the essentials (who is signed in) in the trigger's name too if they must be heard. With a header, the menu's `ref` and `.aura-menu` are the outer box and `role="menu"` is `.aura-menu__list` inside it.
|
|
192
|
+
- **Breadcrumb**: an item with neither `href` nor `onClick` is plain text (`.aura-crumbs__text`), not a button that does nothing.
|
|
193
|
+
- **AppShell** `<main>` has `tabIndex={-1}`, so a skip link or `document.getElementById(mainId)?.focus({ preventScroll: true })` moves focus there when the row you acted on leaves the list. No ring is drawn on the landmark.
|
|
194
|
+
- **Dialog / Drawer `dismissOnScrim`**: `false` keeps it open on a scrim click; Escape and the close button still close it, and focus stays inside. **`role="alertdialog"` now defaults to `false`**, so a stray click outside a confirmation doesn't throw away a typed reason; pass `dismissOnScrim` to get the old behaviour.
|
|
195
|
+
- **BottomNav item `ariaLabel`**: the full name when the visible label is shortened (`label="Konto"`, `ariaLabel="Mitt konto"`); the count or badge words still follow. Include the visible text in it (WCAG 2.5.3).
|
|
196
|
+
- **SideNav** rows are 44px on touch screens (AppShell's phone drawer); 36px with a mouse.
|
|
197
|
+
|
|
198
|
+
## 5.6 — Chamber-OS addendum 4 (selectable rows, richer toasts)
|
|
199
|
+
|
|
200
|
+
- **DataTable** `isRowSelectable={(r) => r.status === 'Awaiting review'}`: a row it rejects shows no checkbox (the cell stays, so columns line up), and select-all, Space, the "N selected" count and `onSelectionChange` skip it. A rejected key passed in through `selected` is never shown as selected and is dropped from your state with one `onSelectionChange` call. `rowSelectDisabledLabel={(r) => …}` names the empty cell for screen readers. Server HTML has no checkbox for those rows.
|
|
201
|
+
- **Toasts**: `description` takes JSX (lines with their own links, read once in the live region); `actions` (up to two; two, or one under a description, go on their own row below the text); an action with `href` is a link through `linkComponent` (Cmd/Ctrl-click opens a tab and keeps the toast); `dismiss: false` keeps the toast open after its action. Escape closes the toast under focus.
|
|
202
|
+
- **Toaster** `position="top-center"` (or `bottom-center`, `top-right`, `bottom-right`) and `offset={64}` (or `--aura-toaster-offset`) to clear a top bar, plus the safe-area inset; below 640px toasts still span the width.
|
|
203
|
+
- **Alt+T** (`hotkey`, matched on the physical key so macOS Option+T works; `false` turns it off) focuses the newest toast's action, else its close button, and pauses its timer while focus stays inside (moving the mouse away doesn't restart it); the region's name and `aria-keyshortcuts` say the shortcut. It matches the key position, so it works on Thai and other layouts; in a text field on macOS, where Option+T types "†", it is left to the field.
|
|
204
|
+
- **Focus comes back**: when a toast holding focus closes (its action ran, Escape, the close button), focus returns to where it was before — the element Alt+T was pressed on, else the one focused when the toast appeared — instead of falling to `<body>`.
|
|
205
|
+
- **Touch**: toast actions get a 44px hit area on coarse pointers, as IconButton does (links in the text get a little padding; a 44px box would overlap the next line). Bottom toasters add the bottom safe-area inset too.
|
|
206
|
+
|
|
189
207
|
## 5.5 — DataTable is generic over its rows
|
|
190
208
|
|
|
191
209
|
- The type of `rows` is the table's row type, and every `render`, `sortValue`, `getRowHref` and `onRowActivate` gets it — no annotations, and a typo inside a callback (`r.amuont`) or a callback written for another type is a compile error (column `key`s stay plain strings):
|
|
192
210
|
|
|
193
211
|
```tsx
|
|
194
|
-
const columns: DataTableColumn<Order>[] = [
|
|
195
|
-
|
|
212
|
+
const columns: DataTableColumn<Order>[] = [
|
|
213
|
+
{ key: 'amount', label: 'AMOUNT', align: 'end', render: (r) => baht(r.amount) },
|
|
214
|
+
];
|
|
215
|
+
<DataTable
|
|
216
|
+
label="Orders"
|
|
217
|
+
rows={orders}
|
|
218
|
+
columns={columns}
|
|
219
|
+
onRowActivate={setDetail}
|
|
220
|
+
getRowHref={(r) => '/orders/' + r.id}
|
|
221
|
+
/>;
|
|
196
222
|
```
|
|
197
223
|
|
|
198
224
|
- `DataTableColumn<Row>` types a column list declared on its own; `<DataTable<Order> …>` names the type explicitly. `rows={[]}` (nothing loaded yet) keeps the untyped default, and so do `any[]`, `Record<string, any>[]` and anything reading `typeof DataTable` (`ComponentProps`, `memo`, wrappers).
|
package/dist/aura.bundle.js
CHANGED
|
@@ -828,6 +828,8 @@ window.Aura = (() => {
|
|
|
828
828
|
const pos = posState[0], setPos = posState[1];
|
|
829
829
|
const items2 = props.items || [];
|
|
830
830
|
const mounted = useMounted();
|
|
831
|
+
const headerId = uid();
|
|
832
|
+
const hasHeader = props.header != null && props.header !== false && props.header !== "";
|
|
831
833
|
const Link = useLinkComponent(props.linkComponent);
|
|
832
834
|
useIsoLayoutEffect(
|
|
833
835
|
function() {
|
|
@@ -845,7 +847,20 @@ window.Aura = (() => {
|
|
|
845
847
|
const left = Math.max(8, Math.min(r.right - mw, window.innerWidth - mw - 8));
|
|
846
848
|
setPos({ top, left, maxHeight });
|
|
847
849
|
},
|
|
848
|
-
[props.anchor, mounted]
|
|
850
|
+
[props.anchor, mounted, hasHeader]
|
|
851
|
+
);
|
|
852
|
+
const hadHeader = React6.useRef(hasHeader);
|
|
853
|
+
React6.useEffect(
|
|
854
|
+
function() {
|
|
855
|
+
if (hadHeader.current === hasHeader) return;
|
|
856
|
+
hadHeader.current = hasHeader;
|
|
857
|
+
const a = document.activeElement;
|
|
858
|
+
if (own.current && (!a || a === document.body)) {
|
|
859
|
+
const first = own.current.querySelector('[role^="menuitem"]:not([disabled])');
|
|
860
|
+
if (first) first.focus();
|
|
861
|
+
}
|
|
862
|
+
},
|
|
863
|
+
[hasHeader]
|
|
849
864
|
);
|
|
850
865
|
React6.useEffect(
|
|
851
866
|
function() {
|
|
@@ -871,22 +886,22 @@ window.Aura = (() => {
|
|
|
871
886
|
[mounted]
|
|
872
887
|
);
|
|
873
888
|
function onKeyDown(e) {
|
|
874
|
-
const
|
|
889
|
+
const list2 = Array.prototype.slice.call(
|
|
875
890
|
own.current.querySelectorAll('[role^="menuitem"]:not([disabled])')
|
|
876
891
|
);
|
|
877
|
-
const i =
|
|
892
|
+
const i = list2.indexOf(document.activeElement);
|
|
878
893
|
if (e.key === "ArrowDown") {
|
|
879
894
|
e.preventDefault();
|
|
880
|
-
|
|
895
|
+
list2[(i + 1) % list2.length].focus();
|
|
881
896
|
} else if (e.key === "ArrowUp") {
|
|
882
897
|
e.preventDefault();
|
|
883
|
-
|
|
898
|
+
list2[(i - 1 + list2.length) % list2.length].focus();
|
|
884
899
|
} else if (e.key === "Home") {
|
|
885
900
|
e.preventDefault();
|
|
886
|
-
|
|
901
|
+
list2[0].focus();
|
|
887
902
|
} else if (e.key === "End") {
|
|
888
903
|
e.preventDefault();
|
|
889
|
-
|
|
904
|
+
list2[list2.length - 1].focus();
|
|
890
905
|
} else if (e.key === " " && document.activeElement && document.activeElement.tagName === "A") {
|
|
891
906
|
e.preventDefault();
|
|
892
907
|
document.activeElement.click();
|
|
@@ -898,9 +913,9 @@ window.Aura = (() => {
|
|
|
898
913
|
}
|
|
899
914
|
e.stopPropagation();
|
|
900
915
|
}
|
|
901
|
-
function groupItems(
|
|
916
|
+
function groupItems(list2) {
|
|
902
917
|
const out = [];
|
|
903
|
-
|
|
918
|
+
list2.forEach(function(it, i) {
|
|
904
919
|
const g = it.type === "radio" && it.group ? it.group : null;
|
|
905
920
|
const last = out[out.length - 1];
|
|
906
921
|
if (last && last.group === g && g !== null) last.items.push({ it, i });
|
|
@@ -955,27 +970,28 @@ window.Aura = (() => {
|
|
|
955
970
|
body
|
|
956
971
|
);
|
|
957
972
|
}
|
|
958
|
-
const
|
|
973
|
+
const style = {
|
|
974
|
+
top: pos ? pos.top : -9999,
|
|
975
|
+
left: pos ? pos.left : -9999,
|
|
976
|
+
maxHeight: pos && pos.maxHeight ? pos.maxHeight : void 0
|
|
977
|
+
};
|
|
978
|
+
const list = groupItems(items2).map(function(block, bi) {
|
|
979
|
+
const rendered = block.items.map(function(x) {
|
|
980
|
+
return renderItem(x.it, x.i);
|
|
981
|
+
});
|
|
982
|
+
return block.group ? /* @__PURE__ */ React6.createElement("div", { key: "g" + bi, role: "group", "aria-label": block.group, className: "aura-menu__group" }, rendered) : /* @__PURE__ */ React6.createElement(React6.Fragment, { key: "f" + bi }, rendered);
|
|
983
|
+
});
|
|
984
|
+
const el = hasHeader ? /* @__PURE__ */ React6.createElement("div", { ref: merged, className: "aura-menu has-header", onKeyDown, style }, /* @__PURE__ */ React6.createElement(
|
|
959
985
|
"div",
|
|
960
986
|
{
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
onKeyDown,
|
|
966
|
-
style: {
|
|
967
|
-
top: pos ? pos.top : -9999,
|
|
968
|
-
left: pos ? pos.left : -9999,
|
|
969
|
-
maxHeight: pos && pos.maxHeight ? pos.maxHeight : void 0
|
|
987
|
+
className: "aura-menu__header",
|
|
988
|
+
id: headerId,
|
|
989
|
+
onMouseDown: function(e) {
|
|
990
|
+
e.preventDefault();
|
|
970
991
|
}
|
|
971
992
|
},
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
return renderItem(x.it, x.i);
|
|
975
|
-
});
|
|
976
|
-
return block.group ? /* @__PURE__ */ React6.createElement("div", { key: "g" + bi, role: "group", "aria-label": block.group, className: "aura-menu__group" }, rendered) : /* @__PURE__ */ React6.createElement(React6.Fragment, { key: "f" + bi }, rendered);
|
|
977
|
-
})
|
|
978
|
-
);
|
|
993
|
+
props.header
|
|
994
|
+
), /* @__PURE__ */ React6.createElement("div", { role: "menu", "aria-label": props.label, "aria-describedby": headerId, className: "aura-menu__list" }, list)) : /* @__PURE__ */ React6.createElement("div", { ref: merged, role: "menu", "aria-label": props.label, className: "aura-menu", onKeyDown, style }, list);
|
|
979
995
|
return mounted ? (0, import_react_dom.createPortal)(el, document.body) : null;
|
|
980
996
|
});
|
|
981
997
|
|
|
@@ -1015,6 +1031,7 @@ window.Aura = (() => {
|
|
|
1015
1031
|
label: props.label,
|
|
1016
1032
|
items: props.items,
|
|
1017
1033
|
linkComponent: props.linkComponent,
|
|
1034
|
+
header: props.header,
|
|
1018
1035
|
onClose: function(restore) {
|
|
1019
1036
|
setAnchor(null);
|
|
1020
1037
|
if (restore && typeof anchor.focus === "function") anchor.focus();
|
|
@@ -3079,10 +3096,35 @@ window.Aura = (() => {
|
|
|
3079
3096
|
promote();
|
|
3080
3097
|
emitToasts();
|
|
3081
3098
|
};
|
|
3099
|
+
var hotkeyOrigin = /* @__PURE__ */ new WeakMap();
|
|
3100
|
+
function outsideToaster(el) {
|
|
3101
|
+
return el && el !== document.body && !el.closest(".aura-toaster") ? el : null;
|
|
3102
|
+
}
|
|
3082
3103
|
function ToastItem(props) {
|
|
3083
3104
|
const str = useStrings();
|
|
3105
|
+
const Link = useLinkComponent();
|
|
3106
|
+
const node = React19.useRef(null);
|
|
3107
|
+
const origin = React19.useRef(null);
|
|
3108
|
+
useIsoLayoutEffect(function() {
|
|
3109
|
+
origin.current = outsideToaster(document.activeElement);
|
|
3110
|
+
const el = node.current;
|
|
3111
|
+
return function() {
|
|
3112
|
+
if (!el || !el.contains(document.activeElement)) return;
|
|
3113
|
+
const back = [hotkeyOrigin.get(el), origin.current].filter(function(b) {
|
|
3114
|
+
return !!b && b.isConnected;
|
|
3115
|
+
})[0];
|
|
3116
|
+
hotkeyOrigin.delete(el);
|
|
3117
|
+
setTimeout(function() {
|
|
3118
|
+
if (back && back.isConnected && (!document.activeElement || document.activeElement === document.body))
|
|
3119
|
+
back.focus();
|
|
3120
|
+
}, 0);
|
|
3121
|
+
};
|
|
3122
|
+
}, []);
|
|
3084
3123
|
const t = props.toast, timer = React19.useRef(null), left = React19.useRef(t.duration || 5e3), since = React19.useRef(0);
|
|
3085
|
-
const hover = React19.useRef(false);
|
|
3124
|
+
const hover = React19.useRef(false), focused = React19.useRef(false);
|
|
3125
|
+
function syncFocus() {
|
|
3126
|
+
if (focused.current && !(node.current && node.current.contains(document.activeElement))) focused.current = false;
|
|
3127
|
+
}
|
|
3086
3128
|
function start() {
|
|
3087
3129
|
if (left.current === Infinity || timer.current) return;
|
|
3088
3130
|
since.current = Date.now();
|
|
@@ -3091,11 +3133,10 @@ window.Aura = (() => {
|
|
|
3091
3133
|
}, left.current);
|
|
3092
3134
|
}
|
|
3093
3135
|
function resume() {
|
|
3094
|
-
|
|
3095
|
-
start();
|
|
3136
|
+
syncFocus();
|
|
3137
|
+
if (!hover.current && !focused.current) start();
|
|
3096
3138
|
}
|
|
3097
3139
|
function pause() {
|
|
3098
|
-
hover.current = true;
|
|
3099
3140
|
if (timer.current) {
|
|
3100
3141
|
clearTimeout(timer.current);
|
|
3101
3142
|
timer.current = null;
|
|
@@ -3107,23 +3148,56 @@ window.Aura = (() => {
|
|
|
3107
3148
|
if (timer.current) clearTimeout(timer.current);
|
|
3108
3149
|
timer.current = null;
|
|
3109
3150
|
left.current = t.duration || 5e3;
|
|
3110
|
-
|
|
3151
|
+
syncFocus();
|
|
3152
|
+
if (!hover.current && !focused.current) start();
|
|
3111
3153
|
return function() {
|
|
3112
3154
|
if (timer.current) clearTimeout(timer.current);
|
|
3113
3155
|
};
|
|
3114
3156
|
},
|
|
3115
3157
|
[t.rev]
|
|
3116
3158
|
);
|
|
3159
|
+
const rich = t.description != null && typeof t.description !== "boolean" && t.description !== "";
|
|
3160
|
+
const actions = (t.actions && t.actions.length ? t.actions : t.action ? [t.action] : []).slice(0, 2);
|
|
3161
|
+
function run(a) {
|
|
3162
|
+
if (a.onClick) a.onClick();
|
|
3163
|
+
if (a.dismiss !== false) toast.dismiss(t.id);
|
|
3164
|
+
}
|
|
3117
3165
|
return /* @__PURE__ */ React19.createElement(
|
|
3118
3166
|
"div",
|
|
3119
3167
|
{
|
|
3120
|
-
|
|
3168
|
+
ref: node,
|
|
3169
|
+
onKeyDown: function(e) {
|
|
3170
|
+
if (e.key === "Escape") {
|
|
3171
|
+
e.stopPropagation();
|
|
3172
|
+
toast.dismiss(t.id);
|
|
3173
|
+
}
|
|
3174
|
+
},
|
|
3175
|
+
className: cx(
|
|
3176
|
+
"aura-toast",
|
|
3177
|
+
"aura-toast--" + t.tone,
|
|
3178
|
+
t.loading && "is-loading",
|
|
3179
|
+
/* Two actions, or one beside a description, go on their own row under the text so it keeps its width. */
|
|
3180
|
+
(actions.length > 1 || actions.length && rich) && "has-action-row"
|
|
3181
|
+
),
|
|
3121
3182
|
role: t.tone === "danger" ? "alert" : "status",
|
|
3122
3183
|
"aria-busy": t.loading || void 0,
|
|
3123
|
-
onMouseEnter:
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3184
|
+
onMouseEnter: function() {
|
|
3185
|
+
hover.current = true;
|
|
3186
|
+
pause();
|
|
3187
|
+
},
|
|
3188
|
+
onMouseLeave: function() {
|
|
3189
|
+
hover.current = false;
|
|
3190
|
+
resume();
|
|
3191
|
+
},
|
|
3192
|
+
onFocus: function() {
|
|
3193
|
+
focused.current = true;
|
|
3194
|
+
pause();
|
|
3195
|
+
},
|
|
3196
|
+
onBlur: function(e) {
|
|
3197
|
+
if (node.current && e.relatedTarget && node.current.contains(e.relatedTarget)) return;
|
|
3198
|
+
focused.current = false;
|
|
3199
|
+
resume();
|
|
3200
|
+
}
|
|
3127
3201
|
},
|
|
3128
3202
|
/* @__PURE__ */ React19.createElement(
|
|
3129
3203
|
Icon,
|
|
@@ -3132,19 +3206,33 @@ window.Aura = (() => {
|
|
|
3132
3206
|
className: cx("aura-toast__icon", t.loading && "aura-spin")
|
|
3133
3207
|
}
|
|
3134
3208
|
),
|
|
3135
|
-
/* @__PURE__ */ React19.createElement("div", { className: "aura-toast__body" }, /* @__PURE__ */ React19.createElement("p", { className: "aura-toast__title" }, t.title),
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3209
|
+
/* @__PURE__ */ React19.createElement("div", { className: "aura-toast__body" }, /* @__PURE__ */ React19.createElement("p", { className: "aura-toast__title" }, t.title), rich ? /* @__PURE__ */ React19.createElement("div", { className: "aura-toast__text" }, t.description) : null),
|
|
3210
|
+
actions.length ? /* @__PURE__ */ React19.createElement("div", { className: "aura-toast__actions" }, actions.map(function(a, i) {
|
|
3211
|
+
return a.href ? /* @__PURE__ */ React19.createElement(
|
|
3212
|
+
Link,
|
|
3213
|
+
{
|
|
3214
|
+
key: i,
|
|
3215
|
+
href: a.href,
|
|
3216
|
+
className: "aura-toast__action",
|
|
3217
|
+
onClick: function(e) {
|
|
3218
|
+
if (plainClick(e)) run(a);
|
|
3219
|
+
else if (a.onClick) a.onClick();
|
|
3220
|
+
}
|
|
3221
|
+
},
|
|
3222
|
+
a.label
|
|
3223
|
+
) : /* @__PURE__ */ React19.createElement(
|
|
3224
|
+
"button",
|
|
3225
|
+
{
|
|
3226
|
+
key: i,
|
|
3227
|
+
type: "button",
|
|
3228
|
+
className: "aura-toast__action",
|
|
3229
|
+
onClick: function() {
|
|
3230
|
+
run(a);
|
|
3231
|
+
}
|
|
3232
|
+
},
|
|
3233
|
+
a.label
|
|
3234
|
+
);
|
|
3235
|
+
})) : null,
|
|
3148
3236
|
/* @__PURE__ */ React19.createElement(
|
|
3149
3237
|
IconButton,
|
|
3150
3238
|
{
|
|
@@ -3158,7 +3246,22 @@ window.Aura = (() => {
|
|
|
3158
3246
|
)
|
|
3159
3247
|
);
|
|
3160
3248
|
}
|
|
3161
|
-
function
|
|
3249
|
+
function hotkeyMatcher(spec) {
|
|
3250
|
+
const parts = spec.split("+").map(function(p) {
|
|
3251
|
+
return p.trim().toLowerCase();
|
|
3252
|
+
});
|
|
3253
|
+
const key = parts[parts.length - 1] || "";
|
|
3254
|
+
const code = /^[a-z]$/.test(key) ? "Key" + key.toUpperCase() : /^[0-9]$/.test(key) ? "Digit" + key : null;
|
|
3255
|
+
const want = function(m) {
|
|
3256
|
+
return parts.indexOf(m) >= 0 && parts.indexOf(m) < parts.length - 1;
|
|
3257
|
+
};
|
|
3258
|
+
return function(e) {
|
|
3259
|
+
if (e.altKey !== want("alt") || e.ctrlKey !== want("ctrl") || e.shiftKey !== want("shift") || e.metaKey !== (want("meta") || want("cmd")))
|
|
3260
|
+
return false;
|
|
3261
|
+
return code ? e.code === code : e.key.toLowerCase() === key;
|
|
3262
|
+
};
|
|
3263
|
+
}
|
|
3264
|
+
function Toaster(props = {}) {
|
|
3162
3265
|
const t = useStrings();
|
|
3163
3266
|
const mounted = useMounted();
|
|
3164
3267
|
const s = React19.useState(toastState.list);
|
|
@@ -3171,15 +3274,49 @@ window.Aura = (() => {
|
|
|
3171
3274
|
});
|
|
3172
3275
|
};
|
|
3173
3276
|
}, []);
|
|
3277
|
+
const region = React19.useRef(null);
|
|
3278
|
+
const hotkey = props.hotkey === void 0 ? "Alt+T" : props.hotkey;
|
|
3279
|
+
React19.useEffect(
|
|
3280
|
+
function() {
|
|
3281
|
+
if (!hotkey) return;
|
|
3282
|
+
const match = hotkeyMatcher(hotkey);
|
|
3283
|
+
function onKey(e) {
|
|
3284
|
+
if (!e.key || e.repeat || e.isComposing || !match(e) || !region.current) return;
|
|
3285
|
+
const el = e.target;
|
|
3286
|
+
const editable = !!el && (el.isContentEditable || /^(INPUT|TEXTAREA)$/.test(el.tagName || ""));
|
|
3287
|
+
const mac = /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent || "");
|
|
3288
|
+
if (editable && mac && e.altKey && !e.ctrlKey && !e.metaKey && e.key.length === 1) return;
|
|
3289
|
+
const items2 = region.current.querySelectorAll(".aura-toast");
|
|
3290
|
+
const last = items2[items2.length - 1];
|
|
3291
|
+
if (!last) return;
|
|
3292
|
+
const target = last.querySelector(".aura-toast__action") || last.querySelector("button");
|
|
3293
|
+
if (!target) return;
|
|
3294
|
+
e.preventDefault();
|
|
3295
|
+
const from = outsideToaster(document.activeElement);
|
|
3296
|
+
if (from) hotkeyOrigin.set(last, from);
|
|
3297
|
+
target.focus();
|
|
3298
|
+
}
|
|
3299
|
+
document.addEventListener("keydown", onKey);
|
|
3300
|
+
return function() {
|
|
3301
|
+
document.removeEventListener("keydown", onKey);
|
|
3302
|
+
};
|
|
3303
|
+
},
|
|
3304
|
+
[hotkey]
|
|
3305
|
+
);
|
|
3174
3306
|
if (!mounted) return null;
|
|
3307
|
+
const pos = props.position || "bottom";
|
|
3308
|
+
const offset = props.offset;
|
|
3175
3309
|
return (0, import_react_dom5.createPortal)(
|
|
3176
3310
|
/* @__PURE__ */ React19.createElement(
|
|
3177
3311
|
"div",
|
|
3178
3312
|
{
|
|
3179
|
-
|
|
3313
|
+
ref: region,
|
|
3314
|
+
className: cx("aura-toaster", pos.indexOf("top") === 0 && "is-top", /center$/.test(pos) && "is-center"),
|
|
3315
|
+
style: offset != null ? { "--aura-toaster-offset": typeof offset === "number" ? offset + "px" : offset } : void 0,
|
|
3180
3316
|
role: "region",
|
|
3181
3317
|
"aria-live": "polite",
|
|
3182
|
-
"aria-label": t.notifications
|
|
3318
|
+
"aria-label": hotkey ? t.notifications + " (" + hotkey + ")" : t.notifications,
|
|
3319
|
+
"aria-keyshortcuts": hotkey || void 0
|
|
3183
3320
|
},
|
|
3184
3321
|
s[0].map(function(t2) {
|
|
3185
3322
|
return /* @__PURE__ */ React19.createElement(ToastItem, { key: t2.id, toast: t2 });
|
|
@@ -3894,6 +4031,7 @@ window.Aura = (() => {
|
|
|
3894
4031
|
function close() {
|
|
3895
4032
|
if (props.dismissible !== false && props.onClose) props.onClose();
|
|
3896
4033
|
}
|
|
4034
|
+
const scrimCloses = props.dismissible !== false && (props.dismissOnScrim !== void 0 ? props.dismissOnScrim : props.role !== "alertdialog");
|
|
3897
4035
|
const modal = useModal(props.open, own, {
|
|
3898
4036
|
autoFocus: props.autoFocus,
|
|
3899
4037
|
onEscape: close,
|
|
@@ -3902,7 +4040,17 @@ window.Aura = (() => {
|
|
|
3902
4040
|
});
|
|
3903
4041
|
if (!modal.ready) return null;
|
|
3904
4042
|
return (0, import_react_dom8.createPortal)(
|
|
3905
|
-
/* @__PURE__ */ React27.createElement("div", { className: "aura-dialog-layer", "data-density": density, onKeyDown: modal.onKeyDown }, /* @__PURE__ */ React27.createElement(
|
|
4043
|
+
/* @__PURE__ */ React27.createElement("div", { className: "aura-dialog-layer", "data-density": density, onKeyDown: modal.onKeyDown }, /* @__PURE__ */ React27.createElement(
|
|
4044
|
+
"div",
|
|
4045
|
+
{
|
|
4046
|
+
className: "aura-scrim",
|
|
4047
|
+
onClick: scrimCloses ? close : void 0,
|
|
4048
|
+
onMouseDown: scrimCloses ? void 0 : function(e) {
|
|
4049
|
+
e.preventDefault();
|
|
4050
|
+
},
|
|
4051
|
+
"aria-hidden": true
|
|
4052
|
+
}
|
|
4053
|
+
), /* @__PURE__ */ React27.createElement(
|
|
3906
4054
|
"div",
|
|
3907
4055
|
{
|
|
3908
4056
|
ref: merged,
|
|
@@ -3936,8 +4084,19 @@ window.Aura = (() => {
|
|
|
3936
4084
|
});
|
|
3937
4085
|
if (!modal.ready) return null;
|
|
3938
4086
|
const side = props.side === "left" ? "left" : "right";
|
|
4087
|
+
const drawerScrimCloses = props.dismissible !== false && props.dismissOnScrim !== false;
|
|
3939
4088
|
return (0, import_react_dom8.createPortal)(
|
|
3940
|
-
/* @__PURE__ */ React27.createElement("div", { className: "aura-dialog-layer aura-drawer-layer", "data-density": density, onKeyDown: modal.onKeyDown }, /* @__PURE__ */ React27.createElement(
|
|
4089
|
+
/* @__PURE__ */ React27.createElement("div", { className: "aura-dialog-layer aura-drawer-layer", "data-density": density, onKeyDown: modal.onKeyDown }, /* @__PURE__ */ React27.createElement(
|
|
4090
|
+
"div",
|
|
4091
|
+
{
|
|
4092
|
+
className: "aura-scrim",
|
|
4093
|
+
onClick: drawerScrimCloses ? close : void 0,
|
|
4094
|
+
onMouseDown: !drawerScrimCloses ? function(e) {
|
|
4095
|
+
e.preventDefault();
|
|
4096
|
+
} : void 0,
|
|
4097
|
+
"aria-hidden": true
|
|
4098
|
+
}
|
|
4099
|
+
), /* @__PURE__ */ React27.createElement(
|
|
3941
4100
|
"div",
|
|
3942
4101
|
{
|
|
3943
4102
|
ref: merged,
|
|
@@ -4007,7 +4166,27 @@ window.Aura = (() => {
|
|
|
4007
4166
|
);
|
|
4008
4167
|
const sort = sortState[0], setSort = sortState[1];
|
|
4009
4168
|
const selState = useMaybeControlled(props.selected, props.defaultSelected || [], props.onSelectionChange);
|
|
4010
|
-
const
|
|
4169
|
+
const canSelect = function(r) {
|
|
4170
|
+
return !!r && (!props.isRowSelectable || !!props.isRowSelectable(r));
|
|
4171
|
+
};
|
|
4172
|
+
const rejected = {};
|
|
4173
|
+
if (props.isRowSelectable)
|
|
4174
|
+
rows.forEach(function(r) {
|
|
4175
|
+
if (!canSelect(r)) rejected[String(r[rowKey])] = true;
|
|
4176
|
+
});
|
|
4177
|
+
const selected = selState[0].filter(function(k) {
|
|
4178
|
+
return !rejected[String(k)];
|
|
4179
|
+
}), setSelected = selState[1];
|
|
4180
|
+
const droppedSig = selState[0].length === selected.length ? "" : "#" + selState[0].filter(function(k) {
|
|
4181
|
+
return rejected[String(k)];
|
|
4182
|
+
}).join("\0") + "#" + selected.join("\0");
|
|
4183
|
+
React28.useEffect(
|
|
4184
|
+
function() {
|
|
4185
|
+
if (droppedSig !== "") setSelected(selected);
|
|
4186
|
+
},
|
|
4187
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
4188
|
+
[droppedSig]
|
|
4189
|
+
);
|
|
4011
4190
|
const pageState = useMaybeControlled(
|
|
4012
4191
|
props.page,
|
|
4013
4192
|
props.defaultPage || 1,
|
|
@@ -4418,7 +4597,7 @@ window.Aura = (() => {
|
|
|
4418
4597
|
el.focus();
|
|
4419
4598
|
}
|
|
4420
4599
|
}
|
|
4421
|
-
const pageKeys = pageRows.map(function(r) {
|
|
4600
|
+
const pageKeys = pageRows.filter(canSelect).map(function(r) {
|
|
4422
4601
|
return r[rowKey];
|
|
4423
4602
|
});
|
|
4424
4603
|
const selSet = {};
|
|
@@ -4682,10 +4861,12 @@ window.Aura = (() => {
|
|
|
4682
4861
|
if (inner) inner.focus();
|
|
4683
4862
|
else handled = false;
|
|
4684
4863
|
} else if (k === " " || k === "Enter") {
|
|
4685
|
-
if (r === 0 && !col && selectable && nRows)
|
|
4686
|
-
|
|
4687
|
-
else if (r
|
|
4688
|
-
else if (r > 0 && k === "
|
|
4864
|
+
if (r === 0 && !col && selectable && nRows) {
|
|
4865
|
+
if (pageKeys.length) toggleAll();
|
|
4866
|
+
} else if (r === 0 && col && col.sortable && canSortAny) sortBy(col.key);
|
|
4867
|
+
else if (r > 0 && k === " " && selectable) {
|
|
4868
|
+
if (canSelect(row)) toggle(row[rowKey], !selSet[row[rowKey]]);
|
|
4869
|
+
} else if (r > 0 && k === "Enter" && rowHref && !target.querySelector("button, a[href]:not(.aura-table__row-link), input, select, textarea"))
|
|
4689
4870
|
followRow(target.closest('[role="row"]'), e);
|
|
4690
4871
|
else if (r > 0 && k === "Enter" && target.querySelector("button, a[href], input, select, textarea"))
|
|
4691
4872
|
target.querySelector("button, a[href], input, select, textarea").focus();
|
|
@@ -4714,7 +4895,7 @@ window.Aura = (() => {
|
|
|
4714
4895
|
activeState[1]({ r: 0, c: 0 });
|
|
4715
4896
|
}
|
|
4716
4897
|
},
|
|
4717
|
-
|
|
4898
|
+
pageKeys.length ? /* @__PURE__ */ React28.createElement(
|
|
4718
4899
|
Checkbox,
|
|
4719
4900
|
{
|
|
4720
4901
|
hideLabel: true,
|
|
@@ -4725,7 +4906,7 @@ window.Aura = (() => {
|
|
|
4725
4906
|
onChange: toggleAll
|
|
4726
4907
|
}
|
|
4727
4908
|
) : null,
|
|
4728
|
-
|
|
4909
|
+
pageKeys.length ? /* @__PURE__ */ React28.createElement("span", { className: "aura-table__sel-text" }, nSel ? t.selectedCount(nSel) : t.selectAll) : /* @__PURE__ */ React28.createElement("span", { className: "aura-sr-only" }, t.selectRows)
|
|
4729
4910
|
)
|
|
4730
4911
|
);
|
|
4731
4912
|
vis.forEach(function(c, i) {
|
|
@@ -4863,12 +5044,12 @@ window.Aura = (() => {
|
|
|
4863
5044
|
className: cx("aura-table__sel", nPinned && "is-pinned"),
|
|
4864
5045
|
tabIndex: tabFor(ri, 0),
|
|
4865
5046
|
"data-rc": ri + ":0",
|
|
4866
|
-
"aria-label": t.selectRow(k),
|
|
5047
|
+
"aria-label": canSelect(r) ? t.selectRow(k) : props.rowSelectDisabledLabel ? props.rowSelectDisabledLabel(r) : void 0,
|
|
4867
5048
|
onFocus: function(e) {
|
|
4868
5049
|
if (e.target === e.currentTarget) activeState[1]({ r: ri, c: 0 });
|
|
4869
5050
|
}
|
|
4870
5051
|
},
|
|
4871
|
-
/* @__PURE__ */ React28.createElement(
|
|
5052
|
+
canSelect(r) ? /* @__PURE__ */ React28.createElement(
|
|
4872
5053
|
Checkbox,
|
|
4873
5054
|
{
|
|
4874
5055
|
hideLabel: true,
|
|
@@ -4879,7 +5060,7 @@ window.Aura = (() => {
|
|
|
4879
5060
|
toggle(k, on);
|
|
4880
5061
|
}
|
|
4881
5062
|
}
|
|
4882
|
-
)
|
|
5063
|
+
) : null
|
|
4883
5064
|
)
|
|
4884
5065
|
);
|
|
4885
5066
|
vis.forEach(function(c, j) {
|
|
@@ -4982,7 +5163,7 @@ window.Aura = (() => {
|
|
|
4982
5163
|
key: k,
|
|
4983
5164
|
role: "row",
|
|
4984
5165
|
"aria-rowindex": first + i + 2,
|
|
4985
|
-
"aria-selected": selectable ? isSel : void 0,
|
|
5166
|
+
"aria-selected": selectable && canSelect(r) ? isSel : void 0,
|
|
4986
5167
|
className: cx(
|
|
4987
5168
|
"aura-table__row",
|
|
4988
5169
|
isSel && "is-selected",
|
|
@@ -5584,7 +5765,10 @@ window.Aura = (() => {
|
|
|
5584
5765
|
const items2 = props.items || [];
|
|
5585
5766
|
return /* @__PURE__ */ React32.createElement("nav", { ref, "aria-label": props.label || t.breadcrumb, className: cx("aura-crumbs", props.className) }, /* @__PURE__ */ React32.createElement("ol", null, items2.map(function(it, i) {
|
|
5586
5767
|
const last = i === items2.length - 1;
|
|
5587
|
-
return /* @__PURE__ */ React32.createElement("li", { key: i }, last ? /* @__PURE__ */ React32.createElement("span", { "aria-current": "page", className: "aura-crumbs__current" }, it.label) : it.href ? /* @__PURE__ */ React32.createElement(Link, { href: it.href, onClick: it.onClick }, it.label) : /* @__PURE__ */ React32.createElement("button", { type: "button", onClick: it.onClick }, it.label)
|
|
5768
|
+
return /* @__PURE__ */ React32.createElement("li", { key: i }, last ? /* @__PURE__ */ React32.createElement("span", { "aria-current": "page", className: "aura-crumbs__current" }, it.label) : it.href ? /* @__PURE__ */ React32.createElement(Link, { href: it.href, onClick: it.onClick }, it.label) : it.onClick ? /* @__PURE__ */ React32.createElement("button", { type: "button", onClick: it.onClick }, it.label) : (
|
|
5769
|
+
/* 5.7: a segment with no page and no action is text, not a button that does nothing. */
|
|
5770
|
+
/* @__PURE__ */ React32.createElement("span", { className: "aura-crumbs__text" }, it.label)
|
|
5771
|
+
), last ? null : /* @__PURE__ */ React32.createElement(Icon, { name: "chevron-right", size: 12, className: "aura-crumbs__sep" }));
|
|
5588
5772
|
})));
|
|
5589
5773
|
});
|
|
5590
5774
|
|
|
@@ -5779,7 +5963,7 @@ window.Aura = (() => {
|
|
|
5779
5963
|
},
|
|
5780
5964
|
"aria-expanded": open
|
|
5781
5965
|
}
|
|
5782
|
-
) : null, /* @__PURE__ */ React38.createElement("div", { className: "aura-shell__bar-content" }, props.header)) : null, /* @__PURE__ */ React38.createElement("main", { className: "aura-shell__content", id: props.mainId || "main" }, props.children), props.bottomNav || null));
|
|
5966
|
+
) : null, /* @__PURE__ */ React38.createElement("div", { className: "aura-shell__bar-content" }, props.header)) : null, /* @__PURE__ */ React38.createElement("main", { className: "aura-shell__content", id: props.mainId || "main", tabIndex: -1 }, props.children), props.bottomNav || null));
|
|
5783
5967
|
});
|
|
5784
5968
|
|
|
5785
5969
|
// src/ActionBar.tsx
|
|
@@ -5934,8 +6118,11 @@ window.Aura = (() => {
|
|
|
5934
6118
|
/* @__PURE__ */ React42.createElement("ul", { className: "aura-bottomnav__list" }, props.items.map(function(it) {
|
|
5935
6119
|
const on = active === it.id;
|
|
5936
6120
|
const count = it.count != null && it.count > 0 ? it.count > 99 ? "99+" : String(it.count) : null;
|
|
6121
|
+
const suffix = count || it.badge && it.badgeLabel ? " (" + (count || it.badgeLabel) + ")" : "";
|
|
5937
6122
|
const common = {
|
|
5938
6123
|
className: cx("aura-bottomnav__item", on && "is-active"),
|
|
6124
|
+
/* 5.7: a full name when the label is shortened; the count / badge words still follow. */
|
|
6125
|
+
"aria-label": it.ariaLabel ? it.ariaLabel + suffix : void 0,
|
|
5939
6126
|
"aria-current": on ? "page" : void 0,
|
|
5940
6127
|
onClick: function(e) {
|
|
5941
6128
|
if (!it.href) e.preventDefault();
|
|
@@ -5946,7 +6133,7 @@ window.Aura = (() => {
|
|
|
5946
6133
|
const inner = [
|
|
5947
6134
|
/* @__PURE__ */ React42.createElement("span", { key: "i", className: "aura-bottomnav__icon" }, /* @__PURE__ */ React42.createElement(Icon, { name: it.icon, size: "md" }), count ? /* @__PURE__ */ React42.createElement("span", { className: "aura-bottomnav__count", "aria-hidden": "true" }, count) : it.badge ? /* @__PURE__ */ React42.createElement("span", { className: "aura-bottomnav__dot", "aria-hidden": "true" }) : null),
|
|
5948
6135
|
/* @__PURE__ */ React42.createElement("span", { key: "l", className: "aura-bottomnav__label" }, it.label),
|
|
5949
|
-
|
|
6136
|
+
suffix && !it.ariaLabel ? /* @__PURE__ */ React42.createElement("span", { key: "s", className: "aura-sr-only" }, suffix) : null
|
|
5950
6137
|
];
|
|
5951
6138
|
return /* @__PURE__ */ React42.createElement("li", { key: it.id, className: "aura-bottomnav__cell" }, it.href ? /* @__PURE__ */ React42.createElement(Link, { href: it.href, ...common }, inner) : /* @__PURE__ */ React42.createElement("button", { type: "button", ...common }, inner));
|
|
5952
6139
|
}))
|