From 007e9013549bffc3e2ee4b87c20e10ca2a5918dc Mon Sep 17 00:00:00 2001 From: Joshua Chen Date: Thu, 15 Jul 2021 00:19:08 +0800 Subject: [PATCH] feat(v2): allow any type of `NavbarItem` to be passed in a navbar dropdown (#5072) * Initial work Signed-off-by: Josh-Cena * More elegant `eslint-disable` Signed-off-by: Josh-Cena * Fix typing Signed-off-by: Josh-Cena * Allow doc links in dropdown Signed-off-by: Josh-Cena * Allow more dropdowns to use linklike items Signed-off-by: Josh-Cena * Finalize Signed-off-by: Josh-Cena * Dogfood Signed-off-by: Josh-Cena * Disallow nested dropdowns Signed-off-by: Josh-Cena * Better typing Signed-off-by: Josh-Cena * Complete type fix Signed-off-by: Josh-Cena * Use flatmap Signed-off-by: Josh-Cena * Patch Signed-off-by: Josh-Cena * Test Signed-off-by: Josh-Cena * Try fix Signed-off-by: Josh-Cena * Style change Signed-off-by: Josh-Cena * Revert (to test) Signed-off-by: Josh-Cena * Hmmm Signed-off-by: Josh-Cena * I know what's wrong Signed-off-by: Josh-Cena * Does this work? Signed-off-by: Josh-Cena * Nope Signed-off-by: Josh-Cena * Wrong class name Signed-off-by: Josh-Cena * Pass prop to render dropdown item differently Signed-off-by: Josh-Cena * This looks better Signed-off-by: Josh-Cena * Tests passed Signed-off-by: Josh-Cena * Separate dropdown from default Signed-off-by: Josh-Cena * Pourquois? Signed-off-by: Josh-Cena * Better prop typing Signed-off-by: Josh-Cena * Make code simpler Signed-off-by: Josh-Cena * There's some extra className Signed-off-by: Josh-Cena * Test Signed-off-by: Josh-Cena * More test Signed-off-by: Josh-Cena * A-ha! Signed-off-by: Josh-Cena * Test again? * Add backward compatibility Signed-off-by: Josh-Cena * Incorporate my type fix Signed-off-by: Josh-Cena * Resolve conflict Signed-off-by: Josh-Cena * minor refactor * minor refactors * allow usage of ES2019 in browser code * revert NavLink rename Co-authored-by: slorber --- .../src/plugin-content-docs.d.ts | 2 +- .../src/theme/DocVersionBanner/index.tsx | 2 +- .../src/theme/Navbar/index.tsx | 23 ++- .../theme/NavbarItem/DefaultNavbarItem.tsx | 163 ++---------------- .../src/theme/NavbarItem/DocNavbarItem.tsx | 11 +- .../DocsVersionDropdownNavbarItem.tsx | 33 ++-- .../theme/NavbarItem/DropdownNavbarItem.tsx | 147 ++++++++++++++++ .../NavbarItem/LocaleDropdownNavbarItem.tsx | 4 +- .../src/theme/NavbarItem/index.tsx | 49 ++++-- .../docusaurus-theme-classic/src/types.d.ts | 96 +++++++---- .../docusaurus-theme-classic/tsconfig.json | 2 +- packages/docusaurus/tsconfig.client.json | 2 +- packages/docusaurus/tsconfig.json | 2 +- 13 files changed, 298 insertions(+), 238 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/NavbarItem/DropdownNavbarItem.tsx diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 54a9569530..3eb8c317c0 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -8,7 +8,7 @@ /* eslint-disable camelcase */ declare module '@docusaurus/plugin-content-docs-types' { - import type {VersionBanner} from './types'; + type VersionBanner = import('./types').VersionBanner; export type PropVersionMetadata = { pluginId: string; diff --git a/packages/docusaurus-theme-classic/src/theme/DocVersionBanner/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocVersionBanner/index.tsx index 9c9fc20f90..e80c8165d5 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocVersionBanner/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocVersionBanner/index.tsx @@ -58,7 +58,7 @@ function UnmaintainedVersionLabel({ } const BannerLabelComponents: Record< - Props['versionMetadata']['banner'], + Exclude, ComponentType > = { unreleased: UnreleasedVersionLabel, diff --git a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx index f76a9b58a7..392d6098df 100644 --- a/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Navbar/index.tsx @@ -19,7 +19,7 @@ import { import useHideableNavbar from '@theme/hooks/useHideableNavbar'; import useLockBodyScroll from '@theme/hooks/useLockBodyScroll'; import useWindowSize from '@theme/hooks/useWindowSize'; -import NavbarItem from '@theme/NavbarItem'; +import NavbarItem, {Props as NavbarItemConfig} from '@theme/NavbarItem'; import Logo from '@theme/Logo'; import IconMenu from '@theme/IconMenu'; @@ -28,9 +28,14 @@ import styles from './styles.module.css'; // retrocompatible with v1 const DefaultNavItemPosition = 'right'; +function useNavbarItems() { + // TODO temporary casting until ThemeConfig type is improved + return useThemeConfig().navbar.items as NavbarItemConfig[]; +} + // If split links by left/right // if position is unspecified, fallback to right (as v1) -function splitNavItemsByPosition(items) { +function splitNavItemsByPosition(items: NavbarItemConfig[]) { const leftItems = items.filter( (item) => (item.position ?? DefaultNavItemPosition) === 'left', ); @@ -132,9 +137,7 @@ function NavbarMobileSidebar({ toggleSidebar, }: NavbarMobileSidebarProps) { useLockBodyScroll(sidebarShown); - const { - navbar: {items}, - } = useThemeConfig(); + const items = useNavbarItems(); const colorModeToggle = useColorModeToggle(); @@ -166,12 +169,7 @@ function NavbarMobileSidebar({
    {items.map((item, i) => ( - + ))}
@@ -196,7 +194,7 @@ function NavbarMobileSidebar({ function Navbar(): JSX.Element { const { - navbar: {items, hideOnScroll, style}, + navbar: {hideOnScroll, style}, } = useThemeConfig(); const mobileSidebar = useMobileSidebar(); @@ -204,6 +202,7 @@ function Navbar(): JSX.Element { const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll); + const items = useNavbarItems(); const hasSearchNavbarItem = items.some((item) => item.type === 'search'); const {leftItems, rightItems} = splitNavItemsByPosition(items); diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx index 5ed2dc65a1..f9beb905a7 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx @@ -5,16 +5,10 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useState, useRef, useEffect} from 'react'; +import React from 'react'; import clsx from 'clsx'; import Link from '@docusaurus/Link'; import useBaseUrl from '@docusaurus/useBaseUrl'; -import {useLocation} from '@docusaurus/router'; -import { - isSamePath, - useCollapsible, - Collapsible, -} from '@docusaurus/theme-common'; import type { NavLinkProps, DesktopOrMobileNavBarItemProps, @@ -25,7 +19,7 @@ import isInternalUrl from '@docusaurus/isInternalUrl'; const dropdownLinkActiveClass = 'dropdown__link--active'; -function NavLink({ +export function NavLink({ activeBasePath, activeBaseRegex, to, @@ -34,7 +28,7 @@ function NavLink({ activeClassName = 'navbar__link--active', prependBaseUrlToHref, ...props -}: NavLinkProps) { +}: NavLinkProps): JSX.Element { // TODO all this seems hacky // {to: 'version'} should probably be forbidden, in favor of {to: '/version'} const toUrl = useBaseUrl(to); @@ -75,159 +69,36 @@ function NavLink({ ); } -function NavItemDesktop({ - items, - position, +function DefaultNavbarItemDesktop({ className, + isDropdownItem = false, ...props }: DesktopOrMobileNavBarItemProps) { - const dropdownRef = useRef(null); - const dropdownMenuRef = useRef(null); - const [showDropdown, setShowDropdown] = useState(false); - - useEffect(() => { - const handleClickOutside = (event) => { - if (!dropdownRef.current || dropdownRef.current.contains(event.target)) { - return; - } - - setShowDropdown(false); - }; - - document.addEventListener('mousedown', handleClickOutside); - document.addEventListener('touchstart', handleClickOutside); - - return () => { - document.removeEventListener('mousedown', handleClickOutside); - document.removeEventListener('touchstart', handleClickOutside); - }; - }, [dropdownRef]); - - const navLinkClassNames = (extraClassName?: string, isDropdownItem = false) => - clsx( - { - 'navbar__item navbar__link': !isDropdownItem, - dropdown__link: isDropdownItem, - }, - extraClassName, - ); - - if (!items) { - return ; - } - return ( -
- e.preventDefault()} - onKeyDown={(e) => { - if (e.key === 'Enter') { - e.preventDefault(); - setShowDropdown(!showDropdown); - } - }}> - {props.children ?? props.label} - -
    - {items.map(({className: childItemClassName, ...childItemProps}, i) => ( -
  • - { - if (i === items.length - 1 && e.key === 'Tab') { - e.preventDefault(); - - setShowDropdown(false); - - const nextNavbarItem = (dropdownRef.current as HTMLElement) - .nextElementSibling; - - if (nextNavbarItem) { - (nextNavbarItem as HTMLElement).focus(); - } - } - }} - activeClassName={dropdownLinkActiveClass} - className={navLinkClassNames(childItemClassName, true)} - {...childItemProps} - /> -
  • - ))} -
-
+ ); } -function NavItemMobile({ - items, +function DefaultNavbarItemMobile({ className, - position: _position, // Need to destructure position from props so that it doesn't get passed on. + isDropdownItem: _isDropdownItem, ...props }: DesktopOrMobileNavBarItemProps) { - const {pathname} = useLocation(); - const {collapsed, toggleCollapsed} = useCollapsible({ - initialState: () => - !items?.some((item) => isSamePath(item.to, pathname)) ?? true, - }); - - const navLinkClassNames = (extraClassName?: string, isSubList = false) => - clsx( - 'menu__link', - { - 'menu__link--sublist': isSubList, - }, - extraClassName, - ); - - if (!items) { - return ( -
  • - -
  • - ); - } - return ( -
  • - { - e.preventDefault(); - toggleCollapsed(); - }}> - {props.children ?? props.label} - - - - {items.map(({className: childItemClassName, ...childItemProps}, i) => ( -
  • - -
  • - ))} - +
  • +
  • ); } function DefaultNavbarItem({mobile = false, ...props}: Props): JSX.Element { - const Comp = mobile ? NavItemMobile : NavItemDesktop; + const Comp = mobile ? DefaultNavbarItemMobile : DefaultNavbarItemDesktop; return ; } diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx index c9a681ea29..baa9bb12b1 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocNavbarItem.tsx @@ -12,17 +12,10 @@ import clsx from 'clsx'; import type {Props} from '@theme/NavbarItem/DocNavbarItem'; import {useDocsPreferredVersion} from '@docusaurus/theme-common'; import {uniq} from '@docusaurus/utils-common'; -import type { - GlobalDataVersion, - GlobalDataDoc, -} from '@docusaurus/plugin-content-docs-types'; +import type {GlobalDataVersion} from '@docusaurus/plugin-content-docs-types'; function getDocInVersions(versions: GlobalDataVersion[], docId: string) { - // vanilla-js flatten, TODO replace soon by ES flat() / flatMap() - const allDocs: GlobalDataDoc[] = [].concat( - ...versions.map((version) => version.docs), - ); - + const allDocs = versions.flatMap((version) => version.docs); const doc = allDocs.find((versionDoc) => versionDoc.id === docId); if (!doc) { const docIds = allDocs.map((versionDoc) => versionDoc.id).join('\n- '); diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx index cfcdd89ded..d3593d3178 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx @@ -7,6 +7,7 @@ import React from 'react'; import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem'; +import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem'; import { useVersions, useLatestVersion, @@ -52,20 +53,7 @@ export default function DocsVersionDropdownNavbarItem({ }; }); - const items = [ - ...dropdownItemsBefore, - ...versionLinks, - ...dropdownItemsAfter, - ]; - - // We don't want to render a version dropdown with 0 or 1 item - // If we build the site with a single docs version (onlyIncludeVersions: ['1.0.0']) - // We'd rather render a button instead of a dropdown - if (items.length <= 1) { - return undefined; - } - - return items; + return [...dropdownItemsBefore, ...versionLinks, ...dropdownItemsAfter]; } const items = getItems(); @@ -78,8 +66,23 @@ export default function DocsVersionDropdownNavbarItem({ const dropdownTo = mobile && items ? undefined : getVersionMainDoc(dropdownVersion).path; + // We don't want to render a version dropdown with 0 or 1 item + // If we build the site with a single docs version (onlyIncludeVersions: ['1.0.0']) + // We'd rather render a button instead of a dropdown + if (items.length <= 1) { + return ( + false : undefined} + /> + ); + } + return ( - (null); + const dropdownMenuRef = useRef(null); + const [showDropdown, setShowDropdown] = useState(false); + + useEffect(() => { + const handleClickOutside = (event: MouseEvent | TouchEvent) => { + if ( + !dropdownRef.current || + dropdownRef.current.contains(event.target as Node) + ) { + return; + } + setShowDropdown(false); + }; + + document.addEventListener('mousedown', handleClickOutside); + document.addEventListener('touchstart', handleClickOutside); + + return () => { + document.removeEventListener('mousedown', handleClickOutside); + document.removeEventListener('touchstart', handleClickOutside); + }; + }, [dropdownRef]); + + return ( +
    + e.preventDefault()} + onKeyDown={(e) => { + if (e.key === 'Enter') { + e.preventDefault(); + setShowDropdown(!showDropdown); + } + }}> + {props.children ?? props.label} + +
      + {items.map((childItemProps, i) => ( + { + if (i === items.length - 1 && e.key === 'Tab') { + e.preventDefault(); + setShowDropdown(false); + const nextNavbarItem = dropdownRef.current!.nextElementSibling; + if (nextNavbarItem) { + (nextNavbarItem as HTMLElement).focus(); + } + } + }} + activeClassName={dropdownLinkActiveClass} + {...childItemProps} + key={i} + /> + ))} +
    +
    + ); +} + +function DropdownNavbarItemMobile({ + items, + className, + position: _position, // Need to destructure position from props so that it doesn't get passed on. + ...props +}: DesktopOrMobileNavBarItemProps) { + const {pathname} = useLocation(); + const {collapsed, toggleCollapsed} = useCollapsible({ + initialState: () => + !items?.some((item) => isSamePath(item.to, pathname)) ?? true, + }); + + return ( +
  • + { + e.preventDefault(); + toggleCollapsed(); + }}> + {props.children ?? props.label} + + + {items.map((childItemProps, i) => ( + + ))} + +
  • + ); +} + +function DropdownNavbarItem({mobile = false, ...props}: Props): JSX.Element { + const Comp = mobile ? DropdownNavbarItemMobile : DropdownNavbarItemDesktop; + return ; +} + +export default DropdownNavbarItem; diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/LocaleDropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/LocaleDropdownNavbarItem.tsx index 800abdcca1..82877b72ae 100644 --- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/LocaleDropdownNavbarItem.tsx +++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/LocaleDropdownNavbarItem.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem'; +import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem'; import IconLanguage from '@theme/IconLanguage'; import type {Props} from '@theme/NavbarItem/LocaleDropdownNavbarItem'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; @@ -49,7 +49,7 @@ export default function LocaleDropdownNavbarItem({ const dropdownLabel = mobile ? 'Languages' : getLocaleLabel(currentLocale); return ( - , + () => (props) => JSX.Element +> = { default: () => DefaultNavbarItem, localeDropdown: () => LocaleDropdownNavbarItem, search: () => SearchNavbarItem, + dropdown: () => DropdownNavbarItem, // Need to lazy load these items as we don't know for sure the docs plugin is loaded // See https://github.com/facebook/docusaurus/issues/3360 - docsVersion: () => - // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require - require('@theme/NavbarItem/DocsVersionNavbarItem').default, + /* eslint-disable @typescript-eslint/no-var-requires, global-require */ + docsVersion: () => require('@theme/NavbarItem/DocsVersionNavbarItem').default, docsVersionDropdown: () => - // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require require('@theme/NavbarItem/DocsVersionDropdownNavbarItem').default, - doc: () => - // eslint-disable-next-line @typescript-eslint/no-var-requires, global-require - require('@theme/NavbarItem/DocNavbarItem').default, + doc: () => require('@theme/NavbarItem/DocNavbarItem').default, + /* eslint-enable @typescript-eslint/no-var-requires, global-require */ } as const; -const getNavbarItemComponent = ( - type: keyof typeof NavbarItemComponents = 'default', -) => { - const navbarItemComponent = NavbarItemComponents[type]; - if (!navbarItemComponent) { +type NavbarItemComponentType = keyof typeof NavbarItemComponents; + +const getNavbarItemComponent = (type: NavbarItemComponentType) => { + const navbarItemComponentFn = NavbarItemComponents[type]; + if (!navbarItemComponentFn) { throw new Error(`No NavbarItem component found for type "${type}".`); } - return navbarItemComponent(); + return navbarItemComponentFn(); }; -export default function NavbarItem({type, ...props}: Props): JSX.Element { - const NavbarItemComponent = getNavbarItemComponent(type); +function getComponentType({type, ...props}: Props): NavbarItemComponentType { + // Backward compatibility: navbar item with no type set + // but containing dropdown items should use the type "dropdown" + if (!type || type === 'default') { + const isDropdown = (props as DropdownNavbarItemProps).items !== undefined; + return isDropdown ? 'dropdown' : 'default'; + } + return type as NavbarItemComponentType; +} + +export default function NavbarItem(props: Props): JSX.Element { + const componentType = getComponentType(props); + const NavbarItemComponent = getNavbarItemComponent(componentType); return ; } diff --git a/packages/docusaurus-theme-classic/src/types.d.ts b/packages/docusaurus-theme-classic/src/types.d.ts index b78ecfa175..ff61653203 100644 --- a/packages/docusaurus-theme-classic/src/types.d.ts +++ b/packages/docusaurus-theme-classic/src/types.d.ts @@ -334,23 +334,18 @@ declare module '@theme/Navbar' { } declare module '@theme/NavbarItem/DefaultNavbarItem' { - import type {ComponentProps, ReactNode} from 'react'; + import type {LinkProps} from '@docusaurus/Link'; - export type NavLinkProps = { - activeBasePath?: string; - activeBaseRegex?: string; - to?: string; - exact?: boolean; - href?: string; - label?: ReactNode; - activeClassName?: string; - prependBaseUrlToHref?: string; - isActive?: () => boolean; - } & ComponentProps<'a'>; + export type NavLinkProps = LinkProps & { + readonly activeBasePath?: string; + readonly activeBaseRegex?: string; + readonly exact?: boolean; + readonly label?: ReactNode; + readonly prependBaseUrlToHref?: string; + }; export type DesktopOrMobileNavBarItemProps = NavLinkProps & { - readonly items?: readonly NavLinkProps[]; - readonly position?: 'left' | 'right'; + readonly isDropdownItem?: boolean; readonly className?: string; }; @@ -358,10 +353,30 @@ declare module '@theme/NavbarItem/DefaultNavbarItem' { readonly mobile?: boolean; }; + export const NavLink: (props: NavLinkProps) => JSX.Element; + const DefaultNavbarItem: (props: Props) => JSX.Element; export default DefaultNavbarItem; } +declare module '@theme/NavbarItem/DropdownNavbarItem' { + import type {NavLinkProps} from '@theme/NavbarItem/DefaultNavbarItem'; + import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem'; + + export type DesktopOrMobileNavBarItemProps = NavLinkProps & { + readonly position?: 'left' | 'right'; + readonly items: readonly LinkLikeNavbarItemProps[]; + readonly className?: string; + }; + + export type Props = DesktopOrMobileNavBarItemProps & { + readonly mobile?: boolean; + }; + + const DropdownNavbarItem: (props: Props) => JSX.Element; + export default DropdownNavbarItem; +} + declare module '@theme/NavbarItem/SearchNavbarItem' { export type Props = {readonly mobile?: boolean}; @@ -370,12 +385,12 @@ declare module '@theme/NavbarItem/SearchNavbarItem' { } declare module '@theme/NavbarItem/LocaleDropdownNavbarItem' { - import type {Props as DefaultNavbarItemProps} from '@theme/NavbarItem/DefaultNavbarItem'; - import type {NavLinkProps} from '@theme/NavbarItem/DefaultNavbarItem'; + import type {Props as DropdownNavbarItemProps} from '@theme/NavbarItem/DropdownNavbarItem'; + import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem'; - export type Props = DefaultNavbarItemProps & { - readonly dropdownItemsBefore: NavLinkProps[]; - readonly dropdownItemsAfter: NavLinkProps[]; + export type Props = DropdownNavbarItemProps & { + readonly dropdownItemsBefore: LinkLikeNavbarItemProps[]; + readonly dropdownItemsAfter: LinkLikeNavbarItemProps[]; }; const LocaleDropdownNavbarItem: (props: Props) => JSX.Element; @@ -383,14 +398,14 @@ declare module '@theme/NavbarItem/LocaleDropdownNavbarItem' { } declare module '@theme/NavbarItem/DocsVersionDropdownNavbarItem' { - import type {Props as DefaultNavbarItemProps} from '@theme/NavbarItem/DefaultNavbarItem'; - import type {NavLinkProps} from '@theme/NavbarItem/DefaultNavbarItem'; + import type {Props as DropdownNavbarItemProps} from '@theme/NavbarItem/DropdownNavbarItem'; + import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem'; - export type Props = DefaultNavbarItemProps & { + export type Props = DropdownNavbarItemProps & { readonly docsPluginId?: string; readonly dropdownActiveClassDisabled?: boolean; - readonly dropdownItemsBefore: NavLinkProps[]; - readonly dropdownItemsAfter: NavLinkProps[]; + readonly dropdownItemsBefore: LinkLikeNavbarItemProps[]; + readonly dropdownItemsAfter: LinkLikeNavbarItemProps[]; }; const DocsVersionDropdownNavbarItem: (props: Props) => JSX.Element; @@ -420,18 +435,35 @@ declare module '@theme/NavbarItem/DocNavbarItem' { } declare module '@theme/NavbarItem' { + import type {ComponentProps} from 'react'; import type {Props as DefaultNavbarItemProps} from '@theme/NavbarItem/DefaultNavbarItem'; - import type {Props as DocsVersionDropdownNavbarItemProps} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem'; + import type {Props as DocNavbarItemProps} from '@theme/NavbarItem/DocNavbarItem'; import type {Props as DocsVersionNavbarItemProps} from '@theme/NavbarItem/DocsVersionNavbarItem'; + import type {Props as DropdownNavbarItemProps} from '@theme/NavbarItem/DropdownNavbarItem'; + import type {Props as DocsVersionDropdownNavbarItemProps} from '@theme/NavbarItem/DocsVersionDropdownNavbarItem'; + import type {Props as LocaleDropdownNavbarItemProps} from '@theme/NavbarItem/LocaleDropdownNavbarItem'; import type {Props as SearchNavbarItemProps} from '@theme/NavbarItem/SearchNavbarItem'; - export type Props = - | ({readonly type?: 'default' | undefined} & DefaultNavbarItemProps) - | ({ - readonly type: 'docsVersionDropdown'; - } & DocsVersionDropdownNavbarItemProps) - | ({readonly type: 'docsVersion'} & DocsVersionNavbarItemProps) - | ({readonly type: 'search'} & SearchNavbarItemProps); + export type LinkLikeNavbarItemProps = + | ({readonly type?: 'default'} & DefaultNavbarItemProps) + | ({readonly type: 'doc'} & DocNavbarItemProps) + | ({readonly type: 'docsVersion'} & DocsVersionNavbarItemProps); + + export type Props = ComponentProps<'a'> & { + readonly position?: 'left' | 'right'; + } & ( + | LinkLikeNavbarItemProps + | ({readonly type?: 'dropdown'} & DropdownNavbarItemProps) + | ({ + readonly type: 'docsVersionDropdown'; + } & DocsVersionDropdownNavbarItemProps) + | ({readonly type: 'localeDropdown'} & LocaleDropdownNavbarItemProps) + | ({ + readonly type: 'search'; + } & SearchNavbarItemProps) + ); + + export type Types = Props['type']; const NavbarItem: (props: Props) => JSX.Element; export default NavbarItem; diff --git a/packages/docusaurus-theme-classic/tsconfig.json b/packages/docusaurus-theme-classic/tsconfig.json index a27160e601..583180dbf9 100644 --- a/packages/docusaurus-theme-classic/tsconfig.json +++ b/packages/docusaurus-theme-classic/tsconfig.json @@ -1,7 +1,7 @@ { "extends": "../../tsconfig.json", "compilerOptions": { - "lib": ["DOM"], + "lib": ["DOM", "ES2019"], "module": "esnext", "noEmit": true, "noImplicitAny": false, diff --git a/packages/docusaurus/tsconfig.client.json b/packages/docusaurus/tsconfig.client.json index 9793574687..be6a7cf8a1 100644 --- a/packages/docusaurus/tsconfig.client.json +++ b/packages/docusaurus/tsconfig.client.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "incremental": true, - "lib": ["DOM"], + "lib": ["DOM", "ES2019"], "module": "esnext", "tsBuildInfoFile": "./lib/client/.tsbuildinfo", "outDir": "lib/client", diff --git a/packages/docusaurus/tsconfig.json b/packages/docusaurus/tsconfig.json index cec1ef7143..17680c56b9 100644 --- a/packages/docusaurus/tsconfig.json +++ b/packages/docusaurus/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "incremental": true, - "lib": ["DOM"], + "lib": ["DOM", "ES2019"], "tsBuildInfoFile": "./lib/.tsbuildinfo", "rootDir": "src", "outDir": "lib",