Skip to content

Commit 5be48fc

Browse files
rohit-gohriLéo MIEULET
andauthored
feat: add support for passing spec directly (#424)
Version of #422 with bare minimum changes while still supporting the feature feat: minimally add spec option to all components and update docs --------- Co-authored-by: Léo MIEULET <[email protected]>
1 parent 2c20013 commit 5be48fc

File tree

21 files changed

+2164
-197
lines changed

21 files changed

+2164
-197
lines changed

.changeset/ninety-eagles-call.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
---
2+
"docusaurus-plugin-redoc": minor
3+
"docusaurus-theme-redoc": minor
4+
"redocusaurus": patch
5+
---
6+
7+
feat: add support for passing `spec` directly to all components
8+
9+
Update docs to add various missing things.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,8 @@
8080
"printWidth": 80,
8181
"tabWidth": 2
8282
},
83-
"packageManager": "[email protected]"
83+
"packageManager": "[email protected]",
84+
"volta": {
85+
"node": "18.12.0"
86+
}
8487
}

packages/docusaurus-plugin-redoc/src/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,18 @@ export default function redocPlugin(
4242
}> {
4343
const { baseUrl } = context.siteConfig;
4444
const options: PluginOptionsWithDefault = { ...DEFAULT_OPTIONS, ...opts };
45-
const { debug, spec, url: downloadUrl, config, themeId, normalizeUrl: normalizeDownloadUrl } = options;
45+
const {
46+
debug,
47+
spec,
48+
url: downloadUrl,
49+
config,
50+
themeId,
51+
normalizeUrl: normalizeDownloadUrl,
52+
} = options;
4653

4754
let url = downloadUrl;
4855
const isSpecFile = fs.existsSync(spec);
56+
4957
const fileName = path.join(
5058
'redocusaurus',
5159
`${options.id || 'api-spec'}.yaml`,

packages/docusaurus-theme-redoc/src/theme/ApiDocMdx/ApiDocMdx.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import React, { useMemo } from 'react';
22
import Redoc from '@theme/Redoc';
33
import useSpecData from '@theme/useSpecData';
4-
import type { MdxProps as Props } from '../../types/common';
4+
import type { MdxProps } from '../../types/common';
55
import '../ApiSchema/styles.css';
66

7-
const ApiDocMdx: React.FC<Props> = ({ id }: Props): JSX.Element => {
8-
const specProps = useSpecData(id);
7+
const ApiDocMdx: React.FC<MdxProps> = ({ id, spec }: MdxProps): JSX.Element => {
8+
const specProps = useSpecData(id, spec);
99
const optionsOverrides = useMemo(() => {
1010
return {
1111
theme: {

packages/docusaurus-theme-redoc/src/theme/ApiOperation/ApiOperation.tsx

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,22 @@
11
import React, { useEffect } from 'react';
2+
import useSpecData from '@theme/useSpecData';
23
import clsx from 'clsx';
34
import { ThemeProvider } from 'styled-components';
45
import '../../global';
56
import { Operation, OperationModel, Section } from 'redoc';
67
import { useSpec } from '../../utils/useSpec';
7-
import { useSpecData } from '../useSpecData';
8-
import type { ApiOperationProps as Props } from '../../types/common';
8+
import type { ApiOperationProps } from '../../types/common';
99
import '../Redoc/styles.css';
1010
import './styles.css';
1111

12-
const ApiOperation: React.FC<Props> = ({
12+
const ApiOperation: React.FC<ApiOperationProps> = ({
1313
id,
14-
example,
14+
spec,
15+
example = false,
1516
pointer,
1617
...rest
17-
}: Props): JSX.Element => {
18-
const specProps = useSpecData(id);
18+
}: ApiOperationProps): JSX.Element => {
19+
const specProps = useSpecData(id, spec);
1920
const { store } = useSpec(specProps);
2021

2122
// The # at the start is not included
@@ -56,8 +57,4 @@ const ApiOperation: React.FC<Props> = ({
5657
);
5758
};
5859

59-
ApiOperation.defaultProps = {
60-
example: false,
61-
};
62-
6360
export default ApiOperation;

packages/docusaurus-theme-redoc/src/theme/ApiSchema/ApiSchema.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,19 @@ import '../../global';
55
import { SchemaDefinition } from 'redoc';
66
import { useSpec } from '../../utils/useSpec';
77
import { useSpecData } from '../useSpecData';
8-
import type { ApiSchemaProps as Props } from '../../types/common';
8+
import type { ApiSchemaProps } from '../../types/common';
99
import '../Redoc/styles.css';
1010
import './styles.css';
1111

12-
const ApiSchema: React.FC<Props> = ({
12+
const ApiSchema: React.FC<ApiSchemaProps> = ({
1313
id,
14-
example,
14+
spec,
1515
pointer,
16+
showExample = false,
17+
example = showExample,
1618
...rest
17-
}: Props): JSX.Element => {
18-
const specProps = useSpecData(id);
19+
}: ApiSchemaProps): JSX.Element => {
20+
const specProps = useSpecData(id, spec);
1921
const { store } = useSpec(specProps);
2022

2123
useEffect(() => {
@@ -38,15 +40,12 @@ const ApiSchema: React.FC<Props> = ({
3840
parser={store.spec.parser}
3941
options={store.options}
4042
schemaRef={pointer}
43+
showExample={example}
4144
{...rest}
4245
/>
4346
</div>
4447
</ThemeProvider>
4548
);
4649
};
4750

48-
ApiSchema.defaultProps = {
49-
example: false,
50-
};
51-
5251
export default ApiSchema;
Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,50 @@
11
import React from 'react';
2+
import useSpecData from '@theme/useSpecData';
23
import clsx from 'clsx';
34
import '../../global';
4-
import { RedocStandalone, RedocRawOptions } from 'redoc';
5-
import type { SpecProps } from '../../types/common';
5+
import { RedocStandalone } from 'redoc';
6+
import type { RedocProps } from '../../types/common';
67
import { useSpecOptions } from '../../utils/useSpecOptions';
78
import './styles.css';
89
import ServerRedoc from './ServerRedoc';
910

11+
const isDevMode = process.env.NODE_ENV === 'development';
12+
1013
/*!
1114
* Redocusaurus
1215
* https://redocusaurus.vercel.app/
13-
* (c) 2024 Rohit Gohri
16+
* (c) 2025 Rohit Gohri
1417
* Released under the MIT License
1518
*/
16-
function Redoc(
17-
props: Partial<SpecProps> & {
18-
className?: string;
19-
optionsOverrides?: RedocRawOptions;
20-
},
21-
): JSX.Element {
22-
const { className, optionsOverrides, spec, url, themeId, isSpecFile } = props;
19+
function Redoc(initProps: RedocProps): JSX.Element {
20+
// eslint-disable-next-line react/destructuring-assignment
21+
const specProps = useSpecData(initProps.id, initProps.spec);
22+
const finalProps = {
23+
...specProps,
24+
...initProps,
25+
};
26+
27+
const {
28+
spec,
29+
className,
30+
isSpecFile = spec != null,
31+
url,
32+
themeId,
33+
optionsOverrides,
34+
} = finalProps;
2335
const { options } = useSpecOptions(themeId, optionsOverrides);
24-
const isDevMode = process.env.NODE_ENV === 'development';
2536

26-
if ((isDevMode && isSpecFile === false) || !spec) {
27-
return (
28-
<div className={clsx(['redocusaurus', className])}>
29-
<RedocStandalone specUrl={url} options={options} />
30-
</div>
31-
);
37+
const enableServerRendering = spec != null && (!isDevMode || isSpecFile);
38+
39+
if (enableServerRendering) {
40+
return <ServerRedoc {...finalProps} spec={spec} />;
3241
}
3342

34-
return <ServerRedoc {...props} spec={spec} />;
43+
return (
44+
<div className={clsx(['redocusaurus', className])}>
45+
<RedocStandalone specUrl={url} options={options} />
46+
</div>
47+
);
3548
}
3649

3750
export default Redoc;
Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,28 @@
11
import React from 'react';
2+
import useBrokenLinks, { BrokenLinks } from '@docusaurus/useBrokenLinks';
23
import clsx from 'clsx';
34
import '../../global';
4-
import { IMenuItem, Redoc as RedocComponent, RedocRawOptions } from 'redoc';
5-
import type { SpecProps } from '../../types/common';
5+
import { IMenuItem, Redoc as RedocComponent } from 'redoc';
6+
import type { ServerRedocProps } from '../../types/common';
67
import { useSpec } from '../../utils/useSpec';
7-
import useBrokenLinks, { BrokenLinks } from '@docusaurus/useBrokenLinks';
88
import { ServerStyles } from './Styles';
99
import './styles.css';
1010

1111
/*!
1212
* Redocusaurus
1313
* https://redocusaurus.vercel.app/
14-
* (c) 2024 Rohit Gohri
14+
* (c) 2025 Rohit Gohri
1515
* Released under the MIT License
1616
*/
17-
function ServerRedoc(
18-
props: SpecProps & {
19-
className?: string;
20-
optionsOverrides?: RedocRawOptions;
21-
},
22-
): JSX.Element {
17+
function ServerRedoc(props: ServerRedocProps): JSX.Element {
2318
const { className, optionsOverrides, ...specProps } = props;
2419
const { store, darkThemeOptions, lightThemeOptions, hasLogo } = useSpec(
2520
specProps,
2621
optionsOverrides,
2722
);
2823

2924
const collector = useBrokenLinks();
25+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
3026
collectMenuItemAnchors(collector, store.menu.items);
3127

3228
return (
@@ -49,23 +45,27 @@ function ServerRedoc(
4945
);
5046
}
5147

52-
function collectMenuItemAnchors(collector: BrokenLinks, menuItems: IMenuItem[], parentAnchor = "") {
48+
function collectMenuItemAnchors(
49+
collector: BrokenLinks,
50+
menuItems: IMenuItem[],
51+
parentAnchor = '',
52+
) {
5353
menuItems.forEach((menuItem) => {
5454
// Register anchor for menu item
5555
collector.collectAnchor(menuItem.id);
5656

5757
// If this is a child menu item, register a shortened anchor as well
5858
// This may not be necessary in all cases, but definitely needed for
5959
// menuItems of the form `tag/<Tag ID>/operation/<Operation ID>`.
60-
if (parentAnchor != "") {
61-
const childAnchor = menuItem.id.replace(`${parentAnchor}/`, "")
60+
if (parentAnchor != '') {
61+
const childAnchor = menuItem.id.replace(`${parentAnchor}/`, '');
6262
collector.collectAnchor(childAnchor);
6363
}
6464

6565
if (menuItem.items.length > 0) {
66-
collectMenuItemAnchors(collector, menuItem.items, menuItem.id)
66+
collectMenuItemAnchors(collector, menuItem.items, menuItem.id);
6767
}
68-
})
68+
});
6969
}
7070

7171
export default ServerRedoc;

packages/docusaurus-theme-redoc/src/theme/Redoc/ServerStyles.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,17 @@ const renderCss = function (store: AppStore): string {
3131
const LIGHT_MODE_PREFIX = "html:not([data-theme='dark'])";
3232
const DARK_MODE_PREFIX = "html([data-theme='dark'])";
3333

34+
export type ServerStylesProps = {
35+
specProps: SpecProps;
36+
lightThemeOptions: RedocRawOptions;
37+
darkThemeOptions: RedocRawOptions;
38+
};
39+
3440
export function ServerStyles({
3541
specProps,
3642
lightThemeOptions,
3743
darkThemeOptions,
38-
}: {
39-
specProps: SpecProps;
40-
lightThemeOptions: RedocRawOptions;
41-
darkThemeOptions: RedocRawOptions;
42-
}) {
44+
}: ServerStylesProps) {
4345
const absoluteUrl = useBaseUrl(specProps.url, { absolute: true });
4446
const fullUrl = specProps.normalizeUrl ? absoluteUrl : specProps.url;
4547

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,11 @@
11
import React from 'react';
22
import '../../global';
3-
import type { RedocRawOptions } from 'redoc';
3+
import type { ServerStylesProps } from './ServerStyles';
44

55
/**
66
* Don't hydrate/replace server styles
77
* @see https://github.com/facebook/react/issues/10923#issuecomment-338715787
88
*/
9-
export function ServerStyles(_props: {
10-
specProps: SpecProps;
11-
lightThemeOptions: RedocRawOptions;
12-
darkThemeOptions: RedocRawOptions;
13-
}) {
9+
export function ServerStyles(_props: ServerStylesProps) {
1410
return <div className="redocusaurus-styles"></div>;
1511
}

0 commit comments

Comments
 (0)