slice-machine-ui 1.22.2-alpha.xru-auto-save-slice-builder.2 → 1.22.2-alpha.xru-auto-save-type-builder.7

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.
Files changed (98) hide show
  1. package/components/DeleteVariationModal/index.tsx +11 -12
  2. package/components/Forms/RenameVariationModal/RenameVariationModal.tsx +11 -12
  3. package/components/ScreenshotChangesModal/VariationDropZone.tsx +9 -31
  4. package/components/ScreenshotChangesModal/index.tsx +0 -3
  5. package/components/ScreenshotChangesModal/useCustomScreenshot.tsx +5 -5
  6. package/components/Simulator/index.tsx +3 -9
  7. package/lib/builders/SliceBuilder/FieldZones/index.tsx +55 -80
  8. package/lib/builders/SliceBuilder/Sidebar/AddVariationModal.tsx +16 -24
  9. package/lib/builders/SliceBuilder/Sidebar/index.tsx +40 -38
  10. package/lib/builders/SliceBuilder/SimulatorButton/index.tsx +26 -3
  11. package/lib/builders/SliceBuilder/index.tsx +96 -10
  12. package/lib/builders/common/Zone/index.jsx +1 -1
  13. package/lib/models/common/Variation.ts +100 -0
  14. package/out/404.html +1 -1
  15. package/out/_next/static/chunks/418-e2ea0df42b95b92d.js +1 -0
  16. package/out/_next/static/chunks/482-9277ff10845fed91.js +1 -0
  17. package/out/_next/static/chunks/538-07f826266d011e85.js +1 -0
  18. package/out/_next/static/chunks/{799-60150dd63657f0cc.js → 799-378edb0fdc3a3a5a.js} +1 -1
  19. package/out/_next/static/chunks/80-7b8a97d0122ff74a.js +1 -0
  20. package/out/_next/static/chunks/858-0b07239d5a20b65c.js +28 -0
  21. package/out/_next/static/chunks/{918-5bb55fb464e34768.js → 918-38d08f1e885b222d.js} +1 -1
  22. package/out/_next/static/chunks/958-247df4bdf5efcb92.js +1 -0
  23. package/out/_next/static/chunks/pages/{_app-10b1f0f39518496e.js → _app-6584070fa9ed8af3.js} +69 -66
  24. package/out/_next/static/chunks/pages/{changelog-68d115a14f1423d7.js → changelog-f8e0869f0551f420.js} +1 -1
  25. package/out/_next/static/chunks/pages/changes-47fe6af1355195e4.js +1 -0
  26. package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-956a2fc70fe78405.js → [customTypeId]-a8658e547a11045d.js} +1 -1
  27. package/out/_next/static/chunks/pages/{custom-types-f87f9caaa5f7d369.js → custom-types-309e8a31d3eb6e3a.js} +1 -1
  28. package/out/_next/static/chunks/pages/{index-8dd208ca96259817.js → index-75046c128aa61430.js} +1 -1
  29. package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-686d4929e736f14a.js → [pageTypeId]-a03d9eea082a69b0.js} +1 -1
  30. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/{simulator-897ca93c114a1435.js → simulator-55d09564cc4f522a.js} +1 -1
  31. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-e084a43056f481f0.js +1 -0
  32. package/out/_next/static/chunks/pages/slices-b1494d473dcb76ee.js +1 -0
  33. package/out/_next/static/km0kuIQfnqh21eAANDKkL/_buildManifest.js +1 -0
  34. package/out/changelog.html +1 -1
  35. package/out/changes.html +1 -1
  36. package/out/custom-types/[customTypeId].html +1 -1
  37. package/out/custom-types.html +1 -1
  38. package/out/index.html +1 -1
  39. package/out/labs.html +1 -1
  40. package/out/page-types/[pageTypeId].html +1 -1
  41. package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  42. package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
  43. package/out/slices.html +1 -1
  44. package/package.json +3 -3
  45. package/pages/slices/[lib]/[sliceName]/[variation]/index.tsx +11 -25
  46. package/pages/slices/[lib]/[sliceName]/[variation]/simulator.tsx +9 -12
  47. package/src/domain/slice.ts +1 -166
  48. package/src/features/autoSave/{AutoSaveStatus.tsx → AutoSaveStatusIndicator.tsx} +8 -6
  49. package/src/features/autoSave/useAutoSave.tsx +132 -77
  50. package/src/features/customTypes/customTypesBuilder/CustomTypeProvider.tsx +20 -17
  51. package/src/features/customTypes/customTypesBuilder/CustomTypesBuilderPage.tsx +3 -3
  52. package/src/features/slices/convertLegacySlice/ConvertLegacySliceAsNewVariationDialog.tsx +5 -5
  53. package/src/features/slices/sliceBuilder/actions/deleteVariation.ts +21 -10
  54. package/src/features/slices/sliceBuilder/actions/renameVariation.ts +22 -10
  55. package/src/hooks/useCurrentSlice.tsx +16 -4
  56. package/src/hooks/useScreenshotChangesModal.ts +0 -1
  57. package/src/hooks/useServerState.ts +27 -1
  58. package/src/layouts/WithSlice.tsx +26 -0
  59. package/src/modules/screenshots/actions.ts +21 -0
  60. package/src/modules/screenshots/sagas.ts +70 -0
  61. package/src/modules/selectedSlice/actions.ts +106 -0
  62. package/src/modules/selectedSlice/reducer.ts +175 -0
  63. package/src/modules/selectedSlice/sagas.ts +72 -0
  64. package/src/modules/selectedSlice/selectors.ts +55 -0
  65. package/src/modules/selectedSlice/types.ts +3 -0
  66. package/src/modules/simulator/index.ts +2 -0
  67. package/src/modules/slices/index.ts +25 -32
  68. package/src/modules/toaster/utils.tsx +23 -0
  69. package/src/modules/useSliceMachineActions.ts +152 -18
  70. package/src/redux/reducer.ts +2 -0
  71. package/src/redux/saga.ts +4 -0
  72. package/src/redux/type.ts +2 -0
  73. package/test/src/modules/selectedSlice/__fixtures__/mocks.json +171 -0
  74. package/test/src/modules/selectedSlice/__fixtures__/model.json +35 -0
  75. package/test/src/modules/selectedSlice/__testutils__/getRefreshStateCreatorPayloadData.ts +72 -0
  76. package/test/src/modules/selectedSlice/__testutils__/getSelectedSliceDummyData.ts +30 -0
  77. package/test/src/modules/selectedSlice/reducer.test.ts +170 -0
  78. package/test/src/modules/selectedSlice/sagas.test.ts +82 -0
  79. package/test/src/modules/simulator.test.ts +2 -0
  80. package/test/src/modules/toaster/utils.test.ts +50 -0
  81. package/out/_next/static/BZjIFXXV7vJrc1uzD_Ies/_buildManifest.js +0 -1
  82. package/out/_next/static/chunks/423-6b74bf3de145fb7c.js +0 -1
  83. package/out/_next/static/chunks/50-cfc2514205b86001.js +0 -1
  84. package/out/_next/static/chunks/543-f8766685f7f451e2.js +0 -1
  85. package/out/_next/static/chunks/584-11ee6995b5faaab8.js +0 -1
  86. package/out/_next/static/chunks/59b4e022-7a3b5554b806349f.js +0 -1
  87. package/out/_next/static/chunks/696-b12edad30a3617e5.js +0 -31
  88. package/out/_next/static/chunks/749-b2f6153434701ad6.js +0 -1
  89. package/out/_next/static/chunks/787-727e3aef5d2a10a8.js +0 -1
  90. package/out/_next/static/chunks/904-30051a26c74a94d6.js +0 -1
  91. package/out/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js +0 -1
  92. package/out/_next/static/chunks/pages/changes-d6dc4c8074a1d8ca.js +0 -1
  93. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-f89c7178fd60120b.js +0 -1
  94. package/out/_next/static/chunks/pages/slices-153cda50ad258428.js +0 -1
  95. package/src/features/slices/actions/uploadSliceScreenshot.ts +0 -45
  96. package/src/features/slices/sliceBuilder/SliceBuilderProvider.tsx +0 -115
  97. package/src/modules/slices/selector.ts +0 -30
  98. /package/out/_next/static/{BZjIFXXV7vJrc1uzD_Ies → km0kuIQfnqh21eAANDKkL}/_ssgManifest.js +0 -0
@@ -7,19 +7,21 @@ import {
7
7
  Text,
8
8
  } from "@prismicio/editor-ui";
9
9
  import { useRouter } from "next/router";
10
- import { useState, type FC, type PropsWithChildren } from "react";
10
+ import type { Dispatch, FC, PropsWithChildren, SetStateAction } from "react";
11
11
 
12
+ import type { SliceBuilderState } from "@builders/SliceBuilder";
12
13
  import type { ComponentUI } from "@lib/models/common/ComponentUI";
13
14
  import type { VariationSM } from "@lib/models/common/Slice";
14
15
  import { deleteVariation } from "@src/features/slices/sliceBuilder/actions/deleteVariation";
15
16
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
16
- import { useSliceState } from "@src/features/slices/sliceBuilder/SliceBuilderProvider";
17
17
 
18
18
  type DeleteVariationModalProps = {
19
19
  isOpen: boolean;
20
20
  onClose: () => void;
21
21
  slice: ComponentUI;
22
22
  variation: VariationSM | undefined;
23
+ sliceBuilderState: SliceBuilderState;
24
+ setSliceBuilderState: Dispatch<SetStateAction<SliceBuilderState>>;
23
25
  };
24
26
 
25
27
  export const DeleteVariationModal: FC<DeleteVariationModalProps> = ({
@@ -27,12 +29,11 @@ export const DeleteVariationModal: FC<DeleteVariationModalProps> = ({
27
29
  onClose,
28
30
  slice,
29
31
  variation,
32
+ sliceBuilderState,
33
+ setSliceBuilderState,
30
34
  }) => {
31
35
  const router = useRouter();
32
- const [isDeleting, setIsDeleting] = useState(false);
33
- const { saveSliceSuccess } = useSliceMachineActions();
34
- const { setSlice } = useSliceState();
35
-
36
+ const { updateAndSaveSlice } = useSliceMachineActions();
36
37
  return (
37
38
  <Dialog
38
39
  open={isOpen}
@@ -55,21 +56,19 @@ export const DeleteVariationModal: FC<DeleteVariationModalProps> = ({
55
56
  onClick: () => {
56
57
  if (!variation) return;
57
58
  void (async () => {
58
- setIsDeleting(true);
59
59
  try {
60
- const newSlice = await deleteVariation({
60
+ await deleteVariation({
61
61
  component: slice,
62
62
  router,
63
- saveSliceSuccess,
63
+ setSliceBuilderState,
64
+ updateAndSaveSlice,
64
65
  variation,
65
66
  });
66
- setSlice(newSlice);
67
67
  } catch {}
68
- setIsDeleting(false);
69
68
  onClose();
70
69
  })();
71
70
  },
72
- loading: isDeleting,
71
+ loading: sliceBuilderState.loading,
73
72
  }}
74
73
  cancel={{ text: "Cancel" }}
75
74
  size="medium"
@@ -8,21 +8,23 @@ import {
8
8
  Text,
9
9
  } from "@prismicio/editor-ui";
10
10
  import { Formik } from "formik";
11
- import { useState, type FC } from "react";
11
+ import type { Dispatch, FC, SetStateAction } from "react";
12
12
 
13
+ import type { SliceBuilderState } from "@builders/SliceBuilder";
13
14
  import type { ComponentUI } from "@lib/models/common/ComponentUI";
14
15
  import type { VariationSM } from "@lib/models/common/Slice";
15
16
  import { renameVariation } from "@src/features/slices/sliceBuilder/actions/renameVariation";
16
17
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
17
18
 
18
19
  import * as styles from "./RenameVariationModal.css";
19
- import { useSliceState } from "@src/features/slices/sliceBuilder/SliceBuilderProvider";
20
20
 
21
21
  type RenameVariationModalProps = {
22
22
  isOpen: boolean;
23
23
  onClose: () => void;
24
24
  slice: ComponentUI;
25
25
  variation: VariationSM | undefined;
26
+ sliceBuilderState: SliceBuilderState;
27
+ setSliceBuilderState: Dispatch<SetStateAction<SliceBuilderState>>;
26
28
  };
27
29
 
28
30
  export const RenameVariationModal: FC<RenameVariationModalProps> = ({
@@ -30,11 +32,10 @@ export const RenameVariationModal: FC<RenameVariationModalProps> = ({
30
32
  onClose,
31
33
  slice,
32
34
  variation,
35
+ sliceBuilderState,
36
+ setSliceBuilderState,
33
37
  }) => {
34
- const [isRenaming, setRenaming] = useState(false);
35
- const { setSlice } = useSliceState();
36
- const { saveSliceSuccess } = useSliceMachineActions();
37
-
38
+ const { updateAndSaveSlice } = useSliceMachineActions();
38
39
  return (
39
40
  <>
40
41
  <Dialog
@@ -55,17 +56,15 @@ export const RenameVariationModal: FC<RenameVariationModalProps> = ({
55
56
  }}
56
57
  onSubmit={async (values) => {
57
58
  if (!variation) return;
58
- setRenaming(true);
59
59
  try {
60
- const newSlice = await renameVariation({
60
+ await renameVariation({
61
61
  component: slice,
62
- saveSliceSuccess,
62
+ setSliceBuilderState,
63
+ updateAndSaveSlice,
63
64
  variation,
64
65
  variationName: values.variationName.trim(),
65
66
  });
66
- setSlice(newSlice);
67
67
  } catch {}
68
- setRenaming(false);
69
68
  onClose();
70
69
  }}
71
70
  >
@@ -103,7 +102,7 @@ export const RenameVariationModal: FC<RenameVariationModalProps> = ({
103
102
  ok={{
104
103
  text: "Rename",
105
104
  onClick: () => void formik.submitForm(),
106
- loading: isRenaming,
105
+ loading: sliceBuilderState.loading,
107
106
  disabled: !formik.isValid,
108
107
  }}
109
108
  cancel={{ text: "Cancel" }}
@@ -14,13 +14,11 @@ import { isLoading } from "@src/modules/loading";
14
14
  import { LoadingKeysEnum } from "@src/modules/loading/types";
15
15
  import { ScreenshotPreview } from "@components/ScreenshotPreview";
16
16
  import { ComponentUI } from "@lib/models/common/ComponentUI";
17
- import { uploadSliceScreenshot } from "@src/features/slices/actions/uploadSliceScreenshot";
18
17
 
19
18
  interface DropZoneProps {
20
19
  imageTypes?: string[];
21
20
  variationID: string;
22
21
  slice: ComponentUI;
23
- onUploadSuccess?: (newSlice: ComponentUI) => void;
24
22
  }
25
23
 
26
24
  const DragActiveView = () => {
@@ -81,7 +79,6 @@ const DropZone: React.FC<DropZoneProps> = ({
81
79
  variationID,
82
80
  slice,
83
81
  imageTypes = acceptedImagesTypes,
84
- onUploadSuccess,
85
82
  }) => {
86
83
  const maybeScreenshot = slice.screenshots[variationID];
87
84
 
@@ -93,7 +90,7 @@ const DropZone: React.FC<DropZoneProps> = ({
93
90
  slice,
94
91
  ]);
95
92
 
96
- const { saveSliceCustomScreenshotSuccess } = useSliceMachineActions();
93
+ const { generateSliceCustomScreenshot } = useSliceMachineActions();
97
94
 
98
95
  const { isLoadingScreenshot } = useSelector(
99
96
  (state: SliceMachineStoreType) => ({
@@ -105,44 +102,25 @@ const DropZone: React.FC<DropZoneProps> = ({
105
102
  );
106
103
 
107
104
  const { FileInputRenderer, fileInputProps } = useCustomScreenshot({
108
- onHandleFile: async (file: File, isDragActive: boolean) => {
109
- const newSlice = await uploadSliceScreenshot({
105
+ onHandleFile: (file: File, isDragActive: boolean) => {
106
+ generateSliceCustomScreenshot(
107
+ variationID,
110
108
  slice,
111
109
  file,
112
- method: isDragActive ? "dragAndDrop" : "upload",
113
- variationId: variationID,
114
- });
110
+ isDragActive ? "dragAndDrop" : "upload",
111
+ );
115
112
  setIsHover(false);
116
-
117
- const screenshot = newSlice?.screenshots[variationID];
118
- if (screenshot) {
119
- // Sync with redux store
120
- saveSliceCustomScreenshotSuccess(variationID, screenshot, newSlice);
121
- onUploadSuccess && onUploadSuccess(newSlice);
122
- }
123
113
  },
124
114
  });
125
115
 
126
- const handleFile = async (file: File) => {
116
+ const handleFile = (file: File) => {
127
117
  if (file.size > 128000000) {
128
118
  return openToaster(
129
119
  "File is too big. Max file size: 128Mb.",
130
120
  ToasterType.ERROR,
131
121
  );
132
122
  }
133
- const newSlice = await uploadSliceScreenshot({
134
- slice,
135
- file,
136
- method: "dragAndDrop",
137
- variationId: variationID,
138
- });
139
-
140
- const screenshot = newSlice?.screenshots[variationID];
141
- if (screenshot) {
142
- // Sync with redux store
143
- saveSliceCustomScreenshotSuccess(variationID, screenshot, newSlice);
144
- onUploadSuccess && onUploadSuccess(newSlice);
145
- }
123
+ generateSliceCustomScreenshot(variationID, slice, file, "dragAndDrop");
146
124
  };
147
125
 
148
126
  const supportsClipboardRead = typeof navigator.clipboard.read === "function";
@@ -171,7 +149,7 @@ const DropZone: React.FC<DropZoneProps> = ({
171
149
  const maybeFile = event.dataTransfer.files?.[0];
172
150
  if (maybeFile !== undefined) {
173
151
  if (imageTypes.some((t) => `image/${t}` === maybeFile.type)) {
174
- return void handleFile(maybeFile);
152
+ return handleFile(maybeFile);
175
153
  }
176
154
  return openToaster(
177
155
  `Only files of type ${imageTypes.join(", ")} are accepted.`,
@@ -171,11 +171,9 @@ const variationSetter = (
171
171
  const ScreenshotChangesModal = ({
172
172
  slices,
173
173
  defaultVariationSelector,
174
- onUploadSuccess,
175
174
  }: {
176
175
  slices: ComponentUI[];
177
176
  defaultVariationSelector?: SliceVariationSelector;
178
- onUploadSuccess?: (newSlice: ComponentUI) => void;
179
177
  }) => {
180
178
  const { closeModals } = useSliceMachineActions();
181
179
 
@@ -277,7 +275,6 @@ const ScreenshotChangesModal = ({
277
275
  <VariationDropZone
278
276
  variationID={variationSelector.variationID}
279
277
  slice={slice}
280
- onUploadSuccess={onUploadSuccess}
281
278
  />
282
279
  ) : null;
283
280
  })()}
@@ -6,11 +6,11 @@ import { acceptedImagesTypes } from "@lib/consts";
6
6
  type HandleFileProp = {
7
7
  inputFile: React.RefObject<HTMLInputElement>;
8
8
  children?: React.ReactNode;
9
- handleFile: (file: File | undefined, isDragActive: boolean) => Promise<void>;
9
+ handleFile: (file: File | undefined, isDragActive: boolean) => void;
10
10
  isDragActive: boolean;
11
11
  };
12
12
  type CustomScreenshotProps = {
13
- onHandleFile: (file: File, isDragActive: boolean) => Promise<void>;
13
+ onHandleFile: (file: File, isDragActive: boolean) => void;
14
14
  };
15
15
 
16
16
  const FileInputRenderer: React.FC<HandleFileProp> = ({
@@ -43,7 +43,7 @@ const FileInputRenderer: React.FC<HandleFileProp> = ({
43
43
  style={{ display: "none" }}
44
44
  accept={acceptedImagesTypes.map((type) => `image/${type}`).join(",")}
45
45
  onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
46
- void handleFile(e.target.files?.[0], isDragActive);
46
+ handleFile(e.target.files?.[0], isDragActive);
47
47
  }}
48
48
  />
49
49
  </>
@@ -63,9 +63,9 @@ export default function useCustomScreenshot({
63
63
  onHandleFile,
64
64
  }: CustomScreenshotProps): CustomScreenshotPayload {
65
65
  const inputFile = useRef<HTMLInputElement>(null);
66
- const handleFile = async (file: File | undefined, isDragActive: boolean) => {
66
+ const handleFile = (file: File | undefined, isDragActive: boolean) => {
67
67
  if (file) {
68
- await onHandleFile(file, isDragActive);
68
+ onHandleFile(file, isDragActive);
69
69
  if (inputFile?.current) {
70
70
  inputFile.current.value = "";
71
71
  }
@@ -1,5 +1,4 @@
1
1
  import {
2
- FC,
3
2
  Suspense,
4
3
  useCallback,
5
4
  useEffect,
@@ -35,6 +34,7 @@ import useThrottle from "@src/hooks/useThrottle";
35
34
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
36
35
 
37
36
  import IframeRenderer from "./components/IframeRenderer";
37
+ import { ComponentWithSliceProps } from "@src/layouts/WithSlice";
38
38
  import {
39
39
  selectIframeStatus,
40
40
  selectIsWaitingForIFrameCheck,
@@ -44,8 +44,7 @@ import {
44
44
  import FullPage from "./components/FullPage";
45
45
  import FailedConnect from "./components/FailedConnect";
46
46
  import SetupModal from "./components/SetupModal";
47
- import { Slices, VariationSM } from "@lib/models/common/Slice";
48
- import { ComponentUI } from "@lib/models/common/ComponentUI";
47
+ import { Slices } from "@lib/models/common/Slice";
49
48
 
50
49
  export enum UiState {
51
50
  LOADING_SETUP = "LOADING_SETUP",
@@ -55,12 +54,7 @@ export enum UiState {
55
54
  SUCCESS = "SUCCESS",
56
55
  }
57
56
 
58
- type SimulatorProps = {
59
- slice: ComponentUI;
60
- variation: VariationSM;
61
- };
62
-
63
- const Simulator: FC<SimulatorProps> = ({ slice, variation }) => {
57
+ const Simulator: ComponentWithSliceProps = ({ slice, variation }) => {
64
58
  const { checkSimulatorSetup, connectToSimulatorIframe, saveSliceMock } =
65
59
  useSliceMachineActions();
66
60
  const {
@@ -1,24 +1,18 @@
1
- import { FC } from "react";
2
- import { flushSync } from "react-dom";
3
- import { DropResult } from "react-beautiful-dnd";
4
- import { NestableWidget } from "@prismicio/types-internal/lib/customtypes";
5
-
6
1
  import { ensureDnDDestination } from "@lib/utils";
7
2
  import { transformKeyAccessor } from "@utils/str";
3
+
4
+ import Zone from "../../common/Zone";
5
+ import EditModal from "../../common/EditModal";
6
+
8
7
  import * as Widgets from "@lib/models/common/widgets";
9
8
  import sliceBuilderWidgetsArray from "@lib/models/common/widgets/sliceBuilderArray";
9
+
10
+ import { DropResult } from "react-beautiful-dnd";
10
11
  import { List } from "@src/components/List";
11
- import { WidgetsArea } from "@lib/models/common/Slice";
12
- import { useSliceState } from "@src/features/slices/sliceBuilder/SliceBuilderProvider";
13
- import {
14
- addField,
15
- deleteField,
16
- reorderField,
17
- updateField,
18
- } from "@src/domain/slice";
19
- import Zone from "@lib/builders/common/Zone";
20
- import EditModal from "@lib/builders/common/EditModal";
21
- import { AnyWidget } from "@lib/models/common/widgets/Widget";
12
+ import useSliceMachineActions from "@src/modules/useSliceMachineActions";
13
+ import { VariationSM, WidgetsArea } from "@lib/models/common/Slice";
14
+
15
+ import { NestableWidget } from "@prismicio/types-internal/lib/customtypes";
22
16
 
23
17
  const dataTipText = ` The non-repeatable zone
24
18
  is for fields<br/> that should appear once, like a<br/>
@@ -28,18 +22,24 @@ const dataTipText2 = `The repeatable zone is for a group<br/>
28
22
  of fields that you want to be able to repeat an<br/>
29
23
  indeterminate number of times, like FAQs`;
30
24
 
31
- const FieldZones: FC = () => {
32
- const { slice, setSlice, variation } = useSliceState();
25
+ type FieldZonesProps = {
26
+ variation: VariationSM;
27
+ };
33
28
 
29
+ const FieldZones: React.FunctionComponent<FieldZonesProps> = ({
30
+ variation,
31
+ }) => {
32
+ const {
33
+ addSliceWidget,
34
+ replaceSliceWidget,
35
+ reorderSliceWidget,
36
+ removeSliceWidget,
37
+ updateSliceWidgetMock,
38
+ deleteSliceWidgetMock,
39
+ } = useSliceMachineActions();
34
40
  const _onDeleteItem = (widgetArea: WidgetsArea) => (key: string) => {
35
- const newSlice = deleteField({
36
- slice,
37
- variationId: variation.id,
38
- widgetArea,
39
- fieldId: key,
40
- });
41
-
42
- setSlice(newSlice);
41
+ deleteSliceWidgetMock(variation.id, widgetArea, key);
42
+ removeSliceWidget(variation.id, widgetArea, key);
43
43
  };
44
44
 
45
45
  const _onSave =
@@ -48,23 +48,30 @@ const FieldZones: FC = () => {
48
48
  apiId: previousKey,
49
49
  newKey,
50
50
  value,
51
+ mockValue,
51
52
  }: {
52
53
  apiId: string;
53
54
  newKey: string;
54
55
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
56
  value: any;
57
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
58
+ mockValue: any;
56
59
  }) => {
57
- const newSlice = updateField({
58
- slice,
59
- variationId: variation.id,
60
- widgetArea,
61
- previousFieldId: previousKey,
62
- newFieldId: newKey,
63
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
64
- newField: value,
65
- });
66
-
67
- setSlice(newSlice);
60
+ // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
61
+ if (mockValue) {
62
+ updateSliceWidgetMock(
63
+ variation.id,
64
+ widgetArea,
65
+ previousKey,
66
+ newKey,
67
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
68
+ mockValue,
69
+ );
70
+ } else {
71
+ deleteSliceWidgetMock(variation.id, widgetArea, newKey);
72
+ }
73
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
74
+ replaceSliceWidget(variation.id, widgetArea, previousKey, newKey, value);
68
75
  };
69
76
 
70
77
  const _onSaveNewField =
@@ -89,56 +96,24 @@ const FieldZones: FC = () => {
89
96
  );
90
97
  }
91
98
 
92
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
93
- const newField = widget.create(label) as NestableWidget;
94
-
95
- if (
96
- newField.type === "Range" ||
97
- newField.type === "IntegrationFields" ||
98
- newField.type === "Separator"
99
- ) {
100
- throw new Error(`Unsupported Field Type: ${newField.type}`);
101
- }
102
-
103
- try {
104
- const CurrentWidget: AnyWidget = Widgets[newField.type];
105
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
106
- CurrentWidget.schema.validateSync(newField, { stripUnknown: false });
107
- } catch (error) {
108
- throw new Error(`Model is invalid for widget "${newField.type}".`);
109
- }
110
-
111
- const newSlice = addField({
112
- slice,
113
- variationId: variation.id,
99
+ addSliceWidget(
100
+ variation.id,
114
101
  widgetArea,
115
- newFieldId: id,
116
- newField,
117
- });
118
-
119
- setSlice(newSlice);
102
+ id,
103
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
104
+ widget.create(label) as NestableWidget,
105
+ );
120
106
  };
121
107
 
122
108
  const _onDragEnd = (widgetArea: WidgetsArea) => (result: DropResult) => {
123
109
  if (ensureDnDDestination(result)) return;
124
110
 
125
- const { source, destination } = result;
126
- if (!destination) {
127
- return;
128
- }
129
-
130
- const newSlice = reorderField({
131
- slice,
132
- variationId: variation.id,
111
+ reorderSliceWidget(
112
+ variation.id,
133
113
  widgetArea,
134
- sourceIndex: source.index,
135
- destinationIndex: destination.index,
136
- });
137
-
138
- // When removing redux and replacing it by a simple useState, react-beautiful-dnd (that is deprecated library) was making the fields flickering on reorder.
139
- // The problem seems to come from the react non-synchronous way to handle our state update that didn't work well with the library.
140
- // It's a hack and since it's used on an old pure JavaScript code with a deprecated library it will be removed when updating the UI of the fields.
141
- flushSync(() => setSlice(newSlice));
114
+ result.source.index,
115
+ result.destination?.index ?? undefined,
116
+ );
142
117
  };
143
118
 
144
119
  return (
@@ -1,13 +1,13 @@
1
+ import { Variation } from "@models/common/Variation";
2
+ import { VariationSM } from "@lib/models/common/Slice";
1
3
  import React, { useEffect, useState } from "react";
2
- import Select from "react-select";
3
4
  import { Formik, Form, Field } from "formik";
4
- import { Button, Box } from "@prismicio/editor-ui";
5
- import { Text, Label, Input } from "theme-ui";
6
- import { camelCase } from "lodash";
7
-
8
5
  import SliceMachineModal from "@components/SliceMachineModal";
6
+
9
7
  import Card from "@components/Card/Default";
10
- import { VariationSM } from "@lib/models/common/Slice";
8
+ import Select from "react-select";
9
+
10
+ import { Text, Box, Button, Label, Input, Flex } from "theme-ui";
11
11
 
12
12
  const Error = ({ msg }: { msg?: string }) => (
13
13
  <Text as="span" sx={{ fontSize: 12, color: "error", mt: "5px", ml: 2 }}>
@@ -17,14 +17,9 @@ const Error = ({ msg }: { msg?: string }) => (
17
17
  );
18
18
  const AddVariationModal: React.FunctionComponent<{
19
19
  isOpen: boolean;
20
- loading?: boolean;
21
20
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
21
  onClose: () => any;
23
- onSubmit: (
24
- id: string,
25
- name: string,
26
- copiedVariation: VariationSM,
27
- ) => Promise<void>;
22
+ onSubmit: (id: string, name: string, copiedVariation: VariationSM) => void;
28
23
  initialVariation: VariationSM;
29
24
  variations: ReadonlyArray<VariationSM>;
30
25
  }> = ({ isOpen, onClose, onSubmit, initialVariation, variations }) => {
@@ -36,7 +31,6 @@ const AddVariationModal: React.FunctionComponent<{
36
31
  value: initialVariation.id,
37
32
  label: initialVariation.name,
38
33
  });
39
- const [isAddingVariation, setIsAddingVariation] = useState(false);
40
34
 
41
35
  function validateForm({
42
36
  id,
@@ -76,7 +70,7 @@ const AddVariationModal: React.FunctionComponent<{
76
70
  }
77
71
 
78
72
  function generateId(str: string) {
79
- const slug = camelCase(str);
73
+ const slug = Variation.generateId(str);
80
74
  setGeneratedId(slug);
81
75
  }
82
76
 
@@ -116,9 +110,7 @@ const AddVariationModal: React.FunctionComponent<{
116
110
  else {
117
111
  const copiedVariation = variations.find((v) => v.id === origin.value);
118
112
  if (copiedVariation) {
119
- setIsAddingVariation(true);
120
- await onSubmit(generatedId, name, copiedVariation);
121
- setIsAddingVariation(false);
113
+ onSubmit(generatedId, name, copiedVariation);
122
114
  handleClose();
123
115
  }
124
116
  }
@@ -156,16 +148,16 @@ const AddVariationModal: React.FunctionComponent<{
156
148
  sx={{ textAlign: "left" }}
157
149
  HeaderContent={<Text as="h2">Add new Variation</Text>}
158
150
  FooterContent={
159
- <Box gap={16} alignItems="center">
160
- <Button onClick={handleClose} color="grey">
151
+ <Flex sx={{ justifyContent: "flex-end" }}>
152
+ <Button onClick={handleClose} mr={2} variant="secondary">
161
153
  Cancel
162
154
  </Button>
163
- <Button loading={isAddingVariation}>Submit</Button>
164
- </Box>
155
+ <Button type="submit">Submit</Button>
156
+ </Flex>
165
157
  }
166
158
  close={handleClose}
167
159
  >
168
- <Box flexDirection="column" padding={{ block: 16 }}>
160
+ <Box sx={{ pb: 4, mt: 4 }}>
169
161
  <Label htmlFor="name" sx={{ mb: 1 }}>
170
162
  Variation name*
171
163
  {errors.name ? <Error msg={errors.name} /> : ""}
@@ -187,7 +179,7 @@ const AddVariationModal: React.FunctionComponent<{
187
179
  in Prismic
188
180
  </Text>
189
181
  </Box>
190
- <Box flexDirection="column" padding={{ bottom: 16 }}>
182
+ <Box sx={{ pb: 4 }}>
191
183
  <Label htmlFor="id" sx={{ mb: 1 }}>
192
184
  Variation ID*{errors.id ? <Error msg={errors.id} /> : ""}
193
185
  </Label>
@@ -209,7 +201,7 @@ const AddVariationModal: React.FunctionComponent<{
209
201
  </Text>
210
202
  </Box>
211
203
 
212
- <Box flexDirection="column" padding={{ bottom: 8 }}>
204
+ <Box sx={{ pb: 4 }}>
213
205
  <Label htmlFor="origin" sx={{ mb: 1 }}>
214
206
  Duplicate from
215
207
  </Label>