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(v2): correct client types and type aliases #4451

Merged
merged 1 commit into from
Mar 19, 2021
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
6 changes: 6 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,12 @@ module.exports = {
'header/header': OFF,
},
},
{
files: ['*.d.ts'],
rules: {
'import/no-duplicates': OFF,
},
},
{
files: ['*.js'],
rules: {
Expand Down
4 changes: 3 additions & 1 deletion packages/docusaurus-module-type-aliases/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
"devDependencies": {
"@types/react": "*",
"@types/react-helmet": "*",
"@types/react-router-dom": "*"
"@types/react-loadable": "*",
"@types/react-router-dom": "*",
"@types/react-router-config": "*"
},
"license": "MIT"
}
106 changes: 84 additions & 22 deletions packages/docusaurus-module-type-aliases/src/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,30 @@ declare module '@theme-original/*';
declare module '@docusaurus/*';

declare module '@docusaurus/Head' {
const helmet: typeof import('react-helmet').Helmet;
export default helmet;
import type {HelmetProps} from 'react-helmet';
import type {ReactNode} from 'react';

export type HeadProps = HelmetProps & {children: ReactNode};

const Head: (props: HeadProps) => JSX.Element;
export default Head;
}

declare module '@docusaurus/Link' {
import type {ReactNode} from 'react';

type RRLinkProps = Partial<import('react-router-dom').LinkProps>;
type LinkProps = RRLinkProps & {
to?: string;
activeClassName?: string;
isNavLink?: boolean;
export type LinkProps = RRLinkProps & {
readonly isNavLink?: boolean;
readonly to?: string;
readonly href?: string;
readonly activeClassName?: string;
readonly children?: ReactNode;
readonly isActive?: (match: any, location: any) => boolean;
readonly autoAddBaseUrl?: boolean;

// escape hatch in case broken links check is annoying for a specific link
readonly 'data-noBrokenLinkCheck'?: boolean;
};
const Link: (props: LinkProps) => JSX.Element;
export default Link;
Expand Down Expand Up @@ -125,41 +139,54 @@ declare module '@docusaurus/Translate' {
InterpolateValues,
} from '@docusaurus/Interpolate';

type TranslateProps<Str extends string> = InterpolateProps<Str> & {
export type TranslateParam<Str extends string> = Partial<
InterpolateProps<Str>
> & {
message: Str;
id?: string;
description?: string;
values?: InterpolateValues<Str, string | number>;
};
export default function Translate<Str extends string>(
props: TranslateProps<Str>,
): JSX.Element;

export function translate<Str extends string>(
param: {
message: Str;
id?: string;
description?: string;
},
param: TranslateParam<Str>,
values?: InterpolateValues<Str, string | number>,
): string;

export type TranslateProps<Str extends string> = InterpolateProps<Str> & {
id?: string;
description?: string;
};

export default function Translate<Str extends string>(
props: TranslateProps<Str>,
): JSX.Element;
}

declare module '@docusaurus/router' {
export const Redirect: (props: {to: string}) => import('react').Component;
export function matchPath(
pathname: string,
opts: {path?: string; exact?: boolean; strict?: boolean},
): boolean;
export function useLocation(): Location;
// eslint-disable-next-line import/no-extraneous-dependencies
export * from 'react-router-dom';
}

declare module '@docusaurus/useDocusaurusContext' {
export default function (): any;
}

declare module '@docusaurus/useBaseUrl' {
export type BaseUrlOptions = {
forcePrependBaseUrl?: boolean;
absolute?: boolean;
};

export type BaseUrlUtils = {
withBaseUrl: (url: string, options?: BaseUrlOptions) => string;
};

export function useBaseUrlUtils(): BaseUrlUtils;

export default function useBaseUrl(
relativePath: string | undefined,
opts?: {absolute?: true; forcePrependBaseUrl?: true},
opts?: BaseUrlOptions,
): string;
}

Expand All @@ -173,6 +200,16 @@ declare module '@docusaurus/ExecutionEnvironment' {
export default ExecutionEnvironment;
}

declare module '@docusaurus/ComponentCreator' {
import type Loadable from 'react-loadable';

function ComponentCreator(
path: string,
hash: string,
): ReturnType<typeof Loadable>;
export default ComponentCreator;
}

declare module '@docusaurus/BrowserOnly' {
export type Props = {
children?: () => JSX.Element;
Expand All @@ -187,6 +224,31 @@ declare module '@docusaurus/isInternalUrl' {
export default function isInternalUrl(url?: string): boolean;
}

declare module '@docusaurus/Noop' {
export default function (): null;
}

declare module '@docusaurus/renderRoutes' {
// eslint-disable-next-line import/no-extraneous-dependencies
import {renderRoutes} from 'react-router-config';

export default renderRoutes;
}

declare module '@docusaurus/useGlobalData' {
export function useAllPluginInstancesData<T = unknown>(
pluginName: string,
): Record<string, T>;

export function usePluginData<T = unknown>(
pluginName: string,
pluginId?: string,
): T;

function useGlobalData(): Record<string, any>;
export default useGlobalData;
}

declare module '*.module.css' {
const classes: {readonly [key: string]: string};
export default classes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ declare module '@theme/DocPage' {
readonly route: {
readonly path: string;
readonly component: () => JSX.Element;
readonly routes: readonly DocumentRoute[];
readonly routes: DocumentRoute[];
};
};

Expand Down
4 changes: 3 additions & 1 deletion packages/docusaurus-theme-classic/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,9 @@ declare module '@theme/Layout' {
}

declare module '@theme/LayoutHead' {
import type {Props} from '@theme/Layout';
import type {Props as LayoutProps} from '@theme/Layout';

export type Props = Omit<LayoutProps, 'children'>;

const LayoutHead: (props: Props) => JSX.Element;
export default LayoutHead;
Expand Down
4 changes: 3 additions & 1 deletion packages/docusaurus/src/client/exports/ComponentCreator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import routesChunkNames from '@generated/routesChunkNames';
import registry from '@generated/registry';
import flat from '../flat';

type OptsLoader = Record<string, typeof registry[keyof typeof registry][0]>;

function ComponentCreator(
path: string,
hash: string,
Expand All @@ -28,7 +30,7 @@ function ComponentCreator(
const chunkNames = routesChunkNames[chunkNamesKey];
const optsModules: string[] = [];
const optsWebpack: string[] = [];
const optsLoader = {};
const optsLoader: OptsLoader = {};

/* Prepare opts data that react-loadable needs
https://github.com/jamiebuilds/react-loadable#declaring-which-modules-are-being-loaded
Expand Down
7 changes: 3 additions & 4 deletions packages/docusaurus/src/client/exports/Head.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
* LICENSE file in the root directory of this source tree.
*/

import React, {ReactNode} from 'react';
import {Helmet, HelmetProps} from 'react-helmet';

type HeadProps = HelmetProps & {children: ReactNode};
import React from 'react';
import {Helmet} from 'react-helmet';
import type {HeadProps} from '@docusaurus/Head';

function Head(props: HeadProps): JSX.Element {
return <Helmet {...props} />;
Expand Down
20 changes: 5 additions & 15 deletions packages/docusaurus/src/client/exports/Interpolate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
*/

import React, {ReactNode} from 'react';
import type {
InterpolateProps,
InterpolateValues,
ExtractInterpolatePlaceholders,
} from '@docusaurus/Interpolate';

/*
Minimal implementation of a React interpolate component.
Expand All @@ -16,16 +21,6 @@ More details here: https://github.com/facebook/docusaurus/pull/4295
const ValueRegexp = /{\w+}/g;
const ValueFoundMarker = '{}'; // does not care much

// TODO use TS template literal feature to make values typesafe!
// (requires upgrading TS first)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
type ExtractInterpolatePlaceholders<Str extends string> = string;

type InterpolateValues<Str extends string, Value extends ReactNode> = Record<
ExtractInterpolatePlaceholders<Str>,
Value
>;

// TS function overload: if all the values are plain strings, then interpolate returns a simple string
export function interpolate<Str extends string>(
text: Str,
Expand Down Expand Up @@ -93,11 +88,6 @@ export function interpolate<Str extends string, Value extends ReactNode>(
}
}

export type InterpolateProps<Str extends string> = {
children: Str;
values?: InterpolateValues<Str, ReactNode>;
};

export default function Interpolate<Str extends string>({
children,
values,
Expand Down
31 changes: 9 additions & 22 deletions packages/docusaurus/src/client/exports/Link.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,36 +5,23 @@
* LICENSE file in the root directory of this source tree.
*/

import React, {ReactNode, useEffect, useRef} from 'react';
import React, {useEffect, useRef} from 'react';

import {NavLink, Link as RRLink} from 'react-router-dom';
import isInternalUrl from './isInternalUrl';
import ExecutionEnvironment from './ExecutionEnvironment';
import {useLinksCollector} from '../LinksCollector';
import {useBaseUrlUtils} from './useBaseUrl';

import type {LinkProps} from '@docusaurus/Link';
import type docusaurus from '../docusaurus';

declare global {
interface Window {
docusaurus: {
prefetch: (routePath: string) => boolean;
preload: (routePath: string) => boolean;
};
docusaurus: typeof docusaurus;
}
}

interface Props {
readonly isNavLink?: boolean;
readonly to?: string;
readonly href?: string;
readonly activeClassName?: string;
readonly children?: ReactNode;
readonly isActive?: () => boolean;
readonly autoAddBaseUrl?: boolean;

// escape hatch in case broken links check is annoying for a specific link
readonly 'data-noBrokenLinkCheck'?: boolean;
}

// TODO all this wouldn't be necessary if we used ReactRouter basename feature
// We don't automatically add base urls to all links,
// only the "safe" ones, starting with / (like /docs/introduction)
Expand All @@ -51,7 +38,7 @@ function Link({
'data-noBrokenLinkCheck': noBrokenLinkCheck,
autoAddBaseUrl = true,
...props
}: Props): JSX.Element {
}: LinkProps): JSX.Element {
const {withBaseUrl} = useBaseUrlUtils();
const linksCollector = useLinksCollector();

Expand Down Expand Up @@ -92,8 +79,8 @@ function Link({

const IOSupported = ExecutionEnvironment.canUseIntersectionObserver;

let io;
const handleIntersection = (el, cb) => {
let io: IntersectionObserver;
const handleIntersection = (el: HTMLAnchorElement, cb: () => void) => {
io = new window.IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (el === entry.target) {
Expand All @@ -112,7 +99,7 @@ function Link({
io.observe(el);
};

const handleRef = (ref) => {
const handleRef = (ref: HTMLAnchorElement | null) => {
if (IOSupported && ref && isInternal) {
// If IO supported and element reference found, setup Observer functionality.
handleIntersection(ref, () => {
Expand Down
13 changes: 1 addition & 12 deletions packages/docusaurus/src/client/exports/Translate.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@
import React from 'react';
import Interpolate, {
interpolate,
InterpolateProps,
InterpolateValues,
} from '@docusaurus/Interpolate';
import type {TranslateParam, TranslateProps} from '@docusaurus/Translate';

// Can't read it from context, due to exposing imperative API
import codeTranslations from '@generated/codeTranslations';
Expand All @@ -25,12 +25,6 @@ function getLocalizedMessage({
return codeTranslations[id ?? message] ?? message;
}

export type TranslateParam<Str extends string> = {
message: Str;
id?: string;
description?: string;
values?: InterpolateValues<Str, string | number>;
};
// Imperative translation API is useful for some edge-cases:
// - translating page titles (meta)
// - translating string props (input placeholders, image alt, aria labels...)
Expand All @@ -42,11 +36,6 @@ export function translate<Str extends string>(
return interpolate(localizedMessage, values);
}

export type TranslateProps<Str extends string> = InterpolateProps<Str> & {
id?: string;
description?: string;
};

// Maybe we'll want to improve this component with additional features
// Like toggling a translation mode that adds a little translation button near the text?
export default function Translate<Str extends string>({
Expand Down
Loading