Skip to content

RFC for a docs version selector #6771

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@
"react-collapsed": "4.0.4",
"react-dom": "^0.0.0-experimental-16d053d59-20230506",
"remark-frontmatter": "^4.0.1",
"remark-gfm": "^3.0.1"
"remark-gfm": "^3.0.1",
"semver": "^7.6.0"
},
"devDependencies": {
"@babel/core": "^7.12.9",
Expand All @@ -54,6 +55,7 @@
"@types/parse-numeric-range": "^0.0.1",
"@types/react": "^18.0.9",
"@types/react-dom": "^18.0.5",
"@types/semver": "^7.5.8",
"@typescript-eslint/eslint-plugin": "^5.36.2",
"@typescript-eslint/parser": "^5.36.2",
"asyncro": "^3.0.0",
Expand Down
18 changes: 14 additions & 4 deletions src/components/Layout/Sidebar/SidebarRouteTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import {useRef, useLayoutEffect, Fragment} from 'react';

import cn from 'classnames';
import * as Semver from 'semver';
import {useRouter} from 'next/router';
import {SidebarLink} from './SidebarLink';
import {useCollapse} from 'react-collapsed';
Expand Down Expand Up @@ -77,6 +78,8 @@ export function SidebarRouteTree({
}: SidebarRouteTreeProps) {
const slug = useRouter().asPath.split(/[\?\#]/)[0];
const pendingRoute = usePendingRoute();
const selectedVersion: string =
(useRouter().query.version as string) ?? '19.0.0';
const currentRoutes = routeTree.routes as RouteItem[];
return (
<ul>
Expand All @@ -86,13 +89,22 @@ export function SidebarRouteTree({
path,
title,
routes,
canary,
heading,
hasSectionHeader,
sectionHeader,
version,
},
index
) => {
if (
version &&
!Semver.satisfies(
Semver.coerce(selectedVersion) as Semver.SemVer,
version
)
) {
return null;
}
const selected = slug === path;
let listItem = null;
if (!path || heading) {
Expand Down Expand Up @@ -120,7 +132,6 @@ export function SidebarRouteTree({
selected={selected}
level={level}
title={title}
canary={canary}
isExpanded={isExpanded}
hideArrow={isForceExpanded}
/>
Expand All @@ -144,7 +155,6 @@ export function SidebarRouteTree({
selected={selected}
level={level}
title={title}
canary={canary}
/>
</li>
);
Expand All @@ -163,7 +173,7 @@ export function SidebarRouteTree({
'mb-1 text-sm font-bold ms-5 text-tertiary dark:text-tertiary-dark',
index !== 0 && 'mt-2'
)}>
{sectionHeader}
{sectionHeader?.replace('%VERSION%', selectedVersion)}
</h3>
</Fragment>
);
Expand Down
15 changes: 15 additions & 0 deletions src/components/Layout/SidebarNav/SidebarNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import cn from 'classnames';
import {Feedback} from '../Feedback';
import {SidebarRouteTree} from '../Sidebar/SidebarRouteTree';
import type {RouteItem} from '../getRouteMeta';
import {useRouter} from 'next/router';

declare global {
interface Window {
Expand All @@ -23,6 +24,14 @@ export default function SidebarNav({
routeTree: RouteItem;
breadcrumbs: RouteItem[];
}) {
const {push, query} = useRouter();
const onChangeVersion = React.useCallback(
(e: any) => {
push({query: {...query, version: e.target.value}});
},
[push, query]
);

// HACK. Fix up the data structures instead.
if ((routeTree as any).routes.length === 1) {
routeTree = (routeTree as any).routes[0];
Expand All @@ -48,6 +57,12 @@ export default function SidebarNav({
className="w-full pt-6 scrolling-touch lg:h-auto grow pe-0 lg:pe-5 lg:pb-16 md:pt-4 lg:pt-4 scrolling-gpu">
{/* No fallback UI so need to be careful not to suspend directly inside. */}
<Suspense fallback={null}>
<select
value={query.version ?? '19.0.0'}
onChange={onChangeVersion}>
<option value="18.0.0">Version 18.0.0</option>
<option value="19.0.0">Version 19.0.0</option>
</select>
<SidebarRouteTree
routeTree={routeTree}
breadcrumbs={breadcrumbs}
Expand Down
4 changes: 2 additions & 2 deletions src/components/Layout/getRouteMeta.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ export type RouteTag =
export interface RouteItem {
/** Page title (for the sidebar) */
title: string;
/** Optional canary flag for heading */
canary?: boolean;
/** Optional version that supports this item */
version?: string;
/** Optional page description for heading */
description?: string;
/* Additional meta info for page tagging */
Expand Down
13 changes: 13 additions & 0 deletions src/components/MDX/MDXComponents.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,21 @@ import ButtonLink from 'components/ButtonLink';
import {TocContext} from './TocContext';
import type {Toc, TocItem} from './TocContext';
import {TeamMember} from './TeamMember';
import * as Semver from 'semver';

import ErrorDecoder from './ErrorDecoder';
import {IconCanary} from '../Icon/IconCanary';
import {useRouter} from 'next/router';

function VersionCondition({children, range}: {children: any; range: string}) {
const router = useRouter();
return Semver.satisfies(
Semver.coerce((router.query.version as any) ?? '19.0.0') as any,
range
)
? children
: null;
}

function CodeStep({children, step}: {children: any; step: number}) {
return (
Expand Down Expand Up @@ -462,6 +474,7 @@ export const MDXComponents = {
CodeStep,
YouTubeIframe,
ErrorDecoder,
VersionCondition,
};

for (let key in MDXComponents) {
Expand Down
8 changes: 8 additions & 0 deletions src/content/reference/react/useCallback.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ const cachedFn = useCallback(fn, dependencies)

### `useCallback(fn, dependencies)` {/*usecallback*/}

<VersionCondition range=">= 19.0.0">
# 19+ content example
</VersionCondition>

<VersionCondition range="< 19.0.0">
# pre 19 content example
</VersionCondition>

Call `useCallback` at the top level of your component to cache a function definition between re-renders:

```js {4,9}
Expand Down
8 changes: 4 additions & 4 deletions src/sidebarReference.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"routes": [
{
"hasSectionHeader": true,
"sectionHeader": "react@18.2.0"
"sectionHeader": "react@%VERSION%"
},
{
"title": "Overview",
Expand All @@ -17,7 +17,7 @@
{
"title": "use",
"path": "/reference/react/use",
"canary": true
"version": ">= 19"
},
{
"title": "useCallback",
Expand Down Expand Up @@ -62,7 +62,7 @@
{
"title": "useOptimistic",
"path": "/reference/react/useOptimistic",
"canary": true
"version": ">= 19"
},
{
"title": "useReducer",
Expand Down Expand Up @@ -168,7 +168,7 @@
},
{
"hasSectionHeader": true,
"sectionHeader": "react-dom@18.2.0"
"sectionHeader": "react-dom@%VERSION%"
},
{
"title": "Hooks",
Expand Down
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,11 @@
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.2.tgz#1a62f89525723dde24ba1b01b092bf5df8ad4d39"
integrity sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==

"@types/semver@^7.5.8":
version "7.5.8"
resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e"
integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==

"@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2":
version "2.0.6"
resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d"
Expand Down Expand Up @@ -5704,6 +5709,13 @@ semver@^7.3.7:
dependencies:
lru-cache "^6.0.0"

semver@^7.6.0:
version "7.6.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d"
integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==
dependencies:
lru-cache "^6.0.0"

[email protected]:
version "0.18.0"
resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
Expand Down
Loading