@coinbase/cds-web 8.43.2 → 8.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dts/alpha/__figma__/Select.figma.d.ts +2 -0
  3. package/dts/alpha/__figma__/Select.figma.d.ts.map +1 -0
  4. package/dts/alpha/data-card/DataCard.d.ts +2 -0
  5. package/dts/alpha/data-card/DataCard.d.ts.map +1 -1
  6. package/dts/alpha/data-card/DataCardLayout.d.ts +8 -0
  7. package/dts/alpha/data-card/DataCardLayout.d.ts.map +1 -1
  8. package/dts/alpha/select/types.d.ts +118 -116
  9. package/dts/alpha/select/types.d.ts.map +1 -1
  10. package/dts/alpha/tabbed-chips/TabbedChips.d.ts +7 -21
  11. package/dts/alpha/tabbed-chips/TabbedChips.d.ts.map +1 -1
  12. package/dts/banner/Banner.d.ts.map +1 -1
  13. package/dts/cards/ContentCard/ContentCardBody.d.ts +8 -24
  14. package/dts/cards/ContentCard/ContentCardBody.d.ts.map +1 -1
  15. package/dts/cards/ContentCard/ContentCardHeader.d.ts +6 -18
  16. package/dts/cards/ContentCard/ContentCardHeader.d.ts.map +1 -1
  17. package/dts/cards/MediaCard/MediaCardLayout.d.ts +10 -0
  18. package/dts/cards/MediaCard/MediaCardLayout.d.ts.map +1 -1
  19. package/dts/cards/MediaCard/index.d.ts +2 -0
  20. package/dts/cards/MediaCard/index.d.ts.map +1 -1
  21. package/dts/cards/MessagingCard/MessagingCardLayout.d.ts +10 -0
  22. package/dts/cards/MessagingCard/MessagingCardLayout.d.ts.map +1 -1
  23. package/dts/cards/MessagingCard/index.d.ts +2 -0
  24. package/dts/cards/MessagingCard/index.d.ts.map +1 -1
  25. package/dts/carousel/Carousel.d.ts +14 -46
  26. package/dts/carousel/Carousel.d.ts.map +1 -1
  27. package/dts/cells/Cell.d.ts +22 -6
  28. package/dts/cells/Cell.d.ts.map +1 -1
  29. package/dts/cells/ContentCell.d.ts +26 -6
  30. package/dts/cells/ContentCell.d.ts.map +1 -1
  31. package/dts/cells/ListCell.d.ts +30 -10
  32. package/dts/cells/ListCell.d.ts.map +1 -1
  33. package/dts/chips/ChipProps.d.ts +6 -2
  34. package/dts/chips/ChipProps.d.ts.map +1 -1
  35. package/dts/controls/CheckboxCell.d.ts +10 -0
  36. package/dts/controls/CheckboxCell.d.ts.map +1 -1
  37. package/dts/controls/RadioCell.d.ts +10 -0
  38. package/dts/controls/RadioCell.d.ts.map +1 -1
  39. package/dts/dots/DotCount.d.ts +8 -30
  40. package/dts/dots/DotCount.d.ts.map +1 -1
  41. package/dts/icons/Icon.d.ts +6 -4
  42. package/dts/icons/Icon.d.ts.map +1 -1
  43. package/dts/navigation/Sidebar.d.ts +10 -30
  44. package/dts/navigation/Sidebar.d.ts.map +1 -1
  45. package/dts/numbers/RollingNumber/RollingNumber.d.ts +38 -138
  46. package/dts/numbers/RollingNumber/RollingNumber.d.ts.map +1 -1
  47. package/dts/overlays/FocusTrap.d.ts +3 -1
  48. package/dts/overlays/FocusTrap.d.ts.map +1 -1
  49. package/dts/overlays/handlebar/HandleBar.d.ts +44 -0
  50. package/dts/overlays/handlebar/HandleBar.d.ts.map +1 -0
  51. package/dts/overlays/handlebar/index.d.ts +2 -0
  52. package/dts/overlays/handlebar/index.d.ts.map +1 -0
  53. package/dts/overlays/tray/Tray.d.ts +113 -20
  54. package/dts/overlays/tray/Tray.d.ts.map +1 -1
  55. package/dts/page/PageHeader.d.ts +11 -31
  56. package/dts/page/PageHeader.d.ts.map +1 -1
  57. package/dts/stepper/Stepper.d.ts +17 -17
  58. package/dts/stepper/Stepper.d.ts.map +1 -1
  59. package/dts/visualizations/ProgressBar.d.ts +12 -48
  60. package/dts/visualizations/ProgressBar.d.ts.map +1 -1
  61. package/dts/visualizations/ProgressBarWithFixedLabels.d.ts +10 -36
  62. package/dts/visualizations/ProgressBarWithFixedLabels.d.ts.map +1 -1
  63. package/dts/visualizations/ProgressBarWithFloatLabel.d.ts +8 -30
  64. package/dts/visualizations/ProgressBarWithFloatLabel.d.ts.map +1 -1
  65. package/dts/visualizations/ProgressCircle.d.ts +20 -72
  66. package/dts/visualizations/ProgressCircle.d.ts.map +1 -1
  67. package/esm/alpha/__figma__/Select.figma.js +68 -0
  68. package/esm/banner/Banner.js +5 -4
  69. package/esm/overlays/FocusTrap.js +3 -1
  70. package/esm/overlays/handlebar/HandleBar.css +3 -0
  71. package/esm/overlays/handlebar/HandleBar.js +66 -0
  72. package/esm/overlays/handlebar/index.js +1 -0
  73. package/esm/overlays/tray/Tray.css +7 -0
  74. package/esm/overlays/tray/Tray.js +300 -112
  75. package/package.json +2 -2
@@ -1,45 +1,96 @@
1
- import React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef, useState } from 'react';
1
+ 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; }
2
+ 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; }
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
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
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 React, { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
7
+ import { DISMISSAL_DRAG_THRESHOLD, DISMISSAL_VELOCITY_THRESHOLD } from '@coinbase/cds-common/animation/drawer';
2
8
  import { OverlayContentContext } from '@coinbase/cds-common/overlays/OverlayContentContext';
3
- import { m, useAnimation } from 'framer-motion';
9
+ import { domMax, LazyMotion, m as motion, useAnimate, useDragControls } from 'framer-motion';
4
10
  import { IconButton } from '../../buttons';
11
+ import { cx } from '../../cx';
12
+ import { useDimensions } from '../../hooks/useDimensions';
5
13
  import { useScrollBlocker } from '../../hooks/useScrollBlocker';
14
+ import { useTheme } from '../../hooks/useTheme';
6
15
  import { Box, HStack } from '../../layout';
7
16
  import { VStack } from '../../layout/VStack';
8
17
  import { Text } from '../../typography/Text';
9
18
  import { FocusTrap } from '../FocusTrap';
19
+ import { HandleBar } from '../handlebar/HandleBar';
10
20
  import { Overlay } from '../overlay/Overlay';
11
21
  import { Portal } from '../Portal';
12
22
  import { trayContainerId } from '../PortalProvider';
13
23
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
- // Animation constants
15
- const ANIMATIONS = {
16
- SLIDE_IN: {
17
- y: 0,
24
+ const DISMISSAL_DRAG_PERCENTAGE = 0.4;
25
+ const MotionVStack = motion(Box);
26
+
27
+ /**
28
+ * Conditionally wraps children in LazyMotion with domMax features to support dragging.
29
+ */
30
+ const DragMotionProvider = _ref => {
31
+ let {
32
+ enabled,
33
+ children
34
+ } = _ref;
35
+ if (!enabled) {
36
+ return children;
37
+ }
38
+ return /*#__PURE__*/_jsx(LazyMotion, {
39
+ features: domMax,
40
+ children: children
41
+ });
42
+ };
43
+ const trayHeaderBorderBaseCss = "trayHeaderBorderBaseCss-t552jyb";
44
+ const trayHeaderBorderVisibleCss = "trayHeaderBorderVisibleCss-tx59ve0";
45
+ const trayContainerBaseCss = "trayContainerBaseCss-t1gubbn2";
46
+ const trayContainerPinBottomCss = "trayContainerPinBottomCss-ttp17ir";
47
+ const trayContainerPinTopCss = "trayContainerPinTopCss-t1ql0a7m";
48
+ const trayContainerPinLeftCss = "trayContainerPinLeftCss-tddpnpb";
49
+ const trayContainerPinRightCss = "trayContainerPinRightCss-t17d10kx";
50
+
51
+ /**
52
+ * Static class names for Tray component parts.
53
+ * Use these selectors to target specific elements with CSS.
54
+ */
55
+ export const trayClassNames = {
56
+ /** Root container element */
57
+ root: 'cds-Tray',
58
+ /** Overlay backdrop element */
59
+ overlay: 'cds-Tray-overlay',
60
+ /** Animated sliding container element */
61
+ container: 'cds-Tray-container',
62
+ /** Header section element */
63
+ header: 'cds-Tray-header',
64
+ /** Title text element */
65
+ title: 'cds-Tray-title',
66
+ /** Content area element */
67
+ content: 'cds-Tray-content',
68
+ /** Handle bar container element, only rendered when showHandleBar is true and pin is "bottom" */
69
+ handleBar: 'cds-Tray-handleBar',
70
+ /** Handle bar indicator element, only rendered when showHandleBar is true and pin is "bottom" */
71
+ handleBarHandle: 'cds-Tray-handleBarHandle',
72
+ /** Close button element */
73
+ closeButton: 'cds-Tray-closeButton'
74
+ };
75
+
76
+ // Extended ref type for web implementation
77
+
78
+ const animationConfig = {
79
+ slideIn: {
18
80
  transition: {
19
81
  duration: 0.3
20
82
  }
21
83
  },
22
- SLIDE_OUT: {
23
- y: '100%',
84
+ slideOut: {
24
85
  transition: {
25
86
  duration: 0.3
26
87
  }
27
- },
28
- SNAP_BACK: {
29
- y: 0,
30
- transition: {
31
- type: 'spring',
32
- stiffness: 300,
33
- damping: 30
34
- }
35
88
  }
36
89
  };
37
-
38
- // Extended props for web-specific functionality
39
-
40
- // Extended ref type for web implementation
41
-
42
- export const Tray = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function Tray(_ref, ref) {
90
+ const overlayContentContextValue = {
91
+ isDrawer: true
92
+ };
93
+ export const Tray = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function Tray(_ref2, ref) {
43
94
  let {
44
95
  children,
45
96
  header,
@@ -50,146 +101,282 @@ export const Tray = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function Tray(_ref
50
101
  onBlur,
51
102
  onClose,
52
103
  onCloseComplete,
53
- preventDismiss = false,
104
+ preventDismiss,
54
105
  id,
55
106
  role = 'dialog',
56
107
  accessibilityLabel = 'Tray',
57
- focusTabIndexElements = false,
108
+ accessibilityLabelledBy,
109
+ focusTabIndexElements,
58
110
  restoreFocusOnUnmount = true,
59
111
  closeAccessibilityLabel = 'Close',
60
- closeAccessibilityHint
61
- } = _ref;
112
+ closeAccessibilityHint,
113
+ styles,
114
+ classNames,
115
+ zIndex,
116
+ pin = 'bottom',
117
+ showHandleBar,
118
+ hideCloseButton
119
+ } = _ref2;
120
+ const theme = useTheme();
62
121
  const [isOpen, setIsOpen] = useState(true);
122
+ const [hasScrolledDown, setHasScrolledDown] = useState(false);
63
123
  const trayRef = useRef(null);
64
- const controls = useAnimation();
124
+ const {
125
+ observe: observeTraySize,
126
+ height: trayHeight
127
+ } = useDimensions();
128
+ const contentRef = useRef(null);
129
+ const [scope, animate] = useAnimate();
130
+ const dragControls = useDragControls();
131
+ const isSideTray = pin === 'right' || pin === 'left';
132
+ const horizontalPadding = useMemo(() => pin !== 'bottom' || showHandleBar ? {
133
+ base: 4,
134
+ phone: 3
135
+ } : 6, [showHandleBar, pin]);
65
136
  const blockScroll = useScrollBlocker();
66
-
67
- // prevent body scroll when modal is open
68
137
  useEffect(() => {
69
138
  blockScroll(isOpen);
70
- return () => {
71
- blockScroll(false);
72
- };
139
+ return () => blockScroll(false);
73
140
  }, [isOpen, blockScroll]);
74
-
75
- // Setup initial animation
76
141
  useEffect(() => {
77
- controls.start(ANIMATIONS.SLIDE_IN);
78
- }, [controls]);
79
-
80
- // Unified dismissal function
142
+ onVisibilityChange === null || onVisibilityChange === void 0 || onVisibilityChange('visible');
143
+ return () => onVisibilityChange === null || onVisibilityChange === void 0 ? void 0 : onVisibilityChange('hidden');
144
+ }, [onVisibilityChange]);
81
145
  const handleClose = useCallback(() => {
82
- // Run the animation
83
- controls.start(ANIMATIONS.SLIDE_OUT).then(() => {
84
- // Then set state after animation completes
146
+ if (!scope.current) return;
147
+ animate(scope.current, isSideTray ? {
148
+ x: pin === 'right' ? '100%' : '-100%'
149
+ } : {
150
+ y: pin === 'bottom' ? '100%' : '-100%'
151
+ }, animationConfig.slideOut.transition).then(() => {
85
152
  setIsOpen(false);
86
153
  onClose === null || onClose === void 0 || onClose();
87
154
  onCloseComplete === null || onCloseComplete === void 0 || onCloseComplete();
88
155
  });
89
- }, [onClose, onCloseComplete, controls]);
90
- const handleOverlayPress = useCallback(() => {
156
+ }, [animate, scope, isSideTray, pin, onClose, onCloseComplete]);
157
+ const handleSwipeClose = useCallback(() => {
158
+ if (!scope.current) return;
159
+ animate(scope.current, {
160
+ y: '100%'
161
+ }, {
162
+ duration: 0.15,
163
+ ease: 'easeOut'
164
+ }).then(() => {
165
+ setIsOpen(false);
166
+ onBlur === null || onBlur === void 0 || onBlur();
167
+ onClose === null || onClose === void 0 || onClose();
168
+ onCloseComplete === null || onCloseComplete === void 0 || onCloseComplete();
169
+ });
170
+ }, [animate, scope, onBlur, onClose, onCloseComplete]);
171
+ useImperativeHandle(ref, () => ({
172
+ close: handleClose
173
+ }), [handleClose]);
174
+ const handleOverlayClick = useCallback(() => {
91
175
  if (!preventDismiss) {
92
176
  onBlur === null || onBlur === void 0 || onBlur();
93
177
  handleClose();
94
178
  }
95
179
  }, [handleClose, preventDismiss, onBlur]);
180
+ const handleDragEnd = useCallback((_event, info) => {
181
+ const offsetY = info.offset.y;
182
+ const velocityY = info.velocity.y;
183
+ const dragThreshold = trayHeight ? Math.min(trayHeight * DISMISSAL_DRAG_PERCENTAGE, DISMISSAL_DRAG_THRESHOLD) : DISMISSAL_DRAG_THRESHOLD;
96
184
 
97
- // Use imperative handle for cleaner ref implementation
98
- useImperativeHandle(ref, () => ({
99
- close: handleClose
100
- }), [handleClose]);
185
+ // Close if dragged past threshold OR if flicked down with high velocity
186
+ if (offsetY >= dragThreshold || velocityY >= DISMISSAL_VELOCITY_THRESHOLD) {
187
+ handleSwipeClose();
188
+ } else {
189
+ // Snap back to closed position
190
+ animate(scope.current, {
191
+ y: 0
192
+ }, {
193
+ duration: 0.2,
194
+ ease: 'easeOut'
195
+ });
196
+ }
197
+ }, [trayHeight, handleSwipeClose, animate, scope]);
198
+ const initialAnimationValue = useMemo(() => isSideTray ? {
199
+ x: pin === 'right' ? '100%' : '-100%'
200
+ } : {
201
+ y: pin === 'bottom' ? '100%' : '-100%'
202
+ }, [isSideTray, pin]);
203
+ const animateValue = useMemo(() => isSideTray ? {
204
+ x: 0
205
+ } : {
206
+ y: 0
207
+ }, [isSideTray]);
101
208
 
102
- // Handle visibility changes
209
+ // Handle bar only shows for bottom-pinned trays (matching mobile behavior)
210
+ const shouldShowHandleBar = showHandleBar && pin === 'bottom';
211
+ const shouldShrinkPadding = pin !== 'bottom' || showHandleBar;
212
+ const shouldShowCloseButton = !preventDismiss && !(hideCloseButton !== null && hideCloseButton !== void 0 ? hideCloseButton : shouldShowHandleBar);
213
+ const shouldShowTitle = title || shouldShowCloseButton;
103
214
  useEffect(() => {
104
- onVisibilityChange === null || onVisibilityChange === void 0 || onVisibilityChange('visible');
105
- return () => {
106
- onVisibilityChange === null || onVisibilityChange === void 0 || onVisibilityChange('hidden');
215
+ const content = contentRef.current;
216
+ if (!content || !shouldShrinkPadding) return;
217
+ const handleScroll = () => {
218
+ setHasScrolledDown(content.scrollTop > 0);
107
219
  };
108
- }, [onVisibilityChange]);
109
- const overlayContentContextValue = {
110
- isDrawer: true
111
- };
220
+ content.addEventListener('scroll', handleScroll, {
221
+ passive: true
222
+ });
223
+ return () => content.removeEventListener('scroll', handleScroll);
224
+ }, [shouldShrinkPadding]);
225
+ const headerContent = useMemo(() => typeof header === 'function' ? header({
226
+ handleClose
227
+ }) : header, [header, handleClose]);
228
+ const content = useMemo(() => typeof children === 'function' ? children({
229
+ handleClose
230
+ }) : children, [children, handleClose]);
231
+ const footerContent = useMemo(() => typeof footer === 'function' ? footer({
232
+ handleClose
233
+ }) : footer, [footer, handleClose]);
234
+ const trayContainerPinCss = useMemo(() => {
235
+ switch (pin) {
236
+ case 'top':
237
+ return trayContainerPinTopCss;
238
+ case 'left':
239
+ return trayContainerPinLeftCss;
240
+ case 'right':
241
+ return trayContainerPinRightCss;
242
+ case 'bottom':
243
+ default:
244
+ return trayContainerPinBottomCss;
245
+ }
246
+ }, [pin]);
112
247
  if (!isOpen) return null;
113
248
  return /*#__PURE__*/_jsx(OverlayContentContext.Provider, {
114
249
  value: overlayContentContextValue,
115
250
  children: /*#__PURE__*/_jsx(Portal, {
116
251
  containerId: trayContainerId,
117
252
  children: /*#__PURE__*/_jsxs(Box, {
253
+ ref: trayRef,
254
+ className: cx(trayClassNames.root, classNames === null || classNames === void 0 ? void 0 : classNames.root),
118
255
  height: "100vh",
119
256
  pin: "all",
120
257
  position: "fixed",
258
+ style: styles === null || styles === void 0 ? void 0 : styles.root,
121
259
  width: "100vw",
260
+ zIndex: zIndex,
122
261
  children: [/*#__PURE__*/_jsx(Overlay, {
123
- onClick: handleOverlayPress,
262
+ className: cx(trayClassNames.overlay, classNames === null || classNames === void 0 ? void 0 : classNames.overlay),
263
+ onClick: handleOverlayClick,
264
+ style: styles === null || styles === void 0 ? void 0 : styles.overlay,
124
265
  testID: "tray-overlay"
125
- }), /*#__PURE__*/_jsx(FocusTrap, {
126
- focusTabIndexElements: focusTabIndexElements,
127
- onEscPress: preventDismiss ? undefined : handleClose,
128
- restoreFocusOnUnmount: restoreFocusOnUnmount,
129
- children: /*#__PURE__*/_jsx(m.div, {
130
- animate: controls,
131
- initial: {
132
- y: '100%'
133
- },
134
- style: {
135
- width: '100%',
136
- position: 'absolute',
137
- bottom: 0,
138
- left: 0,
139
- right: 0,
140
- zIndex: 1,
141
- maxHeight: verticalDrawerPercentageOfView,
142
- overflowY: 'auto'
143
- },
144
- tabIndex: 0,
145
- children: /*#__PURE__*/_jsx(VStack, {
146
- ref: trayRef,
266
+ }), /*#__PURE__*/_jsx(DragMotionProvider, {
267
+ enabled: !preventDismiss,
268
+ children: /*#__PURE__*/_jsx(FocusTrap, {
269
+ focusTabIndexElements: focusTabIndexElements,
270
+ onEscPress: preventDismiss ? undefined : handleClose,
271
+ restoreFocusOnUnmount: restoreFocusOnUnmount,
272
+ children: /*#__PURE__*/_jsx(MotionVStack, {
273
+ ref: scope,
147
274
  accessibilityLabel: accessibilityLabel,
148
- alignItems: "center",
275
+ accessibilityLabelledBy: accessibilityLabelledBy,
276
+ animate: animateValue,
149
277
  "aria-modal": "true",
150
- background: "bg",
151
- borderTopLeftRadius: 400,
152
- borderTopRightRadius: 400,
278
+ bordered: theme.activeColorScheme === 'dark',
279
+ className: cx(trayContainerBaseCss, trayContainerPinCss, trayClassNames.container, classNames === null || classNames === void 0 ? void 0 : classNames.container),
153
280
  "data-testid": "tray",
154
- height: "100%",
281
+ drag: !preventDismiss ? 'y' : undefined,
282
+ dragConstraints: {
283
+ top: 0,
284
+ bottom: 0
285
+ },
286
+ dragControls: dragControls,
287
+ dragElastic: {
288
+ top: 0.5,
289
+ bottom: 0.5
290
+ },
291
+ dragListener: false,
292
+ elevation: 2,
155
293
  id: id,
156
- justifyContent: "center",
157
- minHeight: 200,
294
+ initial: initialAnimationValue,
158
295
  onClick: e => e.stopPropagation(),
296
+ onDragEnd: !preventDismiss ? handleDragEnd : undefined,
297
+ pin: pin,
159
298
  role: role,
299
+ style: _objectSpread({
300
+ maxHeight: isSideTray ? undefined : verticalDrawerPercentageOfView,
301
+ touchAction: !preventDismiss && pin === 'bottom' ? 'none' : undefined
302
+ }, styles === null || styles === void 0 ? void 0 : styles.container),
303
+ tabIndex: 0,
304
+ transition: animationConfig.slideIn.transition,
305
+ width: isSideTray ? 'min(400px, 100vw)' : undefined,
160
306
  children: /*#__PURE__*/_jsxs(VStack, {
161
- maxWidth: "70em",
162
- paddingX: 6,
307
+ ref: observeTraySize,
308
+ flexGrow: 1,
309
+ maxWidth: isSideTray ? undefined : '70em',
310
+ minHeight: 0,
163
311
  width: "100%",
164
- children: [header, /*#__PURE__*/_jsxs(HStack, {
165
- alignItems: "center",
166
- justifyContent: title ? 'space-between' : 'flex-end',
167
- paddingBottom: 1,
168
- paddingTop: 3,
169
- position: "sticky",
170
- top: 0,
171
- children: [title && (typeof title === 'string' ? /*#__PURE__*/_jsx(Text, {
172
- font: "title3",
173
- children: title
174
- }) : title), !preventDismiss && /*#__PURE__*/_jsx(IconButton, {
175
- transparent: true,
312
+ children: [(shouldShowTitle || headerContent || shouldShowHandleBar) && /*#__PURE__*/_jsxs(VStack, {
313
+ className: cx(shouldShrinkPadding && trayHeaderBorderBaseCss, shouldShrinkPadding && hasScrolledDown && trayHeaderBorderVisibleCss, trayClassNames.header, classNames === null || classNames === void 0 ? void 0 : classNames.header),
314
+ flexShrink: 0,
315
+ overflow: "hidden",
316
+ paddingBottom: shouldShrinkPadding ? 0.75 : 1,
317
+ paddingTop: !shouldShrinkPadding ? 3 : shouldShowHandleBar ? 0 : isSideTray ? 4 : 2,
318
+ style: styles === null || styles === void 0 ? void 0 : styles.header,
319
+ children: [shouldShowHandleBar && (preventDismiss ? /*#__PURE__*/_jsx(HandleBar, {
320
+ classNames: {
321
+ root: cx(trayClassNames.handleBar, classNames === null || classNames === void 0 ? void 0 : classNames.handleBar),
322
+ handle: cx(trayClassNames.handleBarHandle, classNames === null || classNames === void 0 ? void 0 : classNames.handleBarHandle)
323
+ },
324
+ styles: {
325
+ root: styles === null || styles === void 0 ? void 0 : styles.handleBar,
326
+ handle: styles === null || styles === void 0 ? void 0 : styles.handleBarHandle
327
+ }
328
+ }) : /*#__PURE__*/_jsx(HandleBar, {
176
329
  accessibilityHint: closeAccessibilityHint,
177
330
  accessibilityLabel: closeAccessibilityLabel,
178
- name: "close",
179
- onClick: handleClose,
180
- testID: "tray-close-button"
181
- })]
331
+ classNames: {
332
+ root: cx(trayClassNames.handleBar, classNames === null || classNames === void 0 ? void 0 : classNames.handleBar),
333
+ handle: cx(trayClassNames.handleBarHandle, classNames === null || classNames === void 0 ? void 0 : classNames.handleBarHandle)
334
+ },
335
+ onClose: handleClose,
336
+ onPointerDown: e => {
337
+ dragControls.start(e);
338
+ },
339
+ styles: {
340
+ root: styles === null || styles === void 0 ? void 0 : styles.handleBar,
341
+ handle: _objectSpread(_objectSpread({}, styles === null || styles === void 0 ? void 0 : styles.handleBarHandle), {}, {
342
+ touchAction: 'none'
343
+ })
344
+ }
345
+ })), shouldShowTitle && /*#__PURE__*/_jsxs(HStack, {
346
+ alignItems: isSideTray ? 'flex-start' : 'center',
347
+ justifyContent: title ? 'space-between' : 'flex-end',
348
+ paddingX: horizontalPadding,
349
+ children: [title && (typeof title === 'string' ? /*#__PURE__*/_jsx(Text, {
350
+ className: cx(trayClassNames.title, classNames === null || classNames === void 0 ? void 0 : classNames.title),
351
+ font: "title3",
352
+ style: styles === null || styles === void 0 ? void 0 : styles.title,
353
+ children: title
354
+ }) : title), shouldShowCloseButton && /*#__PURE__*/_jsx(IconButton, {
355
+ transparent: true,
356
+ accessibilityHint: closeAccessibilityHint,
357
+ accessibilityLabel: closeAccessibilityLabel,
358
+ className: cx(trayClassNames.closeButton, classNames === null || classNames === void 0 ? void 0 : classNames.closeButton),
359
+ margin: isSideTray ? -1.5 : undefined,
360
+ name: "close",
361
+ onClick: handleClose,
362
+ style: styles === null || styles === void 0 ? void 0 : styles.closeButton,
363
+ testID: "tray-close-button"
364
+ })]
365
+ }), headerContent]
182
366
  }), /*#__PURE__*/_jsx(VStack, {
367
+ ref: contentRef,
368
+ className: cx(trayClassNames.content, classNames === null || classNames === void 0 ? void 0 : classNames.content),
369
+ flexGrow: 1,
183
370
  minHeight: 0,
184
- paddingBottom: 2,
185
- paddingTop: 1,
186
- style: {
371
+ overflow: "hidden",
372
+ paddingBottom: shouldShrinkPadding ? 0 : 2,
373
+ paddingTop: shouldShrinkPadding ? 0 : 1,
374
+ paddingX: horizontalPadding,
375
+ style: _objectSpread({
187
376
  overflowY: 'auto'
188
- },
189
- children: typeof children === 'function' ? children({
190
- handleClose
191
- }) : children
192
- }), footer]
377
+ }, styles === null || styles === void 0 ? void 0 : styles.content),
378
+ children: content
379
+ }), footerContent]
193
380
  })
194
381
  })
195
382
  })
@@ -197,4 +384,5 @@ export const Tray = /*#__PURE__*/memo(/*#__PURE__*/forwardRef(function Tray(_ref
197
384
  })
198
385
  })
199
386
  });
200
- }));
387
+ }));
388
+ import "./Tray.css";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coinbase/cds-web",
3
- "version": "8.43.2",
3
+ "version": "8.44.1",
4
4
  "description": "Coinbase Design System - Web",
5
5
  "repository": {
6
6
  "type": "git",
@@ -207,7 +207,7 @@
207
207
  "react-dom": "^18.3.1"
208
208
  },
209
209
  "dependencies": {
210
- "@coinbase/cds-common": "^8.43.2",
210
+ "@coinbase/cds-common": "^8.44.1",
211
211
  "@coinbase/cds-icons": "^5.11.0",
212
212
  "@coinbase/cds-illustrations": "^4.31.0",
213
213
  "@coinbase/cds-lottie-files": "^3.3.4",