@coinbase/cds-web 8.62.0 → 8.66.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/dts/alpha/combobox/DefaultComboboxControl.d.ts.map +1 -1
  3. package/dts/alpha/select/DefaultSelectControl.d.ts.map +1 -1
  4. package/dts/alpha/select/DefaultSelectDropdown.d.ts.map +1 -1
  5. package/dts/alpha/select/Select.d.ts.map +1 -1
  6. package/dts/core/componentConfig.d.ts +2 -2
  7. package/dts/core/componentConfig.d.ts.map +1 -1
  8. package/dts/dropdown/Dropdown.d.ts +4 -0
  9. package/dts/dropdown/Dropdown.d.ts.map +1 -1
  10. package/dts/dropdown/DropdownContent.d.ts +12 -5
  11. package/dts/dropdown/DropdownContent.d.ts.map +1 -1
  12. package/dts/dropdown/DropdownProps.d.ts +20 -0
  13. package/dts/dropdown/DropdownProps.d.ts.map +1 -1
  14. package/dts/dropdown/useResponsiveHeight.d.ts +4 -0
  15. package/dts/dropdown/useResponsiveHeight.d.ts.map +1 -1
  16. package/dts/overlays/Toast.d.ts.map +1 -1
  17. package/dts/overlays/index.d.ts +1 -0
  18. package/dts/overlays/index.d.ts.map +1 -1
  19. package/dts/overlays/modal/ModalHeader.d.ts +3 -3
  20. package/dts/overlays/modal/ModalHeader.d.ts.map +1 -1
  21. package/dts/overlays/modal/ModalWrapper.d.ts.map +1 -1
  22. package/dts/overlays/popover/Popover.d.ts +48 -31
  23. package/dts/overlays/popover/Popover.d.ts.map +1 -1
  24. package/dts/overlays/popover/PopoverPanel.d.ts +164 -0
  25. package/dts/overlays/popover/PopoverPanel.d.ts.map +1 -0
  26. package/dts/overlays/popover/PopoverPanelContent.d.ts +43 -0
  27. package/dts/overlays/popover/PopoverPanelContent.d.ts.map +1 -0
  28. package/dts/overlays/popover/PopoverProps.d.ts +13 -4
  29. package/dts/overlays/popover/PopoverProps.d.ts.map +1 -1
  30. package/dts/overlays/tooltip/TooltipContent.d.ts.map +1 -1
  31. package/dts/stepper/Stepper.d.ts.map +1 -1
  32. package/dts/tabs/DefaultTab.d.ts +42 -0
  33. package/dts/tabs/DefaultTab.d.ts.map +1 -0
  34. package/dts/tabs/DefaultTabsActiveIndicator.d.ts +16 -0
  35. package/dts/tabs/DefaultTabsActiveIndicator.d.ts.map +1 -0
  36. package/dts/tabs/TabIndicator.d.ts +2 -0
  37. package/dts/tabs/TabIndicator.d.ts.map +1 -1
  38. package/dts/tabs/TabLabel.d.ts +2 -0
  39. package/dts/tabs/TabLabel.d.ts.map +1 -1
  40. package/dts/tabs/TabNavigation.d.ts +16 -0
  41. package/dts/tabs/TabNavigation.d.ts.map +1 -1
  42. package/dts/tabs/Tabs.d.ts +25 -11
  43. package/dts/tabs/Tabs.d.ts.map +1 -1
  44. package/dts/tabs/index.d.ts +2 -0
  45. package/dts/tabs/index.d.ts.map +1 -1
  46. package/dts/tour/DefaultTourMask.d.ts +1 -2
  47. package/dts/tour/DefaultTourMask.d.ts.map +1 -1
  48. package/dts/tour/DefaultTourStepArrow.d.ts +1 -1
  49. package/dts/tour/DefaultTourStepArrow.d.ts.map +1 -1
  50. package/dts/tour/Tour.d.ts +35 -7
  51. package/dts/tour/Tour.d.ts.map +1 -1
  52. package/dts/tour/TourStep.d.ts +4 -1
  53. package/dts/tour/TourStep.d.ts.map +1 -1
  54. package/esm/alpha/combobox/DefaultComboboxControl.js +1 -2
  55. package/esm/alpha/select/DefaultSelectControl.js +4 -2
  56. package/esm/alpha/select/DefaultSelectDropdown.js +1 -0
  57. package/esm/alpha/select/Select.js +30 -1
  58. package/esm/dropdown/Dropdown.js +5 -0
  59. package/esm/dropdown/DropdownContent.js +12 -1
  60. package/esm/dropdown/useResponsiveHeight.js +5 -0
  61. package/esm/overlays/FocusTrap.js +1 -1
  62. package/esm/overlays/Toast.js +20 -12
  63. package/esm/overlays/index.js +1 -0
  64. package/esm/overlays/modal/ModalHeader.js +6 -4
  65. package/esm/overlays/modal/ModalWrapper.js +7 -1
  66. package/esm/overlays/popover/Popover.js +71 -28
  67. package/esm/overlays/popover/PopoverPanel.css +2 -0
  68. package/esm/overlays/popover/PopoverPanel.js +220 -0
  69. package/esm/overlays/popover/PopoverPanelContent.js +57 -0
  70. package/esm/overlays/tooltip/TooltipContent.js +3 -5
  71. package/esm/stepper/Stepper.js +4 -3
  72. package/esm/tabs/DefaultTab.css +3 -0
  73. package/esm/tabs/DefaultTab.js +77 -0
  74. package/esm/tabs/DefaultTabsActiveIndicator.js +58 -0
  75. package/esm/tabs/TabIndicator.js +2 -0
  76. package/esm/tabs/TabLabel.js +3 -0
  77. package/esm/tabs/TabNavigation.js +21 -0
  78. package/esm/tabs/Tabs.js +32 -34
  79. package/esm/tabs/index.js +2 -0
  80. package/esm/tour/DefaultTourMask.js +1 -1
  81. package/esm/tour/DefaultTourStepArrow.js +3 -1
  82. package/esm/tour/Tour.js +38 -7
  83. package/esm/tour/TourStep.js +16 -6
  84. package/package.json +4 -4
@@ -3,7 +3,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
3
3
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
4
4
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
5
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
- import { forwardRef, memo, useImperativeHandle, useMemo, useRef, useState } from 'react';
6
+ import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
7
7
  import { autoUpdate, flip, useFloating } from '@floating-ui/react-dom';
8
8
  import { cx } from '../../cx';
9
9
  import { useClickOutside } from '../../hooks/useClickOutside';
@@ -93,6 +93,34 @@ const SelectBase = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_props, ref) => {
93
93
  ref: refs.floating,
94
94
  excludeRefs: [refs.reference]
95
95
  });
96
+ const pendingTypeAheadKeyRef = useRef(null);
97
+ const handleControlKeyDown = useCallback(event => {
98
+ if (disabled || open) return;
99
+ if (event.ctrlKey || event.metaKey || event.altKey) return;
100
+ const key = event.key;
101
+ if (/^[a-z]$/.test(key)) {
102
+ pendingTypeAheadKeyRef.current = key;
103
+ setOpen(true);
104
+ }
105
+ }, [disabled, open, setOpen]);
106
+ useEffect(() => {
107
+ var _accessibilityRoles$o;
108
+ if (!open || !pendingTypeAheadKeyRef.current) return;
109
+ const key = pendingTypeAheadKeyRef.current;
110
+ pendingTypeAheadKeyRef.current = null;
111
+ const floatingEl = refs.floating.current;
112
+ if (!floatingEl) return;
113
+ const optionRole = (_accessibilityRoles$o = accessibilityRoles === null || accessibilityRoles === void 0 ? void 0 : accessibilityRoles.option) !== null && _accessibilityRoles$o !== void 0 ? _accessibilityRoles$o : 'option';
114
+ const options = floatingEl.querySelectorAll("[role=\"".concat(optionRole, "\"]"));
115
+ const matchingOption = Array.from(options).find(option => {
116
+ var _option$textContent, _firstLetterMatch$;
117
+ const firstLetterMatch = (_option$textContent = option.textContent) === null || _option$textContent === void 0 ? void 0 : _option$textContent.match(/[a-z]/i);
118
+ return (firstLetterMatch === null || firstLetterMatch === void 0 || (_firstLetterMatch$ = firstLetterMatch[0]) === null || _firstLetterMatch$ === void 0 ? void 0 : _firstLetterMatch$.toLowerCase()) === key;
119
+ });
120
+ if (matchingOption) {
121
+ matchingOption.focus();
122
+ }
123
+ }, [open, refs.floating, accessibilityRoles === null || accessibilityRoles === void 0 ? void 0 : accessibilityRoles.option]);
96
124
  const rootStyles = useMemo(() => _objectSpread(_objectSpread({}, style), styles === null || styles === void 0 ? void 0 : styles.root), [style, styles === null || styles === void 0 ? void 0 : styles.root]);
97
125
  const controlStyles = useMemo(() => ({
98
126
  controlStartNode: styles === null || styles === void 0 ? void 0 : styles.controlStartNode,
@@ -165,6 +193,7 @@ const SelectBase = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_props, ref) => {
165
193
  labelVariant: labelVariant,
166
194
  maxSelectedOptionsToShow: maxSelectedOptionsToShow,
167
195
  onChange: onChange,
196
+ onKeyDown: handleControlKeyDown,
168
197
  open: open,
169
198
  options: options,
170
199
  placeholder: placeholder,
@@ -170,6 +170,11 @@ const PopoverDropdown = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) =
170
170
  }))
171
171
  });
172
172
  }));
173
+
174
+ /**
175
+ * @deprecated Use PopoverPanel for interactive overlays with arbitrary content, or Select / SelectChip when presenting a list of selectable options. This will be removed in a future major release.
176
+ * @deprecationExpectedRemoval v10
177
+ */
173
178
  export const Dropdown = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_props, ref) => {
174
179
  const mergedProps = useComponentConfig('Dropdown', _props);
175
180
  const {
@@ -6,7 +6,7 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
6
6
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
7
  function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
8
8
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
9
- import React, { forwardRef, memo } from 'react';
9
+ import { forwardRef, memo } from 'react';
10
10
  import { animateDropdownOpacityInConfig, animateDropdownOpacityOutConfig, animateDropdownTransformInConfig, animateDropdownTransformOutConfig } from '@coinbase/cds-common/animation/dropdown';
11
11
  import { zIndex } from '@coinbase/cds-common/tokens/zIndex';
12
12
  import { m as motion } from 'framer-motion';
@@ -14,7 +14,18 @@ import { VStack } from '../layout/VStack';
14
14
  import { useMotionProps } from '../motion/useMotionProps';
15
15
  import { jsx as _jsx } from "react/jsx-runtime";
16
16
  const dropdownStaticClassName = 'cds-dropdown';
17
+
18
+ /**
19
+ * @deprecated Use PopoverPanelContent within a PopoverPanel for interactive overlay content, or Select / SelectChip when presenting a list of selectable options. This will be removed in a future major release.
20
+ * @deprecationExpectedRemoval v10
21
+ */
22
+
17
23
  const MotionVStack = motion(VStack);
24
+
25
+ /**
26
+ * @deprecated Use PopoverPanelContent within a PopoverPanel for interactive overlay content, or Select / SelectChip when presenting a list of selectable options. This will be removed in a future major release.
27
+ * @deprecationExpectedRemoval v10
28
+ */
18
29
  export const DropdownContent = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
19
30
  let {
20
31
  children,
@@ -3,6 +3,11 @@ import { useIsoEffect } from '../hooks/useIsoEffect';
3
3
  import { useTheme } from '../hooks/useTheme';
4
4
  import { getBrowserGlobals, isSSR } from '../utils/browser';
5
5
  const BOTTOM_GUTTER_SPACE = 2;
6
+
7
+ /**
8
+ * @deprecated Import `useResponsivePanelMaxHeight` from `@coinbase/cds-web/popover` instead. This will be removed in a future major release.
9
+ * @deprecationExpectedRemoval v10
10
+ */
6
11
  export function useResponsiveHeight(_ref) {
7
12
  var _getBrowserGlobals;
8
13
  let {
@@ -141,7 +141,7 @@ export const FocusTrap = /*#__PURE__*/memo(_props => {
141
141
  event.preventDefault();
142
142
  const elementWithMatchingFirstLetter = focusableElements.find(el => {
143
143
  var _el$textContent;
144
- const textContentFirstLetter = (_el$textContent = el.textContent) === null || _el$textContent === void 0 || (_el$textContent = _el$textContent.at(0)) === null || _el$textContent === void 0 ? void 0 : _el$textContent.toLowerCase();
144
+ const textContentFirstLetter = (_el$textContent = el.textContent) === null || _el$textContent === void 0 || (_el$textContent = _el$textContent[0]) === null || _el$textContent === void 0 ? void 0 : _el$textContent.toLowerCase();
145
145
  const eventKeyLowerCase = event.key.toLowerCase();
146
146
  return textContentFirstLetter === eventKeyLowerCase;
147
147
  });
@@ -6,10 +6,10 @@ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol"
6
6
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
7
7
  function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
8
8
  function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
9
- import React, { forwardRef, memo, useCallback, useContext, useEffect, useImperativeHandle } from 'react';
9
+ import React, { forwardRef, memo, useCallback, useContext, useImperativeHandle, useRef, useState } from 'react';
10
10
  import { animateInBottomConfig, animateInOpacityConfig, animateOutBottomConfig, animateOutOpacityConfig } from '@coinbase/cds-common/animation/toast';
11
11
  import { ToastContext } from '@coinbase/cds-common/overlays/ToastProvider';
12
- import { m as motion, useAnimation } from 'framer-motion';
12
+ import { m as motion } from 'framer-motion';
13
13
  import { Button } from '../buttons/Button';
14
14
  import { IconButton } from '../buttons/IconButton';
15
15
  import { useComponentConfig } from '../hooks/useComponentConfig';
@@ -48,24 +48,31 @@ export const Toast = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_props, ref) =>
48
48
  pauseTimer,
49
49
  resumeTimer
50
50
  } = useContext(ToastContext);
51
- const animationControls = useAnimation();
51
+ const [motionState, setMotionState] = useState('enter');
52
+ const exitResolverRef = useRef(null);
52
53
  const motionProps = useMotionProps({
53
54
  enterConfigs: [animateInOpacityConfig, animateInBottomConfig],
54
55
  exitConfigs: [animateOutOpacityConfig, animateOutBottomConfig],
55
- animate: animationControls,
56
+ animate: motionState,
56
57
  style: {
57
58
  bottom: bottomOffset
58
59
  }
59
60
  });
60
- useEffect(() => {
61
- void animationControls.start('enter');
62
- }, [animationControls]);
63
- const handleClose = useCallback(async () => {
61
+ const handleAnimationComplete = useCallback(definition => {
62
+ if (definition === 'exit') {
63
+ var _exitResolverRef$curr;
64
+ onDidHide === null || onDidHide === void 0 || onDidHide();
65
+ (_exitResolverRef$curr = exitResolverRef.current) === null || _exitResolverRef$curr === void 0 || _exitResolverRef$curr.call(exitResolverRef, true);
66
+ exitResolverRef.current = null;
67
+ }
68
+ }, [onDidHide]);
69
+ const handleClose = useCallback(() => {
64
70
  onWillHide === null || onWillHide === void 0 || onWillHide();
65
- await animationControls.start('exit');
66
- onDidHide === null || onDidHide === void 0 || onDidHide();
67
- return true;
68
- }, [onWillHide, onDidHide, animationControls]);
71
+ return new Promise(resolve => {
72
+ exitResolverRef.current = resolve;
73
+ setMotionState('exit');
74
+ });
75
+ }, [onWillHide]);
69
76
  useImperativeHandle(ref, () => ({
70
77
  hide: handleClose
71
78
  }), [handleClose]);
@@ -79,6 +86,7 @@ export const Toast = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_props, ref) =>
79
86
  children: /*#__PURE__*/_jsx(motion.div, _objectSpread(_objectSpread({}, motionProps), {}, {
80
87
  className: baseCss,
81
88
  "data-testid": "".concat(testID, "-motion"),
89
+ onAnimationComplete: handleAnimationComplete,
82
90
  children: /*#__PURE__*/_jsx(Box, _objectSpread(_objectSpread({
83
91
  justifyContent: "center",
84
92
  onMouseEnter: pauseTimer // persist toast when hovering
@@ -10,6 +10,7 @@ export * from './modal/ModalFooter';
10
10
  export * from './modal/ModalHeader';
11
11
  export * from './overlay/Overlay';
12
12
  export * from './popover/Popover';
13
+ export * from './popover/PopoverPanel';
13
14
  export * from './popover/PopoverProps';
14
15
  export * from './popover/usePopper';
15
16
  export * from './PortalProvider';
@@ -1,4 +1,4 @@
1
- const _excluded = ["alignItems", "paddingX", "paddingY", "title", "onBackButtonClick", "backAccessibilityLabel", "backAccessibilityHint", "closeAccessibilityLabel", "closeAccessibilityHint"];
1
+ const _excluded = ["alignItems", "paddingX", "paddingY", "font", "title", "onBackButtonClick", "backAccessibilityLabel", "backAccessibilityHint", "closeAccessibilityLabel", "closeAccessibilityHint"];
2
2
  function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
3
3
  function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
4
4
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
@@ -21,6 +21,7 @@ export const ModalHeader = _props => {
21
21
  alignItems = 'center',
22
22
  paddingX = 3,
23
23
  paddingY = 2,
24
+ font = 'headline',
24
25
  title,
25
26
  onBackButtonClick,
26
27
  backAccessibilityLabel,
@@ -45,6 +46,7 @@ export const ModalHeader = _props => {
45
46
  return /*#__PURE__*/_jsxs(HStack, _objectSpread(_objectSpread({
46
47
  alignItems: alignItems,
47
48
  borderedBottom: !hideDividers,
49
+ font: font,
48
50
  paddingX: paddingX,
49
51
  paddingY: paddingY
50
52
  }, props), {}, {
@@ -62,14 +64,14 @@ export const ModalHeader = _props => {
62
64
  flexGrow: 1,
63
65
  justifyContent: "center",
64
66
  paddingX: 2,
65
- children: title && /*#__PURE__*/_jsx(Text, {
67
+ children: title && (typeof title === 'string' ? /*#__PURE__*/_jsx(Text, {
66
68
  as: "h2",
67
69
  display: "block",
68
- font: "headline",
70
+ font: "inherit",
69
71
  id: accessibilityLabelledBy,
70
72
  textAlign: "center",
71
73
  children: title
72
- })
74
+ }) : title)
73
75
  }), !hideCloseButton && /*#__PURE__*/_jsx(Box, {
74
76
  justifyContent: "flex-end",
75
77
  children: /*#__PURE__*/_jsx(IconButton, {
@@ -11,6 +11,7 @@ import { NewAnimatePresence } from '../../animation/NewAnimatePresence';
11
11
  import { cx } from '../../cx';
12
12
  import { useComponentConfig } from '../../hooks/useComponentConfig';
13
13
  import { useScrollBlocker } from '../../hooks/useScrollBlocker';
14
+ import { VStack } from '../../layout';
14
15
  import { Box } from '../../layout/Box';
15
16
  import { media } from '../../styles/media';
16
17
  import { Overlay } from '../overlay/Overlay';
@@ -65,11 +66,16 @@ export const ModalWrapper = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_props, r
65
66
  width: width
66
67
  }, props), {}, {
67
68
  children: /*#__PURE__*/_jsxs(_Fragment, {
68
- children: [!hideOverlay && /*#__PURE__*/_jsx(Overlay, {
69
+ children: [!hideOverlay ? /*#__PURE__*/_jsx(Overlay, {
69
70
  animated: true,
70
71
  className: cx(!dangerouslyDisableResponsiveness && modalOverlayResponsiveCss),
71
72
  onClick: !disableOverlayPress ? onOverlayPress : undefined,
72
73
  testID: "modal-overlay"
74
+ }) : /*#__PURE__*/_jsx(VStack, {
75
+ background: "transparent",
76
+ onClick: !disableOverlayPress ? onOverlayPress : undefined,
77
+ pin: "all",
78
+ position: "fixed"
73
79
  }), children]
74
80
  })
75
81
  }))
@@ -4,17 +4,19 @@ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object
4
4
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
5
5
  function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
6
6
  /* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/click-events-have-key-events */
7
- import React, { memo, useCallback, useMemo } from 'react';
7
+ import React, { forwardRef, memo, useCallback, useMemo } from 'react';
8
+ import { useMergeRefs } from '@coinbase/cds-common/hooks/useMergeRefs';
8
9
  import { zIndex } from '@coinbase/cds-common/tokens/zIndex';
10
+ import { autoPlacement, autoUpdate, flip, limitShift, offset, shift, useFloating } from '@floating-ui/react-dom';
9
11
  import { NewAnimatePresence } from '../../animation/NewAnimatePresence';
10
12
  import { cx } from '../../cx';
13
+ import { useTheme } from '../../hooks/useTheme';
11
14
  import { Box } from '../../layout/Box';
12
15
  import { InvertedThemeProvider } from '../../system/ThemeProvider';
13
16
  import { FocusTrap } from '../FocusTrap';
14
17
  import { Overlay } from '../overlay/Overlay';
15
18
  import { Portal } from '../Portal';
16
19
  import { tooltipContainerId } from '../PortalProvider';
17
- import { usePopper } from './usePopper';
18
20
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
19
21
  const subjectCss = "subjectCss-s1cgr9z4";
20
22
  const defaultContentPosition = {
@@ -27,10 +29,15 @@ const defaultContentPosition = {
27
29
  const blockCss = "blockCss-b13rnbro";
28
30
 
29
31
  /**
30
- * Popover is the internal recommended base component used for any overlay that is laid out with respect to a subject.
31
- * It is purposely a flexible component and is reserved for CDS internal usage.
32
+ * Low-level primitive that positions an arbitrary `content` node relative to a subject (trigger) element.
33
+ * It handles placement, portal rendering, and open/close wiring, but intentionally renders `content` as-is —
34
+ * it does not provide a styled surface, animation, or focus management.
35
+ *
36
+ * For a fully composed overlay with an animated elevated panel and focus trap, use {@link PopoverPanel} instead.
37
+ *
38
+ * @internal Reserved for CDS internal use only.
32
39
  */
33
- export const Popover = /*#__PURE__*/memo(_ref => {
40
+ export const Popover = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
34
41
  let {
35
42
  content,
36
43
  children,
@@ -57,14 +64,51 @@ export const Popover = /*#__PURE__*/memo(_ref => {
57
64
  respectNegativeTabIndex,
58
65
  autoFocusDelay,
59
66
  restoreFocusOnUnmount,
60
- controlledElementAccessibilityProps
67
+ controlledElementAccessibilityProps,
68
+ style,
69
+ className
61
70
  } = _ref;
71
+ const theme = useTheme();
62
72
  const {
63
- setSubject,
64
- setPopper,
65
- popperStyles,
66
- popperAttributes
67
- } = usePopper(contentPosition);
73
+ placement: rawPlacement = 'bottom',
74
+ skid = 0,
75
+ gap = 0,
76
+ offsetGap,
77
+ strategy
78
+ } = contentPosition;
79
+ const computedSkid = theme.space[skid];
80
+ const computedGap = theme.space[gap];
81
+ const getOffsetGap = offsetGap && gap - offsetGap;
82
+ const isAutoPlacement = typeof rawPlacement === 'string' && rawPlacement.startsWith('auto');
83
+ const middleware = useMemo(() => {
84
+ const middlewareList = [offset({
85
+ crossAxis: computedSkid,
86
+ mainAxis: getOffsetGap !== null && getOffsetGap !== void 0 ? getOffsetGap : computedGap
87
+ })];
88
+ if (isAutoPlacement) {
89
+ const alignment = rawPlacement === 'auto-start' ? 'start' : rawPlacement === 'auto-end' ? 'end' : undefined;
90
+ middlewareList.push(autoPlacement(alignment ? {
91
+ alignment
92
+ } : undefined));
93
+ } else {
94
+ middlewareList.push(flip());
95
+ middlewareList.push(shift({
96
+ crossAxis: true,
97
+ limiter: limitShift()
98
+ }));
99
+ }
100
+ return middlewareList;
101
+ }, [computedSkid, getOffsetGap, computedGap, isAutoPlacement, rawPlacement]);
102
+ const {
103
+ refs,
104
+ floatingStyles
105
+ } = useFloating({
106
+ placement: isAutoPlacement ? undefined : rawPlacement,
107
+ strategy,
108
+ middleware,
109
+ whileElementsMounted: autoUpdate
110
+ });
111
+ const mergedRef = useMergeRefs(ref, refs.setReference);
68
112
 
69
113
  // We use this to infer that hover events are triggering the mounting/dismounting of the content
70
114
  const hasHoverInteractions = !!onMouseEnter && !!onMouseLeave && !onPressSubject;
@@ -78,13 +122,13 @@ export const Popover = /*#__PURE__*/memo(_ref => {
78
122
  const handleCaptureEvents = useCallback(event => {
79
123
  event.stopPropagation();
80
124
  }, []);
81
- const memoizedContent = useMemo(() => /*#__PURE__*/_jsx("div", _objectSpread(_objectSpread({
82
- ref: setPopper,
83
- style: _objectSpread(_objectSpread({}, popperStyles.popper), {}, {
84
- zIndex: zIndex.dropdown
85
- })
86
- }, popperAttributes.popper), {}, {
125
+ const memoizedContent = useMemo(() => /*#__PURE__*/_jsx("div", {
126
+ ref: refs.setFloating,
87
127
  onClick: handleCaptureEvents,
128
+ onMouseDown: handleCaptureEvents,
129
+ style: _objectSpread(_objectSpread({}, floatingStyles), {}, {
130
+ zIndex: zIndex.dropdown
131
+ }),
88
132
  children: /*#__PURE__*/_jsx(FocusTrap, {
89
133
  autoFocusDelay: autoFocusDelay,
90
134
  disableAutoFocus: disableAutoFocus,
@@ -101,7 +145,7 @@ export const Popover = /*#__PURE__*/memo(_ref => {
101
145
  children: content
102
146
  }))
103
147
  })
104
- })), [setPopper, popperStyles.popper, popperAttributes.popper, handleCaptureEvents, autoFocusDelay, disableAutoFocus, disableFocusTrap, disableTypeFocus, focusTabIndexElements, handleClose, respectNegativeTabIndex, restoreFocusOnUnmount, testID, controlledElementAccessibilityProps, content]);
148
+ }), [refs.setFloating, floatingStyles, handleCaptureEvents, autoFocusDelay, disableAutoFocus, disableFocusTrap, disableTypeFocus, focusTabIndexElements, handleClose, respectNegativeTabIndex, restoreFocusOnUnmount, testID, controlledElementAccessibilityProps, content]);
105
149
  const renderContent = hasHoverInteractions ? memoizedContent : /*#__PURE__*/_jsx(Box, {
106
150
  "aria-label": accessibilityLabel,
107
151
  "aria-modal": "true",
@@ -114,18 +158,16 @@ export const Popover = /*#__PURE__*/memo(_ref => {
114
158
  });
115
159
  const Wrapper = invertColorScheme ? InvertedThemeProvider : React.Fragment;
116
160
  return /*#__PURE__*/_jsxs("div", {
117
- className: block ? blockCss : undefined,
161
+ ref: mergedRef,
162
+ className: cx(subjectCss, block && blockCss, className),
118
163
  onBlur: onBlur,
164
+ onClick: disabled ? undefined : onPressSubject,
165
+ onFocus: disabled ? undefined : onFocus,
166
+ onMouseDown: disabled ? undefined : onMouseDown,
119
167
  onMouseEnter: disabled ? undefined : onMouseEnter,
120
168
  onMouseLeave: disabled ? undefined : onMouseLeave,
121
- children: [/*#__PURE__*/_jsx("div", {
122
- ref: setSubject,
123
- className: cx(subjectCss, block && blockCss),
124
- onClick: disabled ? undefined : onPressSubject,
125
- onFocus: disabled ? undefined : onFocus,
126
- onMouseDown: disabled ? undefined : onMouseDown,
127
- children: children
128
- }), /*#__PURE__*/_jsx(NewAnimatePresence, {
169
+ style: style,
170
+ children: [children, /*#__PURE__*/_jsx(NewAnimatePresence, {
129
171
  children: shouldShowContent ? /*#__PURE__*/_jsx(Portal, {
130
172
  containerId: tooltipContainerId,
131
173
  disablePortal: disablePortal,
@@ -143,5 +185,6 @@ export const Popover = /*#__PURE__*/memo(_ref => {
143
185
  }) : undefined
144
186
  })]
145
187
  });
146
- });
188
+ }));
189
+ Popover.displayName = 'Popover';
147
190
  import "./Popover.css";
@@ -0,0 +1,2 @@
1
+ @layer cds{.triggerContainerCss-tkun82{width:-webkit-fit-content;width:-moz-fit-content;width:fit-content;}
2
+ .blockCss-bqzogy1{width:100%;}}
@@ -0,0 +1,220 @@
1
+ const _excluded = ["content", "showOverlay", "children", "visible", "onClose", "onOpen", "panelWidth", "minPanelWidth", "maxPanelWidth", "maxPanelHeight", "panelHeight", "testID", "disablePortal", "onBlur", "contentPosition", "block", "disabled", "restoreFocusOnUnmount", "style", "styles", "className", "classNames"],
2
+ _excluded2 = ["children", "content", "maxPanelHeight", "enableMobileModal", "onOpen", "onClose", "restoreFocusOnUnmount"];
3
+ function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
4
+ function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
5
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
6
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
7
+ function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
8
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
9
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
10
+ import React, { forwardRef, memo, useCallback, useImperativeHandle, useMemo, useState } from 'react';
11
+ import useMeasure from 'react-use-measure';
12
+ import { cx } from '../../cx';
13
+ import { useBreakpoints } from '../../hooks/useBreakpoints';
14
+ import { useComponentConfig } from '../../hooks/useComponentConfig';
15
+ import { FocusTrap } from '../FocusTrap';
16
+ import { ModalWrapper } from '../modal/ModalWrapper';
17
+ import { Popover } from './Popover';
18
+ import { PopoverPanelContent } from './PopoverPanelContent';
19
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
20
+ const POPOVER_PANEL_MAX_HEIGHT = 300;
21
+ export const popoverPanelClassNames = {
22
+ /** Elevated panel surface (`PopoverPanelContent`). */
23
+ content: 'cds-PopoverPanel-content',
24
+ /** Wrapper around `children` (the `Popover` root in floating layout, or the trigger `div` in the mobile modal). */
25
+ triggerContainer: 'cds-PopoverPanel-triggerContainer'
26
+ };
27
+ const NOOP = () => {};
28
+ const defaultPopoverContentPositionConfig = {
29
+ gap: 0.5,
30
+ placement: 'bottom-start'
31
+ };
32
+ function usePopoverPanelImperativeHandle(ref, onOpen, onClose) {
33
+ useImperativeHandle(ref, () => ({
34
+ openPopover: onOpen,
35
+ closePopover: onClose
36
+ }), [onOpen, onClose]);
37
+ }
38
+ const triggerContainerCss = "triggerContainerCss-tkun82";
39
+ const blockCss = "blockCss-bqzogy1";
40
+ const MobilePopoverPanel = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref, ref) => {
41
+ let {
42
+ children,
43
+ onOpen = NOOP,
44
+ onClose = NOOP,
45
+ block,
46
+ content,
47
+ disablePortal,
48
+ visible,
49
+ panelWidth,
50
+ showOverlay,
51
+ minPanelWidth,
52
+ maxPanelWidth,
53
+ maxPanelHeight,
54
+ disabled,
55
+ controlledElementAccessibilityProps,
56
+ respectNegativeTabIndex,
57
+ restoreFocusOnUnmount,
58
+ style,
59
+ styles,
60
+ className,
61
+ classNames,
62
+ onBlur,
63
+ testID,
64
+ disableAutoFocus,
65
+ focusTabIndexElements,
66
+ autoFocusDelay
67
+ } = _ref;
68
+ usePopoverPanelImperativeHandle(ref, onOpen, onClose);
69
+ const handleCaptureEvents = useCallback(event => {
70
+ event.stopPropagation();
71
+ }, []);
72
+ return (
73
+ /*#__PURE__*/
74
+ // eslint-disable-next-line jsx-a11y/click-events-have-key-events
75
+ _jsxs("div", {
76
+ className: cx(block ? blockCss : triggerContainerCss, popoverPanelClassNames.triggerContainer, className, classNames === null || classNames === void 0 ? void 0 : classNames.triggerContainer),
77
+ onBlur: onBlur,
78
+ onClick: disabled ? undefined : onOpen,
79
+ style: _objectSpread(_objectSpread({}, style), styles === null || styles === void 0 ? void 0 : styles.triggerContainer),
80
+ children: [children, /*#__PURE__*/_jsx(ModalWrapper, _objectSpread(_objectSpread({
81
+ dangerouslyDisableResponsiveness: true,
82
+ disablePortal: disablePortal,
83
+ hideOverlay: !showOverlay,
84
+ onClick: handleCaptureEvents,
85
+ onOverlayPress: onClose,
86
+ testID: testID,
87
+ visible: visible
88
+ }, controlledElementAccessibilityProps), {}, {
89
+ children: /*#__PURE__*/_jsx(FocusTrap, {
90
+ autoFocusDelay: autoFocusDelay,
91
+ disableAutoFocus: disableAutoFocus,
92
+ focusTabIndexElements: focusTabIndexElements,
93
+ onEscPress: onClose,
94
+ respectNegativeTabIndex: respectNegativeTabIndex,
95
+ restoreFocusOnUnmount: restoreFocusOnUnmount,
96
+ children: /*#__PURE__*/_jsx(PopoverPanelContent, {
97
+ className: classNames === null || classNames === void 0 ? void 0 : classNames.content,
98
+ maxHeight: maxPanelHeight,
99
+ maxWidth: maxPanelWidth,
100
+ minWidth: minPanelWidth,
101
+ style: styles === null || styles === void 0 ? void 0 : styles.content,
102
+ width: panelWidth,
103
+ children: content
104
+ })
105
+ })
106
+ }))]
107
+ })
108
+ );
109
+ }));
110
+ const FloatingPopoverPanel = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) => {
111
+ let {
112
+ content,
113
+ showOverlay,
114
+ children,
115
+ visible,
116
+ onClose = NOOP,
117
+ onOpen = NOOP,
118
+ panelWidth: width,
119
+ minPanelWidth: minWidth,
120
+ maxPanelWidth: maxWidth,
121
+ maxPanelHeight: maxHeight = POPOVER_PANEL_MAX_HEIGHT,
122
+ panelHeight: height,
123
+ testID,
124
+ disablePortal,
125
+ onBlur,
126
+ contentPosition = defaultPopoverContentPositionConfig,
127
+ block,
128
+ disabled,
129
+ restoreFocusOnUnmount,
130
+ style,
131
+ styles,
132
+ className,
133
+ classNames
134
+ } = _ref2,
135
+ props = _objectWithoutProperties(_ref2, _excluded);
136
+ const [triggerRef, triggerBounds] = useMeasure();
137
+ const combinedContentPosition = useMemo(() => _objectSpread(_objectSpread({}, defaultPopoverContentPositionConfig), contentPosition), [contentPosition]);
138
+ const memoizedContent = useMemo(() => /*#__PURE__*/_jsx(PopoverPanelContent, {
139
+ className: classNames === null || classNames === void 0 ? void 0 : classNames.content,
140
+ height: height,
141
+ maxHeight: maxHeight,
142
+ maxWidth: maxWidth,
143
+ minWidth: minWidth,
144
+ placement: combinedContentPosition.placement,
145
+ style: styles === null || styles === void 0 ? void 0 : styles.content,
146
+ width: width !== null && width !== void 0 ? width : triggerBounds.width,
147
+ children: content
148
+ }), [classNames === null || classNames === void 0 ? void 0 : classNames.content, height, maxHeight, maxWidth, minWidth, combinedContentPosition.placement, styles === null || styles === void 0 ? void 0 : styles.content, width, triggerBounds.width, content]);
149
+ usePopoverPanelImperativeHandle(ref, onOpen, onClose);
150
+ return /*#__PURE__*/_jsx(Popover, _objectSpread(_objectSpread({
151
+ ref: triggerRef,
152
+ block: block,
153
+ className: cx(!block && triggerContainerCss, popoverPanelClassNames.triggerContainer, className, classNames === null || classNames === void 0 ? void 0 : classNames.triggerContainer),
154
+ content: disabled ? undefined : memoizedContent,
155
+ contentPosition: combinedContentPosition,
156
+ disablePortal: disablePortal,
157
+ disabled: disabled,
158
+ onBlur: onBlur,
159
+ onClose: onClose,
160
+ onPressSubject: !visible ? onOpen : undefined,
161
+ restoreFocusOnUnmount: restoreFocusOnUnmount,
162
+ showOverlay: showOverlay,
163
+ style: _objectSpread(_objectSpread({}, style), styles === null || styles === void 0 ? void 0 : styles.triggerContainer),
164
+ testID: testID,
165
+ visible: disabled ? false : visible
166
+ }, props), {}, {
167
+ children: children
168
+ }));
169
+ }));
170
+
171
+ /**
172
+ * Anchored floating panel built on {@link Popover} and {@link PopoverPanelContent} without select context. Use for custom panel content.
173
+ * Imperative `openPopover` / `closePopover` are implemented in the floating and modal subcomponents (Dropdown continues to use `openMenu` / `closeMenu` on its ref).
174
+ */
175
+ export const PopoverPanel = /*#__PURE__*/forwardRef((_props, ref) => {
176
+ const mergedProps = useComponentConfig('PopoverPanel', _props);
177
+ const {
178
+ children,
179
+ content,
180
+ maxPanelHeight = POPOVER_PANEL_MAX_HEIGHT,
181
+ enableMobileModal,
182
+ onOpen,
183
+ onClose,
184
+ restoreFocusOnUnmount = true
185
+ } = mergedProps,
186
+ props = _objectWithoutProperties(mergedProps, _excluded2);
187
+ const {
188
+ isPhone
189
+ } = useBreakpoints();
190
+ const [visible, setVisible] = useState(false);
191
+ const handleOpenPopover = useCallback(() => {
192
+ setVisible(true);
193
+ onOpen === null || onOpen === void 0 || onOpen();
194
+ }, [onOpen]);
195
+ const handleClosePopover = useCallback(() => {
196
+ setVisible(false);
197
+ onClose === null || onClose === void 0 || onClose();
198
+ }, [onClose]);
199
+ const resolvedContent = useMemo(() => typeof content === 'function' ? content({
200
+ closePopover: handleClosePopover
201
+ }) : content, [content, handleClosePopover]);
202
+ const sharedProps = _objectSpread({
203
+ maxPanelHeight,
204
+ onClose: handleClosePopover,
205
+ onOpen: handleOpenPopover,
206
+ restoreFocusOnUnmount,
207
+ visible,
208
+ content: resolvedContent
209
+ }, props);
210
+ return isPhone && enableMobileModal ? /*#__PURE__*/_jsx(MobilePopoverPanel, _objectSpread(_objectSpread({
211
+ ref: ref
212
+ }, sharedProps), {}, {
213
+ children: children
214
+ })) : /*#__PURE__*/_jsx(FloatingPopoverPanel, _objectSpread(_objectSpread({
215
+ ref: ref
216
+ }, sharedProps), {}, {
217
+ children: children
218
+ }));
219
+ });
220
+ import "./PopoverPanel.css";