@prismicio/next 0.1.1 → 0.1.4-alpha.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.
package/dist/index.mjs CHANGED
@@ -1,156 +1,6 @@
1
- import * as prismic from '@prismicio/client';
2
- import React, { useEffect } from 'react';
3
- import { PrismicToolbar } from '@prismicio/react';
4
- import { useRouter } from 'next/router';
5
-
6
- async function setPreviewData({
7
- req,
8
- res
9
- }) {
10
- const ref = req.query.token || req.cookies[prismic.cookie.preview];
11
- if (ref) {
12
- res.setPreviewData({ ref });
13
- }
14
- }
15
-
16
- function exitPreview(config) {
17
- const { req } = config;
18
- config.res.clearPreviewData();
19
- if (req.headers.referer) {
20
- const url = new URL(req.headers.referer);
21
- if (url.pathname !== "/api/exit-preview") {
22
- config.res.redirect(req.headers.referer);
23
- return;
24
- }
25
- }
26
- config.res.redirect("/");
27
- }
28
-
29
- const readValue = (value) => {
30
- return value.replace(/%3B/g, ";");
31
- };
32
- const parse = (cookieString) => {
33
- const result = {};
34
- const cookies = cookieString.split("; ");
35
- for (const cookie of cookies) {
36
- const parts = cookie.split("=");
37
- const value = parts.slice(1).join("=");
38
- const name = readValue(parts[0]).replace(/%3D/g, "=");
39
- result[name] = readValue(value);
40
- }
41
- return result;
42
- };
43
- const getAll = (cookieStore) => parse(cookieStore);
44
- const getCookie = (name, cookieStore) => getAll(cookieStore)[name];
45
-
46
- const extractFirstSubdomain = (host) => host.split(".")[0];
47
- const extractRepositoryNameFromObjectRef = (previewRef) => {
48
- try {
49
- const parsed = JSON.parse(decodeURIComponent(previewRef));
50
- const keys = Object.keys(parsed);
51
- const domainKey = keys.find((key) => /\.prismic\.io$/.test(key));
52
- if (domainKey) {
53
- return extractFirstSubdomain(domainKey);
54
- } else {
55
- return void 0;
56
- }
57
- } catch (e) {
58
- return void 0;
59
- }
60
- };
61
- const extractRepositoryNameFromURLRef = (previewRef) => {
62
- try {
63
- const url = new URL(previewRef);
64
- return extractFirstSubdomain(url.host);
65
- } catch (e) {
66
- return void 0;
67
- }
68
- };
69
- const extractPreviewRefRepositoryName = (previewRef) => {
70
- return extractRepositoryNameFromObjectRef(previewRef) || extractRepositoryNameFromURLRef(previewRef);
71
- };
72
-
73
- const isPrismicUpdateToolbarEvent = (event) => {
74
- return "detail" in event && typeof event.detail.ref === "string";
75
- };
76
- function PrismicPreview({
77
- repositoryName,
78
- children,
79
- updatePreviewURL = "/api/preview",
80
- exitPreviewURL = "/api/exit-preview"
81
- }) {
82
- const router = useRouter();
83
- useEffect(() => {
84
- const previewRefRepositoryName = extractPreviewRefRepositoryName(getCookie("io.prismic.preview", globalThis.document.cookie));
85
- const startPreviewIfLoadedFromSharedLink = async () => {
86
- if (previewRefRepositoryName === repositoryName && !router.isPreview) {
87
- await fetch(updatePreviewURL);
88
- window.location.reload();
89
- }
90
- };
91
- startPreviewIfLoadedFromSharedLink();
92
- const handlePrismicPreviewUpdate = async (event) => {
93
- if (isPrismicUpdateToolbarEvent(event)) {
94
- event.preventDefault();
95
- await fetch(updatePreviewURL);
96
- window.location.reload();
97
- }
98
- };
99
- const handlePrismicPreviewEnd = async (event) => {
100
- event.preventDefault();
101
- await fetch(exitPreviewURL);
102
- window.location.reload();
103
- };
104
- if (window) {
105
- window.addEventListener("prismicPreviewUpdate", handlePrismicPreviewUpdate);
106
- window.addEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
107
- }
108
- return () => {
109
- if (window) {
110
- window.removeEventListener("prismicPreviewUpdate", handlePrismicPreviewUpdate);
111
- window.removeEventListener("prismicPreviewEnd", handlePrismicPreviewEnd);
112
- }
113
- };
114
- }, []);
115
- return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(PrismicToolbar, {
116
- repositoryName
117
- }), children);
118
- }
119
-
120
- const isPrismicNextPreviewData = (previewData) => {
121
- return typeof previewData === "object" && "ref" in previewData;
122
- };
123
- const enableAutoPreviews = (config) => {
124
- if ("previewData" in config && config.previewData) {
125
- const { previewData } = config;
126
- if (isPrismicNextPreviewData(previewData) && previewData.ref) {
127
- config.client.queryContentFromRef(previewData.ref);
128
- }
129
- } else if ("req" in config && config.req) {
130
- config.client.enableAutoPreviewsFromReq(config.req);
131
- }
132
- };
133
-
134
- const isPrismicNextQuery = (query) => typeof query.documentId === "string" && typeof query.token === "string";
135
- async function redirectToPreviewURL({
136
- req,
137
- res,
138
- client,
139
- linkResolver,
140
- defaultURL = "/"
141
- }) {
142
- if (isPrismicNextQuery(req.query)) {
143
- const { documentId, token } = req.query;
144
- const previewUrl = await client.resolvePreviewURL({
145
- linkResolver,
146
- defaultURL,
147
- documentID: documentId,
148
- previewToken: token
149
- });
150
- res.redirect(previewUrl);
151
- return;
152
- }
153
- res.redirect(defaultURL);
154
- }
155
-
156
- export { PrismicPreview, enableAutoPreviews, exitPreview, redirectToPreviewURL, setPreviewData };
1
+ export { setPreviewData } from './setPreviewData.mjs';
2
+ export { exitPreview } from './exitPreview.mjs';
3
+ export { PrismicPreview } from './PrismicPreview.mjs';
4
+ export { enableAutoPreviews } from './enableAutoPreviews.mjs';
5
+ export { redirectToPreviewURL } from './redirectToPreviewURL.mjs';
6
+ export { PrismicNextImage } from './PrismicNextImage.mjs';
@@ -0,0 +1,3 @@
1
+ const __PRODUCTION__ = process.env.NODE_ENV === "production";
2
+
3
+ export { __PRODUCTION__ };
@@ -0,0 +1,7 @@
1
+ import { version } from '../package.mjs';
2
+
3
+ const devMsg = (slug) => {
4
+ return `https://prismic.dev/msg/next/v${version}/${slug}`;
5
+ };
6
+
7
+ export { devMsg };
@@ -0,0 +1,5 @@
1
+ const getPreviewCookieRepositoryName = (previewCookie) => {
2
+ return (decodeURIComponent(previewCookie).match(/"(.+).prismic.io"/) || [])[1];
3
+ };
4
+
5
+ export { getPreviewCookieRepositoryName };
@@ -0,0 +1,20 @@
1
+ import * as prismic from '@prismicio/client';
2
+
3
+ const readValue = (value) => {
4
+ return value.replace(/%3B/g, ";");
5
+ };
6
+ const getPrismicPreviewCookie = (cookieJar) => {
7
+ const cookies = cookieJar.split("; ");
8
+ let value;
9
+ for (const cookie of cookies) {
10
+ const parts = cookie.split("=");
11
+ const name = readValue(parts[0]).replace(/%3D/g, "=");
12
+ if (name === prismic.cookie.preview) {
13
+ value = readValue(parts.slice(1).join("="));
14
+ continue;
15
+ }
16
+ }
17
+ return value;
18
+ };
19
+
20
+ export { getPrismicPreviewCookie };
@@ -0,0 +1,3 @@
1
+ const version = "0.1.4-alpha.0";
2
+
3
+ export { version };
@@ -0,0 +1,20 @@
1
+ const isPrismicNextQuery = (query) => {
2
+ return typeof query.documentId === "string" && typeof query.token === "string";
3
+ };
4
+ async function redirectToPreviewURL(config) {
5
+ const defaultURL = config.defaultURL || "/";
6
+ const basePath = config.basePath || "";
7
+ if (isPrismicNextQuery(config.req.query)) {
8
+ const previewUrl = await config.client.resolvePreviewURL({
9
+ linkResolver: config.linkResolver,
10
+ defaultURL,
11
+ documentID: config.req.query.documentId,
12
+ previewToken: config.req.query.token
13
+ });
14
+ config.res.redirect(basePath + previewUrl);
15
+ return;
16
+ }
17
+ config.res.redirect(basePath + defaultURL);
18
+ }
19
+
20
+ export { redirectToPreviewURL };
@@ -0,0 +1,10 @@
1
+ import * as prismic from '@prismicio/client';
2
+
3
+ function setPreviewData({ req, res }) {
4
+ const ref = req.query.token || req.cookies[prismic.cookie.preview];
5
+ if (ref) {
6
+ res.setPreviewData({ ref });
7
+ }
8
+ }
9
+
10
+ export { setPreviewData };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@prismicio/next",
3
- "version": "0.1.1",
4
- "description": "Integrate Prismic into a Next.js app",
3
+ "version": "0.1.4-alpha.0",
4
+ "description": "Helpers to integrate Prismic into Next.js apps",
5
5
  "keywords": [
6
6
  "typescript",
7
7
  "prismic",
@@ -15,66 +15,63 @@
15
15
  },
16
16
  "license": "Apache-2.0",
17
17
  "author": "Prismic <contact@prismic.io> (https://prismic.io)",
18
+ "sideEffects": false,
18
19
  "type": "module",
19
20
  "exports": {
20
- ".": {
21
- "require": "./dist/index.cjs",
22
- "import": "./dist/index.mjs"
23
- },
24
- "./package.json": "./package.json"
21
+ ".": "./dist/index.mjs"
25
22
  },
26
- "main": "./dist/index.cjs",
27
- "module": "dist/index.mjs",
28
23
  "types": "dist/index.d.ts",
29
24
  "files": [
30
25
  "dist",
31
26
  "src"
32
27
  ],
33
28
  "scripts": {
34
- "build": "siroc build",
35
- "dev": "siroc build --watch",
29
+ "build": "unbuild",
30
+ "dev": "unbuild --stub",
36
31
  "format": "prettier --write .",
37
32
  "lint": "eslint --ext .js,.ts .",
38
33
  "prepare": "npm run build",
39
- "release": "npm run build && npm run test && standard-version && git push --follow-tags && npm run build && npm publish",
40
- "release:alpha": "npm run build && npm run test && standard-version --release-as major --prerelease alpha && git push --follow-tags && npm run build && npm publish --tag alpha",
34
+ "release": "npm run test && standard-version && git push --follow-tags && npm run build && npm publish",
35
+ "release:alpha": "npm run test && standard-version --release-as major --prerelease alpha && git push --follow-tags && npm run build && npm publish --tag alpha",
41
36
  "release:alpha:dry": "standard-version --release-as major --prerelease alpha --dry-run",
42
37
  "release:dry": "standard-version --dry-run",
43
- "test": "npm run lint && npm run unit",
44
- "unit": "nyc --reporter=lcovonly --reporter=text --exclude-after-remap=false ava"
38
+ "size": "size-limit",
39
+ "test": "npm run lint && npm run unit && npm run build && npm run size",
40
+ "unit": "vitest run --coverage",
41
+ "unit:watch": "vitest watch"
45
42
  },
46
43
  "dependencies": {
47
- "@prismicio/react": "^2.2.0"
44
+ "@prismicio/client": "^6.7.0",
45
+ "@prismicio/helpers": "^2.3.3",
46
+ "@prismicio/react": "^2.5.0",
47
+ "@prismicio/types": "^0.2.3",
48
+ "eslint-plugin-react": "^7.30.1",
49
+ "eslint-plugin-react-hooks": "^4.6.0",
50
+ "imgix-url-builder": "^0.0.3"
48
51
  },
49
52
  "devDependencies": {
50
- "@prismicio/client": "^6.0.0",
51
- "@prismicio/mock": "^0.0.6",
52
- "@prismicio/types": "^0.1.13",
53
- "@testing-library/react": "^12.1.4",
54
- "@types/jsdom": "^16.2.13",
55
- "@types/jsdom-global": "^3.0.2",
56
- "@types/node-fetch": "^3.0.3",
57
- "@types/sinon": "^10.0.6",
58
- "@typescript-eslint/eslint-plugin": "^4.29.1",
59
- "@typescript-eslint/parser": "^4.29.1",
60
- "ava": "^3.15.0",
61
- "eslint": "^7.32.0",
62
- "eslint-config-prettier": "^8.3.0",
63
- "eslint-plugin-prettier": "^3.4.0",
64
- "eslint-plugin-tsdoc": "^0.2.14",
65
- "jsdom": "^18.1.1",
66
- "jsdom-global": "^3.0.2",
67
- "msw": "^0.35.0",
68
- "node-fetch": "^2.6.6",
53
+ "@prismicio/mock": "^0.1.1",
54
+ "@size-limit/preset-small-lib": "^8.0.1",
55
+ "@types/react-test-renderer": "^18.0.0",
56
+ "@typescript-eslint/eslint-plugin": "^5.34.0",
57
+ "@typescript-eslint/parser": "^5.34.0",
58
+ "@vitest/coverage-c8": "^0.22.1",
59
+ "eslint": "^8.22.0",
60
+ "eslint-config-prettier": "^8.5.0",
61
+ "eslint-plugin-prettier": "^4.2.1",
62
+ "eslint-plugin-tsdoc": "^0.2.16",
63
+ "happy-dom": "^6.0.4",
64
+ "next": "^12.1.4",
69
65
  "nyc": "^15.1.0",
70
- "prettier": "^2.3.2",
71
- "prettier-plugin-jsdoc": "^0.3.30",
72
- "react-test-renderer": "^18.0.0",
73
- "sinon": "^12.0.1",
74
- "siroc": "^0.15.0",
75
- "standard-version": "^9.3.1",
76
- "ts-eager": "^2.0.2",
77
- "typescript": "^4.3.5"
66
+ "prettier": "^2.7.1",
67
+ "prettier-plugin-jsdoc": "^0.3.38",
68
+ "react": "^18.1.0",
69
+ "react-test-renderer": "^18.2.0",
70
+ "size-limit": "^8.0.1",
71
+ "standard-version": "^9.5.0",
72
+ "typescript": "^4.7.4",
73
+ "unbuild": "^0.8.9",
74
+ "vitest": "^0.22.1"
78
75
  },
79
76
  "peerDependencies": {
80
77
  "@prismicio/client": "^6.0.0",
@@ -0,0 +1,125 @@
1
+ import * as React from "react";
2
+ import Image, { ImageProps, ImageLoaderProps } from "next/image";
3
+ import { buildURL, ImgixURLParams } from "imgix-url-builder";
4
+ import * as prismicH from "@prismicio/helpers";
5
+ import * as prismicT from "@prismicio/types";
6
+
7
+ import { __PRODUCTION__ } from "./lib/__PRODUCTION__";
8
+ import { devMsg } from "./lib/devMsg";
9
+
10
+ /**
11
+ * Creates a `next/image` loader for Imgix, which Prismic uses, with an optional
12
+ * collection of default Imgix parameters.
13
+ *
14
+ * @see To learn about `next/image` loaders: https://nextjs.org/docs/api-reference/next/image#loader
15
+ * @see To learn about Imgix's URL API: https://docs.imgix.com/apis/rendering
16
+ */
17
+ const imgixLoader = (args: ImageLoaderProps): string => {
18
+ const url = new URL(args.src);
19
+
20
+ const params: ImgixURLParams = {
21
+ fit: (url.searchParams.get("fit") as ImgixURLParams["fit"]) || "max",
22
+ w: args.width,
23
+ h: undefined,
24
+ };
25
+
26
+ if (args.quality) {
27
+ params.q = args.quality;
28
+ }
29
+
30
+ return buildURL(args.src, params);
31
+ };
32
+
33
+ export type PrismicNextImageProps = Omit<
34
+ ImageProps,
35
+ "src" | "alt" | "width" | "height"
36
+ > & {
37
+ /**
38
+ * The Prismic Image field or thumbnail to render.
39
+ */
40
+ field: prismicT.ImageFieldImage | null | undefined;
41
+
42
+ /**
43
+ * An object of Imgix URL API parameters to transform the image.
44
+ *
45
+ * @see https://docs.imgix.com/apis/rendering
46
+ */
47
+ imgixParams?: ImgixURLParams;
48
+
49
+ /**
50
+ * Declare an image as decorative by providing `alt=""`.
51
+ *
52
+ * See:
53
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/alt#decorative_images
54
+ */
55
+ alt?: "";
56
+
57
+ /**
58
+ * Declare an image as decorative only if the Image field does not have
59
+ * alternative text by providing `fallbackAlt=""`.
60
+ *
61
+ * See:
62
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/alt#decorative_images
63
+ */
64
+ fallbackAlt?: "";
65
+ };
66
+
67
+ /**
68
+ * React component that renders an image from a Prismic Image field or one of
69
+ * its thumbnails using `next/image`. It will automatically set the `alt`
70
+ * attribute using the Image field's `alt` property.
71
+ *
72
+ * It uses an Imgix URL-based loader by default. A custom loader can be provided
73
+ * with the `loader` prop. If you would like to use the Next.js Image
74
+ * Optimization API instead, set `loader={undefined}`.
75
+ *
76
+ * @param props - Props for the component.
77
+ *
78
+ * @returns A responsive image component using `next/image` for the given Image field.
79
+ *
80
+ * @see To learn more about `next/image`, see: https://nextjs.org/docs/api-reference/next/image
81
+ */
82
+ export const PrismicNextImage = ({
83
+ field,
84
+ imgixParams = {},
85
+ alt,
86
+ fallbackAlt,
87
+ layout,
88
+ ...restProps
89
+ }: PrismicNextImageProps) => {
90
+ if (!__PRODUCTION__) {
91
+ if (typeof alt === "string" && alt !== "") {
92
+ console.warn(
93
+ `[PrismicNextImage] 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(
94
+ "alt-must-be-an-empty-string",
95
+ )}`,
96
+ );
97
+ }
98
+
99
+ if (typeof fallbackAlt === "string" && fallbackAlt !== "") {
100
+ console.warn(
101
+ `[PrismicNextImage] 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(
102
+ "alt-must-be-an-empty-string",
103
+ )}`,
104
+ );
105
+ }
106
+ }
107
+
108
+ if (prismicH.isFilled.imageThumbnail(field)) {
109
+ const src = buildURL(field.url, imgixParams);
110
+
111
+ return (
112
+ <Image
113
+ src={src}
114
+ width={layout === "fill" ? undefined : field.dimensions.width}
115
+ height={layout === "fill" ? undefined : field.dimensions.height}
116
+ alt={alt ?? (field.alt || fallbackAlt)}
117
+ loader={imgixLoader}
118
+ layout={layout}
119
+ {...restProps}
120
+ />
121
+ );
122
+ } else {
123
+ return null;
124
+ }
125
+ };