@xsolla/xui-b2b-sidebar 0.158.0 → 0.160.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/web/index.d.mts CHANGED
@@ -16,7 +16,10 @@ interface SidebarLinkProps {
16
16
  isActive?: SidebarLinkActiveCheck;
17
17
  onClick?: SidebarLinkClickHandler;
18
18
  dataId?: string;
19
+ "aria-label"?: string;
19
20
  children: ReactNode;
21
+ /** Test ID for testing frameworks */
22
+ testID?: string;
20
23
  }
21
24
  interface SidebarContextValue {
22
25
  collapsed: boolean;
@@ -32,6 +35,8 @@ interface SidebarProviderProps {
32
35
  pathname?: string;
33
36
  linkComponent?: React.ComponentType<SidebarLinkProps>;
34
37
  children: ReactNode;
38
+ /** Test ID for testing frameworks */
39
+ testID?: string;
35
40
  }
36
41
  declare const SidebarProvider: React.FC<SidebarProviderProps>;
37
42
  declare const useSidebar: () => SidebarContextValue;
@@ -104,6 +109,8 @@ interface SidebarProps {
104
109
  /** Whether the chat button shows a notification badge */
105
110
  chatBadge?: boolean;
106
111
  children: ReactNode;
112
+ /** Test ID for testing frameworks */
113
+ testID?: string;
107
114
  }
108
115
  declare const Sidebar: React.FC<SidebarProps>;
109
116
 
@@ -123,6 +130,8 @@ interface SidebarGroupProps {
123
130
  /** Docks this group to the bottom of the expanded sidebar (e.g. Settings, Billing). */
124
131
  pinnedToBottom?: boolean;
125
132
  children: ReactNode;
133
+ /** Test ID for testing frameworks */
134
+ testID?: string;
126
135
  }
127
136
  declare const SidebarGroup: React.FC<SidebarGroupProps>;
128
137
 
@@ -153,6 +162,8 @@ interface SidebarMenuItemProps {
153
162
  extra?: ReactNode;
154
163
  /** Whether this item is inside a SidebarMenuSub (parent collapsible sets nested styling) */
155
164
  isNested?: boolean;
165
+ /** Test ID for testing frameworks */
166
+ testID?: string;
156
167
  }
157
168
  declare const SidebarMenuItem: React.FC<SidebarMenuItemProps>;
158
169
 
@@ -163,6 +174,8 @@ interface SidebarMenuCollapsibleProps {
163
174
  /** Route prefixes that should auto-expand this collapsible */
164
175
  matchPaths?: string[];
165
176
  children: ReactNode;
177
+ /** Test ID for testing frameworks */
178
+ testID?: string;
166
179
  }
167
180
  declare const SidebarMenuCollapsible: React.FC<SidebarMenuCollapsibleProps>;
168
181
 
@@ -178,6 +191,8 @@ declare const SidebarMenuSub: React.FC<{
178
191
  interface SidebarChatButtonProps {
179
192
  onClick?: () => void;
180
193
  badge?: boolean;
194
+ /** Test ID for testing frameworks */
195
+ testID?: string;
181
196
  }
182
197
  declare const SidebarChatButton: React.FC<SidebarChatButtonProps>;
183
198
 
@@ -189,6 +204,8 @@ interface SidebarCollapsedProps {
189
204
  onChatClick?: () => void;
190
205
  showChat?: boolean;
191
206
  chatBadge?: boolean;
207
+ /** Test ID for testing frameworks */
208
+ testID?: string;
192
209
  }
193
210
  declare const SidebarCollapsed: React.FC<SidebarCollapsedProps>;
194
211
 
@@ -210,6 +227,8 @@ interface SidebarPinnedListProps {
210
227
  onReorder?: (fromKey: string, toKey: string) => void;
211
228
  /** Render 8px top/bottom spacers when items are present. Default true. */
212
229
  spacers?: boolean;
230
+ /** Test ID for testing frameworks */
231
+ testID?: string;
213
232
  }
214
233
  /**
215
234
  * Renders the pinned shortcuts list with pointer-event-based drag-and-drop
package/web/index.d.ts CHANGED
@@ -16,7 +16,10 @@ interface SidebarLinkProps {
16
16
  isActive?: SidebarLinkActiveCheck;
17
17
  onClick?: SidebarLinkClickHandler;
18
18
  dataId?: string;
19
+ "aria-label"?: string;
19
20
  children: ReactNode;
21
+ /** Test ID for testing frameworks */
22
+ testID?: string;
20
23
  }
21
24
  interface SidebarContextValue {
22
25
  collapsed: boolean;
@@ -32,6 +35,8 @@ interface SidebarProviderProps {
32
35
  pathname?: string;
33
36
  linkComponent?: React.ComponentType<SidebarLinkProps>;
34
37
  children: ReactNode;
38
+ /** Test ID for testing frameworks */
39
+ testID?: string;
35
40
  }
36
41
  declare const SidebarProvider: React.FC<SidebarProviderProps>;
37
42
  declare const useSidebar: () => SidebarContextValue;
@@ -104,6 +109,8 @@ interface SidebarProps {
104
109
  /** Whether the chat button shows a notification badge */
105
110
  chatBadge?: boolean;
106
111
  children: ReactNode;
112
+ /** Test ID for testing frameworks */
113
+ testID?: string;
107
114
  }
108
115
  declare const Sidebar: React.FC<SidebarProps>;
109
116
 
@@ -123,6 +130,8 @@ interface SidebarGroupProps {
123
130
  /** Docks this group to the bottom of the expanded sidebar (e.g. Settings, Billing). */
124
131
  pinnedToBottom?: boolean;
125
132
  children: ReactNode;
133
+ /** Test ID for testing frameworks */
134
+ testID?: string;
126
135
  }
127
136
  declare const SidebarGroup: React.FC<SidebarGroupProps>;
128
137
 
@@ -153,6 +162,8 @@ interface SidebarMenuItemProps {
153
162
  extra?: ReactNode;
154
163
  /** Whether this item is inside a SidebarMenuSub (parent collapsible sets nested styling) */
155
164
  isNested?: boolean;
165
+ /** Test ID for testing frameworks */
166
+ testID?: string;
156
167
  }
157
168
  declare const SidebarMenuItem: React.FC<SidebarMenuItemProps>;
158
169
 
@@ -163,6 +174,8 @@ interface SidebarMenuCollapsibleProps {
163
174
  /** Route prefixes that should auto-expand this collapsible */
164
175
  matchPaths?: string[];
165
176
  children: ReactNode;
177
+ /** Test ID for testing frameworks */
178
+ testID?: string;
166
179
  }
167
180
  declare const SidebarMenuCollapsible: React.FC<SidebarMenuCollapsibleProps>;
168
181
 
@@ -178,6 +191,8 @@ declare const SidebarMenuSub: React.FC<{
178
191
  interface SidebarChatButtonProps {
179
192
  onClick?: () => void;
180
193
  badge?: boolean;
194
+ /** Test ID for testing frameworks */
195
+ testID?: string;
181
196
  }
182
197
  declare const SidebarChatButton: React.FC<SidebarChatButtonProps>;
183
198
 
@@ -189,6 +204,8 @@ interface SidebarCollapsedProps {
189
204
  onChatClick?: () => void;
190
205
  showChat?: boolean;
191
206
  chatBadge?: boolean;
207
+ /** Test ID for testing frameworks */
208
+ testID?: string;
192
209
  }
193
210
  declare const SidebarCollapsed: React.FC<SidebarCollapsedProps>;
194
211
 
@@ -210,6 +227,8 @@ interface SidebarPinnedListProps {
210
227
  onReorder?: (fromKey: string, toKey: string) => void;
211
228
  /** Render 8px top/bottom spacers when items are present. Default true. */
212
229
  spacers?: boolean;
230
+ /** Test ID for testing frameworks */
231
+ testID?: string;
213
232
  }
214
233
  /**
215
234
  * Renders the pinned shortcuts list with pointer-event-based drag-and-drop
package/web/index.js CHANGED
@@ -62,7 +62,9 @@ var DefaultLink = ({
62
62
  className,
63
63
  children,
64
64
  dataId,
65
- onClick
65
+ testID,
66
+ onClick,
67
+ "aria-label": ariaLabel
66
68
  }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
67
69
  "a",
68
70
  {
@@ -71,6 +73,8 @@ var DefaultLink = ({
71
73
  target: external ? target ?? "_blank" : target ?? void 0,
72
74
  rel: external ? "noopener noreferrer" : void 0,
73
75
  "data-id": dataId,
76
+ "data-testid": testID,
77
+ "aria-label": ariaLabel,
74
78
  onClick,
75
79
  children
76
80
  }
@@ -420,6 +424,62 @@ var SingleLinkWrap = import_styled_components.default.div`
420
424
  text-decoration: none;
421
425
  }
422
426
  `;
427
+ var CollapsedIconLinkWrap = import_styled_components.default.div`
428
+ width: ${(p) => p.$size}px;
429
+ height: ${(p) => p.$size}px;
430
+ flex-shrink: 0;
431
+
432
+ & > a,
433
+ & > * {
434
+ display: flex;
435
+ width: 100%;
436
+ height: 100%;
437
+ align-items: center;
438
+ justify-content: center;
439
+ border: 0;
440
+ border-radius: ${(p) => p.$radius}px;
441
+ background: ${(p) => p.$active ? p.$activeBg : "transparent"};
442
+ color: ${(p) => p.$active ? p.$hoverColor : p.$color};
443
+ cursor: pointer;
444
+ padding: 0;
445
+ font: inherit;
446
+ text-decoration: none;
447
+ transition:
448
+ background-color 0.15s ease-in-out,
449
+ color 0.15s ease-in-out;
450
+
451
+ ${(p) => p.$active && `
452
+ outline: 1px solid ${p.$activeOutline};
453
+ outline-offset: -1px;
454
+ `}
455
+ }
456
+
457
+ & > a:hover,
458
+ & > *:hover {
459
+ background-color: ${(p) => p.$hoverBg};
460
+ color: ${(p) => p.$hoverColor};
461
+ }
462
+
463
+ & > a:focus-visible,
464
+ & > *:focus-visible {
465
+ outline: ${(p) => p.$focusOutlineWidth}px solid ${(p) => p.$focusOutline};
466
+ outline-offset: -${(p) => p.$focusOutlineWidth}px;
467
+ }
468
+
469
+ & > a > span,
470
+ & > * > span {
471
+ display: flex;
472
+ width: ${(p) => p.$iconSize}px;
473
+ height: ${(p) => p.$iconSize}px;
474
+ align-items: center;
475
+ justify-content: center;
476
+
477
+ svg {
478
+ width: ${(p) => p.$iconSize}px;
479
+ height: ${(p) => p.$iconSize}px;
480
+ }
481
+ }
482
+ `;
423
483
  var isChildActive = (item, pathname) => {
424
484
  if (!item.children || !pathname) {
425
485
  return false;
@@ -434,6 +494,7 @@ var isChildActive = (item, pathname) => {
434
494
  };
435
495
  var CollapsedIconItem = ({ item, onPopoverOpen, onPopoverClose, pathname, sizing, colors }) => {
436
496
  const ref = (0, import_react2.useRef)(null);
497
+ const { LinkComponent } = useSidebar();
437
498
  const hasChildren = Boolean(item.children && item.children.length > 0);
438
499
  const isActive = hasChildren && isChildActive(item, pathname);
439
500
  const openPopover = (0, import_react2.useCallback)(() => {
@@ -459,6 +520,42 @@ var CollapsedIconItem = ({ item, onPopoverOpen, onPopoverClose, pathname, sizing
459
520
  if (!item.icon) {
460
521
  return null;
461
522
  }
523
+ if (!hasChildren) {
524
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
525
+ CollapsedIconLinkWrap,
526
+ {
527
+ ref,
528
+ onMouseEnter: openPopover,
529
+ onMouseLeave: onPopoverClose,
530
+ onFocus: openPopover,
531
+ onBlur: onPopoverClose,
532
+ "data-id": item.dataId,
533
+ $size: sizing.itemHeight,
534
+ $radius: sizing.radius,
535
+ $iconSize: sizing.iconSize,
536
+ $color: colors.content.tertiary,
537
+ $hoverBg: colors.overlay.mono,
538
+ $hoverColor: colors.content.primary,
539
+ $activeBg: colors.overlay.mono,
540
+ $activeOutline: colors.border.secondary,
541
+ $focusOutline: colors.border.brand,
542
+ $focusOutlineWidth: sizing.focusOutlineWidth,
543
+ $active: isSimpleActive,
544
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
545
+ LinkComponent,
546
+ {
547
+ to: item.to,
548
+ exact: item.exact,
549
+ external: item.external,
550
+ target: item.target,
551
+ dataId: item.dataId,
552
+ "aria-label": typeof item.label === "string" ? item.label : void 0,
553
+ children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: item.icon })
554
+ }
555
+ )
556
+ }
557
+ );
558
+ }
462
559
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
463
560
  IconBtn,
464
561
  {
@@ -470,7 +567,7 @@ var CollapsedIconItem = ({ item, onPopoverOpen, onPopoverClose, pathname, sizing
470
567
  onBlur: onPopoverClose,
471
568
  onKeyDown: handleKeyDown,
472
569
  "data-id": item.dataId,
473
- "aria-haspopup": hasChildren ? "menu" : "false",
570
+ "aria-haspopup": "menu",
474
571
  $size: sizing.itemHeight,
475
572
  $radius: sizing.radius,
476
573
  $iconSize: sizing.iconSize,