@xsolla/xui-context-menu 0.64.0-pr81.1768677662

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,1924 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.tsx
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ContextMenu: () => ContextMenu,
34
+ ContextMenuCheckboxItem: () => ContextMenuCheckboxItem,
35
+ ContextMenuGroup: () => ContextMenuGroup,
36
+ ContextMenuItem: () => ContextMenuItem,
37
+ ContextMenuRadioGroup: () => ContextMenuRadioGroup,
38
+ ContextMenuRadioItem: () => ContextMenuRadioItem,
39
+ ContextMenuSearch: () => ContextMenuSearch,
40
+ ContextMenuSeparator: () => ContextMenuSeparator,
41
+ useContextMenu: () => useContextMenu,
42
+ useContextMenuPosition: () => useContextMenuPosition,
43
+ useContextMenuRequired: () => useContextMenuRequired,
44
+ useKeyboardNavigation: () => useKeyboardNavigation,
45
+ useRadioGroup: () => useRadioGroup
46
+ });
47
+ module.exports = __toCommonJS(index_exports);
48
+
49
+ // src/ContextMenu.tsx
50
+ var import_react11 = __toESM(require("react"));
51
+
52
+ // ../primitives-native/src/Box.tsx
53
+ var import_react_native = require("react-native");
54
+ var import_jsx_runtime = require("react/jsx-runtime");
55
+ var Box = ({
56
+ children,
57
+ onPress,
58
+ onLayout,
59
+ onMoveShouldSetResponder,
60
+ onResponderGrant,
61
+ onResponderMove,
62
+ onResponderRelease,
63
+ onResponderTerminate,
64
+ backgroundColor,
65
+ borderColor,
66
+ borderWidth,
67
+ borderBottomWidth,
68
+ borderBottomColor,
69
+ borderTopWidth,
70
+ borderTopColor,
71
+ borderLeftWidth,
72
+ borderLeftColor,
73
+ borderRightWidth,
74
+ borderRightColor,
75
+ borderRadius,
76
+ borderStyle,
77
+ height,
78
+ padding,
79
+ paddingHorizontal,
80
+ paddingVertical,
81
+ margin,
82
+ marginTop,
83
+ marginBottom,
84
+ marginLeft,
85
+ marginRight,
86
+ flexDirection,
87
+ alignItems,
88
+ justifyContent,
89
+ position,
90
+ top,
91
+ bottom,
92
+ left,
93
+ right,
94
+ width,
95
+ flex,
96
+ overflow,
97
+ zIndex,
98
+ hoverStyle,
99
+ pressStyle,
100
+ style,
101
+ "data-testid": dataTestId,
102
+ testID,
103
+ as,
104
+ src,
105
+ alt,
106
+ ...rest
107
+ }) => {
108
+ const getContainerStyle = (pressed) => ({
109
+ backgroundColor: pressed && pressStyle?.backgroundColor ? pressStyle.backgroundColor : backgroundColor,
110
+ borderColor,
111
+ borderWidth,
112
+ borderBottomWidth,
113
+ borderBottomColor,
114
+ borderTopWidth,
115
+ borderTopColor,
116
+ borderLeftWidth,
117
+ borderLeftColor,
118
+ borderRightWidth,
119
+ borderRightColor,
120
+ borderRadius,
121
+ borderStyle,
122
+ overflow,
123
+ zIndex,
124
+ height,
125
+ width,
126
+ padding,
127
+ paddingHorizontal,
128
+ paddingVertical,
129
+ margin,
130
+ marginTop,
131
+ marginBottom,
132
+ marginLeft,
133
+ marginRight,
134
+ flexDirection,
135
+ alignItems,
136
+ justifyContent,
137
+ position,
138
+ top,
139
+ bottom,
140
+ left,
141
+ right,
142
+ flex,
143
+ ...style
144
+ });
145
+ const finalTestID = dataTestId || testID;
146
+ const {
147
+ role,
148
+ tabIndex,
149
+ onKeyDown,
150
+ onKeyUp,
151
+ "aria-label": _ariaLabel,
152
+ "aria-labelledby": _ariaLabelledBy,
153
+ "aria-current": _ariaCurrent,
154
+ "aria-disabled": _ariaDisabled,
155
+ "aria-live": _ariaLive,
156
+ className,
157
+ "data-testid": _dataTestId,
158
+ ...nativeRest
159
+ } = rest;
160
+ if (as === "img" && src) {
161
+ const imageStyle = {
162
+ width,
163
+ height,
164
+ borderRadius,
165
+ position,
166
+ top,
167
+ bottom,
168
+ left,
169
+ right,
170
+ ...style
171
+ };
172
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
173
+ import_react_native.Image,
174
+ {
175
+ source: { uri: src },
176
+ style: imageStyle,
177
+ testID: finalTestID,
178
+ resizeMode: "cover",
179
+ ...nativeRest
180
+ }
181
+ );
182
+ }
183
+ if (onPress) {
184
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
185
+ import_react_native.Pressable,
186
+ {
187
+ onPress,
188
+ onLayout,
189
+ onMoveShouldSetResponder,
190
+ onResponderGrant,
191
+ onResponderMove,
192
+ onResponderRelease,
193
+ onResponderTerminate,
194
+ style: ({ pressed }) => getContainerStyle(pressed),
195
+ testID: finalTestID,
196
+ ...nativeRest,
197
+ children
198
+ }
199
+ );
200
+ }
201
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
202
+ import_react_native.View,
203
+ {
204
+ style: getContainerStyle(),
205
+ testID: finalTestID,
206
+ onLayout,
207
+ onMoveShouldSetResponder,
208
+ onResponderGrant,
209
+ onResponderMove,
210
+ onResponderRelease,
211
+ onResponderTerminate,
212
+ ...nativeRest,
213
+ children
214
+ }
215
+ );
216
+ };
217
+
218
+ // ../primitives-native/src/Text.tsx
219
+ var import_react_native2 = require("react-native");
220
+ var import_jsx_runtime2 = require("react/jsx-runtime");
221
+ var roleMap = {
222
+ alert: "alert",
223
+ heading: "header",
224
+ button: "button",
225
+ link: "link",
226
+ text: "text"
227
+ };
228
+ var Text = ({
229
+ children,
230
+ color,
231
+ fontSize,
232
+ fontWeight,
233
+ fontFamily,
234
+ id,
235
+ role,
236
+ ...props
237
+ }) => {
238
+ let resolvedFontFamily = fontFamily ? fontFamily.split(",")[0].replace(/['"]/g, "").trim() : void 0;
239
+ if (resolvedFontFamily === "Pilat Wide Bold") {
240
+ resolvedFontFamily = void 0;
241
+ }
242
+ const style = {
243
+ color,
244
+ fontSize: typeof fontSize === "number" ? fontSize : void 0,
245
+ fontWeight,
246
+ fontFamily: resolvedFontFamily,
247
+ textDecorationLine: props.textDecoration
248
+ };
249
+ const accessibilityRole = role ? roleMap[role] : void 0;
250
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native2.Text, { style, testID: id, accessibilityRole, children });
251
+ };
252
+
253
+ // ../primitives-native/src/Spinner.tsx
254
+ var import_react_native3 = require("react-native");
255
+ var import_jsx_runtime3 = require("react/jsx-runtime");
256
+ var Spinner = ({
257
+ color,
258
+ size,
259
+ role,
260
+ "aria-label": ariaLabel,
261
+ "aria-live": ariaLive,
262
+ "aria-describedby": ariaDescribedBy,
263
+ testID
264
+ }) => {
265
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
266
+ import_react_native3.View,
267
+ {
268
+ accessible: true,
269
+ accessibilityRole: role === "status" ? "none" : void 0,
270
+ accessibilityLabel: ariaLabel,
271
+ accessibilityLiveRegion: ariaLive === "polite" ? "polite" : ariaLive === "assertive" ? "assertive" : "none",
272
+ testID,
273
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
274
+ import_react_native3.ActivityIndicator,
275
+ {
276
+ color,
277
+ size: typeof size === "number" ? size : "small"
278
+ }
279
+ )
280
+ }
281
+ );
282
+ };
283
+ Spinner.displayName = "Spinner";
284
+
285
+ // ../primitives-native/src/Icon.tsx
286
+ var import_react = __toESM(require("react"));
287
+ var import_react_native4 = require("react-native");
288
+ var import_jsx_runtime4 = require("react/jsx-runtime");
289
+ var Icon = ({ children, color, size }) => {
290
+ const style = {
291
+ width: typeof size === "number" ? size : void 0,
292
+ height: typeof size === "number" ? size : void 0,
293
+ alignItems: "center",
294
+ justifyContent: "center"
295
+ };
296
+ const childrenWithProps = import_react.default.Children.map(children, (child) => {
297
+ if (import_react.default.isValidElement(child)) {
298
+ return import_react.default.cloneElement(child, {
299
+ color: child.props.color || color,
300
+ // Also pass size if child seems to be an icon that needs it
301
+ size: child.props.size || size
302
+ });
303
+ }
304
+ return child;
305
+ });
306
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_react_native4.View, { style, children: childrenWithProps });
307
+ };
308
+
309
+ // ../primitives-native/src/Divider.tsx
310
+ var import_react_native5 = require("react-native");
311
+ var import_jsx_runtime5 = require("react/jsx-runtime");
312
+
313
+ // ../primitives-native/src/Input.tsx
314
+ var import_react2 = require("react");
315
+ var import_react_native6 = require("react-native");
316
+ var import_jsx_runtime6 = require("react/jsx-runtime");
317
+ var keyboardTypeMap = {
318
+ text: "default",
319
+ number: "numeric",
320
+ email: "email-address",
321
+ tel: "phone-pad",
322
+ url: "url",
323
+ decimal: "decimal-pad"
324
+ };
325
+ var inputModeToKeyboardType = {
326
+ none: "default",
327
+ text: "default",
328
+ decimal: "decimal-pad",
329
+ numeric: "number-pad",
330
+ tel: "phone-pad",
331
+ search: "default",
332
+ email: "email-address",
333
+ url: "url"
334
+ };
335
+ var autoCompleteToTextContentType = {
336
+ "one-time-code": "oneTimeCode",
337
+ email: "emailAddress",
338
+ username: "username",
339
+ password: "password",
340
+ "new-password": "newPassword",
341
+ tel: "telephoneNumber",
342
+ "postal-code": "postalCode",
343
+ name: "name"
344
+ };
345
+ var InputPrimitive = (0, import_react2.forwardRef)(
346
+ ({
347
+ value,
348
+ placeholder,
349
+ onChange,
350
+ onChangeText,
351
+ onFocus,
352
+ onBlur,
353
+ onKeyDown,
354
+ disabled,
355
+ secureTextEntry,
356
+ style,
357
+ color,
358
+ fontSize,
359
+ placeholderTextColor,
360
+ maxLength,
361
+ name,
362
+ type,
363
+ inputMode,
364
+ autoComplete,
365
+ id,
366
+ "aria-invalid": ariaInvalid,
367
+ "aria-describedby": ariaDescribedBy,
368
+ "aria-labelledby": ariaLabelledBy,
369
+ "aria-label": ariaLabel,
370
+ "aria-disabled": ariaDisabled,
371
+ "data-testid": dataTestId
372
+ }, ref) => {
373
+ const handleChangeText = (text) => {
374
+ onChangeText?.(text);
375
+ if (onChange) {
376
+ const syntheticEvent = {
377
+ target: { value: text },
378
+ currentTarget: { value: text },
379
+ type: "change",
380
+ nativeEvent: { text },
381
+ preventDefault: () => {
382
+ },
383
+ stopPropagation: () => {
384
+ },
385
+ isTrusted: false
386
+ };
387
+ onChange(syntheticEvent);
388
+ }
389
+ };
390
+ const keyboardType = inputMode ? inputModeToKeyboardType[inputMode] || "default" : type ? keyboardTypeMap[type] || "default" : "default";
391
+ const textContentType = autoComplete ? autoCompleteToTextContentType[autoComplete] : void 0;
392
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
393
+ import_react_native6.TextInput,
394
+ {
395
+ ref,
396
+ value,
397
+ placeholder,
398
+ onChangeText: handleChangeText,
399
+ onFocus,
400
+ onBlur,
401
+ onKeyPress: (e) => {
402
+ if (onKeyDown) {
403
+ onKeyDown({
404
+ key: e.nativeEvent.key,
405
+ preventDefault: () => {
406
+ }
407
+ });
408
+ }
409
+ },
410
+ editable: !disabled,
411
+ secureTextEntry: secureTextEntry || type === "password",
412
+ keyboardType,
413
+ textContentType,
414
+ style: [
415
+ {
416
+ color,
417
+ fontSize: typeof fontSize === "number" ? fontSize : void 0,
418
+ flex: 1,
419
+ padding: 0,
420
+ textAlign: style?.textAlign || "left"
421
+ },
422
+ style
423
+ ],
424
+ placeholderTextColor,
425
+ maxLength,
426
+ testID: dataTestId || id,
427
+ accessibilityLabel: ariaLabel,
428
+ accessibilityHint: ariaDescribedBy,
429
+ accessibilityState: {
430
+ disabled: disabled || ariaDisabled
431
+ },
432
+ accessible: true
433
+ }
434
+ );
435
+ }
436
+ );
437
+ InputPrimitive.displayName = "InputPrimitive";
438
+
439
+ // ../primitives-native/src/TextArea.tsx
440
+ var import_react3 = require("react");
441
+ var import_react_native7 = require("react-native");
442
+ var import_jsx_runtime7 = require("react/jsx-runtime");
443
+ var TextAreaPrimitive = (0, import_react3.forwardRef)(
444
+ ({
445
+ value,
446
+ placeholder,
447
+ onChange,
448
+ onChangeText,
449
+ onFocus,
450
+ onBlur,
451
+ onKeyDown,
452
+ disabled,
453
+ style,
454
+ color,
455
+ fontSize,
456
+ placeholderTextColor,
457
+ maxLength,
458
+ rows,
459
+ id,
460
+ "aria-invalid": ariaInvalid,
461
+ "aria-describedby": ariaDescribedBy,
462
+ "aria-labelledby": ariaLabelledBy,
463
+ "aria-label": ariaLabel,
464
+ "aria-disabled": ariaDisabled,
465
+ "data-testid": dataTestId
466
+ }, ref) => {
467
+ const handleChangeText = (text) => {
468
+ onChangeText?.(text);
469
+ if (onChange) {
470
+ const syntheticEvent = {
471
+ target: { value: text },
472
+ currentTarget: { value: text },
473
+ type: "change",
474
+ nativeEvent: { text },
475
+ preventDefault: () => {
476
+ },
477
+ stopPropagation: () => {
478
+ },
479
+ isTrusted: false
480
+ };
481
+ onChange(syntheticEvent);
482
+ }
483
+ };
484
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
485
+ import_react_native7.TextInput,
486
+ {
487
+ ref,
488
+ value,
489
+ placeholder,
490
+ onChangeText: handleChangeText,
491
+ onFocus,
492
+ onBlur,
493
+ onKeyPress: (e) => {
494
+ if (onKeyDown) {
495
+ onKeyDown({
496
+ key: e.nativeEvent.key,
497
+ preventDefault: () => {
498
+ }
499
+ });
500
+ }
501
+ },
502
+ editable: !disabled,
503
+ multiline: true,
504
+ numberOfLines: rows || 4,
505
+ style: [
506
+ {
507
+ color,
508
+ fontSize: typeof fontSize === "number" ? fontSize : void 0,
509
+ flex: 1,
510
+ padding: 0,
511
+ textAlignVertical: "top",
512
+ textAlign: style?.textAlign || "left"
513
+ },
514
+ style
515
+ ],
516
+ placeholderTextColor,
517
+ maxLength,
518
+ testID: dataTestId || id,
519
+ accessibilityLabel: ariaLabel,
520
+ accessibilityHint: ariaDescribedBy,
521
+ accessibilityState: {
522
+ disabled: disabled || ariaDisabled
523
+ },
524
+ accessible: true
525
+ }
526
+ );
527
+ }
528
+ );
529
+ TextAreaPrimitive.displayName = "TextAreaPrimitive";
530
+
531
+ // src/ContextMenu.tsx
532
+ var import_xui_core7 = require("@xsolla/xui-core");
533
+ var import_xui_spinner = require("@xsolla/xui-spinner");
534
+
535
+ // src/ContextMenuContext.tsx
536
+ var import_react4 = require("react");
537
+ var ContextMenuContext = (0, import_react4.createContext)(void 0);
538
+ var useContextMenu = () => {
539
+ const context = (0, import_react4.useContext)(ContextMenuContext);
540
+ return context;
541
+ };
542
+ var useContextMenuRequired = () => {
543
+ const context = (0, import_react4.useContext)(ContextMenuContext);
544
+ if (!context) {
545
+ throw new Error(
546
+ "useContextMenuRequired must be used within a ContextMenu component"
547
+ );
548
+ }
549
+ return context;
550
+ };
551
+
552
+ // src/ContextMenuItem.tsx
553
+ var import_react5 = require("react");
554
+ var import_xui_core = require("@xsolla/xui-core");
555
+ var import_xui_icons = require("@xsolla/xui-icons");
556
+ var import_jsx_runtime8 = require("react/jsx-runtime");
557
+ var ContextMenuItem = (0, import_react5.forwardRef)(
558
+ ({
559
+ children,
560
+ description,
561
+ icon,
562
+ trailing,
563
+ shortcut,
564
+ selected,
565
+ disabled,
566
+ active,
567
+ size: propSize,
568
+ hasSubmenu,
569
+ onPress,
570
+ "data-testid": testId = "context-menu-item"
571
+ }, ref) => {
572
+ const { theme } = (0, import_xui_core.useDesignSystem)();
573
+ const context = useContextMenu();
574
+ const size = propSize || context?.size || "m";
575
+ const sizeStyles = theme.sizing.contextMenu(size);
576
+ const itemRef = (0, import_react5.useRef)(null);
577
+ const brandColors = theme.colors.control.brand.primary;
578
+ const contentColors = theme.colors.content;
579
+ (0, import_react5.useEffect)(() => {
580
+ if (context && !disabled) {
581
+ const id = typeof children === "string" ? children : String(Math.random());
582
+ context.registerItem(id);
583
+ return () => context.unregisterItem(id);
584
+ }
585
+ }, [context, disabled, children]);
586
+ const handlePress = () => {
587
+ if (disabled) return;
588
+ onPress?.();
589
+ if (context) {
590
+ context.onItemSelect({
591
+ id: typeof children === "string" ? children : "",
592
+ label: typeof children === "string" ? children : "",
593
+ variant: "default",
594
+ selected
595
+ });
596
+ }
597
+ };
598
+ const handleKeyDown = (event) => {
599
+ if (disabled) return;
600
+ if (event.key === "Enter" || event.key === " ") {
601
+ event.preventDefault();
602
+ handlePress();
603
+ }
604
+ };
605
+ const getBackgroundColor = () => {
606
+ if (selected) {
607
+ return brandColors.bg;
608
+ }
609
+ if (active) {
610
+ return theme.colors.control.input.bgHover;
611
+ }
612
+ return "transparent";
613
+ };
614
+ const getTextColor = () => {
615
+ if (disabled) {
616
+ return theme.colors.control.input.textDisable;
617
+ }
618
+ if (selected) {
619
+ return contentColors.on.brand;
620
+ }
621
+ return theme.colors.content.primary;
622
+ };
623
+ const getIconColor = () => {
624
+ if (disabled) {
625
+ return theme.colors.content.tertiary;
626
+ }
627
+ if (selected) {
628
+ return contentColors.on.brand;
629
+ }
630
+ return theme.colors.content.secondary;
631
+ };
632
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
633
+ Box,
634
+ {
635
+ ref: ref || itemRef,
636
+ role: "menuitem",
637
+ "aria-disabled": disabled || void 0,
638
+ "aria-selected": selected || void 0,
639
+ tabIndex: disabled ? -1 : 0,
640
+ flexDirection: "row",
641
+ alignItems: description ? "flex-start" : "center",
642
+ gap: sizeStyles.gap,
643
+ paddingHorizontal: sizeStyles.itemPaddingHorizontal,
644
+ paddingVertical: sizeStyles.itemPaddingVertical,
645
+ backgroundColor: getBackgroundColor(),
646
+ hoverStyle: !disabled && !selected ? {
647
+ backgroundColor: theme.colors.control.input.bgHover
648
+ } : void 0,
649
+ pressStyle: !disabled ? {
650
+ backgroundColor: selected ? brandColors.bgPress : theme.colors.control.input.bgDisable
651
+ } : void 0,
652
+ onPress: handlePress,
653
+ onKeyDown: handleKeyDown,
654
+ style: {
655
+ cursor: disabled ? "not-allowed" : "pointer",
656
+ opacity: disabled ? 0.5 : 1,
657
+ outline: "none"
658
+ },
659
+ "data-testid": testId,
660
+ children: [
661
+ icon && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
662
+ Box,
663
+ {
664
+ width: sizeStyles.iconSize,
665
+ marginTop: description ? 2 : 0,
666
+ alignItems: "center",
667
+ justifyContent: "center",
668
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Icon, { size: sizeStyles.iconSize, color: getIconColor(), children: icon })
669
+ }
670
+ ),
671
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(Box, { flex: 1, flexDirection: "column", gap: 2, children: [
672
+ /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
673
+ Text,
674
+ {
675
+ color: getTextColor(),
676
+ fontSize: sizeStyles.fontSize,
677
+ fontWeight: "400",
678
+ lineHeight: sizeStyles.fontSize + 2,
679
+ children
680
+ }
681
+ ),
682
+ description && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
683
+ Text,
684
+ {
685
+ color: selected ? contentColors.on.brand : theme.colors.content.tertiary,
686
+ fontSize: sizeStyles.descriptionFontSize,
687
+ lineHeight: sizeStyles.descriptionFontSize + 2,
688
+ children: description
689
+ }
690
+ )
691
+ ] }),
692
+ shortcut && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
693
+ Text,
694
+ {
695
+ color: selected ? contentColors.on.brand : theme.colors.content.tertiary,
696
+ fontSize: sizeStyles.descriptionFontSize,
697
+ children: shortcut
698
+ }
699
+ ),
700
+ trailing,
701
+ hasSubmenu && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
702
+ Icon,
703
+ {
704
+ size: sizeStyles.iconSize - 4,
705
+ color: selected ? contentColors.on.brand : theme.colors.content.secondary,
706
+ children: /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_xui_icons.ArrowRight, {})
707
+ }
708
+ )
709
+ ]
710
+ }
711
+ );
712
+ }
713
+ );
714
+ ContextMenuItem.displayName = "ContextMenuItem";
715
+
716
+ // src/ContextMenuCheckboxItem.tsx
717
+ var import_react6 = require("react");
718
+ var import_xui_core2 = require("@xsolla/xui-core");
719
+ var import_xui_icons2 = require("@xsolla/xui-icons");
720
+ var import_jsx_runtime9 = require("react/jsx-runtime");
721
+ var checkboxSizeMap = {
722
+ s: 14,
723
+ m: 16,
724
+ l: 18,
725
+ xl: 20
726
+ };
727
+ var checkIconSizeMap = {
728
+ s: 10,
729
+ m: 12,
730
+ l: 14,
731
+ xl: 16
732
+ };
733
+ var CheckboxIndicator = ({
734
+ checked,
735
+ indeterminate,
736
+ size,
737
+ disabled
738
+ }) => {
739
+ const { theme } = (0, import_xui_core2.useDesignSystem)();
740
+ const brandColors = theme.colors.control.brand.primary;
741
+ const faintColors = theme.colors.control.faint;
742
+ const contentColors = theme.colors.content;
743
+ const boxSize = checkboxSizeMap[size];
744
+ const iconSize = checkIconSizeMap[size];
745
+ const isActive = checked || indeterminate;
746
+ const getBgColor = () => {
747
+ if (disabled) {
748
+ return brandColors.bgDisable;
749
+ }
750
+ if (isActive) {
751
+ return brandColors.bg;
752
+ }
753
+ return faintColors.bg;
754
+ };
755
+ const getBorderColor = () => {
756
+ if (isActive && !disabled) {
757
+ return brandColors.bg;
758
+ }
759
+ return faintColors.border;
760
+ };
761
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
762
+ Box,
763
+ {
764
+ width: boxSize,
765
+ height: boxSize,
766
+ borderRadius: 4,
767
+ borderWidth: isActive ? 0 : 1,
768
+ borderColor: getBorderColor(),
769
+ backgroundColor: getBgColor(),
770
+ alignItems: "center",
771
+ justifyContent: "center",
772
+ children: indeterminate ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
773
+ Icon,
774
+ {
775
+ size: iconSize,
776
+ color: disabled ? contentColors.tertiary : contentColors.on.brand,
777
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_xui_icons2.Minus, {})
778
+ }
779
+ ) : checked ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
780
+ Icon,
781
+ {
782
+ size: iconSize,
783
+ color: disabled ? contentColors.tertiary : contentColors.on.brand,
784
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_xui_icons2.Check, {})
785
+ }
786
+ ) : null
787
+ }
788
+ );
789
+ };
790
+ var ContextMenuCheckboxItem = (0, import_react6.forwardRef)(
791
+ ({
792
+ children,
793
+ description,
794
+ leadingContent,
795
+ trailing,
796
+ checked = false,
797
+ indeterminate = false,
798
+ disabled,
799
+ size: propSize,
800
+ onCheckedChange,
801
+ onPress,
802
+ "data-testid": testId = "context-menu-checkbox-item"
803
+ }, ref) => {
804
+ const { theme } = (0, import_xui_core2.useDesignSystem)();
805
+ const context = useContextMenu();
806
+ const size = propSize || context?.size || "m";
807
+ const sizeStyles = theme.sizing.contextMenu(size);
808
+ const itemRef = (0, import_react6.useRef)(null);
809
+ const contentColors = theme.colors.content;
810
+ (0, import_react6.useEffect)(() => {
811
+ if (context && !disabled) {
812
+ const id = typeof children === "string" ? children : String(Math.random());
813
+ context.registerItem(id);
814
+ return () => context.unregisterItem(id);
815
+ }
816
+ }, [context, disabled, children]);
817
+ const handlePress = () => {
818
+ if (disabled) return;
819
+ const newChecked = !checked;
820
+ onCheckedChange?.(newChecked);
821
+ onPress?.();
822
+ if (context) {
823
+ context.onItemSelect({
824
+ id: typeof children === "string" ? children : "",
825
+ label: typeof children === "string" ? children : "",
826
+ variant: "checkbox",
827
+ checked: newChecked
828
+ });
829
+ }
830
+ };
831
+ const handleKeyDown = (event) => {
832
+ if (disabled) return;
833
+ if (event.key === "Enter" || event.key === " ") {
834
+ event.preventDefault();
835
+ handlePress();
836
+ }
837
+ };
838
+ const getTextColor = () => {
839
+ if (disabled) {
840
+ return theme.colors.control.input.textDisable;
841
+ }
842
+ return theme.colors.control.input.text;
843
+ };
844
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
845
+ Box,
846
+ {
847
+ ref: ref || itemRef,
848
+ role: "menuitemcheckbox",
849
+ "aria-checked": indeterminate ? "mixed" : checked,
850
+ "aria-disabled": disabled || void 0,
851
+ tabIndex: disabled ? -1 : 0,
852
+ flexDirection: "row",
853
+ alignItems: description ? "flex-start" : "center",
854
+ gap: sizeStyles.gap,
855
+ paddingHorizontal: sizeStyles.itemPaddingHorizontal,
856
+ paddingVertical: sizeStyles.itemPaddingVertical,
857
+ backgroundColor: "transparent",
858
+ hoverStyle: !disabled ? {
859
+ backgroundColor: theme.colors.control.input.bgHover
860
+ } : void 0,
861
+ pressStyle: !disabled ? {
862
+ backgroundColor: theme.colors.control.input.bgDisable
863
+ } : void 0,
864
+ onPress: handlePress,
865
+ onKeyDown: handleKeyDown,
866
+ style: {
867
+ cursor: disabled ? "not-allowed" : "pointer",
868
+ opacity: disabled ? 0.5 : 1,
869
+ outline: "none"
870
+ },
871
+ "data-testid": testId,
872
+ children: [
873
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
874
+ Box,
875
+ {
876
+ marginTop: description ? 2 : 0,
877
+ alignItems: "center",
878
+ justifyContent: "center",
879
+ children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
880
+ CheckboxIndicator,
881
+ {
882
+ checked,
883
+ indeterminate,
884
+ size,
885
+ disabled
886
+ }
887
+ )
888
+ }
889
+ ),
890
+ leadingContent && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Box, { padding: 5, alignItems: "center", justifyContent: "center", children: leadingContent }),
891
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Box, { flex: 1, flexDirection: "column", gap: 2, children: [
892
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
893
+ Text,
894
+ {
895
+ color: getTextColor(),
896
+ fontSize: sizeStyles.fontSize,
897
+ fontWeight: "400",
898
+ lineHeight: sizeStyles.fontSize + 2,
899
+ children
900
+ }
901
+ ),
902
+ description && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
903
+ Text,
904
+ {
905
+ color: theme.colors.content.tertiary,
906
+ fontSize: sizeStyles.descriptionFontSize,
907
+ lineHeight: sizeStyles.descriptionFontSize + 2,
908
+ children: description
909
+ }
910
+ )
911
+ ] }),
912
+ trailing
913
+ ]
914
+ }
915
+ );
916
+ }
917
+ );
918
+ ContextMenuCheckboxItem.displayName = "ContextMenuCheckboxItem";
919
+
920
+ // src/ContextMenuRadioGroup.tsx
921
+ var import_react7 = require("react");
922
+ var import_jsx_runtime10 = require("react/jsx-runtime");
923
+ var RadioGroupContext = (0, import_react7.createContext)(null);
924
+ var useRadioGroup = () => (0, import_react7.useContext)(RadioGroupContext);
925
+ var ContextMenuRadioGroup = (0, import_react7.forwardRef)(
926
+ ({
927
+ children,
928
+ value,
929
+ onValueChange,
930
+ "data-testid": testId = "context-menu-radio-group"
931
+ }, ref) => {
932
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(RadioGroupContext.Provider, { value: { value, onValueChange }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Box, { ref, role: "group", flexDirection: "column", "data-testid": testId, children }) });
933
+ }
934
+ );
935
+ ContextMenuRadioGroup.displayName = "ContextMenuRadioGroup";
936
+
937
+ // src/ContextMenuRadioItem.tsx
938
+ var import_react8 = require("react");
939
+ var import_xui_core3 = require("@xsolla/xui-core");
940
+ var import_jsx_runtime11 = require("react/jsx-runtime");
941
+ var radioSizeMap = {
942
+ s: 14,
943
+ m: 16,
944
+ l: 18,
945
+ xl: 20
946
+ };
947
+ var radioDotSizeMap = {
948
+ s: 6,
949
+ m: 8,
950
+ l: 8,
951
+ xl: 10
952
+ };
953
+ var RadioIndicator = ({
954
+ checked,
955
+ size,
956
+ disabled
957
+ }) => {
958
+ const { theme } = (0, import_xui_core3.useDesignSystem)();
959
+ const brandColors = theme.colors.control.brand.primary;
960
+ const faintColors = theme.colors.control.faint;
961
+ const contentColors = theme.colors.content;
962
+ const outerSize = radioSizeMap[size];
963
+ const dotSize = radioDotSizeMap[size];
964
+ const getBgColor = () => {
965
+ if (disabled) {
966
+ return brandColors.bgDisable;
967
+ }
968
+ if (checked) {
969
+ return brandColors.bg;
970
+ }
971
+ return faintColors.bg;
972
+ };
973
+ const getBorderColor = () => {
974
+ if (checked && !disabled) {
975
+ return brandColors.bg;
976
+ }
977
+ return faintColors.border;
978
+ };
979
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
980
+ Box,
981
+ {
982
+ width: outerSize,
983
+ height: outerSize,
984
+ borderRadius: outerSize / 2,
985
+ borderWidth: checked ? 0 : 1,
986
+ borderColor: getBorderColor(),
987
+ backgroundColor: getBgColor(),
988
+ alignItems: "center",
989
+ justifyContent: "center",
990
+ children: checked && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
991
+ Box,
992
+ {
993
+ width: dotSize,
994
+ height: dotSize,
995
+ borderRadius: dotSize / 2,
996
+ backgroundColor: disabled ? contentColors.tertiary : contentColors.on.brand
997
+ }
998
+ )
999
+ }
1000
+ );
1001
+ };
1002
+ var ContextMenuRadioItem = (0, import_react8.forwardRef)(
1003
+ ({
1004
+ children,
1005
+ description,
1006
+ value,
1007
+ disabled,
1008
+ size: propSize,
1009
+ onPress,
1010
+ "data-testid": testId = "context-menu-radio-item"
1011
+ }, ref) => {
1012
+ const { theme } = (0, import_xui_core3.useDesignSystem)();
1013
+ const context = useContextMenu();
1014
+ const radioGroup = useRadioGroup();
1015
+ const size = propSize || context?.size || "m";
1016
+ const sizeStyles = theme.sizing.contextMenu(size);
1017
+ const itemRef = (0, import_react8.useRef)(null);
1018
+ const checked = radioGroup?.value === value;
1019
+ (0, import_react8.useEffect)(() => {
1020
+ if (context && !disabled) {
1021
+ const id = typeof children === "string" ? children : String(Math.random());
1022
+ context.registerItem(id);
1023
+ return () => context.unregisterItem(id);
1024
+ }
1025
+ }, [context, disabled, children]);
1026
+ const handlePress = () => {
1027
+ if (disabled) return;
1028
+ radioGroup?.onValueChange(value);
1029
+ onPress?.();
1030
+ if (context) {
1031
+ context.onItemSelect({
1032
+ id: typeof children === "string" ? children : "",
1033
+ label: typeof children === "string" ? children : "",
1034
+ variant: "radio",
1035
+ checked: true
1036
+ });
1037
+ }
1038
+ };
1039
+ const handleKeyDown = (event) => {
1040
+ if (disabled) return;
1041
+ if (event.key === "Enter" || event.key === " ") {
1042
+ event.preventDefault();
1043
+ handlePress();
1044
+ }
1045
+ };
1046
+ const getTextColor = () => {
1047
+ if (disabled) {
1048
+ return theme.colors.control.input.textDisable;
1049
+ }
1050
+ return theme.colors.control.input.text;
1051
+ };
1052
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
1053
+ Box,
1054
+ {
1055
+ ref: ref || itemRef,
1056
+ role: "menuitemradio",
1057
+ "aria-checked": checked,
1058
+ "aria-disabled": disabled || void 0,
1059
+ tabIndex: disabled ? -1 : 0,
1060
+ flexDirection: "row",
1061
+ alignItems: description ? "flex-start" : "center",
1062
+ gap: sizeStyles.gap,
1063
+ paddingHorizontal: sizeStyles.itemPaddingHorizontal,
1064
+ paddingVertical: sizeStyles.itemPaddingVertical,
1065
+ backgroundColor: "transparent",
1066
+ hoverStyle: !disabled ? {
1067
+ backgroundColor: theme.colors.control.input.bgHover
1068
+ } : void 0,
1069
+ pressStyle: !disabled ? {
1070
+ backgroundColor: theme.colors.control.input.bgDisable
1071
+ } : void 0,
1072
+ onPress: handlePress,
1073
+ onKeyDown: handleKeyDown,
1074
+ style: {
1075
+ cursor: disabled ? "not-allowed" : "pointer",
1076
+ opacity: disabled ? 0.5 : 1,
1077
+ outline: "none"
1078
+ },
1079
+ "data-testid": testId,
1080
+ children: [
1081
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1082
+ Box,
1083
+ {
1084
+ marginTop: description ? 2 : 0,
1085
+ alignItems: "center",
1086
+ justifyContent: "center",
1087
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RadioIndicator, { checked, size, disabled })
1088
+ }
1089
+ ),
1090
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box, { flex: 1, flexDirection: "column", gap: 2, children: [
1091
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1092
+ Text,
1093
+ {
1094
+ color: getTextColor(),
1095
+ fontSize: sizeStyles.fontSize,
1096
+ fontWeight: "400",
1097
+ lineHeight: sizeStyles.fontSize + 2,
1098
+ children
1099
+ }
1100
+ ),
1101
+ description && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1102
+ Text,
1103
+ {
1104
+ color: theme.colors.content.tertiary,
1105
+ fontSize: sizeStyles.descriptionFontSize,
1106
+ lineHeight: sizeStyles.descriptionFontSize + 2,
1107
+ children: description
1108
+ }
1109
+ )
1110
+ ] })
1111
+ ]
1112
+ }
1113
+ );
1114
+ }
1115
+ );
1116
+ ContextMenuRadioItem.displayName = "ContextMenuRadioItem";
1117
+
1118
+ // src/ContextMenuGroup.tsx
1119
+ var import_react9 = require("react");
1120
+ var import_xui_core4 = require("@xsolla/xui-core");
1121
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1122
+ var ContextMenuGroup = (0, import_react9.forwardRef)(
1123
+ ({
1124
+ label,
1125
+ description,
1126
+ children,
1127
+ size: propSize,
1128
+ "data-testid": testId = "context-menu-group"
1129
+ }, ref) => {
1130
+ const { theme } = (0, import_xui_core4.useDesignSystem)();
1131
+ const context = useContextMenu();
1132
+ const size = propSize || context?.size || "m";
1133
+ const sizeStyles = theme.sizing.contextMenu(size);
1134
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(Box, { ref, role: "group", "aria-label": label, "data-testid": testId, children: [
1135
+ label && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
1136
+ Box,
1137
+ {
1138
+ paddingHorizontal: sizeStyles.itemPaddingHorizontal,
1139
+ paddingVertical: sizeStyles.itemPaddingVertical,
1140
+ children: [
1141
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1142
+ Text,
1143
+ {
1144
+ color: theme.colors.content.secondary,
1145
+ fontSize: sizeStyles.descriptionFontSize,
1146
+ fontWeight: "600",
1147
+ style: { textTransform: "uppercase", letterSpacing: 0.5 },
1148
+ children: label
1149
+ }
1150
+ ),
1151
+ description && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1152
+ Text,
1153
+ {
1154
+ color: theme.colors.content.tertiary,
1155
+ fontSize: sizeStyles.descriptionFontSize - 2,
1156
+ marginTop: 2,
1157
+ children: description
1158
+ }
1159
+ )
1160
+ ]
1161
+ }
1162
+ ),
1163
+ children
1164
+ ] });
1165
+ }
1166
+ );
1167
+ ContextMenuGroup.displayName = "ContextMenuGroup";
1168
+
1169
+ // src/ContextMenuSeparator.tsx
1170
+ var import_xui_core5 = require("@xsolla/xui-core");
1171
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1172
+ var ContextMenuSeparator = ({
1173
+ size: propSize,
1174
+ "data-testid": testId = "context-menu-separator"
1175
+ }) => {
1176
+ const { theme } = (0, import_xui_core5.useDesignSystem)();
1177
+ const context = useContextMenu();
1178
+ const size = propSize || context?.size || "m";
1179
+ const sizeStyles = theme.sizing.contextMenu(size);
1180
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1181
+ Box,
1182
+ {
1183
+ role: "separator",
1184
+ marginVertical: sizeStyles.paddingVertical,
1185
+ marginHorizontal: sizeStyles.itemPaddingHorizontal,
1186
+ height: 1,
1187
+ backgroundColor: theme.colors.border.secondary,
1188
+ "data-testid": testId
1189
+ }
1190
+ );
1191
+ };
1192
+ ContextMenuSeparator.displayName = "ContextMenuSeparator";
1193
+
1194
+ // src/ContextMenuSearch.tsx
1195
+ var import_react10 = __toESM(require("react"));
1196
+ var import_xui_core6 = require("@xsolla/xui-core");
1197
+
1198
+ // ../icons-base/dist/web/index.mjs
1199
+ var import_styled_components = __toESM(require("styled-components"), 1);
1200
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1201
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1202
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1203
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1204
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1205
+ var import_jsx_runtime19 = require("react/jsx-runtime");
1206
+ var import_jsx_runtime20 = require("react/jsx-runtime");
1207
+ var import_jsx_runtime21 = require("react/jsx-runtime");
1208
+ var import_jsx_runtime22 = require("react/jsx-runtime");
1209
+ var import_jsx_runtime23 = require("react/jsx-runtime");
1210
+ var import_jsx_runtime24 = require("react/jsx-runtime");
1211
+ var import_jsx_runtime25 = require("react/jsx-runtime");
1212
+ var import_jsx_runtime26 = require("react/jsx-runtime");
1213
+ var import_jsx_runtime27 = require("react/jsx-runtime");
1214
+ var import_jsx_runtime28 = require("react/jsx-runtime");
1215
+ var import_jsx_runtime29 = require("react/jsx-runtime");
1216
+ var import_jsx_runtime30 = require("react/jsx-runtime");
1217
+ var import_jsx_runtime31 = require("react/jsx-runtime");
1218
+ var import_jsx_runtime32 = require("react/jsx-runtime");
1219
+ var import_jsx_runtime33 = require("react/jsx-runtime");
1220
+ var import_jsx_runtime34 = require("react/jsx-runtime");
1221
+ var import_jsx_runtime35 = require("react/jsx-runtime");
1222
+ var import_jsx_runtime36 = require("react/jsx-runtime");
1223
+ var import_jsx_runtime37 = require("react/jsx-runtime");
1224
+ var import_jsx_runtime38 = require("react/jsx-runtime");
1225
+ var import_jsx_runtime39 = require("react/jsx-runtime");
1226
+ var import_jsx_runtime40 = require("react/jsx-runtime");
1227
+ var import_jsx_runtime41 = require("react/jsx-runtime");
1228
+ var import_jsx_runtime42 = require("react/jsx-runtime");
1229
+ var import_jsx_runtime43 = require("react/jsx-runtime");
1230
+ var import_jsx_runtime44 = require("react/jsx-runtime");
1231
+ var import_jsx_runtime45 = require("react/jsx-runtime");
1232
+ var import_jsx_runtime46 = require("react/jsx-runtime");
1233
+ var import_jsx_runtime47 = require("react/jsx-runtime");
1234
+ var import_jsx_runtime48 = require("react/jsx-runtime");
1235
+ var import_jsx_runtime49 = require("react/jsx-runtime");
1236
+ var import_jsx_runtime50 = require("react/jsx-runtime");
1237
+ var import_jsx_runtime51 = require("react/jsx-runtime");
1238
+ var import_jsx_runtime52 = require("react/jsx-runtime");
1239
+ var import_jsx_runtime53 = require("react/jsx-runtime");
1240
+ var import_jsx_runtime54 = require("react/jsx-runtime");
1241
+ var import_jsx_runtime55 = require("react/jsx-runtime");
1242
+ var import_jsx_runtime56 = require("react/jsx-runtime");
1243
+ var import_jsx_runtime57 = require("react/jsx-runtime");
1244
+ var import_jsx_runtime58 = require("react/jsx-runtime");
1245
+ var import_jsx_runtime59 = require("react/jsx-runtime");
1246
+ var import_jsx_runtime60 = require("react/jsx-runtime");
1247
+ var import_jsx_runtime61 = require("react/jsx-runtime");
1248
+ var import_jsx_runtime62 = require("react/jsx-runtime");
1249
+ var import_jsx_runtime63 = require("react/jsx-runtime");
1250
+ var import_jsx_runtime64 = require("react/jsx-runtime");
1251
+ var import_jsx_runtime65 = require("react/jsx-runtime");
1252
+ var import_jsx_runtime66 = require("react/jsx-runtime");
1253
+ var import_jsx_runtime67 = require("react/jsx-runtime");
1254
+ var import_jsx_runtime68 = require("react/jsx-runtime");
1255
+ var import_jsx_runtime69 = require("react/jsx-runtime");
1256
+ var import_jsx_runtime70 = require("react/jsx-runtime");
1257
+ var import_jsx_runtime71 = require("react/jsx-runtime");
1258
+ var import_jsx_runtime72 = require("react/jsx-runtime");
1259
+ var import_jsx_runtime73 = require("react/jsx-runtime");
1260
+ var import_jsx_runtime74 = require("react/jsx-runtime");
1261
+ var import_jsx_runtime75 = require("react/jsx-runtime");
1262
+ var import_jsx_runtime76 = require("react/jsx-runtime");
1263
+ var import_jsx_runtime77 = require("react/jsx-runtime");
1264
+ var import_jsx_runtime78 = require("react/jsx-runtime");
1265
+ var import_jsx_runtime79 = require("react/jsx-runtime");
1266
+ var import_jsx_runtime80 = require("react/jsx-runtime");
1267
+ var import_jsx_runtime81 = require("react/jsx-runtime");
1268
+ var import_jsx_runtime82 = require("react/jsx-runtime");
1269
+ var import_jsx_runtime83 = require("react/jsx-runtime");
1270
+ var import_jsx_runtime84 = require("react/jsx-runtime");
1271
+ var import_jsx_runtime85 = require("react/jsx-runtime");
1272
+ var import_jsx_runtime86 = require("react/jsx-runtime");
1273
+ var import_jsx_runtime87 = require("react/jsx-runtime");
1274
+ var import_jsx_runtime88 = require("react/jsx-runtime");
1275
+ var import_jsx_runtime89 = require("react/jsx-runtime");
1276
+ var import_jsx_runtime90 = require("react/jsx-runtime");
1277
+ var import_jsx_runtime91 = require("react/jsx-runtime");
1278
+ var import_jsx_runtime92 = require("react/jsx-runtime");
1279
+ var import_jsx_runtime93 = require("react/jsx-runtime");
1280
+ var import_jsx_runtime94 = require("react/jsx-runtime");
1281
+ var import_jsx_runtime95 = require("react/jsx-runtime");
1282
+ var import_jsx_runtime96 = require("react/jsx-runtime");
1283
+ var import_jsx_runtime97 = require("react/jsx-runtime");
1284
+ var import_jsx_runtime98 = require("react/jsx-runtime");
1285
+ var import_jsx_runtime99 = require("react/jsx-runtime");
1286
+ var import_jsx_runtime100 = require("react/jsx-runtime");
1287
+ var import_jsx_runtime101 = require("react/jsx-runtime");
1288
+ var import_jsx_runtime102 = require("react/jsx-runtime");
1289
+ var import_jsx_runtime103 = require("react/jsx-runtime");
1290
+ var import_jsx_runtime104 = require("react/jsx-runtime");
1291
+ var import_jsx_runtime105 = require("react/jsx-runtime");
1292
+ var import_jsx_runtime106 = require("react/jsx-runtime");
1293
+ var import_jsx_runtime107 = require("react/jsx-runtime");
1294
+ var import_jsx_runtime108 = require("react/jsx-runtime");
1295
+ var import_jsx_runtime109 = require("react/jsx-runtime");
1296
+ var import_jsx_runtime110 = require("react/jsx-runtime");
1297
+ var import_jsx_runtime111 = require("react/jsx-runtime");
1298
+ var import_jsx_runtime112 = require("react/jsx-runtime");
1299
+ var import_jsx_runtime113 = require("react/jsx-runtime");
1300
+ var import_jsx_runtime114 = require("react/jsx-runtime");
1301
+ var import_jsx_runtime115 = require("react/jsx-runtime");
1302
+ var import_jsx_runtime116 = require("react/jsx-runtime");
1303
+ var import_jsx_runtime117 = require("react/jsx-runtime");
1304
+ var import_jsx_runtime118 = require("react/jsx-runtime");
1305
+ var import_jsx_runtime119 = require("react/jsx-runtime");
1306
+ var import_jsx_runtime120 = require("react/jsx-runtime");
1307
+ var import_jsx_runtime121 = require("react/jsx-runtime");
1308
+ var import_jsx_runtime122 = require("react/jsx-runtime");
1309
+ var import_jsx_runtime123 = require("react/jsx-runtime");
1310
+ var import_jsx_runtime124 = require("react/jsx-runtime");
1311
+ var import_jsx_runtime125 = require("react/jsx-runtime");
1312
+ var import_jsx_runtime126 = require("react/jsx-runtime");
1313
+ var import_jsx_runtime127 = require("react/jsx-runtime");
1314
+ var StyledIcon = import_styled_components.default.div`
1315
+ display: inline-flex;
1316
+ align-items: center;
1317
+ justify-content: center;
1318
+ width: ${(props) => props.$size}px;
1319
+ height: ${(props) => props.$size}px;
1320
+ color: ${(props) => props.$color};
1321
+
1322
+ svg {
1323
+ width: 100%;
1324
+ height: 100%;
1325
+ }
1326
+ `;
1327
+ var BaseIcon = ({
1328
+ variant = "line",
1329
+ size = 24,
1330
+ color = "currentColor",
1331
+ solidContent: solidContent114,
1332
+ lineContent: lineContent114,
1333
+ className,
1334
+ style,
1335
+ "data-testid": testId,
1336
+ "aria-label": ariaLabel,
1337
+ "aria-hidden": ariaHidden
1338
+ }) => {
1339
+ const svgContent = variant === "line" ? lineContent114 : solidContent114;
1340
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1341
+ StyledIcon,
1342
+ {
1343
+ $size: size,
1344
+ $color: color,
1345
+ className,
1346
+ style,
1347
+ "data-testid": testId,
1348
+ role: ariaLabel ? "img" : void 0,
1349
+ "aria-label": ariaLabel,
1350
+ "aria-hidden": ariaHidden != null ? ariaHidden : ariaLabel ? void 0 : true,
1351
+ dangerouslySetInnerHTML: { __html: svgContent }
1352
+ }
1353
+ );
1354
+ };
1355
+ var solidContent100 = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"><g id="icon_search--line"><path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M10 2C14.4183 2 18 5.58172 18 10C18 11.8484 17.3711 13.5488 16.3184 14.9033L21.957 20.543L20.543 21.957L14.9033 16.3174C13.5487 17.3703 11.8486 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2ZM10 4C6.68629 4 4 6.68629 4 10C4 13.3137 6.68629 16 10 16C13.3137 16 16 13.3137 16 10C16 6.68629 13.3137 4 10 4Z" style="fill: currentColor"/></g></svg>`;
1356
+ var lineContent100 = `<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"><g id="icon_search--line"><path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M10 2C14.4183 2 18 5.58172 18 10C18 11.8484 17.3711 13.5488 16.3184 14.9033L21.957 20.543L20.543 21.957L14.9033 16.3174C13.5487 17.3703 11.8486 18 10 18C5.58172 18 2 14.4183 2 10C2 5.58172 5.58172 2 10 2ZM10 4C6.68629 4 4 6.68629 4 10C4 13.3137 6.68629 16 10 16C13.3137 16 16 13.3137 16 10C16 6.68629 13.3137 4 10 4Z" style="fill: currentColor"/></g></svg>`;
1357
+ var Search = (props) => /* @__PURE__ */ (0, import_jsx_runtime114.jsx)(BaseIcon, { ...props, solidContent: solidContent100, lineContent: lineContent100 });
1358
+
1359
+ // src/ContextMenuSearch.tsx
1360
+ var import_xui_divider = require("@xsolla/xui-divider");
1361
+ var import_jsx_runtime128 = require("react/jsx-runtime");
1362
+ var ContextMenuSearch = (0, import_react10.forwardRef)(
1363
+ ({
1364
+ value,
1365
+ onChange,
1366
+ onValueChange,
1367
+ placeholder = "Search",
1368
+ autoFocus = true,
1369
+ size: propSize,
1370
+ "data-testid": testId = "context-menu-search"
1371
+ }, ref) => {
1372
+ const { theme } = (0, import_xui_core6.useDesignSystem)();
1373
+ const context = useContextMenu();
1374
+ const size = propSize || context?.size || "m";
1375
+ const sizeStyles = theme.sizing.contextMenu(size);
1376
+ const inputRef = (0, import_react10.useRef)(null);
1377
+ const inputColors = theme.colors.control.input;
1378
+ import_react10.default.useImperativeHandle(
1379
+ ref,
1380
+ () => inputRef.current,
1381
+ []
1382
+ );
1383
+ (0, import_react10.useEffect)(() => {
1384
+ if (autoFocus && inputRef.current) {
1385
+ setTimeout(() => {
1386
+ inputRef.current?.focus();
1387
+ }, 0);
1388
+ }
1389
+ }, [autoFocus]);
1390
+ const handleChange = (e) => {
1391
+ onChange?.(e);
1392
+ onValueChange?.(e.target.value);
1393
+ };
1394
+ const handleKeyDown = (e) => {
1395
+ e.stopPropagation();
1396
+ if (e.key === "Escape") {
1397
+ context?.closeMenu();
1398
+ }
1399
+ };
1400
+ return /* @__PURE__ */ (0, import_jsx_runtime128.jsxs)(
1401
+ Box,
1402
+ {
1403
+ flexDirection: "column",
1404
+ gap: sizeStyles.searchGap,
1405
+ paddingHorizontal: sizeStyles.searchPaddingHorizontal,
1406
+ paddingVertical: sizeStyles.searchPaddingVertical,
1407
+ "data-testid": testId,
1408
+ children: [
1409
+ /* @__PURE__ */ (0, import_jsx_runtime128.jsxs)(Box, { flexDirection: "row", alignItems: "center", gap: 8, children: [
1410
+ /* @__PURE__ */ (0, import_jsx_runtime128.jsx)(
1411
+ Icon,
1412
+ {
1413
+ size: sizeStyles.searchIconSize,
1414
+ color: inputColors.placeholder,
1415
+ children: /* @__PURE__ */ (0, import_jsx_runtime128.jsx)(Search, {})
1416
+ }
1417
+ ),
1418
+ /* @__PURE__ */ (0, import_jsx_runtime128.jsx)(Box, { flex: 1, children: /* @__PURE__ */ (0, import_jsx_runtime128.jsx)(
1419
+ InputPrimitive,
1420
+ {
1421
+ ref: inputRef,
1422
+ value,
1423
+ onChange: handleChange,
1424
+ onKeyDown: handleKeyDown,
1425
+ placeholder,
1426
+ fontSize: sizeStyles.searchFontSize,
1427
+ color: inputColors.text,
1428
+ placeholderTextColor: inputColors.placeholder,
1429
+ "aria-label": placeholder,
1430
+ "data-testid": `${testId}__input`,
1431
+ style: {
1432
+ lineHeight: `${sizeStyles.searchLineHeight}px`
1433
+ }
1434
+ }
1435
+ ) })
1436
+ ] }),
1437
+ /* @__PURE__ */ (0, import_jsx_runtime128.jsx)(import_xui_divider.Divider, {})
1438
+ ]
1439
+ }
1440
+ );
1441
+ }
1442
+ );
1443
+ ContextMenuSearch.displayName = "ContextMenuSearch";
1444
+
1445
+ // src/ContextMenu.tsx
1446
+ var import_jsx_runtime129 = require("react/jsx-runtime");
1447
+ var ContextMenuRoot = (0, import_react11.forwardRef)(
1448
+ ({
1449
+ children,
1450
+ list,
1451
+ groups,
1452
+ size = "m",
1453
+ isOpen: propIsOpen,
1454
+ onOpenChange,
1455
+ position,
1456
+ trigger,
1457
+ width,
1458
+ maxHeight = 300,
1459
+ onSelect,
1460
+ onCheckedChange,
1461
+ closeOnSelect = true,
1462
+ isLoading,
1463
+ "aria-label": ariaLabel,
1464
+ "data-testid": testId = "context-menu"
1465
+ }, ref) => {
1466
+ const { theme } = (0, import_xui_core7.useDesignSystem)();
1467
+ const [internalIsOpen, setInternalIsOpen] = (0, import_react11.useState)(false);
1468
+ const [activeIndex, setActiveIndex] = (0, import_react11.useState)(-1);
1469
+ const containerRef = (0, import_react11.useRef)(null);
1470
+ const menuRef = (0, import_react11.useRef)(null);
1471
+ const itemsRef = (0, import_react11.useRef)([]);
1472
+ const isOpen = propIsOpen !== void 0 ? propIsOpen : internalIsOpen;
1473
+ const sizeStyles = theme.sizing.contextMenu(size);
1474
+ const closeMenu = (0, import_react11.useCallback)(() => {
1475
+ if (propIsOpen === void 0) {
1476
+ setInternalIsOpen(false);
1477
+ }
1478
+ onOpenChange?.(false);
1479
+ setActiveIndex(-1);
1480
+ }, [propIsOpen, onOpenChange]);
1481
+ const toggleMenu = (0, import_react11.useCallback)(() => {
1482
+ const nextOpen = !isOpen;
1483
+ if (propIsOpen === void 0) {
1484
+ setInternalIsOpen(nextOpen);
1485
+ }
1486
+ onOpenChange?.(nextOpen);
1487
+ if (!nextOpen) {
1488
+ setActiveIndex(-1);
1489
+ }
1490
+ }, [isOpen, propIsOpen, onOpenChange]);
1491
+ (0, import_react11.useEffect)(() => {
1492
+ const handleClickOutside = (event) => {
1493
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
1494
+ closeMenu();
1495
+ }
1496
+ };
1497
+ if (isOpen) {
1498
+ document.addEventListener("mousedown", handleClickOutside);
1499
+ }
1500
+ return () => {
1501
+ document.removeEventListener("mousedown", handleClickOutside);
1502
+ };
1503
+ }, [isOpen, closeMenu]);
1504
+ (0, import_react11.useEffect)(() => {
1505
+ const handleEscape = (event) => {
1506
+ if (event.key === "Escape") {
1507
+ closeMenu();
1508
+ }
1509
+ };
1510
+ if (isOpen) {
1511
+ document.addEventListener("keydown", handleEscape);
1512
+ }
1513
+ return () => {
1514
+ document.removeEventListener("keydown", handleEscape);
1515
+ };
1516
+ }, [isOpen, closeMenu]);
1517
+ (0, import_react11.useEffect)(() => {
1518
+ if (isOpen && menuRef.current) {
1519
+ menuRef.current.focus();
1520
+ }
1521
+ }, [isOpen]);
1522
+ (0, import_react11.useEffect)(() => {
1523
+ if (!isOpen) {
1524
+ itemsRef.current = [];
1525
+ }
1526
+ }, [isOpen]);
1527
+ const registerItem = (0, import_react11.useCallback)((id) => {
1528
+ const index = itemsRef.current.indexOf(id);
1529
+ if (index === -1) {
1530
+ itemsRef.current.push(id);
1531
+ return itemsRef.current.length - 1;
1532
+ }
1533
+ return index;
1534
+ }, []);
1535
+ const unregisterItem = (0, import_react11.useCallback)((id) => {
1536
+ const index = itemsRef.current.indexOf(id);
1537
+ if (index !== -1) {
1538
+ itemsRef.current.splice(index, 1);
1539
+ }
1540
+ }, []);
1541
+ const onItemSelect = (0, import_react11.useCallback)(
1542
+ (item) => {
1543
+ onSelect?.(item);
1544
+ if (item.variant === "checkbox") {
1545
+ onCheckedChange?.(item.id, !item.checked);
1546
+ } else if (item.variant === "radio") {
1547
+ onCheckedChange?.(item.id, true);
1548
+ if (closeOnSelect) {
1549
+ closeMenu();
1550
+ }
1551
+ } else if (closeOnSelect) {
1552
+ closeMenu();
1553
+ }
1554
+ },
1555
+ [onSelect, onCheckedChange, closeOnSelect, closeMenu]
1556
+ );
1557
+ const handleKeyDown = (0, import_react11.useCallback)(
1558
+ (event) => {
1559
+ const itemCount = itemsRef.current.length;
1560
+ if (itemCount === 0) return;
1561
+ switch (event.key) {
1562
+ case "ArrowDown":
1563
+ event.preventDefault();
1564
+ setActiveIndex((prev) => prev < itemCount - 1 ? prev + 1 : 0);
1565
+ break;
1566
+ case "ArrowUp":
1567
+ event.preventDefault();
1568
+ setActiveIndex((prev) => prev > 0 ? prev - 1 : itemCount - 1);
1569
+ break;
1570
+ case "Home":
1571
+ event.preventDefault();
1572
+ setActiveIndex(0);
1573
+ break;
1574
+ case "End":
1575
+ event.preventDefault();
1576
+ setActiveIndex(itemCount - 1);
1577
+ break;
1578
+ case "Enter":
1579
+ case " ":
1580
+ event.preventDefault();
1581
+ break;
1582
+ case "Tab":
1583
+ closeMenu();
1584
+ break;
1585
+ }
1586
+ },
1587
+ [closeMenu]
1588
+ );
1589
+ const contextValue = (0, import_react11.useMemo)(
1590
+ () => ({
1591
+ size,
1592
+ closeMenu,
1593
+ onItemSelect,
1594
+ activeIndex,
1595
+ setActiveIndex,
1596
+ registerItem,
1597
+ unregisterItem
1598
+ }),
1599
+ [size, closeMenu, onItemSelect, activeIndex, registerItem, unregisterItem]
1600
+ );
1601
+ const getPositionStyles = () => {
1602
+ if (position) {
1603
+ return {
1604
+ position: "fixed",
1605
+ left: position.x,
1606
+ top: position.y
1607
+ };
1608
+ }
1609
+ return {
1610
+ position: "absolute",
1611
+ top: "100%",
1612
+ left: 0,
1613
+ marginTop: 4
1614
+ };
1615
+ };
1616
+ const renderItems = (itemsData) => {
1617
+ return itemsData.map((item, index) => {
1618
+ const commonProps = {
1619
+ key: item.id || index,
1620
+ disabled: item.disabled,
1621
+ description: item.description,
1622
+ "data-testid": `context-menu-item-${item.id || index}`
1623
+ };
1624
+ if (item.variant === "checkbox") {
1625
+ return /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
1626
+ ContextMenuCheckboxItem,
1627
+ {
1628
+ ...commonProps,
1629
+ checked: item.checked,
1630
+ onCheckedChange: (checked) => onCheckedChange?.(item.id, checked),
1631
+ onPress: item.onPress,
1632
+ children: item.label
1633
+ }
1634
+ );
1635
+ }
1636
+ if (item.variant === "radio") {
1637
+ return /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
1638
+ ContextMenuRadioItem,
1639
+ {
1640
+ ...commonProps,
1641
+ value: item.id,
1642
+ onPress: item.onPress,
1643
+ children: item.label
1644
+ }
1645
+ );
1646
+ }
1647
+ return /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
1648
+ ContextMenuItem,
1649
+ {
1650
+ ...commonProps,
1651
+ icon: item.icon,
1652
+ selected: item.selected,
1653
+ shortcut: item.trailing?.type === "shortcut" ? item.trailing.content : void 0,
1654
+ trailing: item.trailing?.type !== "shortcut" && item.trailing?.type !== "none" ? item.trailing?.content : void 0,
1655
+ hasSubmenu: item.children && item.children.length > 0,
1656
+ onPress: item.onPress,
1657
+ active: activeIndex === index,
1658
+ children: item.label
1659
+ }
1660
+ );
1661
+ });
1662
+ };
1663
+ const renderGroups = (groupsData) => {
1664
+ return groupsData.map((group, groupIndex) => /* @__PURE__ */ (0, import_jsx_runtime129.jsxs)(import_react11.default.Fragment, { children: [
1665
+ groupIndex > 0 && /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(ContextMenuSeparator, {}),
1666
+ /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
1667
+ ContextMenuGroup,
1668
+ {
1669
+ label: group.label,
1670
+ description: group.description,
1671
+ "data-testid": `context-menu-group-${group.id || groupIndex}`,
1672
+ children: renderItems(group.items)
1673
+ }
1674
+ )
1675
+ ] }, group.id || groupIndex));
1676
+ };
1677
+ const renderContent = () => {
1678
+ if (isLoading) {
1679
+ const brandColor = theme.colors.control.brand.primary.bg;
1680
+ return /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
1681
+ Box,
1682
+ {
1683
+ padding: 16,
1684
+ alignItems: "center",
1685
+ justifyContent: "center",
1686
+ minHeight: 60,
1687
+ children: /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(import_xui_spinner.Spinner, { size: "m", color: brandColor })
1688
+ }
1689
+ );
1690
+ }
1691
+ if (children) {
1692
+ return children;
1693
+ }
1694
+ if (groups && groups.length > 0) {
1695
+ return renderGroups(groups);
1696
+ }
1697
+ if (list && list.length > 0) {
1698
+ return renderItems(list);
1699
+ }
1700
+ return null;
1701
+ };
1702
+ return /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(ContextMenuContext.Provider, { value: contextValue, children: /* @__PURE__ */ (0, import_jsx_runtime129.jsxs)(
1703
+ "div",
1704
+ {
1705
+ ref: containerRef,
1706
+ style: {
1707
+ position: position ? "static" : "relative",
1708
+ width: trigger ? "fit-content" : void 0,
1709
+ display: "inline-block"
1710
+ },
1711
+ "data-testid": testId,
1712
+ children: [
1713
+ trigger && /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
1714
+ "div",
1715
+ {
1716
+ onClick: toggleMenu,
1717
+ style: { cursor: "pointer" },
1718
+ "data-testid": `${testId}-trigger`,
1719
+ children: trigger
1720
+ }
1721
+ ),
1722
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime129.jsx)(
1723
+ Box,
1724
+ {
1725
+ ref: (node) => {
1726
+ menuRef.current = node;
1727
+ if (typeof ref === "function") {
1728
+ ref(node);
1729
+ } else if (ref) {
1730
+ ref.current = node;
1731
+ }
1732
+ },
1733
+ role: "menu",
1734
+ "aria-label": ariaLabel,
1735
+ backgroundColor: theme.colors.background.secondary,
1736
+ borderColor: theme.colors.border.secondary,
1737
+ borderWidth: 1,
1738
+ borderRadius: theme.radius.button,
1739
+ paddingVertical: sizeStyles.paddingVertical,
1740
+ width,
1741
+ minWidth: sizeStyles.minWidth,
1742
+ style: {
1743
+ ...getPositionStyles(),
1744
+ zIndex: 1e3,
1745
+ boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
1746
+ maxHeight,
1747
+ overflowY: "auto",
1748
+ outline: "none"
1749
+ },
1750
+ tabIndex: -1,
1751
+ onKeyDown: handleKeyDown,
1752
+ "data-testid": `${testId}-content`,
1753
+ children: renderContent()
1754
+ }
1755
+ )
1756
+ ]
1757
+ }
1758
+ ) });
1759
+ }
1760
+ );
1761
+ ContextMenuRoot.displayName = "ContextMenu";
1762
+ var ContextMenu = Object.assign(ContextMenuRoot, {
1763
+ Item: ContextMenuItem,
1764
+ CheckboxItem: ContextMenuCheckboxItem,
1765
+ RadioGroup: ContextMenuRadioGroup,
1766
+ RadioItem: ContextMenuRadioItem,
1767
+ Group: ContextMenuGroup,
1768
+ Separator: ContextMenuSeparator,
1769
+ Search: ContextMenuSearch
1770
+ });
1771
+
1772
+ // src/hooks/useContextMenuPosition.ts
1773
+ var import_react12 = require("react");
1774
+ var useContextMenuPosition = ({
1775
+ position,
1776
+ menuRef,
1777
+ isOpen,
1778
+ offset = 8
1779
+ }) => {
1780
+ const [adjustedPosition, setAdjustedPosition] = (0, import_react12.useState)();
1781
+ (0, import_react12.useEffect)(() => {
1782
+ if (!isOpen || !position || !menuRef.current) {
1783
+ setAdjustedPosition(void 0);
1784
+ return;
1785
+ }
1786
+ const rafId = requestAnimationFrame(() => {
1787
+ const menu = menuRef.current;
1788
+ if (!menu) return;
1789
+ const rect = menu.getBoundingClientRect();
1790
+ const viewportWidth = window.innerWidth;
1791
+ const viewportHeight = window.innerHeight;
1792
+ let { x, y } = position;
1793
+ let transformOriginX = "left";
1794
+ let transformOriginY = "top";
1795
+ if (x + rect.width > viewportWidth - offset) {
1796
+ x = Math.max(offset, viewportWidth - rect.width - offset);
1797
+ transformOriginX = "right";
1798
+ }
1799
+ if (x < offset) {
1800
+ x = offset;
1801
+ transformOriginX = "left";
1802
+ }
1803
+ if (y + rect.height > viewportHeight - offset) {
1804
+ const aboveY = position.y - rect.height;
1805
+ if (aboveY >= offset) {
1806
+ y = aboveY;
1807
+ transformOriginY = "bottom";
1808
+ } else {
1809
+ y = Math.max(offset, viewportHeight - rect.height - offset);
1810
+ transformOriginY = "bottom";
1811
+ }
1812
+ }
1813
+ if (y < offset) {
1814
+ y = offset;
1815
+ transformOriginY = "top";
1816
+ }
1817
+ setAdjustedPosition({
1818
+ x,
1819
+ y,
1820
+ transformOrigin: `${transformOriginY} ${transformOriginX}`
1821
+ });
1822
+ });
1823
+ return () => cancelAnimationFrame(rafId);
1824
+ }, [isOpen, position, menuRef, offset]);
1825
+ return adjustedPosition;
1826
+ };
1827
+
1828
+ // src/hooks/useKeyboardNavigation.ts
1829
+ var import_react13 = require("react");
1830
+ var useKeyboardNavigation = ({
1831
+ isOpen,
1832
+ itemCount,
1833
+ activeIndex,
1834
+ setActiveIndex,
1835
+ onSelect,
1836
+ onClose,
1837
+ loop = true
1838
+ }) => {
1839
+ const typeaheadBuffer = (0, import_react13.useRef)("");
1840
+ const typeaheadTimeout = (0, import_react13.useRef)(null);
1841
+ (0, import_react13.useEffect)(() => {
1842
+ if (!isOpen) {
1843
+ typeaheadBuffer.current = "";
1844
+ if (typeaheadTimeout.current) {
1845
+ clearTimeout(typeaheadTimeout.current);
1846
+ }
1847
+ }
1848
+ }, [isOpen]);
1849
+ const handleKeyDown = (0, import_react13.useCallback)(
1850
+ (event) => {
1851
+ if (!isOpen || itemCount === 0) return;
1852
+ switch (event.key) {
1853
+ case "ArrowDown":
1854
+ event.preventDefault();
1855
+ if (loop) {
1856
+ setActiveIndex(activeIndex < itemCount - 1 ? activeIndex + 1 : 0);
1857
+ } else {
1858
+ setActiveIndex(Math.min(activeIndex + 1, itemCount - 1));
1859
+ }
1860
+ break;
1861
+ case "ArrowUp":
1862
+ event.preventDefault();
1863
+ if (loop) {
1864
+ setActiveIndex(activeIndex > 0 ? activeIndex - 1 : itemCount - 1);
1865
+ } else {
1866
+ setActiveIndex(Math.max(activeIndex - 1, 0));
1867
+ }
1868
+ break;
1869
+ case "Home":
1870
+ event.preventDefault();
1871
+ setActiveIndex(0);
1872
+ break;
1873
+ case "End":
1874
+ event.preventDefault();
1875
+ setActiveIndex(itemCount - 1);
1876
+ break;
1877
+ case "Enter":
1878
+ case " ":
1879
+ event.preventDefault();
1880
+ if (activeIndex >= 0 && activeIndex < itemCount) {
1881
+ onSelect(activeIndex);
1882
+ }
1883
+ break;
1884
+ case "Escape":
1885
+ event.preventDefault();
1886
+ onClose();
1887
+ break;
1888
+ case "Tab":
1889
+ onClose();
1890
+ break;
1891
+ default:
1892
+ if (event.key.length === 1 && !event.ctrlKey && !event.metaKey) {
1893
+ typeaheadBuffer.current += event.key.toLowerCase();
1894
+ if (typeaheadTimeout.current) {
1895
+ clearTimeout(typeaheadTimeout.current);
1896
+ }
1897
+ typeaheadTimeout.current = setTimeout(() => {
1898
+ typeaheadBuffer.current = "";
1899
+ }, 500);
1900
+ }
1901
+ break;
1902
+ }
1903
+ },
1904
+ [isOpen, itemCount, activeIndex, setActiveIndex, onSelect, onClose, loop]
1905
+ );
1906
+ return { handleKeyDown };
1907
+ };
1908
+ // Annotate the CommonJS export names for ESM import in node:
1909
+ 0 && (module.exports = {
1910
+ ContextMenu,
1911
+ ContextMenuCheckboxItem,
1912
+ ContextMenuGroup,
1913
+ ContextMenuItem,
1914
+ ContextMenuRadioGroup,
1915
+ ContextMenuRadioItem,
1916
+ ContextMenuSearch,
1917
+ ContextMenuSeparator,
1918
+ useContextMenu,
1919
+ useContextMenuPosition,
1920
+ useContextMenuRequired,
1921
+ useKeyboardNavigation,
1922
+ useRadioGroup
1923
+ });
1924
+ //# sourceMappingURL=index.js.map