Skip to content

Commit

Permalink
docs: add documentation to all exports
Browse files Browse the repository at this point in the history
  • Loading branch information
angeloashmore committed Jul 28, 2021
1 parent 3a083ca commit ba15a01
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 37 deletions.
67 changes: 66 additions & 1 deletion src/PrismicLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,90 @@ import { isInternalURL } from "./lib/isInternalURL";

import { usePrismicContext } from "./PrismicProvider";

/**
* Props provided to a component when rendered with `<PrismicLink>`.
*/
export interface LinkProps {
/** The URL to link. */
href: string;

/** The `target` attribute for anchor elements. If the Prismic field is configured to open in a new window, this prop defaults to `_blank`. */
target?: string;

/** The `rel` attribute for anchor elements. If the `target` prop is set to `"_blank"`, this prop defaults to `"noopener noreferrer"`. */
rel?: string;

/** Children for the component. **/
children?: React.ReactNode;
}

/**
* Props for `<PrismicLink>`.
*/
export type PrismicLinkProps = {
/**
* The Link Resolver used to resolve links.
*
* @remarks If your app uses Route Resolvers when querying for your Prismic repository's content, a Link Resolver does not need to be provided.
*
* @see Learn about Link Resolvers and Route Resolvers {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}
*/
linkResolver?: prismicH.LinkResolverFunction;

/**
* The component rendered for internal URLs. Defaults to `<a>`.
*
* If your app uses a client-side router that requires a special Link component, provide the Link component to this prop.
*/
internalComponent?: string | React.ComponentType<LinkProps>;

/** The component rendered for external URLs. Defaults to `<a>`. */
externalComponent?: string | React.ComponentType<LinkProps>;

/** The `target` attribute for anchor elements. If the Prismic field is configured to open in a new window, this prop defaults to `_blank`. */
target?: string;

/** The `rel` attribute for anchor elements. If the `target` prop is set to `"_blank"`, this prop defaults to `"noopener noreferrer"`. */
rel?: string;

/** Children for the component. **/
children?: React.ReactNode;
} & ({ field: prismicT.LinkField } | { href: string });
} & (
| {
/**
* The Prismic Link field containing the URL or document to link.
*
* @see Learn about Prismic Link fields {@link https://prismic.io/docs/core-concepts/link-content-relationship}
*/
field: prismicT.LinkField;
}
| {
/** The URL to link. */
href: string;
}
);

/**
* The default component rendered for internal URLs.
*/
const defaultInternalComponent = "a";

/**
* The default component rendered for external URLs.
*/
const defaultExternalComponent = "a";

/**
* React component to render a link from a Prismic Link field.
*
* Different components can be rendered depending on whether the link is internal or external. This is helpful when integrating with client-side routers, such as a router-specific Link component.
*
* If a link is configured to open in a new window using `target="_blank"`, `rel="noopener noreferrer"` is set by default.
*
* @param props Props for the component.
*
* @returns The internal or external link component depending on whether the link is internal or external.
*/
export const PrismicLink = (props: PrismicLinkProps): JSX.Element => {
const context = usePrismicContext();

Expand Down
67 changes: 66 additions & 1 deletion src/PrismicProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,89 @@ import * as prismic from "@prismicio/client";
import * as prismicH from "@prismicio/helpers";

import { LinkProps } from "./PrismicLink";
import { JSXFunctionSerializer, JSXMapSerializer } from "./types";

/**
* React context value containing shared configuration for `@prismicio/react` components and hooks.
*/
export type PrismicContextValue = {
/**
* A `@prismicio/client` instance used to fetch content from a Prismic repository. This is used by `@prismicio/react` hooks, such as `usePrismicDocuments()`.
*/
client?: prismic.Client;

/**
* A Link Resolver used to resolve links for `<PrismicLink>` and `<PrismicRichText>`.
*
* @remarks If your app uses Route Resolvers when querying for your Prismic repository's content, a Link Resolver does not need to be provided.
*
* @see Learn about Link Resolvers and Route Resolvers {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}
*/
linkResolver?: prismicH.LinkResolverFunction;
richTextComponents?: Record<string, string | React.ComponentType>;

/**
* A map or function that maps a Rich Text block to a React component.
*
* @remarks Prefer using a map serializer over the function serializer when possible. The map serializer is simpler to maintain.
*
* @example
* A map serializer.
*
* ```ts
* {
* heading1: ({children}) => <Heading>{children}</Heading>
* }
* ```
*
* @example
* A function serializer.
*
* ```ts
* (type, node, content, children) => {
* switch (type) {
* case 'heading1': {
* return <Heading>{chidlren}</Heading>
* }
* }
* }
* ```
*/
richTextComponents?: JSXMapSerializer | JSXFunctionSerializer;

/** The component rendered by `<PrismicLink>` for internal URLs. Defaults to `<a>`. */
internalLinkComponent?: string | React.ComponentType<LinkProps>;

/** The component rendered by `<PrismicLink>` for external URLs. Defaults to `<a>`. */
externalLinkComponent?: string | React.ComponentType<LinkProps>;

/** Children for the component. */
children?: React.ReactNode;
};

/**
* React context containing shared configuration for `@prismicio/react` components and hooks.
*/
export const PrismicContext = React.createContext<PrismicContextValue>({});

/**
* React hook used to read shared configuration for `@prismicio/react` components and hooks.
*
* @returns The closest `<PrismicProvider>` context value.
*/
export const usePrismicContext = (): PrismicContextValue => {
return React.useContext(PrismicContext) || {};
};

/**
* Props for `<PrismicProvider>`.
*/
type PrismicProviderProps = PrismicContextValue;

/**
* React context provider to share configuration for `@prismicio/react` components and hooks.
*
* @returns A React context provider with shared configuration.
*/
export const PrismicProvider = ({
client,
linkResolver,
Expand Down
12 changes: 6 additions & 6 deletions src/PrismicRichText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import * as React from "react";
import * as prismicH from "@prismicio/helpers";
import * as prismicT from "@prismicio/types";
import { usePrismicContext } from "./PrismicProvider";
import { ComponentFunctionSerializer } from "./types";
import { JSXFunctionSerializer } from "./types";
import { PrismicLink, PrismicLinkProps } from "./PrismicLink";

/**
Expand Down Expand Up @@ -94,11 +94,11 @@ function defaultComponentSerializer(
linkResolver: prismicH.LinkResolverFunction<string> | undefined,
internalLinkComponent: PrismicRichTextProps["internalLinkComponent"],
externalLinkComponent: PrismicRichTextProps["externalLinkComponent"],
_type: Parameters<ComponentFunctionSerializer>[0],
node: Parameters<ComponentFunctionSerializer>[1],
content: Parameters<ComponentFunctionSerializer>[2],
children: Parameters<ComponentFunctionSerializer>[3],
_key: Parameters<ComponentFunctionSerializer>[4],
_type: Parameters<JSXFunctionSerializer>[0],
node: Parameters<JSXFunctionSerializer>[1],
content: Parameters<JSXFunctionSerializer>[2],
children: Parameters<JSXFunctionSerializer>[3],
_key: Parameters<JSXFunctionSerializer>[4],
): JSX.Element {
switch (node.type) {
case Element.heading1:
Expand Down
33 changes: 27 additions & 6 deletions src/PrismicText.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,37 @@
import * as React from "react";
import { useMemo } from "react";
import { RichTextField } from "@prismicio/types";
import { asText } from "@prismicio/helpers";
import * as prismicT from "@prismicio/types";
import * as prismicH from "@prismicio/helpers";

/**
* Props for `<PrismicText>`.
*/
export type PrismicTextProps = {
field: RichTextField;
/** The Prismic Rich Text field to render. */
field: prismicT.RichTextField;

/** The separator used between blocks. Defaults to \n`. */
separator?: string;
};

/**
* React component that renders content from a Prismic Rich Text field as plain text.
*
* @remarks This component returns a React fragment with no wrapping element around the content. If you need a wrapper, add a component around `<PrismicText>`.
*
* @see Learn about Rich Text fields {@link https://prismic.io/docs/core-concepts/rich-text-title}
*
* @example
* Rendering a Rich Text field as plain text.
*
* <PrismicText field={document.data.content} />
*
* @param props Props for the component.
*
* @returns The Rich Text field's content as plain text.
*/
export const PrismicText = (props: PrismicTextProps): JSX.Element => {
const text = useMemo(
() => asText(props.field, props.separator),
const text = React.useMemo(
() => prismicH.asText(props.field, props.separator),
[props.field, props.separator],
);

Expand Down
33 changes: 24 additions & 9 deletions src/PrismicToolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,35 @@
import * as React from "react";

/**
* Props for `<PrismicToolbar>`.
*/
export type PrismicToolbarProps = {
/** The name of the Prismic repository. For example, `"my-repo"` if the repository URL is `my-repo.prismic.io`. */
repositoryName: string;

/**
* The type of toolbar needed for the repository. Defaults to `"new"`.
*
* @see To check which version you need, view the Prismic Toolbar documentation {@link https://prismic.io/docs/technologies/previews-and-the-prismic-toolbar-reactjs}
*/
type?: "new" | "legacy";
};

/**
* React component that injects the Prismic Toolbar to the app. This component can be placed anywhere in the React tree.
*/
export const PrismicToolbar = ({
repositoryName,
type = "new",
}: PrismicToolbarProps): JSX.Element => {
return (
<script
src={`https://static.cdn.prismic.io/prismic.js?repositoryName=${repositoryName}${
type == "new" ? "&type=new" : ""
}`}
defer={true}
/>
);
}: PrismicToolbarProps): null => {
React.useEffect(() => {
const script = document.createElement("script");
script.src = `https://static.cdn.prismic.io/prismic.js?repositoryName=${repositoryName}${
type == "new" ? "&type=new" : ""
}`;
script.defer = true;
document.body.appendChild(script);
}, [repositoryName, type]);

return null;
};
6 changes: 6 additions & 0 deletions src/SliceZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,14 @@ export const TODOSliceComponent = __PRODUCTION__
/**
* Renders content from a Prismic Slice Zone using React components for each type of Slice.
*
* If a component is not provided for a type of Slice, a default component can be provided. A fallback component is provided by default that will not be rendered in a production build of your app.
*
* @see Learn about Prismic Slices and Slice Zones {@link https://prismic.io/docs/core-concepts/slices}
*
* @typeParam TSlice - The type(s) of a Slice in the Slice Zone.
* @typeParam TContext - Arbitrary data made available to all Slice components.
*
* @returns The Slice Zone's content as React components.
*/
export const SliceZone = <TSlice extends SliceLike, TContext>({
slices = [],
Expand Down
9 changes: 9 additions & 0 deletions src/createClientHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,15 @@ const getParamHookDependencies = (
];
};

/**
* Creates a React hook that forwards arguments to a specific method of a `@prismicio/client` instance. The created hook has its own internal state manager to report async status, such as pending or error statuses.
*
* @param method The `@prismicio/client` method to which hook arguments will be forwarded.
*
* @returns A new React hook configured for the provided method.
*
* @internal
*/
export const createClientHook = <
// eslint-disable-next-line @typescript-eslint/no-explicit-any
TMethod extends (...args: any[]) => Promise<any>,
Expand Down
8 changes: 8 additions & 0 deletions src/lib/isInternalURL.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
/**
* Determines if a URL is internal or external.
*
* @param url The URL to check if internal or external.
*
* @returns `true` if `url` is internal, `false` otherwise.
*/
// TODO: This does not detect all relative URLs as internal, such as `about` or `./about`. This function assumes relative URLs start with a "/" or "#"`.
export const isInternalURL = (url: string): boolean => {
const isInternal = /^(\/(?!\/)|#)/.test(url);
const isSpecialLink = !isInternal && !/^https?:\/\//.test(url);
Expand Down
21 changes: 7 additions & 14 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,16 @@
import {
RichTextFunctionSerializer,
RichTextMapSerializer,
} from "@prismicio/richtext";
import React from "react";

export type JSXFunctionSerializer = RichTextFunctionSerializer<JSX.Element>;
export type JSXMapSerializer = RichTextMapSerializer<JSX.Element>;
import * as prismicR from "@prismicio/richtext";

/**
* Serializes a node from a rich text or title field with a function to HTML
* A function mapping Rich Text block types to React Components. It is used to render Rich Text or Title fields.
*
* @see Templating rich text and title fields from Prismic {@link https://prismic.io/docs/technologies/templating-rich-text-and-title-fields-javascript}
*/
export type ComponentFunctionSerializer =
RichTextFunctionSerializer<React.ReactNode>;
export type JSXFunctionSerializer =
prismicR.RichTextFunctionSerializer<JSX.Element>;

/**
* Serializes a node from a rich text or title field with a map to HTML
* A map of Rich Text block types to React Components. It is used to render Rich Text or Title fields.
*
* @see Templating rich text and title fields from Prismic {@link https://prismic.io/docs/technologies/templating-rich-text-and-title-fields-javascript}
* @see Templating Rich Text and Title fields from Prismic {@link https://prismic.io/docs/technologies/templating-rich-text-and-title-fields-javascript}
*/
export type ComponentMapSerializer = RichTextMapSerializer<React.ReactNode>;
export type JSXMapSerializer = prismicR.RichTextMapSerializer<JSX.Element>;
7 changes: 7 additions & 0 deletions src/usePrismicClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ import { invariant } from "./lib/invariant";

import { usePrismicContext } from "./PrismicProvider";

/**
* Retrieve the `@prismicio/client` instance provided to `<PrismicProvider>` higher in the React tree.
*
* @param explicitClient An optional `@prismicio/client` instance to override the Client provided to `<PrismicProvider>`.
*
* @return The `@prismicio/client` instance provided to `<PrismicProvider>`.
*/
export const usePrismicClient = (
explicitClient?: prismic.Client,
): prismic.Client => {
Expand Down

0 comments on commit ba15a01

Please sign in to comment.