@prismicio/react 2.2.0 → 2.4.1
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.
- package/dist/index.cjs +90 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +181 -3
- package/dist/index.js +90 -3
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/PrismicImage.tsx +185 -0
- package/src/PrismicLink.tsx +63 -25
- package/src/PrismicText.tsx +13 -0
- package/src/PrismicToolbar.tsx +13 -0
- package/src/index.ts +3 -0
- package/src/lib/devMsg.ts +20 -0
|
@@ -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="") but was provided a non-empty string. You can resolve this warning by removing the "alt" prop or changing it to 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="") but was provided a non-empty string. You can resolve this warning by removing the "fallbackAlt" prop or changing it to 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. You can resolve this warning by removing either the "widths" or "pixelDensities" prop. "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);
|
package/src/PrismicLink.tsx
CHANGED
|
@@ -2,6 +2,8 @@ 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__";
|
|
6
|
+
import { devMsg } from "./lib/devMsg";
|
|
5
7
|
import { isInternalURL } from "./lib/isInternalURL";
|
|
6
8
|
|
|
7
9
|
import { usePrismicContext } from "./usePrismicContext";
|
|
@@ -37,8 +39,8 @@ export interface LinkProps {
|
|
|
37
39
|
* Props for `<PrismicLink>`.
|
|
38
40
|
*/
|
|
39
41
|
export type PrismicLinkProps<
|
|
40
|
-
InternalComponent extends React.ElementType<LinkProps> =
|
|
41
|
-
ExternalComponent extends React.ElementType<LinkProps> =
|
|
42
|
+
InternalComponent extends React.ElementType<LinkProps> = typeof defaultInternalComponent,
|
|
43
|
+
ExternalComponent extends React.ElementType<LinkProps> = typeof defaultInternalComponent,
|
|
42
44
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
43
45
|
LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
|
|
44
46
|
> = Omit<
|
|
@@ -118,26 +120,11 @@ const defaultInternalComponent = "a";
|
|
|
118
120
|
*/
|
|
119
121
|
const defaultExternalComponent = "a";
|
|
120
122
|
|
|
121
|
-
/**
|
|
122
|
-
* React component that renders a link from a Prismic Link field.
|
|
123
|
-
*
|
|
124
|
-
* Different components can be rendered depending on whether the link is
|
|
125
|
-
* internal or external. This is helpful when integrating with client-side
|
|
126
|
-
* routers, such as a router-specific Link component.
|
|
127
|
-
*
|
|
128
|
-
* If a link is configured to open in a new window using `target="_blank"`,
|
|
129
|
-
* `rel="noopener noreferrer"` is set by default.
|
|
130
|
-
*
|
|
131
|
-
* @param props - Props for the component.
|
|
132
|
-
*
|
|
133
|
-
* @returns The internal or external link component depending on whether the
|
|
134
|
-
* link is internal or external.
|
|
135
|
-
*/
|
|
136
123
|
const _PrismicLink = <
|
|
137
|
-
InternalComponent extends React.ElementType<LinkProps
|
|
138
|
-
ExternalComponent extends React.ElementType<LinkProps
|
|
124
|
+
InternalComponent extends React.ElementType<LinkProps> = typeof defaultInternalComponent,
|
|
125
|
+
ExternalComponent extends React.ElementType<LinkProps> = typeof defaultExternalComponent,
|
|
139
126
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
140
|
-
LinkResolverFunction extends prismicH.LinkResolverFunction<any
|
|
127
|
+
LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
|
|
141
128
|
>(
|
|
142
129
|
props: PrismicLinkProps<
|
|
143
130
|
InternalComponent,
|
|
@@ -149,6 +136,37 @@ const _PrismicLink = <
|
|
|
149
136
|
): JSX.Element | null => {
|
|
150
137
|
const context = usePrismicContext();
|
|
151
138
|
|
|
139
|
+
if (!__PRODUCTION__) {
|
|
140
|
+
if ("field" in props && props.field) {
|
|
141
|
+
if (
|
|
142
|
+
!("link_type" in props.field) ||
|
|
143
|
+
!("url" in props.field || "id" in props.field)
|
|
144
|
+
) {
|
|
145
|
+
console.error(
|
|
146
|
+
`[PrismicLink] This "field" prop value caused an error to be thrown.\n`,
|
|
147
|
+
props.field,
|
|
148
|
+
);
|
|
149
|
+
throw new Error(
|
|
150
|
+
`[PrismicLink] The provided field is missing required properties to properly render a link. The link may not render. For more details, see ${devMsg(
|
|
151
|
+
"missing-link-properties",
|
|
152
|
+
)}`,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
} else if ("document" in props && props.document) {
|
|
156
|
+
if (!("url" in props.document || "id" in props.document)) {
|
|
157
|
+
console.error(
|
|
158
|
+
`[PrismicLink] This "document" prop value caused an error to be thrown.\n`,
|
|
159
|
+
props.document,
|
|
160
|
+
);
|
|
161
|
+
throw new Error(
|
|
162
|
+
`[PrismicLink] The provided document is missing required properties to properly render a link. The link may not render. For more details, see ${devMsg(
|
|
163
|
+
"missing-link-properties",
|
|
164
|
+
)}`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
152
170
|
const linkResolver = props.linkResolver || context.linkResolver;
|
|
153
171
|
|
|
154
172
|
let href: string | null | undefined;
|
|
@@ -160,12 +178,15 @@ const _PrismicLink = <
|
|
|
160
178
|
href = prismicH.asLink(props.field, linkResolver);
|
|
161
179
|
}
|
|
162
180
|
|
|
181
|
+
const isInternal = href && isInternalURL(href);
|
|
182
|
+
|
|
163
183
|
const target =
|
|
164
184
|
props.target ||
|
|
165
185
|
("field" in props &&
|
|
166
186
|
props.field &&
|
|
167
187
|
"target" in props.field &&
|
|
168
188
|
props.field.target) ||
|
|
189
|
+
(!isInternal && "_blank") ||
|
|
169
190
|
undefined;
|
|
170
191
|
|
|
171
192
|
const rel =
|
|
@@ -181,8 +202,6 @@ const _PrismicLink = <
|
|
|
181
202
|
context.externalLinkComponent ||
|
|
182
203
|
defaultExternalComponent;
|
|
183
204
|
|
|
184
|
-
const isInternal = href && isInternalURL(href);
|
|
185
|
-
|
|
186
205
|
const Component = isInternal ? InternalComponent : ExternalComponent;
|
|
187
206
|
|
|
188
207
|
const passthroughProps: typeof props = Object.assign({}, props);
|
|
@@ -215,11 +234,30 @@ const _PrismicLink = <
|
|
|
215
234
|
) : null;
|
|
216
235
|
};
|
|
217
236
|
|
|
237
|
+
if (!__PRODUCTION__) {
|
|
238
|
+
_PrismicLink.displayName = "PrismicLink";
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* React component that renders a link from a Prismic Link field.
|
|
243
|
+
*
|
|
244
|
+
* Different components can be rendered depending on whether the link is
|
|
245
|
+
* internal or external. This is helpful when integrating with client-side
|
|
246
|
+
* routers, such as a router-specific Link component.
|
|
247
|
+
*
|
|
248
|
+
* If a link is configured to open in a new window using `target="_blank"`,
|
|
249
|
+
* `rel="noopener noreferrer"` is set by default.
|
|
250
|
+
*
|
|
251
|
+
* @param props - Props for the component.
|
|
252
|
+
*
|
|
253
|
+
* @returns The internal or external link component depending on whether the
|
|
254
|
+
* link is internal or external.
|
|
255
|
+
*/
|
|
218
256
|
export const PrismicLink = React.forwardRef(_PrismicLink) as <
|
|
219
|
-
InternalComponent extends React.ElementType<LinkProps
|
|
220
|
-
ExternalComponent extends React.ElementType<LinkProps
|
|
257
|
+
InternalComponent extends React.ElementType<LinkProps> = typeof defaultInternalComponent,
|
|
258
|
+
ExternalComponent extends React.ElementType<LinkProps> = typeof defaultExternalComponent,
|
|
221
259
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
222
|
-
LinkResolverFunction extends prismicH.LinkResolverFunction<any
|
|
260
|
+
LinkResolverFunction extends prismicH.LinkResolverFunction<any> = prismicH.LinkResolverFunction,
|
|
223
261
|
>(
|
|
224
262
|
props: PrismicLinkProps<
|
|
225
263
|
InternalComponent,
|
package/src/PrismicText.tsx
CHANGED
|
@@ -2,6 +2,9 @@ import * as React from "react";
|
|
|
2
2
|
import * as prismicT from "@prismicio/types";
|
|
3
3
|
import * as prismicH from "@prismicio/helpers";
|
|
4
4
|
|
|
5
|
+
import { __PRODUCTION__ } from "./lib/__PRODUCTION__";
|
|
6
|
+
import { devMsg } from "./lib/devMsg";
|
|
7
|
+
|
|
5
8
|
/**
|
|
6
9
|
* Props for `<PrismicText>`.
|
|
7
10
|
*/
|
|
@@ -42,6 +45,16 @@ export type PrismicTextProps = {
|
|
|
42
45
|
* @see Learn about Rich Text fields {@link https://prismic.io/docs/core-concepts/rich-text-title}
|
|
43
46
|
*/
|
|
44
47
|
export const PrismicText = (props: PrismicTextProps): JSX.Element | null => {
|
|
48
|
+
if (!__PRODUCTION__) {
|
|
49
|
+
if (typeof props.field === "string") {
|
|
50
|
+
throw new Error(
|
|
51
|
+
`[PrismicText] The "field" prop only accepts a Rich Text or Title field's value but was provided a different type of field instead (e.g. a Key Text or Select field). You can resolve this error by rendering the field value inline without <PrismicText>. For more details, see ${devMsg(
|
|
52
|
+
"prismictext-works-only-with-rich-text-and-title-fields",
|
|
53
|
+
)}`,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
45
58
|
return React.useMemo(() => {
|
|
46
59
|
if (prismicH.isFilled.richText(props.field)) {
|
|
47
60
|
const text = prismicH.asText(props.field, props.separator);
|
package/src/PrismicToolbar.tsx
CHANGED
|
@@ -43,6 +43,19 @@ export const PrismicToolbar = ({
|
|
|
43
43
|
script.dataset.repositoryName = repositoryName;
|
|
44
44
|
script.dataset.type = type;
|
|
45
45
|
|
|
46
|
+
// Disable Happy DOM `<script>` evaluation during
|
|
47
|
+
// tests.
|
|
48
|
+
//
|
|
49
|
+
// This is a patch ONLY INCLUDED DURING TESTS. It will
|
|
50
|
+
// be pruned during code minification in non-test
|
|
51
|
+
// environments.
|
|
52
|
+
//
|
|
53
|
+
// @see https://github.com/capricorn86/happy-dom/blob/02ae081e36f990c06171eda44f9d885fd9413d73/packages/happy-dom/src/nodes/html-script-element/HTMLScriptElement.ts#L191-L209
|
|
54
|
+
if (process.env.NODE_ENV === "test") {
|
|
55
|
+
// @ts-expect-error - `_evaluateScript` is a Happy DOM-specific property.
|
|
56
|
+
script._evaluateScript = false;
|
|
57
|
+
}
|
|
58
|
+
|
|
46
59
|
document.body.appendChild(script);
|
|
47
60
|
}
|
|
48
61
|
}, [repositoryName, type, src]);
|
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
|
+
};
|