Skip to content
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

refactor(theme-classic): apply import/no-named-export eslint rule #6283

Merged
merged 6 commits into from
Jan 7, 2022
Merged
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
10 changes: 10 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,16 @@ module.exports = {
],
},
overrides: [
{
files: [
'packages/docusaurus-theme-*/src/theme/**/*.js',
'packages/docusaurus-theme-*/src/theme/**/*.ts',
'packages/docusaurus-theme-*/src/theme/**/*.tsx',
],
rules: {
'import/no-named-export': ERROR,
},
},
{
files: [
'packages/create-docusaurus/templates/**/*.js',
Expand Down
73 changes: 46 additions & 27 deletions packages/docusaurus-theme-classic/src/theme-classic.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -149,23 +149,33 @@ declare module '@theme/DocSidebar' {
declare module '@theme/DocSidebarItem' {
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';

type DocSidebarPropsBase = {
export type DocSidebarPropsBase = {
readonly activePath: string;
readonly onItemClick?: (item: PropSidebarItem) => void;
readonly level: number;
readonly tabIndex?: number;
};

export interface Props extends DocSidebarPropsBase {
export interface Props {
readonly activePath: string;
readonly onItemClick?: (item: PropSidebarItem) => void;
readonly level: number;
readonly tabIndex?: number;
readonly item: PropSidebarItem;
}
const DocSidebarItem: (props: Props) => JSX.Element;
export default DocSidebarItem;

export type DocSidebarItemsProps = DocSidebarPropsBase & {
export default function DocSidebarItem(props: Props): JSX.Element;
}

declare module '@theme/DocSidebarItems' {
import type {Props as DocSidebarItemProps} from '@theme/DocSidebarItem';
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';

export type Props = Omit<DocSidebarItemProps, 'item'> & {
readonly items: readonly PropSidebarItem[];
};
export const DocSidebarItems: (props: DocSidebarItemsProps) => JSX.Element;

export default function DocSidebarItems(props: Props): JSX.Element;
}

declare module '@theme/DocVersionSuggestions' {
Expand Down Expand Up @@ -196,12 +206,13 @@ declare module '@theme/Footer' {
declare module '@theme/Heading' {
import type {ComponentProps} from 'react';

export type HeadingType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
export interface Props extends ComponentProps<HeadingType> {}
type HeadingType = 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';

export interface Props extends ComponentProps<HeadingType> {
as: HeadingType;
}

const Heading: (Tag: HeadingType) => (props: Props) => JSX.Element;
export default Heading;
export const MainHeading: (props: Props) => JSX.Element;
export default function Heading(props: Props): JSX.Element;
}

declare module '@theme/hooks/useHideableNavbar' {
Expand Down Expand Up @@ -372,18 +383,9 @@ declare module '@theme/Navbar' {
}

declare module '@theme/NavbarItem/DefaultNavbarItem' {
import type {ReactNode} from 'react';
import type {LinkProps} from '@docusaurus/Link';
import type {Props as NavbarNavLinkProps} from '@theme/NavbarItem/NavbarNavLink';

export type NavLinkProps = LinkProps & {
readonly activeBasePath?: string;
readonly activeBaseRegex?: string;
readonly exact?: boolean;
readonly label?: ReactNode;
readonly prependBaseUrlToHref?: string;
};

export type DesktopOrMobileNavBarItemProps = NavLinkProps & {
export type DesktopOrMobileNavBarItemProps = NavbarNavLinkProps & {
readonly isDropdownItem?: boolean;
readonly className?: string;
readonly position?: 'left' | 'right';
Expand All @@ -393,17 +395,30 @@ declare module '@theme/NavbarItem/DefaultNavbarItem' {
readonly mobile?: boolean;
}

export const NavLink: (props: NavLinkProps) => JSX.Element;
export default function DefaultNavbarItem(props: Props): JSX.Element;
}

const DefaultNavbarItem: (props: Props) => JSX.Element;
export default DefaultNavbarItem;
declare module '@theme/NavbarItem/NavbarNavLink' {
import type {ReactNode} from 'react';
import type {LinkProps} from '@docusaurus/Link';

export type Props = LinkProps & {
readonly activeBasePath?: string;
readonly activeBaseRegex?: string;
readonly exact?: boolean;
readonly label?: ReactNode;
readonly prependBaseUrlToHref?: string;
};

export default function NavbarNavLink(props: Props): JSX.Element;
}

declare module '@theme/NavbarItem/DropdownNavbarItem' {
import type {NavLinkProps} from '@theme/NavbarItem/DefaultNavbarItem';
import type {Props as NavbarNavLinkProps} from '@theme/NavbarItem/NavbarNavLink';

import type {LinkLikeNavbarItemProps} from '@theme/NavbarItem';

export type DesktopOrMobileNavBarItemProps = NavLinkProps & {
export type DesktopOrMobileNavBarItemProps = NavbarNavLinkProps & {
readonly position?: 'left' | 'right';
readonly items: readonly LinkLikeNavbarItemProps[];
readonly className?: string;
Expand Down Expand Up @@ -526,6 +541,10 @@ declare module '@theme/NavbarItem' {
export default NavbarItem;
}

declare module '@theme/NavbarItem/utils' {
export function getInfimaActiveClassName(mobile?: boolean): string;
}

declare module '@theme/PaginatorNavLink' {
import type {ReactNode} from 'react';
import type {PropNavigationLink} from '@docusaurus/plugin-content-docs';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import DocPaginator from '@theme/DocPaginator';
import Seo from '@theme/Seo';
import DocVersionBanner from '@theme/DocVersionBanner';
import DocVersionBadge from '@theme/DocVersionBadge';
import {MainHeading} from '@theme/Heading';
import Heading from '@theme/Heading';
import useBaseUrl from '@docusaurus/useBaseUrl';

import styles from './styles.module.css';
Expand All @@ -35,9 +35,9 @@ export default function DocCategoryGeneratedIndexPage({
<DocVersionBanner />
<DocVersionBadge />
<header>
<MainHeading className={styles.title}>
<Heading as="h1" className={styles.title}>
{categoryGeneratedIndex.title}
</MainHeading>
</Heading>
{categoryGeneratedIndex.description && (
<p>{categoryGeneratedIndex.description}</p>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type {Props} from '@theme/DocItem';
import DocItemFooter from '@theme/DocItemFooter';
import TOC from '@theme/TOC';
import TOCCollapsible from '@theme/TOCCollapsible';
import {MainHeading} from '@theme/Heading';
import Heading from '@theme/Heading';
import styles from './styles.module.css';
import {ThemeClassNames} from '@docusaurus/theme-common';

Expand Down Expand Up @@ -80,7 +80,11 @@ export default function DocItem(props: Props): JSX.Element {
To make both cases consistent, the added title is added under the same div.markdown block
See https://github.com/facebook/docusaurus/pull/4882#issuecomment-853021120
*/}
{shouldAddTitle && <MainHeading>{title}</MainHeading>}
{shouldAddTitle && (
<header>
<Heading as="h1">{title}</Heading>
</header>
)}

<DocContent />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import useWindowSize from '@theme/hooks/useWindowSize';
import Logo from '@theme/Logo';
import IconArrow from '@theme/IconArrow';
import {translate} from '@docusaurus/Translate';
import {DocSidebarItems} from '@theme/DocSidebarItem';
import DocSidebarItems from '@theme/DocSidebarItems';
import type {Props} from '@theme/DocSidebar';

import styles from './styles.module.css';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/

import React, {useEffect, memo, useMemo} from 'react';
import React, {useEffect, useMemo} from 'react';
import clsx from 'clsx';
import {
isActiveSidebarItem,
Expand All @@ -20,7 +20,8 @@ import isInternalUrl from '@docusaurus/isInternalUrl';
import {translate} from '@docusaurus/Translate';
import IconExternalLink from '@theme/IconExternalLink';

import type {Props, DocSidebarItemsProps} from '@theme/DocSidebarItem';
import DocSidebarItems from '@theme/DocSidebarItems';
import type {Props} from '@theme/DocSidebarItem';
import type {
PropSidebarItemCategory,
PropSidebarItemLink,
Expand All @@ -29,23 +30,6 @@ import type {
import styles from './styles.module.css';
import useIsBrowser from '@docusaurus/useIsBrowser';

// Optimize sidebar at each "level"
// TODO this item should probably not receive the "activePath" props
// TODO this triggers whole sidebar re-renders on navigation
export const DocSidebarItems = memo(
({items, ...props}: DocSidebarItemsProps): JSX.Element => (
<>
{items.map((item, index) => (
<DocSidebarItem
key={index} // sidebar is static, the index does not change
item={item}
{...props}
/>
))}
</>
),
);

export default function DocSidebarItem({
item,
...props
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import React, {memo} from 'react';

import DocSidebarItem from '@theme/DocSidebarItem';

import type {Props} from '@theme/DocSidebarItems';

// TODO this item should probably not receive the "activePath" props
// TODO this triggers whole sidebar re-renders on navigation
function DocSidebarItems({items, ...props}: Props): JSX.Element {
return (
<>
{items.map((item, index) => (
<DocSidebarItem
key={index} // sidebar is static, the index does not change
item={item}
{...props}
/>
))}
</>
);
}

// Optimize sidebar at each "level"
export default memo(DocSidebarItems);
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

@media (min-width: 997px) {
.menuLinkText {
cursor: initial;
}
.menuLinkText:hover {
background: none;
}

.menuLinkText.hasHref {
cursor: pointer;
}
}
85 changes: 39 additions & 46 deletions packages/docusaurus-theme-classic/src/theme/Heading/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,62 +7,55 @@

import React from 'react';
import clsx from 'clsx';
import type {HeadingType, Props} from '@theme/Heading';
import type {Props} from '@theme/Heading';
import {translate} from '@docusaurus/Translate';
import {useThemeConfig} from '@docusaurus/theme-common';

import './styles.css';
import styles from './styles.module.css';

type HeadingComponent = (props: Props) => JSX.Element;
function AnchorHeading({as: As, id, ...props}: Props) {
const {
navbar: {hideOnScroll},
} = useThemeConfig();

// eslint-disable-next-line react/function-component-definition
export const MainHeading: HeadingComponent = ({...props}) => (
<header>
<h1
if (!id) {
return <As {...props} />;
}

return (
<As
{...props}
id={undefined} // h1 headings do not need an id because they don't appear in the TOC
>
className={clsx('anchor', {
[styles.anchorWithHideOnScrollNavbar]: hideOnScroll,
[styles.anchorWithStickyNavbar]: !hideOnScroll,
})}
id={id}>
{props.children}
</h1>
</header>
);

const createAnchorHeading =
(Tag: HeadingType) =>
({id, ...props}: Props) => {
const {
navbar: {hideOnScroll},
} = useThemeConfig();

if (!id) {
return <Tag {...props} />;
}

<a
className="hash-link"
href={`#${id}`}
title={translate({
id: 'theme.common.headingLinkTitle',
message: 'Direct link to heading',
description: 'Title for link to heading',
})}>
&#8203;
</a>
</As>
);
}

export default function Heading({as, ...props}: Props) {
if (as === 'h1') {
return (
<Tag
<h1
{...props}
className={clsx('anchor', {
[styles.anchorWithHideOnScrollNavbar]: hideOnScroll,
[styles.anchorWithStickyNavbar]: !hideOnScroll,
})}
id={id}>
id={undefined} // h1 headings do not need an id because they don't appear in the TOC
>
{props.children}
<a
className="hash-link"
href={`#${id}`}
title={translate({
id: 'theme.common.headingLinkTitle',
message: 'Direct link to heading',
description: 'Title for link to heading',
})}>
&#8203;
</a>
</Tag>
</h1>
);
};

const Heading = (headingType: HeadingType): ((props: Props) => JSX.Element) =>
headingType === 'h1' ? MainHeading : createAnchorHeading(headingType);

export default Heading;
}
return <AnchorHeading as={as} {...props} />;
}
Loading