@xsolla/xui-b2b-drawer 0.147.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.
package/web/index.mjs ADDED
@@ -0,0 +1,708 @@
1
+ // src/Drawer.tsx
2
+ import { forwardRef, useCallback, useEffect as useEffect2, useRef, useState as useState2 } from "react";
3
+
4
+ // ../../foundation/primitives-web/src/Box.tsx
5
+ import React2 from "react";
6
+ import styled from "styled-components";
7
+
8
+ // ../../foundation/primitives-web/src/filterDOMProps.ts
9
+ import React from "react";
10
+
11
+ // ../../../node_modules/@emotion/memoize/dist/memoize.esm.js
12
+ function memoize(fn) {
13
+ var cache = {};
14
+ return function(arg) {
15
+ if (cache[arg] === void 0) cache[arg] = fn(arg);
16
+ return cache[arg];
17
+ };
18
+ }
19
+ var memoize_esm_default = memoize;
20
+
21
+ // ../../../node_modules/@emotion/is-prop-valid/dist/is-prop-valid.esm.js
22
+ var reactPropsRegex = /^((children|dangerouslySetInnerHTML|key|ref|autoFocus|defaultValue|defaultChecked|innerHTML|suppressContentEditableWarning|suppressHydrationWarning|valueLink|accept|acceptCharset|accessKey|action|allow|allowUserMedia|allowPaymentRequest|allowFullScreen|allowTransparency|alt|async|autoComplete|autoPlay|capture|cellPadding|cellSpacing|challenge|charSet|checked|cite|classID|className|cols|colSpan|content|contentEditable|contextMenu|controls|controlsList|coords|crossOrigin|data|dateTime|decoding|default|defer|dir|disabled|disablePictureInPicture|download|draggable|encType|form|formAction|formEncType|formMethod|formNoValidate|formTarget|frameBorder|headers|height|hidden|high|href|hrefLang|htmlFor|httpEquiv|id|inputMode|integrity|is|keyParams|keyType|kind|label|lang|list|loading|loop|low|marginHeight|marginWidth|max|maxLength|media|mediaGroup|method|min|minLength|multiple|muted|name|nonce|noValidate|open|optimum|pattern|placeholder|playsInline|poster|preload|profile|radioGroup|readOnly|referrerPolicy|rel|required|reversed|role|rows|rowSpan|sandbox|scope|scoped|scrolling|seamless|selected|shape|size|sizes|slot|span|spellCheck|src|srcDoc|srcLang|srcSet|start|step|style|summary|tabIndex|target|title|type|useMap|value|width|wmode|wrap|about|datatype|inlist|prefix|property|resource|typeof|vocab|autoCapitalize|autoCorrect|autoSave|color|inert|itemProp|itemScope|itemType|itemID|itemRef|on|results|security|unselectable|accentHeight|accumulate|additive|alignmentBaseline|allowReorder|alphabetic|amplitude|arabicForm|ascent|attributeName|attributeType|autoReverse|azimuth|baseFrequency|baselineShift|baseProfile|bbox|begin|bias|by|calcMode|capHeight|clip|clipPathUnits|clipPath|clipRule|colorInterpolation|colorInterpolationFilters|colorProfile|colorRendering|contentScriptType|contentStyleType|cursor|cx|cy|d|decelerate|descent|diffuseConstant|direction|display|divisor|dominantBaseline|dur|dx|dy|edgeMode|elevation|enableBackground|end|exponent|externalResourcesRequired|fill|fillOpacity|fillRule|filter|filterRes|filterUnits|floodColor|floodOpacity|focusable|fontFamily|fontSize|fontSizeAdjust|fontStretch|fontStyle|fontVariant|fontWeight|format|from|fr|fx|fy|g1|g2|glyphName|glyphOrientationHorizontal|glyphOrientationVertical|glyphRef|gradientTransform|gradientUnits|hanging|horizAdvX|horizOriginX|ideographic|imageRendering|in|in2|intercept|k|k1|k2|k3|k4|kernelMatrix|kernelUnitLength|kerning|keyPoints|keySplines|keyTimes|lengthAdjust|letterSpacing|lightingColor|limitingConeAngle|local|markerEnd|markerMid|markerStart|markerHeight|markerUnits|markerWidth|mask|maskContentUnits|maskUnits|mathematical|mode|numOctaves|offset|opacity|operator|order|orient|orientation|origin|overflow|overlinePosition|overlineThickness|panose1|paintOrder|pathLength|patternContentUnits|patternTransform|patternUnits|pointerEvents|points|pointsAtX|pointsAtY|pointsAtZ|preserveAlpha|preserveAspectRatio|primitiveUnits|r|radius|refX|refY|renderingIntent|repeatCount|repeatDur|requiredExtensions|requiredFeatures|restart|result|rotate|rx|ry|scale|seed|shapeRendering|slope|spacing|specularConstant|specularExponent|speed|spreadMethod|startOffset|stdDeviation|stemh|stemv|stitchTiles|stopColor|stopOpacity|strikethroughPosition|strikethroughThickness|string|stroke|strokeDasharray|strokeDashoffset|strokeLinecap|strokeLinejoin|strokeMiterlimit|strokeOpacity|strokeWidth|surfaceScale|systemLanguage|tableValues|targetX|targetY|textAnchor|textDecoration|textRendering|textLength|to|transform|u1|u2|underlinePosition|underlineThickness|unicode|unicodeBidi|unicodeRange|unitsPerEm|vAlphabetic|vHanging|vIdeographic|vMathematical|values|vectorEffect|version|vertAdvY|vertOriginX|vertOriginY|viewBox|viewTarget|visibility|widths|wordSpacing|writingMode|x|xHeight|x1|x2|xChannelSelector|xlinkActuate|xlinkArcrole|xlinkHref|xlinkRole|xlinkShow|xlinkTitle|xlinkType|xmlBase|xmlns|xmlnsXlink|xmlLang|xmlSpace|y|y1|y2|yChannelSelector|z|zoomAndPan|for|class|autofocus)|(([Dd][Aa][Tt][Aa]|[Aa][Rr][Ii][Aa]|x)-.*))$/;
23
+ var index = memoize_esm_default(
24
+ function(prop) {
25
+ return reactPropsRegex.test(prop) || prop.charCodeAt(0) === 111 && prop.charCodeAt(1) === 110 && prop.charCodeAt(2) < 91;
26
+ }
27
+ /* Z+1 */
28
+ );
29
+ var is_prop_valid_esm_default = index;
30
+
31
+ // ../../foundation/primitives-web/src/filterDOMProps.ts
32
+ var ADDITIONAL_BLOCKED_PROPS = /* @__PURE__ */ new Set([
33
+ // RN-only event handlers (pass isPropValid's on* pattern)
34
+ "onPress",
35
+ "onChangeText",
36
+ "onLayout",
37
+ "onMoveShouldSetResponder",
38
+ "onResponderGrant",
39
+ "onResponderMove",
40
+ "onResponderRelease",
41
+ "onResponderTerminate",
42
+ // SVG attributes that pass isPropValid
43
+ "strokeWidth",
44
+ // CSS properties that pass isPropValid but are used as component props
45
+ "overflow",
46
+ "cursor",
47
+ "fontSize",
48
+ "fontWeight",
49
+ "fontFamily",
50
+ "textDecoration"
51
+ ]);
52
+ function shouldForwardProp(key) {
53
+ if (ADDITIONAL_BLOCKED_PROPS.has(key)) return false;
54
+ return is_prop_valid_esm_default(key);
55
+ }
56
+ function createFilteredElement(defaultTag) {
57
+ const Component = React.forwardRef(
58
+ ({ children, elementType, ...props }, ref) => {
59
+ const Tag = elementType || defaultTag;
60
+ const htmlProps = {};
61
+ for (const key of Object.keys(props)) {
62
+ if (shouldForwardProp(key)) {
63
+ htmlProps[key] = props[key];
64
+ }
65
+ }
66
+ return React.createElement(
67
+ Tag,
68
+ { ref, ...htmlProps },
69
+ children
70
+ );
71
+ }
72
+ );
73
+ Component.displayName = `Filtered(${defaultTag})`;
74
+ return Component;
75
+ }
76
+
77
+ // ../../foundation/primitives-web/src/Box.tsx
78
+ import { jsx } from "react/jsx-runtime";
79
+ var FilteredDiv = createFilteredElement("div");
80
+ var StyledBox = styled(FilteredDiv)`
81
+ display: flex;
82
+ box-sizing: border-box;
83
+ background-color: ${(props) => props.backgroundColor || "transparent"};
84
+ border-color: ${(props) => props.borderColor || "transparent"};
85
+ border-width: ${(props) => typeof props.borderWidth === "number" ? `${props.borderWidth}px` : props.borderWidth || 0};
86
+
87
+ ${(props) => props.borderBottomWidth !== void 0 && `
88
+ border-bottom-width: ${typeof props.borderBottomWidth === "number" ? `${props.borderBottomWidth}px` : props.borderBottomWidth};
89
+ border-bottom-color: ${props.borderBottomColor || props.borderColor || "transparent"};
90
+ border-bottom-style: solid;
91
+ `}
92
+ ${(props) => props.borderTopWidth !== void 0 && `
93
+ border-top-width: ${typeof props.borderTopWidth === "number" ? `${props.borderTopWidth}px` : props.borderTopWidth};
94
+ border-top-color: ${props.borderTopColor || props.borderColor || "transparent"};
95
+ border-top-style: solid;
96
+ `}
97
+ ${(props) => props.borderLeftWidth !== void 0 && `
98
+ border-left-width: ${typeof props.borderLeftWidth === "number" ? `${props.borderLeftWidth}px` : props.borderLeftWidth};
99
+ border-left-color: ${props.borderLeftColor || props.borderColor || "transparent"};
100
+ border-left-style: solid;
101
+ `}
102
+ ${(props) => props.borderRightWidth !== void 0 && `
103
+ border-right-width: ${typeof props.borderRightWidth === "number" ? `${props.borderRightWidth}px` : props.borderRightWidth};
104
+ border-right-color: ${props.borderRightColor || props.borderColor || "transparent"};
105
+ border-right-style: solid;
106
+ `}
107
+
108
+ border-style: ${(props) => props.borderStyle || (props.borderWidth || props.borderBottomWidth || props.borderTopWidth || props.borderLeftWidth || props.borderRightWidth ? "solid" : "none")};
109
+ border-radius: ${(props) => typeof props.borderRadius === "number" ? `${props.borderRadius}px` : props.borderRadius || 0};
110
+ height: ${(props) => typeof props.height === "number" ? `${props.height}px` : props.height || "auto"};
111
+ width: ${(props) => typeof props.width === "number" ? `${props.width}px` : props.width || "auto"};
112
+ min-width: ${(props) => typeof props.minWidth === "number" ? `${props.minWidth}px` : props.minWidth || "auto"};
113
+ min-height: ${(props) => typeof props.minHeight === "number" ? `${props.minHeight}px` : props.minHeight || "auto"};
114
+ max-width: ${(props) => typeof props.maxWidth === "number" ? `${props.maxWidth}px` : props.maxWidth || "none"};
115
+ max-height: ${(props) => typeof props.maxHeight === "number" ? `${props.maxHeight}px` : props.maxHeight || "none"};
116
+
117
+ padding: ${(props) => typeof props.padding === "number" ? `${props.padding}px` : props.padding || 0};
118
+ ${(props) => props.paddingHorizontal && `
119
+ padding-left: ${typeof props.paddingHorizontal === "number" ? `${props.paddingHorizontal}px` : props.paddingHorizontal};
120
+ padding-right: ${typeof props.paddingHorizontal === "number" ? `${props.paddingHorizontal}px` : props.paddingHorizontal};
121
+ `}
122
+ ${(props) => props.paddingVertical && `
123
+ padding-top: ${typeof props.paddingVertical === "number" ? `${props.paddingVertical}px` : props.paddingVertical};
124
+ padding-bottom: ${typeof props.paddingVertical === "number" ? `${props.paddingVertical}px` : props.paddingVertical};
125
+ `}
126
+ ${(props) => props.paddingTop !== void 0 && `padding-top: ${typeof props.paddingTop === "number" ? `${props.paddingTop}px` : props.paddingTop};`}
127
+ ${(props) => props.paddingBottom !== void 0 && `padding-bottom: ${typeof props.paddingBottom === "number" ? `${props.paddingBottom}px` : props.paddingBottom};`}
128
+ ${(props) => props.paddingLeft !== void 0 && `padding-left: ${typeof props.paddingLeft === "number" ? `${props.paddingLeft}px` : props.paddingLeft};`}
129
+ ${(props) => props.paddingRight !== void 0 && `padding-right: ${typeof props.paddingRight === "number" ? `${props.paddingRight}px` : props.paddingRight};`}
130
+
131
+ margin: ${(props) => typeof props.margin === "number" ? `${props.margin}px` : props.margin || 0};
132
+ ${(props) => props.marginTop !== void 0 && `margin-top: ${typeof props.marginTop === "number" ? `${props.marginTop}px` : props.marginTop};`}
133
+ ${(props) => props.marginBottom !== void 0 && `margin-bottom: ${typeof props.marginBottom === "number" ? `${props.marginBottom}px` : props.marginBottom};`}
134
+ ${(props) => props.marginLeft !== void 0 && `margin-left: ${typeof props.marginLeft === "number" ? `${props.marginLeft}px` : props.marginLeft};`}
135
+ ${(props) => props.marginRight !== void 0 && `margin-right: ${typeof props.marginRight === "number" ? `${props.marginRight}px` : props.marginRight};`}
136
+
137
+ flex-direction: ${(props) => props.flexDirection || "column"};
138
+ flex-wrap: ${(props) => props.flexWrap || "nowrap"};
139
+ align-items: ${(props) => props.alignItems || "stretch"};
140
+ justify-content: ${(props) => props.justifyContent || "flex-start"};
141
+ cursor: ${(props) => props.cursor ? props.cursor : props.onClick || props.onPress ? "pointer" : "inherit"};
142
+ position: ${(props) => props.position || "static"};
143
+ top: ${(props) => typeof props.top === "number" ? `${props.top}px` : props.top};
144
+ bottom: ${(props) => typeof props.bottom === "number" ? `${props.bottom}px` : props.bottom};
145
+ left: ${(props) => typeof props.left === "number" ? `${props.left}px` : props.left};
146
+ right: ${(props) => typeof props.right === "number" ? `${props.right}px` : props.right};
147
+ flex: ${(props) => props.flex};
148
+ flex-shrink: ${(props) => props.flexShrink ?? 1};
149
+ gap: ${(props) => typeof props.gap === "number" ? `${props.gap}px` : props.gap || 0};
150
+ align-self: ${(props) => props.alignSelf || "auto"};
151
+ overflow: ${(props) => props.overflow || "visible"};
152
+ overflow-x: ${(props) => props.overflowX || "visible"};
153
+ overflow-y: ${(props) => props.overflowY || "visible"};
154
+ z-index: ${(props) => props.zIndex};
155
+ opacity: ${(props) => props.disabled ? 0.5 : 1};
156
+ pointer-events: ${(props) => props.disabled ? "none" : "auto"};
157
+
158
+ &:hover {
159
+ ${(props) => props.hoverStyle?.backgroundColor && `background-color: ${props.hoverStyle.backgroundColor};`}
160
+ ${(props) => props.hoverStyle?.borderColor && `border-color: ${props.hoverStyle.borderColor};`}
161
+ }
162
+
163
+ &:active {
164
+ ${(props) => props.pressStyle?.backgroundColor && `background-color: ${props.pressStyle.backgroundColor};`}
165
+ }
166
+ `;
167
+ var Box = React2.forwardRef(
168
+ ({
169
+ children,
170
+ onPress,
171
+ onKeyDown,
172
+ onKeyUp,
173
+ role,
174
+ "aria-label": ariaLabel,
175
+ "aria-labelledby": ariaLabelledBy,
176
+ "aria-current": ariaCurrent,
177
+ "aria-disabled": ariaDisabled,
178
+ "aria-live": ariaLive,
179
+ "aria-busy": ariaBusy,
180
+ "aria-describedby": ariaDescribedBy,
181
+ "aria-expanded": ariaExpanded,
182
+ "aria-haspopup": ariaHasPopup,
183
+ "aria-pressed": ariaPressed,
184
+ "aria-controls": ariaControls,
185
+ tabIndex,
186
+ as,
187
+ src,
188
+ alt,
189
+ type,
190
+ disabled,
191
+ id,
192
+ testID,
193
+ "data-testid": dataTestId,
194
+ ...props
195
+ }, ref) => {
196
+ if (as === "img" && src) {
197
+ return /* @__PURE__ */ jsx(
198
+ "img",
199
+ {
200
+ src,
201
+ alt: alt || "",
202
+ style: {
203
+ display: "block",
204
+ objectFit: "cover",
205
+ width: typeof props.width === "number" ? `${props.width}px` : props.width,
206
+ height: typeof props.height === "number" ? `${props.height}px` : props.height,
207
+ borderRadius: typeof props.borderRadius === "number" ? `${props.borderRadius}px` : props.borderRadius,
208
+ position: props.position,
209
+ top: typeof props.top === "number" ? `${props.top}px` : props.top,
210
+ left: typeof props.left === "number" ? `${props.left}px` : props.left,
211
+ right: typeof props.right === "number" ? `${props.right}px` : props.right,
212
+ bottom: typeof props.bottom === "number" ? `${props.bottom}px` : props.bottom
213
+ }
214
+ }
215
+ );
216
+ }
217
+ return /* @__PURE__ */ jsx(
218
+ StyledBox,
219
+ {
220
+ ref,
221
+ elementType: as,
222
+ id,
223
+ type: as === "button" ? type || "button" : void 0,
224
+ disabled: as === "button" ? disabled : void 0,
225
+ onClick: onPress,
226
+ onKeyDown,
227
+ onKeyUp,
228
+ role,
229
+ "aria-label": ariaLabel,
230
+ "aria-labelledby": ariaLabelledBy,
231
+ "aria-current": ariaCurrent,
232
+ "aria-disabled": ariaDisabled,
233
+ "aria-busy": ariaBusy,
234
+ "aria-describedby": ariaDescribedBy,
235
+ "aria-expanded": ariaExpanded,
236
+ "aria-haspopup": ariaHasPopup,
237
+ "aria-pressed": ariaPressed,
238
+ "aria-controls": ariaControls,
239
+ "aria-live": ariaLive,
240
+ tabIndex: tabIndex !== void 0 ? tabIndex : void 0,
241
+ "data-testid": dataTestId || testID,
242
+ ...props,
243
+ children
244
+ }
245
+ );
246
+ }
247
+ );
248
+ Box.displayName = "Box";
249
+
250
+ // src/Drawer.tsx
251
+ import { useResolvedTheme } from "@xsolla/xui-core";
252
+
253
+ // src/DrawerRoot.web.tsx
254
+ import { memo, useEffect, useState } from "react";
255
+ import ReactDOM from "react-dom";
256
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
257
+ var DrawerRoot = memo(
258
+ ({
259
+ children,
260
+ onBackdropClick,
261
+ scrimColor,
262
+ outerPadding,
263
+ animationDuration,
264
+ zIndex,
265
+ open,
266
+ onExited
267
+ }) => {
268
+ const [visible, setVisible] = useState(false);
269
+ useEffect(() => {
270
+ if (!open) return;
271
+ const raf = requestAnimationFrame(() => setVisible(true));
272
+ return () => cancelAnimationFrame(raf);
273
+ }, [open]);
274
+ useEffect(() => {
275
+ if (!open) {
276
+ setVisible(false);
277
+ const timer = setTimeout(onExited, animationDuration);
278
+ return () => clearTimeout(timer);
279
+ }
280
+ }, [open, animationDuration, onExited]);
281
+ useEffect(() => {
282
+ const original = document.body.style.overflow;
283
+ document.body.style.overflow = "hidden";
284
+ return () => {
285
+ document.body.style.overflow = original;
286
+ };
287
+ }, []);
288
+ if (typeof document === "undefined") return null;
289
+ return ReactDOM.createPortal(
290
+ /* @__PURE__ */ jsxs(
291
+ "div",
292
+ {
293
+ style: {
294
+ position: "fixed",
295
+ top: 0,
296
+ left: 0,
297
+ right: 0,
298
+ bottom: 0,
299
+ zIndex,
300
+ padding: outerPadding,
301
+ display: "flex",
302
+ alignItems: "stretch",
303
+ justifyContent: "flex-end"
304
+ },
305
+ children: [
306
+ /* @__PURE__ */ jsx2(
307
+ "div",
308
+ {
309
+ style: {
310
+ position: "absolute",
311
+ top: 0,
312
+ left: 0,
313
+ right: 0,
314
+ bottom: 0,
315
+ background: scrimColor,
316
+ opacity: visible ? 1 : 0,
317
+ cursor: onBackdropClick ? "pointer" : "default",
318
+ transition: `opacity ${animationDuration}ms ease`
319
+ },
320
+ onClick: onBackdropClick,
321
+ "aria-hidden": "true"
322
+ }
323
+ ),
324
+ /* @__PURE__ */ jsx2(
325
+ "div",
326
+ {
327
+ style: {
328
+ position: "relative",
329
+ zIndex: 1,
330
+ height: "100%",
331
+ display: "flex",
332
+ alignItems: "stretch",
333
+ transform: visible ? "translateX(0)" : "translateX(100%)",
334
+ transition: `transform ${animationDuration}ms ease`
335
+ },
336
+ children
337
+ }
338
+ )
339
+ ]
340
+ }
341
+ ),
342
+ document.body
343
+ );
344
+ }
345
+ );
346
+ DrawerRoot.displayName = "DrawerRoot";
347
+
348
+ // src/DrawerHeader.tsx
349
+ import { memo as memo2 } from "react";
350
+ import { IconButton } from "@xsolla/xui-button";
351
+ import { ArrowLeft, Remove } from "@xsolla/xui-icons-base";
352
+ import { Typography } from "@xsolla/xui-typography";
353
+ import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
354
+ var DrawerHeader = memo2(
355
+ ({
356
+ title,
357
+ onBack,
358
+ onClose,
359
+ headerAction,
360
+ paddingX,
361
+ paddingY,
362
+ gap
363
+ }) => {
364
+ return /* @__PURE__ */ jsxs2(
365
+ "div",
366
+ {
367
+ style: {
368
+ flexShrink: 0,
369
+ height: 80,
370
+ width: "100%",
371
+ display: "flex",
372
+ flexDirection: "row",
373
+ alignItems: "center",
374
+ paddingLeft: paddingX,
375
+ paddingRight: paddingX,
376
+ paddingTop: paddingY,
377
+ paddingBottom: paddingY,
378
+ gap,
379
+ boxSizing: "border-box"
380
+ },
381
+ children: [
382
+ /* @__PURE__ */ jsxs2(
383
+ "div",
384
+ {
385
+ style: {
386
+ flex: 1,
387
+ minWidth: 0,
388
+ display: "flex",
389
+ flexDirection: "row",
390
+ alignItems: "center",
391
+ gap: 16
392
+ },
393
+ children: [
394
+ onBack && /* @__PURE__ */ jsx3(
395
+ IconButton,
396
+ {
397
+ variant: "secondary",
398
+ tone: "mono",
399
+ size: "xs",
400
+ icon: /* @__PURE__ */ jsx3(ArrowLeft, {}),
401
+ onPress: onBack,
402
+ "aria-label": "Go back"
403
+ }
404
+ ),
405
+ title && /* @__PURE__ */ jsx3("div", { style: { flex: 1, minWidth: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx3(Typography, { variant: "bodyLgAccent", noWrap: true, children: title }) })
406
+ ]
407
+ }
408
+ ),
409
+ headerAction && /* @__PURE__ */ jsx3("div", { style: { flexShrink: 0 }, children: headerAction }),
410
+ onClose && /* @__PURE__ */ jsx3(
411
+ IconButton,
412
+ {
413
+ variant: "secondary",
414
+ tone: "mono",
415
+ size: "xs",
416
+ icon: /* @__PURE__ */ jsx3(Remove, {}),
417
+ onPress: onClose,
418
+ "aria-label": "Close drawer"
419
+ }
420
+ )
421
+ ]
422
+ }
423
+ );
424
+ }
425
+ );
426
+ DrawerHeader.displayName = "DrawerHeader";
427
+
428
+ // src/DrawerFooter.tsx
429
+ import React3, { memo as memo3 } from "react";
430
+ import { jsx as jsx4 } from "react/jsx-runtime";
431
+ var flattenChildren = (children) => {
432
+ const result = [];
433
+ React3.Children.forEach(children, (child) => {
434
+ if (React3.isValidElement(child) && child.type === React3.Fragment) {
435
+ result.push(
436
+ ...flattenChildren(
437
+ child.props.children
438
+ )
439
+ );
440
+ } else if (child !== null && child !== void 0) {
441
+ result.push(child);
442
+ }
443
+ });
444
+ return result;
445
+ };
446
+ var DrawerFooter = memo3(
447
+ ({ children, align, shadow, fullWidth }) => {
448
+ const justifyContent = align === "center" ? "center" : "flex-end";
449
+ const renderedChildren = fullWidth ? flattenChildren(children).map(
450
+ (child, i) => React3.isValidElement(child) ? React3.cloneElement(
451
+ child,
452
+ {
453
+ key: child.key ?? i,
454
+ fullWidth: true
455
+ }
456
+ ) : child
457
+ ) : children;
458
+ return /* @__PURE__ */ jsx4(
459
+ "div",
460
+ {
461
+ style: {
462
+ flexShrink: 0,
463
+ width: "100%",
464
+ boxShadow: shadow ? "0px 2px 25px 0px rgba(7, 7, 8, 0.15)" : "none"
465
+ },
466
+ children: /* @__PURE__ */ jsx4(
467
+ "div",
468
+ {
469
+ style: {
470
+ display: "flex",
471
+ flexDirection: "row",
472
+ justifyContent: fullWidth ? "stretch" : justifyContent,
473
+ padding: 16,
474
+ gap: 8
475
+ },
476
+ children: renderedChildren
477
+ }
478
+ )
479
+ }
480
+ );
481
+ }
482
+ );
483
+ DrawerFooter.displayName = "DrawerFooter";
484
+
485
+ // src/Drawer.tsx
486
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
487
+ var FOCUSABLE_SELECTORS = 'button:not([disabled]), [href], input:not([disabled]):not([type="hidden"]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
488
+ var isElementVisible = (el) => {
489
+ if (el.offsetParent === null && getComputedStyle(el).position !== "fixed")
490
+ return false;
491
+ const style = getComputedStyle(el);
492
+ return style.visibility !== "hidden" && style.display !== "none";
493
+ };
494
+ var getFocusableElements = (container) => Array.from(
495
+ container.querySelectorAll(FOCUSABLE_SELECTORS)
496
+ ).filter(isElementVisible);
497
+ var DRAWER_WIDTHS = {
498
+ sm: 480,
499
+ md: 620,
500
+ lg: 1056
501
+ };
502
+ var Drawer = forwardRef(
503
+ ({
504
+ open: openProp,
505
+ isOpen,
506
+ onClose,
507
+ size = "md",
508
+ title: titleProp,
509
+ header: headerProp,
510
+ onBack: onBackProp,
511
+ headerAction,
512
+ closeOnOverlayClick = true,
513
+ closeOnEscape = true,
514
+ footer: footerProp,
515
+ bottom,
516
+ footerAlign = "right",
517
+ footerShadow = false,
518
+ footerFullWidth = true,
519
+ stepper,
520
+ children,
521
+ initialFocusRef,
522
+ themeMode,
523
+ themeProductContext
524
+ }, ref) => {
525
+ const open = openProp ?? isOpen ?? false;
526
+ const title = titleProp ?? headerProp?.title;
527
+ const onBack = onBackProp ?? headerProp?.onBack;
528
+ const footer = footerProp ?? bottom;
529
+ const { theme } = useResolvedTheme({ themeMode, themeProductContext });
530
+ const sizing = theme.sizing.drawer();
531
+ const [mounted, setMounted] = useState2(open);
532
+ useEffect2(() => {
533
+ if (open) setMounted(true);
534
+ }, [open]);
535
+ const drawerRef = useRef(null);
536
+ const closeButtonRef = useRef(null);
537
+ const previousActiveElement = useRef(null);
538
+ useEffect2(() => {
539
+ if (!open) return;
540
+ if (typeof document === "undefined") return;
541
+ previousActiveElement.current = document.activeElement;
542
+ const focusTarget = initialFocusRef?.current || closeButtonRef.current || drawerRef.current && getFocusableElements(drawerRef.current)[0];
543
+ if (focusTarget) {
544
+ focusTarget.focus();
545
+ } else {
546
+ drawerRef.current?.focus();
547
+ }
548
+ }, [open, initialFocusRef]);
549
+ useEffect2(() => {
550
+ if (!open || !closeOnEscape || !onClose) return;
551
+ if (typeof document === "undefined") return;
552
+ const handleKeyDown2 = (event) => {
553
+ if (event.key === "Escape") onClose();
554
+ };
555
+ document.addEventListener("keydown", handleKeyDown2);
556
+ return () => document.removeEventListener("keydown", handleKeyDown2);
557
+ }, [open, closeOnEscape, onClose]);
558
+ const handleKeyDown = useCallback((event) => {
559
+ if (event.key !== "Tab" || !drawerRef.current) return;
560
+ if (typeof document === "undefined") return;
561
+ const focusableElements = getFocusableElements(drawerRef.current);
562
+ const firstElement = focusableElements[0];
563
+ const lastElement = focusableElements[focusableElements.length - 1];
564
+ if (!firstElement) {
565
+ event.preventDefault();
566
+ return;
567
+ }
568
+ if (event.shiftKey && document.activeElement === firstElement) {
569
+ event.preventDefault();
570
+ lastElement.focus();
571
+ } else if (!event.shiftKey && document.activeElement === lastElement) {
572
+ event.preventDefault();
573
+ firstElement.focus();
574
+ }
575
+ }, []);
576
+ if (!mounted) return null;
577
+ const contentWidth = DRAWER_WIDTHS[size];
578
+ return /* @__PURE__ */ jsx5(
579
+ DrawerRoot,
580
+ {
581
+ open,
582
+ onExited: () => {
583
+ setMounted(false);
584
+ previousActiveElement.current?.focus();
585
+ },
586
+ onBackdropClick: closeOnOverlayClick ? onClose : void 0,
587
+ scrimColor: sizing.scrimColor,
588
+ outerPadding: sizing.outerPadding,
589
+ animationDuration: sizing.animationDuration,
590
+ zIndex: sizing.zIndex,
591
+ children: /* @__PURE__ */ jsxs3(
592
+ "div",
593
+ {
594
+ style: {
595
+ height: "100%",
596
+ display: "flex",
597
+ flexDirection: "row",
598
+ alignItems: "stretch",
599
+ backgroundColor: theme.colors.background.primary,
600
+ borderRadius: sizing.containerRadius,
601
+ overflow: "hidden",
602
+ gap: stepper ? sizing.stepperContentGap : 0
603
+ },
604
+ children: [
605
+ stepper && /* @__PURE__ */ jsx5(
606
+ "div",
607
+ {
608
+ style: {
609
+ flexShrink: 0,
610
+ alignSelf: "stretch",
611
+ backgroundColor: theme.colors.background.secondary,
612
+ borderRadius: sizing.contentRadius,
613
+ padding: sizing.stepperPadding,
614
+ display: "flex",
615
+ flexDirection: "column"
616
+ },
617
+ children: stepper
618
+ }
619
+ ),
620
+ /* @__PURE__ */ jsxs3(
621
+ Box,
622
+ {
623
+ ref: (node) => {
624
+ drawerRef.current = node;
625
+ if (typeof ref === "function") ref(node);
626
+ else if (ref)
627
+ ref.current = node;
628
+ },
629
+ role: "dialog",
630
+ "aria-modal": "true",
631
+ "aria-label": typeof title === "string" ? title : void 0,
632
+ tabIndex: -1,
633
+ onKeyDown: handleKeyDown,
634
+ style: {
635
+ width: contentWidth,
636
+ height: "100%",
637
+ flexShrink: 0,
638
+ display: "flex",
639
+ flexDirection: "column",
640
+ outline: "none",
641
+ color: theme.colors.content.primary
642
+ },
643
+ children: [
644
+ /* @__PURE__ */ jsx5(
645
+ DrawerHeader,
646
+ {
647
+ title,
648
+ onBack,
649
+ onClose,
650
+ headerAction,
651
+ paddingX: sizing.headerPaddingX,
652
+ paddingY: sizing.headerPaddingY,
653
+ gap: sizing.headerGap
654
+ }
655
+ ),
656
+ /* @__PURE__ */ jsx5(
657
+ Box,
658
+ {
659
+ style: {
660
+ flex: 1,
661
+ minHeight: 0,
662
+ overflowY: "auto",
663
+ paddingLeft: sizing.contentPaddingX,
664
+ paddingRight: sizing.contentPaddingX
665
+ },
666
+ children
667
+ }
668
+ ),
669
+ footer ? /* @__PURE__ */ jsx5(
670
+ DrawerFooter,
671
+ {
672
+ align: footerAlign,
673
+ shadow: footerShadow,
674
+ fullWidth: footerFullWidth,
675
+ children: footer
676
+ }
677
+ ) : /* @__PURE__ */ jsx5("div", { style: { flexShrink: 0, height: 32 } })
678
+ ]
679
+ }
680
+ )
681
+ ]
682
+ }
683
+ )
684
+ }
685
+ );
686
+ }
687
+ );
688
+ Drawer.displayName = "Drawer";
689
+
690
+ // src/useDrawer.ts
691
+ import { useCallback as useCallback2, useState as useState3 } from "react";
692
+ function useDrawer(options) {
693
+ const [isOpen, setIsOpen] = useState3(false);
694
+ const open = useCallback2(() => {
695
+ setIsOpen(true);
696
+ options?.onOpen?.();
697
+ }, [options]);
698
+ const close = useCallback2(() => {
699
+ setIsOpen(false);
700
+ options?.onClose?.();
701
+ }, [options]);
702
+ return { isOpen, open, close };
703
+ }
704
+ export {
705
+ Drawer,
706
+ useDrawer
707
+ };
708
+ //# sourceMappingURL=index.mjs.map