slice-machine-ui 1.22.3-beta.1 → 1.22.3-beta.3

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 (154) hide show
  1. package/components/DeleteVariationModal/index.tsx +12 -11
  2. package/components/Forms/CreateSliceModal/CreateSliceModal.tsx +2 -5
  3. package/components/Forms/RenameCustomTypeModal/RenameCustomTypeModal.tsx +9 -5
  4. package/components/Forms/RenameVariationModal/RenameVariationModal.tsx +12 -11
  5. package/components/ItemHeader/index.tsx +1 -0
  6. package/components/ListItem/index.tsx +5 -2
  7. package/components/ScreenshotChangesModal/VariationDropZone.tsx +31 -9
  8. package/components/ScreenshotChangesModal/index.tsx +3 -0
  9. package/components/ScreenshotChangesModal/useCustomScreenshot.tsx +5 -5
  10. package/components/Simulator/index.tsx +9 -3
  11. package/lib/builders/CustomTypeBuilder/SliceZone/SlicesTemplatesModal.tsx +2 -2
  12. package/lib/builders/CustomTypeBuilder/SliceZone/UpdateSliceZoneModal.tsx +2 -2
  13. package/lib/builders/CustomTypeBuilder/SliceZone/index.tsx +12 -20
  14. package/lib/builders/CustomTypeBuilder/TabModal/update.tsx +3 -1
  15. package/lib/builders/CustomTypeBuilder/TabZone/index.tsx +119 -52
  16. package/lib/builders/CustomTypeBuilder/index.tsx +39 -42
  17. package/lib/builders/SliceBuilder/FieldZones/index.tsx +81 -56
  18. package/lib/builders/SliceBuilder/Sidebar/AddVariationModal.tsx +24 -16
  19. package/lib/builders/SliceBuilder/Sidebar/index.tsx +44 -46
  20. package/lib/builders/SliceBuilder/SimulatorButton/index.tsx +4 -28
  21. package/lib/builders/SliceBuilder/index.tsx +10 -96
  22. package/lib/builders/common/Zone/Card/components/Hints/CodeBlock.tsx +5 -1
  23. package/lib/builders/common/Zone/Card/components/NewField.tsx +16 -15
  24. package/lib/builders/common/Zone/Card/index.jsx +2 -0
  25. package/lib/builders/common/Zone/index.jsx +3 -1
  26. package/lib/models/common/ComponentUI.ts +0 -14
  27. package/lib/models/common/CustomType/sliceZone.ts +0 -29
  28. package/lib/models/common/CustomType/tab.ts +10 -142
  29. package/lib/models/common/widgets/Group/ListItem/index.jsx +61 -23
  30. package/out/404.html +1 -1
  31. package/out/_next/static/chunks/065a3ddb-9a38ca0d60f0bf2f.js +1 -0
  32. package/out/_next/static/chunks/183-4feb6bb3eddbc768.js +1 -0
  33. package/out/_next/static/chunks/18539003-7b2711e6c51d6fac.js +97 -0
  34. package/out/_next/static/chunks/1cc2734a-2c5b6c0367fcde86.js +1 -0
  35. package/out/_next/static/chunks/25-8fedd33ad9b6de5b.js +1 -0
  36. package/out/_next/static/chunks/318-541db69860d31138.js +1 -0
  37. package/out/_next/static/chunks/{505-3f1cf09a086dcba8.js → 376-0ed5822f8afcaa7c.js} +3 -3
  38. package/out/_next/static/chunks/4c744e84-e3161d754618373f.js +1 -0
  39. package/out/_next/static/chunks/50-cfc2514205b86001.js +1 -0
  40. package/out/_next/static/chunks/543-f8766685f7f451e2.js +1 -0
  41. package/out/_next/static/chunks/59b4e022-7a3b5554b806349f.js +1 -0
  42. package/out/_next/static/chunks/696-b12edad30a3617e5.js +31 -0
  43. package/out/_next/static/chunks/727-15cf3f2fea9a37e5.js +1 -0
  44. package/out/_next/static/chunks/731-501990ebe6a71b32.js +1 -0
  45. package/out/_next/static/chunks/787-727e3aef5d2a10a8.js +1 -0
  46. package/out/_next/static/chunks/904-ccd8ca3368ce29fc.js +1 -0
  47. package/out/_next/static/chunks/{918-38d08f1e885b222d.js → 918-5bb55fb464e34768.js} +1 -1
  48. package/out/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js +1 -0
  49. package/out/_next/static/chunks/pages/_app-20876abeebe0fda7.js +430 -0
  50. package/out/_next/static/chunks/pages/changelog-68d115a14f1423d7.js +1 -0
  51. package/out/_next/static/chunks/pages/changes-6f62ae7b6243a1c7.js +1 -0
  52. package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-3a37eb3373bb8823.js → [customTypeId]-3f862ad6111a1fc0.js} +1 -1
  53. package/out/_next/static/chunks/pages/{custom-types-2f5664d9492b13fb.js → custom-types-94b8f8dbf7727412.js} +1 -1
  54. package/out/_next/static/chunks/pages/{index-d8e3a2c0d712904f.js → index-64cfb8b0948ba8ef.js} +1 -1
  55. package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-733f3890c0466a05.js → [pageTypeId]-d1ffca11c42f2603.js} +1 -1
  56. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-897ca93c114a1435.js +1 -0
  57. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-e89e2e6f772a3454.js +1 -0
  58. package/out/_next/static/chunks/pages/slices-9628f8aa54968d6a.js +1 -0
  59. package/out/_next/static/css/{1bbf650dfd37ce69.css → 1aa04669758c24f4.css} +1 -1
  60. package/out/_next/static/j_voPTrYzsuLCERqtl3Hn/_buildManifest.js +1 -0
  61. package/out/changelog.html +1 -1
  62. package/out/changes.html +1 -1
  63. package/out/custom-types/[customTypeId].html +1 -1
  64. package/out/custom-types.html +1 -1
  65. package/out/index.html +1 -1
  66. package/out/labs.html +1 -1
  67. package/out/page-types/[pageTypeId].html +1 -1
  68. package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  69. package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
  70. package/out/slices.html +1 -1
  71. package/package.json +6 -6
  72. package/pages/slices/[lib]/[sliceName]/[variation]/index.tsx +25 -11
  73. package/pages/slices/[lib]/[sliceName]/[variation]/simulator.tsx +12 -9
  74. package/src/apiClient.ts +7 -6
  75. package/src/components/CodeBlock/CodeBlock.tsx +1 -0
  76. package/src/components/Window/Window.tsx +7 -1
  77. package/src/domain/__tests__/customType.test.ts +785 -0
  78. package/src/domain/customType.ts +519 -6
  79. package/src/domain/slice.ts +166 -1
  80. package/src/features/autoSave/AutoSaveStatusIndicator.tsx +43 -0
  81. package/src/features/autoSave/useAutoSave.tsx +177 -0
  82. package/src/features/customTypes/EditDropdown.tsx +3 -0
  83. package/src/features/customTypes/actions/convertCustomToPageType.ts +2 -4
  84. package/src/features/customTypes/customTypesBuilder/CustomTypeProvider.tsx +90 -0
  85. package/src/features/customTypes/customTypesBuilder/CustomTypesBuilderPage.tsx +46 -79
  86. package/src/features/customTypes/customTypesMessages.ts +4 -0
  87. package/src/features/slices/actions/addSlicesToSliceZone.ts +2 -7
  88. package/src/features/slices/actions/uploadSliceScreenshot.ts +45 -0
  89. package/src/features/slices/convertLegacySlice/ConvertLegacySliceAsNewVariationDialog.tsx +5 -5
  90. package/src/features/slices/convertLegacySlice/ConvertLegacySliceButton.tsx +4 -10
  91. package/src/features/slices/sliceBuilder/SliceBuilderProvider.tsx +110 -0
  92. package/src/features/slices/sliceBuilder/actions/deleteVariation.ts +8 -24
  93. package/src/features/slices/sliceBuilder/actions/renameVariation.ts +8 -24
  94. package/src/features/slices/sliceCards/SharedSliceCard.tsx +1 -0
  95. package/src/hooks/useCurrentSlice.tsx +4 -16
  96. package/src/hooks/useScreenshotChangesModal.ts +1 -0
  97. package/src/hooks/useServerState.ts +1 -58
  98. package/src/modules/availableCustomTypes/index.ts +8 -3
  99. package/src/modules/simulator/index.ts +0 -2
  100. package/src/modules/slices/index.ts +32 -25
  101. package/src/modules/slices/selector.ts +30 -0
  102. package/src/modules/useSliceMachineActions.ts +20 -270
  103. package/src/redux/reducer.ts +0 -4
  104. package/src/redux/saga.ts +0 -6
  105. package/src/redux/type.ts +0 -4
  106. package/test/src/modules/availableCustomTypes/index.test.ts +8 -10
  107. package/test/src/modules/simulator.test.ts +0 -2
  108. package/lib/models/common/CustomType/group.ts +0 -80
  109. package/lib/models/common/Variation.ts +0 -100
  110. package/out/_next/static/ZrWICkLApT4ZATA_akn-2/_buildManifest.js +0 -1
  111. package/out/_next/static/chunks/18539003-4460ccbfe3109578.js +0 -97
  112. package/out/_next/static/chunks/482-34cee2a2071c235f.js +0 -1
  113. package/out/_next/static/chunks/550-c80fd46fb64d1eef.js +0 -1
  114. package/out/_next/static/chunks/80-7b8a97d0122ff74a.js +0 -1
  115. package/out/_next/static/chunks/840-163f8a1040e6820d.js +0 -1
  116. package/out/_next/static/chunks/904-519dbf0f7e8c6243.js +0 -1
  117. package/out/_next/static/chunks/958-8aca174b80cb0c35.js +0 -1
  118. package/out/_next/static/chunks/pages/_app-132564608e9a9502.js +0 -458
  119. package/out/_next/static/chunks/pages/changelog-4d0f2f1222e403fe.js +0 -1
  120. package/out/_next/static/chunks/pages/changes-52c9d917808d1461.js +0 -1
  121. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-7b17cb59d0db03b5.js +0 -1
  122. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-ef11594ce026b650.js +0 -1
  123. package/out/_next/static/chunks/pages/slices-884a936a9a062a65.js +0 -1
  124. package/src/domain/__tests__/CustomTypeModel.test.ts +0 -247
  125. package/src/layouts/WithSlice.tsx +0 -26
  126. package/src/modules/screenshots/actions.ts +0 -21
  127. package/src/modules/screenshots/sagas.ts +0 -70
  128. package/src/modules/selectedCustomType/actions.ts +0 -147
  129. package/src/modules/selectedCustomType/index.ts +0 -11
  130. package/src/modules/selectedCustomType/reducer.ts +0 -287
  131. package/src/modules/selectedCustomType/sagas.ts +0 -72
  132. package/src/modules/selectedCustomType/selectors.ts +0 -33
  133. package/src/modules/selectedCustomType/stateHelpers.ts +0 -42
  134. package/src/modules/selectedCustomType/types.ts +0 -9
  135. package/src/modules/selectedSlice/actions.ts +0 -106
  136. package/src/modules/selectedSlice/reducer.ts +0 -175
  137. package/src/modules/selectedSlice/sagas.ts +0 -72
  138. package/src/modules/selectedSlice/selectors.ts +0 -55
  139. package/src/modules/selectedSlice/types.ts +0 -3
  140. package/src/modules/toaster/utils.tsx +0 -23
  141. package/test/lib/models/common/CustomType/sliceZone.test.ts +0 -49
  142. package/test/pages/custom-types.test.tsx +0 -625
  143. package/test/src/modules/selectedCustomType/__fixtures__/model.json +0 -119
  144. package/test/src/modules/selectedCustomType/reducer.test.ts +0 -322
  145. package/test/src/modules/selectedCustomType/sagas.test.ts +0 -89
  146. package/test/src/modules/selectedCustomType/selectors.test.ts +0 -54
  147. package/test/src/modules/selectedSlice/__fixtures__/mocks.json +0 -171
  148. package/test/src/modules/selectedSlice/__fixtures__/model.json +0 -35
  149. package/test/src/modules/selectedSlice/__testutils__/getRefreshStateCreatorPayloadData.ts +0 -72
  150. package/test/src/modules/selectedSlice/__testutils__/getSelectedSliceDummyData.ts +0 -30
  151. package/test/src/modules/selectedSlice/reducer.test.ts +0 -170
  152. package/test/src/modules/selectedSlice/sagas.test.ts +0 -82
  153. package/test/src/modules/toaster/utils.test.ts +0 -50
  154. /package/out/_next/static/{ZrWICkLApT4ZATA_akn-2 → j_voPTrYzsuLCERqtl3Hn}/_ssgManifest.js +0 -0
@@ -1,13 +1,13 @@
1
- import { Variation } from "@models/common/Variation";
2
- import { VariationSM } from "@lib/models/common/Slice";
3
1
  import React, { useEffect, useState } from "react";
2
+ import Select from "react-select";
4
3
  import { Formik, Form, Field } from "formik";
5
- import SliceMachineModal from "@components/SliceMachineModal";
4
+ import { Button, Box } from "@prismicio/editor-ui";
5
+ import { Text, Label, Input } from "theme-ui";
6
+ import { camelCase } from "lodash";
6
7
 
8
+ import SliceMachineModal from "@components/SliceMachineModal";
7
9
  import Card from "@components/Card/Default";
8
- import Select from "react-select";
9
-
10
- import { Text, Box, Button, Label, Input, Flex } from "theme-ui";
10
+ import { VariationSM } from "@lib/models/common/Slice";
11
11
 
12
12
  const Error = ({ msg }: { msg?: string }) => (
13
13
  <Text as="span" sx={{ fontSize: 12, color: "error", mt: "5px", ml: 2 }}>
@@ -17,9 +17,14 @@ const Error = ({ msg }: { msg?: string }) => (
17
17
  );
18
18
  const AddVariationModal: React.FunctionComponent<{
19
19
  isOpen: boolean;
20
+ loading?: boolean;
20
21
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
22
  onClose: () => any;
22
- onSubmit: (id: string, name: string, copiedVariation: VariationSM) => void;
23
+ onSubmit: (
24
+ id: string,
25
+ name: string,
26
+ copiedVariation: VariationSM,
27
+ ) => Promise<void>;
23
28
  initialVariation: VariationSM;
24
29
  variations: ReadonlyArray<VariationSM>;
25
30
  }> = ({ isOpen, onClose, onSubmit, initialVariation, variations }) => {
@@ -31,6 +36,7 @@ const AddVariationModal: React.FunctionComponent<{
31
36
  value: initialVariation.id,
32
37
  label: initialVariation.name,
33
38
  });
39
+ const [isAddingVariation, setIsAddingVariation] = useState(false);
34
40
 
35
41
  function validateForm({
36
42
  id,
@@ -70,7 +76,7 @@ const AddVariationModal: React.FunctionComponent<{
70
76
  }
71
77
 
72
78
  function generateId(str: string) {
73
- const slug = Variation.generateId(str);
79
+ const slug = camelCase(str);
74
80
  setGeneratedId(slug);
75
81
  }
76
82
 
@@ -110,7 +116,9 @@ const AddVariationModal: React.FunctionComponent<{
110
116
  else {
111
117
  const copiedVariation = variations.find((v) => v.id === origin.value);
112
118
  if (copiedVariation) {
113
- onSubmit(generatedId, name, copiedVariation);
119
+ setIsAddingVariation(true);
120
+ await onSubmit(generatedId, name, copiedVariation);
121
+ setIsAddingVariation(false);
114
122
  handleClose();
115
123
  }
116
124
  }
@@ -148,16 +156,16 @@ const AddVariationModal: React.FunctionComponent<{
148
156
  sx={{ textAlign: "left" }}
149
157
  HeaderContent={<Text as="h2">Add new Variation</Text>}
150
158
  FooterContent={
151
- <Flex sx={{ justifyContent: "flex-end" }}>
152
- <Button onClick={handleClose} mr={2} variant="secondary">
159
+ <Box gap={16} alignItems="center">
160
+ <Button onClick={handleClose} color="grey">
153
161
  Cancel
154
162
  </Button>
155
- <Button type="submit">Submit</Button>
156
- </Flex>
163
+ <Button loading={isAddingVariation}>Submit</Button>
164
+ </Box>
157
165
  }
158
166
  close={handleClose}
159
167
  >
160
- <Box sx={{ pb: 4, mt: 4 }}>
168
+ <Box flexDirection="column" padding={{ block: 16 }}>
161
169
  <Label htmlFor="name" sx={{ mb: 1 }}>
162
170
  Variation name*
163
171
  {errors.name ? <Error msg={errors.name} /> : ""}
@@ -179,7 +187,7 @@ const AddVariationModal: React.FunctionComponent<{
179
187
  in Prismic
180
188
  </Text>
181
189
  </Box>
182
- <Box sx={{ pb: 4 }}>
190
+ <Box flexDirection="column" padding={{ bottom: 16 }}>
183
191
  <Label htmlFor="id" sx={{ mb: 1 }}>
184
192
  Variation ID*{errors.id ? <Error msg={errors.id} /> : ""}
185
193
  </Label>
@@ -201,7 +209,7 @@ const AddVariationModal: React.FunctionComponent<{
201
209
  </Text>
202
210
  </Box>
203
211
 
204
- <Box sx={{ pb: 4 }}>
212
+ <Box flexDirection="column" padding={{ bottom: 8 }}>
205
213
  <Label htmlFor="origin" sx={{ mb: 1 }}>
206
214
  Duplicate from
207
215
  </Label>
@@ -1,44 +1,35 @@
1
1
  import { Box, Button, Gradient } from "@prismicio/editor-ui";
2
2
  import { useRouter } from "next/router";
3
- import { type Dispatch, type FC, type SetStateAction, useState } from "react";
3
+ import { type FC, useState } from "react";
4
+ import { toast } from "react-toastify";
4
5
 
5
6
  import AddVariationModal from "@builders/SliceBuilder/Sidebar/AddVariationModal";
6
- import type { SliceBuilderState } from "@builders/SliceBuilder";
7
7
  import { DeleteVariationModal } from "@components/DeleteVariationModal";
8
8
  import { RenameVariationModal } from "@components/Forms/RenameVariationModal";
9
9
  import ScreenshotChangesModal from "@components/ScreenshotChangesModal";
10
- import type { ComponentUI } from "@lib/models/common/ComponentUI";
11
10
  import type { VariationSM } from "@lib/models/common/Slice";
12
- import { Variation } from "@lib/models/common/Variation";
13
11
  import { SharedSliceCard } from "@src/features/slices/sliceCards/SharedSliceCard";
14
12
  import { SLICES_CONFIG } from "@src/features/slices/slicesConfig";
15
13
  import { useScreenshotChangesModal } from "@src/hooks/useScreenshotChangesModal";
14
+ import { updateSlice } from "@src/apiClient";
15
+ import { copySliceVariation } from "@src/domain/slice";
16
+ import { useSliceState } from "@src/features/slices/sliceBuilder/SliceBuilderProvider";
16
17
  import useSliceMachineActions from "@src/modules/useSliceMachineActions";
17
18
 
18
- type SidebarProps = {
19
- slice: ComponentUI;
20
- variation: VariationSM;
21
- sliceBuilderState: SliceBuilderState;
22
- setSliceBuilderState: Dispatch<SetStateAction<SliceBuilderState>>;
23
- };
24
-
25
19
  type DialogState =
26
- | { type: "ADD_VARIATION"; variation?: undefined }
27
- | { type: "RENAME_VARIATION"; variation: VariationSM }
28
- | { type: "DELETE_VARIATION"; variation: VariationSM }
20
+ | { type: "ADD_VARIATION"; variation?: undefined; loading?: boolean }
21
+ | { type: "RENAME_VARIATION"; variation: VariationSM; loading?: boolean }
22
+ | { type: "DELETE_VARIATION"; variation: VariationSM; loading?: boolean }
29
23
  | undefined;
30
24
 
31
- export const Sidebar: FC<SidebarProps> = (props) => {
32
- const { slice, variation, sliceBuilderState, setSliceBuilderState } = props;
33
-
25
+ export const Sidebar: FC = () => {
26
+ const { slice, variation, setSlice } = useSliceState();
34
27
  const [dialog, setDialog] = useState<DialogState>();
35
-
36
28
  const screenshotChangesModal = useScreenshotChangesModal();
37
- const { sliceFilterFn, defaultVariationSelector } =
29
+ const { sliceFilterFn, defaultVariationSelector, onUploadSuccess } =
38
30
  screenshotChangesModal.modalPayload;
39
-
40
- const { copyVariationSlice, updateSlice } = useSliceMachineActions();
41
31
  const router = useRouter();
32
+ const { saveSliceSuccess } = useSliceMachineActions();
42
33
 
43
34
  return (
44
35
  <>
@@ -48,10 +39,16 @@ export const Sidebar: FC<SidebarProps> = (props) => {
48
39
  action={{
49
40
  type: "menu",
50
41
  onRename: () => {
51
- setDialog({ type: "RENAME_VARIATION", variation: v });
42
+ setDialog({
43
+ type: "RENAME_VARIATION",
44
+ variation: v,
45
+ });
52
46
  },
53
47
  onRemove: () => {
54
- setDialog({ type: "DELETE_VARIATION", variation: v });
48
+ setDialog({
49
+ type: "DELETE_VARIATION",
50
+ variation: v,
51
+ });
55
52
  },
56
53
  removeDisabled: slice.model.variations.length <= 1,
57
54
  }}
@@ -64,6 +61,9 @@ export const Sidebar: FC<SidebarProps> = (props) => {
64
61
  sliceID: slice.model.id,
65
62
  variationID: v.id,
66
63
  },
64
+ onUploadSuccess: (newSlice) => {
65
+ setSlice(newSlice);
66
+ },
67
67
  });
68
68
  }}
69
69
  replace
@@ -103,6 +103,7 @@ export const Sidebar: FC<SidebarProps> = (props) => {
103
103
  <ScreenshotChangesModal
104
104
  slices={sliceFilterFn([slice])}
105
105
  defaultVariationSelector={defaultVariationSelector}
106
+ onUploadSuccess={onUploadSuccess}
106
107
  />
107
108
  <RenameVariationModal
108
109
  isOpen={dialog?.type === "RENAME_VARIATION"}
@@ -111,8 +112,6 @@ export const Sidebar: FC<SidebarProps> = (props) => {
111
112
  }}
112
113
  slice={slice}
113
114
  variation={dialog?.variation}
114
- sliceBuilderState={sliceBuilderState}
115
- setSliceBuilderState={setSliceBuilderState}
116
115
  />
117
116
  <DeleteVariationModal
118
117
  isOpen={dialog?.type === "DELETE_VARIATION"}
@@ -121,8 +120,6 @@ export const Sidebar: FC<SidebarProps> = (props) => {
121
120
  }}
122
121
  slice={slice}
123
122
  variation={dialog?.variation}
124
- sliceBuilderState={sliceBuilderState}
125
- setSliceBuilderState={setSliceBuilderState}
126
123
  />
127
124
  <AddVariationModal
128
125
  initialVariation={variation}
@@ -130,27 +127,28 @@ export const Sidebar: FC<SidebarProps> = (props) => {
130
127
  onClose={() => {
131
128
  setDialog(undefined);
132
129
  }}
133
- onSubmit={(id, name, copiedVariation) => {
134
- copyVariationSlice(id, name, copiedVariation);
130
+ onSubmit={async (id, name, copiedVariation) => {
131
+ try {
132
+ const { slice: newSlice, variation: newVariation } =
133
+ copySliceVariation({ slice, id, name, copiedVariation });
134
+
135
+ await updateSlice(newSlice);
136
+ saveSliceSuccess(newSlice);
137
+ setSlice(newSlice);
138
+
139
+ const url = SLICES_CONFIG.getBuilderPagePathname({
140
+ libraryName: newSlice.href,
141
+ sliceName: newSlice.model.name,
142
+ variationId: newVariation.id,
143
+ });
135
144
 
136
- // We have to immediately save the new variation to prevent an
137
- // infinite loop related to screenshots handling.
138
- const newVariation = Variation.copyValue(copiedVariation, id, name);
139
- const newSlice = {
140
- ...slice,
141
- model: {
142
- ...slice.model,
143
- variations: [...slice.model.variations, newVariation],
144
- },
145
- };
146
- updateSlice(newSlice, setSliceBuilderState);
145
+ void router.replace(url);
146
+ } catch (error) {
147
+ const message = `Could not add variation \`${name}\``;
148
+ console.error(message, error);
147
149
 
148
- const url = SLICES_CONFIG.getBuilderPagePathname({
149
- libraryName: newSlice.href,
150
- sliceName: newSlice.model.name,
151
- variationId: newVariation.id,
152
- });
153
- void router.replace(url);
150
+ toast.error(message);
151
+ }
154
152
  }}
155
153
  variations={slice.model.variations}
156
154
  />
@@ -70,24 +70,10 @@ const SimulatorOnboardingTooltip: React.FC<
70
70
  );
71
71
  };
72
72
 
73
- const NeedToSaveTooltip: React.FC = () => (
74
- <ReactTooltipPortal>
75
- <ReactTooltip
76
- clickable
77
- place="bottom"
78
- effect="solid"
79
- delayHide={500}
80
- id="simulator-button-tooltip"
81
- >
82
- Save your work in order to simulate
83
- </ReactTooltip>
84
- </ReactTooltipPortal>
85
- );
86
-
87
73
  const SimulatorButton: React.FC<{
88
74
  isSimulatorAvailableForFramework: boolean;
89
- isTouched: boolean;
90
- }> = ({ isSimulatorAvailableForFramework, isTouched }) => {
75
+ disabled: boolean;
76
+ }> = ({ isSimulatorAvailableForFramework, disabled }) => {
91
77
  const router = useRouter();
92
78
 
93
79
  const ref = useRef<HTMLButtonElement | null>(null);
@@ -115,16 +101,9 @@ const SimulatorButton: React.FC<{
115
101
  }
116
102
  };
117
103
 
118
- const disabled = !isSimulatorAvailableForFramework || isTouched;
119
-
120
104
  const shouldShowSimulatorTooltip =
121
105
  isSimulatorAvailableForFramework && !hasSeenSimulatorTooltip;
122
106
 
123
- const shouldShowNeedToSaveTooltip =
124
- isSimulatorAvailableForFramework &&
125
- shouldShowSimulatorTooltip === false &&
126
- isTouched;
127
-
128
107
  return (
129
108
  <span
130
109
  data-tip={true}
@@ -146,7 +125,7 @@ const SimulatorButton: React.FC<{
146
125
  disabled={disabled}
147
126
  renderStartIcon={() => (
148
127
  <PlayCircleIcon
149
- color={tokens.color.greyLight11}
128
+ color={tokens.color.greyLight1}
150
129
  height={tokens.size[24]}
151
130
  style={{
152
131
  // TODO(DT-1538): our icons should have a `viewBox` of 24px.
@@ -155,16 +134,13 @@ const SimulatorButton: React.FC<{
155
134
  width={tokens.size[24]}
156
135
  />
157
136
  )}
158
- color="grey"
159
137
  >
160
138
  Simulate
161
139
  </Button>
162
140
  </SimulatorOnboardingTooltip>
163
141
  {isSimulatorAvailableForFramework === false ? (
164
142
  <SimulatorNotSupportedTooltip />
165
- ) : shouldShowNeedToSaveTooltip ? (
166
- <NeedToSaveTooltip />
167
- ) : null}
143
+ ) : undefined}
168
144
  </span>
169
145
  );
170
146
  };
@@ -1,23 +1,10 @@
1
- import { Box, Button } from "@prismicio/editor-ui";
2
- import {
3
- type Dispatch,
4
- type FC,
5
- type SetStateAction,
6
- useEffect,
7
- useState,
8
- } from "react";
9
-
10
- import {
11
- type ToastPayload,
12
- handleRemoteResponse,
13
- } from "@src/modules/toaster/utils";
1
+ import { Box } from "@prismicio/editor-ui";
2
+ import { type FC } from "react";
14
3
 
15
4
  import FieldZones from "./FieldZones";
16
5
  import { Sidebar } from "./Sidebar";
17
6
 
18
- import useSliceMachineActions from "src/modules/useSliceMachineActions";
19
7
  import { useSelector } from "react-redux";
20
- import { SliceMachineStoreType } from "@src/redux/type";
21
8
 
22
9
  import SimulatorButton from "@builders/SliceBuilder/SimulatorButton";
23
10
  import {
@@ -28,76 +15,17 @@ import {
28
15
  AppLayoutContent,
29
16
  AppLayoutHeader,
30
17
  } from "@components/AppLayout";
31
- import { VariationSM } from "@lib/models/common/Slice";
32
- import { ComponentUI } from "@lib/models/common/ComponentUI";
33
-
34
18
  import { FloatingBackButton } from "@src/features/slices/sliceBuilder/FloatingBackButton";
35
19
  import { selectIsSimulatorAvailableForFramework } from "@src/modules/environment";
36
- import { isSelectedSliceTouched } from "@src/modules/selectedSlice/selectors";
37
- import { ComponentWithSliceProps } from "@src/layouts/WithSlice";
20
+ import { useSliceState } from "@src/features/slices/sliceBuilder/SliceBuilderProvider";
21
+ import { AutoSaveStatusIndicator } from "@src/features/autoSave/AutoSaveStatusIndicator";
38
22
 
39
- export type SliceBuilderState = ToastPayload & { loading: boolean };
40
-
41
- export const initialState: SliceBuilderState = {
42
- loading: false,
43
- done: false,
44
- };
45
-
46
- const SliceBuilder: ComponentWithSliceProps = ({ slice, variation }) => {
47
- const { openToaster } = useSliceMachineActions();
48
- const isTouched = useSelector((store: SliceMachineStoreType) =>
49
- isSelectedSliceTouched(store, slice.from, slice.model.id),
50
- );
23
+ export const SliceBuilder: FC = () => {
24
+ const { slice, autoSaveStatus } = useSliceState();
51
25
 
52
- // We need to move this state to somewhere global to update the UI if any action from anywhere save or update to the filesystem I'd guess
53
- const [state, setState] = useState<SliceBuilderState>(initialState);
54
-
55
- useEffect(() => {
56
- if (isTouched) {
57
- setState(initialState);
58
- }
59
- }, [isTouched]);
60
-
61
- // activate/deactivate Success message
62
- useEffect(() => {
63
- if (state.done) {
64
- handleRemoteResponse(openToaster)(state);
65
- }
66
- // eslint-disable-next-line react-hooks/exhaustive-deps
67
- }, [state]);
68
-
69
- // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
70
- if (!variation) return <AppLayout />;
71
- else
72
- return (
73
- <SliceBuilderForVariation
74
- setState={setState}
75
- slice={slice}
76
- variation={variation}
77
- isTouched={isTouched}
78
- state={state}
79
- />
80
- );
81
- };
82
-
83
- type SliceBuilderForVariationProps = {
84
- setState: Dispatch<SetStateAction<SliceBuilderState>>;
85
- slice: ComponentUI;
86
- variation: VariationSM;
87
- isTouched: boolean;
88
- state: SliceBuilderState;
89
- };
90
- const SliceBuilderForVariation: FC<SliceBuilderForVariationProps> = ({
91
- setState,
92
- slice,
93
- variation,
94
- isTouched,
95
- state,
96
- }) => {
97
26
  const isSimulatorAvailableForFramework = useSelector(
98
27
  selectIsSimulatorAvailableForFramework,
99
28
  );
100
- const { updateSlice } = useSliceMachineActions();
101
29
 
102
30
  return (
103
31
  <AppLayout>
@@ -105,20 +33,11 @@ const SliceBuilderForVariation: FC<SliceBuilderForVariationProps> = ({
105
33
  <AppLayoutBackButton url="/slices" />
106
34
  <AppLayoutBreadcrumb folder="Slices" page={slice.model.name} />
107
35
  <AppLayoutActions>
36
+ <AutoSaveStatusIndicator status={autoSaveStatus} />
108
37
  <SimulatorButton
109
38
  isSimulatorAvailableForFramework={isSimulatorAvailableForFramework}
110
- isTouched={!!isTouched}
39
+ disabled={autoSaveStatus !== "saved"}
111
40
  />
112
- <Button
113
- loading={state.loading}
114
- disabled={!isTouched || state.loading}
115
- onClick={() => {
116
- updateSlice(slice, setState);
117
- }}
118
- data-cy="builder-save-button"
119
- >
120
- Save
121
- </Button>
122
41
  </AppLayoutActions>
123
42
  </AppLayoutHeader>
124
43
  <AppLayoutContent>
@@ -128,13 +47,8 @@ const SliceBuilderForVariation: FC<SliceBuilderForVariationProps> = ({
128
47
  gap={16}
129
48
  gridTemplateColumns="320px 1fr"
130
49
  >
131
- <Sidebar
132
- slice={slice}
133
- variation={variation}
134
- sliceBuilderState={state}
135
- setSliceBuilderState={setState}
136
- />
137
- <FieldZones variation={variation} />
50
+ <Sidebar />
51
+ <FieldZones />
138
52
  </Box>
139
53
  <FloatingBackButton />
140
54
  </AppLayoutContent>
@@ -83,7 +83,11 @@ const CodeBlock: React.FC<CodeBlockProps> = ({ code, lang }) => {
83
83
  </Code>
84
84
  </Flex>
85
85
  <Box>
86
- <Button onClick={copy} variant="textButton">
86
+ <Button
87
+ aria-label={isCopied ? "Code snippet copied" : "Copy code snippet"}
88
+ onClick={copy}
89
+ variant="textButton"
90
+ >
87
91
  {isCopied ? (
88
92
  <MdCheck
89
93
  size={16}
@@ -1,8 +1,9 @@
1
1
  import { Ref, SetStateAction, useEffect, useRef, useState } from "react";
2
2
  import { Formik, Form, Field } from "formik";
3
- import { Input, Flex, Text, Button, useThemeUI } from "theme-ui";
3
+ import { Input, Flex, Text, useThemeUI } from "theme-ui";
4
4
  import * as CSS from "csstype";
5
5
  import { AnyObjectSchema } from "yup";
6
+ import { Button } from "@prismicio/editor-ui";
6
7
 
7
8
  import { validateId } from "@lib/forms/defaults";
8
9
  import { createInitialValues, createValidationSchema } from "@lib/forms";
@@ -118,7 +119,7 @@ const NewField: React.FC<NewField> = ({
118
119
  validationSchema={validationSchema}
119
120
  initialValues={initialValues}
120
121
  >
121
- {({ errors, values, setValues, setFieldValue }) => (
122
+ {({ errors, values, setValues, setFieldValue, submitForm }) => (
122
123
  <Form data-cy="new-field-form">
123
124
  <Flex
124
125
  as="li"
@@ -162,6 +163,11 @@ const NewField: React.FC<NewField> = ({
162
163
  onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
163
164
  handleLabelChange(e, values, setValues)
164
165
  }
166
+ onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
167
+ if (e.key === "Enter") {
168
+ void submitForm();
169
+ }
170
+ }}
165
171
  name="label"
166
172
  placeholder="Field Name"
167
173
  type="text"
@@ -206,6 +212,11 @@ const NewField: React.FC<NewField> = ({
206
212
  onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
207
213
  handleIdChange(e, setFieldValue)
208
214
  }
215
+ onKeyDown={(e: React.KeyboardEvent<HTMLInputElement>) => {
216
+ if (e.key === "Enter") {
217
+ void submitForm();
218
+ }
219
+ }}
209
220
  name="id"
210
221
  placeholder="e.g. buttonLink"
211
222
  type="text"
@@ -237,23 +248,13 @@ const NewField: React.FC<NewField> = ({
237
248
  <ErrorTooltip error={errors.id} />
238
249
  </Flex>
239
250
  <Flex sx={{ gap: 2 }}>
240
- <Button
241
- onClick={onCancelNewField}
242
- variant="secondary"
243
- type="button"
244
- >
251
+ <Button onClick={onCancelNewField} color="grey">
245
252
  Cancel
246
253
  </Button>
247
254
  <Button
248
- sx={{
249
- fontWeight: "400",
250
- paddingBlock: "8px",
251
- paddingInline: "16px",
252
- fontSize: "14px",
253
- borderRadius: "4px",
254
- lineHeight: "21px",
255
+ onClick={() => {
256
+ void submitForm();
255
257
  }}
256
- type="submit"
257
258
  >
258
259
  Add
259
260
  </Button>
@@ -86,6 +86,8 @@ const FieldZone = ({
86
86
  draggableId: `list-item-${item.key}`,
87
87
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
88
88
  isRepeatableCustomType,
89
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access
90
+ dataCy: `list-item-${item.key}`,
89
91
  };
90
92
 
91
93
  // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
@@ -85,6 +85,7 @@ const Zone = ({
85
85
  size="small"
86
86
  // TODO(DT-1710): add the missing `flexShrink: 0` property to the Editor's Switch component.
87
87
  style={{ flexShrink: 0 }}
88
+ data-cy="code-snippets-switch"
88
89
  />
89
90
  <Button
90
91
  data-cy={`add-${
@@ -93,7 +94,8 @@ const Zone = ({
93
94
  }-field`}
94
95
  onClick={enterSelectMode}
95
96
  startIcon="add"
96
- grey="grey"
97
+ color="grey"
98
+ disabled={newFieldData !== null}
97
99
  >
98
100
  Add a new field
99
101
  </Button>
@@ -58,18 +58,4 @@ export const ComponentUI = {
58
58
  return component.model.variations[0];
59
59
  }
60
60
  },
61
-
62
- updateVariation(component: ComponentUI, variationId: string) {
63
- return (mutateCallbackFn: (v: VariationSM) => VariationSM): ComponentUI => {
64
- const variations = component.model.variations.map((v) => {
65
- if (v.id === variationId) return mutateCallbackFn(v);
66
- else return v;
67
- });
68
-
69
- return {
70
- ...component,
71
- model: { ...component.model, variations },
72
- };
73
- };
74
- },
75
61
  };
@@ -3,7 +3,6 @@ import {
3
3
  CompositeSlice,
4
4
  LegacySlice,
5
5
  } from "@prismicio/types-internal/lib/customtypes/widgets/slices";
6
- import { SlicesSM } from "../Slices";
7
6
  import { ComponentUI } from "../ComponentUI";
8
7
 
9
8
  export type NonSharedSliceInSliceZone = {
@@ -14,31 +13,3 @@ export interface SliceZoneSlice {
14
13
  type: SlicesTypes;
15
14
  payload: ComponentUI | NonSharedSliceInSliceZone;
16
15
  }
17
-
18
- export const SliceZone = {
19
- addSharedSlice(sz: SlicesSM, key: string): SlicesSM {
20
- const value = sz.value.concat([
21
- {
22
- key,
23
- value: {
24
- type: "SharedSlice",
25
- },
26
- },
27
- ]);
28
- return {
29
- ...sz,
30
- value,
31
- };
32
- },
33
- removeSharedSlice(sz: SlicesSM, key: string): SlicesSM {
34
- const value = sz.value.filter(({ key: k }) => k !== key);
35
-
36
- return {
37
- ...sz,
38
- value,
39
- };
40
- },
41
- createEmpty(key: string): SlicesSM {
42
- return { key, value: [] };
43
- },
44
- };