@xsolla/xui-b2b-sidebar 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.
@@ -0,0 +1,1715 @@
1
+ // src/Sidebar.tsx
2
+ import styled2 from "styled-components";
3
+ import { useResolvedTheme as useResolvedTheme2 } from "@xsolla/xui-core";
4
+
5
+ // src/SidebarContext.tsx
6
+ import {
7
+ createContext,
8
+ useContext,
9
+ useMemo,
10
+ useState,
11
+ useCallback
12
+ } from "react";
13
+ import { jsx } from "react/jsx-runtime";
14
+ var DefaultLink = ({
15
+ to,
16
+ external,
17
+ target,
18
+ className,
19
+ children,
20
+ dataId,
21
+ onClick
22
+ }) => /* @__PURE__ */ jsx(
23
+ "a",
24
+ {
25
+ href: to,
26
+ className,
27
+ target: external ? target ?? "_blank" : target ?? void 0,
28
+ rel: external ? "noopener noreferrer" : void 0,
29
+ "data-id": dataId,
30
+ onClick,
31
+ children
32
+ }
33
+ );
34
+ var SidebarContext = createContext({
35
+ collapsed: false,
36
+ onCollapsedChange: () => {
37
+ },
38
+ pathname: "",
39
+ LinkComponent: DefaultLink,
40
+ expandedId: null,
41
+ onExpandedIdChange: () => {
42
+ }
43
+ });
44
+ var SidebarProvider = ({
45
+ collapsed: collapsedProp,
46
+ onCollapsedChange,
47
+ pathname = "",
48
+ linkComponent,
49
+ children
50
+ }) => {
51
+ const [internalCollapsed, setInternalCollapsed] = useState(false);
52
+ const [expandedId, setExpandedId] = useState(null);
53
+ const collapsed = collapsedProp ?? internalCollapsed;
54
+ const handleCollapsedChange = useCallback(
55
+ (next) => {
56
+ if (collapsedProp === void 0) setInternalCollapsed(next);
57
+ onCollapsedChange?.(next);
58
+ },
59
+ [collapsedProp, onCollapsedChange]
60
+ );
61
+ const onExpandedIdChange = useCallback((id) => {
62
+ setExpandedId(id);
63
+ }, []);
64
+ const value = useMemo(
65
+ () => ({
66
+ collapsed,
67
+ onCollapsedChange: handleCollapsedChange,
68
+ pathname,
69
+ LinkComponent: linkComponent || DefaultLink,
70
+ expandedId,
71
+ onExpandedIdChange
72
+ }),
73
+ [
74
+ collapsed,
75
+ handleCollapsedChange,
76
+ pathname,
77
+ linkComponent,
78
+ expandedId,
79
+ onExpandedIdChange
80
+ ]
81
+ );
82
+ return /* @__PURE__ */ jsx(SidebarContext.Provider, { value, children });
83
+ };
84
+ var useSidebar = () => useContext(SidebarContext);
85
+
86
+ // src/SidebarCollapsed.tsx
87
+ import {
88
+ useCallback as useCallback2,
89
+ useEffect,
90
+ useLayoutEffect,
91
+ useRef,
92
+ useState as useState2
93
+ } from "react";
94
+ import { createPortal } from "react-dom";
95
+ import styled from "styled-components";
96
+ import { useResolvedTheme } from "@xsolla/xui-core";
97
+ import { Typography } from "@xsolla/xui-typography";
98
+ import { ChatTwoMessages } from "@xsolla/xui-icons-base";
99
+
100
+ // src/HideSidebarIcon.tsx
101
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
102
+ var HideSidebarIcon = ({
103
+ flipped
104
+ }) => /* @__PURE__ */ jsxs(
105
+ "svg",
106
+ {
107
+ width: "18",
108
+ height: "18",
109
+ viewBox: "0 0 18 18",
110
+ fill: "none",
111
+ xmlns: "http://www.w3.org/2000/svg",
112
+ "aria-hidden": "true",
113
+ focusable: "false",
114
+ style: flipped ? { transform: "rotate(180deg)" } : void 0,
115
+ children: [
116
+ /* @__PURE__ */ jsx2(
117
+ "path",
118
+ {
119
+ d: "M10.1519 3.75L10.9674 4.60262L7.33825 8.39704H15.75V9.60296H7.33825L10.9674 13.3974L10.1519 14.25L5.33446 9.21318C5.22185 9.09544 5.22185 8.90456 5.33446 8.78682L10.1519 3.75Z",
120
+ fill: "currentColor"
121
+ }
122
+ ),
123
+ /* @__PURE__ */ jsx2("path", { d: "M2.25 3.75H3.75V15H2.25V3.75Z", fill: "currentColor" })
124
+ ]
125
+ }
126
+ );
127
+
128
+ // src/SidebarCollapsed.tsx
129
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
130
+ var POPOVER_GAP_PX = 12;
131
+ var POPOVER_VIEWPORT_PADDING_PX = 8;
132
+ var POPOVER_CLOSE_DELAY_MS = 150;
133
+ var POPOVER_ITEM_BASE_CLASS = "xui-sb-popover-item";
134
+ var POPOVER_ITEM_ACTIVE_CLASS = "xui-sb-popover-item--active";
135
+ var Outer = styled.div`
136
+ display: flex;
137
+ width: ${(p) => p.$width}px;
138
+ height: 100%;
139
+ max-height: 100%;
140
+ box-sizing: border-box;
141
+ flex-direction: column;
142
+ flex-shrink: 0;
143
+ overflow: hidden;
144
+ background: ${(p) => p.$bg};
145
+ border-radius: ${(p) => p.$radius}px;
146
+
147
+ a {
148
+ text-decoration: none;
149
+ }
150
+ `;
151
+ var MainScroll = styled.div`
152
+ display: flex;
153
+ flex: 1;
154
+ flex-direction: column;
155
+ align-items: center;
156
+ padding: ${(p) => p.$padding}px 0;
157
+ min-height: 0;
158
+ overflow-y: auto;
159
+
160
+ &::-webkit-scrollbar {
161
+ width: 0;
162
+ }
163
+ `;
164
+ var IconBtn = styled.button`
165
+ display: flex;
166
+ width: ${(p) => p.$size}px;
167
+ height: ${(p) => p.$size}px;
168
+ align-items: center;
169
+ justify-content: center;
170
+ border: 0;
171
+ border-radius: ${(p) => p.$radius}px;
172
+ background: ${(p) => p.$active ? p.$hoverBg : "transparent"};
173
+ color: ${(p) => p.$active ? p.$hoverColor : p.$color};
174
+ cursor: pointer;
175
+ padding: 0;
176
+ font: inherit;
177
+ transition:
178
+ background-color 0.15s ease-in-out,
179
+ color 0.15s ease-in-out;
180
+
181
+ ${(p) => p.$active && `
182
+ background-color: ${p.$activeBg};
183
+ outline: 1px solid ${p.$activeOutline};
184
+ outline-offset: -1px;
185
+ `}
186
+
187
+ &:hover {
188
+ background-color: ${(p) => p.$hoverBg};
189
+ color: ${(p) => p.$hoverColor};
190
+ }
191
+
192
+ &:focus-visible {
193
+ outline: ${(p) => p.$focusOutlineWidth}px solid ${(p) => p.$focusOutline};
194
+ outline-offset: -${(p) => p.$focusOutlineWidth}px;
195
+ }
196
+
197
+ & > span {
198
+ display: flex;
199
+ width: ${(p) => p.$iconSize}px;
200
+ height: ${(p) => p.$iconSize}px;
201
+ align-items: center;
202
+ justify-content: center;
203
+
204
+ svg {
205
+ width: ${(p) => p.$iconSize}px;
206
+ height: ${(p) => p.$iconSize}px;
207
+ }
208
+ }
209
+ `;
210
+ var Spacer = styled.div`
211
+ height: 16px;
212
+ flex-shrink: 0;
213
+ `;
214
+ var FixedBottom = styled.div`
215
+ display: flex;
216
+ flex-direction: column;
217
+ align-items: center;
218
+ padding: ${(p) => p.$padding}px 0;
219
+ flex-shrink: 0;
220
+ `;
221
+ var Footer = styled.div`
222
+ display: flex;
223
+ flex-direction: column;
224
+ align-items: center;
225
+ gap: 4px;
226
+ padding: ${(p) => p.$padding}px 0;
227
+ border-top: 1px solid ${(p) => p.$borderColor};
228
+ flex-shrink: 0;
229
+ `;
230
+ var CollapsedChat = styled.button`
231
+ display: flex;
232
+ width: ${(p) => p.$size}px;
233
+ height: ${(p) => p.$size}px;
234
+ align-items: center;
235
+ justify-content: center;
236
+ border: 1px solid ${(p) => p.$border};
237
+ border-radius: ${(p) => p.$radius}px;
238
+ background: ${(p) => p.$bg};
239
+ color: ${(p) => p.$color};
240
+ cursor: pointer;
241
+ position: relative;
242
+ padding: 0;
243
+ font: inherit;
244
+
245
+ &:hover {
246
+ opacity: 0.9;
247
+ }
248
+
249
+ &:focus-visible {
250
+ outline: ${(p) => p.$focusOutlineWidth}px solid ${(p) => p.$focusOutline};
251
+ outline-offset: 2px;
252
+ }
253
+
254
+ svg {
255
+ width: 16px;
256
+ height: 16px;
257
+ }
258
+ `;
259
+ var CollapsedToggle = styled.button`
260
+ display: flex;
261
+ width: ${(p) => p.$size}px;
262
+ height: ${(p) => p.$size}px;
263
+ align-items: center;
264
+ justify-content: center;
265
+ border: 1px solid ${(p) => p.$borderColor};
266
+ border-radius: ${(p) => p.$radius}px;
267
+ background: transparent;
268
+ cursor: pointer;
269
+ color: ${(p) => p.$color};
270
+ padding: 0;
271
+ font: inherit;
272
+
273
+ &:hover {
274
+ background: ${(p) => p.$hoverBg};
275
+ }
276
+
277
+ &:focus-visible {
278
+ outline: ${(p) => p.$focusOutlineWidth}px solid ${(p) => p.$focusOutline};
279
+ outline-offset: 2px;
280
+ }
281
+
282
+ svg {
283
+ width: ${(p) => p.$iconSize}px;
284
+ height: ${(p) => p.$iconSize}px;
285
+ }
286
+ `;
287
+ var ChatBadge = styled.span`
288
+ position: absolute;
289
+ top: -2px;
290
+ right: -2px;
291
+ width: ${(p) => p.$size}px;
292
+ height: ${(p) => p.$size}px;
293
+ background: ${(p) => p.$color};
294
+ border-radius: 999px;
295
+ `;
296
+ var PopoverContainer = styled.div`
297
+ position: fixed;
298
+ z-index: ${(p) => p.$zIndex};
299
+ min-width: ${(p) => p.$minWidth}px;
300
+ max-width: ${(p) => p.$maxWidth}px;
301
+ `;
302
+ var PopoverInner = styled.div`
303
+ min-height: ${(p) => p.$itemHeight}px;
304
+ padding: ${(p) => p.$padding}px;
305
+ background: ${(p) => p.$bg};
306
+ border-radius: ${(p) => p.$radius}px;
307
+ display: flex;
308
+ flex-direction: column;
309
+ gap: 6px;
310
+ box-shadow: ${(p) => p.$shadow};
311
+ `;
312
+ var PopoverTitle = styled.div`
313
+ display: flex;
314
+ height: 20px;
315
+ align-items: center;
316
+ padding: 0 ${(p) => p.$padding}px;
317
+ overflow: hidden;
318
+ `;
319
+ var PopoverDivider = styled.div`
320
+ height: 1px;
321
+ align-self: stretch;
322
+ background: ${(p) => p.$color};
323
+ `;
324
+ var PopoverItems = styled.div`
325
+ display: flex;
326
+ flex-direction: column;
327
+
328
+ & > .${POPOVER_ITEM_BASE_CLASS} {
329
+ display: flex;
330
+ max-height: ${(p) => p.$itemHeight}px;
331
+ align-items: center;
332
+ padding: 12px ${(p) => p.$padding}px;
333
+ border-radius: ${(p) => p.$radius}px;
334
+ color: ${(p) => p.$colorIdle};
335
+ font-weight: 400;
336
+ cursor: pointer;
337
+ transition: background-color 0.15s ease-in-out;
338
+ text-decoration: none;
339
+ }
340
+
341
+ & > .${POPOVER_ITEM_BASE_CLASS}:hover {
342
+ background-color: ${(p) => p.$hoverBg};
343
+ }
344
+
345
+ & > .${POPOVER_ITEM_BASE_CLASS}:focus-visible {
346
+ outline: ${(p) => p.$focusOutlineWidth}px solid ${(p) => p.$focusOutline};
347
+ outline-offset: -${(p) => p.$focusOutlineWidth}px;
348
+ }
349
+
350
+ & > .${POPOVER_ITEM_ACTIVE_CLASS} {
351
+ background-color: ${(p) => p.$activeBg};
352
+ color: ${(p) => p.$colorActive};
353
+ outline: 1px solid ${(p) => p.$activeOutline};
354
+ outline-offset: -1px;
355
+ font-weight: 500;
356
+ }
357
+ `;
358
+ var SinglePopoverPanel = styled.div`
359
+ padding: 4px;
360
+ background: ${(p) => p.$bg};
361
+ border-radius: ${(p) => p.$radius}px;
362
+ display: inline-flex;
363
+ flex-direction: column;
364
+ box-shadow: ${(p) => p.$shadow};
365
+ `;
366
+ var SingleLinkWrap = styled.div`
367
+ display: contents;
368
+
369
+ & > a,
370
+ & > * {
371
+ display: inline-flex;
372
+ max-height: ${(p) => p.$itemHeight}px;
373
+ align-items: center;
374
+ padding: 0 ${(p) => p.$padding}px;
375
+ border-radius: ${(p) => p.$radius}px;
376
+ color: ${(p) => p.$color};
377
+ cursor: pointer;
378
+ font-size: 14px;
379
+ font-weight: 400;
380
+ line-height: 18px;
381
+ white-space: nowrap;
382
+ text-decoration: none;
383
+ }
384
+ `;
385
+ var isChildActive = (item, pathname) => {
386
+ if (!item.children || !pathname) {
387
+ return false;
388
+ }
389
+ const pathWithoutMerchant = pathname.replace(/^\/\d+/, "");
390
+ return item.children.some((child) => {
391
+ if (typeof child.to !== "string") {
392
+ return false;
393
+ }
394
+ return child.exact ? pathWithoutMerchant === child.to : pathWithoutMerchant === child.to || pathWithoutMerchant.startsWith(`${child.to}/`);
395
+ });
396
+ };
397
+ var CollapsedIconItem = ({ item, onPopoverOpen, onPopoverClose, pathname, sizing, colors }) => {
398
+ const ref = useRef(null);
399
+ const hasChildren = Boolean(item.children && item.children.length > 0);
400
+ const isActive = hasChildren && isChildActive(item, pathname);
401
+ const openPopover = useCallback2(() => {
402
+ if (ref.current) {
403
+ onPopoverOpen(item, ref.current.getBoundingClientRect());
404
+ }
405
+ }, [item, onPopoverOpen]);
406
+ const isSimpleActive = !hasChildren && (() => {
407
+ if (!item.to || !pathname) {
408
+ return false;
409
+ }
410
+ const pathWithoutMerchant = pathname.replace(/^\/\d+/, "");
411
+ return item.exact ? pathWithoutMerchant === item.to : pathWithoutMerchant === item.to || pathWithoutMerchant.startsWith(`${item.to}/`);
412
+ })();
413
+ const handleKeyDown = (e) => {
414
+ if (e.key === "Enter" || e.key === " ") {
415
+ e.preventDefault();
416
+ openPopover();
417
+ } else if (e.key === "Escape") {
418
+ onPopoverClose();
419
+ }
420
+ };
421
+ if (!item.icon) {
422
+ return null;
423
+ }
424
+ return /* @__PURE__ */ jsx3(
425
+ IconBtn,
426
+ {
427
+ ref,
428
+ type: "button",
429
+ onMouseEnter: openPopover,
430
+ onMouseLeave: onPopoverClose,
431
+ onFocus: openPopover,
432
+ onBlur: onPopoverClose,
433
+ onKeyDown: handleKeyDown,
434
+ "data-id": item.dataId,
435
+ "aria-haspopup": hasChildren ? "menu" : "false",
436
+ $size: sizing.itemHeight,
437
+ $radius: sizing.radius,
438
+ $iconSize: sizing.iconSize,
439
+ $color: colors.content.tertiary,
440
+ $hoverBg: colors.overlay.mono,
441
+ $hoverColor: colors.content.primary,
442
+ $activeBg: colors.overlay.mono,
443
+ $activeOutline: colors.border.secondary,
444
+ $focusOutline: colors.border.brand,
445
+ $focusOutlineWidth: sizing.focusOutlineWidth,
446
+ $active: isActive || isSimpleActive,
447
+ children: /* @__PURE__ */ jsx3("span", { children: item.icon })
448
+ }
449
+ );
450
+ };
451
+ var CollapsedPopover = ({
452
+ item,
453
+ triggerRect,
454
+ onClose,
455
+ onMouseEnter,
456
+ onMouseLeave,
457
+ sizing,
458
+ colors
459
+ }) => {
460
+ const { LinkComponent } = useSidebar();
461
+ const popoverRef = useRef(null);
462
+ const hasChildren = Boolean(item.children && item.children.length > 0);
463
+ const [position, setPosition] = useState2({
464
+ top: triggerRect.top,
465
+ left: triggerRect.right + POPOVER_GAP_PX
466
+ });
467
+ useLayoutEffect(() => {
468
+ if (!popoverRef.current) {
469
+ return;
470
+ }
471
+ const rect = popoverRef.current.getBoundingClientRect();
472
+ const triggerCenterY = triggerRect.top + triggerRect.height / 2;
473
+ const idealTop = hasChildren ? triggerRect.top : triggerCenterY - rect.height / 2;
474
+ const maxTop = Math.max(
475
+ POPOVER_VIEWPORT_PADDING_PX,
476
+ window.innerHeight - rect.height - POPOVER_VIEWPORT_PADDING_PX
477
+ );
478
+ const top = Math.max(
479
+ POPOVER_VIEWPORT_PADDING_PX,
480
+ Math.min(idealTop, maxTop)
481
+ );
482
+ const left = Math.min(
483
+ triggerRect.right + POPOVER_GAP_PX,
484
+ window.innerWidth - rect.width - POPOVER_VIEWPORT_PADDING_PX
485
+ );
486
+ if (top !== position.top || left !== position.left) {
487
+ setPosition({ top, left });
488
+ }
489
+ }, [
490
+ triggerRect.top,
491
+ triggerRect.right,
492
+ triggerRect.height,
493
+ hasChildren,
494
+ item.dataId,
495
+ position.top,
496
+ position.left
497
+ ]);
498
+ if (!hasChildren) {
499
+ return /* @__PURE__ */ jsx3(
500
+ PopoverContainer,
501
+ {
502
+ ref: popoverRef,
503
+ style: { top: position.top, left: position.left, minWidth: "auto" },
504
+ onMouseEnter,
505
+ onMouseLeave,
506
+ $minWidth: 0,
507
+ $maxWidth: sizing.popoverMaxWidth,
508
+ $zIndex: sizing.popoverZIndex,
509
+ children: /* @__PURE__ */ jsx3(
510
+ SinglePopoverPanel,
511
+ {
512
+ $padding: sizing.padding,
513
+ $itemHeight: sizing.itemHeight,
514
+ $radius: sizing.radius,
515
+ $bg: colors.layer.float,
516
+ $shadow: sizing.popoverShadow,
517
+ children: /* @__PURE__ */ jsx3(
518
+ SingleLinkWrap,
519
+ {
520
+ $itemHeight: sizing.itemHeight,
521
+ $padding: sizing.padding,
522
+ $radius: sizing.radius,
523
+ $color: colors.content.primary,
524
+ children: /* @__PURE__ */ jsx3(
525
+ LinkComponent,
526
+ {
527
+ to: item.to,
528
+ exact: item.exact,
529
+ external: item.external,
530
+ target: item.target,
531
+ dataId: item.dataId,
532
+ onClick: onClose,
533
+ children: /* @__PURE__ */ jsx3(Typography, { variant: "bodySm", color: "primary", children: item.label })
534
+ }
535
+ )
536
+ }
537
+ )
538
+ }
539
+ )
540
+ }
541
+ );
542
+ }
543
+ return /* @__PURE__ */ jsx3(
544
+ PopoverContainer,
545
+ {
546
+ ref: popoverRef,
547
+ role: "menu",
548
+ style: { top: position.top, left: position.left },
549
+ onMouseEnter,
550
+ onMouseLeave,
551
+ $minWidth: sizing.popoverMinWidth,
552
+ $maxWidth: sizing.popoverMaxWidth,
553
+ $zIndex: sizing.popoverZIndex,
554
+ children: /* @__PURE__ */ jsxs2(
555
+ PopoverInner,
556
+ {
557
+ $itemHeight: sizing.itemHeight,
558
+ $padding: sizing.padding,
559
+ $radius: sizing.radius,
560
+ $bg: colors.layer.float,
561
+ $shadow: sizing.popoverShadow,
562
+ children: [
563
+ /* @__PURE__ */ jsx3(PopoverTitle, { $padding: sizing.padding, children: /* @__PURE__ */ jsx3(Typography, { variant: "bodyXs", color: "primary", children: item.label }) }),
564
+ /* @__PURE__ */ jsx3(PopoverDivider, { $color: colors.border.secondary }),
565
+ /* @__PURE__ */ jsx3(
566
+ PopoverItems,
567
+ {
568
+ $itemHeight: sizing.itemHeight,
569
+ $padding: sizing.padding,
570
+ $radius: sizing.radius,
571
+ $colorIdle: colors.content.tertiary,
572
+ $colorActive: colors.content.primary,
573
+ $hoverBg: colors.overlay.mono,
574
+ $activeBg: colors.overlay.mono,
575
+ $activeOutline: colors.border.secondary,
576
+ $focusOutline: colors.border.brand,
577
+ $focusOutlineWidth: sizing.focusOutlineWidth,
578
+ children: (item.children || []).map((child, i) => /* @__PURE__ */ jsx3(
579
+ LinkComponent,
580
+ {
581
+ to: child.to,
582
+ exact: child.exact,
583
+ external: child.external,
584
+ target: child.target,
585
+ className: POPOVER_ITEM_BASE_CLASS,
586
+ activeClassName: POPOVER_ITEM_ACTIVE_CLASS,
587
+ dataId: child.dataId,
588
+ onClick: onClose,
589
+ children: /* @__PURE__ */ jsx3(Typography, { variant: "bodySm", color: "inherit", children: child.label })
590
+ },
591
+ child.dataId || (typeof child.to === "string" ? child.to : `child-${i}`)
592
+ ))
593
+ }
594
+ )
595
+ ]
596
+ }
597
+ )
598
+ }
599
+ );
600
+ };
601
+ var SidebarCollapsed = ({
602
+ items,
603
+ toolItems = [],
604
+ bottomItems = [],
605
+ onToggleCollapse,
606
+ onChatClick,
607
+ showChat = true,
608
+ chatBadge = false
609
+ }) => {
610
+ const { pathname } = useSidebar();
611
+ const { theme } = useResolvedTheme();
612
+ const sizing = theme.sizing.sidebar();
613
+ const colors = theme.colors;
614
+ const [popover, setPopover] = useState2(null);
615
+ const closeTimerRef = useRef(null);
616
+ const cancelCloseTimer = useCallback2(() => {
617
+ if (closeTimerRef.current) {
618
+ clearTimeout(closeTimerRef.current);
619
+ closeTimerRef.current = null;
620
+ }
621
+ }, []);
622
+ const startCloseTimer = useCallback2(() => {
623
+ cancelCloseTimer();
624
+ closeTimerRef.current = setTimeout(() => {
625
+ setPopover(null);
626
+ }, POPOVER_CLOSE_DELAY_MS);
627
+ }, [cancelCloseTimer]);
628
+ useEffect(() => () => cancelCloseTimer(), [cancelCloseTimer]);
629
+ const handlePopoverOpen = useCallback2(
630
+ (item, rect) => {
631
+ cancelCloseTimer();
632
+ setPopover({ item, triggerRect: rect });
633
+ },
634
+ [cancelCloseTimer]
635
+ );
636
+ return /* @__PURE__ */ jsxs2(
637
+ Outer,
638
+ {
639
+ $width: sizing.widthCollapsed,
640
+ $radius: sizing.radius,
641
+ $bg: colors.background.secondary,
642
+ children: [
643
+ /* @__PURE__ */ jsxs2(MainScroll, { $padding: sizing.padding, children: [
644
+ items.map((item, i) => /* @__PURE__ */ jsx3(
645
+ CollapsedIconItem,
646
+ {
647
+ item,
648
+ onPopoverOpen: handlePopoverOpen,
649
+ onPopoverClose: startCloseTimer,
650
+ pathname,
651
+ sizing,
652
+ colors
653
+ },
654
+ item.dataId || `item-${i}`
655
+ )),
656
+ toolItems.length > 0 && /* @__PURE__ */ jsxs2(Fragment, { children: [
657
+ /* @__PURE__ */ jsx3(Spacer, {}),
658
+ toolItems.map((item, i) => /* @__PURE__ */ jsx3(
659
+ CollapsedIconItem,
660
+ {
661
+ item,
662
+ onPopoverOpen: handlePopoverOpen,
663
+ onPopoverClose: startCloseTimer,
664
+ pathname,
665
+ sizing,
666
+ colors
667
+ },
668
+ item.dataId || `tool-${i}`
669
+ ))
670
+ ] })
671
+ ] }),
672
+ /* @__PURE__ */ jsx3(
673
+ FixedBottom,
674
+ {
675
+ $padding: sizing.padding,
676
+ $borderColor: colors.border.secondary,
677
+ children: bottomItems.map((item, i) => /* @__PURE__ */ jsx3(
678
+ CollapsedIconItem,
679
+ {
680
+ item,
681
+ onPopoverOpen: handlePopoverOpen,
682
+ onPopoverClose: startCloseTimer,
683
+ pathname,
684
+ sizing,
685
+ colors
686
+ },
687
+ item.dataId || `bottom-${i}`
688
+ ))
689
+ }
690
+ ),
691
+ /* @__PURE__ */ jsxs2(Footer, { $padding: sizing.padding, $borderColor: colors.border.secondary, children: [
692
+ showChat && /* @__PURE__ */ jsxs2(
693
+ CollapsedChat,
694
+ {
695
+ onClick: onChatClick,
696
+ type: "button",
697
+ "aria-label": "Open chat",
698
+ $size: sizing.itemHeight,
699
+ $radius: sizing.radius,
700
+ $bg: colors.control.brand.primary.bg,
701
+ $border: colors.control.brand.primary.border,
702
+ $color: colors.content.static.dark,
703
+ $focusOutline: colors.border.brand,
704
+ $focusOutlineWidth: sizing.focusOutlineWidth,
705
+ children: [
706
+ /* @__PURE__ */ jsx3(ChatTwoMessages, { size: 16, variant: "line" }),
707
+ chatBadge && /* @__PURE__ */ jsx3(
708
+ ChatBadge,
709
+ {
710
+ $size: sizing.chatBadgeSize,
711
+ $color: colors.background.alert.primary
712
+ }
713
+ )
714
+ ]
715
+ }
716
+ ),
717
+ /* @__PURE__ */ jsx3(
718
+ CollapsedToggle,
719
+ {
720
+ onClick: onToggleCollapse,
721
+ type: "button",
722
+ "aria-label": "Expand sidebar",
723
+ "aria-pressed": true,
724
+ $size: sizing.itemHeight,
725
+ $radius: sizing.radius,
726
+ $iconSize: sizing.iconSize,
727
+ $borderColor: colors.border.secondary,
728
+ $hoverBg: colors.overlay.mono,
729
+ $color: colors.content.tertiary,
730
+ $focusOutline: colors.border.brand,
731
+ $focusOutlineWidth: sizing.focusOutlineWidth,
732
+ children: /* @__PURE__ */ jsx3(HideSidebarIcon, { flipped: true })
733
+ }
734
+ )
735
+ ] }),
736
+ popover && typeof document !== "undefined" && createPortal(
737
+ /* @__PURE__ */ jsx3(
738
+ CollapsedPopover,
739
+ {
740
+ item: popover.item,
741
+ triggerRect: popover.triggerRect,
742
+ onClose: () => setPopover(null),
743
+ onMouseEnter: cancelCloseTimer,
744
+ onMouseLeave: startCloseTimer,
745
+ sizing,
746
+ colors
747
+ }
748
+ ),
749
+ document.body
750
+ )
751
+ ]
752
+ }
753
+ );
754
+ };
755
+
756
+ // src/Sidebar.tsx
757
+ import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
758
+ var Outer2 = styled2.div`
759
+ width: ${(p) => p.$width}px;
760
+ height: 100%;
761
+ max-height: 100%;
762
+ flex-shrink: 0;
763
+ position: relative;
764
+ overflow: hidden;
765
+ border-radius: ${(p) => p.$radius}px;
766
+ background: ${(p) => p.$bg};
767
+ transition: width ${(p) => p.$transition};
768
+
769
+ a {
770
+ text-decoration: none;
771
+ }
772
+ `;
773
+ var ExpandedPane = styled2.div`
774
+ position: absolute;
775
+ top: 0;
776
+ left: 0;
777
+ width: ${(p) => p.$width}px;
778
+ height: 100%;
779
+ display: flex;
780
+ flex-direction: column;
781
+ overflow: hidden;
782
+ opacity: ${(p) => p.$hidden ? 0 : 1};
783
+ pointer-events: ${(p) => p.$hidden ? "none" : "auto"};
784
+ transition: ${(p) => p.$hidden ? p.$fadeOut : p.$fadeIn};
785
+ `;
786
+ var CollapsedPane = styled2.div`
787
+ position: absolute;
788
+ top: 0;
789
+ left: 0;
790
+ width: ${(p) => p.$width}px;
791
+ height: 100%;
792
+ opacity: ${(p) => p.$hidden ? 0 : 1};
793
+ pointer-events: ${(p) => p.$hidden ? "none" : "auto"};
794
+ transition: ${(p) => p.$hidden ? p.$fadeOut : p.$fadeIn};
795
+
796
+ & > div {
797
+ background: transparent;
798
+ border-radius: 0;
799
+ }
800
+ `;
801
+ var Sidebar = ({
802
+ collapsedItems = [],
803
+ collapsedToolItems = [],
804
+ collapsedBottomItems = [],
805
+ showChat = true,
806
+ onChatClick,
807
+ chatBadge = false,
808
+ children
809
+ }) => {
810
+ const { collapsed, onCollapsedChange } = useSidebar();
811
+ const { theme } = useResolvedTheme2();
812
+ const sizing = theme.sizing.sidebar();
813
+ return /* @__PURE__ */ jsxs3(
814
+ Outer2,
815
+ {
816
+ role: "navigation",
817
+ "aria-label": "Sidebar navigation",
818
+ $expanded: sizing.widthExpanded,
819
+ $collapsed: sizing.widthCollapsed,
820
+ $width: collapsed ? sizing.widthCollapsed : sizing.widthExpanded,
821
+ $radius: sizing.radius,
822
+ $bg: theme.colors.background.secondary,
823
+ $transition: sizing.transitionWidth,
824
+ children: [
825
+ /* @__PURE__ */ jsx4(
826
+ ExpandedPane,
827
+ {
828
+ "aria-hidden": collapsed,
829
+ $width: sizing.widthExpanded,
830
+ $hidden: collapsed,
831
+ $fadeIn: sizing.transitionFadeIn,
832
+ $fadeOut: sizing.transitionFadeOut,
833
+ children
834
+ }
835
+ ),
836
+ /* @__PURE__ */ jsx4(
837
+ CollapsedPane,
838
+ {
839
+ "aria-hidden": !collapsed,
840
+ $width: sizing.widthCollapsed,
841
+ $hidden: !collapsed,
842
+ $fadeIn: sizing.transitionFadeIn,
843
+ $fadeOut: sizing.transitionFadeOut,
844
+ children: /* @__PURE__ */ jsx4(
845
+ SidebarCollapsed,
846
+ {
847
+ items: collapsedItems,
848
+ toolItems: collapsedToolItems,
849
+ bottomItems: collapsedBottomItems,
850
+ onToggleCollapse: () => onCollapsedChange(!collapsed),
851
+ showChat,
852
+ onChatClick,
853
+ chatBadge
854
+ }
855
+ )
856
+ }
857
+ )
858
+ ]
859
+ }
860
+ );
861
+ };
862
+
863
+ // src/SidebarContent.tsx
864
+ import styled3 from "styled-components";
865
+ import { useResolvedTheme as useResolvedTheme3 } from "@xsolla/xui-core";
866
+ import { jsx as jsx5 } from "react/jsx-runtime";
867
+ var ScrollableArea = styled3.div`
868
+ flex: 1;
869
+ display: flex;
870
+ flex-direction: column;
871
+ padding: ${(p) => p.$padding}px;
872
+ padding-bottom: 0;
873
+ overflow: hidden auto;
874
+ min-height: 0;
875
+
876
+ &::-webkit-scrollbar {
877
+ width: 4px;
878
+ }
879
+ &::-webkit-scrollbar-track {
880
+ background: none;
881
+ }
882
+ &::-webkit-scrollbar-thumb {
883
+ background-color: ${(p) => p.$thumbColor};
884
+ border-radius: 2px;
885
+ visibility: hidden;
886
+ }
887
+ &:hover::-webkit-scrollbar-thumb {
888
+ visibility: visible;
889
+ }
890
+ `;
891
+ var SidebarContent = ({
892
+ children
893
+ }) => {
894
+ const { theme } = useResolvedTheme3();
895
+ const sizing = theme.sizing.sidebar();
896
+ return /* @__PURE__ */ jsx5(
897
+ ScrollableArea,
898
+ {
899
+ $padding: sizing.padding,
900
+ $thumbColor: theme.colors.content.tertiary,
901
+ children
902
+ }
903
+ );
904
+ };
905
+
906
+ // ../../foundation/primitives-native/src/Box.tsx
907
+ import {
908
+ View,
909
+ Pressable,
910
+ Image
911
+ } from "react-native";
912
+ import { jsx as jsx6 } from "react/jsx-runtime";
913
+ var Box = ({
914
+ children,
915
+ onPress,
916
+ onLayout,
917
+ onMoveShouldSetResponder,
918
+ onResponderGrant,
919
+ onResponderMove,
920
+ onResponderRelease,
921
+ onResponderTerminate,
922
+ backgroundColor,
923
+ borderColor,
924
+ borderWidth,
925
+ borderBottomWidth,
926
+ borderBottomColor,
927
+ borderTopWidth,
928
+ borderTopColor,
929
+ borderLeftWidth,
930
+ borderLeftColor,
931
+ borderRightWidth,
932
+ borderRightColor,
933
+ borderRadius,
934
+ borderStyle,
935
+ height,
936
+ padding,
937
+ paddingHorizontal,
938
+ paddingVertical,
939
+ margin,
940
+ marginTop,
941
+ marginBottom,
942
+ marginLeft,
943
+ marginRight,
944
+ flexDirection,
945
+ alignItems,
946
+ justifyContent,
947
+ position,
948
+ top,
949
+ bottom,
950
+ left,
951
+ right,
952
+ width,
953
+ minWidth,
954
+ minHeight,
955
+ maxWidth,
956
+ maxHeight,
957
+ flex,
958
+ overflow,
959
+ zIndex,
960
+ hoverStyle,
961
+ pressStyle,
962
+ style,
963
+ "data-testid": dataTestId,
964
+ testID,
965
+ as,
966
+ src,
967
+ alt,
968
+ ...rest
969
+ }) => {
970
+ const getContainerStyle = (pressed) => ({
971
+ backgroundColor: pressed && pressStyle?.backgroundColor ? pressStyle.backgroundColor : backgroundColor,
972
+ borderColor,
973
+ borderWidth,
974
+ borderBottomWidth,
975
+ borderBottomColor,
976
+ borderTopWidth,
977
+ borderTopColor,
978
+ borderLeftWidth,
979
+ borderLeftColor,
980
+ borderRightWidth,
981
+ borderRightColor,
982
+ borderRadius,
983
+ borderStyle,
984
+ overflow,
985
+ zIndex,
986
+ height,
987
+ width,
988
+ minWidth,
989
+ minHeight,
990
+ maxWidth,
991
+ maxHeight,
992
+ padding,
993
+ paddingHorizontal,
994
+ paddingVertical,
995
+ margin,
996
+ marginTop,
997
+ marginBottom,
998
+ marginLeft,
999
+ marginRight,
1000
+ flexDirection,
1001
+ alignItems,
1002
+ justifyContent,
1003
+ position,
1004
+ top,
1005
+ bottom,
1006
+ left,
1007
+ right,
1008
+ flex,
1009
+ ...style
1010
+ });
1011
+ const finalTestID = dataTestId || testID;
1012
+ const {
1013
+ role,
1014
+ tabIndex,
1015
+ onKeyDown,
1016
+ onKeyUp,
1017
+ "aria-label": _ariaLabel,
1018
+ "aria-labelledby": _ariaLabelledBy,
1019
+ "aria-current": _ariaCurrent,
1020
+ "aria-disabled": _ariaDisabled,
1021
+ "aria-live": _ariaLive,
1022
+ className,
1023
+ "data-testid": _dataTestId,
1024
+ ...nativeRest
1025
+ } = rest;
1026
+ if (as === "img" && src) {
1027
+ const imageStyle = {
1028
+ width,
1029
+ height,
1030
+ borderRadius,
1031
+ position,
1032
+ top,
1033
+ bottom,
1034
+ left,
1035
+ right,
1036
+ ...style
1037
+ };
1038
+ return /* @__PURE__ */ jsx6(
1039
+ Image,
1040
+ {
1041
+ source: { uri: src },
1042
+ style: imageStyle,
1043
+ testID: finalTestID,
1044
+ resizeMode: "cover",
1045
+ ...nativeRest
1046
+ }
1047
+ );
1048
+ }
1049
+ if (onPress) {
1050
+ return /* @__PURE__ */ jsx6(
1051
+ Pressable,
1052
+ {
1053
+ onPress,
1054
+ onLayout,
1055
+ onMoveShouldSetResponder,
1056
+ onResponderGrant,
1057
+ onResponderMove,
1058
+ onResponderRelease,
1059
+ onResponderTerminate,
1060
+ style: ({ pressed }) => getContainerStyle(pressed),
1061
+ testID: finalTestID,
1062
+ ...nativeRest,
1063
+ children
1064
+ }
1065
+ );
1066
+ }
1067
+ return /* @__PURE__ */ jsx6(
1068
+ View,
1069
+ {
1070
+ style: getContainerStyle(),
1071
+ testID: finalTestID,
1072
+ onLayout,
1073
+ onMoveShouldSetResponder,
1074
+ onResponderGrant,
1075
+ onResponderMove,
1076
+ onResponderRelease,
1077
+ onResponderTerminate,
1078
+ ...nativeRest,
1079
+ children
1080
+ }
1081
+ );
1082
+ };
1083
+
1084
+ // src/SidebarFooter.tsx
1085
+ import { useResolvedTheme as useResolvedTheme4 } from "@xsolla/xui-core";
1086
+ import { jsx as jsx7 } from "react/jsx-runtime";
1087
+ var SidebarFooter = ({
1088
+ children
1089
+ }) => {
1090
+ const { theme } = useResolvedTheme4();
1091
+ const sizing = theme.sizing.sidebar();
1092
+ return /* @__PURE__ */ jsx7(
1093
+ Box,
1094
+ {
1095
+ flexDirection: "row",
1096
+ alignItems: "flex-end",
1097
+ justifyContent: "space-between",
1098
+ padding: sizing.padding,
1099
+ borderTopWidth: 1,
1100
+ borderTopColor: theme.colors.border.secondary,
1101
+ flexShrink: 0,
1102
+ children
1103
+ }
1104
+ );
1105
+ };
1106
+
1107
+ // src/SidebarTrigger.tsx
1108
+ import styled4 from "styled-components";
1109
+ import { useResolvedTheme as useResolvedTheme5 } from "@xsolla/xui-core";
1110
+ import { jsx as jsx8 } from "react/jsx-runtime";
1111
+ var ToggleButton = styled4.button`
1112
+ display: flex;
1113
+ width: ${(p) => p.$size}px;
1114
+ height: ${(p) => p.$size}px;
1115
+ align-items: center;
1116
+ justify-content: center;
1117
+ border: 1px solid ${(p) => p.$borderColor};
1118
+ border-radius: ${(p) => p.$radius}px;
1119
+ background: transparent;
1120
+ backdrop-filter: blur(30px);
1121
+ cursor: pointer;
1122
+ color: ${(p) => p.$color};
1123
+ padding: 0;
1124
+ font: inherit;
1125
+
1126
+ &:hover {
1127
+ background: ${(p) => p.$hoverBg};
1128
+ }
1129
+
1130
+ &:focus-visible {
1131
+ outline: ${(p) => p.$focusOutlineWidth}px solid ${(p) => p.$focusOutline};
1132
+ outline-offset: 2px;
1133
+ }
1134
+
1135
+ svg {
1136
+ width: ${(p) => p.$iconSize}px;
1137
+ height: ${(p) => p.$iconSize}px;
1138
+ }
1139
+ `;
1140
+ var SidebarTrigger = () => {
1141
+ const { collapsed, onCollapsedChange } = useSidebar();
1142
+ const { theme } = useResolvedTheme5();
1143
+ const sizing = theme.sizing.sidebar();
1144
+ return /* @__PURE__ */ jsx8(
1145
+ ToggleButton,
1146
+ {
1147
+ type: "button",
1148
+ onClick: () => onCollapsedChange(!collapsed),
1149
+ "aria-label": collapsed ? "Expand sidebar" : "Collapse sidebar",
1150
+ "aria-pressed": collapsed,
1151
+ $size: sizing.itemHeight,
1152
+ $radius: sizing.radius,
1153
+ $iconSize: sizing.iconSize,
1154
+ $borderColor: theme.colors.border.secondary,
1155
+ $hoverBg: theme.colors.overlay.mono,
1156
+ $color: theme.colors.content.tertiary,
1157
+ $focusOutline: theme.colors.border.brand,
1158
+ $focusOutlineWidth: sizing.focusOutlineWidth,
1159
+ children: /* @__PURE__ */ jsx8(HideSidebarIcon, { flipped: collapsed })
1160
+ }
1161
+ );
1162
+ };
1163
+
1164
+ // src/SidebarGroup.tsx
1165
+ import { useResolvedTheme as useResolvedTheme6 } from "@xsolla/xui-core";
1166
+ import { Typography as Typography2 } from "@xsolla/xui-typography";
1167
+ import { jsx as jsx9, jsxs as jsxs4 } from "react/jsx-runtime";
1168
+ var SidebarGroup = ({
1169
+ label,
1170
+ dataId,
1171
+ children
1172
+ }) => {
1173
+ const { theme } = useResolvedTheme6();
1174
+ const sizing = theme.sizing.sidebar();
1175
+ return /* @__PURE__ */ jsxs4(
1176
+ Box,
1177
+ {
1178
+ flexDirection: "column",
1179
+ "data-id": dataId,
1180
+ role: label ? "group" : void 0,
1181
+ "aria-label": label,
1182
+ children: [
1183
+ label && /* @__PURE__ */ jsx9(
1184
+ Box,
1185
+ {
1186
+ flexDirection: "row",
1187
+ alignItems: "center",
1188
+ height: sizing.sectionLabelHeight,
1189
+ paddingHorizontal: sizing.padding,
1190
+ marginTop: sizing.padding,
1191
+ children: /* @__PURE__ */ jsx9(Typography2, { variant: "bodyXs", color: "secondary", children: label })
1192
+ }
1193
+ ),
1194
+ children
1195
+ ]
1196
+ }
1197
+ );
1198
+ };
1199
+
1200
+ // src/SidebarMenu.tsx
1201
+ import { jsx as jsx10 } from "react/jsx-runtime";
1202
+ var SidebarMenu = ({
1203
+ children
1204
+ }) => /* @__PURE__ */ jsx10(Box, { flexDirection: "column", alignItems: "stretch", children });
1205
+
1206
+ // src/SidebarMenuItem.tsx
1207
+ import styled5 from "styled-components";
1208
+ import { useResolvedTheme as useResolvedTheme7 } from "@xsolla/xui-core";
1209
+ import { Typography as Typography3 } from "@xsolla/xui-typography";
1210
+ import { Tooltip } from "@xsolla/xui-tooltip";
1211
+ import { OpenIn } from "@xsolla/xui-icons-base";
1212
+
1213
+ // src/constants.ts
1214
+ var ITEM_BASE_CLASS = "xui-sb-item";
1215
+ var ITEM_ACTIVE_CLASS = "xui-sb-item--active";
1216
+
1217
+ // src/SidebarMenuItem.tsx
1218
+ import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
1219
+ var TOOLTIP_TRUNCATE_LENGTH = 20;
1220
+ var ItemWrapper = styled5.div`
1221
+ display: contents;
1222
+
1223
+ & > .${ITEM_BASE_CLASS} {
1224
+ display: flex;
1225
+ height: ${(p) => p.$multiLine ? "auto" : `${p.$itemHeight}px`};
1226
+ max-height: ${(p) => p.$multiLine ? "none" : `${p.$itemHeight}px`};
1227
+ width: 100%;
1228
+ box-sizing: border-box;
1229
+ align-items: ${(p) => p.$multiLine ? "flex-start" : "center"};
1230
+ gap: 8px;
1231
+ padding: 0 ${(p) => p.$padding}px;
1232
+ border-radius: ${(p) => p.$radius}px;
1233
+ color: ${(p) => p.$colorIdle};
1234
+ cursor: pointer;
1235
+ font-size: 14px;
1236
+ font-weight: 500;
1237
+ line-height: 18px;
1238
+ overflow: hidden;
1239
+ transition:
1240
+ background-color 0.15s ease-in-out,
1241
+ color 0.15s ease-in-out;
1242
+ white-space: ${(p) => p.$multiLine ? "normal" : "nowrap"};
1243
+ text-align: left;
1244
+ text-decoration: none;
1245
+ }
1246
+
1247
+ & > .${ITEM_BASE_CLASS}:hover {
1248
+ background-color: ${(p) => p.$hoverBg};
1249
+ }
1250
+
1251
+ & > .${ITEM_BASE_CLASS}:focus-visible {
1252
+ outline: ${(p) => p.$focusOutlineWidth}px solid ${(p) => p.$focusOutline};
1253
+ outline-offset: -${(p) => p.$focusOutlineWidth}px;
1254
+ }
1255
+
1256
+ & > .${ITEM_ACTIVE_CLASS} {
1257
+ background-color: ${(p) => p.$activeBg};
1258
+ outline: 1px solid ${(p) => p.$activeOutline};
1259
+ outline-offset: -1px;
1260
+ color: ${(p) => p.$colorActive};
1261
+ font-weight: 500;
1262
+ }
1263
+ `;
1264
+ var IconBox = styled5.div`
1265
+ display: flex;
1266
+ width: ${(p) => p.$size}px;
1267
+ height: ${(p) => p.$size}px;
1268
+ flex-shrink: 0;
1269
+ align-items: center;
1270
+ justify-content: center;
1271
+ color: inherit;
1272
+
1273
+ svg {
1274
+ width: ${(p) => p.$pin ? "12px" : `${p.$size}px`};
1275
+ height: ${(p) => p.$pin ? "12px" : `${p.$size}px`};
1276
+ }
1277
+ `;
1278
+ var LabelBox = styled5.span`
1279
+ display: flex;
1280
+ flex: 1;
1281
+ gap: 4px;
1282
+ height: 20px;
1283
+ align-items: center;
1284
+ min-width: 0;
1285
+ overflow: hidden;
1286
+ text-overflow: ellipsis;
1287
+ `;
1288
+ var BadgeDot = styled5.span`
1289
+ width: ${(p) => p.$size}px;
1290
+ height: ${(p) => p.$size}px;
1291
+ flex-shrink: 0;
1292
+ background: ${(p) => p.$color};
1293
+ border-radius: 999px;
1294
+ `;
1295
+ var BetaTag = styled5.span`
1296
+ padding: 2px 6px;
1297
+ border-radius: ${(p) => p.$radius}px;
1298
+ background: ${(p) => p.$bg};
1299
+ color: ${(p) => p.$color};
1300
+ font-size: 11px;
1301
+ font-weight: 500;
1302
+ line-height: 14px;
1303
+ flex-shrink: 0;
1304
+ `;
1305
+ var ExternalIconBox = styled5.span`
1306
+ display: flex;
1307
+ width: ${(p) => p.$size}px;
1308
+ height: ${(p) => p.$size}px;
1309
+ flex-shrink: 0;
1310
+ align-items: center;
1311
+ justify-content: center;
1312
+ margin-left: auto;
1313
+ color: ${(p) => p.$color};
1314
+ `;
1315
+ var SidebarMenuItem = ({
1316
+ to,
1317
+ label,
1318
+ icon,
1319
+ exact,
1320
+ external,
1321
+ hasExternalIcon,
1322
+ target,
1323
+ onClick,
1324
+ dataId,
1325
+ isActive,
1326
+ isPinned,
1327
+ showBadge,
1328
+ hasTooltip,
1329
+ beta,
1330
+ multiLine,
1331
+ extra,
1332
+ isNested = false
1333
+ }) => {
1334
+ const { LinkComponent } = useSidebar();
1335
+ const { theme } = useResolvedTheme7();
1336
+ const sizing = theme.sizing.sidebar();
1337
+ const shouldTruncate = Boolean(hasTooltip) && typeof label === "string" && label.length > TOOLTIP_TRUNCATE_LENGTH;
1338
+ const displayLabel = shouldTruncate ? /* @__PURE__ */ jsx11(Tooltip, { content: label, placement: "right", size: "md", children: /* @__PURE__ */ jsx11("span", { children: `${label.slice(0, TOOLTIP_TRUNCATE_LENGTH)}\u2026` }) }) : label;
1339
+ return /* @__PURE__ */ jsx11(
1340
+ ItemWrapper,
1341
+ {
1342
+ $itemHeight: sizing.itemHeight,
1343
+ $iconSize: sizing.iconSize,
1344
+ $padding: sizing.padding,
1345
+ $radius: sizing.radius,
1346
+ $colorIdle: theme.colors.content.tertiary,
1347
+ $colorActive: theme.colors.content.primary,
1348
+ $hoverBg: theme.colors.overlay.mono,
1349
+ $activeBg: theme.colors.overlay.mono,
1350
+ $activeOutline: theme.colors.border.secondary,
1351
+ $focusOutline: theme.colors.border.brand,
1352
+ $focusOutlineWidth: sizing.focusOutlineWidth,
1353
+ $multiLine: multiLine,
1354
+ children: /* @__PURE__ */ jsxs5(
1355
+ LinkComponent,
1356
+ {
1357
+ to,
1358
+ exact,
1359
+ external,
1360
+ target,
1361
+ onClick,
1362
+ isActive,
1363
+ className: ITEM_BASE_CLASS,
1364
+ activeClassName: ITEM_ACTIVE_CLASS,
1365
+ dataId,
1366
+ children: [
1367
+ icon && !isNested && /* @__PURE__ */ jsx11(IconBox, { $size: sizing.iconSize, $pin: isPinned, children: icon }),
1368
+ extra,
1369
+ /* @__PURE__ */ jsxs5(LabelBox, { children: [
1370
+ /* @__PURE__ */ jsx11(
1371
+ Typography3,
1372
+ {
1373
+ variant: isNested ? "bodySm" : "bodySmAccent",
1374
+ color: "inherit",
1375
+ noWrap: !multiLine,
1376
+ children: displayLabel
1377
+ }
1378
+ ),
1379
+ showBadge && /* @__PURE__ */ jsx11(
1380
+ BadgeDot,
1381
+ {
1382
+ $size: sizing.itemBadgeSize,
1383
+ $color: theme.colors.background.alert.primary
1384
+ }
1385
+ )
1386
+ ] }),
1387
+ beta && /* @__PURE__ */ jsx11(
1388
+ BetaTag,
1389
+ {
1390
+ $bg: theme.colors.overlay.mono,
1391
+ $color: theme.colors.content.tertiary,
1392
+ $radius: sizing.radius,
1393
+ children: "Beta"
1394
+ }
1395
+ ),
1396
+ external && hasExternalIcon && /* @__PURE__ */ jsx11(
1397
+ ExternalIconBox,
1398
+ {
1399
+ $size: sizing.externalIconSize,
1400
+ $color: theme.colors.content.secondary,
1401
+ children: /* @__PURE__ */ jsx11(OpenIn, { size: 18, variant: "line" })
1402
+ }
1403
+ )
1404
+ ]
1405
+ }
1406
+ )
1407
+ }
1408
+ );
1409
+ };
1410
+
1411
+ // src/SidebarMenuCollapsible.tsx
1412
+ import { useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2 } from "react";
1413
+ import styled6 from "styled-components";
1414
+ import { useResolvedTheme as useResolvedTheme8 } from "@xsolla/xui-core";
1415
+ import { Typography as Typography4 } from "@xsolla/xui-typography";
1416
+ import { ChevronRight, ChevronUp } from "@xsolla/xui-icons-base";
1417
+ import { Fragment as Fragment2, jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
1418
+ var HeaderButton = styled6.button`
1419
+ display: flex;
1420
+ height: ${(p) => p.$itemHeight}px;
1421
+ width: 100%;
1422
+ box-sizing: border-box;
1423
+ align-items: center;
1424
+ gap: 8px;
1425
+ padding: 0 ${(p) => p.$padding}px;
1426
+ border: 0;
1427
+ border-radius: ${(p) => p.$radius}px;
1428
+ background: transparent;
1429
+ color: ${(p) => p.$color};
1430
+ cursor: pointer;
1431
+ font-size: 14px;
1432
+ font-weight: 500;
1433
+ line-height: 18px;
1434
+ font-family: inherit;
1435
+ text-align: left;
1436
+ white-space: nowrap;
1437
+ overflow: hidden;
1438
+ transition:
1439
+ background-color 0.15s ease-in-out,
1440
+ color 0.15s ease-in-out;
1441
+
1442
+ &:hover {
1443
+ background-color: ${(p) => p.$hoverBg};
1444
+ }
1445
+
1446
+ &:focus-visible {
1447
+ outline: ${(p) => p.$focusOutlineWidth}px solid ${(p) => p.$focusOutline};
1448
+ outline-offset: -${(p) => p.$focusOutlineWidth}px;
1449
+ }
1450
+ `;
1451
+ var ExpandRegion = styled6.div`
1452
+ display: grid;
1453
+ grid-template-rows: ${(p) => p.$expanded ? "1fr" : "0fr"};
1454
+ transition: ${(p) => p.$transition};
1455
+
1456
+ & > div {
1457
+ overflow: hidden;
1458
+ }
1459
+
1460
+ & .${ITEM_BASE_CLASS} {
1461
+ position: relative;
1462
+ padding: 0 ${(p) => p.$padding}px 0 ${(p) => p.$nestedPaddingLeft}px;
1463
+ font-weight: 400;
1464
+
1465
+ &::before {
1466
+ content: "";
1467
+ position: absolute;
1468
+ left: ${(p) => p.$railLeft}px;
1469
+ top: 0;
1470
+ bottom: 0;
1471
+ width: 1px;
1472
+ background: ${(p) => p.$railColor};
1473
+ transform: translateX(-50%);
1474
+ }
1475
+ }
1476
+
1477
+ & .${ITEM_ACTIVE_CLASS} {
1478
+ font-weight: 500;
1479
+ color: ${(p) => p.$colorActive};
1480
+ background-color: ${(p) => p.$activeBg};
1481
+ outline: 1px solid ${(p) => p.$activeOutline};
1482
+ outline-offset: -1px;
1483
+ }
1484
+ `;
1485
+ var IconBox2 = styled6.div`
1486
+ display: flex;
1487
+ width: ${(p) => p.$size}px;
1488
+ height: ${(p) => p.$size}px;
1489
+ flex-shrink: 0;
1490
+ align-items: center;
1491
+ justify-content: center;
1492
+ color: inherit;
1493
+
1494
+ svg {
1495
+ width: ${(p) => p.$size}px;
1496
+ height: ${(p) => p.$size}px;
1497
+ }
1498
+ `;
1499
+ var LabelBox2 = styled6.span`
1500
+ display: flex;
1501
+ flex: 1;
1502
+ gap: 4px;
1503
+ height: 20px;
1504
+ align-items: center;
1505
+ min-width: 0;
1506
+ overflow: hidden;
1507
+ text-overflow: ellipsis;
1508
+ `;
1509
+ var ChevronBox = styled6.span`
1510
+ display: flex;
1511
+ width: ${(p) => p.$size}px;
1512
+ height: ${(p) => p.$size}px;
1513
+ flex-shrink: 0;
1514
+ align-items: center;
1515
+ justify-content: center;
1516
+ margin-left: auto;
1517
+ color: inherit;
1518
+
1519
+ svg {
1520
+ width: ${(p) => p.$size}px;
1521
+ height: ${(p) => p.$size}px;
1522
+ }
1523
+ `;
1524
+ var computeRouteMatch = (pathname, matchPaths) => {
1525
+ if (matchPaths.length === 0) {
1526
+ return false;
1527
+ }
1528
+ const pathWithoutMerchant = pathname.replace(/^\/\d+/, "");
1529
+ return matchPaths.some((p) => {
1530
+ if (p === "/") return pathWithoutMerchant === "/";
1531
+ return pathWithoutMerchant === p || pathWithoutMerchant.startsWith(`${p}/`);
1532
+ });
1533
+ };
1534
+ var SidebarMenuCollapsible = ({
1535
+ icon,
1536
+ label,
1537
+ dataId,
1538
+ matchPaths = [],
1539
+ children
1540
+ }) => {
1541
+ const { pathname, expandedId, onExpandedIdChange } = useSidebar();
1542
+ const { theme } = useResolvedTheme8();
1543
+ const sizing = theme.sizing.sidebar();
1544
+ const idRef = useRef2();
1545
+ if (!idRef.current) {
1546
+ idRef.current = dataId || `sb-collapsible-${Math.random().toString(36).slice(2, 10)}`;
1547
+ }
1548
+ const collapsibleId = idRef.current;
1549
+ const contentId = `sidebar-collapsible-${collapsibleId}`;
1550
+ const matchKey = matchPaths.join("|");
1551
+ const isRouteMatch = useMemo2(
1552
+ () => computeRouteMatch(pathname, matchPaths),
1553
+ [pathname, matchKey, matchPaths]
1554
+ );
1555
+ const prevMatchRef = useRef2(isRouteMatch);
1556
+ useEffect2(() => {
1557
+ if (prevMatchRef.current !== isRouteMatch) {
1558
+ prevMatchRef.current = isRouteMatch;
1559
+ if (isRouteMatch) {
1560
+ onExpandedIdChange(collapsibleId);
1561
+ }
1562
+ }
1563
+ }, [isRouteMatch, collapsibleId, onExpandedIdChange]);
1564
+ const mountRef = useRef2(true);
1565
+ useEffect2(() => {
1566
+ if (mountRef.current && isRouteMatch) {
1567
+ onExpandedIdChange(collapsibleId);
1568
+ mountRef.current = false;
1569
+ }
1570
+ }, [isRouteMatch, collapsibleId, onExpandedIdChange]);
1571
+ const isExpanded = expandedId === collapsibleId;
1572
+ const handleToggle = () => {
1573
+ onExpandedIdChange(isExpanded ? null : collapsibleId);
1574
+ };
1575
+ return /* @__PURE__ */ jsxs6(Fragment2, { children: [
1576
+ /* @__PURE__ */ jsxs6(
1577
+ HeaderButton,
1578
+ {
1579
+ type: "button",
1580
+ onClick: handleToggle,
1581
+ "data-id": dataId,
1582
+ "aria-expanded": isExpanded,
1583
+ "aria-controls": contentId,
1584
+ $itemHeight: sizing.itemHeight,
1585
+ $padding: sizing.padding,
1586
+ $radius: sizing.radius,
1587
+ $color: theme.colors.content.tertiary,
1588
+ $hoverBg: theme.colors.control.mono.secondary.bgHover,
1589
+ $focusOutline: theme.colors.border.brand,
1590
+ $focusOutlineWidth: sizing.focusOutlineWidth,
1591
+ children: [
1592
+ icon && /* @__PURE__ */ jsx12(IconBox2, { $size: sizing.iconSize, children: icon }),
1593
+ /* @__PURE__ */ jsx12(LabelBox2, { children: /* @__PURE__ */ jsx12(Typography4, { variant: "bodySmAccent", color: "inherit", noWrap: true, children: label }) }),
1594
+ /* @__PURE__ */ jsx12(ChevronBox, { $size: sizing.chevronSize, children: isExpanded ? /* @__PURE__ */ jsx12(ChevronUp, { size: 14, variant: "solid" }) : /* @__PURE__ */ jsx12(ChevronRight, { size: 14, variant: "solid" }) })
1595
+ ]
1596
+ }
1597
+ ),
1598
+ /* @__PURE__ */ jsx12(
1599
+ ExpandRegion,
1600
+ {
1601
+ id: contentId,
1602
+ role: "region",
1603
+ $expanded: isExpanded,
1604
+ $transition: sizing.transitionRows,
1605
+ $padding: sizing.padding,
1606
+ $nestedPaddingLeft: sizing.nestedItemPaddingLeft,
1607
+ $railLeft: sizing.nestedItemRailLeft,
1608
+ $railColor: theme.colors.border.secondary,
1609
+ $colorActive: theme.colors.content.primary,
1610
+ $activeBg: theme.colors.overlay.mono,
1611
+ $activeOutline: theme.colors.border.secondary,
1612
+ children: /* @__PURE__ */ jsx12("div", { children })
1613
+ }
1614
+ )
1615
+ ] });
1616
+ };
1617
+
1618
+ // src/SidebarMenuSub.tsx
1619
+ import { Fragment as Fragment3, jsx as jsx13 } from "react/jsx-runtime";
1620
+ var SidebarMenuSub = ({
1621
+ children
1622
+ }) => /* @__PURE__ */ jsx13(Fragment3, { children });
1623
+
1624
+ // src/SidebarChatButton.tsx
1625
+ import styled7 from "styled-components";
1626
+ import { useResolvedTheme as useResolvedTheme9 } from "@xsolla/xui-core";
1627
+ import { Typography as Typography5 } from "@xsolla/xui-typography";
1628
+ import { ChatTwoMessages as ChatTwoMessages2 } from "@xsolla/xui-icons-base";
1629
+ import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
1630
+ var ChatButton = styled7.button`
1631
+ display: flex;
1632
+ height: ${(p) => p.$height}px;
1633
+ align-items: center;
1634
+ gap: 8px;
1635
+ padding: 0 ${(p) => p.$padding}px;
1636
+ border: 1px solid ${(p) => p.$border};
1637
+ border-radius: ${(p) => p.$radius}px;
1638
+ background: ${(p) => p.$bg};
1639
+ color: ${(p) => p.$color};
1640
+ cursor: pointer;
1641
+ font: inherit;
1642
+ position: relative;
1643
+
1644
+ &:hover {
1645
+ opacity: 0.9;
1646
+ }
1647
+
1648
+ &:focus-visible {
1649
+ outline: ${(p) => p.$focusOutlineWidth}px solid ${(p) => p.$focusOutline};
1650
+ outline-offset: 2px;
1651
+ }
1652
+
1653
+ svg {
1654
+ width: 16px;
1655
+ height: 16px;
1656
+ }
1657
+ `;
1658
+ var Badge = styled7.span`
1659
+ position: absolute;
1660
+ top: -2px;
1661
+ right: -2px;
1662
+ width: ${(p) => p.$size}px;
1663
+ height: ${(p) => p.$size}px;
1664
+ background: ${(p) => p.$color};
1665
+ border-radius: 999px;
1666
+ `;
1667
+ var SidebarChatButton = ({
1668
+ onClick,
1669
+ badge
1670
+ }) => {
1671
+ const { theme } = useResolvedTheme9();
1672
+ const sizing = theme.sizing.sidebar();
1673
+ return /* @__PURE__ */ jsxs7(
1674
+ ChatButton,
1675
+ {
1676
+ onClick,
1677
+ type: "button",
1678
+ $height: sizing.itemHeight,
1679
+ $padding: sizing.padding,
1680
+ $radius: sizing.radius,
1681
+ $bg: theme.colors.control.brand.primary.bg,
1682
+ $border: theme.colors.control.brand.primary.border,
1683
+ $color: theme.colors.content.static.dark,
1684
+ $focusOutline: theme.colors.border.brand,
1685
+ $focusOutlineWidth: sizing.focusOutlineWidth,
1686
+ children: [
1687
+ /* @__PURE__ */ jsx14(ChatTwoMessages2, { size: 16, variant: "line" }),
1688
+ /* @__PURE__ */ jsx14(Typography5, { variant: "bodySmAccent", color: "inherit", children: "Chat" }),
1689
+ badge && /* @__PURE__ */ jsx14(
1690
+ Badge,
1691
+ {
1692
+ $size: sizing.chatBadgeSize,
1693
+ $color: theme.colors.background.alert.primary
1694
+ }
1695
+ )
1696
+ ]
1697
+ }
1698
+ );
1699
+ };
1700
+ export {
1701
+ Sidebar,
1702
+ SidebarChatButton,
1703
+ SidebarCollapsed,
1704
+ SidebarContent,
1705
+ SidebarFooter,
1706
+ SidebarGroup,
1707
+ SidebarMenu,
1708
+ SidebarMenuCollapsible,
1709
+ SidebarMenuItem,
1710
+ SidebarMenuSub,
1711
+ SidebarProvider,
1712
+ SidebarTrigger,
1713
+ useSidebar
1714
+ };
1715
+ //# sourceMappingURL=index.mjs.map