@xsolla/xui-b2b-drawer 0.158.0 → 0.160.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -19,23 +19,28 @@ import {
19
19
  type DrawerFooterAlign,
20
20
  type UseDrawerOptions,
21
21
  type UseDrawerReturn,
22
- } from '@xsolla/xui-b2b-drawer';
22
+ } from "@xsolla/xui-b2b-drawer";
23
23
  ```
24
24
 
25
25
  ## Quick start
26
26
 
27
27
  ```tsx
28
- import { useState } from 'react';
29
- import { Drawer } from '@xsolla/xui-b2b-drawer';
30
- import { Button } from '@xsolla/xui-button';
31
- import { Typography } from '@xsolla/xui-typography';
28
+ import { useState } from "react";
29
+ import { Drawer } from "@xsolla/xui-b2b-drawer";
30
+ import { Button } from "@xsolla/xui-button";
31
+ import { Typography } from "@xsolla/xui-typography";
32
32
 
33
33
  function BasicDrawer() {
34
34
  const [open, setOpen] = useState(false);
35
35
 
36
36
  return (
37
37
  <>
38
- <Button variant="primary" tone="brand" size="sm" onPress={() => setOpen(true)}>
38
+ <Button
39
+ variant="primary"
40
+ tone="brand"
41
+ size="sm"
42
+ onPress={() => setOpen(true)}
43
+ >
39
44
  Open drawer
40
45
  </Button>
41
46
  <Drawer
@@ -44,10 +49,20 @@ function BasicDrawer() {
44
49
  title="Settings"
45
50
  footer={
46
51
  <>
47
- <Button variant="secondary" tone="mono" size="sm" onPress={() => setOpen(false)}>
52
+ <Button
53
+ variant="secondary"
54
+ tone="mono"
55
+ size="sm"
56
+ onPress={() => setOpen(false)}
57
+ >
48
58
  Cancel
49
59
  </Button>
50
- <Button variant="primary" tone="brand" size="sm" onPress={() => setOpen(false)}>
60
+ <Button
61
+ variant="primary"
62
+ tone="brand"
63
+ size="sm"
64
+ onPress={() => setOpen(false)}
65
+ >
51
66
  Save
52
67
  </Button>
53
68
  </>
@@ -64,33 +79,34 @@ function BasicDrawer() {
64
79
 
65
80
  ### `<Drawer>`
66
81
 
67
- | Prop | Type | Default | Description |
68
- | --- | --- | --- | --- |
69
- | `open` | `boolean` | `false` | Whether the drawer is visible. |
70
- | `onClose` | `() => void` | | Called when the drawer should close (Escape, overlay click, close button). |
71
- | `size` | `DrawerSize` | `"md"` | Width preset: `sm` 480px, `md` 620px, `lg` 1056px. |
72
- | `title` | `ReactNode` | | Title displayed in the header. |
73
- | `onBack` | `() => void` | — | When provided, renders a back arrow button in the header. |
74
- | `headerAction` | `ReactNode` | — | Element rendered between the title and the close button. |
75
- | `closeOnOverlayClick` | `boolean` | `true` | Whether clicking the backdrop closes the drawer. |
76
- | `closeOnEscape` | `boolean` | `true` | Whether pressing Escape closes the drawer. |
77
- | `footer` | `ReactNode` | | Footer content (typically action buttons). |
78
- | `footerAlign` | `DrawerFooterAlign` | `"right"` | Alignment of footer content. |
79
- | `footerShadow` | `boolean` | `false` | Show a drop shadow above the footer (useful with scrollable content). |
80
- | `footerFullWidth` | `boolean` | `true` | Whether footer buttons stretch to full width. |
81
- | `stepper` | `ReactNode` | | Stepper sidebar rendered to the left of the content panel. |
82
- | `children` | `ReactNode` | — | **Required.** Main scrollable body content. |
83
- | `initialFocusRef` | `RefObject<HTMLElement>` | — | Ref to the element that should receive focus when the drawer opens. |
82
+ | Prop | Type | Default | Description |
83
+ | --------------------- | ------------------------ | --------- | ------------------------------------------------------------------------------------------------------------- |
84
+ | `testID` | `string` | | Test ID for testing frameworks. On web this renders as `data-testid`; on React Native it renders as `testID`. |
85
+ | `open` | `boolean` | `false` | Whether the drawer is visible. |
86
+ | `onClose` | `() => void` | | Called when the drawer should close (Escape, overlay click, close button). |
87
+ | `size` | `DrawerSize` | `"md"` | Width preset: `sm` 480px, `md` 620px, `lg` 1056px. |
88
+ | `title` | `ReactNode` | — | Title displayed in the header. |
89
+ | `onBack` | `() => void` | — | When provided, renders a back arrow button in the header. |
90
+ | `headerAction` | `ReactNode` | | Element rendered between the title and the close button. |
91
+ | `closeOnOverlayClick` | `boolean` | `true` | Whether clicking the backdrop closes the drawer. |
92
+ | `closeOnEscape` | `boolean` | `true` | Whether pressing Escape closes the drawer. |
93
+ | `footer` | `ReactNode` | | Footer content (typically action buttons). |
94
+ | `footerAlign` | `DrawerFooterAlign` | `"right"` | Alignment of footer content. |
95
+ | `footerShadow` | `boolean` | `false` | Show a drop shadow above the footer (useful with scrollable content). |
96
+ | `footerFullWidth` | `boolean` | `true` | Whether footer buttons stretch to full width. |
97
+ | `stepper` | `ReactNode` | — | Stepper sidebar rendered to the left of the content panel. |
98
+ | `children` | `ReactNode` | — | **Required.** Main scrollable body content. |
99
+ | `initialFocusRef` | `RefObject<HTMLElement>` | — | Ref to the element that should receive focus when the drawer opens. |
84
100
 
85
101
  Inherits `ThemeOverrideProps` (`themeMode`, `themeProductContext`).
86
102
 
87
103
  #### Deprecated props
88
104
 
89
- | Prop | Replacement |
90
- | --- | --- |
91
- | `isOpen` | `open` |
105
+ | Prop | Replacement |
106
+ | ------------------------------ | ------------------ |
107
+ | `isOpen` | `open` |
92
108
  | `header` (`{ title, onBack }`) | `title` + `onBack` |
93
- | `bottom` | `footer` |
109
+ | `bottom` | `footer` |
94
110
 
95
111
  ### `useDrawer(options?)`
96
112
 
@@ -116,8 +132,8 @@ interface UseDrawerReturn {
116
132
  ### Type exports
117
133
 
118
134
  ```ts
119
- type DrawerSize = 'sm' | 'md' | 'lg';
120
- type DrawerFooterAlign = 'center' | 'right';
135
+ type DrawerSize = "sm" | "md" | "lg";
136
+ type DrawerFooterAlign = "center" | "right";
121
137
  ```
122
138
 
123
139
  ## Examples
@@ -138,7 +154,7 @@ import { Drawer } from '@xsolla/xui-b2b-drawer';
138
154
  ### With back button
139
155
 
140
156
  ```tsx
141
- import { Drawer } from '@xsolla/xui-b2b-drawer';
157
+ import { Drawer } from "@xsolla/xui-b2b-drawer";
142
158
 
143
159
  <Drawer
144
160
  open={open}
@@ -153,8 +169,8 @@ import { Drawer } from '@xsolla/xui-b2b-drawer';
153
169
  ### With header action
154
170
 
155
171
  ```tsx
156
- import { Drawer } from '@xsolla/xui-b2b-drawer';
157
- import { Button } from '@xsolla/xui-button';
172
+ import { Drawer } from "@xsolla/xui-b2b-drawer";
173
+ import { Button } from "@xsolla/xui-button";
158
174
 
159
175
  <Drawer
160
176
  open={open}
@@ -173,12 +189,12 @@ import { Button } from '@xsolla/xui-button';
173
189
  ### `useDrawer` hook
174
190
 
175
191
  ```tsx
176
- import { Drawer, useDrawer } from '@xsolla/xui-b2b-drawer';
177
- import { Button } from '@xsolla/xui-button';
178
- import { Typography } from '@xsolla/xui-typography';
192
+ import { Drawer, useDrawer } from "@xsolla/xui-b2b-drawer";
193
+ import { Button } from "@xsolla/xui-button";
194
+ import { Typography } from "@xsolla/xui-typography";
179
195
 
180
196
  function HookExample() {
181
- const drawer = useDrawer({ onOpen: () => console.log('opened') });
197
+ const drawer = useDrawer({ onOpen: () => console.log("opened") });
182
198
  return (
183
199
  <>
184
200
  <Button variant="primary" tone="brand" size="sm" onPress={drawer.open}>
@@ -195,16 +211,16 @@ function HookExample() {
195
211
  ### With stepper sidebar
196
212
 
197
213
  ```tsx
198
- import { useState } from 'react';
199
- import { Drawer } from '@xsolla/xui-b2b-drawer';
200
- import { Stepper } from '@xsolla/xui-b2b-stepper';
201
- import { Button } from '@xsolla/xui-button';
202
- import { Typography } from '@xsolla/xui-typography';
214
+ import { useState } from "react";
215
+ import { Drawer } from "@xsolla/xui-b2b-drawer";
216
+ import { Stepper } from "@xsolla/xui-b2b-stepper";
217
+ import { Button } from "@xsolla/xui-button";
218
+ import { Typography } from "@xsolla/xui-typography";
203
219
 
204
220
  const STEPS = [
205
- { title: 'Account', description: 'Name and email' },
206
- { title: 'Billing', description: 'Payment method' },
207
- { title: 'Confirm', description: 'Review and submit' },
221
+ { title: "Account", description: "Name and email" },
222
+ { title: "Billing", description: "Payment method" },
223
+ { title: "Confirm", description: "Review and submit" },
208
224
  ];
209
225
 
210
226
  function StepperDrawer() {
@@ -214,15 +230,26 @@ function StepperDrawer() {
214
230
  const steps = STEPS.map((s, i) => ({
215
231
  ...s,
216
232
  state:
217
- i < active ? ('complete' as const) :
218
- i === active ? ('current' as const) : ('incomplete' as const),
233
+ i < active
234
+ ? ("complete" as const)
235
+ : i === active
236
+ ? ("current" as const)
237
+ : ("incomplete" as const),
219
238
  }));
220
239
 
221
240
  const isLast = active === steps.length - 1;
222
241
 
223
242
  return (
224
243
  <>
225
- <Button variant="primary" tone="brand" size="sm" onPress={() => { setActive(0); setOpen(true); }}>
244
+ <Button
245
+ variant="primary"
246
+ tone="brand"
247
+ size="sm"
248
+ onPress={() => {
249
+ setActive(0);
250
+ setOpen(true);
251
+ }}
252
+ >
226
253
  Open wizard
227
254
  </Button>
228
255
  <Drawer
@@ -240,16 +267,23 @@ function StepperDrawer() {
240
267
  }
241
268
  footer={
242
269
  <>
243
- <Button variant="secondary" tone="mono" size="sm" onPress={() => setOpen(false)}>
270
+ <Button
271
+ variant="secondary"
272
+ tone="mono"
273
+ size="sm"
274
+ onPress={() => setOpen(false)}
275
+ >
244
276
  Cancel
245
277
  </Button>
246
278
  <Button
247
279
  variant="primary"
248
280
  tone="brand"
249
281
  size="sm"
250
- onPress={() => (isLast ? setOpen(false) : setActive((a) => a + 1))}
282
+ onPress={() =>
283
+ isLast ? setOpen(false) : setActive((a) => a + 1)
284
+ }
251
285
  >
252
- {isLast ? 'Submit' : 'Next'}
286
+ {isLast ? "Submit" : "Next"}
253
287
  </Button>
254
288
  </>
255
289
  }
@@ -264,20 +298,26 @@ function StepperDrawer() {
264
298
  ### Scrollable content with footer shadow
265
299
 
266
300
  ```tsx
267
- import { Drawer } from '@xsolla/xui-b2b-drawer';
268
- import { Button } from '@xsolla/xui-button';
269
- import { Typography } from '@xsolla/xui-typography';
301
+ import { Drawer } from "@xsolla/xui-b2b-drawer";
302
+ import { Button } from "@xsolla/xui-button";
303
+ import { Typography } from "@xsolla/xui-typography";
270
304
 
271
305
  <Drawer
272
306
  open={open}
273
307
  onClose={onClose}
274
308
  title="Long content"
275
309
  footerShadow
276
- footer={<Button variant="primary" tone="brand" size="sm">Done</Button>}
310
+ footer={
311
+ <Button variant="primary" tone="brand" size="sm">
312
+ Done
313
+ </Button>
314
+ }
277
315
  >
278
- <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
316
+ <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
279
317
  {Array.from({ length: 40 }, (_, i) => (
280
- <Typography key={i} variant="bodyMd">Item {i + 1}</Typography>
318
+ <Typography key={i} variant="bodyMd">
319
+ Item {i + 1}
320
+ </Typography>
281
321
  ))}
282
322
  </div>
283
323
  </Drawer>;
@@ -46,6 +46,8 @@ interface DrawerProps extends ThemeOverrideProps {
46
46
  children: ReactNode;
47
47
  /** Ref to element that should receive focus when the drawer opens */
48
48
  initialFocusRef?: RefObject<HTMLElement>;
49
+ /** Test ID for testing frameworks */
50
+ testID?: string;
49
51
  }
50
52
 
51
53
  declare const Drawer: react.ForwardRefExoticComponent<DrawerProps & react.RefAttributes<HTMLDivElement>>;
package/native/index.d.ts CHANGED
@@ -46,6 +46,8 @@ interface DrawerProps extends ThemeOverrideProps {
46
46
  children: ReactNode;
47
47
  /** Ref to element that should receive focus when the drawer opens */
48
48
  initialFocusRef?: RefObject<HTMLElement>;
49
+ /** Test ID for testing frameworks */
50
+ testID?: string;
49
51
  }
50
52
 
51
53
  declare const Drawer: react.ForwardRefExoticComponent<DrawerProps & react.RefAttributes<HTMLDivElement>>;
package/native/index.js CHANGED
@@ -321,7 +321,14 @@ var flattenChildren = (children) => {
321
321
  return result;
322
322
  };
323
323
  var DrawerFooter = (0, import_react3.memo)(
324
- ({ children, align, shadow, fullWidth }) => {
324
+ ({
325
+ children,
326
+ align,
327
+ shadow,
328
+ fullWidth,
329
+ paddingX,
330
+ paddingY
331
+ }) => {
325
332
  const justifyContent = align === "center" ? "center" : "flex-end";
326
333
  const renderedChildren = fullWidth ? flattenChildren(children).map(
327
334
  (child, i) => import_react3.default.isValidElement(child) ? import_react3.default.cloneElement(
@@ -347,7 +354,7 @@ var DrawerFooter = (0, import_react3.memo)(
347
354
  display: "flex",
348
355
  flexDirection: "row",
349
356
  justifyContent: fullWidth ? "stretch" : justifyContent,
350
- padding: 16,
357
+ padding: `${paddingY}px ${paddingX}px`,
351
358
  gap: 8
352
359
  },
353
360
  children: renderedChildren
@@ -396,6 +403,7 @@ var Drawer = (0, import_react4.forwardRef)(
396
403
  stepper,
397
404
  children,
398
405
  initialFocusRef,
406
+ testID,
399
407
  themeMode,
400
408
  themeProductContext
401
409
  }, ref) => {
@@ -497,6 +505,7 @@ var Drawer = (0, import_react4.forwardRef)(
497
505
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
498
506
  Box,
499
507
  {
508
+ testID,
500
509
  ref: (node) => {
501
510
  drawerRef.current = node;
502
511
  if (typeof ref === "function") ref(node);
@@ -549,6 +558,8 @@ var Drawer = (0, import_react4.forwardRef)(
549
558
  align: footerAlign,
550
559
  shadow: footerShadow,
551
560
  fullWidth: footerFullWidth,
561
+ paddingX: sizing.contentPaddingX,
562
+ paddingY: sizing.footerPadding,
552
563
  children: footer
553
564
  }
554
565
  ) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { flexShrink: 0, height: 32 } })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.tsx","../../src/Drawer.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../src/DrawerRoot.native.tsx","../../src/DrawerHeader.tsx","../../src/DrawerFooter.tsx","../../src/useDrawer.ts"],"sourcesContent":["export { Drawer } from \"./Drawer\";\nexport { useDrawer } from \"./useDrawer\";\nexport type {\n DrawerProps,\n DrawerSize,\n DrawerFooterAlign,\n LegacyDrawerHeader,\n} from \"./types\";\nexport type { UseDrawerOptions, UseDrawerReturn } from \"./useDrawer\";\n","import { forwardRef, useCallback, useEffect, useRef, useState } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme } from \"@xsolla/xui-core\";\nimport type { DrawerProps } from \"./types\";\nimport { DrawerRoot } from \"./DrawerRoot\";\nimport { DrawerHeader } from \"./DrawerHeader\";\nimport { DrawerFooter } from \"./DrawerFooter\";\n\nconst FOCUSABLE_SELECTORS =\n 'button:not([disabled]), [href], input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nconst isElementVisible = (el: HTMLElement): boolean => {\n if (el.offsetParent === null && getComputedStyle(el).position !== \"fixed\")\n return false;\n const style = getComputedStyle(el);\n return style.visibility !== \"hidden\" && style.display !== \"none\";\n};\n\nconst getFocusableElements = (container: HTMLElement): HTMLElement[] =>\n Array.from(\n container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS)\n ).filter(isElementVisible);\n\nconst DRAWER_WIDTHS: Record<string, number> = {\n sm: 480,\n md: 620,\n lg: 1056,\n};\n\nexport const Drawer = forwardRef<HTMLDivElement, DrawerProps>(\n (\n {\n open: openProp,\n isOpen,\n onClose,\n size = \"md\",\n title: titleProp,\n header: headerProp,\n onBack: onBackProp,\n headerAction,\n closeOnOverlayClick = true,\n closeOnEscape = true,\n footer: footerProp,\n bottom,\n footerAlign = \"right\",\n footerShadow = false,\n footerFullWidth = true,\n stepper,\n children,\n initialFocusRef,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n // Resolve legacy aliases — new props take precedence\n const open = openProp ?? isOpen ?? false;\n const title = titleProp ?? headerProp?.title;\n const onBack = onBackProp ?? headerProp?.onBack;\n const footer = footerProp ?? bottom;\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const sizing = theme.sizing.drawer();\n\n const [mounted, setMounted] = useState(open);\n\n useEffect(() => {\n if (open) setMounted(true);\n }, [open]);\n\n const drawerRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLDivElement>(null);\n const previousActiveElement = useRef<HTMLElement | null>(null);\n\n // Focus management on open/close\n useEffect(() => {\n if (!open) return;\n if (typeof document === \"undefined\") return;\n\n previousActiveElement.current = document.activeElement as HTMLElement;\n\n const focusTarget =\n initialFocusRef?.current ||\n closeButtonRef.current ||\n (drawerRef.current && getFocusableElements(drawerRef.current)[0]);\n\n if (focusTarget) {\n (focusTarget as HTMLElement).focus();\n } else {\n drawerRef.current?.focus();\n }\n\n // Focus is restored inside onExited (after the exit animation) so that\n // keyboard focus does not escape back to the page while the drawer is\n // still visible on screen.\n }, [open, initialFocusRef]);\n\n // Escape key handler\n useEffect(() => {\n if (!open || !closeOnEscape || !onClose) return;\n if (typeof document === \"undefined\") return;\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, closeOnEscape, onClose]);\n\n // Focus trap\n const handleKeyDown = useCallback((event: React.KeyboardEvent) => {\n if (event.key !== \"Tab\" || !drawerRef.current) return;\n if (typeof document === \"undefined\") return;\n\n const focusableElements = getFocusableElements(drawerRef.current);\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (!firstElement) {\n event.preventDefault();\n return;\n }\n\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }, []);\n\n if (!mounted) return null;\n\n const contentWidth = DRAWER_WIDTHS[size];\n\n return (\n <DrawerRoot\n open={open}\n onExited={() => {\n setMounted(false);\n previousActiveElement.current?.focus();\n }}\n onBackdropClick={closeOnOverlayClick ? onClose : undefined}\n scrimColor={sizing.scrimColor}\n outerPadding={sizing.outerPadding}\n animationDuration={sizing.animationDuration}\n zIndex={sizing.zIndex}\n >\n {/* Outer panel — white background + container radius clips the inner content corners */}\n <div\n style={{\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"stretch\",\n backgroundColor: theme.colors.background.primary,\n borderRadius: sizing.containerRadius,\n overflow: \"hidden\",\n gap: stepper ? sizing.stepperContentGap : 0,\n }}\n >\n {/* Optional stepper sidebar */}\n {stepper && (\n <div\n style={{\n flexShrink: 0,\n alignSelf: \"stretch\",\n backgroundColor: theme.colors.background.secondary,\n borderRadius: sizing.contentRadius,\n padding: sizing.stepperPadding,\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {stepper}\n </div>\n )}\n\n {/* Content panel */}\n <Box\n ref={(node: HTMLDivElement | null) => {\n (\n drawerRef as React.MutableRefObject<HTMLDivElement | null>\n ).current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref)\n (ref as React.MutableRefObject<HTMLDivElement | null>).current =\n node;\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={typeof title === \"string\" ? title : undefined}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n style={{\n width: contentWidth,\n height: \"100%\",\n flexShrink: 0,\n display: \"flex\",\n flexDirection: \"column\",\n outline: \"none\",\n color: theme.colors.content.primary,\n }}\n >\n {/* Header */}\n <DrawerHeader\n title={title}\n onBack={onBack}\n onClose={onClose}\n headerAction={headerAction}\n paddingX={sizing.headerPaddingX}\n paddingY={sizing.headerPaddingY}\n gap={sizing.headerGap}\n />\n\n {/* Body */}\n <Box\n style={{\n flex: 1,\n minHeight: 0,\n overflowY: \"auto\",\n paddingLeft: sizing.contentPaddingX,\n paddingRight: sizing.contentPaddingX,\n }}\n >\n {children}\n </Box>\n\n {/* Footer */}\n {footer ? (\n <DrawerFooter\n align={footerAlign}\n shadow={footerShadow}\n fullWidth={footerFullWidth}\n >\n {footer}\n </DrawerFooter>\n ) : (\n <div style={{ flexShrink: 0, height: 32 }} />\n )}\n </Box>\n </div>\n </DrawerRoot>\n );\n }\n);\n\nDrawer.displayName = \"Drawer\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import { memo } from \"react\";\nimport type { DrawerRootProps } from \"./types\";\n\n// Web portal not available on React Native.\n// Native drawer implementation would use RN-specific approach (e.g. Animated.View).\nexport const DrawerRoot = memo((_props: DrawerRootProps) => {\n return null;\n});\n\nDrawerRoot.displayName = \"DrawerRoot\";\n","import { memo } from \"react\";\nimport { IconButton } from \"@xsolla/xui-button\";\nimport { ArrowLeft, Remove } from \"@xsolla/xui-icons-base\";\nimport { Typography } from \"@xsolla/xui-typography\";\nimport type { DrawerHeaderProps } from \"./types\";\n\nexport const DrawerHeader = memo(\n ({\n title,\n onBack,\n onClose,\n headerAction,\n paddingX,\n paddingY,\n gap,\n }: DrawerHeaderProps) => {\n return (\n <div\n style={{\n flexShrink: 0,\n height: 80,\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n paddingLeft: paddingX,\n paddingRight: paddingX,\n paddingTop: paddingY,\n paddingBottom: paddingY,\n gap,\n boxSizing: \"border-box\",\n }}\n >\n {/* Left content: back button + title */}\n <div\n style={{\n flex: 1,\n minWidth: 0,\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 16,\n }}\n >\n {/* Back button */}\n {onBack && (\n <IconButton\n variant=\"secondary\"\n tone=\"mono\"\n size=\"xs\"\n icon={<ArrowLeft />}\n onPress={onBack}\n aria-label=\"Go back\"\n />\n )}\n\n {/* Title */}\n {title && (\n <div style={{ flex: 1, minWidth: 0, overflow: \"hidden\" }}>\n <Typography variant=\"bodyLgAccent\" noWrap>\n {title}\n </Typography>\n </div>\n )}\n </div>\n\n {/* Optional header action */}\n {headerAction && <div style={{ flexShrink: 0 }}>{headerAction}</div>}\n\n {/* Close button */}\n {onClose && (\n <IconButton\n variant=\"secondary\"\n tone=\"mono\"\n size=\"xs\"\n icon={<Remove />}\n onPress={onClose}\n aria-label=\"Close drawer\"\n />\n )}\n </div>\n );\n }\n);\n\nDrawerHeader.displayName = \"DrawerHeader\";\n","import React, { memo } from \"react\";\nimport type { DrawerFooterProps } from \"./types\";\n\nconst flattenChildren = (children: React.ReactNode): React.ReactNode[] => {\n const result: React.ReactNode[] = [];\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child) && child.type === React.Fragment) {\n result.push(\n ...flattenChildren(\n (child.props as { children: React.ReactNode }).children\n )\n );\n } else if (child !== null && child !== undefined) {\n result.push(child);\n }\n });\n return result;\n};\n\nexport const DrawerFooter = memo(\n ({ children, align, shadow, fullWidth }: DrawerFooterProps) => {\n const justifyContent = align === \"center\" ? \"center\" : \"flex-end\";\n\n const renderedChildren = fullWidth\n ? flattenChildren(children).map((child, i) =>\n React.isValidElement(child)\n ? React.cloneElement(\n child as React.ReactElement<Record<string, unknown>>,\n {\n key: (child as React.ReactElement).key ?? i,\n fullWidth: true,\n }\n )\n : child\n )\n : children;\n\n return (\n <div\n style={{\n flexShrink: 0,\n width: \"100%\",\n boxShadow: shadow ? \"0px 2px 25px 0px rgba(7, 7, 8, 0.15)\" : \"none\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n justifyContent: fullWidth ? \"stretch\" : justifyContent,\n padding: 16,\n gap: 8,\n }}\n >\n {renderedChildren}\n </div>\n </div>\n );\n }\n);\n\nDrawerFooter.displayName = \"DrawerFooter\";\n","import { useCallback, useState } from \"react\";\n\nexport interface UseDrawerOptions {\n onOpen?: () => void;\n onClose?: () => void;\n}\n\nexport interface UseDrawerReturn {\n isOpen: boolean;\n open: () => void;\n close: () => void;\n}\n\nexport function useDrawer(options?: UseDrawerOptions): UseDrawerReturn {\n const [isOpen, setIsOpen] = useState(false);\n\n const open = useCallback(() => {\n setIsOpen(true);\n options?.onOpen?.();\n }, [options]);\n\n const close = useCallback(() => {\n setIsOpen(false);\n options?.onClose?.();\n }, [options]);\n\n return { isOpen, open, close };\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","React","import_jsx_runtime","handleKeyDown","import_react"]}
1
+ {"version":3,"sources":["../../src/index.tsx","../../src/Drawer.tsx","../../../../foundation/primitives-native/src/Box.tsx","../../src/DrawerRoot.native.tsx","../../src/DrawerHeader.tsx","../../src/DrawerFooter.tsx","../../src/useDrawer.ts"],"sourcesContent":["export { Drawer } from \"./Drawer\";\nexport { useDrawer } from \"./useDrawer\";\nexport type {\n DrawerProps,\n DrawerSize,\n DrawerFooterAlign,\n LegacyDrawerHeader,\n} from \"./types\";\nexport type { UseDrawerOptions, UseDrawerReturn } from \"./useDrawer\";\n","import { forwardRef, useCallback, useEffect, useRef, useState } from \"react\";\n// @ts-expect-error - this will be resolved at build time\nimport { Box } from \"@xsolla/xui-primitives\";\nimport { useResolvedTheme } from \"@xsolla/xui-core\";\nimport type { DrawerProps } from \"./types\";\nimport { DrawerRoot } from \"./DrawerRoot\";\nimport { DrawerHeader } from \"./DrawerHeader\";\nimport { DrawerFooter } from \"./DrawerFooter\";\n\nconst FOCUSABLE_SELECTORS =\n 'button:not([disabled]), [href], input:not([disabled]):not([type=\"hidden\"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex=\"-1\"])';\n\nconst isElementVisible = (el: HTMLElement): boolean => {\n if (el.offsetParent === null && getComputedStyle(el).position !== \"fixed\")\n return false;\n const style = getComputedStyle(el);\n return style.visibility !== \"hidden\" && style.display !== \"none\";\n};\n\nconst getFocusableElements = (container: HTMLElement): HTMLElement[] =>\n Array.from(\n container.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTORS)\n ).filter(isElementVisible);\n\nconst DRAWER_WIDTHS: Record<string, number> = {\n sm: 480,\n md: 620,\n lg: 1056,\n};\n\nexport const Drawer = forwardRef<HTMLDivElement, DrawerProps>(\n (\n {\n open: openProp,\n isOpen,\n onClose,\n size = \"md\",\n title: titleProp,\n header: headerProp,\n onBack: onBackProp,\n headerAction,\n closeOnOverlayClick = true,\n closeOnEscape = true,\n footer: footerProp,\n bottom,\n footerAlign = \"right\",\n footerShadow = false,\n footerFullWidth = true,\n stepper,\n children,\n initialFocusRef,\n testID,\n themeMode,\n themeProductContext,\n },\n ref\n ) => {\n // Resolve legacy aliases — new props take precedence\n const open = openProp ?? isOpen ?? false;\n const title = titleProp ?? headerProp?.title;\n const onBack = onBackProp ?? headerProp?.onBack;\n const footer = footerProp ?? bottom;\n const { theme } = useResolvedTheme({ themeMode, themeProductContext });\n const sizing = theme.sizing.drawer();\n\n const [mounted, setMounted] = useState(open);\n\n useEffect(() => {\n if (open) setMounted(true);\n }, [open]);\n\n const drawerRef = useRef<HTMLDivElement>(null);\n const closeButtonRef = useRef<HTMLDivElement>(null);\n const previousActiveElement = useRef<HTMLElement | null>(null);\n\n // Focus management on open/close\n useEffect(() => {\n if (!open) return;\n if (typeof document === \"undefined\") return;\n\n previousActiveElement.current = document.activeElement as HTMLElement;\n\n const focusTarget =\n initialFocusRef?.current ||\n closeButtonRef.current ||\n (drawerRef.current && getFocusableElements(drawerRef.current)[0]);\n\n if (focusTarget) {\n (focusTarget as HTMLElement).focus();\n } else {\n drawerRef.current?.focus();\n }\n\n // Focus is restored inside onExited (after the exit animation) so that\n // keyboard focus does not escape back to the page while the drawer is\n // still visible on screen.\n }, [open, initialFocusRef]);\n\n // Escape key handler\n useEffect(() => {\n if (!open || !closeOnEscape || !onClose) return;\n if (typeof document === \"undefined\") return;\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") onClose();\n };\n document.addEventListener(\"keydown\", handleKeyDown);\n return () => document.removeEventListener(\"keydown\", handleKeyDown);\n }, [open, closeOnEscape, onClose]);\n\n // Focus trap\n const handleKeyDown = useCallback((event: React.KeyboardEvent) => {\n if (event.key !== \"Tab\" || !drawerRef.current) return;\n if (typeof document === \"undefined\") return;\n\n const focusableElements = getFocusableElements(drawerRef.current);\n const firstElement = focusableElements[0];\n const lastElement = focusableElements[focusableElements.length - 1];\n\n if (!firstElement) {\n event.preventDefault();\n return;\n }\n\n if (event.shiftKey && document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n } else if (!event.shiftKey && document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }, []);\n\n if (!mounted) return null;\n\n const contentWidth = DRAWER_WIDTHS[size];\n\n return (\n <DrawerRoot\n open={open}\n onExited={() => {\n setMounted(false);\n previousActiveElement.current?.focus();\n }}\n onBackdropClick={closeOnOverlayClick ? onClose : undefined}\n scrimColor={sizing.scrimColor}\n outerPadding={sizing.outerPadding}\n animationDuration={sizing.animationDuration}\n zIndex={sizing.zIndex}\n >\n {/* Outer panel — white background + container radius clips the inner content corners */}\n <div\n style={{\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"stretch\",\n backgroundColor: theme.colors.background.primary,\n borderRadius: sizing.containerRadius,\n overflow: \"hidden\",\n gap: stepper ? sizing.stepperContentGap : 0,\n }}\n >\n {/* Optional stepper sidebar */}\n {stepper && (\n <div\n style={{\n flexShrink: 0,\n alignSelf: \"stretch\",\n backgroundColor: theme.colors.background.secondary,\n borderRadius: sizing.contentRadius,\n padding: sizing.stepperPadding,\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {stepper}\n </div>\n )}\n\n {/* Content panel */}\n <Box\n testID={testID}\n ref={(node: HTMLDivElement | null) => {\n (\n drawerRef as React.MutableRefObject<HTMLDivElement | null>\n ).current = node;\n if (typeof ref === \"function\") ref(node);\n else if (ref)\n (ref as React.MutableRefObject<HTMLDivElement | null>).current =\n node;\n }}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={typeof title === \"string\" ? title : undefined}\n tabIndex={-1}\n onKeyDown={handleKeyDown}\n style={{\n width: contentWidth,\n height: \"100%\",\n flexShrink: 0,\n display: \"flex\",\n flexDirection: \"column\",\n outline: \"none\",\n color: theme.colors.content.primary,\n }}\n >\n {/* Header */}\n <DrawerHeader\n title={title}\n onBack={onBack}\n onClose={onClose}\n headerAction={headerAction}\n paddingX={sizing.headerPaddingX}\n paddingY={sizing.headerPaddingY}\n gap={sizing.headerGap}\n />\n\n {/* Body */}\n <Box\n style={{\n flex: 1,\n minHeight: 0,\n overflowY: \"auto\",\n paddingLeft: sizing.contentPaddingX,\n paddingRight: sizing.contentPaddingX,\n }}\n >\n {children}\n </Box>\n\n {/* Footer */}\n {footer ? (\n <DrawerFooter\n align={footerAlign}\n shadow={footerShadow}\n fullWidth={footerFullWidth}\n paddingX={sizing.contentPaddingX}\n paddingY={sizing.footerPadding}\n >\n {footer}\n </DrawerFooter>\n ) : (\n <div style={{ flexShrink: 0, height: 32 }} />\n )}\n </Box>\n </div>\n </DrawerRoot>\n );\n }\n);\n\nDrawer.displayName = \"Drawer\";\n","import React from \"react\";\nimport {\n View,\n Pressable,\n Image,\n ViewStyle,\n ImageStyle,\n DimensionValue,\n AnimatableNumericValue,\n} from \"react-native\";\nimport { BoxProps } from \"@xsolla/xui-primitives-core\";\n\nexport const Box: React.FC<BoxProps> = ({\n children,\n onPress,\n onLayout,\n onMoveShouldSetResponder,\n onResponderGrant,\n onResponderMove,\n onResponderRelease,\n onResponderTerminate,\n backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius,\n borderStyle,\n height,\n padding,\n paddingHorizontal,\n paddingVertical,\n margin,\n marginTop,\n marginBottom,\n marginLeft,\n marginRight,\n flexDirection,\n alignItems,\n justifyContent,\n position,\n top,\n bottom,\n left,\n right,\n width,\n minWidth,\n minHeight,\n maxWidth,\n maxHeight,\n flex,\n overflow,\n zIndex,\n hoverStyle,\n pressStyle,\n style,\n \"data-testid\": dataTestId,\n testID,\n as,\n src,\n alt,\n ...rest\n}) => {\n const getContainerStyle = (pressed?: boolean): ViewStyle => ({\n backgroundColor:\n pressed && pressStyle?.backgroundColor\n ? pressStyle.backgroundColor\n : backgroundColor,\n borderColor,\n borderWidth,\n borderBottomWidth,\n borderBottomColor,\n borderTopWidth,\n borderTopColor,\n borderLeftWidth,\n borderLeftColor,\n borderRightWidth,\n borderRightColor,\n borderRadius: borderRadius as AnimatableNumericValue,\n borderStyle: borderStyle as ViewStyle[\"borderStyle\"],\n overflow,\n zIndex,\n height: height as DimensionValue,\n width: width as DimensionValue,\n minWidth: minWidth as DimensionValue,\n minHeight: minHeight as DimensionValue,\n maxWidth: maxWidth as DimensionValue,\n maxHeight: maxHeight as DimensionValue,\n padding: padding as DimensionValue,\n paddingHorizontal: paddingHorizontal as DimensionValue,\n paddingVertical: paddingVertical as DimensionValue,\n margin: margin as DimensionValue,\n marginTop: marginTop as DimensionValue,\n marginBottom: marginBottom as DimensionValue,\n marginLeft: marginLeft as DimensionValue,\n marginRight: marginRight as DimensionValue,\n flexDirection,\n alignItems,\n justifyContent,\n position: position as ViewStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n flex,\n ...(style as ViewStyle),\n });\n\n const finalTestID = dataTestId || testID;\n\n // Destructure and drop web-only props from rest before passing to RN components\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const {\n role,\n tabIndex,\n onKeyDown,\n onKeyUp,\n \"aria-label\": _ariaLabel,\n \"aria-labelledby\": _ariaLabelledBy,\n \"aria-current\": _ariaCurrent,\n \"aria-disabled\": _ariaDisabled,\n \"aria-live\": _ariaLive,\n className,\n \"data-testid\": _dataTestId,\n ...nativeRest\n } = rest as Record<string, unknown>;\n\n // Handle as=\"img\" for React Native\n if (as === \"img\" && src) {\n const imageStyle: ImageStyle = {\n width: width as DimensionValue,\n height: height as DimensionValue,\n borderRadius: borderRadius as number,\n position: position as ImageStyle[\"position\"],\n top: top as DimensionValue,\n bottom: bottom as DimensionValue,\n left: left as DimensionValue,\n right: right as DimensionValue,\n ...(style as ImageStyle),\n };\n\n return (\n <Image\n source={{ uri: src }}\n style={imageStyle}\n testID={finalTestID}\n resizeMode=\"cover\"\n {...nativeRest}\n />\n );\n }\n\n if (onPress) {\n return (\n <Pressable\n onPress={onPress}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n style={({ pressed }) => getContainerStyle(pressed)}\n testID={finalTestID}\n {...nativeRest}\n >\n {children}\n </Pressable>\n );\n }\n\n return (\n <View\n style={getContainerStyle()}\n testID={finalTestID}\n onLayout={onLayout}\n onMoveShouldSetResponder={onMoveShouldSetResponder}\n onResponderGrant={onResponderGrant}\n onResponderMove={onResponderMove}\n onResponderRelease={onResponderRelease}\n onResponderTerminate={onResponderTerminate}\n {...nativeRest}\n >\n {children}\n </View>\n );\n};\n","import { memo } from \"react\";\nimport type { DrawerRootProps } from \"./types\";\n\n// Web portal not available on React Native.\n// Native drawer implementation would use RN-specific approach (e.g. Animated.View).\nexport const DrawerRoot = memo((_props: DrawerRootProps) => {\n return null;\n});\n\nDrawerRoot.displayName = \"DrawerRoot\";\n","import { memo } from \"react\";\nimport { IconButton } from \"@xsolla/xui-button\";\nimport { ArrowLeft, Remove } from \"@xsolla/xui-icons-base\";\nimport { Typography } from \"@xsolla/xui-typography\";\nimport type { DrawerHeaderProps } from \"./types\";\n\nexport const DrawerHeader = memo(\n ({\n title,\n onBack,\n onClose,\n headerAction,\n paddingX,\n paddingY,\n gap,\n }: DrawerHeaderProps) => {\n return (\n <div\n style={{\n flexShrink: 0,\n height: 80,\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n paddingLeft: paddingX,\n paddingRight: paddingX,\n paddingTop: paddingY,\n paddingBottom: paddingY,\n gap,\n boxSizing: \"border-box\",\n }}\n >\n {/* Left content: back button + title */}\n <div\n style={{\n flex: 1,\n minWidth: 0,\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: 16,\n }}\n >\n {/* Back button */}\n {onBack && (\n <IconButton\n variant=\"secondary\"\n tone=\"mono\"\n size=\"xs\"\n icon={<ArrowLeft />}\n onPress={onBack}\n aria-label=\"Go back\"\n />\n )}\n\n {/* Title */}\n {title && (\n <div style={{ flex: 1, minWidth: 0, overflow: \"hidden\" }}>\n <Typography variant=\"bodyLgAccent\" noWrap>\n {title}\n </Typography>\n </div>\n )}\n </div>\n\n {/* Optional header action */}\n {headerAction && <div style={{ flexShrink: 0 }}>{headerAction}</div>}\n\n {/* Close button */}\n {onClose && (\n <IconButton\n variant=\"secondary\"\n tone=\"mono\"\n size=\"xs\"\n icon={<Remove />}\n onPress={onClose}\n aria-label=\"Close drawer\"\n />\n )}\n </div>\n );\n }\n);\n\nDrawerHeader.displayName = \"DrawerHeader\";\n","import React, { memo } from \"react\";\nimport type { DrawerFooterProps } from \"./types\";\n\nconst flattenChildren = (children: React.ReactNode): React.ReactNode[] => {\n const result: React.ReactNode[] = [];\n React.Children.forEach(children, (child) => {\n if (React.isValidElement(child) && child.type === React.Fragment) {\n result.push(\n ...flattenChildren(\n (child.props as { children: React.ReactNode }).children\n )\n );\n } else if (child !== null && child !== undefined) {\n result.push(child);\n }\n });\n return result;\n};\n\nexport const DrawerFooter = memo(\n ({\n children,\n align,\n shadow,\n fullWidth,\n paddingX,\n paddingY,\n }: DrawerFooterProps) => {\n const justifyContent = align === \"center\" ? \"center\" : \"flex-end\";\n\n const renderedChildren = fullWidth\n ? flattenChildren(children).map((child, i) =>\n React.isValidElement(child)\n ? React.cloneElement(\n child as React.ReactElement<Record<string, unknown>>,\n {\n key: (child as React.ReactElement).key ?? i,\n fullWidth: true,\n }\n )\n : child\n )\n : children;\n\n return (\n <div\n style={{\n flexShrink: 0,\n width: \"100%\",\n boxShadow: shadow ? \"0px 2px 25px 0px rgba(7, 7, 8, 0.15)\" : \"none\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n justifyContent: fullWidth ? \"stretch\" : justifyContent,\n padding: `${paddingY}px ${paddingX}px`,\n gap: 8,\n }}\n >\n {renderedChildren}\n </div>\n </div>\n );\n }\n);\n\nDrawerFooter.displayName = \"DrawerFooter\";\n","import { useCallback, useState } from \"react\";\n\nexport interface UseDrawerOptions {\n onOpen?: () => void;\n onClose?: () => void;\n}\n\nexport interface UseDrawerReturn {\n isOpen: boolean;\n open: () => void;\n close: () => void;\n}\n\nexport function useDrawer(options?: UseDrawerOptions): UseDrawerReturn {\n const [isOpen, setIsOpen] = useState(false);\n\n const open = useCallback(() => {\n setIsOpen(true);\n options?.onOpen?.();\n }, [options]);\n\n const close = useCallback(() => {\n setIsOpen(false);\n options?.onClose?.();\n }, [options]);\n\n return { isOpen, open, close };\n}\n"],"mappings":"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","names":["import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","React","import_jsx_runtime","handleKeyDown","import_react"]}
package/native/index.mjs CHANGED
@@ -288,7 +288,14 @@ var flattenChildren = (children) => {
288
288
  return result;
289
289
  };
290
290
  var DrawerFooter = memo3(
291
- ({ children, align, shadow, fullWidth }) => {
291
+ ({
292
+ children,
293
+ align,
294
+ shadow,
295
+ fullWidth,
296
+ paddingX,
297
+ paddingY
298
+ }) => {
292
299
  const justifyContent = align === "center" ? "center" : "flex-end";
293
300
  const renderedChildren = fullWidth ? flattenChildren(children).map(
294
301
  (child, i) => React.isValidElement(child) ? React.cloneElement(
@@ -314,7 +321,7 @@ var DrawerFooter = memo3(
314
321
  display: "flex",
315
322
  flexDirection: "row",
316
323
  justifyContent: fullWidth ? "stretch" : justifyContent,
317
- padding: 16,
324
+ padding: `${paddingY}px ${paddingX}px`,
318
325
  gap: 8
319
326
  },
320
327
  children: renderedChildren
@@ -363,6 +370,7 @@ var Drawer = forwardRef(
363
370
  stepper,
364
371
  children,
365
372
  initialFocusRef,
373
+ testID,
366
374
  themeMode,
367
375
  themeProductContext
368
376
  }, ref) => {
@@ -464,6 +472,7 @@ var Drawer = forwardRef(
464
472
  /* @__PURE__ */ jsxs2(
465
473
  Box,
466
474
  {
475
+ testID,
467
476
  ref: (node) => {
468
477
  drawerRef.current = node;
469
478
  if (typeof ref === "function") ref(node);
@@ -516,6 +525,8 @@ var Drawer = forwardRef(
516
525
  align: footerAlign,
517
526
  shadow: footerShadow,
518
527
  fullWidth: footerFullWidth,
528
+ paddingX: sizing.contentPaddingX,
529
+ paddingY: sizing.footerPadding,
519
530
  children: footer
520
531
  }
521
532
  ) : /* @__PURE__ */ jsx4("div", { style: { flexShrink: 0, height: 32 } })