@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.
@@ -810,6 +810,8 @@ var Menu = React6.forwardRef(function Menu2(props, ref) {
810
810
  const pos = posState[0], setPos = posState[1];
811
811
  const items2 = props.items || [];
812
812
  const mounted = useMounted();
813
+ const headerId = uid();
814
+ const hasHeader = props.header != null && props.header !== false && props.header !== "";
813
815
  const Link = useLinkComponent(props.linkComponent);
814
816
  useIsoLayoutEffect(
815
817
  function() {
@@ -827,7 +829,20 @@ var Menu = React6.forwardRef(function Menu2(props, ref) {
827
829
  const left = Math.max(8, Math.min(r.right - mw, window.innerWidth - mw - 8));
828
830
  setPos({ top, left, maxHeight });
829
831
  },
830
- [props.anchor, mounted]
832
+ [props.anchor, mounted, hasHeader]
833
+ );
834
+ const hadHeader = React6.useRef(hasHeader);
835
+ React6.useEffect(
836
+ function() {
837
+ if (hadHeader.current === hasHeader) return;
838
+ hadHeader.current = hasHeader;
839
+ const a = document.activeElement;
840
+ if (own.current && (!a || a === document.body)) {
841
+ const first = own.current.querySelector('[role^="menuitem"]:not([disabled])');
842
+ if (first) first.focus();
843
+ }
844
+ },
845
+ [hasHeader]
831
846
  );
832
847
  React6.useEffect(
833
848
  function() {
@@ -853,22 +868,22 @@ var Menu = React6.forwardRef(function Menu2(props, ref) {
853
868
  [mounted]
854
869
  );
855
870
  function onKeyDown(e) {
856
- const list = Array.prototype.slice.call(
871
+ const list2 = Array.prototype.slice.call(
857
872
  own.current.querySelectorAll('[role^="menuitem"]:not([disabled])')
858
873
  );
859
- const i = list.indexOf(document.activeElement);
874
+ const i = list2.indexOf(document.activeElement);
860
875
  if (e.key === "ArrowDown") {
861
876
  e.preventDefault();
862
- list[(i + 1) % list.length].focus();
877
+ list2[(i + 1) % list2.length].focus();
863
878
  } else if (e.key === "ArrowUp") {
864
879
  e.preventDefault();
865
- list[(i - 1 + list.length) % list.length].focus();
880
+ list2[(i - 1 + list2.length) % list2.length].focus();
866
881
  } else if (e.key === "Home") {
867
882
  e.preventDefault();
868
- list[0].focus();
883
+ list2[0].focus();
869
884
  } else if (e.key === "End") {
870
885
  e.preventDefault();
871
- list[list.length - 1].focus();
886
+ list2[list2.length - 1].focus();
872
887
  } else if (e.key === " " && document.activeElement && document.activeElement.tagName === "A") {
873
888
  e.preventDefault();
874
889
  document.activeElement.click();
@@ -880,9 +895,9 @@ var Menu = React6.forwardRef(function Menu2(props, ref) {
880
895
  }
881
896
  e.stopPropagation();
882
897
  }
883
- function groupItems(list) {
898
+ function groupItems(list2) {
884
899
  const out = [];
885
- list.forEach(function(it, i) {
900
+ list2.forEach(function(it, i) {
886
901
  const g = it.type === "radio" && it.group ? it.group : null;
887
902
  const last = out[out.length - 1];
888
903
  if (last && last.group === g && g !== null) last.items.push({ it, i });
@@ -937,27 +952,28 @@ var Menu = React6.forwardRef(function Menu2(props, ref) {
937
952
  body
938
953
  );
939
954
  }
940
- const el = /* @__PURE__ */ React6.createElement(
955
+ const style = {
956
+ top: pos ? pos.top : -9999,
957
+ left: pos ? pos.left : -9999,
958
+ maxHeight: pos && pos.maxHeight ? pos.maxHeight : void 0
959
+ };
960
+ const list = groupItems(items2).map(function(block, bi) {
961
+ const rendered = block.items.map(function(x) {
962
+ return renderItem(x.it, x.i);
963
+ });
964
+ 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);
965
+ });
966
+ const el = hasHeader ? /* @__PURE__ */ React6.createElement("div", { ref: merged, className: "aura-menu has-header", onKeyDown, style }, /* @__PURE__ */ React6.createElement(
941
967
  "div",
942
968
  {
943
- ref: merged,
944
- role: "menu",
945
- "aria-label": props.label,
946
- className: "aura-menu",
947
- onKeyDown,
948
- style: {
949
- top: pos ? pos.top : -9999,
950
- left: pos ? pos.left : -9999,
951
- maxHeight: pos && pos.maxHeight ? pos.maxHeight : void 0
969
+ className: "aura-menu__header",
970
+ id: headerId,
971
+ onMouseDown: function(e) {
972
+ e.preventDefault();
952
973
  }
953
974
  },
954
- groupItems(items2).map(function(block, bi) {
955
- const rendered = block.items.map(function(x) {
956
- return renderItem(x.it, x.i);
957
- });
958
- 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);
959
- })
960
- );
975
+ props.header
976
+ ), /* @__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);
961
977
  return mounted ? (0, import_react_dom.createPortal)(el, document.body) : null;
962
978
  });
963
979
 
@@ -997,6 +1013,7 @@ var DropdownMenu = React7.forwardRef(function DropdownMenu2(props, ref) {
997
1013
  label: props.label,
998
1014
  items: props.items,
999
1015
  linkComponent: props.linkComponent,
1016
+ header: props.header,
1000
1017
  onClose: function(restore) {
1001
1018
  setAnchor(null);
1002
1019
  if (restore && typeof anchor.focus === "function") anchor.focus();
@@ -3061,10 +3078,35 @@ toast.dismiss = function(id) {
3061
3078
  promote();
3062
3079
  emitToasts();
3063
3080
  };
3081
+ var hotkeyOrigin = /* @__PURE__ */ new WeakMap();
3082
+ function outsideToaster(el) {
3083
+ return el && el !== document.body && !el.closest(".aura-toaster") ? el : null;
3084
+ }
3064
3085
  function ToastItem(props) {
3065
3086
  const str = useStrings();
3087
+ const Link = useLinkComponent();
3088
+ const node = React19.useRef(null);
3089
+ const origin = React19.useRef(null);
3090
+ useIsoLayoutEffect(function() {
3091
+ origin.current = outsideToaster(document.activeElement);
3092
+ const el = node.current;
3093
+ return function() {
3094
+ if (!el || !el.contains(document.activeElement)) return;
3095
+ const back = [hotkeyOrigin.get(el), origin.current].filter(function(b) {
3096
+ return !!b && b.isConnected;
3097
+ })[0];
3098
+ hotkeyOrigin.delete(el);
3099
+ setTimeout(function() {
3100
+ if (back && back.isConnected && (!document.activeElement || document.activeElement === document.body))
3101
+ back.focus();
3102
+ }, 0);
3103
+ };
3104
+ }, []);
3066
3105
  const t = props.toast, timer = React19.useRef(null), left = React19.useRef(t.duration || 5e3), since = React19.useRef(0);
3067
- const hover = React19.useRef(false);
3106
+ const hover = React19.useRef(false), focused = React19.useRef(false);
3107
+ function syncFocus() {
3108
+ if (focused.current && !(node.current && node.current.contains(document.activeElement))) focused.current = false;
3109
+ }
3068
3110
  function start() {
3069
3111
  if (left.current === Infinity || timer.current) return;
3070
3112
  since.current = Date.now();
@@ -3073,11 +3115,10 @@ function ToastItem(props) {
3073
3115
  }, left.current);
3074
3116
  }
3075
3117
  function resume() {
3076
- hover.current = false;
3077
- start();
3118
+ syncFocus();
3119
+ if (!hover.current && !focused.current) start();
3078
3120
  }
3079
3121
  function pause() {
3080
- hover.current = true;
3081
3122
  if (timer.current) {
3082
3123
  clearTimeout(timer.current);
3083
3124
  timer.current = null;
@@ -3089,23 +3130,56 @@ function ToastItem(props) {
3089
3130
  if (timer.current) clearTimeout(timer.current);
3090
3131
  timer.current = null;
3091
3132
  left.current = t.duration || 5e3;
3092
- if (!hover.current) start();
3133
+ syncFocus();
3134
+ if (!hover.current && !focused.current) start();
3093
3135
  return function() {
3094
3136
  if (timer.current) clearTimeout(timer.current);
3095
3137
  };
3096
3138
  },
3097
3139
  [t.rev]
3098
3140
  );
3141
+ const rich = t.description != null && typeof t.description !== "boolean" && t.description !== "";
3142
+ const actions = (t.actions && t.actions.length ? t.actions : t.action ? [t.action] : []).slice(0, 2);
3143
+ function run(a) {
3144
+ if (a.onClick) a.onClick();
3145
+ if (a.dismiss !== false) toast.dismiss(t.id);
3146
+ }
3099
3147
  return /* @__PURE__ */ React19.createElement(
3100
3148
  "div",
3101
3149
  {
3102
- className: cx("aura-toast", "aura-toast--" + t.tone, t.loading && "is-loading"),
3150
+ ref: node,
3151
+ onKeyDown: function(e) {
3152
+ if (e.key === "Escape") {
3153
+ e.stopPropagation();
3154
+ toast.dismiss(t.id);
3155
+ }
3156
+ },
3157
+ className: cx(
3158
+ "aura-toast",
3159
+ "aura-toast--" + t.tone,
3160
+ t.loading && "is-loading",
3161
+ /* Two actions, or one beside a description, go on their own row under the text so it keeps its width. */
3162
+ (actions.length > 1 || actions.length && rich) && "has-action-row"
3163
+ ),
3103
3164
  role: t.tone === "danger" ? "alert" : "status",
3104
3165
  "aria-busy": t.loading || void 0,
3105
- onMouseEnter: pause,
3106
- onMouseLeave: resume,
3107
- onFocus: pause,
3108
- onBlur: resume
3166
+ onMouseEnter: function() {
3167
+ hover.current = true;
3168
+ pause();
3169
+ },
3170
+ onMouseLeave: function() {
3171
+ hover.current = false;
3172
+ resume();
3173
+ },
3174
+ onFocus: function() {
3175
+ focused.current = true;
3176
+ pause();
3177
+ },
3178
+ onBlur: function(e) {
3179
+ if (node.current && e.relatedTarget && node.current.contains(e.relatedTarget)) return;
3180
+ focused.current = false;
3181
+ resume();
3182
+ }
3109
3183
  },
3110
3184
  /* @__PURE__ */ React19.createElement(
3111
3185
  Icon,
@@ -3114,19 +3188,33 @@ function ToastItem(props) {
3114
3188
  className: cx("aura-toast__icon", t.loading && "aura-spin")
3115
3189
  }
3116
3190
  ),
3117
- /* @__PURE__ */ React19.createElement("div", { className: "aura-toast__body" }, /* @__PURE__ */ React19.createElement("p", { className: "aura-toast__title" }, t.title), t.description ? /* @__PURE__ */ React19.createElement("p", { className: "aura-toast__text" }, t.description) : null),
3118
- t.action ? /* @__PURE__ */ React19.createElement(
3119
- "button",
3120
- {
3121
- type: "button",
3122
- className: "aura-toast__action",
3123
- onClick: function() {
3124
- t.action.onClick && t.action.onClick();
3125
- toast.dismiss(t.id);
3126
- }
3127
- },
3128
- t.action.label
3129
- ) : null,
3191
+ /* @__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),
3192
+ actions.length ? /* @__PURE__ */ React19.createElement("div", { className: "aura-toast__actions" }, actions.map(function(a, i) {
3193
+ return a.href ? /* @__PURE__ */ React19.createElement(
3194
+ Link,
3195
+ {
3196
+ key: i,
3197
+ href: a.href,
3198
+ className: "aura-toast__action",
3199
+ onClick: function(e) {
3200
+ if (plainClick(e)) run(a);
3201
+ else if (a.onClick) a.onClick();
3202
+ }
3203
+ },
3204
+ a.label
3205
+ ) : /* @__PURE__ */ React19.createElement(
3206
+ "button",
3207
+ {
3208
+ key: i,
3209
+ type: "button",
3210
+ className: "aura-toast__action",
3211
+ onClick: function() {
3212
+ run(a);
3213
+ }
3214
+ },
3215
+ a.label
3216
+ );
3217
+ })) : null,
3130
3218
  /* @__PURE__ */ React19.createElement(
3131
3219
  IconButton,
3132
3220
  {
@@ -3140,7 +3228,22 @@ function ToastItem(props) {
3140
3228
  )
3141
3229
  );
3142
3230
  }
3143
- function Toaster(props) {
3231
+ function hotkeyMatcher(spec) {
3232
+ const parts = spec.split("+").map(function(p) {
3233
+ return p.trim().toLowerCase();
3234
+ });
3235
+ const key = parts[parts.length - 1] || "";
3236
+ const code = /^[a-z]$/.test(key) ? "Key" + key.toUpperCase() : /^[0-9]$/.test(key) ? "Digit" + key : null;
3237
+ const want = function(m) {
3238
+ return parts.indexOf(m) >= 0 && parts.indexOf(m) < parts.length - 1;
3239
+ };
3240
+ return function(e) {
3241
+ if (e.altKey !== want("alt") || e.ctrlKey !== want("ctrl") || e.shiftKey !== want("shift") || e.metaKey !== (want("meta") || want("cmd")))
3242
+ return false;
3243
+ return code ? e.code === code : e.key.toLowerCase() === key;
3244
+ };
3245
+ }
3246
+ function Toaster(props = {}) {
3144
3247
  const t = useStrings();
3145
3248
  const mounted = useMounted();
3146
3249
  const s = React19.useState(toastState.list);
@@ -3153,15 +3256,49 @@ function Toaster(props) {
3153
3256
  });
3154
3257
  };
3155
3258
  }, []);
3259
+ const region = React19.useRef(null);
3260
+ const hotkey = props.hotkey === void 0 ? "Alt+T" : props.hotkey;
3261
+ React19.useEffect(
3262
+ function() {
3263
+ if (!hotkey) return;
3264
+ const match = hotkeyMatcher(hotkey);
3265
+ function onKey(e) {
3266
+ if (!e.key || e.repeat || e.isComposing || !match(e) || !region.current) return;
3267
+ const el = e.target;
3268
+ const editable = !!el && (el.isContentEditable || /^(INPUT|TEXTAREA)$/.test(el.tagName || ""));
3269
+ const mac = /Mac|iPhone|iPad|iPod/.test(navigator.platform || navigator.userAgent || "");
3270
+ if (editable && mac && e.altKey && !e.ctrlKey && !e.metaKey && e.key.length === 1) return;
3271
+ const items2 = region.current.querySelectorAll(".aura-toast");
3272
+ const last = items2[items2.length - 1];
3273
+ if (!last) return;
3274
+ const target = last.querySelector(".aura-toast__action") || last.querySelector("button");
3275
+ if (!target) return;
3276
+ e.preventDefault();
3277
+ const from = outsideToaster(document.activeElement);
3278
+ if (from) hotkeyOrigin.set(last, from);
3279
+ target.focus();
3280
+ }
3281
+ document.addEventListener("keydown", onKey);
3282
+ return function() {
3283
+ document.removeEventListener("keydown", onKey);
3284
+ };
3285
+ },
3286
+ [hotkey]
3287
+ );
3156
3288
  if (!mounted) return null;
3289
+ const pos = props.position || "bottom";
3290
+ const offset = props.offset;
3157
3291
  return (0, import_react_dom5.createPortal)(
3158
3292
  /* @__PURE__ */ React19.createElement(
3159
3293
  "div",
3160
3294
  {
3161
- className: cx("aura-toaster", props && props.position === "top" && "is-top"),
3295
+ ref: region,
3296
+ className: cx("aura-toaster", pos.indexOf("top") === 0 && "is-top", /center$/.test(pos) && "is-center"),
3297
+ style: offset != null ? { "--aura-toaster-offset": typeof offset === "number" ? offset + "px" : offset } : void 0,
3162
3298
  role: "region",
3163
3299
  "aria-live": "polite",
3164
- "aria-label": t.notifications
3300
+ "aria-label": hotkey ? t.notifications + " (" + hotkey + ")" : t.notifications,
3301
+ "aria-keyshortcuts": hotkey || void 0
3165
3302
  },
3166
3303
  s[0].map(function(t2) {
3167
3304
  return /* @__PURE__ */ React19.createElement(ToastItem, { key: t2.id, toast: t2 });
@@ -3876,6 +4013,7 @@ var Dialog = React27.forwardRef(function Dialog2(props, ref) {
3876
4013
  function close() {
3877
4014
  if (props.dismissible !== false && props.onClose) props.onClose();
3878
4015
  }
4016
+ const scrimCloses = props.dismissible !== false && (props.dismissOnScrim !== void 0 ? props.dismissOnScrim : props.role !== "alertdialog");
3879
4017
  const modal = useModal(props.open, own, {
3880
4018
  autoFocus: props.autoFocus,
3881
4019
  onEscape: close,
@@ -3884,7 +4022,17 @@ var Dialog = React27.forwardRef(function Dialog2(props, ref) {
3884
4022
  });
3885
4023
  if (!modal.ready) return null;
3886
4024
  return (0, import_react_dom8.createPortal)(
3887
- /* @__PURE__ */ React27.createElement("div", { className: "aura-dialog-layer", "data-density": density, onKeyDown: modal.onKeyDown }, /* @__PURE__ */ React27.createElement("div", { className: "aura-scrim", onClick: close, "aria-hidden": true }), /* @__PURE__ */ React27.createElement(
4025
+ /* @__PURE__ */ React27.createElement("div", { className: "aura-dialog-layer", "data-density": density, onKeyDown: modal.onKeyDown }, /* @__PURE__ */ React27.createElement(
4026
+ "div",
4027
+ {
4028
+ className: "aura-scrim",
4029
+ onClick: scrimCloses ? close : void 0,
4030
+ onMouseDown: scrimCloses ? void 0 : function(e) {
4031
+ e.preventDefault();
4032
+ },
4033
+ "aria-hidden": true
4034
+ }
4035
+ ), /* @__PURE__ */ React27.createElement(
3888
4036
  "div",
3889
4037
  {
3890
4038
  ref: merged,
@@ -3918,8 +4066,19 @@ var Drawer = React27.forwardRef(function Drawer2(props, ref) {
3918
4066
  });
3919
4067
  if (!modal.ready) return null;
3920
4068
  const side = props.side === "left" ? "left" : "right";
4069
+ const drawerScrimCloses = props.dismissible !== false && props.dismissOnScrim !== false;
3921
4070
  return (0, import_react_dom8.createPortal)(
3922
- /* @__PURE__ */ React27.createElement("div", { className: "aura-dialog-layer aura-drawer-layer", "data-density": density, onKeyDown: modal.onKeyDown }, /* @__PURE__ */ React27.createElement("div", { className: "aura-scrim", onClick: close, "aria-hidden": true }), /* @__PURE__ */ React27.createElement(
4071
+ /* @__PURE__ */ React27.createElement("div", { className: "aura-dialog-layer aura-drawer-layer", "data-density": density, onKeyDown: modal.onKeyDown }, /* @__PURE__ */ React27.createElement(
4072
+ "div",
4073
+ {
4074
+ className: "aura-scrim",
4075
+ onClick: drawerScrimCloses ? close : void 0,
4076
+ onMouseDown: !drawerScrimCloses ? function(e) {
4077
+ e.preventDefault();
4078
+ } : void 0,
4079
+ "aria-hidden": true
4080
+ }
4081
+ ), /* @__PURE__ */ React27.createElement(
3923
4082
  "div",
3924
4083
  {
3925
4084
  ref: merged,
@@ -3989,7 +4148,27 @@ var DataTableImpl = React28.forwardRef(function DataTable(props, ref) {
3989
4148
  );
3990
4149
  const sort = sortState[0], setSort = sortState[1];
3991
4150
  const selState = useMaybeControlled(props.selected, props.defaultSelected || [], props.onSelectionChange);
3992
- const selected = selState[0], setSelected = selState[1];
4151
+ const canSelect = function(r) {
4152
+ return !!r && (!props.isRowSelectable || !!props.isRowSelectable(r));
4153
+ };
4154
+ const rejected = {};
4155
+ if (props.isRowSelectable)
4156
+ rows.forEach(function(r) {
4157
+ if (!canSelect(r)) rejected[String(r[rowKey])] = true;
4158
+ });
4159
+ const selected = selState[0].filter(function(k) {
4160
+ return !rejected[String(k)];
4161
+ }), setSelected = selState[1];
4162
+ const droppedSig = selState[0].length === selected.length ? "" : "#" + selState[0].filter(function(k) {
4163
+ return rejected[String(k)];
4164
+ }).join("\0") + "#" + selected.join("\0");
4165
+ React28.useEffect(
4166
+ function() {
4167
+ if (droppedSig !== "") setSelected(selected);
4168
+ },
4169
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4170
+ [droppedSig]
4171
+ );
3993
4172
  const pageState = useMaybeControlled(
3994
4173
  props.page,
3995
4174
  props.defaultPage || 1,
@@ -4400,7 +4579,7 @@ var DataTableImpl = React28.forwardRef(function DataTable(props, ref) {
4400
4579
  el.focus();
4401
4580
  }
4402
4581
  }
4403
- const pageKeys = pageRows.map(function(r) {
4582
+ const pageKeys = pageRows.filter(canSelect).map(function(r) {
4404
4583
  return r[rowKey];
4405
4584
  });
4406
4585
  const selSet = {};
@@ -4664,10 +4843,12 @@ var DataTableImpl = React28.forwardRef(function DataTable(props, ref) {
4664
4843
  if (inner) inner.focus();
4665
4844
  else handled = false;
4666
4845
  } else if (k === " " || k === "Enter") {
4667
- if (r === 0 && !col && selectable && nRows) toggleAll();
4668
- else if (r === 0 && col && col.sortable && canSortAny) sortBy(col.key);
4669
- else if (r > 0 && k === " " && selectable) toggle(row[rowKey], !selSet[row[rowKey]]);
4670
- else if (r > 0 && k === "Enter" && rowHref && !target.querySelector("button, a[href]:not(.aura-table__row-link), input, select, textarea"))
4846
+ if (r === 0 && !col && selectable && nRows) {
4847
+ if (pageKeys.length) toggleAll();
4848
+ } else if (r === 0 && col && col.sortable && canSortAny) sortBy(col.key);
4849
+ else if (r > 0 && k === " " && selectable) {
4850
+ if (canSelect(row)) toggle(row[rowKey], !selSet[row[rowKey]]);
4851
+ } else if (r > 0 && k === "Enter" && rowHref && !target.querySelector("button, a[href]:not(.aura-table__row-link), input, select, textarea"))
4671
4852
  followRow(target.closest('[role="row"]'), e);
4672
4853
  else if (r > 0 && k === "Enter" && target.querySelector("button, a[href], input, select, textarea"))
4673
4854
  target.querySelector("button, a[href], input, select, textarea").focus();
@@ -4696,7 +4877,7 @@ var DataTableImpl = React28.forwardRef(function DataTable(props, ref) {
4696
4877
  activeState[1]({ r: 0, c: 0 });
4697
4878
  }
4698
4879
  },
4699
- nRows ? /* @__PURE__ */ React28.createElement(
4880
+ pageKeys.length ? /* @__PURE__ */ React28.createElement(
4700
4881
  Checkbox,
4701
4882
  {
4702
4883
  hideLabel: true,
@@ -4707,7 +4888,7 @@ var DataTableImpl = React28.forwardRef(function DataTable(props, ref) {
4707
4888
  onChange: toggleAll
4708
4889
  }
4709
4890
  ) : null,
4710
- nRows ? /* @__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)
4891
+ 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)
4711
4892
  )
4712
4893
  );
4713
4894
  vis.forEach(function(c, i) {
@@ -4845,12 +5026,12 @@ var DataTableImpl = React28.forwardRef(function DataTable(props, ref) {
4845
5026
  className: cx("aura-table__sel", nPinned && "is-pinned"),
4846
5027
  tabIndex: tabFor(ri, 0),
4847
5028
  "data-rc": ri + ":0",
4848
- "aria-label": t.selectRow(k),
5029
+ "aria-label": canSelect(r) ? t.selectRow(k) : props.rowSelectDisabledLabel ? props.rowSelectDisabledLabel(r) : void 0,
4849
5030
  onFocus: function(e) {
4850
5031
  if (e.target === e.currentTarget) activeState[1]({ r: ri, c: 0 });
4851
5032
  }
4852
5033
  },
4853
- /* @__PURE__ */ React28.createElement(
5034
+ canSelect(r) ? /* @__PURE__ */ React28.createElement(
4854
5035
  Checkbox,
4855
5036
  {
4856
5037
  hideLabel: true,
@@ -4861,7 +5042,7 @@ var DataTableImpl = React28.forwardRef(function DataTable(props, ref) {
4861
5042
  toggle(k, on);
4862
5043
  }
4863
5044
  }
4864
- )
5045
+ ) : null
4865
5046
  )
4866
5047
  );
4867
5048
  vis.forEach(function(c, j) {
@@ -4964,7 +5145,7 @@ var DataTableImpl = React28.forwardRef(function DataTable(props, ref) {
4964
5145
  key: k,
4965
5146
  role: "row",
4966
5147
  "aria-rowindex": first + i + 2,
4967
- "aria-selected": selectable ? isSel : void 0,
5148
+ "aria-selected": selectable && canSelect(r) ? isSel : void 0,
4968
5149
  className: cx(
4969
5150
  "aura-table__row",
4970
5151
  isSel && "is-selected",
@@ -5566,7 +5747,10 @@ var Breadcrumb = React32.forwardRef(function Breadcrumb2(props, ref) {
5566
5747
  const items2 = props.items || [];
5567
5748
  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) {
5568
5749
  const last = i === items2.length - 1;
5569
- 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), last ? null : /* @__PURE__ */ React32.createElement(Icon, { name: "chevron-right", size: 12, className: "aura-crumbs__sep" }));
5750
+ 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) : (
5751
+ /* 5.7: a segment with no page and no action is text, not a button that does nothing. */
5752
+ /* @__PURE__ */ React32.createElement("span", { className: "aura-crumbs__text" }, it.label)
5753
+ ), last ? null : /* @__PURE__ */ React32.createElement(Icon, { name: "chevron-right", size: 12, className: "aura-crumbs__sep" }));
5570
5754
  })));
5571
5755
  });
5572
5756
 
@@ -5761,7 +5945,7 @@ var AppShell = React38.forwardRef(function AppShell2(props, ref) {
5761
5945
  },
5762
5946
  "aria-expanded": open
5763
5947
  }
5764
- ) : 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));
5948
+ ) : 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));
5765
5949
  });
5766
5950
 
5767
5951
  // src/ActionBar.tsx
@@ -5916,8 +6100,11 @@ var BottomNav = React42.forwardRef(function BottomNav2(props, ref) {
5916
6100
  /* @__PURE__ */ React42.createElement("ul", { className: "aura-bottomnav__list" }, props.items.map(function(it) {
5917
6101
  const on = active === it.id;
5918
6102
  const count = it.count != null && it.count > 0 ? it.count > 99 ? "99+" : String(it.count) : null;
6103
+ const suffix = count || it.badge && it.badgeLabel ? " (" + (count || it.badgeLabel) + ")" : "";
5919
6104
  const common = {
5920
6105
  className: cx("aura-bottomnav__item", on && "is-active"),
6106
+ /* 5.7: a full name when the label is shortened; the count / badge words still follow. */
6107
+ "aria-label": it.ariaLabel ? it.ariaLabel + suffix : void 0,
5921
6108
  "aria-current": on ? "page" : void 0,
5922
6109
  onClick: function(e) {
5923
6110
  if (!it.href) e.preventDefault();
@@ -5928,7 +6115,7 @@ var BottomNav = React42.forwardRef(function BottomNav2(props, ref) {
5928
6115
  const inner = [
5929
6116
  /* @__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),
5930
6117
  /* @__PURE__ */ React42.createElement("span", { key: "l", className: "aura-bottomnav__label" }, it.label),
5931
- count || it.badge && it.badgeLabel ? /* @__PURE__ */ React42.createElement("span", { key: "s", className: "aura-sr-only" }, " (" + (count || it.badgeLabel) + ")") : null
6118
+ suffix && !it.ariaLabel ? /* @__PURE__ */ React42.createElement("span", { key: "s", className: "aura-sr-only" }, suffix) : null
5932
6119
  ];
5933
6120
  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));
5934
6121
  }))
@@ -59,7 +59,7 @@ const AppShell = React.forwardRef(function AppShell2(props, ref) {
59
59
  },
60
60
  "aria-expanded": open
61
61
  }
62
- ) : null, /* @__PURE__ */ React.createElement("div", { className: "aura-shell__bar-content" }, props.header)) : null, /* @__PURE__ */ React.createElement("main", { className: "aura-shell__content", id: props.mainId || "main" }, props.children), props.bottomNav || null));
62
+ ) : null, /* @__PURE__ */ React.createElement("div", { className: "aura-shell__bar-content" }, props.header)) : null, /* @__PURE__ */ React.createElement("main", { className: "aura-shell__content", id: props.mainId || "main", tabIndex: -1 }, props.children), props.bottomNav || null));
63
63
  });
64
64
  export {
65
65
  AppShell
@@ -23,8 +23,11 @@ const BottomNav = React.forwardRef(function BottomNav2(props, ref) {
23
23
  /* @__PURE__ */ React.createElement("ul", { className: "aura-bottomnav__list" }, props.items.map(function(it) {
24
24
  const on = active === it.id;
25
25
  const count = it.count != null && it.count > 0 ? it.count > 99 ? "99+" : String(it.count) : null;
26
+ const suffix = count || it.badge && it.badgeLabel ? " (" + (count || it.badgeLabel) + ")" : "";
26
27
  const common = {
27
28
  className: cx("aura-bottomnav__item", on && "is-active"),
29
+ /* 5.7: a full name when the label is shortened; the count / badge words still follow. */
30
+ "aria-label": it.ariaLabel ? it.ariaLabel + suffix : void 0,
28
31
  "aria-current": on ? "page" : void 0,
29
32
  onClick: function(e) {
30
33
  if (!it.href) e.preventDefault();
@@ -35,7 +38,7 @@ const BottomNav = React.forwardRef(function BottomNav2(props, ref) {
35
38
  const inner = [
36
39
  /* @__PURE__ */ React.createElement("span", { key: "i", className: "aura-bottomnav__icon" }, /* @__PURE__ */ React.createElement(Icon, { name: it.icon, size: "md" }), count ? /* @__PURE__ */ React.createElement("span", { className: "aura-bottomnav__count", "aria-hidden": "true" }, count) : it.badge ? /* @__PURE__ */ React.createElement("span", { className: "aura-bottomnav__dot", "aria-hidden": "true" }) : null),
37
40
  /* @__PURE__ */ React.createElement("span", { key: "l", className: "aura-bottomnav__label" }, it.label),
38
- count || it.badge && it.badgeLabel ? /* @__PURE__ */ React.createElement("span", { key: "s", className: "aura-sr-only" }, " (" + (count || it.badgeLabel) + ")") : null
41
+ suffix && !it.ariaLabel ? /* @__PURE__ */ React.createElement("span", { key: "s", className: "aura-sr-only" }, suffix) : null
39
42
  ];
40
43
  return /* @__PURE__ */ React.createElement("li", { key: it.id, className: "aura-bottomnav__cell" }, it.href ? /* @__PURE__ */ React.createElement(Link, { href: it.href, ...common }, inner) : /* @__PURE__ */ React.createElement("button", { type: "button", ...common }, inner));
41
44
  }))
@@ -9,7 +9,10 @@ const Breadcrumb = React.forwardRef(function Breadcrumb2(props, ref) {
9
9
  const items = props.items || [];
10
10
  return /* @__PURE__ */ React.createElement("nav", { ref, "aria-label": props.label || t.breadcrumb, className: cx("aura-crumbs", props.className) }, /* @__PURE__ */ React.createElement("ol", null, items.map(function(it, i) {
11
11
  const last = i === items.length - 1;
12
- return /* @__PURE__ */ React.createElement("li", { key: i }, last ? /* @__PURE__ */ React.createElement("span", { "aria-current": "page", className: "aura-crumbs__current" }, it.label) : it.href ? /* @__PURE__ */ React.createElement(Link, { href: it.href, onClick: it.onClick }, it.label) : /* @__PURE__ */ React.createElement("button", { type: "button", onClick: it.onClick }, it.label), last ? null : /* @__PURE__ */ React.createElement(Icon, { name: "chevron-right", size: 12, className: "aura-crumbs__sep" }));
12
+ return /* @__PURE__ */ React.createElement("li", { key: i }, last ? /* @__PURE__ */ React.createElement("span", { "aria-current": "page", className: "aura-crumbs__current" }, it.label) : it.href ? /* @__PURE__ */ React.createElement(Link, { href: it.href, onClick: it.onClick }, it.label) : it.onClick ? /* @__PURE__ */ React.createElement("button", { type: "button", onClick: it.onClick }, it.label) : (
13
+ /* 5.7: a segment with no page and no action is text, not a button that does nothing. */
14
+ /* @__PURE__ */ React.createElement("span", { className: "aura-crumbs__text" }, it.label)
15
+ ), last ? null : /* @__PURE__ */ React.createElement(Icon, { name: "chevron-right", size: 12, className: "aura-crumbs__sep" }));
13
16
  })));
14
17
  });
15
18
  export {