@deque/cauldron-react 6.12.0-canary.b5982813 → 6.12.0-canary.dc7e4ac4

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.
@@ -0,0 +1,20 @@
1
+ import { type Placement } from '@floating-ui/dom';
2
+ import React from 'react';
3
+ declare const AnchoredOverlay: React.ForwardRefExoticComponent<{
4
+ /** A target element or ref to attach the overlay anchor element. */
5
+ target: HTMLElement | React.RefObject<HTMLElement> | React.MutableRefObject<HTMLElement>;
6
+ /** Positional placement value to anchor the overlay element relative to its anchored target. */
7
+ placement?: "auto" | Placement | "auto-start" | "auto-end" | undefined;
8
+ /** Determines if the overlay anchor is currently visible. */
9
+ open?: boolean | undefined;
10
+ /** A callback function that is called when the overlay state changes. */
11
+ onOpenChange?: ((open: boolean) => void) | undefined;
12
+ /** A callback function that is called when the placement of the overlay changes. */
13
+ onPlacementChange?: ((placement: Placement) => void) | undefined;
14
+ /** An optional offset number to position the anchor element from its anchored target. */
15
+ offset?: number | undefined;
16
+ children?: React.ReactNode;
17
+ } & React.HTMLAttributes<HTMLElement> & {
18
+ as?: React.ElementType<any, keyof React.JSX.IntrinsicElements> | undefined;
19
+ } & React.RefAttributes<HTMLElement>>;
20
+ export default AnchoredOverlay;
@@ -2,15 +2,29 @@ import React from 'react';
2
2
  import type { ListboxOption } from './ListboxContext';
3
3
  import type { ListboxValue } from './ListboxOption';
4
4
  import type { PolymorphicProps, PolymorphicComponent } from '../../utils/polymorphicComponent';
5
- interface ListboxProps extends PolymorphicProps<Omit<React.HTMLAttributes<HTMLElement>, 'onSelect'>> {
6
- value?: ListboxValue;
5
+ interface BaseListboxProps extends PolymorphicProps<Omit<React.HTMLAttributes<HTMLElement>, 'onSelect' | 'defaultValue'>> {
7
6
  navigation?: 'cycle' | 'bound';
8
- onSelectionChange?: <T extends HTMLElement = HTMLElement>({ value }: {
7
+ onActiveChange?: (option: ListboxOption) => void;
8
+ }
9
+ interface SingleSelectListboxProps extends BaseListboxProps {
10
+ multiselect?: false;
11
+ value?: ListboxValue;
12
+ defaultValue?: ListboxValue;
13
+ onSelectionChange?: <T extends HTMLElement = HTMLElement>(props: {
9
14
  target: T;
10
15
  previousValue: ListboxValue;
11
16
  value: ListboxValue;
12
17
  }) => void;
13
- onActiveChange?: (option: ListboxOption) => void;
14
18
  }
15
- declare const Listbox: PolymorphicComponent<ListboxProps>;
19
+ interface MultiSelectListboxProps extends BaseListboxProps {
20
+ multiselect: true;
21
+ value?: ListboxValue[];
22
+ defaultValue?: ListboxValue[];
23
+ onSelectionChange?: <T extends HTMLElement = HTMLElement>(props: {
24
+ target: T;
25
+ previousValue: ListboxValue[];
26
+ value: ListboxValue[];
27
+ }) => void;
28
+ }
29
+ declare const Listbox: PolymorphicComponent<SingleSelectListboxProps | MultiSelectListboxProps>;
16
30
  export default Listbox;
@@ -8,7 +8,8 @@ type ListboxOption<Element = HTMLElement, Value = string | number> = {
8
8
  type ListboxContext<T extends ListboxOption> = {
9
9
  options: T[];
10
10
  active: T | null;
11
- selected: T | null;
11
+ selected: T[] | null;
12
+ multiselect: boolean;
12
13
  setOptions: React.Dispatch<React.SetStateAction<T[]>>;
13
14
  onSelect: (option: T) => void;
14
15
  };
@@ -19,9 +20,10 @@ declare const ListboxContext: React.Context<{
19
20
  options: never[];
20
21
  active: null;
21
22
  selected: null;
23
+ multiselect: boolean;
22
24
  setOptions: () => null;
23
25
  onSelect: () => null;
24
26
  }>;
25
- declare function ListboxProvider<T extends ListboxOption>({ options, active, selected, setOptions, onSelect, children }: ListboxProvider<T>): React.JSX.Element;
27
+ declare function ListboxProvider<T extends ListboxOption>({ options, active, selected, multiselect, setOptions, onSelect, children }: ListboxProvider<T>): React.JSX.Element;
26
28
  declare function useListboxContext<T extends ListboxOption>(): ListboxContext<T>;
27
29
  export { ListboxProvider, useListboxContext, ListboxOption };
@@ -4,6 +4,7 @@ export type ListboxValue = Readonly<string | number | undefined>;
4
4
  interface ListboxOptionProps extends PolymorphicProps<React.HTMLAttributes<HTMLElement>> {
5
5
  value?: ListboxValue;
6
6
  disabled?: boolean;
7
+ selected?: boolean;
7
8
  activeClass?: string;
8
9
  }
9
10
  declare const ListboxOption: PolymorphicComponent<ListboxOptionProps>;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Placement } from '@popperjs/core';
2
+ import type AnchoredOverlay from '../AnchoredOverlay';
3
3
  import { ContentNode } from '../../types';
4
4
  interface Props extends React.HTMLAttributes<HTMLDivElement> {
5
5
  totalItems: number;
@@ -15,7 +15,7 @@ interface Props extends React.HTMLAttributes<HTMLDivElement> {
15
15
  onPreviousPageClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
16
16
  onFirstPageClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
17
17
  onLastPageClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
18
- tooltipPlacement?: Placement;
18
+ tooltipPlacement?: React.ComponentProps<typeof AnchoredOverlay>['placement'];
19
19
  thin?: boolean;
20
20
  className?: string;
21
21
  }
@@ -1,13 +1,13 @@
1
1
  import React, { ReactNode } from 'react';
2
- import { Placement } from '@popperjs/core';
3
2
  import { Cauldron } from '../../types';
3
+ import AnchoredOverlay from '../AnchoredOverlay';
4
4
  export type PopoverVariant = 'prompt' | 'custom';
5
5
  type BaseProps = React.HTMLAttributes<HTMLDivElement> & {
6
6
  target: React.RefObject<HTMLElement> | HTMLElement;
7
7
  variant?: PopoverVariant;
8
8
  show: boolean;
9
9
  onClose: () => void;
10
- placement?: Placement;
10
+ placement?: React.ComponentProps<typeof AnchoredOverlay>['placement'];
11
11
  portal?: React.RefObject<HTMLElement> | HTMLElement;
12
12
  };
13
13
  type CustomProps = BaseProps & {
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  export type Column = {
3
3
  align: ColumnAlignment;
4
4
  width?: ColumnWidth;
5
+ maxWidth?: ColumnWidth;
5
6
  };
6
7
  export type ColumnAlignment = 'start' | 'center' | 'end';
7
8
  export type ColumnWidth = 'auto' | 'min-content' | 'max-content' | `${number}` | `${number}%` | `${number}fr`;
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { Placement } from '@popperjs/core';
2
+ import AnchoredOverlay from '../AnchoredOverlay';
3
3
  export interface TooltipProps extends React.HTMLAttributes<HTMLDivElement> {
4
4
  children: React.ReactNode;
5
5
  className?: string;
@@ -8,7 +8,7 @@ export interface TooltipProps extends React.HTMLAttributes<HTMLDivElement> {
8
8
  association?: 'aria-labelledby' | 'aria-describedby' | 'none';
9
9
  show?: boolean | undefined;
10
10
  defaultShow?: boolean;
11
- placement?: Placement;
11
+ placement?: React.ComponentProps<typeof AnchoredOverlay>['placement'];
12
12
  portal?: React.RefObject<HTMLElement> | HTMLElement;
13
13
  hideElementOnHidden?: boolean;
14
14
  }
package/lib/index.d.ts CHANGED
@@ -61,6 +61,7 @@ export { default as TextEllipsis } from './components/TextEllipsis';
61
61
  export { default as CopyButton } from './components/CopyButton';
62
62
  export { default as Drawer } from './components/Drawer';
63
63
  export { default as BottomSheet } from './components/BottomSheet';
64
+ export { default as AnchoredOverlay } from './components/AnchoredOverlay';
64
65
  /**
65
66
  * Helpers / Utils
66
67
  */
package/lib/index.js CHANGED
@@ -9,7 +9,8 @@ var nextId = require('react-id-generator');
9
9
  var keyname = require('keyname');
10
10
  var reactDom = require('react-dom');
11
11
  var FocusTrap = require('focus-trap-react');
12
- var reactPopper = require('react-popper');
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');
@@ -1584,40 +1585,25 @@ var Button = React.forwardRef(function (_a, ref) {
1584
1585
  Button.displayName = 'Button';
1585
1586
 
1586
1587
  /**
1587
- * Returns a unique set of id refs from the provided string
1588
- * @param ids - string of id refs
1589
- */
1590
- function idRefs(ids) {
1591
- if (!ids || !ids.trim()) {
1592
- return new Set();
1593
- }
1594
- return new Set(ids.trim().split(/\s+/));
1595
- }
1596
- /**
1597
- * Returns an updated id ref string with the provided id value added
1598
- * @param ids - string of id refs
1599
- * @param id - id to add
1600
- */
1601
- function addIdRef(ids, id) {
1602
- return tslib.__spreadArray([], tslib.__read(idRefs(ids).add(id)), false).join(' ');
1603
- }
1604
- /**
1605
- * Returns an updated id ref string with the provided id value removed
1606
- * @param ids - string of id refs
1607
- * @param id - id to remove
1608
- */
1609
- function removeIdRef(_ids, id) {
1610
- var ids = idRefs(_ids);
1611
- ids.delete(id);
1612
- return tslib.__spreadArray([], tslib.__read(ids), false).join(' ');
1613
- }
1614
- /**
1615
- * Returns if an id ref string contains the provided id value
1616
- * @param ids - string of id refs
1617
- * @param id - id to check if it exists in the provided idRef string
1588
+ * When a component needs to track an internal ref on a component that has a
1589
+ * forwarded ref, useSharedRef will return a MutableRefObject<T> that will
1590
+ * correctly invoke the parent ref as well providing an internal ref.
1591
+ *
1592
+ * @example
1593
+ * React.forwardRef(function Component({ children }, ref) {
1594
+ * const internalRef = useSharedRef<HTMLElement>(ref)
1595
+ * if (internalRef.current) {
1596
+ * // do something with the internal ref...
1597
+ * }
1598
+ * return (<div ref={internalRef}>...</div>)
1599
+ * })
1618
1600
  */
1619
- function hasIdRef(ids, id) {
1620
- return idRefs(ids).has(id);
1601
+ function useSharedRef(ref) {
1602
+ var internalRef = React.useRef();
1603
+ React.useEffect(function () {
1604
+ setRef(ref, internalRef.current);
1605
+ }, [ref]);
1606
+ return internalRef;
1621
1607
  }
1622
1608
 
1623
1609
  var isEscapeKey = function (event) {
@@ -1660,6 +1646,99 @@ function useEscapeKey(options, dependencies) {
1660
1646
  ], tslib.__read(dependencies), false));
1661
1647
  }
1662
1648
 
1649
+ function getAutoAlignment(placement) {
1650
+ switch (placement) {
1651
+ case 'auto-start':
1652
+ return 'start';
1653
+ case 'auto-end':
1654
+ return 'end';
1655
+ default:
1656
+ return null;
1657
+ }
1658
+ }
1659
+ var AnchoredOverlay = React.forwardRef(function (_a, refProp) {
1660
+ 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"]);
1661
+ var ref = useSharedRef(refProp);
1662
+ var Component = as || 'div';
1663
+ var _d = reactDom$1.useFloating({
1664
+ open: open,
1665
+ // default to initial placement on top when placement is auto
1666
+ // @ts-expect-error auto placement is not a valid placement for floating-ui
1667
+ placement: initialPlacement.startsWith('auto') ? 'top' : initialPlacement,
1668
+ middleware: [
1669
+ reactDom$1.offset(offset !== null && offset !== void 0 ? offset : 0),
1670
+ initialPlacement.startsWith('auto')
1671
+ ? reactDom$1.autoPlacement({
1672
+ alignment: getAutoAlignment(initialPlacement)
1673
+ })
1674
+ : reactDom$1.flip()
1675
+ ].filter(Boolean),
1676
+ elements: {
1677
+ reference: resolveElement(target),
1678
+ floating: ref.current
1679
+ },
1680
+ whileElementsMounted: dom.autoUpdate
1681
+ }), floatingStyles = _d.floatingStyles, placement = _d.placement;
1682
+ useEscapeKey({
1683
+ active: open,
1684
+ capture: true,
1685
+ defaultPrevented: true,
1686
+ callback: function (event) {
1687
+ // when an anchored overlay is open, we want to prevent other potential "escape"
1688
+ // keypress events, like the closing of modals from occurring
1689
+ event.preventDefault();
1690
+ // istanbul ignore else
1691
+ if (typeof onOpenChange === 'function') {
1692
+ onOpenChange(!open);
1693
+ }
1694
+ }
1695
+ });
1696
+ React.useEffect(function () {
1697
+ if (typeof onPlacementChange === 'function') {
1698
+ onPlacementChange(placement);
1699
+ }
1700
+ }, [placement]);
1701
+ return (React__default["default"].createElement(Component, tslib.__assign({ ref: ref }, props, { style: tslib.__assign(tslib.__assign({}, floatingStyles), style) }), children));
1702
+ });
1703
+ AnchoredOverlay.displayName = 'AnchoredOverlay';
1704
+
1705
+ /**
1706
+ * Returns a unique set of id refs from the provided string
1707
+ * @param ids - string of id refs
1708
+ */
1709
+ function idRefs(ids) {
1710
+ if (!ids || !ids.trim()) {
1711
+ return new Set();
1712
+ }
1713
+ return new Set(ids.trim().split(/\s+/));
1714
+ }
1715
+ /**
1716
+ * Returns an updated id ref string with the provided id value added
1717
+ * @param ids - string of id refs
1718
+ * @param id - id to add
1719
+ */
1720
+ function addIdRef(ids, id) {
1721
+ return tslib.__spreadArray([], tslib.__read(idRefs(ids).add(id)), false).join(' ');
1722
+ }
1723
+ /**
1724
+ * Returns an updated id ref string with the provided id value removed
1725
+ * @param ids - string of id refs
1726
+ * @param id - id to remove
1727
+ */
1728
+ function removeIdRef(_ids, id) {
1729
+ var ids = idRefs(_ids);
1730
+ ids.delete(id);
1731
+ return tslib.__spreadArray([], tslib.__read(ids), false).join(' ');
1732
+ }
1733
+ /**
1734
+ * Returns if an id ref string contains the provided id value
1735
+ * @param ids - string of id refs
1736
+ * @param id - id to check if it exists in the provided idRef string
1737
+ */
1738
+ function hasIdRef(ids, id) {
1739
+ return idRefs(ids).has(id);
1740
+ }
1741
+
1663
1742
  var TIP_HIDE_DELAY = 100;
1664
1743
  // fires a custom "cauldron:tooltip:show" / "cauldron:tooltip:hide" event
1665
1744
  // to allow projects using cauldron to hook into when a tooltip is shown/hidden
@@ -1678,50 +1757,27 @@ function Tooltip(_a) {
1678
1757
  var _g = tslib.__read(propId ? [propId] : nextId.useId(1, 'tooltip'), 1), id = _g[0];
1679
1758
  var hideTimeoutRef = React.useRef(null);
1680
1759
  var _h = tslib.__read(React.useState(!!showProp || defaultShow), 2), showTooltip = _h[0], setShowTooltip = _h[1];
1681
- var _j = tslib.__read(React.useState(null), 2), targetElement = _j[0], setTargetElement = _j[1];
1682
- var _k = tslib.__read(React.useState(null), 2), tooltipElement = _k[0], setTooltipElement = _k[1];
1683
- var _l = tslib.__read(React.useState(null), 2), arrowElement = _l[0], setArrowElement = _l[1];
1760
+ var _j = tslib.__read(React.useState(null), 2), tooltipElement = _j[0], setTooltipElement = _j[1];
1761
+ var _k = tslib.__read(React.useState(initialPlacement), 2), placement = _k[0], setPlacement = _k[1];
1684
1762
  var hasAriaAssociation = association !== 'none';
1685
- var _m = reactPopper.usePopper(targetElement, tooltipElement, {
1686
- placement: initialPlacement,
1687
- modifiers: [
1688
- { name: 'preventOverflow', options: { padding: 8 } },
1689
- {
1690
- name: 'flip',
1691
- options: { fallbackPlacements: ['left', 'right', 'top', 'bottom'] }
1692
- },
1693
- { name: 'offset', options: { offset: [0, 8] } },
1694
- { name: 'arrow', options: { padding: 5, element: arrowElement } }
1695
- ]
1696
- }), styles = _m.styles, attributes = _m.attributes, update = _m.update;
1697
1763
  // Show the tooltip
1698
1764
  var show = React.useCallback(function () { return tslib.__awaiter(_this, void 0, void 0, function () {
1765
+ var targetElement;
1699
1766
  return tslib.__generator(this, function (_a) {
1700
- switch (_a.label) {
1701
- case 0:
1702
- // Clear the hide timeout if there was one pending
1703
- if (hideTimeoutRef.current) {
1704
- clearTimeout(hideTimeoutRef.current);
1705
- hideTimeoutRef.current = null;
1706
- }
1707
- if (!update) return [3 /*break*/, 2];
1708
- return [4 /*yield*/, update()];
1709
- case 1:
1710
- _a.sent();
1711
- _a.label = 2;
1712
- case 2:
1713
- setShowTooltip(true);
1714
- fireCustomEvent(true, targetElement);
1715
- return [2 /*return*/];
1767
+ targetElement = resolveElement(target);
1768
+ // Clear the hide timeout if there was one pending
1769
+ if (hideTimeoutRef.current) {
1770
+ clearTimeout(hideTimeoutRef.current);
1771
+ hideTimeoutRef.current = null;
1716
1772
  }
1773
+ setShowTooltip(true);
1774
+ fireCustomEvent(true, targetElement);
1775
+ return [2 /*return*/];
1717
1776
  });
1718
- }); }, [
1719
- targetElement,
1720
- // update starts off as null
1721
- update
1722
- ]);
1777
+ }); }, [target]);
1723
1778
  // Hide the tooltip
1724
1779
  var hide = React.useCallback(function () {
1780
+ var targetElement = resolveElement(target);
1725
1781
  if (!hideTimeoutRef.current) {
1726
1782
  hideTimeoutRef.current = setTimeout(function () {
1727
1783
  hideTimeoutRef.current = null;
@@ -1732,32 +1788,15 @@ function Tooltip(_a) {
1732
1788
  return function () {
1733
1789
  clearTimeout(hideTimeoutRef.current);
1734
1790
  };
1735
- }, [targetElement]);
1736
- // Keep targetElement in sync with target prop
1737
- React.useEffect(function () {
1738
- var targetElement = target && 'current' in target ? target.current : target;
1739
- setTargetElement(targetElement);
1740
1791
  }, [target]);
1741
1792
  React.useEffect(function () {
1742
1793
  if (typeof showProp === 'boolean') {
1743
1794
  setShowTooltip(showProp);
1744
1795
  }
1745
1796
  }, [showProp]);
1746
- // Get popper placement
1747
- var placement = (attributes.popper &&
1748
- attributes.popper['data-popper-placement']) ||
1749
- initialPlacement;
1750
- // Only listen to key ups when the tooltip is visible
1751
- useEscapeKey({
1752
- callback: function (event) {
1753
- event.preventDefault();
1754
- setShowTooltip(false);
1755
- },
1756
- capture: true,
1757
- active: showTooltip && typeof showProp !== 'boolean'
1758
- }, [setShowTooltip]);
1759
1797
  // Handle hover and focus events for the targetElement
1760
1798
  React.useEffect(function () {
1799
+ var targetElement = resolveElement(target);
1761
1800
  if (typeof showProp !== 'boolean') {
1762
1801
  targetElement === null || targetElement === void 0 ? void 0 : targetElement.addEventListener('mouseenter', show);
1763
1802
  targetElement === null || targetElement === void 0 ? void 0 : targetElement.addEventListener('mouseleave', hide);
@@ -1770,7 +1809,7 @@ function Tooltip(_a) {
1770
1809
  targetElement === null || targetElement === void 0 ? void 0 : targetElement.removeEventListener('focusin', show);
1771
1810
  targetElement === null || targetElement === void 0 ? void 0 : targetElement.removeEventListener('focusout', hide);
1772
1811
  };
1773
- }, [targetElement, show, hide, showProp]);
1812
+ }, [target, show, hide, showProp]);
1774
1813
  // Handle hover events for the tooltipElement
1775
1814
  React.useEffect(function () {
1776
1815
  if (typeof showProp !== 'boolean') {
@@ -1784,6 +1823,7 @@ function Tooltip(_a) {
1784
1823
  }, [tooltipElement, show, hide, showProp]);
1785
1824
  // Keep the target's id in sync
1786
1825
  React.useEffect(function () {
1826
+ var targetElement = resolveElement(target);
1787
1827
  if (hasAriaAssociation) {
1788
1828
  var idRefs = targetElement === null || targetElement === void 0 ? void 0 : targetElement.getAttribute(association);
1789
1829
  if (!hasIdRef(idRefs, id)) {
@@ -1796,14 +1836,14 @@ function Tooltip(_a) {
1796
1836
  targetElement.setAttribute(association, removeIdRef(idRefs, id));
1797
1837
  }
1798
1838
  };
1799
- }, [targetElement, id, association]);
1839
+ }, [target, id, association]);
1800
1840
  return (React__default["default"].createElement(React__default["default"].Fragment, null, (showTooltip || hideElementOnHidden) && isBrowser()
1801
- ? reactDom.createPortal(React__default["default"].createElement("div", tslib.__assign({ id: id, className: classNames__default["default"]('Tooltip', "Tooltip--".concat(placement), className, {
1841
+ ? 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, {
1802
1842
  TooltipInfo: variant === 'info',
1803
1843
  'Tooltip--hidden': !showTooltip && hideElementOnHidden,
1804
1844
  'Tooltip--big': variant === 'big'
1805
- }), ref: setTooltipElement, role: "tooltip", style: styles.popper }, attributes.popper, props),
1806
- variant !== 'big' && (React__default["default"].createElement("div", { className: "TooltipArrow", ref: setArrowElement, style: styles.arrow })),
1845
+ }), ref: setTooltipElement, role: "tooltip", offset: 8 }, props),
1846
+ variant !== 'big' && React__default["default"].createElement("div", { className: "TooltipArrow" }),
1807
1847
  children), (portal && 'current' in portal ? portal.current : portal) ||
1808
1848
  (
1809
1849
  // eslint-disable-next-line ssr-friendly/no-dom-globals-in-react-fc
@@ -2519,28 +2559,6 @@ var SearchField = React.forwardRef(function (_a, ref) {
2519
2559
  });
2520
2560
  SearchField.displayName = 'SearchField';
2521
2561
 
2522
- /**
2523
- * When a component needs to track an internal ref on a component that has a
2524
- * forwarded ref, useSharedRef will return a MutableRefObject<T> that will
2525
- * correctly invoke the parent ref as well providing an internal ref.
2526
- *
2527
- * @example
2528
- * React.forwardRef(function Component({ children }, ref) {
2529
- * const internalRef = useSharedRef<HTMLElement>(ref)
2530
- * if (internalRef.current) {
2531
- * // do something with the internal ref...
2532
- * }
2533
- * return (<div ref={internalRef}>...</div>)
2534
- * })
2535
- */
2536
- function useSharedRef(ref) {
2537
- var internalRef = React.useRef();
2538
- React.useEffect(function () {
2539
- setRef(ref, internalRef.current);
2540
- }, [ref]);
2541
- return internalRef;
2542
- }
2543
-
2544
2562
  function copyTextToClipboard(text) {
2545
2563
  return tslib.__awaiter(this, void 0, void 0, function () {
2546
2564
  var copied, element, range, selection;
@@ -2797,6 +2815,16 @@ function useTable() {
2797
2815
  return React.useContext(TableContext);
2798
2816
  }
2799
2817
 
2818
+ function parseColumnWidth(width) {
2819
+ var number = Number(width);
2820
+ if (!isNaN(number)) {
2821
+ return "".concat(number, "px");
2822
+ }
2823
+ if (!width) {
2824
+ return 'auto';
2825
+ }
2826
+ return width;
2827
+ }
2800
2828
  var Table = React__default["default"].forwardRef(function (_a, ref) {
2801
2829
  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"]);
2802
2830
  var isGridLayout = layout === 'grid';
@@ -2817,8 +2845,11 @@ var Table = React__default["default"].forwardRef(function (_a, ref) {
2817
2845
  }
2818
2846
  return columns
2819
2847
  .map(function (_a) {
2820
- var width = _a.width;
2821
- return width || 'auto';
2848
+ var width = _a.width, maxWidth = _a.maxWidth;
2849
+ if (maxWidth) {
2850
+ return "minmax(".concat(parseColumnWidth(width), ", ").concat(parseColumnWidth(maxWidth), ")");
2851
+ }
2852
+ return parseColumnWidth(width);
2822
2853
  })
2823
2854
  .join(' ');
2824
2855
  }, [layout, columns]);
@@ -3444,19 +3475,21 @@ var ListboxContext = React.createContext({
3444
3475
  options: [],
3445
3476
  active: null,
3446
3477
  selected: null,
3478
+ multiselect: false,
3447
3479
  setOptions: function () { return null; },
3448
3480
  onSelect: function () { return null; }
3449
3481
  });
3450
3482
  function ListboxProvider(_a) {
3451
- var options = _a.options, active = _a.active, selected = _a.selected, setOptions = _a.setOptions, onSelect = _a.onSelect, children = _a.children;
3483
+ var options = _a.options, active = _a.active, selected = _a.selected, multiselect = _a.multiselect, setOptions = _a.setOptions, onSelect = _a.onSelect, children = _a.children;
3452
3484
  var Provider = ListboxContext.Provider;
3453
3485
  var value = React.useMemo(function () { return ({
3454
3486
  options: options,
3455
3487
  active: active,
3456
3488
  selected: selected,
3489
+ multiselect: multiselect,
3457
3490
  setOptions: setOptions,
3458
3491
  onSelect: onSelect
3459
- }); }, [options, active, selected, setOptions]);
3492
+ }); }, [options, active, selected, multiselect, setOptions]);
3460
3493
  return React__default["default"].createElement(Provider, { value: value }, children);
3461
3494
  }
3462
3495
  function useListboxContext() {
@@ -3478,40 +3511,78 @@ var optionMatchesValue = function (option, value) {
3478
3511
  option.value === value;
3479
3512
  };
3480
3513
  var Listbox = React.forwardRef(function (_a, ref) {
3481
- 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"]);
3482
- var _d = tslib.__read(React.useState([]), 2), options = _d[0], setOptions = _d[1];
3483
- var _e = tslib.__read(React.useState(null), 2), activeOption = _e[0], setActiveOption = _e[1];
3484
- var _f = tslib.__read(React.useState(null), 2), selectedOption = _f[0], setSelectedOption = _f[1];
3514
+ 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"]);
3515
+ var _e = tslib.__read(React.useState([]), 2), options = _e[0], setOptions = _e[1];
3516
+ var _f = tslib.__read(React.useState(null), 2), activeOption = _f[0], setActiveOption = _f[1];
3517
+ var _g = tslib.__read(React.useState([]), 2), selectedOptions = _g[0], setSelectedOptions = _g[1];
3485
3518
  var listboxRef = useSharedRef(ref);
3486
3519
  var isControlled = typeof value !== 'undefined';
3487
3520
  React.useLayoutEffect(function () {
3488
- if (!isControlled && selectedOption) {
3521
+ if (!isControlled && selectedOptions.length > 0) {
3489
3522
  return;
3490
3523
  }
3491
3524
  var listboxValue = isControlled ? value : defaultValue;
3492
- var matchingOption = options.find(function (option) {
3493
- return optionMatchesValue(option, listboxValue);
3494
- });
3495
- setSelectedOption(matchingOption || null);
3496
- setActiveOption(matchingOption || null);
3497
- }, [isControlled, options, value]);
3525
+ if (!listboxValue) {
3526
+ return;
3527
+ }
3528
+ if (multiselect) {
3529
+ var matchingOptions = options.filter(function (option) {
3530
+ return listboxValue.find(function (value) {
3531
+ return optionMatchesValue(option, value);
3532
+ });
3533
+ });
3534
+ setSelectedOptions(matchingOptions);
3535
+ setActiveOption(matchingOptions[0] || null);
3536
+ }
3537
+ else {
3538
+ var matchingOption = options.find(function (option) {
3539
+ return optionMatchesValue(option, listboxValue);
3540
+ });
3541
+ setSelectedOptions(matchingOption ? [matchingOption] : []);
3542
+ setActiveOption(matchingOption || null);
3543
+ }
3544
+ }, [isControlled, options, value, defaultValue]);
3498
3545
  React.useEffect(function () {
3499
3546
  if (activeOption) {
3500
3547
  onActiveChange === null || onActiveChange === void 0 ? void 0 : onActiveChange(activeOption);
3501
3548
  }
3502
3549
  }, [activeOption]);
3503
3550
  var handleSelect = React.useCallback(function (option) {
3551
+ var _a;
3504
3552
  setActiveOption(option);
3553
+ var optionIsSelected = selectedOptions.some(function (selected) { return selected.element === option.element; });
3554
+ var previousValues = selectedOptions.map(function (selected) { return selected.value; });
3505
3555
  // istanbul ignore else
3506
3556
  if (!isControlled) {
3507
- setSelectedOption(option);
3557
+ if (!multiselect) {
3558
+ setSelectedOptions([option]);
3559
+ }
3560
+ else {
3561
+ setSelectedOptions(optionIsSelected
3562
+ ? tslib.__spreadArray([], tslib.__read(selectedOptions.filter(function (selected) { return selected.element !== option.element; })), false) : tslib.__spreadArray(tslib.__spreadArray([], tslib.__read(selectedOptions), false), [option], false));
3563
+ }
3508
3564
  }
3509
- onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange({
3510
- target: option.element,
3511
- value: option.value,
3512
- previousValue: selectedOption === null || selectedOption === void 0 ? void 0 : selectedOption.value
3513
- });
3514
- }, [isControlled, selectedOption]);
3565
+ if (multiselect) {
3566
+ onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange({
3567
+ target: option.element,
3568
+ value: optionIsSelected
3569
+ ? selectedOptions
3570
+ .filter(function (selectedOption) {
3571
+ return selectedOption.element !== option.element;
3572
+ })
3573
+ .map(function (selectedOption) { return selectedOption.value; })
3574
+ : tslib.__spreadArray(tslib.__spreadArray([], tslib.__read(previousValues), false), [option.value], false),
3575
+ previousValue: previousValues
3576
+ });
3577
+ }
3578
+ else {
3579
+ onSelectionChange === null || onSelectionChange === void 0 ? void 0 : onSelectionChange({
3580
+ target: option.element,
3581
+ value: option.value,
3582
+ previousValue: (_a = selectedOptions[0]) === null || _a === void 0 ? void 0 : _a.value
3583
+ });
3584
+ }
3585
+ }, [isControlled, selectedOptions, multiselect, onSelectionChange]);
3515
3586
  var handleKeyDown = React.useCallback(function (event) {
3516
3587
  onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
3517
3588
  if (!keys.includes(event.key)) {
@@ -3561,9 +3632,9 @@ var Listbox = React.forwardRef(function (_a, ref) {
3561
3632
  activeOption && handleSelect(activeOption);
3562
3633
  break;
3563
3634
  }
3564
- }, [options, activeOption, navigation]);
3635
+ }, [options, activeOption, navigation, handleSelect]);
3565
3636
  var handleFocus = React.useCallback(function (event) {
3566
- if (!activeOption && !selectedOption) {
3637
+ if (!activeOption) {
3567
3638
  var firstOption = options.find(function (option) { return !isDisabledOption(option); });
3568
3639
  // istanbul ignore else
3569
3640
  if (firstOption) {
@@ -3571,13 +3642,14 @@ var Listbox = React.forwardRef(function (_a, ref) {
3571
3642
  }
3572
3643
  // istanbul ignore else
3573
3644
  }
3574
- else if (event.target === listboxRef.current) {
3575
- setActiveOption(selectedOption);
3645
+ else if (selectedOptions.length &&
3646
+ event.target === listboxRef.current) {
3647
+ setActiveOption(selectedOptions[selectedOptions.length - 1]);
3576
3648
  }
3577
3649
  onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
3578
- }, [options, activeOption, selectedOption]);
3579
- 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),
3580
- React__default["default"].createElement(ListboxProvider, { options: options, active: activeOption, selected: selectedOption, setOptions: setOptions, onSelect: handleSelect }, children)));
3650
+ }, [options, activeOption, selectedOptions]);
3651
+ 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),
3652
+ React__default["default"].createElement(ListboxProvider, { options: options, active: activeOption, multiselect: multiselect, selected: selectedOptions, setOptions: setOptions, onSelect: handleSelect }, children)));
3581
3653
  });
3582
3654
  Listbox.displayName = 'Listbox';
3583
3655
 
@@ -3587,12 +3659,15 @@ function isElementPreceding(a, b) {
3587
3659
  var ListboxOption = React.forwardRef(function (_a, ref) {
3588
3660
  var _b;
3589
3661
  var _c;
3590
- 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"]);
3662
+ 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"]);
3591
3663
  var _f = useListboxContext(), active = _f.active, selected = _f.selected, setOptions = _f.setOptions, onSelect = _f.onSelect;
3592
3664
  var listboxOptionRef = useSharedRef(ref);
3593
3665
  var _g = tslib.__read(propId ? [propId] : nextId.useId(1, 'listbox-option'), 1), id = _g[0];
3594
- var isActive = active !== null && active.element === listboxOptionRef.current;
3595
- var isSelected = selected !== null && selected.element === listboxOptionRef.current;
3666
+ var isActive = (active === null || active === void 0 ? void 0 : active.element) === listboxOptionRef.current;
3667
+ var isSelected = typeof selectedProp === 'boolean'
3668
+ ? selectedProp
3669
+ : selected !== null &&
3670
+ !!selected.find(function (option) { return option.element === listboxOptionRef.current; });
3596
3671
  var optionValue = typeof value !== 'undefined'
3597
3672
  ? value
3598
3673
  : (_c = listboxOptionRef.current) === null || _c === void 0 ? void 0 : _c.innerText;
@@ -3642,7 +3717,7 @@ var ListboxOption = React.forwardRef(function (_a, ref) {
3642
3717
  }
3643
3718
  onSelect({ element: listboxOptionRef.current, value: optionValue });
3644
3719
  onClick === null || onClick === void 0 ? void 0 : onClick(event);
3645
- }, [optionValue]);
3720
+ }, [optionValue, onSelect, onClick, disabled]);
3646
3721
  return (React__default["default"].createElement(Component, tslib.__assign({ id: id, className: classNames__default["default"](className, (_b = {},
3647
3722
  _b[activeClass] = isActive,
3648
3723
  _b)), role: "option", ref: listboxOptionRef, "aria-disabled": typeof disabled === 'boolean' ? disabled : undefined, "aria-selected": isSelected, onClick: handleClick }, props), children));
@@ -3764,17 +3839,20 @@ var ComboboxMatch = function (_a) {
3764
3839
  React__default["default"].createElement("span", null, matchAfter)));
3765
3840
  };
3766
3841
  var ComboboxOption = React.forwardRef(function (_a, ref) {
3842
+ var _b;
3767
3843
  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"]);
3768
- var _b = tslib.__read(propId ? [propId] : nextId.useId(1, 'combobox-option'), 1), id = _b[0];
3769
- var _c = useListboxContext(), selected = _c.selected, active = _c.active;
3770
- var _d = useComboboxContext(), selectedValue = _d.selectedValue, matches = _d.matches, setMatchingOptions = _d.setMatchingOptions, setFormValue = _d.setFormValue;
3844
+ var _c = tslib.__read(propId ? [propId] : nextId.useId(1, 'combobox-option'), 1), id = _c[0];
3845
+ var _d = useListboxContext(), selected = _d.selected, active = _d.active;
3846
+ var _e = useComboboxContext(), selectedValue = _e.selectedValue, matches = _e.matches, setMatchingOptions = _e.setMatchingOptions, setFormValue = _e.setFormValue;
3771
3847
  var comboboxOptionRef = useSharedRef(ref);
3772
3848
  var intersectionRef = useIntersectionRef(comboboxOptionRef, {
3773
3849
  root: null,
3774
3850
  threshold: 1.0
3775
3851
  });
3776
3852
  var isActive = !!(active === null || active === void 0 ? void 0 : active.element) && active.element === comboboxOptionRef.current;
3777
- var isSelected = !!(selected === null || selected === void 0 ? void 0 : selected.element) && selected.element === comboboxOptionRef.current;
3853
+ var isSelected = !!(selected &&
3854
+ !!((_b = selected[0]) === null || _b === void 0 ? void 0 : _b.element) &&
3855
+ selected[0].element === comboboxOptionRef.current);
3778
3856
  var isMatching = (typeof matches === 'boolean' && matches) ||
3779
3857
  (typeof matches === 'function' && matches(children));
3780
3858
  // istanbul ignore next
@@ -4110,19 +4188,7 @@ var Popover = React.forwardRef(function (_a, ref) {
4110
4188
  var _f = tslib.__read(React.useState(null), 2), targetElement = _f[0], setTargetElement = _f[1];
4111
4189
  var _g = tslib.__read(React.useState(null), 2), isolator = _g[0], setIsolator = _g[1];
4112
4190
  var popoverRef = useSharedRef(ref);
4113
- var _h = tslib.__read(React.useState(null), 2), arrowElement = _h[0], setArrowElement = _h[1];
4114
- var _j = reactPopper.usePopper(targetElement, popoverRef === null || popoverRef === void 0 ? void 0 : popoverRef.current, {
4115
- placement: initialPlacement,
4116
- modifiers: [
4117
- { name: 'preventOverflow', options: { padding: 8 } },
4118
- { name: 'flip' },
4119
- { name: 'offset', options: { offset: [0, 8] } },
4120
- { name: 'arrow', options: { padding: 5, element: arrowElement } }
4121
- ]
4122
- }), styles = _j.styles, attributes = _j.attributes;
4123
- var placement = (attributes.popper &&
4124
- attributes.popper['data-popper-placement']) ||
4125
- initialPlacement;
4191
+ var _h = tslib.__read(React.useState(initialPlacement), 2), placement = _h[0], setPlacement = _h[1];
4126
4192
  var additionalProps = variant === 'prompt' && !props['aria-label']
4127
4193
  ? { 'aria-labelledby': "".concat(id, "-label") }
4128
4194
  : {};
@@ -4203,11 +4269,11 @@ var Popover = React.forwardRef(function (_a, ref) {
4203
4269
  fallbackFocus: '.Popover__borderLeft'
4204
4270
  } },
4205
4271
  React__default["default"].createElement(ClickOutsideListener$1, { onClickOutside: handleClickOutside },
4206
- React__default["default"].createElement("div", tslib.__assign({ id: id, className: classNames__default["default"]('Popover', "Popover--".concat(placement), className, {
4272
+ React__default["default"].createElement(AnchoredOverlay, tslib.__assign({ id: id, className: classNames__default["default"]('Popover', "Popover--".concat(placement), className, {
4207
4273
  'Popover--hidden': !show,
4208
4274
  'Popover--prompt': variant === 'prompt'
4209
- }), ref: popoverRef, role: "dialog", style: styles.popper }, attributes.popper, additionalProps, props),
4210
- React__default["default"].createElement("div", { className: "Popover__popoverArrow", ref: setArrowElement, style: styles.arrow }),
4275
+ }), ref: popoverRef, role: "dialog", target: target, open: show, placement: initialPlacement, onPlacementChange: setPlacement, offset: 8 }, additionalProps, props),
4276
+ React__default["default"].createElement("div", { className: "Popover__popoverArrow" }),
4211
4277
  React__default["default"].createElement("div", { className: "Popover__borderLeft" }),
4212
4278
  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) ||
4213
4279
  // Dependent on "isBrowser" check above:
@@ -4476,6 +4542,7 @@ exports.AddressLine = AddressLine;
4476
4542
  exports.Alert = Alert;
4477
4543
  exports.AlertActions = AlertActions;
4478
4544
  exports.AlertContent = AlertContent;
4545
+ exports.AnchoredOverlay = AnchoredOverlay;
4479
4546
  exports.AriaIsolate = AriaIsolate;
4480
4547
  exports.Badge = Badge;
4481
4548
  exports.BadgeLabel = BadgeLabel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deque/cauldron-react",
3
- "version": "6.12.0-canary.b5982813",
3
+ "version": "6.12.0-canary.dc7e4ac4",
4
4
  "license": "MPL-2.0",
5
5
  "description": "Fully accessible react components library for Deque Cauldron",
6
6
  "homepage": "https://cauldron.dequelabs.com/",
@@ -23,13 +23,12 @@
23
23
  "test": "jest --maxWorkers=1 --coverage"
24
24
  },
25
25
  "dependencies": {
26
- "@popperjs/core": "^2.5.4",
26
+ "@floating-ui/react-dom": "^2.1.2",
27
27
  "classnames": "^2.2.6",
28
28
  "focus-trap-react": "^10.2.3",
29
29
  "focusable": "^2.3.0",
30
30
  "keyname": "^0.1.0",
31
31
  "react-id-generator": "^3.0.1",
32
- "react-popper": "^2.2.4",
33
32
  "react-syntax-highlighter": "^15.5.0",
34
33
  "tslib": "^2.4.0"
35
34
  },