@prismicio/react 2.1.2-alpha.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,185 @@
1
+ import * as React from "react";
2
+ import * as prismicT from "@prismicio/types";
3
+ import * as prismicH from "@prismicio/helpers";
4
+
5
+ import { __PRODUCTION__ } from "./lib/__PRODUCTION__";
6
+ import { devMsg } from "./lib/devMsg";
7
+
8
+ /**
9
+ * Props for `<PrismicImage>`.
10
+ */
11
+ export type PrismicImageProps = Omit<
12
+ React.DetailedHTMLProps<
13
+ React.ImgHTMLAttributes<HTMLImageElement>,
14
+ HTMLImageElement
15
+ >,
16
+ "src" | "srcset" | "alt"
17
+ > & {
18
+ /**
19
+ * The Prismic Image field or thumbnail to render.
20
+ */
21
+ field: prismicT.ImageFieldImage | null | undefined;
22
+
23
+ /**
24
+ * An object of Imgix URL API parameters to transform the image.
25
+ *
26
+ * See: https://docs.imgix.com/apis/rendering
27
+ */
28
+ imgixParams?: Parameters<typeof prismicH.asImageSrc>[1];
29
+
30
+ /**
31
+ * Declare an image as decorative by providing `alt=""`.
32
+ *
33
+ * See:
34
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/alt#decorative_images
35
+ */
36
+ alt?: "";
37
+
38
+ /**
39
+ * Declare an image as decorative only if the Image field does not have
40
+ * alternative text by providing `fallbackAlt=""`.
41
+ *
42
+ * See:
43
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/alt#decorative_images
44
+ */
45
+ fallbackAlt?: "";
46
+ } & (
47
+ | {
48
+ /**
49
+ * Widths used to build a `srcset` value for the Image field.
50
+ *
51
+ * If a `widths` prop is not given or `"defaults"` is passed, the
52
+ * following widths will be used: 640, 750, 828, 1080, 1200, 1920, 2048, 3840.
53
+ *
54
+ * If the Image field contains responsive views, each responsive view
55
+ * can be used as a width in the resulting `srcset` by passing
56
+ * `"thumbnails"` as the `widths` prop.
57
+ */
58
+ widths?:
59
+ | NonNullable<
60
+ Parameters<typeof prismicH.asImageWidthSrcSet>[1]
61
+ >["widths"]
62
+ | "defaults";
63
+ /**
64
+ * Not used when the `widths` prop is used.
65
+ */
66
+ pixelDensities?: never;
67
+ }
68
+ | {
69
+ /**
70
+ * Not used when the `widths` prop is used.
71
+ */
72
+ widths?: never;
73
+ /**
74
+ * Pixel densities used to build a `srcset` value for the Image field.
75
+ *
76
+ * If a `pixelDensities` prop is passed `"defaults"`, the following
77
+ * pixel densities will be used: 1, 2, 3.
78
+ */
79
+ pixelDensities:
80
+ | NonNullable<
81
+ Parameters<typeof prismicH.asImagePixelDensitySrcSet>[1]
82
+ >["pixelDensities"]
83
+ | "defaults";
84
+ }
85
+ );
86
+
87
+ const _PrismicImage = (
88
+ props: PrismicImageProps,
89
+ ref: React.ForwardedRef<HTMLImageElement>,
90
+ ): JSX.Element | null => {
91
+ const {
92
+ field,
93
+ alt,
94
+ fallbackAlt,
95
+ imgixParams,
96
+ widths,
97
+ pixelDensities,
98
+ ...restProps
99
+ } = props;
100
+
101
+ if (!__PRODUCTION__) {
102
+ if (typeof alt === "string" && props.alt !== "") {
103
+ console.warn(
104
+ `[PrismicImage] The alt prop can only be used to declare an image as decorative by passing an empty string (alt=""). For more details, see ${devMsg(
105
+ "alt-must-be-an-empty-string",
106
+ )}`,
107
+ );
108
+ }
109
+
110
+ if (typeof fallbackAlt === "string" && fallbackAlt !== "") {
111
+ console.warn(
112
+ `[PrismicImage] The fallbackAlt prop can only be used to declare an image as decorative by passing an empty string (fallbackAlt=""). For more details, see ${devMsg(
113
+ "alt-must-be-an-empty-string",
114
+ )}`,
115
+ );
116
+ }
117
+
118
+ if (widths && pixelDensities) {
119
+ console.warn(
120
+ `[PrismicImage] Only one of "widths" or "pixelDensities" props can be provided. "widths" will be used in this case.`,
121
+ );
122
+ }
123
+ }
124
+
125
+ if (prismicH.isFilled.imageThumbnail(field)) {
126
+ let src: string | undefined;
127
+ let srcSet: string | undefined;
128
+
129
+ if (widths || !pixelDensities) {
130
+ const res = prismicH.asImageWidthSrcSet(field, {
131
+ ...imgixParams,
132
+ widths: widths === "defaults" ? undefined : widths,
133
+ });
134
+
135
+ src = res.src;
136
+ srcSet = res.srcset;
137
+ } else if (pixelDensities) {
138
+ const res = prismicH.asImagePixelDensitySrcSet(field, {
139
+ ...imgixParams,
140
+ pixelDensities:
141
+ pixelDensities === "defaults" ? undefined : pixelDensities,
142
+ });
143
+
144
+ src = res.src;
145
+ srcSet = res.srcset;
146
+ }
147
+
148
+ return (
149
+ <img
150
+ ref={ref}
151
+ src={src}
152
+ srcSet={srcSet}
153
+ alt={alt ?? (field.alt || fallbackAlt)}
154
+ {...restProps}
155
+ />
156
+ );
157
+ } else {
158
+ return null;
159
+ }
160
+ };
161
+
162
+ if (!__PRODUCTION__) {
163
+ _PrismicImage.displayName = "PrismicImage";
164
+ }
165
+
166
+ /**
167
+ * React component that renders an image from a Prismic Image field or one of
168
+ * its thumbnails. It will automatically set the `alt` attribute using the Image
169
+ * field's `alt` property.
170
+ *
171
+ * By default, a widths-based srcset will be used to support responsive images.
172
+ * This ensures only the smallest image needed for a browser is downloaded.
173
+ *
174
+ * To use a pixel-density-based srcset, use the `pixelDensities` prop. Default
175
+ * pixel densities can be used by using `pixelDensities="defaults"`.
176
+ *
177
+ * **Note**: If you are using a framework that has a native image component,
178
+ * such as Next.js and Gatsby, prefer using those image components instead. They
179
+ * can provide deeper framework integration than `<PrismicImage>`.
180
+ *
181
+ * @param props - Props for the component.
182
+ *
183
+ * @returns A responsive image component for the given Image field.
184
+ */
185
+ export const PrismicImage = React.forwardRef(_PrismicImage);
@@ -2,6 +2,7 @@ import * as React from "react";
2
2
  import * as prismicH from "@prismicio/helpers";
3
3
  import * as prismicT from "@prismicio/types";
4
4
 
5
+ import { __PRODUCTION__ } from "./lib/__PRODUCTION__";
5
6
  import { isInternalURL } from "./lib/isInternalURL";
6
7
 
7
8
  import { usePrismicContext } from "./usePrismicContext";
@@ -37,9 +38,10 @@ export interface LinkProps {
37
38
  * Props for `<PrismicLink>`.
38
39
  */
39
40
  export type PrismicLinkProps<
40
- InternalComponent extends React.ElementType<LinkProps> = React.ElementType<LinkProps>,
41
- ExternalComponent extends React.ElementType<LinkProps> = React.ElementType<LinkProps>,
42
- LinkResolverFunction extends prismicH.LinkResolverFunction = prismicH.LinkResolverFunction,
41
+ InternalComponent extends React.ElementType<LinkProps> = typeof defaultInternalComponent,
42
+ ExternalComponent extends React.ElementType<LinkProps> = typeof defaultInternalComponent,
43
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
44
+ LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
43
45
  > = Omit<
44
46
  React.ComponentPropsWithoutRef<InternalComponent> &
45
47
  React.ComponentPropsWithoutRef<ExternalComponent>,
@@ -117,25 +119,11 @@ const defaultInternalComponent = "a";
117
119
  */
118
120
  const defaultExternalComponent = "a";
119
121
 
120
- /**
121
- * React component that renders a link from a Prismic Link field.
122
- *
123
- * Different components can be rendered depending on whether the link is
124
- * internal or external. This is helpful when integrating with client-side
125
- * routers, such as a router-specific Link component.
126
- *
127
- * If a link is configured to open in a new window using `target="_blank"`,
128
- * `rel="noopener noreferrer"` is set by default.
129
- *
130
- * @param props - Props for the component.
131
- *
132
- * @returns The internal or external link component depending on whether the
133
- * link is internal or external.
134
- */
135
122
  const _PrismicLink = <
136
123
  InternalComponent extends React.ElementType<LinkProps> = typeof defaultInternalComponent,
137
124
  ExternalComponent extends React.ElementType<LinkProps> = typeof defaultExternalComponent,
138
- LinkResolverFunction extends prismicH.LinkResolverFunction = prismicH.LinkResolverFunction,
125
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
126
+ LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
139
127
  >(
140
128
  props: PrismicLinkProps<
141
129
  InternalComponent,
@@ -213,10 +201,30 @@ const _PrismicLink = <
213
201
  ) : null;
214
202
  };
215
203
 
204
+ if (!__PRODUCTION__) {
205
+ _PrismicLink.displayName = "PrismicLink";
206
+ }
207
+
208
+ /**
209
+ * React component that renders a link from a Prismic Link field.
210
+ *
211
+ * Different components can be rendered depending on whether the link is
212
+ * internal or external. This is helpful when integrating with client-side
213
+ * routers, such as a router-specific Link component.
214
+ *
215
+ * If a link is configured to open in a new window using `target="_blank"`,
216
+ * `rel="noopener noreferrer"` is set by default.
217
+ *
218
+ * @param props - Props for the component.
219
+ *
220
+ * @returns The internal or external link component depending on whether the
221
+ * link is internal or external.
222
+ */
216
223
  export const PrismicLink = React.forwardRef(_PrismicLink) as <
217
- InternalComponent extends React.ElementType<LinkProps>,
218
- ExternalComponent extends React.ElementType<LinkProps>,
219
- LinkResolverFunction extends prismicH.LinkResolverFunction,
224
+ InternalComponent extends React.ElementType<LinkProps> = typeof defaultInternalComponent,
225
+ ExternalComponent extends React.ElementType<LinkProps> = typeof defaultExternalComponent,
226
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
227
+ LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
220
228
  >(
221
229
  props: PrismicLinkProps<
222
230
  InternalComponent,
@@ -10,7 +10,10 @@ import { JSXFunctionSerializer, JSXMapSerializer } from "./types";
10
10
  * React context value containing shared configuration for `@prismicio/react`
11
11
  * components and hooks.
12
12
  */
13
- export type PrismicContextValue = {
13
+ export type PrismicContextValue<
14
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
15
+ LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
16
+ > = {
14
17
  /**
15
18
  * A `@prismicio/client` instance used to fetch content from a Prismic
16
19
  * repository. This is used by `@prismicio/react` hooks, such as
@@ -26,7 +29,7 @@ export type PrismicContextValue = {
26
29
  * repository's content, a Link Resolver does not need to be provided.
27
30
  * @see Learn about Link Resolvers and Route Resolvers {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}
28
31
  */
29
- linkResolver?: prismicH.LinkResolverFunction;
32
+ linkResolver?: LinkResolverFunction;
30
33
 
31
34
  /**
32
35
  * A map or function that maps a Rich Text block to a React component.
@@ -81,7 +84,9 @@ export const PrismicContext = React.createContext<PrismicContextValue>({});
81
84
  /**
82
85
  * Props for `<PrismicProvider>`.
83
86
  */
84
- export type PrismicProviderProps = PrismicContextValue;
87
+ export type PrismicProviderProps<
88
+ LinkResolverFunction extends prismicH.LinkResolverFunction,
89
+ > = PrismicContextValue<LinkResolverFunction>;
85
90
 
86
91
  /**
87
92
  * React context provider to share configuration for `@prismicio/react`
@@ -89,15 +94,18 @@ export type PrismicProviderProps = PrismicContextValue;
89
94
  *
90
95
  * @returns A React context provider with shared configuration.
91
96
  */
92
- export const PrismicProvider = ({
97
+ export const PrismicProvider = <
98
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
99
+ LinkResolverFunction extends prismicH.LinkResolverFunction<any>,
100
+ >({
93
101
  client,
94
102
  linkResolver,
95
103
  richTextComponents,
96
104
  internalLinkComponent,
97
105
  externalLinkComponent,
98
106
  children,
99
- }: PrismicProviderProps): JSX.Element => {
100
- const value = React.useMemo<PrismicContextValue>(
107
+ }: PrismicProviderProps<LinkResolverFunction>): JSX.Element => {
108
+ const value = React.useMemo<PrismicContextValue<LinkResolverFunction>>(
101
109
  () => ({
102
110
  client,
103
111
  linkResolver,
@@ -13,7 +13,10 @@ import { usePrismicContext } from "./usePrismicContext";
13
13
  /**
14
14
  * Props for `<PrismicRichText>`.
15
15
  */
16
- export type PrismicRichTextProps = {
16
+ export type PrismicRichTextProps<
17
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
18
+ LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
19
+ > = {
17
20
  /**
18
21
  * The Prismic Rich Text field to render.
19
22
  */
@@ -27,7 +30,7 @@ export type PrismicRichTextProps = {
27
30
  * repository's content, a Link Resolver does not need to be provided.
28
31
  * @see Learn about Link Resolvers and Route Resolvers {@link https://prismic.io/docs/core-concepts/link-resolver-route-resolver}
29
32
  */
30
- linkResolver?: PrismicLinkProps["linkResolver"];
33
+ linkResolver?: LinkResolverFunction;
31
34
 
32
35
  /**
33
36
  * A function that maps a Rich Text block to a React component.
@@ -58,7 +61,7 @@ export type PrismicRichTextProps = {
58
61
  * (type, node, content, children) => {
59
62
  * switch (type) {
60
63
  * case "heading1": {
61
- * return <Heading>{chidlren}</Heading>;
64
+ * return <Heading>{children}</Heading>;
62
65
  * }
63
66
  * }
64
67
  * };
@@ -79,10 +82,19 @@ export type PrismicRichTextProps = {
79
82
  * @defaultValue `<a>`
80
83
  */
81
84
  externalLinkComponent?: PrismicLinkProps["externalComponent"];
85
+
86
+ /**
87
+ * The value to be rendered when the field is empty. If a fallback is not
88
+ * given, `null` will be rendered.
89
+ */
90
+ fallback?: React.ReactNode;
82
91
  };
83
92
 
84
- type CreateDefaultSerializerArgs = {
85
- linkResolver: prismicH.LinkResolverFunction<string> | undefined;
93
+ type CreateDefaultSerializerArgs<
94
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
95
+ LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
96
+ > = {
97
+ linkResolver: LinkResolverFunction | undefined;
86
98
  internalLinkComponent: PrismicRichTextProps["internalLinkComponent"];
87
99
  externalLinkComponent: PrismicRichTextProps["externalLinkComponent"];
88
100
  };
@@ -214,8 +226,11 @@ const createDefaultSerializer = (
214
226
  * @see Learn about Rich Text fields {@link https://prismic.io/docs/core-concepts/rich-text-title}
215
227
  * @see Learn about Rich Text serializers {@link https://prismic.io/docs/core-concepts/html-serializer}
216
228
  */
217
- export const PrismicRichText = (
218
- props: PrismicRichTextProps,
229
+ export const PrismicRichText = <
230
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
231
+ LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
232
+ >(
233
+ props: PrismicRichTextProps<LinkResolverFunction>,
219
234
  ): JSX.Element | null => {
220
235
  const context = usePrismicContext();
221
236
 
@@ -255,7 +270,7 @@ export const PrismicRichText = (
255
270
 
256
271
  return <>{serialized}</>;
257
272
  } else {
258
- return null;
273
+ return props.fallback != null ? <>{props.fallback}</> : null;
259
274
  }
260
275
  }, [
261
276
  props.field,
@@ -263,6 +278,7 @@ export const PrismicRichText = (
263
278
  props.externalLinkComponent,
264
279
  props.components,
265
280
  props.linkResolver,
281
+ props.fallback,
266
282
  context.linkResolver,
267
283
  context.richTextComponents,
268
284
  ]);
package/src/SliceZone.tsx CHANGED
@@ -4,24 +4,57 @@ import * as prismicT from "@prismicio/types";
4
4
  import { __PRODUCTION__ } from "./lib/__PRODUCTION__";
5
5
  import { pascalCase, PascalCase } from "./lib/pascalCase";
6
6
 
7
+ /**
8
+ * Returns the type of a `SliceLike` type.
9
+ *
10
+ * @typeParam Slice - The Slice from which the type will be extracted.
11
+ */
12
+ type ExtractSliceType<Slice extends SliceLike> = Slice extends SliceLikeRestV2
13
+ ? Slice["slice_type"]
14
+ : Slice extends SliceLikeGraphQL
15
+ ? Slice["type"]
16
+ : never;
17
+
18
+ /**
19
+ * The minimum required properties to represent a Prismic Slice from the Prismic
20
+ * Rest API V2 for the `<SliceZone>` component.
21
+ *
22
+ * If using Prismic's Rest API V2, use the `Slice` export from
23
+ * `@prismicio/types` for a full interface.
24
+ *
25
+ * @typeParam SliceType - Type name of the Slice.
26
+ */
27
+ export type SliceLikeRestV2<SliceType extends string = string> = {
28
+ slice_type: prismicT.Slice<SliceType>["slice_type"];
29
+ };
30
+
31
+ /**
32
+ * The minimum required properties to represent a Prismic Slice from the Prismic
33
+ * GraphQL API for the `<SliceZone>` component.
34
+ *
35
+ * @typeParam SliceType - Type name of the Slice.
36
+ */
37
+ export type SliceLikeGraphQL<SliceType extends string = string> = {
38
+ type: prismicT.Slice<SliceType>["slice_type"];
39
+ };
40
+
7
41
  /**
8
42
  * The minimum required properties to represent a Prismic Slice for the
9
43
  * `<SliceZone>` component.
10
44
  *
11
- * If using Prismic's REST API, use the `Slice` export from `@prismicio/types`
12
- * for a full interface.
45
+ * If using Prismic's Rest API V2, use the `Slice` export from
46
+ * `@prismicio/types` for a full interface.
13
47
  *
14
48
  * @typeParam SliceType - Type name of the Slice.
15
49
  */
16
- export type SliceLike<SliceType extends string = string> = Pick<
17
- prismicT.Slice<SliceType>,
18
- "slice_type"
19
- >;
50
+ export type SliceLike<SliceType extends string = string> =
51
+ | SliceLikeRestV2<SliceType>
52
+ | SliceLikeGraphQL<SliceType>;
20
53
 
21
54
  /**
22
55
  * A looser version of the `SliceZone` type from `@prismicio/types` using `SliceLike`.
23
56
  *
24
- * If using Prismic's REST API, use the `SliceZone` export from
57
+ * If using Prismic's Rest API V2, use the `SliceZone` export from
25
58
  * `@prismicio/types` for the full type.
26
59
  *
27
60
  * @typeParam TSlice - The type(s) of a Slice in the Slice Zone.
@@ -97,10 +130,7 @@ export type SliceZoneComponents<
97
130
  // signals to future developers that it is a placeholder and should be
98
131
  // implemented.
99
132
  {
100
- [SliceType in keyof Record<
101
- TSlice["slice_type"],
102
- never
103
- >]: SliceComponentType<
133
+ [SliceType in ExtractSliceType<TSlice>]: SliceComponentType<
104
134
  Extract<TSlice, SliceLike<SliceType>> extends never
105
135
  ? SliceLike
106
136
  : Extract<TSlice, SliceLike<SliceType>>,
@@ -119,19 +149,18 @@ export const TODOSliceComponent = __PRODUCTION__
119
149
  : <TSlice extends SliceLike, TContext>({
120
150
  slice,
121
151
  }: SliceComponentProps<TSlice, TContext>): JSX.Element | null => {
152
+ const type = "slice_type" in slice ? slice.slice_type : slice.type;
153
+
122
154
  React.useEffect(() => {
123
155
  console.warn(
124
- `[SliceZone] Could not find a component for Slice type "${slice.slice_type}"`,
156
+ `[SliceZone] Could not find a component for Slice type "${type}"`,
125
157
  slice,
126
158
  );
127
- }, [slice]);
159
+ }, [slice, type]);
128
160
 
129
161
  return (
130
- <section
131
- data-slice-zone-todo-component=""
132
- data-slice-type={slice.slice_type}
133
- >
134
- Could not find a component for Slice type &ldquo;{slice.slice_type}
162
+ <section data-slice-zone-todo-component="" data-slice-type={type}>
163
+ Could not find a component for Slice type &ldquo;{type}
135
164
  &rdquo;
136
165
  </section>
137
166
  );
@@ -149,7 +178,7 @@ type SliceZoneResolverArgs<TSlice extends SliceLike = SliceLike> = {
149
178
  /**
150
179
  * The name of the Slice.
151
180
  */
152
- sliceName: PascalCase<TSlice["slice_type"]>;
181
+ sliceName: PascalCase<ExtractSliceType<TSlice>>;
153
182
 
154
183
  /**
155
184
  * The index of the Slice in the Slice Zone.
@@ -243,14 +272,16 @@ export const SliceZone = <TSlice extends SliceLike, TContext>({
243
272
  }: SliceZoneProps<TSlice, TContext>): JSX.Element => {
244
273
  const renderedSlices = React.useMemo(() => {
245
274
  return slices.map((slice, index) => {
246
- let Comp = (components[slice.slice_type as keyof typeof components] ||
275
+ const type = "slice_type" in slice ? slice.slice_type : slice.type;
276
+
277
+ let Comp = (components[type as keyof typeof components] ||
247
278
  defaultComponent) as SliceComponentType<TSlice, TContext>;
248
279
 
249
280
  // TODO: Remove `resolver` in v3 in favor of `components`.
250
281
  if (resolver) {
251
282
  const resolvedComp = resolver({
252
283
  slice,
253
- sliceName: pascalCase(slice.slice_type),
284
+ sliceName: pascalCase(type),
254
285
  i: index,
255
286
  });
256
287
 
package/src/index.ts CHANGED
@@ -25,6 +25,9 @@ export { Element };
25
25
  // TODO: Remove in v3.
26
26
  export const Elements = Element;
27
27
 
28
+ export { PrismicImage } from "./PrismicImage";
29
+ export type { PrismicImageProps } from "./PrismicImage";
30
+
28
31
  export { SliceZone, TODOSliceComponent } from "./SliceZone";
29
32
  export type {
30
33
  SliceComponentProps,
@@ -0,0 +1,20 @@
1
+ import { version } from "../../package.json";
2
+
3
+ /**
4
+ * Returns a `prismic.dev/msg` URL for a given message slug.
5
+ *
6
+ * @example
7
+ *
8
+ * ```ts
9
+ * devMsg("missing-param");
10
+ * // => "https://prismic.dev/msg/react/v1.2.3/missing-param.md"
11
+ * ```
12
+ *
13
+ * @param slug - Slug for the message. This corresponds to a Markdown file in
14
+ * the Git repository's `/messages` directory.
15
+ *
16
+ * @returns The `prismic.dev/msg` URL for the given slug.
17
+ */
18
+ export const devMsg = (slug: string) => {
19
+ return `https://prismic.dev/msg/react/v${version}/${slug}`;
20
+ };
@@ -34,7 +34,7 @@ type InnerCamelCaseStringArray<
34
34
 
35
35
  type CamelCaseStringArray<Parts extends readonly string[]> = Parts extends [
36
36
  `${infer FirstPart}`,
37
- ...infer RemainingParts
37
+ ...infer RemainingParts,
38
38
  ]
39
39
  ? Uncapitalize<`${FirstPart}${InnerCamelCaseStringArray<
40
40
  RemainingParts,