From 20268ac0c494b85e643fe9ae2cb3f391a835b88d Mon Sep 17 00:00:00 2001 From: brynpttrsn Date: Sat, 15 Jul 2023 13:34:28 -0400 Subject: [PATCH] feat(website): switch overload on hash location (#9699) * feat(website): switch overload on hash location * Update apps/website/src/components/OverloadSwitcher.tsx --------- Co-authored-by: Noel --- .../src/components/OverloadSwitcher.tsx | 39 ++++++++++++++++++- .../components/model/function/Function.tsx | 2 +- .../src/components/model/method/Method.tsx | 2 +- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/apps/website/src/components/OverloadSwitcher.tsx b/apps/website/src/components/OverloadSwitcher.tsx index 34bd125b1..a8358ec82 100644 --- a/apps/website/src/components/OverloadSwitcher.tsx +++ b/apps/website/src/components/OverloadSwitcher.tsx @@ -4,17 +4,52 @@ import { VscChevronDown } from '@react-icons/all-files/vsc/VscChevronDown'; import { VscVersions } from '@react-icons/all-files/vsc/VscVersions'; import { Menu, MenuButton, MenuItem, useMenuState } from 'ariakit/menu'; import type { PropsWithChildren, ReactNode } from 'react'; -import { useMemo, useState } from 'react'; +import { useCallback, useMemo, useState, useEffect } from 'react'; export interface OverloadSwitcherProps { + methodName: string; overloads: ReactNode[]; } -export default function OverloadSwitcher({ overloads, children }: PropsWithChildren<{ overloads: ReactNode[] }>) { +export default function OverloadSwitcher({ + methodName, + overloads, + children, +}: PropsWithChildren<{ methodName: string; overloads: ReactNode[] }>) { + const [hash, setHash] = useState(() => (typeof window === 'undefined' ? '' : window.location.hash)); + const hashChangeHandler = useCallback(() => { + setHash(window.location.hash); + }, []); const [overloadIndex, setOverloadIndex] = useState(1); const overloadedNode = overloads[overloadIndex - 1]!; const menu = useMenuState({ gutter: 8, sameWidth: true, fitViewport: true }); + useEffect(() => { + window.addEventListener('hashchange', hashChangeHandler); + return () => { + window.removeEventListener('hashchange', hashChangeHandler); + }; + }); + + useEffect(() => { + if (hash) { + const elementId = hash.replace('#', ''); + const [name, idx] = elementId.split(':'); + if (name && methodName === name) { + if (idx) { + const hashOverload = Number.parseInt(idx, 10); + const resolvedOverload = Math.max(Math.min(hashOverload, overloads.length), 1); + setOverloadIndex(Number.isNaN(resolvedOverload) ? 1 : resolvedOverload); + } + + const element = document.querySelector(`[id^='${name}']`); + if (element) { + element.scrollIntoView({ behavior: 'smooth' }); + } + } + } + }, [hash, methodName, overloads.length]); + const menuItems = useMemo( () => overloads.map((_, idx) => ( diff --git a/apps/website/src/components/model/function/Function.tsx b/apps/website/src/components/model/function/Function.tsx index d903f2ae2..abbb5c443 100644 --- a/apps/website/src/components/model/function/Function.tsx +++ b/apps/website/src/components/model/function/Function.tsx @@ -16,7 +16,7 @@ export function Function({ item }: { item: ApiFunction }) { return (
{header} - +
); } diff --git a/apps/website/src/components/model/method/Method.tsx b/apps/website/src/components/model/method/Method.tsx index dd6405235..e407dbc26 100644 --- a/apps/website/src/components/model/method/Method.tsx +++ b/apps/website/src/components/model/method/Method.tsx @@ -28,7 +28,7 @@ export function Method({ )); - return ; + return ; } // We have just a single method, render it on the server.