@redocly/theme 0.59.0-next.1 → 0.59.0-next.3
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/LICENSE +7 -1
- package/lib/components/Accordion/Accordion.js +17 -7
- package/lib/components/Accordion/AccordionBody.js +17 -7
- package/lib/components/Admonition/Admonition.js +17 -7
- package/lib/components/Badge/Badge.js +17 -7
- package/lib/components/Breadcrumbs/Breadcrumb.js +17 -7
- package/lib/components/Breadcrumbs/BreadcrumbDropdown.js +17 -7
- package/lib/components/Button/Button.js +17 -7
- package/lib/components/Buttons/AIAssistantButton.js +17 -7
- package/lib/components/Buttons/CopyButton.js +17 -7
- package/lib/components/Catalog/Catalog.d.ts +6 -0
- package/lib/components/Catalog/Catalog.js +7 -6
- package/lib/components/Catalog/CatalogEntities.js +17 -7
- package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.js +17 -7
- package/lib/components/Catalog/CatalogEntity/CatalogEntityGraph/CatalogEntityRelationsGraph.lazy.js +17 -7
- package/lib/components/Catalog/CatalogEntity/CatalogEntityMetadata.js +17 -7
- package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityApiDescriptionRelations.js +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityRelations.js +17 -7
- package/lib/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations.js +1 -1
- package/lib/components/Catalog/CatalogEntity/CatalogEntitySchema.js +17 -7
- package/lib/components/Catalog/CatalogFilter/CatalogFilterCheckboxes.js +17 -7
- package/lib/components/Catalog/CatalogFilter/CatalogFilterContent.js +17 -7
- package/lib/components/Catalog/CatalogFilter/CatalogFilterDateRange.js +17 -7
- package/lib/components/Catalog/CatalogFilter/CatalogFilterSelect.js +17 -7
- package/lib/components/Catalog/CatalogSortButton.js +17 -7
- package/lib/components/Catalog/CatalogTableView/CatalogTableHeaderCell.js +17 -7
- package/lib/components/Catalog/CatalogViewModeToggle.js +17 -7
- package/lib/components/CatalogClassic/CatalogClassicActions.js +17 -7
- package/lib/components/CatalogClassic/CatalogClassicCard.js +17 -7
- package/lib/components/CatalogClassic/CatalogClassicHighlight.js +17 -7
- package/lib/components/CatalogClassic/CatalogClassicVirtualizedGroups.js +17 -7
- package/lib/components/CodeBlock/CodeBlock.js +17 -7
- package/lib/components/CodeBlock/CodeBlockContainer.js +17 -7
- package/lib/components/CodeBlock/CodeBlockTabs.js +17 -7
- package/lib/components/Dropdown/Dropdown.d.ts +16 -2
- package/lib/components/Dropdown/Dropdown.js +22 -12
- package/lib/components/Dropdown/DropdownMenuItem.js +17 -7
- package/lib/components/Feedback/Comment.js +17 -7
- package/lib/components/Feedback/Feedback.js +17 -7
- package/lib/components/Feedback/Mood.js +17 -7
- package/lib/components/Feedback/Rating.js +17 -7
- package/lib/components/Feedback/Reasons.js +17 -7
- package/lib/components/Feedback/Scale.js +17 -7
- package/lib/components/Feedback/Sentiment.js +17 -7
- package/lib/components/Feedback/Stars.js +17 -7
- package/lib/components/Filter/FilterContent.js +17 -7
- package/lib/components/Filter/FilterInput.js +17 -7
- package/lib/components/Image/Image.js +17 -7
- package/lib/components/JsonViewer/JsonViewer.js +17 -7
- package/lib/components/JsonViewer/helpers.js +17 -7
- package/lib/components/LastUpdated/LastUpdated.js +17 -7
- package/lib/components/Link/Link.js +17 -7
- package/lib/components/Markdown/Markdown.js +17 -7
- package/lib/components/Marker/Marker.js +17 -7
- package/lib/components/Menu/MenuContainer.js +17 -7
- package/lib/components/Menu/MenuItem.js +18 -8
- package/lib/components/Menu/MenuMobile.js +17 -7
- package/lib/components/Navbar/NavbarItem.js +3 -3
- package/lib/components/PageActions/PageActions.js +17 -7
- package/lib/components/PageNavigation/NextButton.js +17 -7
- package/lib/components/Panel/Panel.js +17 -7
- package/lib/components/Panel/PanelBody.js +17 -7
- package/lib/components/Search/FilterFields/SearchFilterFieldSelect.js +17 -7
- package/lib/components/Search/FilterFields/SearchFilterFieldTags.js +1 -2
- package/lib/components/Search/SearchAiConversationInput.d.ts +2 -1
- package/lib/components/Search/SearchAiConversationInput.js +28 -10
- package/lib/components/Search/SearchAiDialog.js +17 -7
- package/lib/components/Search/SearchDialog.js +23 -10
- package/lib/components/Search/SearchFilter.js +17 -7
- package/lib/components/Search/SearchGroups.js +19 -9
- package/lib/components/Search/SearchHighlight.js +17 -7
- package/lib/components/Search/SearchItem.js +17 -7
- package/lib/components/Search/SearchRecent.js +17 -7
- package/lib/components/Search/SearchShortcut.js +17 -7
- package/lib/components/Search/SearchSuggestedPages.js +17 -7
- package/lib/components/Search/SearchTrigger.js +17 -7
- package/lib/components/Search/variables.js +5 -1
- package/lib/components/Segmented/Segmented.js +17 -7
- package/lib/components/Select/Select.js +17 -7
- package/lib/components/Select/SelectInput.js +18 -8
- package/lib/components/Sidebar/Sidebar.js +17 -7
- package/lib/components/SidebarActions/styled.js +17 -7
- package/lib/components/SkipContent/SkipContent.js +17 -7
- package/lib/components/Switch/Switch.js +17 -7
- package/lib/components/TableOfContent/TableOfContent.js +17 -7
- package/lib/components/Tag/Tag.d.ts +2 -1
- package/lib/components/Tag/Tag.js +67 -18
- package/lib/components/Tag/variables.dark.js +135 -36
- package/lib/components/Tag/variables.js +78 -61
- package/lib/components/Tooltip/Tooltip.js +17 -7
- package/lib/components/VersionPicker/VersionPicker.js +17 -7
- package/lib/core/constants/search.d.ts +5 -4
- package/lib/core/constants/search.js +4 -5
- package/lib/core/contexts/CodeSnippetContext.js +17 -7
- package/lib/core/hooks/use-tabs.d.ts +3 -2
- package/lib/core/hooks/use-tabs.js +115 -57
- package/lib/core/templates/Markdown.js +17 -7
- package/lib/core/types/hooks.d.ts +6 -3
- package/lib/core/types/l10n.d.ts +1 -1
- package/lib/core/utils/download-code-walkthrough.js +17 -7
- package/lib/core/utils/get-file-icon.js +17 -7
- package/lib/icons/AiStarsIcon/AiStarsIcon.js +11 -2
- package/lib/icons/GenericIcon/GenericIcon.js +17 -7
- package/lib/icons/RedoclyIcon/RedoclyIcon.js +4 -7
- package/lib/icons/Spinner/Spinner.js +17 -7
- package/lib/index.js +17 -7
- package/lib/layouts/OIDCForbidden.js +17 -7
- package/lib/layouts/ThreePanelLayout.js +17 -7
- package/lib/markdoc/components/Cards/Cards.js +17 -7
- package/lib/markdoc/components/CodeGroup/CodeGroup.js +17 -7
- package/lib/markdoc/components/CodeWalkthrough/CodeContainer.js +17 -7
- package/lib/markdoc/components/CodeWalkthrough/CodePanel.js +17 -7
- package/lib/markdoc/components/CodeWalkthrough/CodePanelHeader.js +17 -7
- package/lib/markdoc/components/CodeWalkthrough/CodePanelPreview.js +17 -7
- package/lib/markdoc/components/CodeWalkthrough/CodePanelToolbar.js +17 -7
- package/lib/markdoc/components/CodeWalkthrough/CodeStep.js +17 -7
- package/lib/markdoc/components/CodeWalkthrough/CodeToggle.js +17 -7
- package/lib/markdoc/components/CodeWalkthrough/CodeWalkthrough.js +17 -7
- package/lib/markdoc/components/CodeWalkthrough/Input.js +17 -7
- package/lib/markdoc/components/Heading/Heading.js +17 -7
- package/lib/markdoc/components/HtmlBlock/HtmlBlock.js +17 -7
- package/lib/markdoc/components/InlineSvg/InlineSvg.js +17 -7
- package/lib/markdoc/components/MarkdocExample/MarkdocExample.js +17 -7
- package/lib/markdoc/components/Tabs/TabList.d.ts +3 -1
- package/lib/markdoc/components/Tabs/TabList.js +214 -54
- package/lib/markdoc/components/Tabs/Tabs.d.ts +2 -1
- package/lib/markdoc/components/Tabs/Tabs.js +74 -19
- package/lib/markdoc/default.d.ts +104 -1
- package/lib/markdoc/default.js +17 -7
- package/package.json +6 -6
- package/src/components/Catalog/Catalog.tsx +15 -4
- package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityApiDescriptionRelations.tsx +1 -1
- package/src/components/Catalog/CatalogEntity/CatalogEntityRelations/CatalogEntityTeamRelations.tsx +1 -1
- package/src/components/Dropdown/Dropdown.tsx +84 -79
- package/src/components/Menu/MenuItem.tsx +1 -0
- package/src/components/Navbar/NavbarItem.tsx +6 -5
- package/src/components/Search/FilterFields/SearchFilterFieldTags.tsx +3 -3
- package/src/components/Search/SearchAiConversationInput.tsx +12 -2
- package/src/components/Search/SearchDialog.tsx +6 -3
- package/src/components/Search/SearchGroups.tsx +2 -0
- package/src/components/Search/variables.ts +5 -1
- package/src/components/Select/SelectInput.tsx +1 -0
- package/src/components/Tag/Tag.tsx +36 -20
- package/src/components/Tag/variables.dark.ts +135 -36
- package/src/components/Tag/variables.ts +78 -61
- package/src/core/constants/search.ts +8 -4
- package/src/core/hooks/use-tabs.ts +168 -86
- package/src/core/types/hooks.ts +6 -1
- package/src/core/types/l10n.ts +1 -0
- package/src/icons/AiStarsIcon/AiStarsIcon.tsx +11 -2
- package/src/icons/RedoclyIcon/RedoclyIcon.tsx +4 -22
- package/src/markdoc/components/Tabs/TabList.tsx +312 -105
- package/src/markdoc/components/Tabs/Tabs.tsx +136 -11
|
@@ -13,39 +13,75 @@ type Tabs = {
|
|
|
13
13
|
overflow: number[];
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
+
type UseTabsReturn = {
|
|
17
|
+
setTabRef: (element: HTMLButtonElement | null, index: number) => void;
|
|
18
|
+
onTabClick: (labelOrIndex: string | number) => void;
|
|
19
|
+
handleKeyboard: (event: React.KeyboardEvent, index: number) => void;
|
|
20
|
+
visibleTabs: number[];
|
|
21
|
+
overflowTabs: number[];
|
|
22
|
+
isReady: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
type UseActiveTabProps = {
|
|
26
|
+
initialTab: string;
|
|
27
|
+
tabsId?: string;
|
|
28
|
+
};
|
|
29
|
+
|
|
16
30
|
const MORE_BUTTON_WIDTH = 80;
|
|
17
31
|
const TABS_GAP = 8;
|
|
18
32
|
|
|
19
|
-
export function useTabs({
|
|
33
|
+
export function useTabs({
|
|
34
|
+
activeTab,
|
|
35
|
+
onTabChange,
|
|
36
|
+
totalTabs,
|
|
37
|
+
containerRef,
|
|
38
|
+
}: UseTabsProps): UseTabsReturn {
|
|
20
39
|
const [tabs, setTabs] = useState<Tabs>({
|
|
21
40
|
visible: Array.from({ length: totalTabs }, (_, i) => i),
|
|
22
41
|
overflow: [],
|
|
23
42
|
});
|
|
24
|
-
|
|
43
|
+
const [isReady, setIsReady] = useState(false);
|
|
44
|
+
const isFirstCalculation = useRef(true);
|
|
25
45
|
const tabRefs = useRef<(HTMLButtonElement | null)[]>([]);
|
|
26
46
|
const tabWidthsRef = useRef<number[]>([]);
|
|
27
47
|
const tabLabelsRef = useRef<string[]>([]);
|
|
48
|
+
const activeTabRef = useRef(activeTab);
|
|
49
|
+
const calculateVisibleTabsRef = useRef<(() => void) | null>(null);
|
|
28
50
|
|
|
29
|
-
|
|
51
|
+
// Synchronously update ref before any callbacks or effects run
|
|
52
|
+
activeTabRef.current = activeTab;
|
|
30
53
|
|
|
31
|
-
const setTabRef = useCallback(
|
|
32
|
-
|
|
54
|
+
const setTabRef = useCallback(
|
|
55
|
+
(element: HTMLButtonElement | null, index: number) => {
|
|
56
|
+
tabRefs.current[index] = element;
|
|
33
57
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
58
|
+
const width = element?.offsetWidth;
|
|
59
|
+
if (width) {
|
|
60
|
+
tabWidthsRef.current[index] = width;
|
|
61
|
+
}
|
|
38
62
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}, []);
|
|
63
|
+
const label = element?.getAttribute('data-label');
|
|
64
|
+
if (label) {
|
|
65
|
+
tabLabelsRef.current[index] = label;
|
|
66
|
+
}
|
|
44
67
|
|
|
45
|
-
|
|
68
|
+
// Trigger calculation once all tabs are registered
|
|
69
|
+
if (
|
|
70
|
+
isFirstCalculation.current &&
|
|
71
|
+
tabWidthsRef.current.length >= totalTabs &&
|
|
72
|
+
tabLabelsRef.current.length >= totalTabs &&
|
|
73
|
+
calculateVisibleTabsRef.current
|
|
74
|
+
) {
|
|
75
|
+
requestAnimationFrame(calculateVisibleTabsRef.current);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
[totalTabs],
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
const focusTab = useCallback((index: number) => {
|
|
46
82
|
const currentElement = tabRefs.current[index];
|
|
47
83
|
currentElement?.focus();
|
|
48
|
-
};
|
|
84
|
+
}, []);
|
|
49
85
|
|
|
50
86
|
const onTabSelect = useCallback(
|
|
51
87
|
(index: number) => {
|
|
@@ -53,7 +89,7 @@ export function useTabs({ activeTab, onTabChange, totalTabs, containerRef }: Use
|
|
|
53
89
|
const label = tabRefs.current[index]?.getAttribute('data-label');
|
|
54
90
|
if (label) onTabChange(label);
|
|
55
91
|
},
|
|
56
|
-
[onTabChange],
|
|
92
|
+
[onTabChange, focusTab],
|
|
57
93
|
);
|
|
58
94
|
|
|
59
95
|
const handleKeyboard = useCallback(
|
|
@@ -77,30 +113,19 @@ export function useTabs({ activeTab, onTabChange, totalTabs, containerRef }: Use
|
|
|
77
113
|
[totalTabs, onTabSelect],
|
|
78
114
|
);
|
|
79
115
|
|
|
80
|
-
const replaceLastVisibleTabWithClickedOverflowTab = useCallback(
|
|
81
|
-
(
|
|
82
|
-
const { visible: visibleTabs, overflow: overflowTabs } =
|
|
83
|
-
|
|
84
|
-
// Indexes of visible tabs should be sorted(asc), to replace the last visible tab with the clicked tab
|
|
85
|
-
const newVisibleTabs = [...visibleTabs].sort((a, b) => a - b);
|
|
86
|
-
const newOverflowTabs = [...overflowTabs];
|
|
87
|
-
|
|
88
|
-
const clickedIdxInOverflow = newOverflowTabs.indexOf(clickedIndex);
|
|
89
|
-
if (clickedIdxInOverflow !== -1) {
|
|
90
|
-
const lastVisible = newVisibleTabs[newVisibleTabs.length - 1];
|
|
91
|
-
newOverflowTabs.splice(clickedIdxInOverflow, 1);
|
|
92
|
-
newOverflowTabs.unshift(lastVisible);
|
|
93
|
-
newVisibleTabs.splice(newVisibleTabs.length - 1, 1);
|
|
94
|
-
newVisibleTabs.unshift(clickedIndex);
|
|
95
|
-
}
|
|
116
|
+
const replaceLastVisibleTabWithClickedOverflowTab = useCallback((clickedIndex: number) => {
|
|
117
|
+
setTabs((prevTabs) => {
|
|
118
|
+
const { visible: visibleTabs, overflow: overflowTabs } = prevTabs;
|
|
96
119
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
120
|
+
const sortedVisible = [...visibleTabs].sort((a, b) => a - b);
|
|
121
|
+
const lastVisible = sortedVisible[sortedVisible.length - 1];
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
visible: visibleTabs.map((idx) => (idx === lastVisible ? clickedIndex : idx)),
|
|
125
|
+
overflow: overflowTabs.map((idx) => (idx === clickedIndex ? lastVisible : idx)),
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
}, []);
|
|
104
129
|
|
|
105
130
|
const onTabClick = useCallback(
|
|
106
131
|
(labelOrIndex: string | number) => {
|
|
@@ -111,18 +136,18 @@ export function useTabs({ activeTab, onTabChange, totalTabs, containerRef }: Use
|
|
|
111
136
|
|
|
112
137
|
if (clickedIndex === -1) return;
|
|
113
138
|
|
|
114
|
-
const
|
|
115
|
-
if (
|
|
139
|
+
const label = tabLabelsRef.current[clickedIndex];
|
|
140
|
+
if (!label) return;
|
|
141
|
+
|
|
142
|
+
// If this is an overflow tab, replace it with a visible one
|
|
143
|
+
if (tabs.overflow.includes(clickedIndex)) {
|
|
116
144
|
replaceLastVisibleTabWithClickedOverflowTab(clickedIndex);
|
|
117
145
|
}
|
|
118
146
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
onTabChange(label);
|
|
122
|
-
focusTab(clickedIndex);
|
|
123
|
-
}
|
|
147
|
+
onTabChange(label);
|
|
148
|
+
focusTab(clickedIndex);
|
|
124
149
|
},
|
|
125
|
-
[
|
|
150
|
+
[tabs.overflow, onTabChange, replaceLastVisibleTabWithClickedOverflowTab, focusTab],
|
|
126
151
|
);
|
|
127
152
|
|
|
128
153
|
const calculateVisibleTabs = useCallback(() => {
|
|
@@ -131,87 +156,141 @@ export function useTabs({ activeTab, onTabChange, totalTabs, containerRef }: Use
|
|
|
131
156
|
|
|
132
157
|
const containerWidth = container.offsetWidth;
|
|
133
158
|
const tabWidths = tabWidthsRef.current;
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
159
|
+
const tabLabels = tabLabelsRef.current;
|
|
160
|
+
|
|
161
|
+
// Wait until all tabs are registered before calculating
|
|
162
|
+
if (tabWidths.length < totalTabs || tabLabels.length < totalTabs) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Check if container has proper width (not zero)
|
|
167
|
+
if (containerWidth === 0) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Find active tab index by label in tabLabelsRef, not by DOM element
|
|
172
|
+
// because tab might not be rendered if it's in overflow
|
|
173
|
+
const activeTabIndex = tabLabels.findIndex((label) => label === activeTabRef.current);
|
|
137
174
|
|
|
138
|
-
// Active tab should always be visible, so we include it at the beginning of the array
|
|
139
175
|
let tabsWidth = activeTabIndex !== -1 ? tabWidths[activeTabIndex] : 0;
|
|
140
|
-
const
|
|
141
|
-
const
|
|
176
|
+
const visibleTabs = activeTabIndex !== -1 ? [activeTabIndex] : [];
|
|
177
|
+
const overflowTabs = [];
|
|
142
178
|
|
|
143
179
|
for (let i = 0; i < tabWidths.length; i++) {
|
|
144
|
-
|
|
145
|
-
if (i === activeTabIndex) {
|
|
146
|
-
continue;
|
|
147
|
-
}
|
|
180
|
+
if (i === activeTabIndex) continue;
|
|
148
181
|
|
|
149
182
|
const tabWidthWithGap = tabWidths[i] + TABS_GAP;
|
|
150
183
|
const projectedWidth = tabsWidth + tabWidthWithGap;
|
|
151
184
|
|
|
152
185
|
if (projectedWidth <= containerWidth) {
|
|
153
|
-
|
|
186
|
+
visibleTabs.push(i);
|
|
154
187
|
tabsWidth += tabWidthWithGap;
|
|
155
188
|
} else {
|
|
156
|
-
|
|
189
|
+
overflowTabs.push(i);
|
|
157
190
|
}
|
|
158
191
|
}
|
|
159
192
|
|
|
160
|
-
if (
|
|
193
|
+
if (overflowTabs.length > 0) {
|
|
161
194
|
tabsWidth += MORE_BUTTON_WIDTH;
|
|
162
195
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
if (removed !== undefined) {
|
|
167
|
-
|
|
196
|
+
while (tabsWidth > containerWidth && visibleTabs.length > 1) {
|
|
197
|
+
const removed = visibleTabs.pop();
|
|
198
|
+
// Never remove the active tab - it should always stay visible or be the last one
|
|
199
|
+
if (removed !== undefined && removed !== activeTabIndex) {
|
|
200
|
+
overflowTabs.unshift(removed);
|
|
168
201
|
tabsWidth -= tabWidths[removed];
|
|
202
|
+
} else if (removed === activeTabIndex) {
|
|
203
|
+
// Put it back if we accidentally removed the active tab
|
|
204
|
+
visibleTabs.push(removed);
|
|
205
|
+
break;
|
|
169
206
|
}
|
|
170
207
|
}
|
|
208
|
+
|
|
209
|
+
// If even with only the active tab visible, it doesn't fit with More button,
|
|
210
|
+
// move all tabs to overflow (show only dropdown)
|
|
211
|
+
if (tabsWidth > containerWidth && visibleTabs.length === 1) {
|
|
212
|
+
overflowTabs.unshift(...visibleTabs);
|
|
213
|
+
visibleTabs.length = 0;
|
|
214
|
+
}
|
|
171
215
|
}
|
|
172
216
|
|
|
173
217
|
setTabs({
|
|
174
|
-
visible,
|
|
175
|
-
overflow,
|
|
218
|
+
visible: visibleTabs,
|
|
219
|
+
overflow: overflowTabs,
|
|
176
220
|
});
|
|
177
|
-
}, [containerRef, activeTab]);
|
|
178
221
|
|
|
222
|
+
// Set ready state on first calculation
|
|
223
|
+
if (isFirstCalculation.current) {
|
|
224
|
+
isFirstCalculation.current = false;
|
|
225
|
+
setIsReady(true);
|
|
226
|
+
}
|
|
227
|
+
}, [containerRef, totalTabs]);
|
|
228
|
+
|
|
229
|
+
// Store calculateVisibleTabs in ref for use in setTabRef
|
|
230
|
+
calculateVisibleTabsRef.current = calculateVisibleTabs;
|
|
231
|
+
|
|
232
|
+
// Reset isFirstCalculation when totalTabs changes (new page/tabs)
|
|
233
|
+
useEffect(() => {
|
|
234
|
+
isFirstCalculation.current = true;
|
|
235
|
+
setIsReady(false);
|
|
236
|
+
// Clear refs so we wait for new tabs to register
|
|
237
|
+
tabWidthsRef.current = [];
|
|
238
|
+
tabLabelsRef.current = [];
|
|
239
|
+
}, [totalTabs]);
|
|
240
|
+
|
|
241
|
+
// Call calculateVisibleTabs on first render and resize
|
|
179
242
|
useEffect(() => {
|
|
180
|
-
|
|
243
|
+
const container = containerRef?.current;
|
|
244
|
+
if (!container) return;
|
|
245
|
+
|
|
246
|
+
let resizeTimeout: number | null = null;
|
|
247
|
+
|
|
248
|
+
// Use ResizeObserver to wait until container has proper size
|
|
249
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
250
|
+
if (resizeTimeout) cancelAnimationFrame(resizeTimeout);
|
|
251
|
+
resizeTimeout = requestAnimationFrame(calculateVisibleTabs);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
resizeObserver.observe(container);
|
|
181
255
|
|
|
182
|
-
let resizeTimeout = requestAnimationFrame(calculateVisibleTabs);
|
|
183
256
|
const handleResize = () => {
|
|
184
|
-
if (resizeTimeout)
|
|
185
|
-
cancelAnimationFrame(resizeTimeout);
|
|
186
|
-
}
|
|
257
|
+
if (resizeTimeout) cancelAnimationFrame(resizeTimeout);
|
|
187
258
|
resizeTimeout = requestAnimationFrame(calculateVisibleTabs);
|
|
188
259
|
};
|
|
189
260
|
|
|
190
261
|
window.addEventListener('resize', handleResize);
|
|
262
|
+
|
|
191
263
|
return () => {
|
|
264
|
+
resizeObserver.disconnect();
|
|
192
265
|
window.removeEventListener('resize', handleResize);
|
|
193
|
-
cancelAnimationFrame(resizeTimeout);
|
|
266
|
+
if (resizeTimeout) cancelAnimationFrame(resizeTimeout);
|
|
194
267
|
};
|
|
195
268
|
}, [containerRef, totalTabs, calculateVisibleTabs]);
|
|
196
269
|
|
|
270
|
+
// Recalculate when activeTab changes to ensure it's visible
|
|
271
|
+
useEffect(() => {
|
|
272
|
+
if (!containerRef?.current || isFirstCalculation.current) return;
|
|
273
|
+
requestAnimationFrame(calculateVisibleTabs);
|
|
274
|
+
}, [activeTab, containerRef, calculateVisibleTabs]);
|
|
275
|
+
|
|
197
276
|
return {
|
|
198
277
|
setTabRef,
|
|
199
278
|
onTabClick,
|
|
200
279
|
handleKeyboard,
|
|
201
280
|
visibleTabs: tabs.visible,
|
|
202
281
|
overflowTabs: tabs.overflow,
|
|
203
|
-
|
|
282
|
+
isReady,
|
|
204
283
|
};
|
|
205
284
|
}
|
|
206
285
|
|
|
207
|
-
type UseActiveTabProps = {
|
|
208
|
-
initialTab: string;
|
|
209
|
-
tabsId?: string;
|
|
210
|
-
};
|
|
211
|
-
|
|
212
286
|
export const useActiveTab = ({ initialTab, tabsId }: UseActiveTabProps) => {
|
|
213
287
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
214
|
-
const
|
|
288
|
+
const initialTabValue = useMemo(
|
|
289
|
+
() => getInitialTab({ initialTab, searchParams, tabsId }),
|
|
290
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
291
|
+
[],
|
|
292
|
+
);
|
|
293
|
+
const [activeTab, setActiveTab] = useState(initialTabValue);
|
|
215
294
|
const prevActiveTabRef = useRef(activeTab);
|
|
216
295
|
|
|
217
296
|
useEffect(() => {
|
|
@@ -228,10 +307,13 @@ export const useActiveTab = ({ initialTab, tabsId }: UseActiveTabProps) => {
|
|
|
228
307
|
});
|
|
229
308
|
}, [activeTab, setSearchParams, tabsId]);
|
|
230
309
|
|
|
231
|
-
return
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
310
|
+
return useMemo(
|
|
311
|
+
() => ({
|
|
312
|
+
activeTab,
|
|
313
|
+
setActiveTab,
|
|
314
|
+
}),
|
|
315
|
+
[activeTab],
|
|
316
|
+
);
|
|
235
317
|
};
|
|
236
318
|
|
|
237
319
|
type GetInitialTabProps = {
|
package/src/core/types/hooks.ts
CHANGED
|
@@ -86,6 +86,7 @@ export type ThemeHooks = {
|
|
|
86
86
|
useSearch: (
|
|
87
87
|
product?: string,
|
|
88
88
|
autoSearchDisabled?: boolean,
|
|
89
|
+
searchSessionId?: string,
|
|
89
90
|
) => {
|
|
90
91
|
query: string;
|
|
91
92
|
setQuery: React.Dispatch<React.SetStateAction<string>>;
|
|
@@ -107,7 +108,10 @@ export type ThemeHooks = {
|
|
|
107
108
|
advancedSearch?: boolean;
|
|
108
109
|
askAi?: boolean;
|
|
109
110
|
};
|
|
110
|
-
useAiSearch: (
|
|
111
|
+
useAiSearch: (
|
|
112
|
+
options?: { filter?: SearchFilterItem[] },
|
|
113
|
+
searchSessionId?: string,
|
|
114
|
+
) => {
|
|
111
115
|
askQuestion: (question: string, history?: AiSearchConversationItem[]) => void;
|
|
112
116
|
isGeneratingResponse: boolean;
|
|
113
117
|
question: string;
|
|
@@ -142,6 +146,7 @@ export type ThemeHooks = {
|
|
|
142
146
|
| undefined;
|
|
143
147
|
useCatalog: (
|
|
144
148
|
config?: CatalogEntityConfig,
|
|
149
|
+
serverFilters?: Record<string, { value: string; count: number }[]>,
|
|
145
150
|
entitiesCounterInitial?: number,
|
|
146
151
|
initialViewMode?: CatalogViewMode,
|
|
147
152
|
) => UseCatalogResponse;
|
package/src/core/types/l10n.ts
CHANGED
|
@@ -146,6 +146,7 @@ export type TranslationKey =
|
|
|
146
146
|
| 'catalog.entity.metadata.title'
|
|
147
147
|
| 'catalog.entity.schema.title'
|
|
148
148
|
| 'catalog.entity.properties.apiDescription.title'
|
|
149
|
+
| 'catalog.backToAllLabel'
|
|
149
150
|
| 'sidebar.menu.backLabel'
|
|
150
151
|
| 'sidebar.menu.backToLabel'
|
|
151
152
|
| 'sidebar.actions.show'
|
|
@@ -35,19 +35,28 @@ export const AiStarsIcon = styled(Icon).attrs(() => ({
|
|
|
35
35
|
height: ${({ size }) => size || '16px'};
|
|
36
36
|
width: ${({ size }) => size || '16px'};
|
|
37
37
|
|
|
38
|
-
${({ background, borderRadius, margin }) =>
|
|
38
|
+
${({ background, borderRadius, margin, padding, size }) =>
|
|
39
39
|
background &&
|
|
40
40
|
`
|
|
41
41
|
display: flex;
|
|
42
42
|
align-items: center;
|
|
43
43
|
justify-content: center;
|
|
44
|
+
flex-shrink: 0;
|
|
44
45
|
|
|
45
46
|
background: ${getCssColorVariable(background)};
|
|
47
|
+
width: ${size || '16px'};
|
|
48
|
+
height: ${size || '16px'};
|
|
46
49
|
|
|
47
|
-
padding: var(--spacing-xs);
|
|
50
|
+
padding: ${padding || 'var(--spacing-xs)'};
|
|
48
51
|
margin: ${margin || '0'};
|
|
49
52
|
|
|
50
53
|
border-radius: ${background && borderRadius ? borderRadius : 'none'};
|
|
54
|
+
|
|
55
|
+
svg {
|
|
56
|
+
width: calc(${size || '16px'} - 2 * (${padding || 'var(--spacing-xs)'}));
|
|
57
|
+
height: calc(${size || '16px'} - 2 * (${padding || 'var(--spacing-xs)'}));
|
|
58
|
+
flex-shrink: 0;
|
|
59
|
+
}
|
|
51
60
|
`}
|
|
52
61
|
|
|
53
62
|
color: ${({ color }) => color && getCssColorVariable(color)};
|
|
@@ -6,29 +6,11 @@ import type { IconProps } from '@redocly/theme/icons/types';
|
|
|
6
6
|
import { getCssColorVariable } from '@redocly/theme/core/utils';
|
|
7
7
|
|
|
8
8
|
const Icon = (props: IconProps) => (
|
|
9
|
-
<svg
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
fill="none"
|
|
14
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
15
|
-
{...props}
|
|
16
|
-
>
|
|
17
|
-
<g clipPath="url(#clip0_4053_1165)">
|
|
18
|
-
<path
|
|
19
|
-
d="M14.625 6.19973C14.625 8.69176 12.6173 10.712 10.1406 10.712H2.8125V10.2717C5.04753 10.2717 6.85938 8.44864 6.85938 6.19973C6.85938 3.95082 5.04753 2.12772 2.8125 2.12772V1.6875H10.1406C12.6173 1.6875 14.625 3.70769 14.625 6.19973Z"
|
|
20
|
-
fill="#2467F2"
|
|
21
|
-
/>
|
|
22
|
-
<path
|
|
23
|
-
d="M14.625 16.875C14.625 14.383 12.6173 12.3628 10.1406 12.3628H2.8125V12.803C5.04753 12.803 6.85938 14.6261 6.85938 16.875H14.625Z"
|
|
24
|
-
fill="#2467F2"
|
|
25
|
-
/>
|
|
9
|
+
<svg viewBox="0 0 18 18" xmlns="http://www.w3.org/2000/svg" {...props}>
|
|
10
|
+
<g>
|
|
11
|
+
<path d="M14.625 6.19973C14.625 8.69176 12.6173 10.712 10.1406 10.712H2.8125V10.2717C5.04753 10.2717 6.85938 8.44864 6.85938 6.19973C6.85938 3.95082 5.04753 2.12772 2.8125 2.12772V1.6875H10.1406C12.6173 1.6875 14.625 3.70769 14.625 6.19973Z" />
|
|
12
|
+
<path d="M14.625 16.875C14.625 14.383 12.6173 12.3628 10.1406 12.3628H2.8125V12.803C5.04753 12.803 6.85938 14.6261 6.85938 16.875H14.625Z" />
|
|
26
13
|
</g>
|
|
27
|
-
<defs>
|
|
28
|
-
<clipPath id="clip0_4053_1165">
|
|
29
|
-
<rect width="18" height="18" fill="white" />
|
|
30
|
-
</clipPath>
|
|
31
|
-
</defs>
|
|
32
14
|
</svg>
|
|
33
15
|
);
|
|
34
16
|
|