@slicemachine/adapter-next 0.3.37-beta.7 → 0.3.37-beta.8
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/hooks/project-init.cjs +64 -14
- package/dist/hooks/project-init.cjs.map +1 -1
- package/dist/hooks/project-init.js +64 -14
- package/dist/hooks/project-init.js.map +1 -1
- package/dist/hooks/sliceSimulator-setup-read.cjs +50 -13
- package/dist/hooks/sliceSimulator-setup-read.cjs.map +1 -1
- package/dist/hooks/sliceSimulator-setup-read.js +50 -13
- package/dist/hooks/sliceSimulator-setup-read.js.map +1 -1
- package/dist/simulator/SliceSimulator.cjs +7 -12
- package/dist/simulator/SliceSimulator.cjs.map +1 -1
- package/dist/simulator/SliceSimulator.d.ts +11 -3
- package/dist/simulator/SliceSimulator.js +8 -13
- package/dist/simulator/SliceSimulator.js.map +1 -1
- package/dist/simulator/SliceSimulatorWrapper.cjs +19 -0
- package/dist/simulator/SliceSimulatorWrapper.cjs.map +1 -0
- package/dist/simulator/SliceSimulatorWrapper.d.ts +14 -0
- package/dist/simulator/SliceSimulatorWrapper.js +19 -0
- package/dist/simulator/SliceSimulatorWrapper.js.map +1 -0
- package/dist/simulator/getSlices.cjs +7 -0
- package/dist/simulator/getSlices.cjs.map +1 -0
- package/dist/simulator/getSlices.d.ts +9 -0
- package/dist/simulator/getSlices.js +7 -0
- package/dist/simulator/getSlices.js.map +1 -0
- package/dist/simulator/index.d.ts +2 -0
- package/dist/simulator/react-server/SliceSimulator.cjs +76 -0
- package/dist/simulator/react-server/SliceSimulator.cjs.map +1 -0
- package/dist/simulator/react-server/SliceSimulator.d.ts +7 -0
- package/dist/simulator/react-server/SliceSimulator.js +59 -0
- package/dist/simulator/react-server/SliceSimulator.js.map +1 -0
- package/dist/simulator/react-server/actions.cjs +10 -0
- package/dist/simulator/react-server/actions.cjs.map +1 -0
- package/dist/simulator/react-server/actions.d.ts +1 -0
- package/dist/simulator/react-server/actions.js +10 -0
- package/dist/simulator/react-server/actions.js.map +1 -0
- package/dist/simulator/react-server/getSlices.cjs +9 -0
- package/dist/simulator/react-server/getSlices.cjs.map +1 -0
- package/dist/simulator/react-server/getSlices.d.ts +2 -0
- package/dist/simulator/react-server/getSlices.js +9 -0
- package/dist/simulator/react-server/getSlices.js.map +1 -0
- package/dist/simulator/react-server/index.d.ts +2 -0
- package/dist/simulator/react-server.cjs +7 -0
- package/dist/simulator/react-server.cjs.map +1 -0
- package/dist/simulator/react-server.js +7 -0
- package/dist/simulator/react-server.js.map +1 -0
- package/dist/simulator/types.d.ts +11 -0
- package/dist/simulator.cjs +2 -0
- package/dist/simulator.cjs.map +1 -1
- package/dist/simulator.js +3 -1
- package/dist/simulator.js.map +1 -1
- package/package.json +14 -5
- package/src/hooks/project-init.ts +64 -13
- package/src/hooks/sliceSimulator-setup-read.ts +64 -14
- package/src/simulator/SliceSimulator.tsx +49 -60
- package/src/simulator/SliceSimulatorWrapper.tsx +68 -0
- package/src/simulator/getSlices.ts +19 -0
- package/src/simulator/index.ts +3 -0
- package/src/simulator/react-server/SliceSimulator.tsx +113 -0
- package/src/simulator/react-server/actions.ts +7 -0
- package/src/simulator/react-server/getSlices.ts +16 -0
- package/src/simulator/react-server/index.ts +4 -0
- package/src/simulator/types.ts +11 -0
package/dist/simulator.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simulator.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"simulator.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
package/dist/simulator.js
CHANGED
package/dist/simulator.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simulator.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"simulator.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@slicemachine/adapter-next",
|
|
3
|
-
"version": "0.3.37-beta.
|
|
3
|
+
"version": "0.3.37-beta.8",
|
|
4
4
|
"description": "Slice Machine adapter for Next.js.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -21,9 +21,16 @@
|
|
|
21
21
|
"import": "./dist/index.js"
|
|
22
22
|
},
|
|
23
23
|
"./simulator": {
|
|
24
|
-
"
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
"react-server": {
|
|
25
|
+
"types": "./dist/simulator/react-server/index.d.ts",
|
|
26
|
+
"require": "./dist/simulator/react-server.cjs",
|
|
27
|
+
"import": "./dist/simulator/react-server.js"
|
|
28
|
+
},
|
|
29
|
+
"default": {
|
|
30
|
+
"types": "./dist/simulator/index.d.ts",
|
|
31
|
+
"require": "./dist/simulator.cjs",
|
|
32
|
+
"import": "./dist/simulator.js"
|
|
33
|
+
}
|
|
27
34
|
},
|
|
28
35
|
"./package.json": "./package.json"
|
|
29
36
|
},
|
|
@@ -61,11 +68,12 @@
|
|
|
61
68
|
"dependencies": {
|
|
62
69
|
"@prismicio/simulator": "^0.1.4",
|
|
63
70
|
"@prismicio/types-internal": "^2.2.0",
|
|
64
|
-
"@slicemachine/plugin-kit": "0.4.37-beta.
|
|
71
|
+
"@slicemachine/plugin-kit": "0.4.37-beta.8",
|
|
65
72
|
"common-tags": "^1.8.2",
|
|
66
73
|
"fp-ts": "^2.13.1",
|
|
67
74
|
"io-ts": "^2.2.20",
|
|
68
75
|
"io-ts-types": "^0.5.19",
|
|
76
|
+
"lz-string": "1.5.0",
|
|
69
77
|
"monocle-ts": "^2.3.13",
|
|
70
78
|
"newtype-ts": "^0.3.5",
|
|
71
79
|
"node-fetch": "^3.3.1",
|
|
@@ -86,6 +94,7 @@
|
|
|
86
94
|
"eslint-config-prettier": "9.0.0",
|
|
87
95
|
"eslint-plugin-prettier": "5.0.1",
|
|
88
96
|
"eslint-plugin-tsdoc": "0.2.17",
|
|
97
|
+
"next": "14.1.3",
|
|
89
98
|
"prettier": "3.0.3",
|
|
90
99
|
"prettier-plugin-jsdoc": "1.1.1",
|
|
91
100
|
"react": "18.2.0",
|
|
@@ -251,6 +251,10 @@ const createSliceSimulatorPage = async ({
|
|
|
251
251
|
helpers,
|
|
252
252
|
options,
|
|
253
253
|
}: CreateSliceSimulatorPageArgs) => {
|
|
254
|
+
const isTypeScriptProject = await checkIsTypeScriptProject({
|
|
255
|
+
helpers,
|
|
256
|
+
options,
|
|
257
|
+
});
|
|
254
258
|
const hasSrcDirectory = await checkHasSrcDirectory({ helpers });
|
|
255
259
|
const hasAppRouter = await checkHasAppRouter({ helpers });
|
|
256
260
|
|
|
@@ -270,22 +274,69 @@ const createSliceSimulatorPage = async ({
|
|
|
270
274
|
return;
|
|
271
275
|
}
|
|
272
276
|
|
|
273
|
-
|
|
274
|
-
"use client"
|
|
277
|
+
let contents;
|
|
275
278
|
|
|
276
|
-
|
|
277
|
-
|
|
279
|
+
if (hasAppRouter) {
|
|
280
|
+
if (isTypeScriptProject) {
|
|
281
|
+
contents = source`
|
|
282
|
+
import {
|
|
283
|
+
SliceSimulator,
|
|
284
|
+
SliceSimulatorParams,
|
|
285
|
+
getSlices,
|
|
286
|
+
} from "@slicemachine/adapter-next/simulator";
|
|
287
|
+
import { SliceZone } from "@prismicio/react";
|
|
288
|
+
|
|
289
|
+
import { components } from "../../slices";
|
|
290
|
+
|
|
291
|
+
export default function SliceSimulatorPage({
|
|
292
|
+
searchParams,
|
|
293
|
+
}: SliceSimulatorParams) {
|
|
294
|
+
const slices = getSlices(searchParams.state);
|
|
295
|
+
|
|
296
|
+
return (
|
|
297
|
+
<SliceSimulator>
|
|
298
|
+
<SliceZone slices={slices} components={components} />
|
|
299
|
+
</SliceSimulator>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
`;
|
|
303
|
+
} else {
|
|
304
|
+
contents = source`
|
|
305
|
+
import {
|
|
306
|
+
SliceSimulator,
|
|
307
|
+
getSlices,
|
|
308
|
+
} from "@slicemachine/adapter-next/simulator";
|
|
309
|
+
import { SliceZone } from "@prismicio/react";
|
|
310
|
+
|
|
311
|
+
import { components } from "../../slices";
|
|
312
|
+
|
|
313
|
+
export default function SliceSimulatorPage({ searchParams }) {
|
|
314
|
+
const slices = getSlices(searchParams.state);
|
|
315
|
+
|
|
316
|
+
return (
|
|
317
|
+
<SliceSimulator>
|
|
318
|
+
<SliceZone slices={slices} components={components} />
|
|
319
|
+
</SliceSimulator>
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
`;
|
|
323
|
+
}
|
|
324
|
+
} else {
|
|
325
|
+
contents = source`
|
|
326
|
+
import { SliceSimulator } from "@slicemachine/adapter-next/simulator";
|
|
327
|
+
import { SliceZone } from "@prismicio/react";
|
|
278
328
|
|
|
279
|
-
|
|
329
|
+
import { components } from "../slices";
|
|
280
330
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
331
|
+
export default function SliceSimulatorPage() {
|
|
332
|
+
return (
|
|
333
|
+
<SliceSimulator
|
|
334
|
+
sliceZone={(props) => <SliceZone {...props} components={components} />}
|
|
335
|
+
/>
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
`;
|
|
339
|
+
}
|
|
289
340
|
|
|
290
341
|
await writeProjectFile({
|
|
291
342
|
filename,
|
|
@@ -10,6 +10,7 @@ import fetch, { Response } from "node-fetch";
|
|
|
10
10
|
import { getJSFileExtension } from "../lib/getJSFileExtension";
|
|
11
11
|
|
|
12
12
|
import type { PluginOptions } from "../types";
|
|
13
|
+
import { checkHasAppRouter } from "../lib/checkHasAppRouter";
|
|
13
14
|
|
|
14
15
|
const REQUIRED_DEPENDENCIES = ["@prismicio/react"];
|
|
15
16
|
|
|
@@ -79,29 +80,78 @@ const createStep2 = async ({
|
|
|
79
80
|
helpers,
|
|
80
81
|
options,
|
|
81
82
|
}: Args): Promise<SliceSimulatorSetupStep> => {
|
|
83
|
+
const hasAppRouter = await checkHasAppRouter({ helpers });
|
|
84
|
+
|
|
82
85
|
const extension = await getJSFileExtension({ helpers, options, jsx: true });
|
|
86
|
+
|
|
87
|
+
if (hasAppRouter) {
|
|
88
|
+
const fileName = `page.${extension}`;
|
|
89
|
+
const filePath = helpers.joinPathFromRoot(
|
|
90
|
+
"app",
|
|
91
|
+
"slice-simulator",
|
|
92
|
+
fileName,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
const fileContents = await helpers.format(
|
|
96
|
+
source`
|
|
97
|
+
import {
|
|
98
|
+
SliceSimulator,
|
|
99
|
+
SliceSimulatorParams,
|
|
100
|
+
getSlices,
|
|
101
|
+
} from "@slicemachine/adapter-next/simulator";
|
|
102
|
+
import { SliceZone } from "@prismicio/react";
|
|
103
|
+
|
|
104
|
+
import { components } from "../../slices";
|
|
105
|
+
|
|
106
|
+
export default function SliceSimulatorPage({
|
|
107
|
+
searchParams,
|
|
108
|
+
}: SliceSimulatorParams) {
|
|
109
|
+
const slices = getSlices(searchParams.state);
|
|
110
|
+
|
|
111
|
+
return (
|
|
112
|
+
<SliceSimulator>
|
|
113
|
+
<SliceZone slices={slices} components={components} />
|
|
114
|
+
</SliceSimulator>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
`,
|
|
118
|
+
filePath,
|
|
119
|
+
{ includeNewlineAtEnd: false },
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
return {
|
|
123
|
+
title: "Create a page for the simulator",
|
|
124
|
+
description: `In your \`app\` directory, create a file called \`slice-simulator/${fileName}\` containing this code.`,
|
|
125
|
+
body: source`
|
|
126
|
+
In your \`app\` directory, create a file called \`slice-simulator/${fileName}\` and add the following code. This route will be used to simulate and develop your components.
|
|
127
|
+
|
|
128
|
+
~~~tsx
|
|
129
|
+
${fileContents}
|
|
130
|
+
~~~
|
|
131
|
+
`,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
83
135
|
const fileName = `slice-simulator.${extension}`;
|
|
84
136
|
const filePath = helpers.joinPathFromRoot("pages", fileName);
|
|
85
137
|
|
|
86
138
|
const fileContents = await helpers.format(
|
|
87
139
|
source`
|
|
88
|
-
|
|
89
|
-
|
|
140
|
+
import { SliceSimulator } from "@slicemachine/adapter-next/simulator";
|
|
141
|
+
import { SliceZone } from "@prismicio/react";
|
|
90
142
|
|
|
91
|
-
|
|
143
|
+
import { components } from "../slices";
|
|
92
144
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
145
|
+
export default function SliceSimulatorPage() {
|
|
146
|
+
return (
|
|
147
|
+
<SliceSimulator
|
|
148
|
+
sliceZone={(props) => <SliceZone {...props} components={components} />}
|
|
149
|
+
/>
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
`,
|
|
101
153
|
filePath,
|
|
102
|
-
{
|
|
103
|
-
includeNewlineAtEnd: false,
|
|
104
|
-
},
|
|
154
|
+
{ includeNewlineAtEnd: false },
|
|
105
155
|
);
|
|
106
156
|
|
|
107
157
|
return {
|
|
@@ -7,15 +7,12 @@ import {
|
|
|
7
7
|
SimulatorManager,
|
|
8
8
|
SliceSimulatorState,
|
|
9
9
|
StateEventType,
|
|
10
|
-
disableEventHandler,
|
|
11
10
|
getDefaultMessage,
|
|
12
|
-
getDefaultProps,
|
|
13
11
|
getDefaultSlices,
|
|
14
|
-
onClickHandler,
|
|
15
|
-
simulatorClass,
|
|
16
|
-
simulatorRootClass,
|
|
17
12
|
} from "@prismicio/simulator/kit";
|
|
18
13
|
|
|
14
|
+
import { SliceSimulatorWrapper } from "./SliceSimulatorWrapper";
|
|
15
|
+
|
|
19
16
|
const simulatorManager = new SimulatorManager();
|
|
20
17
|
|
|
21
18
|
export type SliceSimulatorSliceZoneProps = {
|
|
@@ -23,35 +20,50 @@ export type SliceSimulatorSliceZoneProps = {
|
|
|
23
20
|
};
|
|
24
21
|
|
|
25
22
|
export type SliceSimulatorProps = {
|
|
26
|
-
/**
|
|
27
|
-
* React component to render simulated Slices.
|
|
28
|
-
*
|
|
29
|
-
* @example
|
|
30
|
-
*
|
|
31
|
-
* ```tsx
|
|
32
|
-
* import { SliceSimulator } from "@slicemachine/adapter-next/simulator";
|
|
33
|
-
* import { SliceZone } from "@prismicio/react";
|
|
34
|
-
*
|
|
35
|
-
* import { components } from "../slices";
|
|
36
|
-
*
|
|
37
|
-
* <SliceSimulator
|
|
38
|
-
* sliceZone={({ slices }) => (
|
|
39
|
-
* <SliceZone slices={slices} components={components} />
|
|
40
|
-
* )}
|
|
41
|
-
* />;
|
|
42
|
-
* ```
|
|
43
|
-
*/
|
|
44
|
-
sliceZone: (props: SliceSimulatorSliceZoneProps) => JSX.Element;
|
|
45
23
|
className?: string;
|
|
46
|
-
} & Omit<BaseSliceSimulatorProps, "state"
|
|
24
|
+
} & Omit<BaseSliceSimulatorProps, "state"> &
|
|
25
|
+
(
|
|
26
|
+
| {
|
|
27
|
+
/**
|
|
28
|
+
* React component to render simulated Slices.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
*
|
|
32
|
+
* ```tsx
|
|
33
|
+
* import { SliceSimulator } from "@slicemachine/adapter-next/simulator";
|
|
34
|
+
* import { SliceZone } from "@prismicio/react";
|
|
35
|
+
*
|
|
36
|
+
* import { components } from "../slices";
|
|
37
|
+
*
|
|
38
|
+
* <SliceSimulator
|
|
39
|
+
* sliceZone={({ slices }) => (
|
|
40
|
+
* <SliceZone slices={slices} components={components} />
|
|
41
|
+
* )}
|
|
42
|
+
* />;
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
sliceZone: (props: SliceSimulatorSliceZoneProps) => JSX.Element;
|
|
46
|
+
}
|
|
47
|
+
| {
|
|
48
|
+
children: React.ReactNode;
|
|
49
|
+
}
|
|
50
|
+
);
|
|
47
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Simulate slices in isolation. The slice simulator enables live slice
|
|
54
|
+
* development in Slice Machine and live previews in the Page Builder.
|
|
55
|
+
*/
|
|
48
56
|
export const SliceSimulator = ({
|
|
49
|
-
sliceZone: SliceZoneComp,
|
|
50
57
|
background,
|
|
51
58
|
zIndex,
|
|
52
59
|
className,
|
|
60
|
+
...restProps
|
|
53
61
|
}: SliceSimulatorProps): JSX.Element => {
|
|
54
|
-
|
|
62
|
+
if (!("sliceZone" in restProps)) {
|
|
63
|
+
throw new Error(
|
|
64
|
+
"A sliceZone prop must be provided when <SliceZone> is rendered in a Client Component. Add a sliceZone prop or convert your simulator to a Server Component with the getSlices helper.",
|
|
65
|
+
);
|
|
66
|
+
}
|
|
55
67
|
|
|
56
68
|
const [slices, setSlices] = React.useState(() => getDefaultSlices());
|
|
57
69
|
const [message, setMessage] = React.useState(() => getDefaultMessage());
|
|
@@ -81,40 +93,17 @@ export const SliceSimulator = ({
|
|
|
81
93
|
};
|
|
82
94
|
}, []);
|
|
83
95
|
|
|
96
|
+
const SliceZoneComp = restProps.sliceZone;
|
|
97
|
+
|
|
84
98
|
return (
|
|
85
|
-
<
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
: zIndex ?? undefined,
|
|
92
|
-
position: "fixed",
|
|
93
|
-
top: 0,
|
|
94
|
-
left: 0,
|
|
95
|
-
width: "100%",
|
|
96
|
-
height: "100vh",
|
|
97
|
-
overflow: "auto",
|
|
98
|
-
background:
|
|
99
|
-
typeof background === "undefined"
|
|
100
|
-
? defaultProps.background
|
|
101
|
-
: background ?? undefined,
|
|
102
|
-
}}
|
|
99
|
+
<SliceSimulatorWrapper
|
|
100
|
+
message={message}
|
|
101
|
+
hasSlices={slices.length > 0}
|
|
102
|
+
background={background}
|
|
103
|
+
zIndex={zIndex}
|
|
104
|
+
className={className}
|
|
103
105
|
>
|
|
104
|
-
{
|
|
105
|
-
|
|
106
|
-
) : slices.length ? (
|
|
107
|
-
<div
|
|
108
|
-
id="root"
|
|
109
|
-
className={simulatorRootClass}
|
|
110
|
-
onClickCapture={onClickHandler as unknown as React.MouseEventHandler}
|
|
111
|
-
onSubmitCapture={
|
|
112
|
-
disableEventHandler as unknown as React.FormEventHandler
|
|
113
|
-
}
|
|
114
|
-
>
|
|
115
|
-
<SliceZoneComp slices={slices} />
|
|
116
|
-
</div>
|
|
117
|
-
) : null}
|
|
118
|
-
</div>
|
|
106
|
+
<SliceZoneComp slices={slices} />
|
|
107
|
+
</SliceSimulatorWrapper>
|
|
119
108
|
);
|
|
120
109
|
};
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import {
|
|
3
|
+
SliceSimulatorProps,
|
|
4
|
+
disableEventHandler,
|
|
5
|
+
getDefaultProps,
|
|
6
|
+
onClickHandler,
|
|
7
|
+
simulatorClass,
|
|
8
|
+
simulatorRootClass,
|
|
9
|
+
} from "@prismicio/simulator/kit";
|
|
10
|
+
|
|
11
|
+
type SliceSimulatorWrapperProps = {
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
className?: string;
|
|
14
|
+
message?: string;
|
|
15
|
+
hasSlices: boolean;
|
|
16
|
+
} & Omit<SliceSimulatorProps, "state">;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A wrapper for the slice simulator that isolates the given children from the
|
|
20
|
+
* page's layout.
|
|
21
|
+
*/
|
|
22
|
+
export const SliceSimulatorWrapper = ({
|
|
23
|
+
className,
|
|
24
|
+
children,
|
|
25
|
+
zIndex,
|
|
26
|
+
background,
|
|
27
|
+
message,
|
|
28
|
+
hasSlices,
|
|
29
|
+
}: SliceSimulatorWrapperProps): JSX.Element => {
|
|
30
|
+
const defaultProps = getDefaultProps();
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<div
|
|
34
|
+
className={[simulatorClass, className].filter(Boolean).join(" ")}
|
|
35
|
+
style={{
|
|
36
|
+
zIndex:
|
|
37
|
+
typeof zIndex === "undefined"
|
|
38
|
+
? defaultProps.zIndex
|
|
39
|
+
: zIndex ?? undefined,
|
|
40
|
+
position: "fixed",
|
|
41
|
+
top: 0,
|
|
42
|
+
left: 0,
|
|
43
|
+
width: "100%",
|
|
44
|
+
height: "100vh",
|
|
45
|
+
overflow: "auto",
|
|
46
|
+
background:
|
|
47
|
+
typeof background === "undefined"
|
|
48
|
+
? defaultProps.background
|
|
49
|
+
: background ?? undefined,
|
|
50
|
+
}}
|
|
51
|
+
>
|
|
52
|
+
{message ? (
|
|
53
|
+
<article dangerouslySetInnerHTML={{ __html: message }} />
|
|
54
|
+
) : hasSlices ? (
|
|
55
|
+
<div
|
|
56
|
+
id="root"
|
|
57
|
+
className={simulatorRootClass}
|
|
58
|
+
onClickCapture={onClickHandler as unknown as React.MouseEventHandler}
|
|
59
|
+
onSubmitCapture={
|
|
60
|
+
disableEventHandler as unknown as React.FormEventHandler
|
|
61
|
+
}
|
|
62
|
+
>
|
|
63
|
+
{children}
|
|
64
|
+
</div>
|
|
65
|
+
) : null}
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { StateEvents, StateEventType } from "@prismicio/simulator/kit";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Returns the simulator's slices from the page's `searchParams.state` value.
|
|
5
|
+
* The `state` value is set by `<SliceSimulator>`.
|
|
6
|
+
*
|
|
7
|
+
* **Note**: `getSlices` should only be used in the App Router with a Server
|
|
8
|
+
* Component.
|
|
9
|
+
*/
|
|
10
|
+
export const getSlices = (
|
|
11
|
+
state: string | null | undefined,
|
|
12
|
+
): StateEvents[StateEventType.Slices] => {
|
|
13
|
+
// Prevent tsserver + eslint warnings about unused vars.
|
|
14
|
+
state;
|
|
15
|
+
|
|
16
|
+
throw new Error(
|
|
17
|
+
"getSlices is designed only for Server Components. Convert your simulator page to a Server Component or remove the function from your Client Component.",
|
|
18
|
+
);
|
|
19
|
+
};
|
package/src/simulator/index.ts
CHANGED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
// This `<SliceSimulator>` is only accessible from Server Components.
|
|
2
|
+
|
|
3
|
+
"use client";
|
|
4
|
+
|
|
5
|
+
import * as React from "react";
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
SliceSimulatorProps as BaseSliceSimulatorProps,
|
|
9
|
+
SimulatorManager,
|
|
10
|
+
StateEventType,
|
|
11
|
+
getDefaultMessage,
|
|
12
|
+
} from "@prismicio/simulator/kit";
|
|
13
|
+
import { compressToEncodedURIComponent } from "lz-string";
|
|
14
|
+
|
|
15
|
+
import { SliceSimulatorWrapper } from "../SliceSimulatorWrapper";
|
|
16
|
+
import { revalidatePath } from "./actions";
|
|
17
|
+
import { getSlices } from "./getSlices";
|
|
18
|
+
|
|
19
|
+
const STATE_PARAMS_KEY = "state";
|
|
20
|
+
|
|
21
|
+
const throttle =
|
|
22
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
23
|
+
<TArgs extends [...any]>(fn: (...args: TArgs) => unknown, wait: number) => {
|
|
24
|
+
let timeoutId: ReturnType<typeof setTimeout>;
|
|
25
|
+
let lastCallTime = 0;
|
|
26
|
+
|
|
27
|
+
return (...args: TArgs) => {
|
|
28
|
+
clearTimeout(timeoutId);
|
|
29
|
+
|
|
30
|
+
const now = Date.now();
|
|
31
|
+
const timeSinceLastCall = now - lastCallTime;
|
|
32
|
+
const delayForNextCall = wait - timeSinceLastCall;
|
|
33
|
+
|
|
34
|
+
if (delayForNextCall <= 0) {
|
|
35
|
+
lastCallTime = now;
|
|
36
|
+
fn(...args);
|
|
37
|
+
} else {
|
|
38
|
+
timeoutId = setTimeout(() => {
|
|
39
|
+
lastCallTime = Date.now();
|
|
40
|
+
fn(...args);
|
|
41
|
+
}, delayForNextCall);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
};
|
|
45
|
+
const throttledRevalidatePath = throttle(revalidatePath, 300);
|
|
46
|
+
|
|
47
|
+
const simulatorManager = new SimulatorManager();
|
|
48
|
+
|
|
49
|
+
export type SliceSimulatorProps = Omit<BaseSliceSimulatorProps, "state"> & {
|
|
50
|
+
children: React.ReactNode;
|
|
51
|
+
className?: string;
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
export const SliceSimulator = ({
|
|
55
|
+
children,
|
|
56
|
+
background,
|
|
57
|
+
zIndex,
|
|
58
|
+
className,
|
|
59
|
+
}: SliceSimulatorProps): JSX.Element => {
|
|
60
|
+
const [message, setMessage] = React.useState(() => getDefaultMessage());
|
|
61
|
+
|
|
62
|
+
const state =
|
|
63
|
+
typeof window !== "undefined"
|
|
64
|
+
? new URL(window.location.href).searchParams.get(STATE_PARAMS_KEY)
|
|
65
|
+
: undefined;
|
|
66
|
+
const hasSlices = getSlices(state).length > 0;
|
|
67
|
+
|
|
68
|
+
React.useEffect(() => {
|
|
69
|
+
simulatorManager.state.on(
|
|
70
|
+
StateEventType.Slices,
|
|
71
|
+
(newSlices) => {
|
|
72
|
+
const url = new URL(window.location.href);
|
|
73
|
+
url.searchParams.set(
|
|
74
|
+
STATE_PARAMS_KEY,
|
|
75
|
+
compressToEncodedURIComponent(JSON.stringify(newSlices)),
|
|
76
|
+
);
|
|
77
|
+
window.history.pushState(null, "", url);
|
|
78
|
+
|
|
79
|
+
// A 0 ms timeout is needed to prevent a bug
|
|
80
|
+
// where the path is revalidated before the URL
|
|
81
|
+
// is updated with the new state.
|
|
82
|
+
const path = window.location.pathname;
|
|
83
|
+
setTimeout(() => throttledRevalidatePath(path), 0);
|
|
84
|
+
},
|
|
85
|
+
"simulator-slices",
|
|
86
|
+
);
|
|
87
|
+
simulatorManager.state.on(
|
|
88
|
+
StateEventType.Message,
|
|
89
|
+
(newMessage) => setMessage(newMessage),
|
|
90
|
+
"simulator-message",
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
simulatorManager.init();
|
|
94
|
+
|
|
95
|
+
return () => {
|
|
96
|
+
simulatorManager.state.off(StateEventType.Slices, "simulator-slices");
|
|
97
|
+
|
|
98
|
+
simulatorManager.state.off(StateEventType.Message, "simulator-message");
|
|
99
|
+
};
|
|
100
|
+
}, []);
|
|
101
|
+
|
|
102
|
+
return (
|
|
103
|
+
<SliceSimulatorWrapper
|
|
104
|
+
message={message}
|
|
105
|
+
hasSlices={hasSlices}
|
|
106
|
+
background={background}
|
|
107
|
+
zIndex={zIndex}
|
|
108
|
+
className={className}
|
|
109
|
+
>
|
|
110
|
+
{children}
|
|
111
|
+
</SliceSimulatorWrapper>
|
|
112
|
+
);
|
|
113
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// This `getSlices` is only accessible from Server Components.
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getDefaultSlices,
|
|
5
|
+
StateEvents,
|
|
6
|
+
StateEventType,
|
|
7
|
+
} from "@prismicio/simulator/kit";
|
|
8
|
+
import { decompressFromEncodedURIComponent } from "lz-string";
|
|
9
|
+
|
|
10
|
+
export const getSlices = (
|
|
11
|
+
state: string | null | undefined,
|
|
12
|
+
): StateEvents[StateEventType.Slices] => {
|
|
13
|
+
return state
|
|
14
|
+
? JSON.parse(decompressFromEncodedURIComponent(state))
|
|
15
|
+
: getDefaultSlices();
|
|
16
|
+
};
|