@jirawatpyk/aura-react 5.9.0 → 5.10.1
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 +15 -0
- package/dist/aura.bundle.js +66 -20
- package/dist/cjs/index.cjs +66 -20
- package/dist/esm/DropdownMenu.js +1 -1
- package/dist/esm/Menu.js +35 -11
- package/dist/esm/Tabs.js +13 -7
- package/dist/esm/Tag.js +18 -2
- package/dist/index.d.cts +8 -0
- package/dist/index.d.ts +8 -0
- package/dist/styles.css +33 -2
- package/dist/styles.layer.css +33 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -186,6 +186,21 @@ 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.10.1 — fixes from a new project
|
|
190
|
+
|
|
191
|
+
- **Switch**: a disabled switch that is on ("always on", enforced by policy) no longer fades into the same grey as an off one. Disabled rows, on or off, now look alike and stay readable: the label turns `aura-fg-secondary`, the description (often the reason it's locked) keeps its colour, the row shows a not-allowed cursor, and only the switch fades — off to the disabled opacity, on to 0.75, at least 3:1 apart in both themes. In forced colours a locked switch is `GrayText`. Use it instead of a Badge for settings people can see but not change.
|
|
192
|
+
- **Tag**: the remove button is named from the words inside any children — `<Tag onRemove={…}><strong>Acme</strong> AB</Tag>` is "Remove Acme AB" (was "Remove "). With no text at all (an icon only), a dev notice asks for `removeLabel`.
|
|
193
|
+
- **SideNav** (docs): an item's `badge` takes any element, so a fault or warning is a toned Badge — `badge: <Badge tone="danger">Fault</Badge>`; `count` stays a neutral number.
|
|
194
|
+
|
|
195
|
+
## 5.10 — Chamber-OS addendum 10 (adopting 5.9)
|
|
196
|
+
|
|
197
|
+
- **Tabs `variant="segmented"`** (item 72): the tab list as a pill track with the selected tab raised — SegmentedControl's look — keeping every Tabs behaviour (tab / tabpanel roles, `keepMounted`, `activation`, `tabProps`). `fullWidth` stretches the track and shares it equally. Tabs are 44px on touch screens, the list doesn't scroll so the focus ring is never clipped, and in forced colours the selected tab gets a `Highlight` outline. Default (`underline`) output is unchanged.
|
|
198
|
+
```tsx
|
|
199
|
+
<Tabs label="Payment method" variant="segmented" fullWidth keepMounted activation="manual" … />
|
|
200
|
+
```
|
|
201
|
+
- **Disabled menu items stay reachable** (item 73): a disabled `MenuItem` is `aria-disabled` rather than a disabled button, so the arrow keys reach it and screen readers announce it as dimmed (WAI-ARIA APG); choosing it does nothing and keeps the menu open. `disabledReason` shows in place of the hint and is read with the item ("Again in 5 min"). A menu with nothing to focus takes focus itself, so Escape and Tab still close it and focus returns to the trigger. Enabled items are unchanged; tests that expected the arrows to skip a disabled item now land on it.
|
|
202
|
+
- **SegmentedControl boundary** (item 74): measured again — the selected pill's inset edge (`aura-border-control`, zinc-500) is 4.6:1 against the light track (zinc-50) and 5.8:1 in dark; CI now measures the rendered edge in both themes (≥3:1). A value near 2.5:1 is zinc-400, dark mode's `aura-border-control`: check that the light page isn't picking up the dark tokens (a `.dark` / `data-theme="dark"` ancestor, or a theme override).
|
|
203
|
+
|
|
189
204
|
## 5.9 — Chamber-OS addendum 9 (pay sheet)
|
|
190
205
|
|
|
191
206
|
- **Drawer** (item 70): other attributes (`id`, `data-*`, `aria-*`) go on the `.aura-drawer` panel; `closeLabel` names the close button and its tooltip after what it closes ("Close payment drawer" — pass it in the page's language); `closeProps` puts attributes on that button (`{ 'data-testid': 'pay-sheet-close' }`; its `onClick` runs first and can `preventDefault()` to keep the drawer open). Without them the output is as before; focus trap, Escape, scrim and focus return are unchanged.
|
package/dist/aura.bundle.js
CHANGED
|
@@ -1233,13 +1233,14 @@ window.Aura = (() => {
|
|
|
1233
1233
|
// src/Menu.tsx
|
|
1234
1234
|
var React8 = __toESM(require_react(), 1);
|
|
1235
1235
|
var import_react_dom = __toESM(require_react_dom(), 1);
|
|
1236
|
+
var ITEMS = '[role^="menuitem"]';
|
|
1236
1237
|
var Menu = React8.forwardRef(function Menu2(props, ref) {
|
|
1237
1238
|
const own = React8.useRef(null), merged = useMergedRef(ref, own);
|
|
1238
1239
|
const posState = React8.useState(null);
|
|
1239
1240
|
const pos = posState[0], setPos = posState[1];
|
|
1240
1241
|
const items2 = props.items || [];
|
|
1241
1242
|
const mounted = useMounted();
|
|
1242
|
-
const headerId = uid();
|
|
1243
|
+
const headerId = uid(), itemId = uid();
|
|
1243
1244
|
const hasHeader = props.header != null && props.header !== false && props.header !== "";
|
|
1244
1245
|
const Link = useLinkComponent(props.linkComponent);
|
|
1245
1246
|
useIsoLayoutEffect(
|
|
@@ -1267,8 +1268,8 @@ window.Aura = (() => {
|
|
|
1267
1268
|
hadHeader.current = hasHeader;
|
|
1268
1269
|
const a = document.activeElement;
|
|
1269
1270
|
if (own.current && (!a || a === document.body)) {
|
|
1270
|
-
const first = own.current.querySelector(
|
|
1271
|
-
|
|
1271
|
+
const first = own.current.querySelector(ITEMS);
|
|
1272
|
+
(first || own.current.querySelector('[role="menu"]') || own.current).focus();
|
|
1272
1273
|
}
|
|
1273
1274
|
},
|
|
1274
1275
|
[hasHeader]
|
|
@@ -1276,8 +1277,11 @@ window.Aura = (() => {
|
|
|
1276
1277
|
React8.useEffect(
|
|
1277
1278
|
function() {
|
|
1278
1279
|
if (!mounted) return;
|
|
1279
|
-
const first = own.current && own.current.querySelector(
|
|
1280
|
-
if (
|
|
1280
|
+
const first = own.current && own.current.querySelector(ITEMS);
|
|
1281
|
+
if (props.autoFocus !== false) {
|
|
1282
|
+
if (first) first.focus();
|
|
1283
|
+
else if (own.current) (own.current.querySelector('[role="menu"]') || own.current).focus();
|
|
1284
|
+
}
|
|
1281
1285
|
function outside(e) {
|
|
1282
1286
|
if (own.current && !own.current.contains(e.target) && !(props.anchor && props.anchor.contains(e.target)))
|
|
1283
1287
|
props.onClose(false);
|
|
@@ -1297,16 +1301,18 @@ window.Aura = (() => {
|
|
|
1297
1301
|
[mounted]
|
|
1298
1302
|
);
|
|
1299
1303
|
function onKeyDown(e) {
|
|
1300
|
-
const list2 = Array.prototype.slice.call(
|
|
1301
|
-
own.current.querySelectorAll('[role^="menuitem"]:not([disabled])')
|
|
1302
|
-
);
|
|
1304
|
+
const list2 = Array.prototype.slice.call(own.current.querySelectorAll(ITEMS));
|
|
1303
1305
|
const i = list2.indexOf(document.activeElement);
|
|
1306
|
+
if (!list2.length && e.key !== "Escape" && e.key !== "Tab") {
|
|
1307
|
+
e.stopPropagation();
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1304
1310
|
if (e.key === "ArrowDown") {
|
|
1305
1311
|
e.preventDefault();
|
|
1306
1312
|
list2[(i + 1) % list2.length].focus();
|
|
1307
1313
|
} else if (e.key === "ArrowUp") {
|
|
1308
1314
|
e.preventDefault();
|
|
1309
|
-
list2[(i - 1 + list2.length) % list2.length].focus();
|
|
1315
|
+
list2[i < 0 ? list2.length - 1 : (i - 1 + list2.length) % list2.length].focus();
|
|
1310
1316
|
} else if (e.key === "Home") {
|
|
1311
1317
|
e.preventDefault();
|
|
1312
1318
|
list2[0].focus();
|
|
@@ -1345,6 +1351,10 @@ window.Aura = (() => {
|
|
|
1345
1351
|
it.hint ? /* @__PURE__ */ React8.createElement("span", { key: "h", className: "aura-menu__hint" }, it.hint) : null
|
|
1346
1352
|
];
|
|
1347
1353
|
const cls = cx("aura-menu__item", it.tone === "danger" && "aura-menu__item--danger");
|
|
1354
|
+
const reasonId = it.disabled && it.disabledReason ? itemId + "-r" + i : void 0;
|
|
1355
|
+
if (reasonId)
|
|
1356
|
+
body[2] = /* Hidden from the name (it would be read twice); aria-describedby still reads it. */
|
|
1357
|
+
/* @__PURE__ */ React8.createElement("span", { key: "h", id: reasonId, className: "aura-menu__hint aura-menu__reason", "aria-hidden": true }, it.disabledReason);
|
|
1348
1358
|
if (it.href && !it.disabled)
|
|
1349
1359
|
return /* @__PURE__ */ React8.createElement(
|
|
1350
1360
|
Link,
|
|
@@ -1369,11 +1379,13 @@ window.Aura = (() => {
|
|
|
1369
1379
|
key: i,
|
|
1370
1380
|
type: "button",
|
|
1371
1381
|
tabIndex: -1,
|
|
1372
|
-
disabled: it.disabled,
|
|
1382
|
+
"aria-disabled": it.disabled ? true : void 0,
|
|
1383
|
+
"aria-describedby": reasonId,
|
|
1373
1384
|
role: isRadio ? "menuitemradio" : isCheck ? "menuitemcheckbox" : "menuitem",
|
|
1374
1385
|
"aria-checked": isRadio || isCheck ? !!it.checked : void 0,
|
|
1375
1386
|
className: cls,
|
|
1376
1387
|
onClick: function() {
|
|
1388
|
+
if (it.disabled) return;
|
|
1377
1389
|
if (it.onSelect) it.onSelect();
|
|
1378
1390
|
if (!it.keepOpen) props.onClose(true);
|
|
1379
1391
|
}
|
|
@@ -1402,7 +1414,19 @@ window.Aura = (() => {
|
|
|
1402
1414
|
}
|
|
1403
1415
|
},
|
|
1404
1416
|
props.header
|
|
1405
|
-
), /* @__PURE__ */ React8.createElement("div", { role: "menu", "aria-label": props.label, "aria-describedby": headerId, className: "aura-menu__list" }, list)) : /* @__PURE__ */ React8.createElement(
|
|
1417
|
+
), /* @__PURE__ */ React8.createElement("div", { role: "menu", tabIndex: -1, "aria-label": props.label, "aria-describedby": headerId, className: "aura-menu__list" }, list)) : /* @__PURE__ */ React8.createElement(
|
|
1418
|
+
"div",
|
|
1419
|
+
{
|
|
1420
|
+
ref: merged,
|
|
1421
|
+
role: "menu",
|
|
1422
|
+
tabIndex: -1,
|
|
1423
|
+
"aria-label": props.label,
|
|
1424
|
+
className: "aura-menu",
|
|
1425
|
+
onKeyDown,
|
|
1426
|
+
style
|
|
1427
|
+
},
|
|
1428
|
+
list
|
|
1429
|
+
);
|
|
1406
1430
|
return mounted ? (0, import_react_dom.createPortal)(el, document.body) : null;
|
|
1407
1431
|
});
|
|
1408
1432
|
|
|
@@ -1417,7 +1441,7 @@ window.Aura = (() => {
|
|
|
1417
1441
|
function() {
|
|
1418
1442
|
if (!anchor || !toLast.current || !menuRef.current) return;
|
|
1419
1443
|
toLast.current = false;
|
|
1420
|
-
const list = menuRef.current.querySelectorAll('[role^="menuitem"]
|
|
1444
|
+
const list = menuRef.current.querySelectorAll('[role^="menuitem"]');
|
|
1421
1445
|
if (list.length) list[list.length - 1].focus();
|
|
1422
1446
|
},
|
|
1423
1447
|
[anchor]
|
|
@@ -3859,6 +3883,16 @@ window.Aura = (() => {
|
|
|
3859
3883
|
|
|
3860
3884
|
// src/Tag.tsx
|
|
3861
3885
|
var React24 = __toESM(require_react(), 1);
|
|
3886
|
+
function textOf(node) {
|
|
3887
|
+
if (node == null || typeof node === "boolean") return "";
|
|
3888
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
3889
|
+
if (Array.isArray(node)) return node.map(textOf).join("");
|
|
3890
|
+
if (React24.isValidElement(node)) {
|
|
3891
|
+
const p = node.props;
|
|
3892
|
+
return p["aria-hidden"] === true || p["aria-hidden"] === "true" ? "" : textOf(p.children);
|
|
3893
|
+
}
|
|
3894
|
+
return "";
|
|
3895
|
+
}
|
|
3862
3896
|
var Tag = React24.forwardRef(function Tag2(props, ref) {
|
|
3863
3897
|
const t = useStrings();
|
|
3864
3898
|
const selectable = props.onClick != null || props.selected != null;
|
|
@@ -3882,12 +3916,18 @@ window.Aura = (() => {
|
|
|
3882
3916
|
inner[1]
|
|
3883
3917
|
);
|
|
3884
3918
|
}
|
|
3919
|
+
const name = props.onRemove && !props.removeLabel ? textOf(props.children).replace(/\s+/g, " ").trim() : "";
|
|
3920
|
+
if (props.onRemove && !props.disabled && !props.removeLabel && !name)
|
|
3921
|
+
devWarnOnce(
|
|
3922
|
+
"tag-remove-label",
|
|
3923
|
+
'Tag: the remove button has no name \u2014 its children have no text. Pass removeLabel (e.g. "Remove Acme AB").'
|
|
3924
|
+
);
|
|
3885
3925
|
return /* @__PURE__ */ React24.createElement("span", { ...rest, ref, className: cx("aura-tag", props.disabled && "is-disabled", props.className) }, inner, props.onRemove && !props.disabled ? /* @__PURE__ */ React24.createElement(
|
|
3886
3926
|
"button",
|
|
3887
3927
|
{
|
|
3888
3928
|
type: "button",
|
|
3889
3929
|
className: "aura-tag__remove",
|
|
3890
|
-
"aria-label": props.removeLabel || t.remove(
|
|
3930
|
+
"aria-label": props.removeLabel || t.remove(name),
|
|
3891
3931
|
onClick: props.onRemove
|
|
3892
3932
|
},
|
|
3893
3933
|
/* @__PURE__ */ React24.createElement(Icon, { name: /* @__PURE__ */ React24.createElement(IconX, null), size: 12 })
|
|
@@ -5876,6 +5916,12 @@ window.Aura = (() => {
|
|
|
5876
5916
|
})[0] || firstOn || items2[0];
|
|
5877
5917
|
const Link = useLinkComponent(props.linkComponent);
|
|
5878
5918
|
const manual = props.activation === "manual";
|
|
5919
|
+
const seg = props.variant === "segmented";
|
|
5920
|
+
const listCls = cx("aura-tabs__list", seg && "aura-segmented", seg && props.fullWidth && "is-full");
|
|
5921
|
+
const tabCls = function(on, extra) {
|
|
5922
|
+
return cx("aura-tab", on && "is-active", seg && "aura-segmented__option", seg && on && "is-selected", extra);
|
|
5923
|
+
};
|
|
5924
|
+
const rootCls = cx("aura-tabs", seg && "aura-tabs--segmented");
|
|
5879
5925
|
const [focusId, setFocusId] = React32.useState(null);
|
|
5880
5926
|
items2.forEach(function(t) {
|
|
5881
5927
|
const al = t.tabProps && t.tabProps["aria-label"];
|
|
@@ -5891,9 +5937,9 @@ window.Aura = (() => {
|
|
|
5891
5937
|
{
|
|
5892
5938
|
ref,
|
|
5893
5939
|
"aria-label": props.label,
|
|
5894
|
-
className: cx("aura-tabs
|
|
5940
|
+
className: cx(rootCls, "aura-tabs--links", props.className)
|
|
5895
5941
|
},
|
|
5896
|
-
/* @__PURE__ */ React32.createElement("div", { className:
|
|
5942
|
+
/* @__PURE__ */ React32.createElement("div", { className: listCls }, items2.map(function(t) {
|
|
5897
5943
|
const on = t.id === cur;
|
|
5898
5944
|
const inner = [
|
|
5899
5945
|
t.icon ? /* @__PURE__ */ React32.createElement(Icon, { key: "i", name: t.icon }) : null,
|
|
@@ -5917,7 +5963,7 @@ window.Aura = (() => {
|
|
|
5917
5963
|
{
|
|
5918
5964
|
...omit(own, ["onClick"]),
|
|
5919
5965
|
key: t.id,
|
|
5920
|
-
className: cx("
|
|
5966
|
+
className: cx(tabCls(false), "is-disabled", own.className),
|
|
5921
5967
|
"aria-disabled": true
|
|
5922
5968
|
},
|
|
5923
5969
|
inner
|
|
@@ -5927,7 +5973,7 @@ window.Aura = (() => {
|
|
|
5927
5973
|
...own,
|
|
5928
5974
|
key: t.id,
|
|
5929
5975
|
href: t.href,
|
|
5930
|
-
className:
|
|
5976
|
+
className: tabCls(on, own.className),
|
|
5931
5977
|
"aria-current": on ? "page" : void 0,
|
|
5932
5978
|
onClick: function(e) {
|
|
5933
5979
|
if (own.onClick) own.onClick(e);
|
|
@@ -5951,12 +5997,12 @@ window.Aura = (() => {
|
|
|
5951
5997
|
const stop = manual && focusId && items2.filter(function(t) {
|
|
5952
5998
|
return t.id === focusId && !t.disabled;
|
|
5953
5999
|
})[0] || current2;
|
|
5954
|
-
return /* @__PURE__ */ React32.createElement("div", { ref, className: cx(
|
|
6000
|
+
return /* @__PURE__ */ React32.createElement("div", { ref, className: cx(rootCls, props.className) }, /* @__PURE__ */ React32.createElement(
|
|
5955
6001
|
"div",
|
|
5956
6002
|
{
|
|
5957
6003
|
role: "tablist",
|
|
5958
6004
|
"aria-label": props.label,
|
|
5959
|
-
className:
|
|
6005
|
+
className: listCls,
|
|
5960
6006
|
onBlur: manual ? function(e) {
|
|
5961
6007
|
if (!e.currentTarget.contains(e.relatedTarget)) setFocusId(null);
|
|
5962
6008
|
} : void 0,
|
|
@@ -5999,7 +6045,7 @@ window.Aura = (() => {
|
|
|
5999
6045
|
ref: function(el) {
|
|
6000
6046
|
refs.current[t.id] = el;
|
|
6001
6047
|
},
|
|
6002
|
-
className:
|
|
6048
|
+
className: tabCls(on, own.className),
|
|
6003
6049
|
onFocus: manual ? function(e) {
|
|
6004
6050
|
if (own.onFocus) own.onFocus(e);
|
|
6005
6051
|
setFocusId(t.id);
|
package/dist/cjs/index.cjs
CHANGED
|
@@ -1215,13 +1215,14 @@ var IconButton = React7.forwardRef(function IconButton2(props, ref) {
|
|
|
1215
1215
|
// src/Menu.tsx
|
|
1216
1216
|
var React8 = __toESM(require("react"), 1);
|
|
1217
1217
|
var import_react_dom = require("react-dom");
|
|
1218
|
+
var ITEMS = '[role^="menuitem"]';
|
|
1218
1219
|
var Menu = React8.forwardRef(function Menu2(props, ref) {
|
|
1219
1220
|
const own = React8.useRef(null), merged = useMergedRef(ref, own);
|
|
1220
1221
|
const posState = React8.useState(null);
|
|
1221
1222
|
const pos = posState[0], setPos = posState[1];
|
|
1222
1223
|
const items2 = props.items || [];
|
|
1223
1224
|
const mounted = useMounted();
|
|
1224
|
-
const headerId = uid();
|
|
1225
|
+
const headerId = uid(), itemId = uid();
|
|
1225
1226
|
const hasHeader = props.header != null && props.header !== false && props.header !== "";
|
|
1226
1227
|
const Link = useLinkComponent(props.linkComponent);
|
|
1227
1228
|
useIsoLayoutEffect(
|
|
@@ -1249,8 +1250,8 @@ var Menu = React8.forwardRef(function Menu2(props, ref) {
|
|
|
1249
1250
|
hadHeader.current = hasHeader;
|
|
1250
1251
|
const a = document.activeElement;
|
|
1251
1252
|
if (own.current && (!a || a === document.body)) {
|
|
1252
|
-
const first = own.current.querySelector(
|
|
1253
|
-
|
|
1253
|
+
const first = own.current.querySelector(ITEMS);
|
|
1254
|
+
(first || own.current.querySelector('[role="menu"]') || own.current).focus();
|
|
1254
1255
|
}
|
|
1255
1256
|
},
|
|
1256
1257
|
[hasHeader]
|
|
@@ -1258,8 +1259,11 @@ var Menu = React8.forwardRef(function Menu2(props, ref) {
|
|
|
1258
1259
|
React8.useEffect(
|
|
1259
1260
|
function() {
|
|
1260
1261
|
if (!mounted) return;
|
|
1261
|
-
const first = own.current && own.current.querySelector(
|
|
1262
|
-
if (
|
|
1262
|
+
const first = own.current && own.current.querySelector(ITEMS);
|
|
1263
|
+
if (props.autoFocus !== false) {
|
|
1264
|
+
if (first) first.focus();
|
|
1265
|
+
else if (own.current) (own.current.querySelector('[role="menu"]') || own.current).focus();
|
|
1266
|
+
}
|
|
1263
1267
|
function outside(e) {
|
|
1264
1268
|
if (own.current && !own.current.contains(e.target) && !(props.anchor && props.anchor.contains(e.target)))
|
|
1265
1269
|
props.onClose(false);
|
|
@@ -1279,16 +1283,18 @@ var Menu = React8.forwardRef(function Menu2(props, ref) {
|
|
|
1279
1283
|
[mounted]
|
|
1280
1284
|
);
|
|
1281
1285
|
function onKeyDown(e) {
|
|
1282
|
-
const list2 = Array.prototype.slice.call(
|
|
1283
|
-
own.current.querySelectorAll('[role^="menuitem"]:not([disabled])')
|
|
1284
|
-
);
|
|
1286
|
+
const list2 = Array.prototype.slice.call(own.current.querySelectorAll(ITEMS));
|
|
1285
1287
|
const i = list2.indexOf(document.activeElement);
|
|
1288
|
+
if (!list2.length && e.key !== "Escape" && e.key !== "Tab") {
|
|
1289
|
+
e.stopPropagation();
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1286
1292
|
if (e.key === "ArrowDown") {
|
|
1287
1293
|
e.preventDefault();
|
|
1288
1294
|
list2[(i + 1) % list2.length].focus();
|
|
1289
1295
|
} else if (e.key === "ArrowUp") {
|
|
1290
1296
|
e.preventDefault();
|
|
1291
|
-
list2[(i - 1 + list2.length) % list2.length].focus();
|
|
1297
|
+
list2[i < 0 ? list2.length - 1 : (i - 1 + list2.length) % list2.length].focus();
|
|
1292
1298
|
} else if (e.key === "Home") {
|
|
1293
1299
|
e.preventDefault();
|
|
1294
1300
|
list2[0].focus();
|
|
@@ -1327,6 +1333,10 @@ var Menu = React8.forwardRef(function Menu2(props, ref) {
|
|
|
1327
1333
|
it.hint ? /* @__PURE__ */ React8.createElement("span", { key: "h", className: "aura-menu__hint" }, it.hint) : null
|
|
1328
1334
|
];
|
|
1329
1335
|
const cls = cx("aura-menu__item", it.tone === "danger" && "aura-menu__item--danger");
|
|
1336
|
+
const reasonId = it.disabled && it.disabledReason ? itemId + "-r" + i : void 0;
|
|
1337
|
+
if (reasonId)
|
|
1338
|
+
body[2] = /* Hidden from the name (it would be read twice); aria-describedby still reads it. */
|
|
1339
|
+
/* @__PURE__ */ React8.createElement("span", { key: "h", id: reasonId, className: "aura-menu__hint aura-menu__reason", "aria-hidden": true }, it.disabledReason);
|
|
1330
1340
|
if (it.href && !it.disabled)
|
|
1331
1341
|
return /* @__PURE__ */ React8.createElement(
|
|
1332
1342
|
Link,
|
|
@@ -1351,11 +1361,13 @@ var Menu = React8.forwardRef(function Menu2(props, ref) {
|
|
|
1351
1361
|
key: i,
|
|
1352
1362
|
type: "button",
|
|
1353
1363
|
tabIndex: -1,
|
|
1354
|
-
disabled: it.disabled,
|
|
1364
|
+
"aria-disabled": it.disabled ? true : void 0,
|
|
1365
|
+
"aria-describedby": reasonId,
|
|
1355
1366
|
role: isRadio ? "menuitemradio" : isCheck ? "menuitemcheckbox" : "menuitem",
|
|
1356
1367
|
"aria-checked": isRadio || isCheck ? !!it.checked : void 0,
|
|
1357
1368
|
className: cls,
|
|
1358
1369
|
onClick: function() {
|
|
1370
|
+
if (it.disabled) return;
|
|
1359
1371
|
if (it.onSelect) it.onSelect();
|
|
1360
1372
|
if (!it.keepOpen) props.onClose(true);
|
|
1361
1373
|
}
|
|
@@ -1384,7 +1396,19 @@ var Menu = React8.forwardRef(function Menu2(props, ref) {
|
|
|
1384
1396
|
}
|
|
1385
1397
|
},
|
|
1386
1398
|
props.header
|
|
1387
|
-
), /* @__PURE__ */ React8.createElement("div", { role: "menu", "aria-label": props.label, "aria-describedby": headerId, className: "aura-menu__list" }, list)) : /* @__PURE__ */ React8.createElement(
|
|
1399
|
+
), /* @__PURE__ */ React8.createElement("div", { role: "menu", tabIndex: -1, "aria-label": props.label, "aria-describedby": headerId, className: "aura-menu__list" }, list)) : /* @__PURE__ */ React8.createElement(
|
|
1400
|
+
"div",
|
|
1401
|
+
{
|
|
1402
|
+
ref: merged,
|
|
1403
|
+
role: "menu",
|
|
1404
|
+
tabIndex: -1,
|
|
1405
|
+
"aria-label": props.label,
|
|
1406
|
+
className: "aura-menu",
|
|
1407
|
+
onKeyDown,
|
|
1408
|
+
style
|
|
1409
|
+
},
|
|
1410
|
+
list
|
|
1411
|
+
);
|
|
1388
1412
|
return mounted ? (0, import_react_dom.createPortal)(el, document.body) : null;
|
|
1389
1413
|
});
|
|
1390
1414
|
|
|
@@ -1399,7 +1423,7 @@ var DropdownMenu = React9.forwardRef(function DropdownMenu2(props, ref) {
|
|
|
1399
1423
|
function() {
|
|
1400
1424
|
if (!anchor || !toLast.current || !menuRef.current) return;
|
|
1401
1425
|
toLast.current = false;
|
|
1402
|
-
const list = menuRef.current.querySelectorAll('[role^="menuitem"]
|
|
1426
|
+
const list = menuRef.current.querySelectorAll('[role^="menuitem"]');
|
|
1403
1427
|
if (list.length) list[list.length - 1].focus();
|
|
1404
1428
|
},
|
|
1405
1429
|
[anchor]
|
|
@@ -3841,6 +3865,16 @@ var React25 = __toESM(require("react"), 1);
|
|
|
3841
3865
|
|
|
3842
3866
|
// src/Tag.tsx
|
|
3843
3867
|
var React24 = __toESM(require("react"), 1);
|
|
3868
|
+
function textOf(node) {
|
|
3869
|
+
if (node == null || typeof node === "boolean") return "";
|
|
3870
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
3871
|
+
if (Array.isArray(node)) return node.map(textOf).join("");
|
|
3872
|
+
if (React24.isValidElement(node)) {
|
|
3873
|
+
const p = node.props;
|
|
3874
|
+
return p["aria-hidden"] === true || p["aria-hidden"] === "true" ? "" : textOf(p.children);
|
|
3875
|
+
}
|
|
3876
|
+
return "";
|
|
3877
|
+
}
|
|
3844
3878
|
var Tag = React24.forwardRef(function Tag2(props, ref) {
|
|
3845
3879
|
const t = useStrings();
|
|
3846
3880
|
const selectable = props.onClick != null || props.selected != null;
|
|
@@ -3864,12 +3898,18 @@ var Tag = React24.forwardRef(function Tag2(props, ref) {
|
|
|
3864
3898
|
inner[1]
|
|
3865
3899
|
);
|
|
3866
3900
|
}
|
|
3901
|
+
const name = props.onRemove && !props.removeLabel ? textOf(props.children).replace(/\s+/g, " ").trim() : "";
|
|
3902
|
+
if (props.onRemove && !props.disabled && !props.removeLabel && !name)
|
|
3903
|
+
devWarnOnce(
|
|
3904
|
+
"tag-remove-label",
|
|
3905
|
+
'Tag: the remove button has no name \u2014 its children have no text. Pass removeLabel (e.g. "Remove Acme AB").'
|
|
3906
|
+
);
|
|
3867
3907
|
return /* @__PURE__ */ React24.createElement("span", { ...rest, ref, className: cx("aura-tag", props.disabled && "is-disabled", props.className) }, inner, props.onRemove && !props.disabled ? /* @__PURE__ */ React24.createElement(
|
|
3868
3908
|
"button",
|
|
3869
3909
|
{
|
|
3870
3910
|
type: "button",
|
|
3871
3911
|
className: "aura-tag__remove",
|
|
3872
|
-
"aria-label": props.removeLabel || t.remove(
|
|
3912
|
+
"aria-label": props.removeLabel || t.remove(name),
|
|
3873
3913
|
onClick: props.onRemove
|
|
3874
3914
|
},
|
|
3875
3915
|
/* @__PURE__ */ React24.createElement(Icon, { name: /* @__PURE__ */ React24.createElement(IconX, null), size: 12 })
|
|
@@ -5858,6 +5898,12 @@ var Tabs = React32.forwardRef(function Tabs2(props, ref) {
|
|
|
5858
5898
|
})[0] || firstOn || items2[0];
|
|
5859
5899
|
const Link = useLinkComponent(props.linkComponent);
|
|
5860
5900
|
const manual = props.activation === "manual";
|
|
5901
|
+
const seg = props.variant === "segmented";
|
|
5902
|
+
const listCls = cx("aura-tabs__list", seg && "aura-segmented", seg && props.fullWidth && "is-full");
|
|
5903
|
+
const tabCls = function(on, extra) {
|
|
5904
|
+
return cx("aura-tab", on && "is-active", seg && "aura-segmented__option", seg && on && "is-selected", extra);
|
|
5905
|
+
};
|
|
5906
|
+
const rootCls = cx("aura-tabs", seg && "aura-tabs--segmented");
|
|
5861
5907
|
const [focusId, setFocusId] = React32.useState(null);
|
|
5862
5908
|
items2.forEach(function(t) {
|
|
5863
5909
|
const al = t.tabProps && t.tabProps["aria-label"];
|
|
@@ -5873,9 +5919,9 @@ var Tabs = React32.forwardRef(function Tabs2(props, ref) {
|
|
|
5873
5919
|
{
|
|
5874
5920
|
ref,
|
|
5875
5921
|
"aria-label": props.label,
|
|
5876
|
-
className: cx("aura-tabs
|
|
5922
|
+
className: cx(rootCls, "aura-tabs--links", props.className)
|
|
5877
5923
|
},
|
|
5878
|
-
/* @__PURE__ */ React32.createElement("div", { className:
|
|
5924
|
+
/* @__PURE__ */ React32.createElement("div", { className: listCls }, items2.map(function(t) {
|
|
5879
5925
|
const on = t.id === cur;
|
|
5880
5926
|
const inner = [
|
|
5881
5927
|
t.icon ? /* @__PURE__ */ React32.createElement(Icon, { key: "i", name: t.icon }) : null,
|
|
@@ -5899,7 +5945,7 @@ var Tabs = React32.forwardRef(function Tabs2(props, ref) {
|
|
|
5899
5945
|
{
|
|
5900
5946
|
...omit(own, ["onClick"]),
|
|
5901
5947
|
key: t.id,
|
|
5902
|
-
className: cx("
|
|
5948
|
+
className: cx(tabCls(false), "is-disabled", own.className),
|
|
5903
5949
|
"aria-disabled": true
|
|
5904
5950
|
},
|
|
5905
5951
|
inner
|
|
@@ -5909,7 +5955,7 @@ var Tabs = React32.forwardRef(function Tabs2(props, ref) {
|
|
|
5909
5955
|
...own,
|
|
5910
5956
|
key: t.id,
|
|
5911
5957
|
href: t.href,
|
|
5912
|
-
className:
|
|
5958
|
+
className: tabCls(on, own.className),
|
|
5913
5959
|
"aria-current": on ? "page" : void 0,
|
|
5914
5960
|
onClick: function(e) {
|
|
5915
5961
|
if (own.onClick) own.onClick(e);
|
|
@@ -5933,12 +5979,12 @@ var Tabs = React32.forwardRef(function Tabs2(props, ref) {
|
|
|
5933
5979
|
const stop = manual && focusId && items2.filter(function(t) {
|
|
5934
5980
|
return t.id === focusId && !t.disabled;
|
|
5935
5981
|
})[0] || current2;
|
|
5936
|
-
return /* @__PURE__ */ React32.createElement("div", { ref, className: cx(
|
|
5982
|
+
return /* @__PURE__ */ React32.createElement("div", { ref, className: cx(rootCls, props.className) }, /* @__PURE__ */ React32.createElement(
|
|
5937
5983
|
"div",
|
|
5938
5984
|
{
|
|
5939
5985
|
role: "tablist",
|
|
5940
5986
|
"aria-label": props.label,
|
|
5941
|
-
className:
|
|
5987
|
+
className: listCls,
|
|
5942
5988
|
onBlur: manual ? function(e) {
|
|
5943
5989
|
if (!e.currentTarget.contains(e.relatedTarget)) setFocusId(null);
|
|
5944
5990
|
} : void 0,
|
|
@@ -5981,7 +6027,7 @@ var Tabs = React32.forwardRef(function Tabs2(props, ref) {
|
|
|
5981
6027
|
ref: function(el) {
|
|
5982
6028
|
refs.current[t.id] = el;
|
|
5983
6029
|
},
|
|
5984
|
-
className:
|
|
6030
|
+
className: tabCls(on, own.className),
|
|
5985
6031
|
onFocus: manual ? function(e) {
|
|
5986
6032
|
if (own.onFocus) own.onFocus(e);
|
|
5987
6033
|
setFocusId(t.id);
|
package/dist/esm/DropdownMenu.js
CHANGED
|
@@ -11,7 +11,7 @@ const DropdownMenu = React.forwardRef(function DropdownMenu2(props, ref) {
|
|
|
11
11
|
function() {
|
|
12
12
|
if (!anchor || !toLast.current || !menuRef.current) return;
|
|
13
13
|
toLast.current = false;
|
|
14
|
-
const list = menuRef.current.querySelectorAll('[role^="menuitem"]
|
|
14
|
+
const list = menuRef.current.querySelectorAll('[role^="menuitem"]');
|
|
15
15
|
if (list.length) list[list.length - 1].focus();
|
|
16
16
|
},
|
|
17
17
|
[anchor]
|
package/dist/esm/Menu.js
CHANGED
|
@@ -5,13 +5,14 @@ import { cx, uid, useIsoLayoutEffect, useMounted, useMergedRef } from "./interna
|
|
|
5
5
|
import { Icon } from "./Icon.js";
|
|
6
6
|
import { useLinkComponent } from "./locale.js";
|
|
7
7
|
import { IconCheck } from "./icons.js";
|
|
8
|
+
const ITEMS = '[role^="menuitem"]';
|
|
8
9
|
const Menu = React.forwardRef(function Menu2(props, ref) {
|
|
9
10
|
const own = React.useRef(null), merged = useMergedRef(ref, own);
|
|
10
11
|
const posState = React.useState(null);
|
|
11
12
|
const pos = posState[0], setPos = posState[1];
|
|
12
13
|
const items = props.items || [];
|
|
13
14
|
const mounted = useMounted();
|
|
14
|
-
const headerId = uid();
|
|
15
|
+
const headerId = uid(), itemId = uid();
|
|
15
16
|
const hasHeader = props.header != null && props.header !== false && props.header !== "";
|
|
16
17
|
const Link = useLinkComponent(props.linkComponent);
|
|
17
18
|
useIsoLayoutEffect(
|
|
@@ -39,8 +40,8 @@ const Menu = React.forwardRef(function Menu2(props, ref) {
|
|
|
39
40
|
hadHeader.current = hasHeader;
|
|
40
41
|
const a = document.activeElement;
|
|
41
42
|
if (own.current && (!a || a === document.body)) {
|
|
42
|
-
const first = own.current.querySelector(
|
|
43
|
-
|
|
43
|
+
const first = own.current.querySelector(ITEMS);
|
|
44
|
+
(first || own.current.querySelector('[role="menu"]') || own.current).focus();
|
|
44
45
|
}
|
|
45
46
|
},
|
|
46
47
|
[hasHeader]
|
|
@@ -48,8 +49,11 @@ const Menu = React.forwardRef(function Menu2(props, ref) {
|
|
|
48
49
|
React.useEffect(
|
|
49
50
|
function() {
|
|
50
51
|
if (!mounted) return;
|
|
51
|
-
const first = own.current && own.current.querySelector(
|
|
52
|
-
if (
|
|
52
|
+
const first = own.current && own.current.querySelector(ITEMS);
|
|
53
|
+
if (props.autoFocus !== false) {
|
|
54
|
+
if (first) first.focus();
|
|
55
|
+
else if (own.current) (own.current.querySelector('[role="menu"]') || own.current).focus();
|
|
56
|
+
}
|
|
53
57
|
function outside(e) {
|
|
54
58
|
if (own.current && !own.current.contains(e.target) && !(props.anchor && props.anchor.contains(e.target)))
|
|
55
59
|
props.onClose(false);
|
|
@@ -69,16 +73,18 @@ const Menu = React.forwardRef(function Menu2(props, ref) {
|
|
|
69
73
|
[mounted]
|
|
70
74
|
);
|
|
71
75
|
function onKeyDown(e) {
|
|
72
|
-
const list2 = Array.prototype.slice.call(
|
|
73
|
-
own.current.querySelectorAll('[role^="menuitem"]:not([disabled])')
|
|
74
|
-
);
|
|
76
|
+
const list2 = Array.prototype.slice.call(own.current.querySelectorAll(ITEMS));
|
|
75
77
|
const i = list2.indexOf(document.activeElement);
|
|
78
|
+
if (!list2.length && e.key !== "Escape" && e.key !== "Tab") {
|
|
79
|
+
e.stopPropagation();
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
76
82
|
if (e.key === "ArrowDown") {
|
|
77
83
|
e.preventDefault();
|
|
78
84
|
list2[(i + 1) % list2.length].focus();
|
|
79
85
|
} else if (e.key === "ArrowUp") {
|
|
80
86
|
e.preventDefault();
|
|
81
|
-
list2[(i - 1 + list2.length) % list2.length].focus();
|
|
87
|
+
list2[i < 0 ? list2.length - 1 : (i - 1 + list2.length) % list2.length].focus();
|
|
82
88
|
} else if (e.key === "Home") {
|
|
83
89
|
e.preventDefault();
|
|
84
90
|
list2[0].focus();
|
|
@@ -117,6 +123,10 @@ const Menu = React.forwardRef(function Menu2(props, ref) {
|
|
|
117
123
|
it.hint ? /* @__PURE__ */ React.createElement("span", { key: "h", className: "aura-menu__hint" }, it.hint) : null
|
|
118
124
|
];
|
|
119
125
|
const cls = cx("aura-menu__item", it.tone === "danger" && "aura-menu__item--danger");
|
|
126
|
+
const reasonId = it.disabled && it.disabledReason ? itemId + "-r" + i : void 0;
|
|
127
|
+
if (reasonId)
|
|
128
|
+
body[2] = /* Hidden from the name (it would be read twice); aria-describedby still reads it. */
|
|
129
|
+
/* @__PURE__ */ React.createElement("span", { key: "h", id: reasonId, className: "aura-menu__hint aura-menu__reason", "aria-hidden": true }, it.disabledReason);
|
|
120
130
|
if (it.href && !it.disabled)
|
|
121
131
|
return /* @__PURE__ */ React.createElement(
|
|
122
132
|
Link,
|
|
@@ -141,11 +151,13 @@ const Menu = React.forwardRef(function Menu2(props, ref) {
|
|
|
141
151
|
key: i,
|
|
142
152
|
type: "button",
|
|
143
153
|
tabIndex: -1,
|
|
144
|
-
disabled: it.disabled,
|
|
154
|
+
"aria-disabled": it.disabled ? true : void 0,
|
|
155
|
+
"aria-describedby": reasonId,
|
|
145
156
|
role: isRadio ? "menuitemradio" : isCheck ? "menuitemcheckbox" : "menuitem",
|
|
146
157
|
"aria-checked": isRadio || isCheck ? !!it.checked : void 0,
|
|
147
158
|
className: cls,
|
|
148
159
|
onClick: function() {
|
|
160
|
+
if (it.disabled) return;
|
|
149
161
|
if (it.onSelect) it.onSelect();
|
|
150
162
|
if (!it.keepOpen) props.onClose(true);
|
|
151
163
|
}
|
|
@@ -174,7 +186,19 @@ const Menu = React.forwardRef(function Menu2(props, ref) {
|
|
|
174
186
|
}
|
|
175
187
|
},
|
|
176
188
|
props.header
|
|
177
|
-
), /* @__PURE__ */ React.createElement("div", { role: "menu", "aria-label": props.label, "aria-describedby": headerId, className: "aura-menu__list" }, list)) : /* @__PURE__ */ React.createElement(
|
|
189
|
+
), /* @__PURE__ */ React.createElement("div", { role: "menu", tabIndex: -1, "aria-label": props.label, "aria-describedby": headerId, className: "aura-menu__list" }, list)) : /* @__PURE__ */ React.createElement(
|
|
190
|
+
"div",
|
|
191
|
+
{
|
|
192
|
+
ref: merged,
|
|
193
|
+
role: "menu",
|
|
194
|
+
tabIndex: -1,
|
|
195
|
+
"aria-label": props.label,
|
|
196
|
+
className: "aura-menu",
|
|
197
|
+
onKeyDown,
|
|
198
|
+
style
|
|
199
|
+
},
|
|
200
|
+
list
|
|
201
|
+
);
|
|
178
202
|
return mounted ? createPortal(el, document.body) : null;
|
|
179
203
|
});
|
|
180
204
|
export {
|
package/dist/esm/Tabs.js
CHANGED
|
@@ -23,6 +23,12 @@ const Tabs = React.forwardRef(function Tabs2(props, ref) {
|
|
|
23
23
|
})[0] || firstOn || items[0];
|
|
24
24
|
const Link = useLinkComponent(props.linkComponent);
|
|
25
25
|
const manual = props.activation === "manual";
|
|
26
|
+
const seg = props.variant === "segmented";
|
|
27
|
+
const listCls = cx("aura-tabs__list", seg && "aura-segmented", seg && props.fullWidth && "is-full");
|
|
28
|
+
const tabCls = function(on, extra) {
|
|
29
|
+
return cx("aura-tab", on && "is-active", seg && "aura-segmented__option", seg && on && "is-selected", extra);
|
|
30
|
+
};
|
|
31
|
+
const rootCls = cx("aura-tabs", seg && "aura-tabs--segmented");
|
|
26
32
|
const [focusId, setFocusId] = React.useState(null);
|
|
27
33
|
items.forEach(function(t) {
|
|
28
34
|
const al = t.tabProps && t.tabProps["aria-label"];
|
|
@@ -38,9 +44,9 @@ const Tabs = React.forwardRef(function Tabs2(props, ref) {
|
|
|
38
44
|
{
|
|
39
45
|
ref,
|
|
40
46
|
"aria-label": props.label,
|
|
41
|
-
className: cx("aura-tabs
|
|
47
|
+
className: cx(rootCls, "aura-tabs--links", props.className)
|
|
42
48
|
},
|
|
43
|
-
/* @__PURE__ */ React.createElement("div", { className:
|
|
49
|
+
/* @__PURE__ */ React.createElement("div", { className: listCls }, items.map(function(t) {
|
|
44
50
|
const on = t.id === cur;
|
|
45
51
|
const inner = [
|
|
46
52
|
t.icon ? /* @__PURE__ */ React.createElement(Icon, { key: "i", name: t.icon }) : null,
|
|
@@ -64,7 +70,7 @@ const Tabs = React.forwardRef(function Tabs2(props, ref) {
|
|
|
64
70
|
{
|
|
65
71
|
...omit(own, ["onClick"]),
|
|
66
72
|
key: t.id,
|
|
67
|
-
className: cx("
|
|
73
|
+
className: cx(tabCls(false), "is-disabled", own.className),
|
|
68
74
|
"aria-disabled": true
|
|
69
75
|
},
|
|
70
76
|
inner
|
|
@@ -74,7 +80,7 @@ const Tabs = React.forwardRef(function Tabs2(props, ref) {
|
|
|
74
80
|
...own,
|
|
75
81
|
key: t.id,
|
|
76
82
|
href: t.href,
|
|
77
|
-
className:
|
|
83
|
+
className: tabCls(on, own.className),
|
|
78
84
|
"aria-current": on ? "page" : void 0,
|
|
79
85
|
onClick: function(e) {
|
|
80
86
|
if (own.onClick) own.onClick(e);
|
|
@@ -98,12 +104,12 @@ const Tabs = React.forwardRef(function Tabs2(props, ref) {
|
|
|
98
104
|
const stop = manual && focusId && items.filter(function(t) {
|
|
99
105
|
return t.id === focusId && !t.disabled;
|
|
100
106
|
})[0] || current;
|
|
101
|
-
return /* @__PURE__ */ React.createElement("div", { ref, className: cx(
|
|
107
|
+
return /* @__PURE__ */ React.createElement("div", { ref, className: cx(rootCls, props.className) }, /* @__PURE__ */ React.createElement(
|
|
102
108
|
"div",
|
|
103
109
|
{
|
|
104
110
|
role: "tablist",
|
|
105
111
|
"aria-label": props.label,
|
|
106
|
-
className:
|
|
112
|
+
className: listCls,
|
|
107
113
|
onBlur: manual ? function(e) {
|
|
108
114
|
if (!e.currentTarget.contains(e.relatedTarget)) setFocusId(null);
|
|
109
115
|
} : void 0,
|
|
@@ -146,7 +152,7 @@ const Tabs = React.forwardRef(function Tabs2(props, ref) {
|
|
|
146
152
|
ref: function(el) {
|
|
147
153
|
refs.current[t.id] = el;
|
|
148
154
|
},
|
|
149
|
-
className:
|
|
155
|
+
className: tabCls(on, own.className),
|
|
150
156
|
onFocus: manual ? function(e) {
|
|
151
157
|
if (own.onFocus) own.onFocus(e);
|
|
152
158
|
setFocusId(t.id);
|
package/dist/esm/Tag.js
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import * as React from "react";
|
|
3
3
|
import { Icon } from "./Icon.js";
|
|
4
|
-
import { cx, omit } from "./internal.js";
|
|
4
|
+
import { cx, devWarnOnce, omit } from "./internal.js";
|
|
5
5
|
import { useStrings } from "./locale.js";
|
|
6
6
|
import { IconCheck, IconX } from "./icons.js";
|
|
7
|
+
function textOf(node) {
|
|
8
|
+
if (node == null || typeof node === "boolean") return "";
|
|
9
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
10
|
+
if (Array.isArray(node)) return node.map(textOf).join("");
|
|
11
|
+
if (React.isValidElement(node)) {
|
|
12
|
+
const p = node.props;
|
|
13
|
+
return p["aria-hidden"] === true || p["aria-hidden"] === "true" ? "" : textOf(p.children);
|
|
14
|
+
}
|
|
15
|
+
return "";
|
|
16
|
+
}
|
|
7
17
|
const Tag = React.forwardRef(function Tag2(props, ref) {
|
|
8
18
|
const t = useStrings();
|
|
9
19
|
const selectable = props.onClick != null || props.selected != null;
|
|
@@ -27,12 +37,18 @@ const Tag = React.forwardRef(function Tag2(props, ref) {
|
|
|
27
37
|
inner[1]
|
|
28
38
|
);
|
|
29
39
|
}
|
|
40
|
+
const name = props.onRemove && !props.removeLabel ? textOf(props.children).replace(/\s+/g, " ").trim() : "";
|
|
41
|
+
if (props.onRemove && !props.disabled && !props.removeLabel && !name)
|
|
42
|
+
devWarnOnce(
|
|
43
|
+
"tag-remove-label",
|
|
44
|
+
'Tag: the remove button has no name \u2014 its children have no text. Pass removeLabel (e.g. "Remove Acme AB").'
|
|
45
|
+
);
|
|
30
46
|
return /* @__PURE__ */ React.createElement("span", { ...rest, ref, className: cx("aura-tag", props.disabled && "is-disabled", props.className) }, inner, props.onRemove && !props.disabled ? /* @__PURE__ */ React.createElement(
|
|
31
47
|
"button",
|
|
32
48
|
{
|
|
33
49
|
type: "button",
|
|
34
50
|
className: "aura-tag__remove",
|
|
35
|
-
"aria-label": props.removeLabel || t.remove(
|
|
51
|
+
"aria-label": props.removeLabel || t.remove(name),
|
|
36
52
|
onClick: props.onRemove
|
|
37
53
|
},
|
|
38
54
|
/* @__PURE__ */ React.createElement(Icon, { name: /* @__PURE__ */ React.createElement(IconX, null), size: 12 })
|
package/dist/index.d.cts
CHANGED
|
@@ -278,7 +278,10 @@ export interface MenuItem {
|
|
|
278
278
|
icon?: IconInput | undefined;
|
|
279
279
|
/** Present = a checkable item (menuitemcheckbox). */
|
|
280
280
|
checked?: boolean | undefined;
|
|
281
|
+
/** Dimmed and does nothing when chosen, but still reachable with the arrow keys and announced (5.10). */
|
|
281
282
|
disabled?: boolean | undefined;
|
|
283
|
+
/** Why it's disabled ("You can resend in 5 minutes"): shown in place of the hint and read with the item. (5.10) */
|
|
284
|
+
disabledReason?: string | undefined;
|
|
282
285
|
/** Keep the menu open after choosing (checkbox lists). */
|
|
283
286
|
keepOpen?: boolean | undefined;
|
|
284
287
|
/** Short right-aligned hint, e.g. a shortcut. */
|
|
@@ -617,6 +620,11 @@ export interface TabsProps {
|
|
|
617
620
|
/** `auto` (default): arrow keys select as they move. `manual`: arrows, Home and End only move focus; Enter, Space
|
|
618
621
|
* or a click selects — for tabs whose selection does work (loads data, starts a payment). (5.9) */
|
|
619
622
|
activation?: "auto" | "manual" | undefined;
|
|
623
|
+
/** `underline` (default) or `segmented`: the tabs as a pill track with the selected one raised, like
|
|
624
|
+
* SegmentedControl, keeping every Tabs behaviour (panels, keepMounted, activation, tabProps). (5.10, Chamber-OS 72) */
|
|
625
|
+
variant?: "underline" | "segmented" | undefined;
|
|
626
|
+
/** With `variant="segmented"`: stretch the track to the full width, tabs sharing it equally. (5.10) */
|
|
627
|
+
fullWidth?: boolean | undefined;
|
|
620
628
|
}
|
|
621
629
|
export interface NavItem {
|
|
622
630
|
id: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -278,7 +278,10 @@ export interface MenuItem {
|
|
|
278
278
|
icon?: IconInput | undefined;
|
|
279
279
|
/** Present = a checkable item (menuitemcheckbox). */
|
|
280
280
|
checked?: boolean | undefined;
|
|
281
|
+
/** Dimmed and does nothing when chosen, but still reachable with the arrow keys and announced (5.10). */
|
|
281
282
|
disabled?: boolean | undefined;
|
|
283
|
+
/** Why it's disabled ("You can resend in 5 minutes"): shown in place of the hint and read with the item. (5.10) */
|
|
284
|
+
disabledReason?: string | undefined;
|
|
282
285
|
/** Keep the menu open after choosing (checkbox lists). */
|
|
283
286
|
keepOpen?: boolean | undefined;
|
|
284
287
|
/** Short right-aligned hint, e.g. a shortcut. */
|
|
@@ -617,6 +620,11 @@ export interface TabsProps {
|
|
|
617
620
|
/** `auto` (default): arrow keys select as they move. `manual`: arrows, Home and End only move focus; Enter, Space
|
|
618
621
|
* or a click selects — for tabs whose selection does work (loads data, starts a payment). (5.9) */
|
|
619
622
|
activation?: "auto" | "manual" | undefined;
|
|
623
|
+
/** `underline` (default) or `segmented`: the tabs as a pill track with the selected one raised, like
|
|
624
|
+
* SegmentedControl, keeping every Tabs behaviour (panels, keepMounted, activation, tabProps). (5.10, Chamber-OS 72) */
|
|
625
|
+
variant?: "underline" | "segmented" | undefined;
|
|
626
|
+
/** With `variant="segmented"`: stretch the track to the full width, tabs sharing it equally. (5.10) */
|
|
627
|
+
fullWidth?: boolean | undefined;
|
|
620
628
|
}
|
|
621
629
|
export interface NavItem {
|
|
622
630
|
id: string;
|
package/dist/styles.css
CHANGED
|
@@ -226,7 +226,13 @@ a.aura-btn { text-decoration: none; }
|
|
|
226
226
|
}
|
|
227
227
|
.aura-menu__item:hover, .aura-menu__item:focus { background: var(--aura-bg-surface-hover); outline: none; }
|
|
228
228
|
.aura-menu__item:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: calc(-1 * var(--aura-focus-ring-width)); }
|
|
229
|
-
.aura-menu__item:disabled { opacity: var(--aura-disabled-opacity); cursor: default;
|
|
229
|
+
.aura-menu__item:disabled { opacity: var(--aura-disabled-opacity); cursor: default; }
|
|
230
|
+
/* 5.10: a disabled item is dimmed but focusable; its reason stays at full strength (it is the information). */
|
|
231
|
+
.aura-menu__item[aria-disabled="true"] { cursor: default; }
|
|
232
|
+
.aura-menu__item[aria-disabled="true"] > :not(.aura-menu__reason) { opacity: var(--aura-disabled-opacity); }
|
|
233
|
+
.aura-menu__reason { padding-left: var(--aura-space-4); }
|
|
234
|
+
.aura-menu__item:disabled, .aura-menu__item[aria-disabled="true"]:hover:not(:focus) { background: transparent; }
|
|
235
|
+
.aura-menu:focus, .aura-menu__list:focus { outline: none; }
|
|
230
236
|
.aura-menu__item .aura-icon { color: var(--aura-fg-secondary); }
|
|
231
237
|
.aura-menu__label { flex: 1; }
|
|
232
238
|
.aura-menu__blank { width: var(--aura-icon-sm); flex: none; }
|
|
@@ -460,7 +466,13 @@ a.aura-icon-btn { text-decoration: none; }
|
|
|
460
466
|
.aura-radio-group.is-invalid .aura-radio:not(:checked) { border-color: var(--aura-border-danger); }
|
|
461
467
|
|
|
462
468
|
.aura-switch-row { display: flex; align-items: flex-start; gap: var(--aura-space-3); font-family: var(--font-sans); }
|
|
463
|
-
.
|
|
469
|
+
/* 5.10.1: disabled rows, on or off, are treated alike and stay readable — the label turns secondary, the description
|
|
470
|
+
* keeps its colour (often the reason it's locked) — and only the switch fades: off to the disabled opacity, on to 0.75,
|
|
471
|
+
* ≥3:1 apart in both themes, so "locked on" never looks like "off". */
|
|
472
|
+
.aura-switch-row.is-disabled { cursor: not-allowed; }
|
|
473
|
+
.aura-switch-row.is-disabled .aura-choice__label { color: var(--aura-fg-secondary); cursor: not-allowed; }
|
|
474
|
+
.aura-switch:disabled { opacity: var(--aura-disabled-opacity); }
|
|
475
|
+
.aura-switch.is-on:disabled { opacity: 0.75; }
|
|
464
476
|
.aura-switch {
|
|
465
477
|
position: relative; flex: none; box-sizing: border-box; margin: 0; padding: 0;
|
|
466
478
|
width: var(--aura-switch-width); height: var(--aura-switch-height); border-radius: var(--aura-radius-full);
|
|
@@ -1203,6 +1215,16 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
|
|
|
1203
1215
|
.aura-segmented--sm .aura-segmented__option { height: 24px; padding: 0 var(--aura-space-3); font-size: 12px; }
|
|
1204
1216
|
.aura-segmented--sm .aura-segmented__option.is-icon { width: 28px; padding: 0; }
|
|
1205
1217
|
.aura-segmented.is-disabled { opacity: var(--aura-disabled-opacity); }
|
|
1218
|
+
/* 5.10 (Chamber-OS 72): Tabs variant="segmented" — the tablist wears SegmentedControl's track and pills. The focus
|
|
1219
|
+
* ring is drawn inside the pill, so neither the scrolling list (many tabs on a phone) nor the next pill can cover it;
|
|
1220
|
+
* full-width tabs share the track but never shrink below their label (the track scrolls instead). The phone rule's
|
|
1221
|
+
* wider tab gap doesn't apply. */
|
|
1222
|
+
.aura-tabs--segmented .aura-tabs__list.aura-segmented { gap: 2px; }
|
|
1223
|
+
.aura-tabs--segmented .aura-tabs__list.aura-segmented.is-full .aura-tab { min-width: max-content; }
|
|
1224
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option { margin-bottom: 0; }
|
|
1225
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option:focus-visible { border-radius: var(--aura-radius-full); outline-offset: calc(-1 * var(--aura-focus-ring-width)); }
|
|
1226
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option:disabled,
|
|
1227
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option.is-disabled { opacity: var(--aura-disabled-opacity); cursor: not-allowed; }
|
|
1206
1228
|
|
|
1207
1229
|
/* A field inside a row Stack takes the remaining width (a search box beside its button). */
|
|
1208
1230
|
.aura-stack > .aura-field { flex: 1 1 auto; min-width: 0; }
|
|
@@ -1585,9 +1607,18 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
|
|
|
1585
1607
|
.aura-switch__thumb { background: CanvasText; forced-color-adjust: none; }
|
|
1586
1608
|
.aura-switch.is-on { background: Highlight; forced-color-adjust: none; }
|
|
1587
1609
|
.aura-switch.is-on .aura-switch__thumb { background: HighlightText; }
|
|
1610
|
+
.aura-switch:disabled, .aura-switch.is-on:disabled { border-color: GrayText; opacity: 1; }
|
|
1611
|
+
.aura-switch:disabled .aura-switch__thumb { background: GrayText; }
|
|
1612
|
+
.aura-switch.is-on:disabled { background: GrayText; }
|
|
1613
|
+
.aura-switch.is-on:disabled .aura-switch__thumb { background: Canvas; }
|
|
1614
|
+
.aura-switch-row.is-disabled .aura-choice__label { color: GrayText; }
|
|
1588
1615
|
.aura-progress__track, .aura-upload__bar { border: 1px solid CanvasText; }
|
|
1589
1616
|
.aura-progress__bar, .aura-upload__bar > span { background: Highlight; forced-color-adjust: none; }
|
|
1590
1617
|
.aura-segmented__option.is-selected { outline: 2px solid Highlight; outline-offset: -2px; }
|
|
1591
1618
|
.aura-tab { border-bottom-color: Canvas; }
|
|
1592
1619
|
.aura-tab.is-active { border-bottom-color: Highlight; }
|
|
1620
|
+
/* 5.10: segmented tabs mark the selection with a border and focus with a dashed ring inside it, so a focused tab
|
|
1621
|
+
* and the selected one never look alike (manual activation moves focus without selecting). */
|
|
1622
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option.is-selected { outline: none; border: 2px solid Highlight; }
|
|
1623
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option:focus-visible { outline: 2px dashed CanvasText; outline-offset: -5px; }
|
|
1593
1624
|
}
|
package/dist/styles.layer.css
CHANGED
|
@@ -228,7 +228,13 @@ a.aura-btn { text-decoration: none; }
|
|
|
228
228
|
}
|
|
229
229
|
.aura-menu__item:hover, .aura-menu__item:focus { background: var(--aura-bg-surface-hover); outline: none; }
|
|
230
230
|
.aura-menu__item:focus-visible { outline: var(--aura-focus-ring-width) solid var(--aura-focus-ring); outline-offset: calc(-1 * var(--aura-focus-ring-width)); }
|
|
231
|
-
.aura-menu__item:disabled { opacity: var(--aura-disabled-opacity); cursor: default;
|
|
231
|
+
.aura-menu__item:disabled { opacity: var(--aura-disabled-opacity); cursor: default; }
|
|
232
|
+
/* 5.10: a disabled item is dimmed but focusable; its reason stays at full strength (it is the information). */
|
|
233
|
+
.aura-menu__item[aria-disabled="true"] { cursor: default; }
|
|
234
|
+
.aura-menu__item[aria-disabled="true"] > :not(.aura-menu__reason) { opacity: var(--aura-disabled-opacity); }
|
|
235
|
+
.aura-menu__reason { padding-left: var(--aura-space-4); }
|
|
236
|
+
.aura-menu__item:disabled, .aura-menu__item[aria-disabled="true"]:hover:not(:focus) { background: transparent; }
|
|
237
|
+
.aura-menu:focus, .aura-menu__list:focus { outline: none; }
|
|
232
238
|
.aura-menu__item .aura-icon { color: var(--aura-fg-secondary); }
|
|
233
239
|
.aura-menu__label { flex: 1; }
|
|
234
240
|
.aura-menu__blank { width: var(--aura-icon-sm); flex: none; }
|
|
@@ -462,7 +468,13 @@ a.aura-icon-btn { text-decoration: none; }
|
|
|
462
468
|
.aura-radio-group.is-invalid .aura-radio:not(:checked) { border-color: var(--aura-border-danger); }
|
|
463
469
|
|
|
464
470
|
.aura-switch-row { display: flex; align-items: flex-start; gap: var(--aura-space-3); font-family: var(--font-sans); }
|
|
465
|
-
.
|
|
471
|
+
/* 5.10.1: disabled rows, on or off, are treated alike and stay readable — the label turns secondary, the description
|
|
472
|
+
* keeps its colour (often the reason it's locked) — and only the switch fades: off to the disabled opacity, on to 0.75,
|
|
473
|
+
* ≥3:1 apart in both themes, so "locked on" never looks like "off". */
|
|
474
|
+
.aura-switch-row.is-disabled { cursor: not-allowed; }
|
|
475
|
+
.aura-switch-row.is-disabled .aura-choice__label { color: var(--aura-fg-secondary); cursor: not-allowed; }
|
|
476
|
+
.aura-switch:disabled { opacity: var(--aura-disabled-opacity); }
|
|
477
|
+
.aura-switch.is-on:disabled { opacity: 0.75; }
|
|
466
478
|
.aura-switch {
|
|
467
479
|
position: relative; flex: none; box-sizing: border-box; margin: 0; padding: 0;
|
|
468
480
|
width: var(--aura-switch-width); height: var(--aura-switch-height); border-radius: var(--aura-radius-full);
|
|
@@ -1205,6 +1217,16 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
|
|
|
1205
1217
|
.aura-segmented--sm .aura-segmented__option { height: 24px; padding: 0 var(--aura-space-3); font-size: 12px; }
|
|
1206
1218
|
.aura-segmented--sm .aura-segmented__option.is-icon { width: 28px; padding: 0; }
|
|
1207
1219
|
.aura-segmented.is-disabled { opacity: var(--aura-disabled-opacity); }
|
|
1220
|
+
/* 5.10 (Chamber-OS 72): Tabs variant="segmented" — the tablist wears SegmentedControl's track and pills. The focus
|
|
1221
|
+
* ring is drawn inside the pill, so neither the scrolling list (many tabs on a phone) nor the next pill can cover it;
|
|
1222
|
+
* full-width tabs share the track but never shrink below their label (the track scrolls instead). The phone rule's
|
|
1223
|
+
* wider tab gap doesn't apply. */
|
|
1224
|
+
.aura-tabs--segmented .aura-tabs__list.aura-segmented { gap: 2px; }
|
|
1225
|
+
.aura-tabs--segmented .aura-tabs__list.aura-segmented.is-full .aura-tab { min-width: max-content; }
|
|
1226
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option { margin-bottom: 0; }
|
|
1227
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option:focus-visible { border-radius: var(--aura-radius-full); outline-offset: calc(-1 * var(--aura-focus-ring-width)); }
|
|
1228
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option:disabled,
|
|
1229
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option.is-disabled { opacity: var(--aura-disabled-opacity); cursor: not-allowed; }
|
|
1208
1230
|
|
|
1209
1231
|
/* A field inside a row Stack takes the remaining width (a search box beside its button). */
|
|
1210
1232
|
.aura-stack > .aura-field { flex: 1 1 auto; min-width: 0; }
|
|
@@ -1587,11 +1609,20 @@ button.aura-stepper__step:hover .aura-stepper__label { text-decoration: underlin
|
|
|
1587
1609
|
.aura-switch__thumb { background: CanvasText; forced-color-adjust: none; }
|
|
1588
1610
|
.aura-switch.is-on { background: Highlight; forced-color-adjust: none; }
|
|
1589
1611
|
.aura-switch.is-on .aura-switch__thumb { background: HighlightText; }
|
|
1612
|
+
.aura-switch:disabled, .aura-switch.is-on:disabled { border-color: GrayText; opacity: 1; }
|
|
1613
|
+
.aura-switch:disabled .aura-switch__thumb { background: GrayText; }
|
|
1614
|
+
.aura-switch.is-on:disabled { background: GrayText; }
|
|
1615
|
+
.aura-switch.is-on:disabled .aura-switch__thumb { background: Canvas; }
|
|
1616
|
+
.aura-switch-row.is-disabled .aura-choice__label { color: GrayText; }
|
|
1590
1617
|
.aura-progress__track, .aura-upload__bar { border: 1px solid CanvasText; }
|
|
1591
1618
|
.aura-progress__bar, .aura-upload__bar > span { background: Highlight; forced-color-adjust: none; }
|
|
1592
1619
|
.aura-segmented__option.is-selected { outline: 2px solid Highlight; outline-offset: -2px; }
|
|
1593
1620
|
.aura-tab { border-bottom-color: Canvas; }
|
|
1594
1621
|
.aura-tab.is-active { border-bottom-color: Highlight; }
|
|
1622
|
+
/* 5.10: segmented tabs mark the selection with a border and focus with a dashed ring inside it, so a focused tab
|
|
1623
|
+
* and the selected one never look alike (manual activation moves focus without selecting). */
|
|
1624
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option.is-selected { outline: none; border: 2px solid Highlight; }
|
|
1625
|
+
.aura-tabs--segmented .aura-tab.aura-segmented__option:focus-visible { outline: 2px dashed CanvasText; outline-offset: -5px; }
|
|
1595
1626
|
}
|
|
1596
1627
|
|
|
1597
1628
|
}
|
package/package.json
CHANGED