@deque/cauldron-react 6.12.0 → 6.13.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/lib/index.js CHANGED
@@ -8,8 +8,9 @@ var classNames = require('classnames');
8
8
  var nextId = require('react-id-generator');
9
9
  var keyname = require('keyname');
10
10
  var reactDom = require('react-dom');
11
- var FocusTrap = require('focus-trap-react');
12
- var reactPopper = require('react-popper');
11
+ var focusable = require('focusable');
12
+ var dom = require('@floating-ui/dom');
13
+ var reactDom$1 = require('@floating-ui/react-dom');
13
14
  var SyntaxHighlighter = require('react-syntax-highlighter/dist/cjs/light');
14
15
  var js = require('react-syntax-highlighter/dist/cjs/languages/hljs/javascript');
15
16
  var css = require('react-syntax-highlighter/dist/cjs/languages/hljs/css');
@@ -22,7 +23,7 @@ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
22
23
  var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
23
24
  var nextId__default = /*#__PURE__*/_interopDefaultLegacy(nextId);
24
25
  var keyname__default = /*#__PURE__*/_interopDefaultLegacy(keyname);
25
- var FocusTrap__default = /*#__PURE__*/_interopDefaultLegacy(FocusTrap);
26
+ var focusable__default = /*#__PURE__*/_interopDefaultLegacy(focusable);
26
27
  var SyntaxHighlighter__default = /*#__PURE__*/_interopDefaultLegacy(SyntaxHighlighter);
27
28
  var js__default = /*#__PURE__*/_interopDefaultLegacy(js);
28
29
  var css__default = /*#__PURE__*/_interopDefaultLegacy(css);
@@ -1282,7 +1283,7 @@ var SideBar = /** @class */ (function (_super) {
1282
1283
  }(React.Component));
1283
1284
 
1284
1285
  var SideBarItem = function (_a) {
1285
- var children = _a.children, autoClickLink = _a.autoClickLink, other = tslib.__rest(_a, ["children", "autoClickLink"]);
1286
+ var children = _a.children, _b = _a.autoClickLink, autoClickLink = _b === void 0 ? true : _b, other = tslib.__rest(_a, ["children", "autoClickLink"]);
1286
1287
  var onClick = function (e) {
1287
1288
  if (!autoClickLink) {
1288
1289
  return;
@@ -1294,9 +1295,6 @@ var SideBarItem = function (_a) {
1294
1295
  /* eslint-enable jsx-a11y/no-noninteractive-element-interactions, jsx-a11y/click-events-have-key-events */
1295
1296
  };
1296
1297
  SideBarItem.displayName = 'SideBarItem';
1297
- SideBarItem.defaultProps = {
1298
- autoClickLink: true
1299
- };
1300
1298
 
1301
1299
  /**
1302
1300
  * Handles aria-hidden for dialogs.
@@ -1344,133 +1342,277 @@ var AriaIsolate = /** @class */ (function () {
1344
1342
  return AriaIsolate;
1345
1343
  }());
1346
1344
 
1347
- var isEscape = function (event) {
1348
- return event.key === 'Escape' || event.key === 'Esc' || event.keyCode === 27;
1349
- };
1350
- var noop = function () {
1351
- //not empty
1345
+ /**
1346
+ * When a component needs to track an internal ref on a component that has a
1347
+ * forwarded ref, useSharedRef will return a MutableRefObject<T> that will
1348
+ * correctly invoke the parent ref as well providing an internal ref.
1349
+ *
1350
+ * @example
1351
+ * React.forwardRef(function Component({ children }, ref) {
1352
+ * const internalRef = useSharedRef<HTMLElement>(ref)
1353
+ * if (internalRef.current) {
1354
+ * // do something with the internal ref...
1355
+ * }
1356
+ * return (<div ref={internalRef}>...</div>)
1357
+ * })
1358
+ */
1359
+ function useSharedRef(ref) {
1360
+ var internalRef = React.useRef();
1361
+ React.useEffect(function () {
1362
+ setRef(ref, internalRef.current);
1363
+ }, [ref]);
1364
+ return internalRef;
1365
+ }
1366
+
1367
+ // When multiple focus traps are created, we need to keep track of all previous traps
1368
+ // in the stack and temporarily suspend any traps created before the most recent trap
1369
+ var focusTrapStack = [];
1370
+ var removeFocusTrapFromStack = function (focusTrap) {
1371
+ var focusTrapIndex = focusTrapStack.findIndex(function (trap) { return focusTrap.targetElement === trap.targetElement; });
1372
+ focusTrapStack.splice(focusTrapIndex, 1);
1352
1373
  };
1353
- var Dialog = /** @class */ (function (_super) {
1354
- tslib.__extends(Dialog, _super);
1355
- function Dialog(props) {
1356
- var _this = _super.call(this, props) || this;
1357
- _this.headingId = nextId__default["default"]('dialog-title-');
1358
- _this.close = _this.close.bind(_this);
1359
- _this.focusHeading = _this.focusHeading.bind(_this);
1360
- _this.handleClickOutside = _this.handleClickOutside.bind(_this);
1361
- _this.handleEscape = _this.handleEscape.bind(_this);
1362
- _this.state = {};
1363
- return _this;
1374
+ function getActiveElement(target) {
1375
+ var _a;
1376
+ return (((_a = target === null || target === void 0 ? void 0 : target.ownerDocument.activeElement) !== null && _a !== void 0 ? _a : document.activeElement) ||
1377
+ document.body);
1378
+ }
1379
+ function elementContains(containerElement, targetElement) {
1380
+ if (!targetElement) {
1381
+ return false;
1364
1382
  }
1365
- Dialog.prototype.componentDidMount = function () {
1366
- var _this = this;
1367
- if (this.props.show) {
1368
- this.attachEventListeners();
1369
- this.attachIsolator(function () { return setTimeout(_this.focusHeading); });
1383
+ if (containerElement.getRootNode() === targetElement.getRootNode()) {
1384
+ return containerElement.contains(targetElement);
1385
+ }
1386
+ var root = targetElement.getRootNode();
1387
+ while (root && root !== containerElement.getRootNode()) {
1388
+ if (root.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
1389
+ // likely a shadow root, and we need to get the host
1390
+ root = root.host;
1370
1391
  }
1392
+ else {
1393
+ break;
1394
+ }
1395
+ }
1396
+ return root && containerElement.contains(root);
1397
+ }
1398
+ function createTrapGuard() {
1399
+ var trapGuard = document.createElement('span');
1400
+ trapGuard.setAttribute('tabindex', '0');
1401
+ trapGuard.setAttribute('aria-hidden', 'true');
1402
+ return trapGuard;
1403
+ }
1404
+ function createFocusTrap(targetElement, initialFocusElement) {
1405
+ var _a;
1406
+ var startGuard = createTrapGuard();
1407
+ var endGuard = createTrapGuard();
1408
+ targetElement.insertAdjacentElement('beforebegin', startGuard);
1409
+ targetElement.insertAdjacentElement('afterend', endGuard);
1410
+ var focusTrapMetadata = {
1411
+ targetElement: targetElement,
1412
+ lastFocusedElement: null,
1413
+ suspended: false
1371
1414
  };
1372
- Dialog.prototype.componentWillUnmount = function () {
1373
- var isolator = this.state.isolator;
1374
- isolator === null || isolator === void 0 ? void 0 : isolator.deactivate();
1375
- this.removeEventListeners();
1376
- };
1377
- Dialog.prototype.componentDidUpdate = function (prevProps) {
1378
- if (!prevProps.show && this.props.show) {
1379
- this.attachIsolator(this.focusHeading);
1380
- this.attachEventListeners();
1415
+ var focusListener = function (event) {
1416
+ var _a, _b, _c, _d;
1417
+ var eventTarget = event.target;
1418
+ var elementContainsTarget = elementContains(targetElement, eventTarget);
1419
+ if (focusTrapMetadata.suspended) {
1420
+ return;
1381
1421
  }
1382
- else if (prevProps.show && !this.props.show) {
1383
- this.removeEventListeners();
1384
- this.close();
1422
+ if (!elementContainsTarget) {
1423
+ // If the event target element is not contained within the target element
1424
+ // for this focus trap, we need to prevent focus from escaping the container
1425
+ event.stopImmediatePropagation();
1385
1426
  }
1386
- };
1387
- Dialog.prototype.attachIsolator = function (done) {
1388
- this.setState({
1389
- isolator: new AriaIsolate(this.element)
1390
- }, done);
1391
- };
1392
- Dialog.prototype.render = function () {
1393
- var _this = this;
1394
- var _a = this.props, dialogRef = _a.dialogRef, forceAction = _a.forceAction, className = _a.className, children = _a.children, closeButtonText = _a.closeButtonText, heading = _a.heading, show = _a.show, other = tslib.__rest(_a, ["dialogRef", "forceAction", "className", "children", "closeButtonText", "heading", "show"]);
1395
- if (!show || !isBrowser()) {
1396
- return null;
1427
+ else if (eventTarget instanceof HTMLElement) {
1428
+ // Ensure we keep track of the most recent valid focus element if we
1429
+ // need to redirect focus later
1430
+ focusTrapMetadata.lastFocusedElement = eventTarget;
1431
+ return;
1397
1432
  }
1398
- var portal = this.props.portal || document.body;
1399
- var close = !forceAction ? (React__default["default"].createElement("button", { className: "Dialog__close", type: "button", onClick: this.close },
1400
- React__default["default"].createElement(Icon, { type: "close", "aria-hidden": "true" }),
1401
- React__default["default"].createElement(Offscreen, null, closeButtonText))) : null;
1402
- var Heading = "h".concat(typeof heading === 'object' && 'level' in heading && !!heading.level
1403
- ? heading.level
1404
- : 2);
1405
- var Dialog = (React__default["default"].createElement(FocusTrap__default["default"], { focusTrapOptions: {
1406
- allowOutsideClick: true,
1407
- escapeDeactivates: false,
1408
- fallbackFocus: '.Dialog__heading'
1409
- } },
1410
- React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: this.handleClickOutside },
1411
- React__default["default"].createElement("div", tslib.__assign({ role: "dialog", className: classNames__default["default"]('Dialog', className, {
1412
- 'Dialog--show': show
1413
- }), ref: function (el) {
1414
- _this.element = el;
1415
- if (!dialogRef) {
1416
- return;
1417
- }
1418
- setRef(dialogRef, el);
1419
- }, "aria-labelledby": this.headingId }, other),
1420
- React__default["default"].createElement("div", { className: "Dialog__inner" },
1421
- React__default["default"].createElement("div", { className: "Dialog__header" },
1422
- React__default["default"].createElement(Heading, { className: "Dialog__heading", ref: function (el) { return (_this.heading = el); }, tabIndex: -1, id: this.headingId }, typeof heading === 'object' && 'text' in heading
1423
- ? heading.text
1424
- : heading),
1425
- close),
1426
- children)))));
1427
- return reactDom.createPortal(Dialog, ('current' in portal ? portal.current : portal) || document.body);
1428
- };
1429
- Dialog.prototype.close = function () {
1430
- var _a, _b, _c;
1431
- (_a = this.state.isolator) === null || _a === void 0 ? void 0 : _a.deactivate();
1432
- if (this.props.show) {
1433
- (_c = (_b = this.props).onClose) === null || _c === void 0 ? void 0 : _c.call(_b);
1433
+ var focusableElements = Array.from((targetElement === null || targetElement === void 0 ? void 0 : targetElement.querySelectorAll(focusable__default["default"])) || []);
1434
+ // If focus reaches the trap guards, we need to wrap focus around to the leading
1435
+ // or trailing focusable element depending on which guard obtained focus
1436
+ if (focusableElements.length && eventTarget === startGuard) {
1437
+ (_a = focusableElements.reverse()[0]) === null || _a === void 0 ? void 0 : _a.focus();
1438
+ return;
1434
1439
  }
1435
- };
1436
- Dialog.prototype.handleClickOutside = function () {
1437
- var _a = this.props, show = _a.show, forceAction = _a.forceAction;
1438
- if (show && !forceAction) {
1439
- this.close();
1440
+ else if (focusableElements.length && eventTarget === endGuard) {
1441
+ (_b = focusableElements[0]) === null || _b === void 0 ? void 0 : _b.focus();
1442
+ return;
1443
+ }
1444
+ // If focus somehow escaped the trap, we need to try to restore focus to
1445
+ // to a suitable focusable element within the focus trap target. Otherwise
1446
+ // we'll need to focus on an alternative within the container.
1447
+ if (elementContains(targetElement, focusTrapMetadata.lastFocusedElement)) {
1448
+ (_c = focusTrapMetadata.lastFocusedElement) === null || _c === void 0 ? void 0 : _c.focus();
1449
+ }
1450
+ else if (focusableElements.length) {
1451
+ (_d = focusableElements[0]) === null || _d === void 0 ? void 0 : _d.focus();
1452
+ }
1453
+ else {
1454
+ // if there are no focusable elements, just focus the container
1455
+ targetElement.focus();
1440
1456
  }
1441
1457
  };
1442
- Dialog.prototype.focusHeading = function () {
1458
+ document.addEventListener('focus', focusListener, true);
1459
+ if (focusTrapStack.length >= 1) {
1460
+ // Suspend any other traps in the stack while this one is active
1461
+ focusTrapStack.forEach(function (trap) {
1462
+ trap.suspended = true;
1463
+ });
1464
+ }
1465
+ focusTrapStack.push(focusTrapMetadata);
1466
+ if (initialFocusElement) {
1467
+ initialFocusElement.focus();
1468
+ }
1469
+ else {
1470
+ // Try to find a suitable focus element
1471
+ var focusableElements = Array.from((targetElement === null || targetElement === void 0 ? void 0 : targetElement.querySelectorAll(focusable__default["default"])) ||
1472
+ /* istanbul ignore else */ []);
1473
+ (_a = focusableElements[0]) === null || _a === void 0 ? void 0 : _a.focus();
1474
+ }
1475
+ return tslib.__assign(tslib.__assign({}, focusTrapMetadata), { initialFocusElement: initialFocusElement, destroy: function () {
1476
+ var _a, _b;
1477
+ document.removeEventListener('focus', focusListener, true);
1478
+ removeFocusTrapFromStack(focusTrapMetadata);
1479
+ (_a = startGuard.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(startGuard);
1480
+ (_b = endGuard.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(endGuard);
1481
+ // If there are any remaining focus traps in the stack, we need
1482
+ // to unsuspend the most recently added focus trap
1483
+ if (focusTrapStack.length) {
1484
+ focusTrapStack[focusTrapStack.length - 1].suspended = false;
1485
+ }
1486
+ } });
1487
+ }
1488
+ function useFocusTrap(target, options) {
1489
+ if (options === void 0) { options = {}; }
1490
+ var _a = options.disabled, disabled = _a === void 0 ? false : _a, _b = options.returnFocus, returnFocus = _b === void 0 ? true : _b, initialFocusElementOrRef = options.initialFocusElement, returnFocusElement = options.returnFocusElement;
1491
+ var focusTrap = React.useRef(null);
1492
+ var returnFocusElementRef = React.useRef();
1493
+ function restoreFocusToReturnFocusElement() {
1443
1494
  var _a;
1444
- if (this.heading) {
1445
- this.heading.focus();
1495
+ var resolvedReturnFocusElement = resolveElement(returnFocusElement);
1496
+ if (resolvedReturnFocusElement instanceof HTMLElement) {
1497
+ resolvedReturnFocusElement.focus();
1446
1498
  }
1447
- (_a = this.state.isolator) === null || _a === void 0 ? void 0 : _a.activate();
1448
- };
1449
- Dialog.prototype.handleEscape = function (keyboardEvent) {
1499
+ else {
1500
+ (_a = returnFocusElementRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1501
+ returnFocusElementRef.current = null;
1502
+ }
1503
+ }
1504
+ React.useEffect(function () {
1505
+ var targetElement = resolveElement(target);
1506
+ var initialFocusElement = resolveElement(initialFocusElementOrRef);
1507
+ if (!targetElement || disabled) {
1508
+ return;
1509
+ }
1510
+ returnFocusElementRef.current = getActiveElement(targetElement);
1511
+ focusTrap.current = createFocusTrap(targetElement, initialFocusElement);
1512
+ return function () {
1513
+ var _a;
1514
+ (_a = focusTrap.current) === null || _a === void 0 ? void 0 : _a.destroy();
1515
+ focusTrap.current = null;
1516
+ // istanbul ignore else
1517
+ if (returnFocus) {
1518
+ restoreFocusToReturnFocusElement();
1519
+ }
1520
+ };
1521
+ }, [target, disabled]);
1522
+ return focusTrap;
1523
+ }
1524
+
1525
+ var isEscape = function (event) {
1526
+ return event.key === 'Escape' || event.key === 'Esc' || event.keyCode === 27;
1527
+ };
1528
+ var Dialog = React.forwardRef(function (_a, ref) {
1529
+ var dialogRefProp = _a.dialogRef, _b = _a.forceAction, forceAction = _b === void 0 ? false : _b, className = _a.className, children = _a.children, _c = _a.closeButtonText, closeButtonText = _c === void 0 ? 'Close' : _c, heading = _a.heading, _d = _a.show, show = _d === void 0 ? false : _d, portal = _a.portal, _e = _a.onClose, onClose = _e === void 0 ? function () { return null; } : _e, other = tslib.__rest(_a, ["dialogRef", "forceAction", "className", "children", "closeButtonText", "heading", "show", "portal", "onClose"]);
1530
+ var dialogRef = useSharedRef(dialogRefProp || ref);
1531
+ var _f = tslib.__read(nextId.useId(1, 'dialog-title-'), 1), headingId = _f[0];
1532
+ var headingRef = React.useRef(null);
1533
+ var isolatorRef = React.useRef();
1534
+ var handleClose = React.useCallback(function () {
1535
+ var _a;
1536
+ (_a = isolatorRef.current) === null || _a === void 0 ? void 0 : _a.deactivate();
1537
+ if (show) {
1538
+ onClose();
1539
+ }
1540
+ }, [show, onClose]);
1541
+ var handleClickOutside = React.useCallback(function () {
1542
+ if (show && !forceAction) {
1543
+ handleClose();
1544
+ }
1545
+ }, [show, forceAction, handleClose]);
1546
+ var focusHeading = React.useCallback(function () {
1547
+ var _a, _b;
1548
+ (_a = headingRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1549
+ (_b = isolatorRef.current) === null || _b === void 0 ? void 0 : _b.activate();
1550
+ }, []);
1551
+ var handleEscape = React.useCallback(function (keyboardEvent) {
1450
1552
  if (!keyboardEvent.defaultPrevented && isEscape(keyboardEvent)) {
1451
- this.close();
1553
+ handleClose();
1452
1554
  }
1453
- };
1454
- Dialog.prototype.attachEventListeners = function () {
1455
- var forceAction = this.props.forceAction;
1555
+ }, [handleClose]);
1556
+ React.useEffect(function () {
1557
+ if (!show || !dialogRef.current)
1558
+ return;
1559
+ isolatorRef.current = new AriaIsolate(dialogRef.current);
1560
+ setTimeout(focusHeading);
1561
+ return function () {
1562
+ var _a;
1563
+ (_a = isolatorRef.current) === null || _a === void 0 ? void 0 : _a.deactivate();
1564
+ };
1565
+ }, [show, focusHeading]);
1566
+ React.useEffect(function () {
1456
1567
  if (!forceAction) {
1457
- var portal = this.props.portal || document.body;
1458
- var targetElement = portal instanceof HTMLElement ? portal : portal.current;
1459
- targetElement === null || targetElement === void 0 ? void 0 : targetElement.addEventListener('keyup', this.handleEscape);
1568
+ var portalElement_1 = portal
1569
+ ? 'current' in portal
1570
+ ? portal.current
1571
+ : portal
1572
+ : document.body;
1573
+ if (show) {
1574
+ portalElement_1 === null || portalElement_1 === void 0 ? void 0 : portalElement_1.addEventListener('keyup', handleEscape);
1575
+ }
1576
+ return function () {
1577
+ portalElement_1 === null || portalElement_1 === void 0 ? void 0 : portalElement_1.removeEventListener('keyup', handleEscape);
1578
+ };
1460
1579
  }
1461
- };
1462
- Dialog.prototype.removeEventListeners = function () {
1463
- var portal = this.props.portal || document.body;
1464
- var targetElement = portal instanceof HTMLElement ? portal : portal.current;
1465
- targetElement === null || targetElement === void 0 ? void 0 : targetElement.removeEventListener('keyup', this.handleEscape);
1466
- };
1467
- Dialog.defaultProps = {
1468
- onClose: noop,
1469
- forceAction: false,
1470
- closeButtonText: 'Close'
1471
- };
1472
- return Dialog;
1473
- }(React__default["default"].Component));
1580
+ }, [show, forceAction, portal, handleEscape]);
1581
+ useFocusTrap(dialogRef, {
1582
+ disabled: !show,
1583
+ initialFocusElement: headingRef
1584
+ });
1585
+ if (!show || !isBrowser()) {
1586
+ return null;
1587
+ }
1588
+ var portalElement = portal
1589
+ ? 'current' in portal
1590
+ ? portal.current
1591
+ : portal
1592
+ : // eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
1593
+ document.body;
1594
+ var closeButton = !forceAction ? (React__default["default"].createElement("button", { className: "Dialog__close", type: "button", onClick: handleClose },
1595
+ React__default["default"].createElement(Icon, { type: "close", "aria-hidden": "true" }),
1596
+ React__default["default"].createElement(Offscreen, null, closeButtonText))) : null;
1597
+ var HeadingLevel = "h".concat(typeof heading === 'object' && 'level' in heading && heading.level
1598
+ ? heading.level
1599
+ : 2);
1600
+ var dialog = (React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: handleClickOutside },
1601
+ React__default["default"].createElement("div", tslib.__assign({ role: "dialog", className: classNames__default["default"]('Dialog', className, {
1602
+ 'Dialog--show': show
1603
+ }), ref: dialogRef, "aria-labelledby": headingId }, other),
1604
+ React__default["default"].createElement("div", { className: "Dialog__inner" },
1605
+ React__default["default"].createElement("div", { className: "Dialog__header" },
1606
+ React__default["default"].createElement(HeadingLevel, { className: "Dialog__heading", ref: headingRef, tabIndex: -1, id: headingId }, typeof heading === 'object' && 'text' in heading
1607
+ ? heading.text
1608
+ : heading),
1609
+ closeButton),
1610
+ children))));
1611
+ return reactDom.createPortal(dialog,
1612
+ // eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
1613
+ portalElement || document.body);
1614
+ });
1615
+ Dialog.displayName = 'Dialog';
1474
1616
  var DialogContent = function (_a) {
1475
1617
  var children = _a.children, className = _a.className, align = _a.align, other = tslib.__rest(_a, ["children", "className", "align"]);
1476
1618
  return (React__default["default"].createElement("div", tslib.__assign({ className: classNames__default["default"]('Dialog__content', className, {
@@ -1586,43 +1728,6 @@ var Button = React.forwardRef(function (_a, ref) {
1586
1728
  });
1587
1729
  Button.displayName = 'Button';
1588
1730
 
1589
- /**
1590
- * Returns a unique set of id refs from the provided string
1591
- * @param ids - string of id refs
1592
- */
1593
- function idRefs(ids) {
1594
- if (!ids || !ids.trim()) {
1595
- return new Set();
1596
- }
1597
- return new Set(ids.trim().split(/\s+/));
1598
- }
1599
- /**
1600
- * Returns an updated id ref string with the provided id value added
1601
- * @param ids - string of id refs
1602
- * @param id - id to add
1603
- */
1604
- function addIdRef(ids, id) {
1605
- return tslib.__spreadArray([], tslib.__read(idRefs(ids).add(id)), false).join(' ');
1606
- }
1607
- /**
1608
- * Returns an updated id ref string with the provided id value removed
1609
- * @param ids - string of id refs
1610
- * @param id - id to remove
1611
- */
1612
- function removeIdRef(_ids, id) {
1613
- var ids = idRefs(_ids);
1614
- ids.delete(id);
1615
- return tslib.__spreadArray([], tslib.__read(ids), false).join(' ');
1616
- }
1617
- /**
1618
- * Returns if an id ref string contains the provided id value
1619
- * @param ids - string of id refs
1620
- * @param id - id to check if it exists in the provided idRef string
1621
- */
1622
- function hasIdRef(ids, id) {
1623
- return idRefs(ids).has(id);
1624
- }
1625
-
1626
1731
  var isEscapeKey = function (event) {
1627
1732
  return event.key === 'Escape' || event.key === 'Esc' || event.keyCode === 27;
1628
1733
  };
@@ -1663,6 +1768,99 @@ function useEscapeKey(options, dependencies) {
1663
1768
  ], tslib.__read(dependencies), false));
1664
1769
  }
1665
1770
 
1771
+ function getAutoAlignment(placement) {
1772
+ switch (placement) {
1773
+ case 'auto-start':
1774
+ return 'start';
1775
+ case 'auto-end':
1776
+ return 'end';
1777
+ default:
1778
+ return null;
1779
+ }
1780
+ }
1781
+ var AnchoredOverlay = React.forwardRef(function (_a, refProp) {
1782
+ var as = _a.as, _b = _a.placement, initialPlacement = _b === void 0 ? 'auto' : _b, target = _a.target, children = _a.children, style = _a.style, _c = _a.open, open = _c === void 0 ? false : _c, offset = _a.offset, onOpenChange = _a.onOpenChange, onPlacementChange = _a.onPlacementChange, props = tslib.__rest(_a, ["as", "placement", "target", "children", "style", "open", "offset", "onOpenChange", "onPlacementChange"]);
1783
+ var ref = useSharedRef(refProp);
1784
+ var Component = as || 'div';
1785
+ var _d = reactDom$1.useFloating({
1786
+ open: open,
1787
+ // default to initial placement on top when placement is auto
1788
+ // @ts-expect-error auto placement is not a valid placement for floating-ui
1789
+ placement: initialPlacement.startsWith('auto') ? 'top' : initialPlacement,
1790
+ middleware: [
1791
+ reactDom$1.offset(offset !== null && offset !== void 0 ? offset : 0),
1792
+ initialPlacement.startsWith('auto')
1793
+ ? reactDom$1.autoPlacement({
1794
+ alignment: getAutoAlignment(initialPlacement)
1795
+ })
1796
+ : reactDom$1.flip()
1797
+ ].filter(Boolean),
1798
+ elements: {
1799
+ reference: resolveElement(target),
1800
+ floating: ref.current
1801
+ },
1802
+ whileElementsMounted: dom.autoUpdate
1803
+ }), floatingStyles = _d.floatingStyles, placement = _d.placement;
1804
+ useEscapeKey({
1805
+ active: open,
1806
+ capture: true,
1807
+ defaultPrevented: true,
1808
+ callback: function (event) {
1809
+ // when an anchored overlay is open, we want to prevent other potential "escape"
1810
+ // keypress events, like the closing of modals from occurring
1811
+ event.preventDefault();
1812
+ // istanbul ignore else
1813
+ if (typeof onOpenChange === 'function') {
1814
+ onOpenChange(!open);
1815
+ }
1816
+ }
1817
+ });
1818
+ React.useEffect(function () {
1819
+ if (typeof onPlacementChange === 'function') {
1820
+ onPlacementChange(placement);
1821
+ }
1822
+ }, [placement]);
1823
+ return (React__default["default"].createElement(Component, tslib.__assign({ ref: ref }, props, { style: tslib.__assign(tslib.__assign({}, floatingStyles), style) }), children));
1824
+ });
1825
+ AnchoredOverlay.displayName = 'AnchoredOverlay';
1826
+
1827
+ /**
1828
+ * Returns a unique set of id refs from the provided string
1829
+ * @param ids - string of id refs
1830
+ */
1831
+ function idRefs(ids) {
1832
+ if (!ids || !ids.trim()) {
1833
+ return new Set();
1834
+ }
1835
+ return new Set(ids.trim().split(/\s+/));
1836
+ }
1837
+ /**
1838
+ * Returns an updated id ref string with the provided id value added
1839
+ * @param ids - string of id refs
1840
+ * @param id - id to add
1841
+ */
1842
+ function addIdRef(ids, id) {
1843
+ return tslib.__spreadArray([], tslib.__read(idRefs(ids).add(id)), false).join(' ');
1844
+ }
1845
+ /**
1846
+ * Returns an updated id ref string with the provided id value removed
1847
+ * @param ids - string of id refs
1848
+ * @param id - id to remove
1849
+ */
1850
+ function removeIdRef(_ids, id) {
1851
+ var ids = idRefs(_ids);
1852
+ ids.delete(id);
1853
+ return tslib.__spreadArray([], tslib.__read(ids), false).join(' ');
1854
+ }
1855
+ /**
1856
+ * Returns if an id ref string contains the provided id value
1857
+ * @param ids - string of id refs
1858
+ * @param id - id to check if it exists in the provided idRef string
1859
+ */
1860
+ function hasIdRef(ids, id) {
1861
+ return idRefs(ids).has(id);
1862
+ }
1863
+
1666
1864
  var TIP_HIDE_DELAY = 100;
1667
1865
  // fires a custom "cauldron:tooltip:show" / "cauldron:tooltip:hide" event
1668
1866
  // to allow projects using cauldron to hook into when a tooltip is shown/hidden
@@ -1681,50 +1879,27 @@ function Tooltip(_a) {
1681
1879
  var _g = tslib.__read(propId ? [propId] : nextId.useId(1, 'tooltip'), 1), id = _g[0];
1682
1880
  var hideTimeoutRef = React.useRef(null);
1683
1881
  var _h = tslib.__read(React.useState(!!showProp || defaultShow), 2), showTooltip = _h[0], setShowTooltip = _h[1];
1684
- var _j = tslib.__read(React.useState(null), 2), targetElement = _j[0], setTargetElement = _j[1];
1685
- var _k = tslib.__read(React.useState(null), 2), tooltipElement = _k[0], setTooltipElement = _k[1];
1686
- var _l = tslib.__read(React.useState(null), 2), arrowElement = _l[0], setArrowElement = _l[1];
1882
+ var _j = tslib.__read(React.useState(null), 2), tooltipElement = _j[0], setTooltipElement = _j[1];
1883
+ var _k = tslib.__read(React.useState(initialPlacement), 2), placement = _k[0], setPlacement = _k[1];
1687
1884
  var hasAriaAssociation = association !== 'none';
1688
- var _m = reactPopper.usePopper(targetElement, tooltipElement, {
1689
- placement: initialPlacement,
1690
- modifiers: [
1691
- { name: 'preventOverflow', options: { padding: 8 } },
1692
- {
1693
- name: 'flip',
1694
- options: { fallbackPlacements: ['left', 'right', 'top', 'bottom'] }
1695
- },
1696
- { name: 'offset', options: { offset: [0, 8] } },
1697
- { name: 'arrow', options: { padding: 5, element: arrowElement } }
1698
- ]
1699
- }), styles = _m.styles, attributes = _m.attributes, update = _m.update;
1700
1885
  // Show the tooltip
1701
1886
  var show = React.useCallback(function () { return tslib.__awaiter(_this, void 0, void 0, function () {
1887
+ var targetElement;
1702
1888
  return tslib.__generator(this, function (_a) {
1703
- switch (_a.label) {
1704
- case 0:
1705
- // Clear the hide timeout if there was one pending
1706
- if (hideTimeoutRef.current) {
1707
- clearTimeout(hideTimeoutRef.current);
1708
- hideTimeoutRef.current = null;
1709
- }
1710
- if (!update) return [3 /*break*/, 2];
1711
- return [4 /*yield*/, update()];
1712
- case 1:
1713
- _a.sent();
1714
- _a.label = 2;
1715
- case 2:
1716
- setShowTooltip(true);
1717
- fireCustomEvent(true, targetElement);
1718
- return [2 /*return*/];
1889
+ targetElement = resolveElement(target);
1890
+ // Clear the hide timeout if there was one pending
1891
+ if (hideTimeoutRef.current) {
1892
+ clearTimeout(hideTimeoutRef.current);
1893
+ hideTimeoutRef.current = null;
1719
1894
  }
1895
+ setShowTooltip(true);
1896
+ fireCustomEvent(true, targetElement);
1897
+ return [2 /*return*/];
1720
1898
  });
1721
- }); }, [
1722
- targetElement,
1723
- // update starts off as null
1724
- update
1725
- ]);
1899
+ }); }, [target]);
1726
1900
  // Hide the tooltip
1727
1901
  var hide = React.useCallback(function () {
1902
+ var targetElement = resolveElement(target);
1728
1903
  if (!hideTimeoutRef.current) {
1729
1904
  hideTimeoutRef.current = setTimeout(function () {
1730
1905
  hideTimeoutRef.current = null;
@@ -1735,32 +1910,15 @@ function Tooltip(_a) {
1735
1910
  return function () {
1736
1911
  clearTimeout(hideTimeoutRef.current);
1737
1912
  };
1738
- }, [targetElement]);
1739
- // Keep targetElement in sync with target prop
1740
- React.useEffect(function () {
1741
- var targetElement = target && 'current' in target ? target.current : target;
1742
- setTargetElement(targetElement);
1743
1913
  }, [target]);
1744
1914
  React.useEffect(function () {
1745
1915
  if (typeof showProp === 'boolean') {
1746
1916
  setShowTooltip(showProp);
1747
1917
  }
1748
1918
  }, [showProp]);
1749
- // Get popper placement
1750
- var placement = (attributes.popper &&
1751
- attributes.popper['data-popper-placement']) ||
1752
- initialPlacement;
1753
- // Only listen to key ups when the tooltip is visible
1754
- useEscapeKey({
1755
- callback: function (event) {
1756
- event.preventDefault();
1757
- setShowTooltip(false);
1758
- },
1759
- capture: true,
1760
- active: showTooltip && typeof showProp !== 'boolean'
1761
- }, [setShowTooltip]);
1762
1919
  // Handle hover and focus events for the targetElement
1763
1920
  React.useEffect(function () {
1921
+ var targetElement = resolveElement(target);
1764
1922
  if (typeof showProp !== 'boolean') {
1765
1923
  targetElement === null || targetElement === void 0 ? void 0 : targetElement.addEventListener('mouseenter', show);
1766
1924
  targetElement === null || targetElement === void 0 ? void 0 : targetElement.addEventListener('mouseleave', hide);
@@ -1773,7 +1931,7 @@ function Tooltip(_a) {
1773
1931
  targetElement === null || targetElement === void 0 ? void 0 : targetElement.removeEventListener('focusin', show);
1774
1932
  targetElement === null || targetElement === void 0 ? void 0 : targetElement.removeEventListener('focusout', hide);
1775
1933
  };
1776
- }, [targetElement, show, hide, showProp]);
1934
+ }, [target, show, hide, showProp]);
1777
1935
  // Handle hover events for the tooltipElement
1778
1936
  React.useEffect(function () {
1779
1937
  if (typeof showProp !== 'boolean') {
@@ -1787,6 +1945,7 @@ function Tooltip(_a) {
1787
1945
  }, [tooltipElement, show, hide, showProp]);
1788
1946
  // Keep the target's id in sync
1789
1947
  React.useEffect(function () {
1948
+ var targetElement = resolveElement(target);
1790
1949
  if (hasAriaAssociation) {
1791
1950
  var idRefs = targetElement === null || targetElement === void 0 ? void 0 : targetElement.getAttribute(association);
1792
1951
  if (!hasIdRef(idRefs, id)) {
@@ -1799,14 +1958,14 @@ function Tooltip(_a) {
1799
1958
  targetElement.setAttribute(association, removeIdRef(idRefs, id));
1800
1959
  }
1801
1960
  };
1802
- }, [targetElement, id, association]);
1961
+ }, [target, id, association]);
1803
1962
  return (React__default["default"].createElement(React__default["default"].Fragment, null, (showTooltip || hideElementOnHidden) && isBrowser()
1804
- ? reactDom.createPortal(React__default["default"].createElement("div", tslib.__assign({ id: id, className: classNames__default["default"]('Tooltip', "Tooltip--".concat(placement), className, {
1963
+ ? reactDom.createPortal(React__default["default"].createElement(AnchoredOverlay, tslib.__assign({ id: id, target: target, placement: initialPlacement, onPlacementChange: setPlacement, open: showTooltip && typeof showProp !== 'boolean', onOpenChange: setShowTooltip, className: classNames__default["default"]('Tooltip', "Tooltip--".concat(placement), className, {
1805
1964
  TooltipInfo: variant === 'info',
1806
1965
  'Tooltip--hidden': !showTooltip && hideElementOnHidden,
1807
1966
  'Tooltip--big': variant === 'big'
1808
- }), ref: setTooltipElement, role: "tooltip", style: styles.popper }, attributes.popper, props),
1809
- variant !== 'big' && (React__default["default"].createElement("div", { className: "TooltipArrow", ref: setArrowElement, style: styles.arrow })),
1967
+ }), ref: setTooltipElement, role: "tooltip", offset: 8 }, props),
1968
+ variant !== 'big' && React__default["default"].createElement("div", { className: "TooltipArrow" }),
1810
1969
  children), (portal && 'current' in portal ? portal.current : portal) ||
1811
1970
  (
1812
1971
  // eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
@@ -2522,28 +2681,6 @@ var SearchField = React.forwardRef(function (_a, ref) {
2522
2681
  });
2523
2682
  SearchField.displayName = 'SearchField';
2524
2683
 
2525
- /**
2526
- * When a component needs to track an internal ref on a component that has a
2527
- * forwarded ref, useSharedRef will return a MutableRefObject<T> that will
2528
- * correctly invoke the parent ref as well providing an internal ref.
2529
- *
2530
- * @example
2531
- * React.forwardRef(function Component({ children }, ref) {
2532
- * const internalRef = useSharedRef<HTMLElement>(ref)
2533
- * if (internalRef.current) {
2534
- * // do something with the internal ref...
2535
- * }
2536
- * return (<div ref={internalRef}>...</div>)
2537
- * })
2538
- */
2539
- function useSharedRef(ref) {
2540
- var internalRef = React.useRef();
2541
- React.useEffect(function () {
2542
- setRef(ref, internalRef.current);
2543
- }, [ref]);
2544
- return internalRef;
2545
- }
2546
-
2547
2684
  function copyTextToClipboard(text) {
2548
2685
  return tslib.__awaiter(this, void 0, void 0, function () {
2549
2686
  var copied, element, range, selection;
@@ -2702,21 +2839,16 @@ var LoaderOverlay = React.forwardRef(function (_a, ref) {
2702
2839
  overlayRef.current.focus();
2703
2840
  }
2704
2841
  }, []);
2705
- var Wrapper = focusTrap ? FocusTrap__default["default"] : React__default["default"].Fragment;
2706
- var wrapperProps = focusTrap
2707
- ? {
2708
- focusTrapOptions: {
2709
- fallbackFocus: '.Loader__overlay'
2710
- }
2711
- }
2712
- : {};
2713
- return (React__default["default"].createElement(Wrapper, tslib.__assign({}, wrapperProps),
2714
- React__default["default"].createElement("div", tslib.__assign({ className: classNames__default["default"]('Loader__overlay', className), ref: overlayRef, tabIndex: -1 }, other),
2715
- React__default["default"].createElement("div", { className: "Loader__overlay__loader" },
2716
- React__default["default"].createElement(Loader, null),
2717
- React__default["default"].createElement(AxeLoader, null)),
2718
- label ? (React__default["default"].createElement("span", { className: "Loader__overlay__label" }, label)) : null,
2719
- children)));
2842
+ useFocusTrap(overlayRef, {
2843
+ disabled: !focusTrap,
2844
+ initialFocusElement: overlayRef
2845
+ });
2846
+ return (React__default["default"].createElement("div", tslib.__assign({ className: classNames__default["default"]('Loader__overlay', className), ref: overlayRef, tabIndex: -1 }, other),
2847
+ React__default["default"].createElement("div", { className: "Loader__overlay__loader" },
2848
+ React__default["default"].createElement(Loader, null),
2849
+ React__default["default"].createElement(AxeLoader, null)),
2850
+ label ? React__default["default"].createElement("span", { className: "Loader__overlay__label" }, label) : null,
2851
+ children));
2720
2852
  });
2721
2853
  LoaderOverlay.displayName = 'LoaderOverlay';
2722
2854
 
@@ -2800,6 +2932,16 @@ function useTable() {
2800
2932
  return React.useContext(TableContext);
2801
2933
  }
2802
2934
 
2935
+ function parseColumnWidth(width) {
2936
+ var number = Number(width);
2937
+ if (!isNaN(number)) {
2938
+ return "".concat(number, "px");
2939
+ }
2940
+ if (!width) {
2941
+ return 'auto';
2942
+ }
2943
+ return width;
2944
+ }
2803
2945
  var Table = React__default["default"].forwardRef(function (_a, ref) {
2804
2946
  var children = _a.children, className = _a.className, variant = _a.variant, layout = _a.layout, _b = _a.columns, columnsProp = _b === void 0 ? [] : _b, style = _a.style, other = tslib.__rest(_a, ["children", "className", "variant", "layout", "columns", "style"]);
2805
2947
  var isGridLayout = layout === 'grid';
@@ -2820,8 +2962,11 @@ var Table = React__default["default"].forwardRef(function (_a, ref) {
2820
2962
  }
2821
2963
  return columns
2822
2964
  .map(function (_a) {
2823
- var width = _a.width;
2824
- return width || 'auto';
2965
+ var width = _a.width, maxWidth = _a.maxWidth;
2966
+ if (maxWidth) {
2967
+ return "minmax(".concat(parseColumnWidth(width), ", ").concat(parseColumnWidth(maxWidth), ")");
2968
+ }
2969
+ return parseColumnWidth(width);
2825
2970
  })
2826
2971
  .join(' ');
2827
2972
  }, [layout, columns]);
@@ -3389,16 +3534,14 @@ var TwoColumnPanel = React.forwardRef(function (_a, ref) {
3389
3534
  setCollapsed(true);
3390
3535
  }
3391
3536
  };
3537
+ useFocusTrap(columnLeftRef, {
3538
+ disabled: !showPanel || !isFocusTrap
3539
+ });
3392
3540
  return (React__default["default"].createElement("div", tslib.__assign({ className: classNames__default["default"]('TwoColumnPanel', className, {
3393
3541
  'TwoColumnPanel--show': !isCollapsed,
3394
3542
  'TwoColumnPanel--hide': isCollapsed
3395
3543
  }) }, props, { ref: ref }),
3396
3544
  React__default["default"].createElement(React__default["default"].Fragment, null,
3397
- React__default["default"].createElement(FocusTrap__default["default"], { active: !isCollapsed && isFocusTrap, focusTrapOptions: {
3398
- escapeDeactivates: true,
3399
- allowOutsideClick: true,
3400
- fallbackFocus: columnLeftRef.current
3401
- }, containerElements: [columnLeftRef.current] }),
3402
3545
  React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: handleClickOutside, target: columnLeftRef.current }),
3403
3546
  isCollapsed ? null : skipLink,
3404
3547
  showPanel ? ColumnLeftComponent : null,
@@ -3447,19 +3590,21 @@ var ListboxContext = React.createContext({
3447
3590
  options: [],
3448
3591
  active: null,
3449
3592
  selected: null,
3593
+ multiselect: false,
3450
3594
  setOptions: function () { return null; },
3451
3595
  onSelect: function () { return null; }
3452
3596
  });
3453
3597
  function ListboxProvider(_a) {
3454
- var options = _a.options, active = _a.active, selected = _a.selected, setOptions = _a.setOptions, onSelect = _a.onSelect, children = _a.children;
3598
+ var options = _a.options, active = _a.active, selected = _a.selected, multiselect = _a.multiselect, setOptions = _a.setOptions, onSelect = _a.onSelect, children = _a.children;
3455
3599
  var Provider = ListboxContext.Provider;
3456
3600
  var value = React.useMemo(function () { return ({
3457
3601
  options: options,
3458
3602
  active: active,
3459
3603
  selected: selected,
3604
+ multiselect: multiselect,
3460
3605
  setOptions: setOptions,
3461
3606
  onSelect: onSelect
3462
- }); }, [options, active, selected, setOptions]);
3607
+ }); }, [options, active, selected, multiselect, setOptions]);
3463
3608
  return React__default["default"].createElement(Provider, { value: value }, children);
3464
3609
  }
3465
3610
  function useListboxContext() {
@@ -3481,40 +3626,78 @@ var optionMatchesValue = function (option, value) {
3481
3626
  option.value === value;
3482
3627
  };
3483
3628
  var Listbox = React.forwardRef(function (_a, ref) {
3484
- var _b = _a.as, Component = _b === void 0 ? 'ul' : _b, children = _a.children, defaultValue = _a.defaultValue, value = _a.value, _c = _a.navigation, navigation = _c === void 0 ? 'bound' : _c, onKeyDown = _a.onKeyDown, onFocus = _a.onFocus, onSelectionChange = _a.onSelectionChange, onActiveChange = _a.onActiveChange, props = tslib.__rest(_a, ["as", "children", "defaultValue", "value", "navigation", "onKeyDown", "onFocus", "onSelectionChange", "onActiveChange"]);
3485
- var _d = tslib.__read(React.useState([]), 2), options = _d[0], setOptions = _d[1];
3486
- var _e = tslib.__read(React.useState(null), 2), activeOption = _e[0], setActiveOption = _e[1];
3487
- var _f = tslib.__read(React.useState(null), 2), selectedOption = _f[0], setSelectedOption = _f[1];
3629
+ var _b = _a.as, Component = _b === void 0 ? 'ul' : _b, children = _a.children, defaultValue = _a.defaultValue, value = _a.value, _c = _a.navigation, navigation = _c === void 0 ? 'bound' : _c, _d = _a.multiselect, multiselect = _d === void 0 ? false : _d, onKeyDown = _a.onKeyDown, onFocus = _a.onFocus, onSelectionChange = _a.onSelectionChange, onActiveChange = _a.onActiveChange, props = tslib.__rest(_a, ["as", "children", "defaultValue", "value", "navigation", "multiselect", "onKeyDown", "onFocus", "onSelectionChange", "onActiveChange"]);
3630
+ var _e = tslib.__read(React.useState([]), 2), options = _e[0], setOptions = _e[1];
3631
+ var _f = tslib.__read(React.useState(null), 2), activeOption = _f[0], setActiveOption = _f[1];
3632
+ var _g = tslib.__read(React.useState([]), 2), selectedOptions = _g[0], setSelectedOptions = _g[1];
3488
3633
  var listboxRef = useSharedRef(ref);
3489
3634
  var isControlled = typeof value !== 'undefined';
3490
3635
  React.useLayoutEffect(function () {
3491
- if (!isControlled && selectedOption) {
3636
+ if (!isControlled && selectedOptions.length > 0) {
3492
3637
  return;
3493
3638
  }
3494
3639
  var listboxValue = isControlled ? value : defaultValue;
3495
- var matchingOption = options.find(function (option) {
3496
- return optionMatchesValue(option, listboxValue);
3497
- });
3498
- setSelectedOption(matchingOption || null);
3499
- setActiveOption(matchingOption || null);
3500
- }, [isControlled, options, value]);
3640
+ if (!listboxValue) {
3641
+ return;
3642
+ }
3643
+ if (multiselect) {
3644
+ var matchingOptions = options.filter(function (option) {
3645
+ return listboxValue.find(function (value) {
3646
+ return optionMatchesValue(option, value);
3647
+ });
3648
+ });
3649
+ setSelectedOptions(matchingOptions);
3650
+ setActiveOption(matchingOptions[0] || null);
3651
+ }
3652
+ else {
3653
+ var matchingOption = options.find(function (option) {
3654
+ return optionMatchesValue(option, listboxValue);
3655
+ });
3656
+ setSelectedOptions(matchingOption ? [matchingOption] : []);
3657
+ setActiveOption(matchingOption || null);
3658
+ }
3659
+ }, [isControlled, options, value, defaultValue]);
3501
3660
  React.useEffect(function () {
3502
3661
  if (activeOption) {
3503
3662
  onActiveChange === null || onActiveChange === void 0 ? void 0 : onActiveChange(activeOption);
3504
3663
  }
3505
3664
  }, [activeOption]);
3506
3665
  var handleSelect = React.useCallback(function (option) {
3666
+ var _a;
3507
3667
  setActiveOption(option);
3668
+ var optionIsSelected = selectedOptions.some(function (selected) { return selected.element === option.element; });
3669
+ var previousValues = selectedOptions.map(function (selected) { return selected.value; });
3508
3670
  // istanbul ignore else
3509
3671
  if (!isControlled) {
3510
- setSelectedOption(option);
3672
+ if (!multiselect) {
3673
+ setSelectedOptions([option]);
3674
+ }
3675
+ else {
3676
+ setSelectedOptions(optionIsSelected
3677
+ ? tslib.__spreadArray([], tslib.__read(selectedOptions.filter(function (selected) { return selected.element !== option.element; })), false) : tslib.__spreadArray(tslib.__spreadArray([], tslib.__read(selectedOptions), false), [option], false));
3678
+ }
3511
3679
  }
3512
- onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange({
3513
- target: option.element,
3514
- value: option.value,
3515
- previousValue: selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value
3516
- });
3517
- }, [isControlled, selectedOption]);
3680
+ if (multiselect) {
3681
+ onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange({
3682
+ target: option.element,
3683
+ value: optionIsSelected
3684
+ ? selectedOptions
3685
+ .filter(function (selectedOption) {
3686
+ return selectedOption.element !== option.element;
3687
+ })
3688
+ .map(function (selectedOption) { return selectedOption.value; })
3689
+ : tslib.__spreadArray(tslib.__spreadArray([], tslib.__read(previousValues), false), [option.value], false),
3690
+ previousValue: previousValues
3691
+ });
3692
+ }
3693
+ else {
3694
+ onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange({
3695
+ target: option.element,
3696
+ value: option.value,
3697
+ previousValue: (_a = selectedOptions[0]) === null || _a === void 0 ? void 0 : _a.value
3698
+ });
3699
+ }
3700
+ }, [isControlled, selectedOptions, multiselect, onSelectionChange]);
3518
3701
  var handleKeyDown = React.useCallback(function (event) {
3519
3702
  onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
3520
3703
  if (!keys.includes(event.key)) {
@@ -3564,9 +3747,9 @@ var Listbox = React.forwardRef(function (_a, ref) {
3564
3747
  activeOption && handleSelect(activeOption);
3565
3748
  break;
3566
3749
  }
3567
- }, [options, activeOption, navigation]);
3750
+ }, [options, activeOption, navigation, handleSelect]);
3568
3751
  var handleFocus = React.useCallback(function (event) {
3569
- if (!activeOption && !selectedOption) {
3752
+ if (!activeOption) {
3570
3753
  var firstOption = options.find(function (option) { return !isDisabledOption(option); });
3571
3754
  // istanbul ignore else
3572
3755
  if (firstOption) {
@@ -3574,13 +3757,14 @@ var Listbox = React.forwardRef(function (_a, ref) {
3574
3757
  }
3575
3758
  // istanbul ignore else
3576
3759
  }
3577
- else if (event.target === listboxRef.current) {
3578
- setActiveOption(selectedOption);
3760
+ else if (selectedOptions.length &&
3761
+ event.target === listboxRef.current) {
3762
+ setActiveOption(selectedOptions[selectedOptions.length - 1]);
3579
3763
  }
3580
3764
  onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
3581
- }, [options, activeOption, selectedOption]);
3582
- return (React__default["default"].createElement(Component, tslib.__assign({ role: "listbox", ref: listboxRef, tabIndex: "0", onKeyDown: handleKeyDown, onFocus: handleFocus, "aria-activedescendant": activeOption ? getOptionId(activeOption) : undefined }, props),
3583
- React__default["default"].createElement(ListboxProvider, { options: options, active: activeOption, selected: selectedOption, setOptions: setOptions, onSelect: handleSelect }, children)));
3765
+ }, [options, activeOption, selectedOptions]);
3766
+ return (React__default["default"].createElement(Component, tslib.__assign({ role: "listbox", ref: listboxRef, tabIndex: "0", onKeyDown: handleKeyDown, onFocus: handleFocus, "aria-multiselectable": multiselect ? true : undefined, "aria-activedescendant": activeOption ? getOptionId(activeOption) : undefined }, props),
3767
+ React__default["default"].createElement(ListboxProvider, { options: options, active: activeOption, multiselect: multiselect, selected: selectedOptions, setOptions: setOptions, onSelect: handleSelect }, children)));
3584
3768
  });
3585
3769
  Listbox.displayName = 'Listbox';
3586
3770
 
@@ -3590,12 +3774,15 @@ function isElementPreceding(a, b) {
3590
3774
  var ListboxOption = React.forwardRef(function (_a, ref) {
3591
3775
  var _b;
3592
3776
  var _c;
3593
- var propId = _a.id, className = _a.className, _d = _a.as, Component = _d === void 0 ? 'li' : _d, children = _a.children, value = _a.value, disabled = _a.disabled, _e = _a.activeClass, activeClass = _e === void 0 ? 'ListboxOption--active' : _e, onClick = _a.onClick, props = tslib.__rest(_a, ["id", "className", "as", "children", "value", "disabled", "activeClass", "onClick"]);
3777
+ var propId = _a.id, className = _a.className, _d = _a.as, Component = _d === void 0 ? 'li' : _d, children = _a.children, value = _a.value, disabled = _a.disabled, selectedProp = _a.selected, _e = _a.activeClass, activeClass = _e === void 0 ? 'ListboxOption--active' : _e, onClick = _a.onClick, props = tslib.__rest(_a, ["id", "className", "as", "children", "value", "disabled", "selected", "activeClass", "onClick"]);
3594
3778
  var _f = useListboxContext(), active = _f.active, selected = _f.selected, setOptions = _f.setOptions, onSelect = _f.onSelect;
3595
3779
  var listboxOptionRef = useSharedRef(ref);
3596
3780
  var _g = tslib.__read(propId ? [propId] : nextId.useId(1, 'listbox-option'), 1), id = _g[0];
3597
- var isActive = active !== null && active.element === listboxOptionRef.current;
3598
- var isSelected = selected !== null && selected.element === listboxOptionRef.current;
3781
+ var isActive = (active === null || active === void 0 ? void 0 : active.element) === listboxOptionRef.current;
3782
+ var isSelected = typeof selectedProp === 'boolean'
3783
+ ? selectedProp
3784
+ : selected !== null &&
3785
+ !!selected.find(function (option) { return option.element === listboxOptionRef.current; });
3599
3786
  var optionValue = typeof value !== 'undefined'
3600
3787
  ? value
3601
3788
  : (_c = listboxOptionRef.current) === null || _c === void 0 ? void 0 : _c.innerText;
@@ -3645,7 +3832,7 @@ var ListboxOption = React.forwardRef(function (_a, ref) {
3645
3832
  }
3646
3833
  onSelect({ element: listboxOptionRef.current, value: optionValue });
3647
3834
  onClick === null || onClick === void 0 ? void 0 : onClick(event);
3648
- }, [optionValue]);
3835
+ }, [optionValue, onSelect, onClick, disabled]);
3649
3836
  return (React__default["default"].createElement(Component, tslib.__assign({ id: id, className: classNames__default["default"](className, (_b = {},
3650
3837
  _b[activeClass] = isActive,
3651
3838
  _b)), role: "option", ref: listboxOptionRef, "aria-disabled": typeof disabled === 'boolean' ? disabled : undefined, "aria-selected": isSelected, onClick: handleClick }, props), children));
@@ -3767,17 +3954,20 @@ var ComboboxMatch = function (_a) {
3767
3954
  React__default["default"].createElement("span", null, matchAfter)));
3768
3955
  };
3769
3956
  var ComboboxOption = React.forwardRef(function (_a, ref) {
3957
+ var _b;
3770
3958
  var className = _a.className, children = _a.children, disabled = _a.disabled, propId = _a.id, description = _a.description, propValue = _a.value, formValue = _a.formValue, props = tslib.__rest(_a, ["className", "children", "disabled", "id", "description", "value", "formValue"]);
3771
- var _b = tslib.__read(propId ? [propId] : nextId.useId(1, 'combobox-option'), 1), id = _b[0];
3772
- var _c = useListboxContext(), selected = _c.selected, active = _c.active;
3773
- var _d = useComboboxContext(), selectedValue = _d.selectedValue, matches = _d.matches, setMatchingOptions = _d.setMatchingOptions, setFormValue = _d.setFormValue;
3959
+ var _c = tslib.__read(propId ? [propId] : nextId.useId(1, 'combobox-option'), 1), id = _c[0];
3960
+ var _d = useListboxContext(), selected = _d.selected, active = _d.active;
3961
+ var _e = useComboboxContext(), selectedValue = _e.selectedValue, matches = _e.matches, setMatchingOptions = _e.setMatchingOptions, setFormValue = _e.setFormValue;
3774
3962
  var comboboxOptionRef = useSharedRef(ref);
3775
3963
  var intersectionRef = useIntersectionRef(comboboxOptionRef, {
3776
3964
  root: null,
3777
3965
  threshold: 1.0
3778
3966
  });
3779
3967
  var isActive = !!(active === null || active === void 0 ? void 0 : active.element) && active.element === comboboxOptionRef.current;
3780
- var isSelected = !!(selected === null || selected === void 0 ? void 0 : selected.element) && selected.element === comboboxOptionRef.current;
3968
+ var isSelected = !!(selected &&
3969
+ !!((_b = selected[0]) === null || _b === void 0 ? void 0 : _b.element) &&
3970
+ selected[0].element === comboboxOptionRef.current);
3781
3971
  var isMatching = (typeof matches === 'boolean' && matches) ||
3782
3972
  (typeof matches === 'function' && matches(children));
3783
3973
  // istanbul ignore next
@@ -4113,19 +4303,7 @@ var Popover = React.forwardRef(function (_a, ref) {
4113
4303
  var _f = tslib.__read(React.useState(null), 2), targetElement = _f[0], setTargetElement = _f[1];
4114
4304
  var _g = tslib.__read(React.useState(null), 2), isolator = _g[0], setIsolator = _g[1];
4115
4305
  var popoverRef = useSharedRef(ref);
4116
- var _h = tslib.__read(React.useState(null), 2), arrowElement = _h[0], setArrowElement = _h[1];
4117
- var _j = reactPopper.usePopper(targetElement, popoverRef === null || popoverRef === void 0 ? void 0 : popoverRef.current, {
4118
- placement: initialPlacement,
4119
- modifiers: [
4120
- { name: 'preventOverflow', options: { padding: 8 } },
4121
- { name: 'flip' },
4122
- { name: 'offset', options: { offset: [0, 8] } },
4123
- { name: 'arrow', options: { padding: 5, element: arrowElement } }
4124
- ]
4125
- }), styles = _j.styles, attributes = _j.attributes;
4126
- var placement = (attributes.popper &&
4127
- attributes.popper['data-popper-placement']) ||
4128
- initialPlacement;
4306
+ var _h = tslib.__read(React.useState(initialPlacement), 2), placement = _h[0], setPlacement = _h[1];
4129
4307
  var additionalProps = variant === 'prompt' && !props['aria-label']
4130
4308
  ? { 'aria-labelledby': "".concat(id, "-label") }
4131
4309
  : {};
@@ -4157,15 +4335,8 @@ var Popover = React.forwardRef(function (_a, ref) {
4157
4335
  attachIsolator();
4158
4336
  }, [popoverRef.current]);
4159
4337
  React.useEffect(function () {
4160
- if (show && popoverRef.current) {
4161
- // Find the first focusable element inside the container
4162
- var firstFocusableElement = popoverRef.current.querySelector(focusableSelector);
4163
- if (firstFocusableElement instanceof HTMLElement) {
4164
- firstFocusableElement.focus();
4165
- }
4166
- }
4167
4338
  targetElement === null || targetElement === void 0 ? void 0 : targetElement.setAttribute('aria-expanded', Boolean(show).toString());
4168
- }, [show, popoverRef.current]);
4339
+ }, [show]);
4169
4340
  React.useEffect(function () {
4170
4341
  var attrText = targetElement === null || targetElement === void 0 ? void 0 : targetElement.getAttribute('aria-controls');
4171
4342
  var hasPopupAttr = targetElement === null || targetElement === void 0 ? void 0 : targetElement.getAttribute('aria-haspopup');
@@ -4199,20 +4370,17 @@ var Popover = React.forwardRef(function (_a, ref) {
4199
4370
  callback: handleClosePopover,
4200
4371
  active: show
4201
4372
  }, [show]);
4373
+ useFocusTrap(popoverRef, { disabled: !show, returnFocus: true });
4202
4374
  if (!show || !isBrowser())
4203
4375
  return null;
4204
- return reactDom.createPortal(React__default["default"].createElement(FocusTrap__default["default"], { focusTrapOptions: {
4205
- allowOutsideClick: true,
4206
- fallbackFocus: '.Popover__borderLeft'
4207
- } },
4208
- React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: handleClickOutside },
4209
- React__default["default"].createElement("div", tslib.__assign({ id: id, className: classNames__default["default"]('Popover', "Popover--".concat(placement), className, {
4210
- 'Popover--hidden': !show,
4211
- 'Popover--prompt': variant === 'prompt'
4212
- }), ref: popoverRef, role: "dialog", style: styles.popper }, attributes.popper, additionalProps, props),
4213
- React__default["default"].createElement("div", { className: "Popover__popoverArrow", ref: setArrowElement, style: styles.arrow }),
4214
- React__default["default"].createElement("div", { className: "Popover__borderLeft" }),
4215
- variant === 'prompt' ? (React__default["default"].createElement(PromptPopoverContent, { applyButtonText: applyButtonText, onApply: onApply, closeButtonText: closeButtonText, infoText: infoText || '', onClose: handleClosePopover, infoTextId: "".concat(id, "-label") })) : (children)))), (portal && 'current' in portal ? portal.current : portal) ||
4376
+ return reactDom.createPortal(React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: handleClickOutside },
4377
+ React__default["default"].createElement(AnchoredOverlay, tslib.__assign({ id: id, className: classNames__default["default"]('Popover', "Popover--".concat(placement), className, {
4378
+ 'Popover--hidden': !show,
4379
+ 'Popover--prompt': variant === 'prompt'
4380
+ }), ref: popoverRef, role: "dialog", target: target, open: show, placement: initialPlacement, onPlacementChange: setPlacement, offset: 8 }, additionalProps, props),
4381
+ React__default["default"].createElement("div", { className: "Popover__popoverArrow" }),
4382
+ React__default["default"].createElement("div", { className: "Popover__borderLeft" }),
4383
+ variant === 'prompt' ? (React__default["default"].createElement(PromptPopoverContent, { applyButtonText: applyButtonText, onApply: onApply, closeButtonText: closeButtonText, infoText: infoText || '', onClose: handleClosePopover, infoTextId: "".concat(id, "-label") })) : (children))), (portal && 'current' in portal ? portal.current : portal) ||
4216
4384
  // Dependent on "isBrowser" check above:
4217
4385
  // eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
4218
4386
  document.body);
@@ -4280,7 +4448,6 @@ var Drawer = React.forwardRef(function (_a, ref) {
4280
4448
  var children = _a.children, className = _a.className, position = _a.position, _b = _a.open, open = _b === void 0 ? false : _b, _c = _a.behavior, behavior = _c === void 0 ? 'modal' : _c, _d = _a.focusOptions, focusOptions = _d === void 0 ? {} : _d, portal = _a.portal, onClose = _a.onClose, style = _a.style, props = tslib.__rest(_a, ["children", "className", "position", "open", "behavior", "focusOptions", "portal", "onClose", "style"]);
4281
4449
  var drawerRef = useSharedRef(ref);
4282
4450
  var openRef = React.useRef(!!open);
4283
- var previousActiveElementRef = React.useRef(null);
4284
4451
  var focusInitial = focusOptions.initialFocus, focusReturn = focusOptions.returnFocus;
4285
4452
  var _e = tslib.__read(React.useState(!!open), 2), isTransitioning = _e[0], setIsTransitioning = _e[1];
4286
4453
  var isModal = behavior === 'modal';
@@ -4320,60 +4487,27 @@ var Drawer = React.forwardRef(function (_a, ref) {
4320
4487
  isolator.deactivate();
4321
4488
  };
4322
4489
  }, [isModal, open]);
4323
- React.useLayoutEffect(function () {
4324
- var _a, _b, _c;
4325
- if (open) {
4326
- previousActiveElementRef.current =
4327
- document.activeElement;
4328
- var initialFocusElement = resolveElement(focusInitial);
4329
- if (initialFocusElement) {
4330
- initialFocusElement.focus();
4331
- }
4332
- else {
4333
- var focusable = (_a = drawerRef.current) === null || _a === void 0 ? void 0 : _a.querySelector(focusableSelector);
4334
- if (focusable) {
4335
- focusable.focus();
4336
- }
4337
- else {
4338
- // fallback focus
4339
- (_b = drawerRef.current) === null || _b === void 0 ? void 0 : _b.focus();
4340
- }
4341
- }
4342
- }
4343
- else if (previousActiveElementRef.current) {
4344
- var returnFocusElement = resolveElement(focusReturn);
4345
- if (returnFocusElement) {
4346
- returnFocusElement.focus();
4347
- }
4348
- else {
4349
- // fallback focus
4350
- (_c = previousActiveElementRef.current) === null || _c === void 0 ? void 0 : _c.focus();
4351
- }
4352
- }
4353
- }, [open, focusInitial, focusReturn]);
4354
4490
  useEscapeKey({ callback: handleClose, active: open, defaultPrevented: true }, [onClose]);
4355
4491
  // istanbul ignore next
4356
4492
  if (!isBrowser()) {
4357
4493
  return null;
4358
4494
  }
4495
+ useFocusTrap(drawerRef, {
4496
+ disabled: !isModal || !open,
4497
+ initialFocusElement: focusInitial || drawerRef,
4498
+ returnFocus: true,
4499
+ returnFocusElement: focusReturn
4500
+ });
4359
4501
  var portalElement = resolveElement(portal);
4360
4502
  return reactDom.createPortal(React__default["default"].createElement(React__default["default"].Fragment, null,
4361
4503
  React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: handleClose, mouseEvent: open ? undefined : false, touchEvent: open ? undefined : false, target: drawerRef },
4362
- React__default["default"].createElement(FocusTrap__default["default"], { active: !!isModal && !!open, focusTrapOptions: {
4363
- allowOutsideClick: true,
4364
- escapeDeactivates: false,
4365
- clickOutsideDeactivates: false,
4366
- initialFocus: false,
4367
- setReturnFocus: false,
4368
- fallbackFocus: function () { return drawerRef.current; }
4369
- } },
4370
- React__default["default"].createElement("div", tslib.__assign({ ref: drawerRef, className: classNames__default["default"](className, 'Drawer', {
4371
- 'Drawer--open': !!open,
4372
- 'Drawer--top': position === 'top',
4373
- 'Drawer--bottom': position === 'bottom',
4374
- 'Drawer--left': position === 'left',
4375
- 'Drawer--right': position === 'right'
4376
- }), "aria-hidden": !open || undefined, style: tslib.__assign({ visibility: !open && !isTransitioning ? 'hidden' : undefined }, style), tabIndex: open ? -1 : undefined }, props), children))),
4504
+ React__default["default"].createElement("div", tslib.__assign({ ref: drawerRef, className: classNames__default["default"](className, 'Drawer', {
4505
+ 'Drawer--open': !!open,
4506
+ 'Drawer--top': position === 'top',
4507
+ 'Drawer--bottom': position === 'bottom',
4508
+ 'Drawer--left': position === 'left',
4509
+ 'Drawer--right': position === 'right'
4510
+ }), "aria-hidden": !open || undefined, style: tslib.__assign({ visibility: !open && !isTransitioning ? 'hidden' : undefined }, style), tabIndex: open ? -1 : undefined }, props), children)),
4377
4511
  React__default["default"].createElement(Scrim, { show: !!open && !!isModal })), portalElement ||
4378
4512
  (
4379
4513
  // eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
@@ -4479,6 +4613,7 @@ exports.AddressLine = AddressLine;
4479
4613
  exports.Alert = Alert;
4480
4614
  exports.AlertActions = AlertActions;
4481
4615
  exports.AlertContent = AlertContent;
4616
+ exports.AnchoredOverlay = AnchoredOverlay;
4482
4617
  exports.AriaIsolate = AriaIsolate;
4483
4618
  exports.Badge = Badge;
4484
4619
  exports.BadgeLabel = BadgeLabel;