@redocly/theme 0.70.0-next.3 → 0.70.0-next.5

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.
Files changed (123) hide show
  1. package/lib/components/Catalog/Catalog.js +1 -1
  2. package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.d.ts +1 -1
  3. package/lib/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.js +2 -2
  4. package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +1 -1
  5. package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.js +30 -11
  6. package/lib/components/Catalog/CatalogMobileFiltersPanel/CatalogMobileFiltersPanel.js +1 -1
  7. package/lib/components/Catalog/CatalogMobileFiltersPanel/CatalogMobileFiltersPanelOverlay.js +2 -2
  8. package/lib/components/Dropdown/Dropdown.js +3 -1
  9. package/lib/components/Dropdown/DropdownMenu.d.ts +1 -0
  10. package/lib/components/Dropdown/DropdownMenu.js +1 -1
  11. package/lib/components/Feedback/Reasons.js +3 -2
  12. package/lib/components/Filter/FilterCheckboxes.js +30 -11
  13. package/lib/components/Image/Image.js +24 -4
  14. package/lib/components/Markdown/Markdown.js +3 -2
  15. package/lib/components/Menu/Menu.js +4 -0
  16. package/lib/components/Menu/MenuSelect.d.ts +7 -0
  17. package/lib/components/Menu/MenuSelect.js +129 -0
  18. package/lib/components/Menu/variables.js +43 -4
  19. package/lib/components/Navbar/Navbar.js +44 -5
  20. package/lib/components/Navbar/variables.js +3 -0
  21. package/lib/components/NavigationTabs/NavigationTab.d.ts +7 -0
  22. package/lib/components/NavigationTabs/NavigationTab.js +93 -0
  23. package/lib/components/NavigationTabs/NavigationTabContent.d.ts +7 -0
  24. package/lib/components/NavigationTabs/NavigationTabContent.js +50 -0
  25. package/lib/components/NavigationTabs/NavigationTabMenu.d.ts +7 -0
  26. package/lib/components/NavigationTabs/NavigationTabMenu.js +18 -0
  27. package/lib/components/NavigationTabs/NavigationTabs.d.ts +7 -0
  28. package/lib/components/NavigationTabs/NavigationTabs.js +97 -0
  29. package/lib/components/NavigationTabs/variables.d.ts +1 -0
  30. package/lib/components/NavigationTabs/variables.js +37 -0
  31. package/lib/components/Search/SearchTrigger.js +8 -2
  32. package/lib/components/Segmented/Segmented.js +23 -3
  33. package/lib/components/Select/Select.js +10 -3
  34. package/lib/components/Select/SelectInput.d.ts +1 -0
  35. package/lib/components/Select/SelectInput.js +3 -3
  36. package/lib/components/Sidebar/Sidebar.js +2 -2
  37. package/lib/components/TableOfContent/TableOfContent.js +2 -2
  38. package/lib/core/constants/common.d.ts +1 -0
  39. package/lib/core/constants/common.js +1 -0
  40. package/lib/core/hooks/index.d.ts +2 -0
  41. package/lib/core/hooks/index.js +2 -0
  42. package/lib/core/hooks/menu/use-mobile-menu-items.js +75 -51
  43. package/lib/core/hooks/menu/use-mobile-menu-levels.js +12 -7
  44. package/lib/core/hooks/use-scroll-item-into-view.d.ts +2 -0
  45. package/lib/core/hooks/use-scroll-item-into-view.js +16 -0
  46. package/lib/core/hooks/use-tab-list.d.ts +31 -0
  47. package/lib/core/hooks/use-tab-list.js +49 -0
  48. package/lib/core/hooks/use-theme-hooks.js +2 -0
  49. package/lib/core/styles/global.js +12 -2
  50. package/lib/core/types/hooks.d.ts +5 -0
  51. package/lib/core/types/index.d.ts +1 -0
  52. package/lib/core/types/l10n.d.ts +1 -1
  53. package/lib/core/types/navigation-tabs.d.ts +49 -0
  54. package/lib/core/types/navigation-tabs.js +3 -0
  55. package/lib/core/utils/Dynamic.d.ts +8 -1
  56. package/lib/core/utils/Dynamic.js +34 -3
  57. package/lib/core/utils/index.d.ts +1 -0
  58. package/lib/core/utils/index.js +1 -0
  59. package/lib/core/utils/menu.d.ts +4 -0
  60. package/lib/core/utils/menu.js +42 -3
  61. package/lib/core/utils/navigation-tabs.d.ts +8 -0
  62. package/lib/core/utils/navigation-tabs.js +71 -0
  63. package/lib/index.d.ts +5 -0
  64. package/lib/index.js +7 -1
  65. package/lib/layouts/PageLayout.js +1 -1
  66. package/lib/layouts/RootLayout.js +2 -2
  67. package/lib/markdoc/components/CodeWalkthrough/CodeFilters.js +1 -1
  68. package/lib/markdoc/components/CodeWalkthrough/CodePanel.js +3 -3
  69. package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.js +1 -1
  70. package/package.json +3 -3
  71. package/src/components/Catalog/Catalog.tsx +1 -1
  72. package/src/components/Catalog/CatalogEntity/CatalogEntityHistory/CatalogEntityHistorySidebar.tsx +2 -2
  73. package/src/components/Catalog/CatalogEntity/CatalogEntitySchema.tsx +1 -1
  74. package/src/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.tsx +37 -22
  75. package/src/components/Catalog/CatalogMobileFiltersPanel/CatalogMobileFiltersPanel.tsx +1 -1
  76. package/src/components/Catalog/CatalogMobileFiltersPanel/CatalogMobileFiltersPanelOverlay.tsx +2 -2
  77. package/src/components/Dropdown/Dropdown.tsx +4 -1
  78. package/src/components/Dropdown/DropdownMenu.tsx +7 -1
  79. package/src/components/Feedback/Reasons.tsx +3 -2
  80. package/src/components/Filter/FilterCheckboxes.tsx +33 -18
  81. package/src/components/Image/Image.tsx +26 -5
  82. package/src/components/Markdown/Markdown.tsx +3 -2
  83. package/src/components/Menu/Menu.tsx +5 -0
  84. package/src/components/Menu/MenuSelect.tsx +198 -0
  85. package/src/components/Menu/variables.ts +43 -4
  86. package/src/components/Navbar/Navbar.tsx +22 -5
  87. package/src/components/Navbar/variables.ts +3 -0
  88. package/src/components/NavigationTabs/NavigationTab.tsx +148 -0
  89. package/src/components/NavigationTabs/NavigationTabContent.tsx +66 -0
  90. package/src/components/NavigationTabs/NavigationTabMenu.tsx +40 -0
  91. package/src/components/NavigationTabs/NavigationTabs.tsx +83 -0
  92. package/src/components/NavigationTabs/variables.ts +34 -0
  93. package/src/components/Search/SearchTrigger.tsx +11 -2
  94. package/src/components/Segmented/Segmented.tsx +25 -16
  95. package/src/components/Select/Select.tsx +12 -6
  96. package/src/components/Select/SelectInput.tsx +8 -10
  97. package/src/components/Sidebar/Sidebar.tsx +2 -2
  98. package/src/components/TableOfContent/TableOfContent.tsx +2 -2
  99. package/src/core/constants/common.ts +1 -0
  100. package/src/core/hooks/__mocks__/use-theme-hooks.ts +3 -0
  101. package/src/core/hooks/index.ts +2 -0
  102. package/src/core/hooks/menu/use-mobile-menu-items.ts +91 -56
  103. package/src/core/hooks/menu/use-mobile-menu-levels.ts +14 -6
  104. package/src/core/hooks/use-scroll-item-into-view.ts +18 -0
  105. package/src/core/hooks/use-tab-list.ts +63 -0
  106. package/src/core/hooks/use-theme-hooks.ts +2 -0
  107. package/src/core/styles/global.ts +12 -2
  108. package/src/core/types/hooks.ts +5 -0
  109. package/src/core/types/index.ts +1 -0
  110. package/src/core/types/l10n.ts +3 -0
  111. package/src/core/types/navigation-tabs.ts +54 -0
  112. package/src/core/utils/Dynamic.tsx +67 -35
  113. package/src/core/utils/index.ts +1 -0
  114. package/src/core/utils/menu.ts +49 -3
  115. package/src/core/utils/navigation-tabs.ts +99 -0
  116. package/src/icons/CheckboxIcon/CheckboxIcon.tsx +1 -0
  117. package/src/icons/ChevronSortIcon/ChevronSortIcon.tsx +1 -0
  118. package/src/index.ts +6 -0
  119. package/src/layouts/PageLayout.tsx +1 -1
  120. package/src/layouts/RootLayout.tsx +2 -2
  121. package/src/markdoc/components/CodeWalkthrough/CodeFilters.tsx +1 -1
  122. package/src/markdoc/components/CodeWalkthrough/CodePanel.tsx +3 -3
  123. package/src/markdoc/components/CodeWalkthrough/CodeWalkthrough.tsx +1 -1
@@ -0,0 +1,66 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { NavigationTabRowItem } from '@redocly/theme/core/types';
6
+
7
+ import { useThemeHooks } from '@redocly/theme/core/hooks';
8
+ import { GenericIcon } from '@redocly/theme/icons/GenericIcon/GenericIcon';
9
+ import { LaunchIcon } from '@redocly/theme/icons/LaunchIcon/LaunchIcon';
10
+
11
+ export type NavigationTabContentProps = {
12
+ item: NavigationTabRowItem;
13
+ className?: string;
14
+ };
15
+
16
+ export function NavigationTabContent({ item, className }: NavigationTabContentProps): JSX.Element {
17
+ const { useTranslate } = useThemeHooks();
18
+ const { translate } = useTranslate();
19
+ const label = translate(item.labelTranslationKey, item.label);
20
+
21
+ return (
22
+ <NavigationTabContentWrapper
23
+ data-component-name="NavigationTabs/NavigationTabContent"
24
+ className={className}
25
+ >
26
+ {(item.icon || item.srcSet) && <NavigationTabIcon icon={item.icon} srcSet={item.srcSet} />}
27
+ <NavigationTabLabel data-label={label} data-translation-key={item.labelTranslationKey}>
28
+ {label}
29
+ </NavigationTabLabel>
30
+ {'external' in item && item.external ? <NavigationTabExternalIcon size="10px" /> : null}
31
+ </NavigationTabContentWrapper>
32
+ );
33
+ }
34
+
35
+ const NavigationTabContentWrapper = styled.span`
36
+ display: inline-flex;
37
+ align-items: center;
38
+ gap: var(--navigation-tabs-item-content-gap);
39
+ `;
40
+
41
+ const NavigationTabIcon = styled(GenericIcon)`
42
+ --icon-width: var(--navigation-tabs-item-icon-size);
43
+ --icon-height: var(--navigation-tabs-item-icon-size);
44
+ flex-shrink: 0;
45
+ `;
46
+
47
+ const NavigationTabLabel = styled.span`
48
+ display: inline-flex;
49
+ flex-direction: column;
50
+ cursor: pointer;
51
+ vertical-align: middle;
52
+
53
+ &::after {
54
+ content: attr(data-label);
55
+ height: 0;
56
+ overflow: hidden;
57
+ visibility: hidden;
58
+ pointer-events: none;
59
+ font-weight: var(--navigation-tabs-item-label-font-weight-active);
60
+ }
61
+ `;
62
+
63
+ const NavigationTabExternalIcon = styled(LaunchIcon)`
64
+ margin-left: var(--navigation-tabs-item-external-icon-margin-left);
65
+ flex-shrink: 0;
66
+ `;
@@ -0,0 +1,40 @@
1
+ import React from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { NavigationTabItem } from '@redocly/theme/core/types';
6
+
7
+ import { DropdownMenu } from '@redocly/theme/components/Dropdown/DropdownMenu';
8
+ import { DropdownMenuItem } from '@redocly/theme/components/Dropdown/DropdownMenuItem';
9
+ import { NavigationTabContent } from '@redocly/theme/components/NavigationTabs/NavigationTabContent';
10
+
11
+ export type NavigationTabMenuProps = {
12
+ items: NavigationTabItem[];
13
+ className?: string;
14
+ };
15
+
16
+ export function NavigationTabMenu({ items, className }: NavigationTabMenuProps): JSX.Element {
17
+ return (
18
+ <NavigationTabMenuWrapper
19
+ data-component-name="NavigationTabs/NavigationTabMenu"
20
+ className={className}
21
+ >
22
+ <DropdownMenu>
23
+ {items.map((item, index) => (
24
+ <DropdownMenuItem
25
+ key={`${item.label}_${index}`}
26
+ to={item.link}
27
+ external={item.external}
28
+ data-translation-key={item.labelTranslationKey}
29
+ active={item.active}
30
+ aria-current={item.active ? 'page' : undefined}
31
+ >
32
+ <NavigationTabContent item={item} />
33
+ </DropdownMenuItem>
34
+ ))}
35
+ </DropdownMenu>
36
+ </NavigationTabMenuWrapper>
37
+ );
38
+ }
39
+
40
+ const NavigationTabMenuWrapper = styled.div``;
@@ -0,0 +1,83 @@
1
+ import React, { useRef } from 'react';
2
+ import styled from 'styled-components';
3
+
4
+ import type { JSX } from 'react';
5
+ import type { NavigationTabsConfig } from '@redocly/theme/core/types';
6
+
7
+ import { breakpoints } from '@redocly/theme/core/utils';
8
+ import { useScrollItemIntoView, useThemeHooks } from '@redocly/theme/core/hooks';
9
+ import { NavigationTab } from '@redocly/theme/components/NavigationTabs/NavigationTab';
10
+
11
+ export type NavigationTabsProps = {
12
+ config?: NavigationTabsConfig;
13
+ className?: string;
14
+ };
15
+
16
+ export function NavigationTabs({ config, className }: NavigationTabsProps): JSX.Element | null {
17
+ const { useTranslate } = useThemeHooks();
18
+ const { translate } = useTranslate();
19
+ const listRef = useRef<HTMLUListElement | null>(null);
20
+
21
+ const tabs = config?.items ?? [];
22
+ const activeIndex = tabs.findIndex((tab) => tab.active);
23
+
24
+ useScrollItemIntoView(listRef, activeIndex);
25
+
26
+ if (!tabs.length) {
27
+ return null;
28
+ }
29
+
30
+ return (
31
+ <NavigationTabsWrapper
32
+ data-component-name="NavigationTabs/NavigationTabs"
33
+ className={className}
34
+ aria-label={translate('navigationTabs.label', 'Navigation tabs')}
35
+ >
36
+ <NavigationTabsList ref={listRef}>
37
+ {tabs.map((tab, index) => (
38
+ <NavigationTab key={`${tab.label}_${index}`} tab={tab} />
39
+ ))}
40
+ </NavigationTabsList>
41
+ </NavigationTabsWrapper>
42
+ );
43
+ }
44
+
45
+ const NavigationTabsWrapper = styled.nav`
46
+ display: none;
47
+ box-sizing: border-box;
48
+ width: 100%;
49
+ height: var(--navigation-tabs-height);
50
+ max-width: var(--navbar-container-max-width);
51
+ padding: var(--navigation-tabs-padding);
52
+ background: var(--navigation-tabs-bg-color);
53
+ border-bottom: var(--navigation-tabs-bottom-border);
54
+ flex-shrink: 0;
55
+
56
+ @media screen and (min-width: ${breakpoints.medium}) {
57
+ display: flex;
58
+ }
59
+
60
+ @media screen and (min-width: ${breakpoints.max}) {
61
+ max-width: var(--container-max-width);
62
+ margin-left: auto;
63
+ margin-right: auto;
64
+ }
65
+ `;
66
+
67
+ const NavigationTabsList = styled.ul`
68
+ list-style: none;
69
+ margin: 0 0 calc(-1 * var(--navigation-tabs-border-width));
70
+ padding: 0;
71
+ display: flex;
72
+ flex-wrap: nowrap;
73
+ align-items: stretch;
74
+ gap: var(--navigation-tabs-gap);
75
+ min-width: 0;
76
+ overflow-x: auto;
77
+ scrollbar-width: none;
78
+ -ms-overflow-style: none;
79
+
80
+ &::-webkit-scrollbar {
81
+ display: none;
82
+ }
83
+ `;
@@ -0,0 +1,34 @@
1
+ import { css } from 'styled-components';
2
+
3
+ export const navigationTabs = css`
4
+ --navigation-tabs-height: 48px; // @presenter Spacing
5
+ --navigation-tabs-bg-color: transparent; // @presenter Color
6
+ --navigation-tabs-border-color: var(--border-color-secondary);
7
+ --navigation-tabs-border-width: 1px;
8
+ --navigation-tabs-bottom-border: var(--navigation-tabs-border-width) solid var(--navigation-tabs-border-color);
9
+ --navigation-tabs-padding-vertical: 0;
10
+ --navigation-tabs-padding-horizontal: var(--spacing-xl);
11
+ --navigation-tabs-padding: var(--navigation-tabs-padding-vertical) var(--navigation-tabs-padding-horizontal); // @presenter Spacing
12
+ --navigation-tabs-gap: var(--spacing-base); // @presenter Spacing
13
+
14
+ --navigation-tabs-item-padding-vertical: var(--spacing-xxs);
15
+ --navigation-tabs-item-padding-horizontal: 0;
16
+ --navigation-tabs-item-padding: var(--navigation-tabs-item-padding-vertical) var(--navigation-tabs-item-padding-horizontal);
17
+ --navigation-tabs-item-content-gap: var(--spacing-xs);
18
+ --navigation-tabs-item-font-size: var(--font-size-base);
19
+ --navigation-tabs-item-line-height: var(--line-height-base);
20
+ --navigation-tabs-item-font-weight: var(--font-weight-regular);
21
+ --navigation-tabs-item-font-weight-active: var(--font-weight-medium);
22
+ --navigation-tabs-item-text-color: var(--navbar-text-color); // @presenter Color
23
+ --navigation-tabs-item-text-color-hover: var(--text-color-primary); // @presenter Color
24
+ --navigation-tabs-item-text-color-active: var(--text-color-primary); // @presenter Color
25
+ --navigation-tabs-item-bottom-border: var(--navigation-tabs-border-width) solid transparent;
26
+ --navigation-tabs-item-bottom-border-hover: var(--navigation-tabs-border-width) solid var(--border-color-primary);
27
+ --navigation-tabs-item-bottom-border-active: var(--navigation-tabs-border-width) solid var(--border-color-inverse);
28
+ --navigation-tabs-item-border-color-focused: var(--button-border-color-focused);
29
+ --navigation-tabs-item-border-radius: var(--navbar-item-border-radius);
30
+ --navigation-tabs-item-icon-size: 1.25em; // @presenter Spacing
31
+ --navigation-tabs-item-external-icon-margin-left: 0;
32
+ --navigation-tabs-item-label-font-weight-active: var(--navigation-tabs-item-font-weight-active);
33
+ --navigation-tabs-item-transition: 150ms ease-in-out;
34
+ `;
@@ -31,7 +31,10 @@ export function SearchTrigger({ onClick, className }: SearchTriggerProps): JSX.E
31
31
  }
32
32
 
33
33
  mainShortcutKey = mainShortcutKey?.toUpperCase();
34
- const isMac = getUserAgent().includes('Mac');
34
+ // A page can be cached and served to every platform, so the server renders a hidden
35
+ // placeholder and the browser picks the label after hydration.
36
+ const [isMac, setIsMac] = React.useState<boolean | undefined>(undefined);
37
+ React.useEffect(() => setIsMac(getUserAgent().includes('Mac')), []);
35
38
 
36
39
  return (
37
40
  <SearchTriggerWrapper
@@ -53,7 +56,9 @@ export function SearchTrigger({ onClick, className }: SearchTriggerProps): JSX.E
53
56
  <SearchIcon />
54
57
  {translate('search.navbar.label', 'Search')}
55
58
  {mainShortcutKey === DEFAULT_KEYBOARD_SHORTCUTS ? (
56
- <span>{isMac ? '⌘K' : 'Ctrl+K'}</span>
59
+ <SearchTriggerShortcut $isPending={isMac === undefined}>
60
+ {isMac ? '⌘K' : 'Ctrl+K'}
61
+ </SearchTriggerShortcut>
57
62
  ) : (
58
63
  <span>{mainShortcutKey}</span>
59
64
  )}
@@ -80,6 +85,10 @@ const SearchTriggerButton = styled(Button)`
80
85
  }
81
86
  `;
82
87
 
88
+ const SearchTriggerShortcut = styled.span<{ $isPending: boolean }>`
89
+ visibility: ${({ $isPending }) => ($isPending ? 'hidden' : 'visible')};
90
+ `;
91
+
83
92
  const SearchTriggerInput = styled.div`
84
93
  display: none;
85
94
  align-items: center;
@@ -5,34 +5,43 @@ import type { ForwardedRef, ReactElement } from 'react';
5
5
  import type { SegmentedProps } from '@redocly/theme/core/types';
6
6
 
7
7
  import { typedMemo } from '@redocly/theme/core/hoc/typed-memo';
8
+ import { useTabList } from '@redocly/theme/core/hooks';
8
9
 
9
10
  function SegmentedComponent<T>(
10
11
  { options, onChange, value, className = '', size = 'regular' }: SegmentedProps<T>,
11
12
  ref?: ForwardedRef<HTMLDivElement>,
12
13
  ): ReactElement {
14
+ const { tabListProps, getTabProps } = useTabList({
15
+ count: options.length,
16
+ activeIndex: options.findIndex((opt) => value == opt.value),
17
+ onChange: (index) => onChange(options[index]),
18
+ });
19
+
13
20
  return (
14
21
  <SegmentedGroup
15
22
  ref={ref}
16
23
  data-component-name="Segmented/Segmented"
17
24
  className={`tag-grey ${size} ${className}`}
18
- role="tablist"
25
+ {...tabListProps}
19
26
  $size={size}
20
27
  >
21
- {options.map((opt, index) => (
22
- <React.Fragment key={index}>
23
- {opt.divider}
24
- <SegmentedItem
25
- key={opt.label}
26
- role="tab"
27
- title={opt.label}
28
- onClick={() => onChange(opt)}
29
- $isActive={value == opt.value}
30
- $size={size}
31
- >
32
- {opt.element || opt.label}
33
- </SegmentedItem>
34
- </React.Fragment>
35
- ))}
28
+ {options.map((opt, index) => {
29
+ const { 'aria-controls': _noPanel, ...tabProps } = getTabProps(index);
30
+ return (
31
+ <React.Fragment key={index}>
32
+ {opt.divider}
33
+ <SegmentedItem
34
+ key={opt.label}
35
+ {...tabProps}
36
+ title={opt.label}
37
+ $isActive={value == opt.value}
38
+ $size={size}
39
+ >
40
+ {opt.element || opt.label}
41
+ </SegmentedItem>
42
+ </React.Fragment>
43
+ );
44
+ })}
36
45
  </SegmentedGroup>
37
46
  );
38
47
  }
@@ -63,6 +63,7 @@ export function Select<T>(props: SelectProps<T>): JSX.Element {
63
63
  const [filteredOptions, setFilteredOptions] = useState<SelectOption<T>[]>(options);
64
64
  const [stickyInputValue, setStickyInputValue] = useState<string>(placeholder || '');
65
65
  const inputId = useId();
66
+ const listboxId = `${inputId}-listbox`;
66
67
 
67
68
  useOutsideClick(selectRef, () => {
68
69
  setDropdownActive(false);
@@ -189,7 +190,8 @@ export function Select<T>(props: SelectProps<T>): JSX.Element {
189
190
  return (
190
191
  <SelectInput
191
192
  id={inputId}
192
- listboxId={inputId}
193
+ listboxId={listboxId}
194
+ expanded={dropdownActive}
193
195
  selectedOptions={selectedOptions}
194
196
  searchValue={searchValue}
195
197
  placeholder={placeholder}
@@ -223,10 +225,14 @@ export function Select<T>(props: SelectProps<T>): JSX.Element {
223
225
  setDropdownActive(!dropdownActive);
224
226
  }
225
227
  }}
226
- tabIndex={0}
227
- aria-haspopup="listbox"
228
- aria-expanded={dropdownActive}
229
- aria-label="Select option"
228
+ tabIndex={searchable ? undefined : 0}
229
+ {...(!searchable && {
230
+ role: 'combobox',
231
+ 'aria-haspopup': 'listbox' as const,
232
+ 'aria-expanded': dropdownActive,
233
+ 'aria-controls': listboxId,
234
+ 'aria-label': 'Select option',
235
+ })}
230
236
  onFocus={(e) => {
231
237
  if (e.target === selectRef.current) {
232
238
  selectInputRef.current?.focus();
@@ -245,7 +251,7 @@ export function Select<T>(props: SelectProps<T>): JSX.Element {
245
251
  alignment={alignment}
246
252
  active={!renderInput ? dropdownActive : undefined}
247
253
  >
248
- <SelectDropdownMenu role="listbox" footer={footer}>
254
+ <SelectDropdownMenu id={listboxId} role="listbox" footer={footer}>
249
255
  {filteredOptions.length === 0 ? (
250
256
  <DropdownMenuItem disabled>
251
257
  {translate('select.noResults', 'No results')}
@@ -22,6 +22,7 @@ type SelectInputProps<T> = {
22
22
  placeholder?: string;
23
23
  multiple?: boolean;
24
24
  searchable?: boolean;
25
+ expanded?: boolean;
25
26
  clearable?: boolean;
26
27
  inputRef?: React.ForwardedRef<HTMLInputElement>;
27
28
  /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
@@ -48,6 +49,7 @@ export function SelectInput<T>(props: SelectInputProps<T>): React.ReactNode {
48
49
  stickyValue,
49
50
  multiple,
50
51
  searchable,
52
+ expanded,
51
53
  clearable,
52
54
  clearHandler,
53
55
  searchHandler,
@@ -134,6 +136,11 @@ export function SelectInput<T>(props: SelectInputProps<T>): React.ReactNode {
134
136
  }}
135
137
  $width={multiple ? (!searchValue && selectedOptions.length ? '10px' : 'auto') : '100%'}
136
138
  tabIndex={0}
139
+ role="combobox"
140
+ aria-expanded={!!expanded}
141
+ aria-controls={listboxId}
142
+ aria-autocomplete="list"
143
+ aria-label="Select option"
137
144
  onFocus={(e) => {
138
145
  e.stopPropagation();
139
146
  }}
@@ -156,16 +163,7 @@ export function SelectInput<T>(props: SelectInputProps<T>): React.ReactNode {
156
163
  );
157
164
 
158
165
  return (
159
- <SelectInputWrapper
160
- id={id}
161
- onFocus={onFocusHandler}
162
- onClick={onClickHandler}
163
- role="button"
164
- aria-haspopup="listbox"
165
- aria-controls={listboxId}
166
- aria-owns={listboxId}
167
- aria-label="Select option"
168
- >
166
+ <SelectInputWrapper id={id} onFocus={onFocusHandler} onClick={onClickHandler}>
169
167
  {!onlyIcon && (
170
168
  <>
171
169
  <SelectInputValue>
@@ -84,8 +84,8 @@ const SidebarContent = styled.aside<{ $opened: boolean; $collapsed?: boolean }>`
84
84
  flex-direction: column;
85
85
  width: 100%;
86
86
  -webkit-font-smoothing: antialiased;
87
- top: calc(var(--navbar-height) + var(--banner-height));
88
- height: calc(100vh - var(--navbar-height) - var(--banner-height));
87
+ top: var(--navbar-offset);
88
+ height: calc(100vh - var(--navbar-offset));
89
89
  overflow-x: hidden;
90
90
  ${({ $opened }) => `
91
91
  display: ${$opened ? 'flex' : 'none'}
@@ -101,8 +101,8 @@ const TableOfContentHeader = styled.div`
101
101
 
102
102
  const TableOfContentItems = styled.div`
103
103
  position: sticky;
104
- top: calc(var(--navbar-height) + var(--toc-offset-top));
105
- max-height: calc(100vh - var(--navbar-height) - var(--toc-offset-top));
104
+ top: calc(var(--navbar-stack-height) + var(--toc-offset-top));
105
+ max-height: calc(100vh - var(--navbar-stack-height) - var(--toc-offset-top));
106
106
  overflow-y: auto;
107
107
  width: var(--toc-width);
108
108
  border-left: solid 1px var(--toc-border-color);
@@ -18,6 +18,7 @@ export enum FEEDBACK_TYPES {
18
18
  export const DEFAULT_FEEDBACK_TYPE = FEEDBACK_TYPES.SENTIMENT;
19
19
 
20
20
  export enum MenuItemType {
21
+ Select = 'select',
21
22
  Separator = 'separator',
22
23
  DrillDown = 'drilldown',
23
24
  Group = 'group',
@@ -20,6 +20,7 @@ export const useThemeHooks = vi.fn(() => ({
20
20
  sendPageActionsButtonClickedMessage: vi.fn(),
21
21
  sendColorModeSwitchedMessage: vi.fn(),
22
22
  sendConsentChangedMessage: vi.fn(),
23
+ sendFilterCheckboxToggledMessage: vi.fn(),
23
24
  })),
24
25
  useBreadcrumbs: vi.fn().mockReturnValue({ breadcrumbs: [], siblings: undefined }),
25
26
  useBanner: vi.fn(() => ({
@@ -70,6 +71,7 @@ export const useThemeHooks = vi.fn(() => ({
70
71
  items: [],
71
72
  isLoading: false,
72
73
  })),
74
+ useSearchFeatures: vi.fn(() => ({ askAi: false })),
73
75
  useAiSearch: vi.fn(() => ({
74
76
  askQuestion: vi.fn(),
75
77
  isGeneratingResponse: false,
@@ -117,6 +119,7 @@ export const useThemeHooks = vi.fn(() => ({
117
119
  pushDrilldownState: vi.fn(),
118
120
  }),
119
121
  useSidebarSiblingsData: vi.fn(),
122
+ useNavigationTabs: vi.fn(),
120
123
  useSubmitFeedback: vi.fn(() => ({
121
124
  submitFeedback: vi.fn(),
122
125
  })),
@@ -21,6 +21,7 @@ export * from './menu/use-mobile-menu-levels';
21
21
  export * from './menu/use-collapse';
22
22
  export * from './feedback/use-report-dialog';
23
23
  export * from './use-tabs';
24
+ export * from './use-tab-list';
24
25
  export * from './use-focus-trap';
25
26
  export * from './use-consent-dialog';
26
27
  export * from './use-consent-telemetry';
@@ -58,3 +59,4 @@ export * from './use-toast-logic';
58
59
  export * from './use-banner-telemetry';
59
60
  export * from './use-tooltip-fallback-placement';
60
61
  export * from './use-anchor-positioning';
62
+ export * from './use-scroll-item-into-view';