@slicemachine/adapter-next 0.0.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/LICENSE +202 -0
- package/README.md +98 -0
- package/dist/index.cjs +699 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +671 -0
- package/dist/index.js.map +1 -0
- package/package.json +87 -0
- package/src/SliceSimulator.tsx +158 -0
- package/src/hooks/customType-create.ts +56 -0
- package/src/hooks/customType-delete.ts +13 -0
- package/src/hooks/customType-library-read.ts +40 -0
- package/src/hooks/customType-read.ts +19 -0
- package/src/hooks/customType-update.ts +3 -0
- package/src/hooks/slice-create.ts +146 -0
- package/src/hooks/slice-delete.ts +50 -0
- package/src/hooks/slice-library-read.ts +51 -0
- package/src/hooks/slice-read.ts +20 -0
- package/src/hooks/slice-update.ts +58 -0
- package/src/hooks/sliceSimulator-setup-read.ts +244 -0
- package/src/hooks/snippet-read.ts +115 -0
- package/src/index.ts +10 -0
- package/src/lib/buildSliceLibraryIndexFileContents.ts +38 -0
- package/src/lib/getJSOrTSXFileExtension.ts +13 -0
- package/src/lib/pascalCase.ts +12 -0
- package/src/lib/readJSONFile.ts +7 -0
- package/src/plugin.ts +43 -0
- package/src/types.ts +12 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,671 @@
|
|
|
1
|
+
import { SliceSimulatorSetupStepValidationMessageType, defineSliceMachinePlugin } from '@slicemachine/plugin-kit';
|
|
2
|
+
import { generateTypes } from 'prismic-ts-codegen';
|
|
3
|
+
import { stripIndent } from 'common-tags';
|
|
4
|
+
import * as fs from 'node:fs/promises';
|
|
5
|
+
import * as path from 'node:path';
|
|
6
|
+
import { pascalCase as pascalCase$1 } from 'pascal-case';
|
|
7
|
+
import { createRequire } from 'node:module';
|
|
8
|
+
import * as http from 'node:http';
|
|
9
|
+
import * as React from 'react';
|
|
10
|
+
import { CoreManager, getDefaultProps, getDefaultManagedState, getDefaultSlices, getDefaultMessage, StateManagerEventType, simulatorClass, simulatorRootClass, StateManagerStatus, onClickHandler, disableEventHandler } from '@prismicio/slice-simulator-core';
|
|
11
|
+
|
|
12
|
+
var name = "@slicemachine/adapter-next";
|
|
13
|
+
|
|
14
|
+
const pascalCase = (...input) => {
|
|
15
|
+
return pascalCase$1(input.filter(Boolean).join(" "));
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const buildSliceLibraryIndexFileContents = async (args) => {
|
|
19
|
+
const filePath = args.helpers.joinPathFromRoot(args.libraryID, args.options.typescript ? "index.ts" : "index.js");
|
|
20
|
+
const sliceLibrary = await args.actions.readSliceLibrary({
|
|
21
|
+
libraryID: args.libraryID
|
|
22
|
+
});
|
|
23
|
+
let contents = stripIndent`
|
|
24
|
+
import dynamic from 'next/dynamic'
|
|
25
|
+
|
|
26
|
+
export const components = {
|
|
27
|
+
${sliceLibrary.sliceIDs.map((id) => `${id}: dynamic(() => import('./${pascalCase(id)}')),`)}
|
|
28
|
+
}
|
|
29
|
+
`;
|
|
30
|
+
if (args.options.format) {
|
|
31
|
+
contents = await args.helpers.format(contents, filePath);
|
|
32
|
+
}
|
|
33
|
+
return { filePath, contents };
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const getJSOrTSXFileExtension = (pluginOptions) => {
|
|
37
|
+
if (pluginOptions.typescript) {
|
|
38
|
+
return "tsx";
|
|
39
|
+
} else if (pluginOptions.jsxExtension) {
|
|
40
|
+
return "jsx";
|
|
41
|
+
} else {
|
|
42
|
+
return "js";
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const createModelFile$1 = async ({ dir, data, helpers, options }) => {
|
|
47
|
+
const filePath = path.join(dir, "model.json");
|
|
48
|
+
let contents = JSON.stringify(data.model);
|
|
49
|
+
if (options.format) {
|
|
50
|
+
contents = await helpers.format(contents, filePath);
|
|
51
|
+
}
|
|
52
|
+
await fs.writeFile(filePath, contents);
|
|
53
|
+
};
|
|
54
|
+
const createComponentFile = async ({ dir, data, helpers, options }) => {
|
|
55
|
+
const filePath = path.join(dir, `index.${getJSOrTSXFileExtension(options)}`);
|
|
56
|
+
const model = data.model;
|
|
57
|
+
const pascalID = pascalCase(model.id);
|
|
58
|
+
let contents;
|
|
59
|
+
if (options.typescript) {
|
|
60
|
+
contents = stripIndent`
|
|
61
|
+
import { SliceComponentProps } from "@prismicio/react";
|
|
62
|
+
import { ${pascalID}Slice } from "./types";
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Props for \`${pascalID}\`.
|
|
66
|
+
*/
|
|
67
|
+
export type ${pascalID}Props = SliceComponentProps<${pascalID}Slice>;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Component for "${model.name}" Slices.
|
|
71
|
+
*/
|
|
72
|
+
const ${pascalID} = ({ slice }: ${pascalID}Props): React.Element => {
|
|
73
|
+
return (
|
|
74
|
+
<section
|
|
75
|
+
data-slice-type={slice.slice_type}
|
|
76
|
+
data-slice-variation={slice.variation}
|
|
77
|
+
>
|
|
78
|
+
Placeholder component for ${model.id} (variation: {slice.variation}) Slices
|
|
79
|
+
</section>
|
|
80
|
+
);
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
export default ${pascalID}
|
|
84
|
+
`;
|
|
85
|
+
} else {
|
|
86
|
+
contents = stripIndent`
|
|
87
|
+
/**
|
|
88
|
+
* @typedef {import("./types").${pascalID}Slice} ${pascalID}Slice
|
|
89
|
+
* @typedef {import("@prismicio/react").SliceComponentProps<${pascalID}Slice>} ${pascalID}Props
|
|
90
|
+
* @param {${pascalID}Props}
|
|
91
|
+
*/
|
|
92
|
+
const ${pascalID} = ({ slice }) => {
|
|
93
|
+
return (
|
|
94
|
+
<section
|
|
95
|
+
data-slice-type={slice.slice_type}
|
|
96
|
+
data-slice-variation={slice.variation}
|
|
97
|
+
>
|
|
98
|
+
Placeholder component for ${model.id} (variation: {slice.variation}) Slices
|
|
99
|
+
</section>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export default ${pascalID};
|
|
104
|
+
`;
|
|
105
|
+
}
|
|
106
|
+
if (options.format) {
|
|
107
|
+
contents = await helpers.format(contents, filePath);
|
|
108
|
+
}
|
|
109
|
+
await fs.writeFile(filePath, contents);
|
|
110
|
+
};
|
|
111
|
+
const createTypesFile$1 = async ({ dir, data, helpers, options }) => {
|
|
112
|
+
const filePath = path.join(dir, "types.ts");
|
|
113
|
+
let contents = generateTypes({
|
|
114
|
+
sharedSliceModels: [data.model]
|
|
115
|
+
});
|
|
116
|
+
if (options.format) {
|
|
117
|
+
contents = await helpers.format(contents, filePath);
|
|
118
|
+
}
|
|
119
|
+
await fs.writeFile(filePath, contents);
|
|
120
|
+
};
|
|
121
|
+
const upsertSliceLibraryIndexFile = async ({
|
|
122
|
+
data,
|
|
123
|
+
actions,
|
|
124
|
+
helpers,
|
|
125
|
+
project,
|
|
126
|
+
options
|
|
127
|
+
}) => {
|
|
128
|
+
const { filePath, contents } = await buildSliceLibraryIndexFileContents({
|
|
129
|
+
libraryID: data.libraryID,
|
|
130
|
+
actions,
|
|
131
|
+
helpers,
|
|
132
|
+
project,
|
|
133
|
+
options
|
|
134
|
+
});
|
|
135
|
+
await fs.writeFile(filePath, contents);
|
|
136
|
+
};
|
|
137
|
+
const sliceCreate = async (data, context) => {
|
|
138
|
+
const dir = context.helpers.joinPathFromRoot(data.libraryID, pascalCase(data.model.id));
|
|
139
|
+
await fs.mkdir(dir, { recursive: true });
|
|
140
|
+
await Promise.allSettled([
|
|
141
|
+
createModelFile$1({ dir, data, ...context }),
|
|
142
|
+
createComponentFile({ dir, data, ...context }),
|
|
143
|
+
createTypesFile$1({ dir, data, ...context })
|
|
144
|
+
]);
|
|
145
|
+
await upsertSliceLibraryIndexFile({ data, ...context });
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
const updateModelFile = async ({ dir, data, helpers, options }) => {
|
|
149
|
+
const filePath = path.join(dir, "model.json");
|
|
150
|
+
let contents = JSON.stringify(data.model);
|
|
151
|
+
if (options.format) {
|
|
152
|
+
contents = await helpers.format(contents, filePath);
|
|
153
|
+
}
|
|
154
|
+
await fs.writeFile(filePath, contents);
|
|
155
|
+
};
|
|
156
|
+
const updateTypesFile = async ({ dir, data, helpers, options }) => {
|
|
157
|
+
const filePath = path.join(dir, "types.ts");
|
|
158
|
+
let contents = generateTypes({
|
|
159
|
+
sharedSliceModels: [data.model]
|
|
160
|
+
});
|
|
161
|
+
if (options.format) {
|
|
162
|
+
contents = await helpers.format(contents, filePath);
|
|
163
|
+
}
|
|
164
|
+
await fs.writeFile(filePath, contents);
|
|
165
|
+
};
|
|
166
|
+
const sliceUpdate = async (data, context) => {
|
|
167
|
+
const dir = context.helpers.joinPathFromRoot(data.libraryID, pascalCase(data.model.id));
|
|
168
|
+
await Promise.allSettled([
|
|
169
|
+
updateModelFile({ dir, data, ...context }),
|
|
170
|
+
updateTypesFile({ dir, data, ...context })
|
|
171
|
+
]);
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const deleteSliceDir = async ({ data, helpers }) => {
|
|
175
|
+
const dir = helpers.joinPathFromRoot(data.libraryID, pascalCase(data.model.id));
|
|
176
|
+
await fs.rm(dir, { recursive: true });
|
|
177
|
+
};
|
|
178
|
+
const updateSliceLibraryIndexFile = async ({
|
|
179
|
+
data,
|
|
180
|
+
actions,
|
|
181
|
+
helpers,
|
|
182
|
+
project,
|
|
183
|
+
options
|
|
184
|
+
}) => {
|
|
185
|
+
const { filePath, contents } = await buildSliceLibraryIndexFileContents({
|
|
186
|
+
libraryID: data.libraryID,
|
|
187
|
+
actions,
|
|
188
|
+
helpers,
|
|
189
|
+
project,
|
|
190
|
+
options
|
|
191
|
+
});
|
|
192
|
+
await fs.writeFile(filePath, contents);
|
|
193
|
+
};
|
|
194
|
+
const sliceDelete = async (data, context) => {
|
|
195
|
+
await deleteSliceDir({ data, ...context });
|
|
196
|
+
await updateSliceLibraryIndexFile({ data, ...context });
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const readJSONFile = async (path) => {
|
|
200
|
+
const contents = await fs.readFile(path, "utf8");
|
|
201
|
+
return JSON.parse(contents);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const sliceRead = async (data, { helpers }) => {
|
|
205
|
+
const filePath = helpers.joinPathFromRoot(data.libraryID, pascalCase(data.sliceID), "model.json");
|
|
206
|
+
return await readJSONFile(filePath);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const CustomTypeModelFieldType = {
|
|
210
|
+
Boolean: "Boolean",
|
|
211
|
+
Color: "Color",
|
|
212
|
+
Date: "Date",
|
|
213
|
+
Embed: "Embed",
|
|
214
|
+
GeoPoint: "GeoPoint",
|
|
215
|
+
Group: "Group",
|
|
216
|
+
Image: "Image",
|
|
217
|
+
IntegrationFields: "IntegrationFields",
|
|
218
|
+
Link: "Link",
|
|
219
|
+
Number: "Number",
|
|
220
|
+
Select: "Select",
|
|
221
|
+
Slices: "Slices",
|
|
222
|
+
StructuredText: "StructuredText",
|
|
223
|
+
Text: "Text",
|
|
224
|
+
Timestamp: "Timestamp",
|
|
225
|
+
UID: "UID",
|
|
226
|
+
Range: "Range",
|
|
227
|
+
Separator: "Separator",
|
|
228
|
+
LegacySlices: "Choice"
|
|
229
|
+
};
|
|
230
|
+
const CustomTypeModelSliceType = {
|
|
231
|
+
Slice: "Slice",
|
|
232
|
+
SharedSlice: "SharedSlice"
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
const isSharedSliceModel = (input) => {
|
|
236
|
+
return typeof input === "object" && input !== null && "type" in input && input.type === CustomTypeModelSliceType.SharedSlice;
|
|
237
|
+
};
|
|
238
|
+
const sliceLibraryRead = async (data, { helpers }) => {
|
|
239
|
+
const dirPath = helpers.joinPathFromRoot(data.libraryID);
|
|
240
|
+
const childDirs = await fs.readdir(dirPath);
|
|
241
|
+
const sliceIDs = [];
|
|
242
|
+
await Promise.all(childDirs.map(async (childDir) => {
|
|
243
|
+
const modelPath = path.join(dirPath, childDir, "model.json");
|
|
244
|
+
try {
|
|
245
|
+
const modelContents = await readJSONFile(modelPath);
|
|
246
|
+
if (isSharedSliceModel(modelContents)) {
|
|
247
|
+
sliceIDs.push(modelContents.id);
|
|
248
|
+
}
|
|
249
|
+
} catch (e) {
|
|
250
|
+
}
|
|
251
|
+
}));
|
|
252
|
+
return {
|
|
253
|
+
id: data.libraryID,
|
|
254
|
+
sliceIDs: sliceIDs.sort()
|
|
255
|
+
};
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const createModelFile = async ({ dir, data, helpers, options }) => {
|
|
259
|
+
const filePath = path.join(dir, "index.json");
|
|
260
|
+
let contents = JSON.stringify(data.model);
|
|
261
|
+
if (options.format) {
|
|
262
|
+
contents = await helpers.format(contents, filePath);
|
|
263
|
+
}
|
|
264
|
+
await fs.writeFile(filePath, contents);
|
|
265
|
+
};
|
|
266
|
+
const createTypesFile = async ({ dir, data, helpers, options }) => {
|
|
267
|
+
const filePath = path.join(dir, "types.ts");
|
|
268
|
+
let contents = generateTypes({
|
|
269
|
+
customTypeModels: [data.model]
|
|
270
|
+
});
|
|
271
|
+
if (options.format) {
|
|
272
|
+
contents = await helpers.format(contents, filePath);
|
|
273
|
+
}
|
|
274
|
+
await fs.writeFile(filePath, contents);
|
|
275
|
+
};
|
|
276
|
+
const customTypeCreate = async (data, context) => {
|
|
277
|
+
const dir = context.helpers.joinPathFromRoot("customtypes", data.model.id);
|
|
278
|
+
await fs.mkdir(dir, { recursive: true });
|
|
279
|
+
await Promise.allSettled([
|
|
280
|
+
createModelFile({ dir, data, ...context }),
|
|
281
|
+
createTypesFile({ dir, data, ...context })
|
|
282
|
+
]);
|
|
283
|
+
};
|
|
284
|
+
|
|
285
|
+
const customTypeUpdate = customTypeCreate;
|
|
286
|
+
|
|
287
|
+
const customTypeDelete = async (data, { helpers }) => {
|
|
288
|
+
const dir = helpers.joinPathFromRoot("customtypes", data.model.id);
|
|
289
|
+
await fs.rm(dir, { recursive: true });
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const customTypeRead = async (data, { helpers }) => {
|
|
293
|
+
const filePath = helpers.joinPathFromRoot("customtypes", data.id, "index.json");
|
|
294
|
+
return await readJSONFile(filePath);
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
const isCustomTypeModel = (input) => {
|
|
298
|
+
return typeof input === "object" && input !== null && "json" in input;
|
|
299
|
+
};
|
|
300
|
+
const customTypeLibraryRead = async (_data, { helpers }) => {
|
|
301
|
+
const dirPath = helpers.joinPathFromRoot("customtypes");
|
|
302
|
+
const childDirs = await fs.readdir(dirPath);
|
|
303
|
+
const ids = [];
|
|
304
|
+
await Promise.all(childDirs.map(async (childDir) => {
|
|
305
|
+
const modelPath = path.join(dirPath, childDir, "index.json");
|
|
306
|
+
const modelContents = await readJSONFile(modelPath);
|
|
307
|
+
if (isCustomTypeModel(modelContents)) {
|
|
308
|
+
ids.push(modelContents.id);
|
|
309
|
+
}
|
|
310
|
+
}));
|
|
311
|
+
return {
|
|
312
|
+
ids: ids.sort()
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const prettierOptions = { parser: "typescript" };
|
|
317
|
+
const dotPath = (segments) => {
|
|
318
|
+
return segments.join(".");
|
|
319
|
+
};
|
|
320
|
+
const snippetRead = async (data, { helpers }) => {
|
|
321
|
+
const { fieldPath } = data;
|
|
322
|
+
const label = "React";
|
|
323
|
+
switch (data.model.type) {
|
|
324
|
+
case CustomTypeModelFieldType.Link: {
|
|
325
|
+
return {
|
|
326
|
+
label,
|
|
327
|
+
language: "tsx",
|
|
328
|
+
code: await helpers.format(stripIndent`
|
|
329
|
+
<PrismicLink field={${dotPath(fieldPath)}}>Link</PrismicLink>
|
|
330
|
+
`, void 0, { prettier: prettierOptions })
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
case CustomTypeModelFieldType.Image: {
|
|
334
|
+
return [
|
|
335
|
+
{
|
|
336
|
+
label: `${label} (next/image)`,
|
|
337
|
+
language: "tsx",
|
|
338
|
+
code: await helpers.format(stripIndent`
|
|
339
|
+
<PrismicNextImage field={${dotPath(fieldPath)}} />
|
|
340
|
+
`, void 0, { prettier: prettierOptions })
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
label,
|
|
344
|
+
language: "tsx",
|
|
345
|
+
code: await helpers.format(stripIndent`
|
|
346
|
+
<PrismicImage field={${dotPath(fieldPath)}} />
|
|
347
|
+
`, void 0, { prettier: prettierOptions })
|
|
348
|
+
}
|
|
349
|
+
];
|
|
350
|
+
}
|
|
351
|
+
case CustomTypeModelFieldType.Group: {
|
|
352
|
+
const code = await helpers.format(stripIndent`
|
|
353
|
+
<>{${dotPath(fieldPath)}.map(item => (
|
|
354
|
+
<>{/* Render content for item */}</>
|
|
355
|
+
))}</>
|
|
356
|
+
`, void 0, { prettier: prettierOptions });
|
|
357
|
+
return {
|
|
358
|
+
label,
|
|
359
|
+
language: "tsx",
|
|
360
|
+
code
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
case CustomTypeModelFieldType.Slices: {
|
|
364
|
+
const code = await helpers.format(stripIndent`
|
|
365
|
+
<SliceZone
|
|
366
|
+
slices={${dotPath(fieldPath)}}
|
|
367
|
+
components={components}
|
|
368
|
+
/>
|
|
369
|
+
`, void 0, { prettier: prettierOptions });
|
|
370
|
+
return {
|
|
371
|
+
label,
|
|
372
|
+
language: "tsx",
|
|
373
|
+
code
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
default: {
|
|
377
|
+
return {
|
|
378
|
+
label,
|
|
379
|
+
language: "tsx",
|
|
380
|
+
code: await helpers.format(stripIndent`
|
|
381
|
+
<>{${dotPath(fieldPath)}}</>
|
|
382
|
+
`, void 0, { prettier: prettierOptions })
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
const REQUIRED_DEPENDENCIES = [
|
|
389
|
+
"@prismicio/react",
|
|
390
|
+
"@prismicio/slice-simulator-react",
|
|
391
|
+
"@prismicio/client@latest",
|
|
392
|
+
"@prismicio/helpers"
|
|
393
|
+
];
|
|
394
|
+
const createStep1 = async ({
|
|
395
|
+
project
|
|
396
|
+
}) => {
|
|
397
|
+
const require = createRequire(project.root);
|
|
398
|
+
return {
|
|
399
|
+
title: "Install packages",
|
|
400
|
+
body: stripIndent`
|
|
401
|
+
The simulator requires extra dependencies. Run the following command to install them.
|
|
402
|
+
|
|
403
|
+
~~~sh
|
|
404
|
+
npm install --save @prismicio/react @prismicio/slice-simulator-react @prismicio/client@latest @prismicio/helpers
|
|
405
|
+
~~~
|
|
406
|
+
`,
|
|
407
|
+
validate: async () => {
|
|
408
|
+
const missingDependencies = [];
|
|
409
|
+
for (const dependency of REQUIRED_DEPENDENCIES) {
|
|
410
|
+
try {
|
|
411
|
+
require.resolve(dependency);
|
|
412
|
+
} catch (e) {
|
|
413
|
+
missingDependencies.push(dependency);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
if (missingDependencies.length >= REQUIRED_DEPENDENCIES.length) {
|
|
417
|
+
return {
|
|
418
|
+
type: SliceSimulatorSetupStepValidationMessageType.Error,
|
|
419
|
+
title: "Missing all dependencies",
|
|
420
|
+
message: stripIndent`
|
|
421
|
+
Install the required dependencies to continue.
|
|
422
|
+
`
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
if (missingDependencies.length > 0) {
|
|
426
|
+
const formattedMissingDependencies = missingDependencies.map((missingDependency) => `\`${missingDependency}\``).join(", ");
|
|
427
|
+
return {
|
|
428
|
+
type: SliceSimulatorSetupStepValidationMessageType.Warning,
|
|
429
|
+
title: "Missing some dependencies",
|
|
430
|
+
message: stripIndent`
|
|
431
|
+
The following dependencies are missing: ${formattedMissingDependencies}
|
|
432
|
+
`
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
};
|
|
437
|
+
};
|
|
438
|
+
const createStep2 = async ({
|
|
439
|
+
helpers,
|
|
440
|
+
options
|
|
441
|
+
}) => {
|
|
442
|
+
const fileName = `slice-simulator.${getJSOrTSXFileExtension}`;
|
|
443
|
+
const filePath = helpers.joinPathFromRoot("pages", fileName);
|
|
444
|
+
let fileContents;
|
|
445
|
+
if (options.typescript) {
|
|
446
|
+
fileContents = stripIndent`
|
|
447
|
+
import { GetStaticProps } from "next/types";
|
|
448
|
+
import { SliceSimulator } from "@prismicio/slice-simulator-react";
|
|
449
|
+
import { SliceZone } from "@prismicio/react";
|
|
450
|
+
|
|
451
|
+
import state from "../.slicemachine/libraries-state.json";
|
|
452
|
+
import { components } from "../slices";
|
|
453
|
+
|
|
454
|
+
const SliceSimulatorPage = () => {
|
|
455
|
+
return (
|
|
456
|
+
<SliceSimulator
|
|
457
|
+
sliceZone={(props) => <SliceZone {...props} components={components} />}
|
|
458
|
+
state={state}
|
|
459
|
+
/>
|
|
460
|
+
);
|
|
461
|
+
};
|
|
462
|
+
|
|
463
|
+
export default SliceSimulatorPage;
|
|
464
|
+
|
|
465
|
+
export const getStaticProps: GetStaticProps = () => {
|
|
466
|
+
return {
|
|
467
|
+
// Exclude this page from production builds.
|
|
468
|
+
notFound: process.env.NODE_ENV === "production",
|
|
469
|
+
};
|
|
470
|
+
};
|
|
471
|
+
`;
|
|
472
|
+
} else {
|
|
473
|
+
fileContents = stripIndent`
|
|
474
|
+
import { SliceSimulator } from "@prismicio/slice-simulator-react";
|
|
475
|
+
import { SliceZone } from "@prismicio/react";
|
|
476
|
+
|
|
477
|
+
import state from "../.slicemachine/libraries-state.json";
|
|
478
|
+
import { components } from "../slices";
|
|
479
|
+
|
|
480
|
+
const SliceSimulatorPage = () => {
|
|
481
|
+
return (
|
|
482
|
+
<SliceSimulator
|
|
483
|
+
sliceZone={(props) => <SliceZone {...props} components={components} />}
|
|
484
|
+
state={state}
|
|
485
|
+
/>
|
|
486
|
+
);
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
export default SliceSimulatorPage;
|
|
490
|
+
|
|
491
|
+
export const getStaticProps= () => {
|
|
492
|
+
return {
|
|
493
|
+
// Exclude this page from production builds.
|
|
494
|
+
notFound: process.env.NODE_ENV === "production",
|
|
495
|
+
};
|
|
496
|
+
};
|
|
497
|
+
`;
|
|
498
|
+
}
|
|
499
|
+
fileContents = await helpers.format(fileContents, filePath);
|
|
500
|
+
return {
|
|
501
|
+
title: "Create a page for the simulator",
|
|
502
|
+
body: stripIndent`
|
|
503
|
+
In your \`pages\` directory, create a file called \`${fileName}\` and add the following code. This route will be used to simulate and develop your components.
|
|
504
|
+
|
|
505
|
+
~~~tsx
|
|
506
|
+
${fileContents}
|
|
507
|
+
~~~
|
|
508
|
+
`
|
|
509
|
+
};
|
|
510
|
+
};
|
|
511
|
+
const createStep3 = async ({
|
|
512
|
+
helpers
|
|
513
|
+
}) => {
|
|
514
|
+
const filePath = helpers.joinPathFromRoot("sm.json");
|
|
515
|
+
const fileContents = await helpers.format(`
|
|
516
|
+
{
|
|
517
|
+
"localSliceSimulatorURL": "http://localhost:3000/slice-simulator"
|
|
518
|
+
}
|
|
519
|
+
`, filePath);
|
|
520
|
+
return {
|
|
521
|
+
title: "Update `sm.json`",
|
|
522
|
+
body: stripIndent`
|
|
523
|
+
Update your \`sm.json\` file with a \`localSliceSimulatorURL\` property pointing to your \`slice-simulator\` page.
|
|
524
|
+
|
|
525
|
+
~~~json
|
|
526
|
+
${fileContents}
|
|
527
|
+
~~~
|
|
528
|
+
`,
|
|
529
|
+
validate: async () => {
|
|
530
|
+
const project = await helpers.getProject();
|
|
531
|
+
if (!("localSliceSimulatorURL" in project.config)) {
|
|
532
|
+
return {
|
|
533
|
+
type: SliceSimulatorSetupStepValidationMessageType.Error,
|
|
534
|
+
title: "Missing `localSliceSimulatorURL` property",
|
|
535
|
+
message: stripIndent`
|
|
536
|
+
A \`localSliceSimulatorURL\` property was not found in your \`sm.json\` file.
|
|
537
|
+
`
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
try {
|
|
541
|
+
if (project.config.localSliceSimulatorURL) {
|
|
542
|
+
new URL(project.config.localSliceSimulatorURL);
|
|
543
|
+
} else {
|
|
544
|
+
throw new Error("Undefined Slice Simulator URL");
|
|
545
|
+
}
|
|
546
|
+
} catch (e) {
|
|
547
|
+
return {
|
|
548
|
+
type: SliceSimulatorSetupStepValidationMessageType.Warning,
|
|
549
|
+
title: "An invalid URL was provided",
|
|
550
|
+
message: stripIndent`
|
|
551
|
+
The \`localSliceSimulatorURL\` property should be of the shape \`http://localhost:PORT/PATH\`. See the codeblock for an example.
|
|
552
|
+
`
|
|
553
|
+
};
|
|
554
|
+
}
|
|
555
|
+
const ok = await new Promise((resolve) => {
|
|
556
|
+
if (project.config.localSliceSimulatorURL) {
|
|
557
|
+
http.get(project.config.localSliceSimulatorURL, (res) => {
|
|
558
|
+
if (res.statusCode) {
|
|
559
|
+
resolve(res.statusCode >= 200 && res.statusCode < 300);
|
|
560
|
+
}
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
resolve(false);
|
|
564
|
+
});
|
|
565
|
+
if (!ok) {
|
|
566
|
+
return {
|
|
567
|
+
type: SliceSimulatorSetupStepValidationMessageType.Warning,
|
|
568
|
+
title: "Unable to connect to simulator page",
|
|
569
|
+
message: stripIndent`
|
|
570
|
+
Check that the \`localSliceSimulatorURL\` property in \`sm.json\` is correct and try again. See the [troubleshooting page](https://prismic.io/docs/technologies/setup-slice-simulator-nextjs) for more details.
|
|
571
|
+
`
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
};
|
|
576
|
+
};
|
|
577
|
+
const sliceSimulatorSetupRead = async (_data, context) => {
|
|
578
|
+
return Promise.all([
|
|
579
|
+
createStep1(context),
|
|
580
|
+
createStep2(context),
|
|
581
|
+
createStep3(context)
|
|
582
|
+
]);
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
const plugin = defineSliceMachinePlugin({
|
|
586
|
+
meta: {
|
|
587
|
+
name: name
|
|
588
|
+
},
|
|
589
|
+
defaultOptions: {
|
|
590
|
+
format: true
|
|
591
|
+
},
|
|
592
|
+
setup({ hook }) {
|
|
593
|
+
hook("slice:create", sliceCreate);
|
|
594
|
+
hook("slice:update", sliceUpdate);
|
|
595
|
+
hook("slice:delete", sliceDelete);
|
|
596
|
+
hook("slice:read", sliceRead);
|
|
597
|
+
hook("slice-library:read", sliceLibraryRead);
|
|
598
|
+
hook("custom-type:create", customTypeCreate);
|
|
599
|
+
hook("custom-type:update", customTypeUpdate);
|
|
600
|
+
hook("custom-type:delete", customTypeDelete);
|
|
601
|
+
hook("custom-type:read", customTypeRead);
|
|
602
|
+
hook("custom-type-library:read", customTypeLibraryRead);
|
|
603
|
+
hook("snippet:read", snippetRead);
|
|
604
|
+
hook("slice-simulator:setup:read", sliceSimulatorSetupRead);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
const coreManager = new CoreManager();
|
|
609
|
+
const SliceSimulator = ({
|
|
610
|
+
sliceZone: SliceZoneComp,
|
|
611
|
+
state,
|
|
612
|
+
background,
|
|
613
|
+
zIndex,
|
|
614
|
+
className
|
|
615
|
+
}) => {
|
|
616
|
+
const defaultProps = getDefaultProps();
|
|
617
|
+
const [managedState, setManagedState] = React.useState(() => getDefaultManagedState());
|
|
618
|
+
const [slices, setSlices] = React.useState(() => getDefaultSlices());
|
|
619
|
+
const [message, setMessage] = React.useState(() => getDefaultMessage());
|
|
620
|
+
React.useEffect(() => {
|
|
621
|
+
coreManager.stateManager.on(StateManagerEventType.ManagedState, (_managedState) => {
|
|
622
|
+
setManagedState(_managedState);
|
|
623
|
+
}, "simulator-managed-state");
|
|
624
|
+
coreManager.stateManager.on(StateManagerEventType.Slices, (_slices) => {
|
|
625
|
+
setSlices(_slices);
|
|
626
|
+
}, "simulator-slices");
|
|
627
|
+
coreManager.stateManager.on(StateManagerEventType.Message, (_message) => {
|
|
628
|
+
setMessage(_message);
|
|
629
|
+
}, "simulator-message");
|
|
630
|
+
coreManager.init(state);
|
|
631
|
+
return () => {
|
|
632
|
+
coreManager.stateManager.off(StateManagerEventType.ManagedState, "simulator-managed-state");
|
|
633
|
+
coreManager.stateManager.off(StateManagerEventType.Slices, "simulator-slices");
|
|
634
|
+
coreManager.stateManager.off(StateManagerEventType.Message, "simulator-message");
|
|
635
|
+
};
|
|
636
|
+
}, []);
|
|
637
|
+
const didMount = React.useRef(false);
|
|
638
|
+
React.useEffect(() => {
|
|
639
|
+
if (didMount.current) {
|
|
640
|
+
coreManager.stateManager.reload(state);
|
|
641
|
+
} else {
|
|
642
|
+
didMount.current = true;
|
|
643
|
+
}
|
|
644
|
+
}, [state]);
|
|
645
|
+
return /* @__PURE__ */ React.createElement("div", {
|
|
646
|
+
className: [simulatorClass, className].filter(Boolean).join(" "),
|
|
647
|
+
style: {
|
|
648
|
+
zIndex: typeof zIndex === "undefined" ? defaultProps.zIndex : zIndex != null ? zIndex : void 0,
|
|
649
|
+
position: "fixed",
|
|
650
|
+
top: 0,
|
|
651
|
+
left: 0,
|
|
652
|
+
width: "100%",
|
|
653
|
+
height: "100vh",
|
|
654
|
+
overflow: "auto",
|
|
655
|
+
background: typeof background === "undefined" ? defaultProps.background : background != null ? background : void 0
|
|
656
|
+
}
|
|
657
|
+
}, message ? /* @__PURE__ */ React.createElement("article", {
|
|
658
|
+
dangerouslySetInnerHTML: { __html: message }
|
|
659
|
+
}) : slices.length ? /* @__PURE__ */ React.createElement("div", {
|
|
660
|
+
id: "root",
|
|
661
|
+
className: simulatorRootClass,
|
|
662
|
+
style: managedState.status !== StateManagerStatus.Loaded ? { display: "none" } : void 0,
|
|
663
|
+
onClickCapture: onClickHandler,
|
|
664
|
+
onSubmitCapture: disableEventHandler
|
|
665
|
+
}, /* @__PURE__ */ React.createElement(SliceZoneComp, {
|
|
666
|
+
slices
|
|
667
|
+
})) : null);
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
export { SliceSimulator, plugin as default };
|
|
671
|
+
//# sourceMappingURL=index.js.map
|