@docusaurus/theme-classic 0.0.0-5428 → 0.0.0-5430

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.
@@ -8,7 +8,6 @@ import React from 'react';
8
8
  import {composeProviders} from '@docusaurus/theme-common';
9
9
  import {
10
10
  ColorModeProvider,
11
- TabGroupChoiceProvider,
12
11
  AnnouncementBarProvider,
13
12
  DocsPreferredVersionContextProvider,
14
13
  ScrollControllerProvider,
@@ -18,7 +17,6 @@ import {
18
17
  const Provider = composeProviders([
19
18
  ColorModeProvider,
20
19
  AnnouncementBarProvider,
21
- TabGroupChoiceProvider,
22
20
  ScrollControllerProvider,
23
21
  DocsPreferredVersionContextProvider,
24
22
  PluginHtmlClassNameProvider,
@@ -4,168 +4,25 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- import React, {
8
- cloneElement,
9
- isValidElement,
10
- useCallback,
11
- useEffect,
12
- useState,
13
- } from 'react';
7
+ import React, {cloneElement} from 'react';
14
8
  import clsx from 'clsx';
15
- import {useHistory, useLocation} from '@docusaurus/router';
16
- import {duplicates, useEvent} from '@docusaurus/theme-common';
17
9
  import {
18
10
  useScrollPositionBlocker,
19
- useTabGroupChoice,
11
+ useTabs,
20
12
  } from '@docusaurus/theme-common/internal';
21
13
  import useIsBrowser from '@docusaurus/useIsBrowser';
22
14
  import styles from './styles.module.css';
23
- // A very rough duck type, but good enough to guard against mistakes while
24
- // allowing customization
25
- function isTabItem(comp) {
26
- return 'value' in comp.props;
27
- }
28
- function getSearchKey({queryString = false, groupId}) {
29
- if (typeof queryString === 'string') {
30
- return queryString;
31
- }
32
- if (queryString === false) {
33
- return undefined;
34
- }
35
- if (queryString === true && !groupId) {
36
- throw new Error(
37
- `Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".`,
38
- );
39
- }
40
- return groupId;
41
- }
42
- function useTabQueryString({queryString = false, groupId}) {
43
- // TODO not re-render optimized
44
- // See https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api
45
- const location = useLocation();
46
- const history = useHistory();
47
- const searchKey = getSearchKey({queryString, groupId});
48
- const get = useCallback(() => {
49
- if (!searchKey) {
50
- return undefined;
51
- }
52
- return new URLSearchParams(location.search).get(searchKey);
53
- }, [searchKey, location.search]);
54
- const set = useCallback(
55
- (newTabValue) => {
56
- if (!searchKey) {
57
- return; // no-op
58
- }
59
- const searchParams = new URLSearchParams(location.search);
60
- searchParams.set(searchKey, newTabValue);
61
- history.replace({...location, search: searchParams.toString()});
62
- },
63
- [searchKey, history, location],
64
- );
65
- return {get, set};
66
- }
67
- function TabsComponent(props) {
68
- const {
69
- lazy,
70
- block,
71
- defaultValue: defaultValueProp,
72
- values: valuesProp,
73
- groupId,
74
- className,
75
- queryString = false,
76
- } = props;
77
- const children = React.Children.map(props.children, (child) => {
78
- if (isValidElement(child) && isTabItem(child)) {
79
- return child;
80
- }
81
- // child.type.name will give non-sensical values in prod because of
82
- // minification, but we assume it won't throw in prod.
83
- throw new Error(
84
- `Docusaurus error: Bad <Tabs> child <${
85
- // @ts-expect-error: guarding against unexpected cases
86
- typeof child.type === 'string' ? child.type : child.type.name
87
- }>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`,
88
- );
89
- });
90
- const tabQueryString = useTabQueryString({queryString, groupId});
91
- const values =
92
- valuesProp ??
93
- // Only pick keys that we recognize. MDX would inject some keys by default
94
- children.map(({props: {value, label, attributes}}) => ({
95
- value,
96
- label,
97
- attributes,
98
- }));
99
- const dup = duplicates(values, (a, b) => a.value === b.value);
100
- if (dup.length > 0) {
101
- throw new Error(
102
- `Docusaurus error: Duplicate values "${dup
103
- .map((a) => a.value)
104
- .join(', ')}" found in <Tabs>. Every value needs to be unique.`,
105
- );
106
- }
107
- // Warn user about passing incorrect defaultValue as prop.
108
- if (
109
- defaultValueProp !== null &&
110
- defaultValueProp !== undefined &&
111
- !values.some((a) => a.value === defaultValueProp)
112
- ) {
113
- throw new Error(
114
- `Docusaurus error: The <Tabs> has a defaultValue "${defaultValueProp}" but none of its children has the corresponding value. Available values are: ${values
115
- .map((a) => a.value)
116
- .join(
117
- ', ',
118
- )}. If you intend to show no default tab, use defaultValue={null} instead.`,
119
- );
120
- }
121
- const {
122
- ready: tabGroupChoicesReady,
123
- tabGroupChoices,
124
- setTabGroupChoices,
125
- } = useTabGroupChoice();
126
- const defaultValue =
127
- defaultValueProp !== undefined
128
- ? defaultValueProp
129
- : children.find((child) => child.props.default)?.props.value ??
130
- children[0].props.value;
131
- const [selectedValue, setSelectedValue] = useState(defaultValue);
15
+ function TabList({className, block, selectedValue, selectValue, tabValues}) {
132
16
  const tabRefs = [];
133
17
  const {blockElementScrollPositionUntilNextRender} =
134
18
  useScrollPositionBlocker();
135
- // Lazily restore the appropriate tab selected value
136
- // We can't read queryString/localStorage on first render
137
- // It would trigger a React SSR/client hydration mismatch
138
- const restoreTabSelectedValue = useEvent(() => {
139
- // wait for localStorage values to be set (initially empty object :s)
140
- if (tabGroupChoicesReady) {
141
- // querystring value > localStorage value
142
- const valueToRestore =
143
- tabQueryString.get() ?? (groupId && tabGroupChoices[groupId]);
144
- const isValid =
145
- valueToRestore &&
146
- values.some((value) => value.value === valueToRestore);
147
- if (isValid) {
148
- setSelectedValue(valueToRestore);
149
- }
150
- }
151
- });
152
- useEffect(() => {
153
- // wait for localStorage values to be set (initially empty object :s)
154
- if (tabGroupChoicesReady) {
155
- restoreTabSelectedValue();
156
- }
157
- }, [tabGroupChoicesReady, restoreTabSelectedValue]);
158
19
  const handleTabChange = (event) => {
159
20
  const newTab = event.currentTarget;
160
21
  const newTabIndex = tabRefs.indexOf(newTab);
161
- const newTabValue = values[newTabIndex].value;
22
+ const newTabValue = tabValues[newTabIndex].value;
162
23
  if (newTabValue !== selectedValue) {
163
24
  blockElementScrollPositionUntilNextRender(newTab);
164
- setSelectedValue(newTabValue);
165
- tabQueryString.set(newTabValue);
166
- if (groupId != null) {
167
- setTabGroupChoices(groupId, String(newTabValue));
168
- }
25
+ selectValue(newTabValue);
169
26
  }
170
27
  };
171
28
  const handleKeydown = (event) => {
@@ -191,60 +48,67 @@ function TabsComponent(props) {
191
48
  focusElement?.focus();
192
49
  };
193
50
  return (
194
- <div className={clsx('tabs-container', styles.tabList)}>
195
- <ul
196
- role="tablist"
197
- aria-orientation="horizontal"
198
- className={clsx(
199
- 'tabs',
200
- {
201
- 'tabs--block': block,
202
- },
203
- className,
204
- )}>
205
- {values.map(({value, label, attributes}) => (
206
- <li
207
- role="tab"
208
- tabIndex={selectedValue === value ? 0 : -1}
209
- aria-selected={selectedValue === value}
210
- key={value}
211
- ref={(tabControl) => tabRefs.push(tabControl)}
212
- onKeyDown={handleKeydown}
213
- onClick={handleTabChange}
214
- {...attributes}
215
- className={clsx(
216
- 'tabs__item',
217
- styles.tabItem,
218
- attributes?.className,
219
- {
220
- 'tabs__item--active': selectedValue === value,
221
- },
222
- )}>
223
- {label ?? value}
224
- </li>
225
- ))}
226
- </ul>
227
-
228
- {lazy ? (
229
- cloneElement(
230
- children.filter(
231
- (tabItem) => tabItem.props.value === selectedValue,
232
- )[0],
233
- {className: 'margin-top--md'},
234
- )
235
- ) : (
236
- <div className="margin-top--md">
237
- {children.map((tabItem, i) =>
238
- cloneElement(tabItem, {
239
- key: i,
240
- hidden: tabItem.props.value !== selectedValue,
241
- }),
242
- )}
243
- </div>
51
+ <ul
52
+ role="tablist"
53
+ aria-orientation="horizontal"
54
+ className={clsx(
55
+ 'tabs',
56
+ {
57
+ 'tabs--block': block,
58
+ },
59
+ className,
60
+ )}>
61
+ {tabValues.map(({value, label, attributes}) => (
62
+ <li
63
+ // TODO extract TabListItem
64
+ role="tab"
65
+ tabIndex={selectedValue === value ? 0 : -1}
66
+ aria-selected={selectedValue === value}
67
+ key={value}
68
+ ref={(tabControl) => tabRefs.push(tabControl)}
69
+ onKeyDown={handleKeydown}
70
+ onClick={handleTabChange}
71
+ {...attributes}
72
+ className={clsx('tabs__item', styles.tabItem, attributes?.className, {
73
+ 'tabs__item--active': selectedValue === value,
74
+ })}>
75
+ {label ?? value}
76
+ </li>
77
+ ))}
78
+ </ul>
79
+ );
80
+ }
81
+ function TabContent({lazy, children, selectedValue}) {
82
+ if (lazy) {
83
+ const selectedTabItem = children.find(
84
+ (tabItem) => tabItem.props.value === selectedValue,
85
+ );
86
+ if (!selectedTabItem) {
87
+ // fail-safe or fail-fast? not sure what's best here
88
+ return null;
89
+ }
90
+ return cloneElement(selectedTabItem, {className: 'margin-top--md'});
91
+ }
92
+ return (
93
+ <div className="margin-top--md">
94
+ {children.map((tabItem, i) =>
95
+ cloneElement(tabItem, {
96
+ key: i,
97
+ hidden: tabItem.props.value !== selectedValue,
98
+ }),
244
99
  )}
245
100
  </div>
246
101
  );
247
102
  }
103
+ function TabsComponent(props) {
104
+ const tabs = useTabs(props);
105
+ return (
106
+ <div className={clsx('tabs-container', styles.tabList)}>
107
+ <TabList {...props} {...tabs} />
108
+ <TabContent {...props} {...tabs} />
109
+ </div>
110
+ );
111
+ }
248
112
  export default function Tabs(props) {
249
113
  const isBrowser = useIsBrowser();
250
114
  return (
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/theme-classic",
3
- "version": "0.0.0-5428",
3
+ "version": "0.0.0-5430",
4
4
  "description": "Classic theme for Docusaurus",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/theme-classic.d.ts",
@@ -20,18 +20,18 @@
20
20
  "copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
21
21
  },
22
22
  "dependencies": {
23
- "@docusaurus/core": "0.0.0-5428",
24
- "@docusaurus/mdx-loader": "0.0.0-5428",
25
- "@docusaurus/module-type-aliases": "0.0.0-5428",
26
- "@docusaurus/plugin-content-blog": "0.0.0-5428",
27
- "@docusaurus/plugin-content-docs": "0.0.0-5428",
28
- "@docusaurus/plugin-content-pages": "0.0.0-5428",
29
- "@docusaurus/theme-common": "0.0.0-5428",
30
- "@docusaurus/theme-translations": "0.0.0-5428",
31
- "@docusaurus/types": "0.0.0-5428",
32
- "@docusaurus/utils": "0.0.0-5428",
33
- "@docusaurus/utils-common": "0.0.0-5428",
34
- "@docusaurus/utils-validation": "0.0.0-5428",
23
+ "@docusaurus/core": "0.0.0-5430",
24
+ "@docusaurus/mdx-loader": "0.0.0-5430",
25
+ "@docusaurus/module-type-aliases": "0.0.0-5430",
26
+ "@docusaurus/plugin-content-blog": "0.0.0-5430",
27
+ "@docusaurus/plugin-content-docs": "0.0.0-5430",
28
+ "@docusaurus/plugin-content-pages": "0.0.0-5430",
29
+ "@docusaurus/theme-common": "0.0.0-5430",
30
+ "@docusaurus/theme-translations": "0.0.0-5430",
31
+ "@docusaurus/types": "0.0.0-5430",
32
+ "@docusaurus/utils": "0.0.0-5430",
33
+ "@docusaurus/utils-common": "0.0.0-5430",
34
+ "@docusaurus/utils-validation": "0.0.0-5430",
35
35
  "@mdx-js/react": "^1.6.22",
36
36
  "clsx": "^1.2.1",
37
37
  "copy-text-to-clipboard": "^3.0.1",
@@ -62,5 +62,5 @@
62
62
  "engines": {
63
63
  "node": ">=16.14"
64
64
  },
65
- "gitHead": "71631dbc003d6fe7844c6fd9211327c11f8c6f7a"
65
+ "gitHead": "2758916f72e969d3a8e3ae28dcd6203cfcf3600b"
66
66
  }
@@ -9,7 +9,6 @@ import React from 'react';
9
9
  import {composeProviders} from '@docusaurus/theme-common';
10
10
  import {
11
11
  ColorModeProvider,
12
- TabGroupChoiceProvider,
13
12
  AnnouncementBarProvider,
14
13
  DocsPreferredVersionContextProvider,
15
14
  ScrollControllerProvider,
@@ -21,7 +20,6 @@ import type {Props} from '@theme/Layout/Provider';
21
20
  const Provider = composeProviders([
22
21
  ColorModeProvider,
23
22
  AnnouncementBarProvider,
24
- TabGroupChoiceProvider,
25
23
  ScrollControllerProvider,
26
24
  DocsPreferredVersionContextProvider,
27
25
  PluginHtmlClassNameProvider,
@@ -5,181 +5,27 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import React, {
9
- cloneElement,
10
- isValidElement,
11
- useCallback,
12
- useEffect,
13
- useState,
14
- type ReactElement,
15
- } from 'react';
8
+ import React, {cloneElement} from 'react';
16
9
  import clsx from 'clsx';
17
- import {useHistory, useLocation} from '@docusaurus/router';
18
- import {duplicates, useEvent} from '@docusaurus/theme-common';
19
10
  import {
20
11
  useScrollPositionBlocker,
21
- useTabGroupChoice,
12
+ useTabs,
22
13
  } from '@docusaurus/theme-common/internal';
23
14
  import useIsBrowser from '@docusaurus/useIsBrowser';
24
- import type {Props as TabItemProps} from '@theme/TabItem';
25
15
  import type {Props} from '@theme/Tabs';
26
16
  import styles from './styles.module.css';
27
17
 
28
- // A very rough duck type, but good enough to guard against mistakes while
29
- // allowing customization
30
- function isTabItem(
31
- comp: ReactElement<object>,
32
- ): comp is ReactElement<TabItemProps> {
33
- return 'value' in comp.props;
34
- }
35
-
36
- function getSearchKey({
37
- queryString = false,
38
- groupId,
39
- }: Pick<Props, 'queryString' | 'groupId'>) {
40
- if (typeof queryString === 'string') {
41
- return queryString;
42
- }
43
- if (queryString === false) {
44
- return undefined;
45
- }
46
- if (queryString === true && !groupId) {
47
- throw new Error(
48
- `Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".`,
49
- );
50
- }
51
- return groupId;
52
- }
53
-
54
- function useTabQueryString({
55
- queryString = false,
56
- groupId,
57
- }: Pick<Props, 'queryString' | 'groupId'>) {
58
- // TODO not re-render optimized
59
- // See https://thisweekinreact.com/articles/useSyncExternalStore-the-underrated-react-api
60
- const location = useLocation();
61
- const history = useHistory();
62
-
63
- const searchKey = getSearchKey({queryString, groupId});
64
-
65
- const get = useCallback(() => {
66
- if (!searchKey) {
67
- return undefined;
68
- }
69
- return new URLSearchParams(location.search).get(searchKey);
70
- }, [searchKey, location.search]);
71
-
72
- const set = useCallback(
73
- (newTabValue: string) => {
74
- if (!searchKey) {
75
- return; // no-op
76
- }
77
- const searchParams = new URLSearchParams(location.search);
78
- searchParams.set(searchKey, newTabValue);
79
- history.replace({...location, search: searchParams.toString()});
80
- },
81
- [searchKey, history, location],
82
- );
83
-
84
- return {get, set};
85
- }
86
-
87
- function TabsComponent(props: Props): JSX.Element {
88
- const {
89
- lazy,
90
- block,
91
- defaultValue: defaultValueProp,
92
- values: valuesProp,
93
- groupId,
94
- className,
95
- queryString = false,
96
- } = props;
97
- const children = React.Children.map(props.children, (child) => {
98
- if (isValidElement(child) && isTabItem(child)) {
99
- return child;
100
- }
101
- // child.type.name will give non-sensical values in prod because of
102
- // minification, but we assume it won't throw in prod.
103
- throw new Error(
104
- `Docusaurus error: Bad <Tabs> child <${
105
- // @ts-expect-error: guarding against unexpected cases
106
- typeof child.type === 'string' ? child.type : child.type.name
107
- }>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`,
108
- );
109
- });
110
- const tabQueryString = useTabQueryString({queryString, groupId});
111
- const values =
112
- valuesProp ??
113
- // Only pick keys that we recognize. MDX would inject some keys by default
114
- children.map(({props: {value, label, attributes}}) => ({
115
- value,
116
- label,
117
- attributes,
118
- }));
119
- const dup = duplicates(values, (a, b) => a.value === b.value);
120
- if (dup.length > 0) {
121
- throw new Error(
122
- `Docusaurus error: Duplicate values "${dup
123
- .map((a) => a.value)
124
- .join(', ')}" found in <Tabs>. Every value needs to be unique.`,
125
- );
126
- }
127
-
128
- // Warn user about passing incorrect defaultValue as prop.
129
- if (
130
- defaultValueProp !== null &&
131
- defaultValueProp !== undefined &&
132
- !values.some((a) => a.value === defaultValueProp)
133
- ) {
134
- throw new Error(
135
- `Docusaurus error: The <Tabs> has a defaultValue "${defaultValueProp}" but none of its children has the corresponding value. Available values are: ${values
136
- .map((a) => a.value)
137
- .join(
138
- ', ',
139
- )}. If you intend to show no default tab, use defaultValue={null} instead.`,
140
- );
141
- }
142
-
143
- const {
144
- ready: tabGroupChoicesReady,
145
- tabGroupChoices,
146
- setTabGroupChoices,
147
- } = useTabGroupChoice();
148
- const defaultValue =
149
- defaultValueProp !== undefined
150
- ? defaultValueProp
151
- : children.find((child) => child.props.default)?.props.value ??
152
- children[0]!.props.value;
153
-
154
- const [selectedValue, setSelectedValue] = useState(defaultValue);
18
+ function TabList({
19
+ className,
20
+ block,
21
+ selectedValue,
22
+ selectValue,
23
+ tabValues,
24
+ }: Props & ReturnType<typeof useTabs>) {
155
25
  const tabRefs: (HTMLLIElement | null)[] = [];
156
26
  const {blockElementScrollPositionUntilNextRender} =
157
27
  useScrollPositionBlocker();
158
28
 
159
- // Lazily restore the appropriate tab selected value
160
- // We can't read queryString/localStorage on first render
161
- // It would trigger a React SSR/client hydration mismatch
162
- const restoreTabSelectedValue = useEvent(() => {
163
- // wait for localStorage values to be set (initially empty object :s)
164
- if (tabGroupChoicesReady) {
165
- // querystring value > localStorage value
166
- const valueToRestore =
167
- tabQueryString.get() ?? (groupId && tabGroupChoices[groupId]);
168
- const isValid =
169
- valueToRestore &&
170
- values.some((value) => value.value === valueToRestore);
171
- if (isValid) {
172
- setSelectedValue(valueToRestore);
173
- }
174
- }
175
- });
176
- useEffect(() => {
177
- // wait for localStorage values to be set (initially empty object :s)
178
- if (tabGroupChoicesReady) {
179
- restoreTabSelectedValue();
180
- }
181
- }, [tabGroupChoicesReady, restoreTabSelectedValue]);
182
-
183
29
  const handleTabChange = (
184
30
  event:
185
31
  | React.FocusEvent<HTMLLIElement>
@@ -188,15 +34,11 @@ function TabsComponent(props: Props): JSX.Element {
188
34
  ) => {
189
35
  const newTab = event.currentTarget;
190
36
  const newTabIndex = tabRefs.indexOf(newTab);
191
- const newTabValue = values[newTabIndex]!.value;
37
+ const newTabValue = tabValues[newTabIndex]!.value;
192
38
 
193
39
  if (newTabValue !== selectedValue) {
194
40
  blockElementScrollPositionUntilNextRender(newTab);
195
- setSelectedValue(newTabValue);
196
- tabQueryString.set(newTabValue);
197
- if (groupId != null) {
198
- setTabGroupChoices(groupId, String(newTabValue));
199
- }
41
+ selectValue(newTabValue);
200
42
  }
201
43
  };
202
44
 
@@ -226,61 +68,79 @@ function TabsComponent(props: Props): JSX.Element {
226
68
  };
227
69
 
228
70
  return (
229
- <div className={clsx('tabs-container', styles.tabList)}>
230
- <ul
231
- role="tablist"
232
- aria-orientation="horizontal"
233
- className={clsx(
234
- 'tabs',
235
- {
236
- 'tabs--block': block,
237
- },
238
- className,
239
- )}>
240
- {values.map(({value, label, attributes}) => (
241
- <li
242
- role="tab"
243
- tabIndex={selectedValue === value ? 0 : -1}
244
- aria-selected={selectedValue === value}
245
- key={value}
246
- ref={(tabControl) => tabRefs.push(tabControl)}
247
- onKeyDown={handleKeydown}
248
- onClick={handleTabChange}
249
- {...attributes}
250
- className={clsx(
251
- 'tabs__item',
252
- styles.tabItem,
253
- attributes?.className as string,
254
- {
255
- 'tabs__item--active': selectedValue === value,
256
- },
257
- )}>
258
- {label ?? value}
259
- </li>
260
- ))}
261
- </ul>
71
+ <ul
72
+ role="tablist"
73
+ aria-orientation="horizontal"
74
+ className={clsx(
75
+ 'tabs',
76
+ {
77
+ 'tabs--block': block,
78
+ },
79
+ className,
80
+ )}>
81
+ {tabValues.map(({value, label, attributes}) => (
82
+ <li
83
+ // TODO extract TabListItem
84
+ role="tab"
85
+ tabIndex={selectedValue === value ? 0 : -1}
86
+ aria-selected={selectedValue === value}
87
+ key={value}
88
+ ref={(tabControl) => tabRefs.push(tabControl)}
89
+ onKeyDown={handleKeydown}
90
+ onClick={handleTabChange}
91
+ {...attributes}
92
+ className={clsx(
93
+ 'tabs__item',
94
+ styles.tabItem,
95
+ attributes?.className as string,
96
+ {
97
+ 'tabs__item--active': selectedValue === value,
98
+ },
99
+ )}>
100
+ {label ?? value}
101
+ </li>
102
+ ))}
103
+ </ul>
104
+ );
105
+ }
262
106
 
263
- {lazy ? (
264
- cloneElement(
265
- children.filter(
266
- (tabItem) => tabItem.props.value === selectedValue,
267
- )[0]!,
268
- {className: 'margin-top--md'},
269
- )
270
- ) : (
271
- <div className="margin-top--md">
272
- {children.map((tabItem, i) =>
273
- cloneElement(tabItem, {
274
- key: i,
275
- hidden: tabItem.props.value !== selectedValue,
276
- }),
277
- )}
278
- </div>
107
+ function TabContent({
108
+ lazy,
109
+ children,
110
+ selectedValue,
111
+ }: Props & ReturnType<typeof useTabs>) {
112
+ if (lazy) {
113
+ const selectedTabItem = children.find(
114
+ (tabItem) => tabItem.props.value === selectedValue,
115
+ );
116
+ if (!selectedTabItem) {
117
+ // fail-safe or fail-fast? not sure what's best here
118
+ return null;
119
+ }
120
+ return cloneElement(selectedTabItem, {className: 'margin-top--md'});
121
+ }
122
+ return (
123
+ <div className="margin-top--md">
124
+ {children.map((tabItem, i) =>
125
+ cloneElement(tabItem, {
126
+ key: i,
127
+ hidden: tabItem.props.value !== selectedValue,
128
+ }),
279
129
  )}
280
130
  </div>
281
131
  );
282
132
  }
283
133
 
134
+ function TabsComponent(props: Props): JSX.Element {
135
+ const tabs = useTabs(props);
136
+ return (
137
+ <div className={clsx('tabs-container', styles.tabList)}>
138
+ <TabList {...props} {...tabs} />
139
+ <TabContent {...props} {...tabs} />
140
+ </div>
141
+ );
142
+ }
143
+
284
144
  export default function Tabs(props: Props): JSX.Element {
285
145
  const isBrowser = useIsBrowser();
286
146
  return (
@@ -1232,39 +1232,17 @@ declare module '@theme/Mermaid' {
1232
1232
  }
1233
1233
 
1234
1234
  declare module '@theme/TabItem' {
1235
- import type {ReactNode} from 'react';
1235
+ import type {TabItemProps} from '@docusaurus/theme-common/internal';
1236
1236
 
1237
- export interface Props {
1238
- readonly children: ReactNode;
1239
- readonly value: string;
1240
- readonly default?: boolean;
1241
- readonly label?: string;
1242
- readonly hidden?: boolean;
1243
- readonly className?: string;
1244
- readonly attributes?: {[key: string]: unknown};
1245
- }
1237
+ export interface Props extends TabItemProps {}
1246
1238
 
1247
1239
  export default function TabItem(props: Props): JSX.Element;
1248
1240
  }
1249
1241
 
1250
1242
  declare module '@theme/Tabs' {
1251
- import type {ReactElement} from 'react';
1252
- import type {Props as TabItemProps} from '@theme/TabItem';
1243
+ import type {TabsProps} from '@docusaurus/theme-common/internal';
1253
1244
 
1254
- export interface Props {
1255
- readonly lazy?: boolean;
1256
- readonly block?: boolean;
1257
- readonly children: readonly ReactElement<TabItemProps>[];
1258
- readonly defaultValue?: string | null;
1259
- readonly values?: readonly {
1260
- value: string;
1261
- label?: string;
1262
- attributes?: {[key: string]: unknown};
1263
- }[];
1264
- readonly groupId?: string;
1265
- readonly className?: string;
1266
- readonly queryString?: string | boolean;
1267
- }
1245
+ export interface Props extends TabsProps {}
1268
1246
 
1269
1247
  export default function Tabs(props: Props): JSX.Element;
1270
1248
  }