Skip to content

Commit

Permalink
feat: remove the ability to configure components via `@prismicio/reac…
Browse files Browse the repository at this point in the history
…t/config`
  • Loading branch information
angeloashmore committed Apr 5, 2023
1 parent 2b420c0 commit 180802a
Show file tree
Hide file tree
Showing 13 changed files with 1,261 additions and 199 deletions.
17 changes: 4 additions & 13 deletions src/rsc/PrismicLink.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import * as React from "react";
import * as prismicH from "@prismicio/helpers";
import * as prismicT from "@prismicio/types";
import { config } from "@prismicio/react/config";

import { devMsg } from "../lib/devMsg";
import { isInternalURL } from "../lib/isInternalURL";
Expand All @@ -11,8 +10,6 @@ const voidToUndefined = <T,>(value: T): Exclude<T, void> => {
return (value === undefined ? undefined : value) as Exclude<T, void>;
};

export type LinkComponent = React.ElementType<LinkProps>;

/**
* Props provided to a component when rendered with `<PrismicLink>`.
*/
Expand Down Expand Up @@ -174,15 +171,13 @@ const _PrismicLink = <
}
}

const linkResolver = props.linkResolver || config.linkResolver;

let href: string | null | undefined;
if ("href" in props) {
href = props.href;
} else if ("document" in props && props.document) {
href = voidToUndefined(prismicH.asLink(props.document, linkResolver));
href = voidToUndefined(prismicH.asLink(props.document, props.linkResolver));
} else if ("field" in props && props.field) {
href = voidToUndefined(prismicH.asLink(props.field, linkResolver));
href = voidToUndefined(prismicH.asLink(props.field, props.linkResolver));
}

const isInternal = href && isInternalURL(href);
Expand All @@ -199,14 +194,10 @@ const _PrismicLink = <
props.rel || (target === "_blank" ? "noopener noreferrer" : undefined);

const InternalComponent: React.ElementType<LinkProps> =
props.internalComponent ||
config.internalLinkComponent ||
defaultInternalComponent;
props.internalComponent || defaultInternalComponent;

const ExternalComponent: React.ElementType<LinkProps> =
props.externalComponent ||
config.externalLinkComponent ||
defaultExternalComponent;
props.externalComponent || defaultExternalComponent;

const Component = (
isInternal ? InternalComponent : ExternalComponent
Expand Down
56 changes: 42 additions & 14 deletions src/rsc/PrismicRichText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,21 @@ import * as React from "react";
import * as prismicT from "@prismicio/types";
import * as prismicH from "@prismicio/helpers";
import * as prismicR from "@prismicio/richtext";
import { config } from "@prismicio/react/config";

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

import { PrismicLink, PrismicLinkProps } from "./PrismicLink";
import { LinkProps, PrismicLink, PrismicLinkProps } from "./PrismicLink";

/**
* Props for `<PrismicRichText>`.
*/
export type PrismicRichTextProps<
InternalLinkComponent extends React.ElementType<LinkProps> = NonNullable<
PrismicLinkProps["internalComponent"]
>,
ExternalLinkComponent extends React.ElementType<LinkProps> = NonNullable<
PrismicLinkProps["externalComponent"]
>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
> = {
Expand Down Expand Up @@ -75,14 +80,14 @@ export type PrismicRichTextProps<
*
* @defaultValue `<a>`
*/
internalLinkComponent?: PrismicLinkProps["internalComponent"];
internalLinkComponent?: InternalLinkComponent;

/**
* The React component rendered for links when the URL is external.
*
* @defaultValue `<a>`
*/
externalLinkComponent?: PrismicLinkProps["externalComponent"];
externalLinkComponent?: ExternalLinkComponent;

/**
* The value to be rendered when the field is empty. If a fallback is not
Expand All @@ -92,19 +97,31 @@ export type PrismicRichTextProps<
};

type CreateDefaultSerializerArgs<
InternalLinkComponent extends React.ElementType<LinkProps> = NonNullable<
PrismicLinkProps["internalComponent"]
>,
ExternalLinkComponent extends React.ElementType<LinkProps> = NonNullable<
PrismicLinkProps["externalComponent"]
>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
> = {
linkResolver: LinkResolverFunction | undefined;
internalLinkComponent: PrismicRichTextProps["internalLinkComponent"];
externalLinkComponent: PrismicRichTextProps["externalLinkComponent"];
internalLinkComponent?: InternalLinkComponent;
externalLinkComponent?: ExternalLinkComponent;
};

const createDefaultSerializer = <
InternalLinkComponent extends React.ElementType<LinkProps>,
ExternalLinkComponent extends React.ElementType<LinkProps>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
>(
args: CreateDefaultSerializerArgs<LinkResolverFunction>,
args: CreateDefaultSerializerArgs<
InternalLinkComponent,
ExternalLinkComponent,
LinkResolverFunction
>,
): JSXFunctionSerializer =>
prismicR.wrapMapSerializer({
heading1: ({ children, key }) => <h1 key={key}>{children}</h1>,
Expand Down Expand Up @@ -133,6 +150,11 @@ const createDefaultSerializer = <
return (
<p key={key} className="block-img">
{node.linkTo ? (
// @ts-expect-error - This component is missing required
// props from `internalLinkComponent` and
// `externalLinkComponent`. We currently do not have a
// way to pass extra props to nested links, so we are
// ignoring the error for now.
<PrismicLink
linkResolver={args.linkResolver}
internalComponent={args.internalLinkComponent}
Expand All @@ -157,6 +179,11 @@ const createDefaultSerializer = <
/>
),
hyperlink: ({ node, children, key }) => (
// @ts-expect-error - This component is missing required
// props from `internalLinkComponent` and
// `externalLinkComponent`. We currently do not have a
// way to pass extra props to nested links, so we are
// ignoring the error for now.
<PrismicLink
key={key}
field={node.data}
Expand Down Expand Up @@ -231,24 +258,25 @@ const createDefaultSerializer = <
* @see Learn about Rich Text serializers {@link https://prismic.io/docs/core-concepts/html-serializer}
*/
export const PrismicRichText = <
InternalLinkComponent extends React.ElementType<LinkProps>,
ExternalLinkComponent extends React.ElementType<LinkProps>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
>(
props: PrismicRichTextProps<LinkResolverFunction>,
props: PrismicRichTextProps<
InternalLinkComponent,
ExternalLinkComponent,
LinkResolverFunction
>,
): JSX.Element | null => {
return React.useMemo(() => {
if (prismicH.isFilled.richText(props.field)) {
const linkResolver = props.linkResolver || config.linkResolver;

const serializer = prismicR.composeSerializers(
typeof props.components === "object"
? prismicR.wrapMapSerializer(props.components)
: props.components,
typeof config.richTextComponents === "object"
? prismicR.wrapMapSerializer(config.richTextComponents)
: config.richTextComponents,
createDefaultSerializer({
linkResolver,
linkResolver: props.linkResolver,
internalLinkComponent: props.internalLinkComponent,
externalLinkComponent: props.externalLinkComponent,
}),
Expand Down
42 changes: 0 additions & 42 deletions src/rsc/SliceZone.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,6 @@ import * as prismicT from "@prismicio/types";

import { __PRODUCTION__ } from "../lib/__PRODUCTION__";

/**
* Returns the type of a `SliceLike` type.
*
* @typeParam Slice - The Slice from which the type will be extracted.
*/
type ExtractSliceType<Slice extends SliceLike> = Slice extends SliceLikeRestV2
? Slice["slice_type"]
: Slice extends SliceLikeGraphQL
? Slice["type"]
: never;

/**
* The minimum required properties to represent a Prismic Slice from the Prismic
* Rest API V2 for the `<SliceZone>` component.
Expand Down Expand Up @@ -114,37 +103,6 @@ export type SliceComponentType<
TContext = unknown,
> = React.ComponentType<SliceComponentProps<TSlice, TContext>>;

/**
* A record of Slice types mapped to a React component. The component will be
* rendered for each instance of its Slice.
*
* @deprecated This type is no longer used by `@prismicio/react`. Prefer using
* `Record<string, SliceComponentType<any>>` instead.
* @typeParam TSlice - The type(s) of a Slice in the Slice Zone.
* @typeParam TContext - Arbitrary data made available to all Slice components.
*/
export type SliceZoneComponents<
TSlice extends SliceLike = SliceLike,
TContext = unknown,
> =
// This is purposely not wrapped in Partial to ensure a component is provided
// for all Slice types. <SliceZone> will render a default component if one is
// not provided, but it *should* be a type error if an explicit component is
// missing.
//
// If a developer purposely does not want to provide a component, they can
// assign it to the TODOSliceComponent exported from this package. This
// signals to future developers that it is a placeholder and should be
// implemented.
{
[SliceType in ExtractSliceType<TSlice>]: SliceComponentType<
Extract<TSlice, SliceLike<SliceType>> extends never
? SliceLike
: Extract<TSlice, SliceLike<SliceType>>,
TContext
>;
};

/**
* This Slice component can be used as a reminder to provide a proper
* implementation.
Expand Down
3 changes: 0 additions & 3 deletions src/rsc/__defaultConfig__.ts

This file was deleted.

56 changes: 0 additions & 56 deletions src/rsc/definePrismicConfig.ts

This file was deleted.

8 changes: 6 additions & 2 deletions src/rsc/getPrismicToolbarSrc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@
*
* @param repositoryName - The name of the Prismic repository. For example,
* `"my-repo"` if the repository URL is `my-repo.prismic.io`.
*
* @returns The URL for the given Prismic repository's Prismic Toolbar script.
*/
export const getPrismicToolbarSrc = (repositoryName: string): string => {
return `https://static.cdn.prismic.io/prismic.js?new=true&repo=${repositoryName}`;
export const getPrismicToolbarSrc = <TRepositoryName extends string>(
repositoryName: TRepositoryName,
): `https://static.cdn.prismic.io/prismic.js?new=true&repo=${TRepositoryName}` => {
return `https://static.cdn.prismic.io/prismic.js?new=true&repo=${repositoryName}` as const;
};
19 changes: 8 additions & 11 deletions src/rsc/index.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
export { SliceZone, TODOSliceComponent } from "./SliceZone";
export type {
SliceComponentProps,
SliceComponentType,
SliceLike,
SliceLikeGraphQL,
SliceLikeRestV2,
SliceZoneLike,
SliceZoneProps,
SliceLikeRestV2,
SliceLikeGraphQL,
SliceComponentType,
SliceComponentProps,
} from "./SliceZone";

export { PrismicLink } from "./PrismicLink";
export type { LinkComponent, LinkProps, PrismicLinkProps } from "./PrismicLink";
export type { LinkProps, PrismicLinkProps } from "./PrismicLink";

export { PrismicRichText } from "./PrismicRichText";
export type { PrismicRichTextProps } from "./PrismicRichText";

export { getPrismicToolbarSrc } from "./getPrismicToolbarSrc";

export { definePrismicConfig } from "./definePrismicConfig";

export { PrismicConfig } from "./types";

// These exports do not have RSC-specific implementations.
// They are aliases for the root-level exports.
export { PrismicText, PrismicTextProps } from "../PrismicText";
export { PrismicImage, PrismicImageProps } from "../PrismicImage";
export { Element } from "..";
export { PrismicImage } from "../PrismicImage";
export type { PrismicImageProps } from "../PrismicImage";
export type { JSXMapSerializer, JSXFunctionSerializer } from "../types";
Loading

0 comments on commit 180802a

Please sign in to comment.