slice-machine-ui 2.2.2-beta.1 → 2.2.2-beta.11

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 (108) hide show
  1. package/next.config.mjs +11 -1
  2. package/out/404.html +1 -1
  3. package/out/_next/static/chunks/18539003-7b839478e0b5720a.js +22 -0
  4. package/out/_next/static/chunks/{66-d37d30551288858b.js → 210-565d01ee9777d1a1.js} +2 -2
  5. package/out/_next/static/chunks/{212-cbaa35389c0aacf1.js → 212-b6a2b8d9d16ef3c5.js} +1 -1
  6. package/out/_next/static/chunks/448-a0de8b21d55d4da3.js +1 -0
  7. package/out/_next/static/chunks/{465-47a6d2a5f66f521e.js → 465-d5dd75edd8e6bb65.js} +1 -1
  8. package/out/_next/static/chunks/574-319271e279f042bc.js +1 -0
  9. package/out/_next/static/chunks/59b4e022-8e544a511d670317.js +1 -0
  10. package/out/_next/static/chunks/695-603bd96af31f4302.js +12 -0
  11. package/out/_next/static/chunks/{816-68d4db26c0adab2e.js → 816-17afd84d2642f4c4.js} +1 -1
  12. package/out/_next/static/chunks/f36c6662-1f3a854183168b10.js +1 -0
  13. package/out/_next/static/chunks/pages/_app-f7a7229e62fc765c.js +544 -0
  14. package/out/_next/static/chunks/pages/{changelog-d309ea186a0e56bf.js → changelog-1d15a7ef498f499a.js} +1 -1
  15. package/out/_next/static/chunks/pages/{changes-1bb1a7b784a22151.js → changes-0af2a1a5244418f9.js} +1 -1
  16. package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-74be2c0ac9c854c7.js → [customTypeId]-a6ff1618238b3510.js} +1 -1
  17. package/out/_next/static/chunks/pages/{index-785a0ab6e2a4fc27.js → index-2610e550d79c5bb1.js} +1 -1
  18. package/out/_next/static/chunks/pages/{labs-2e4f3a5f68e65b93.js → labs-240ba57bfdabe998.js} +1 -1
  19. package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-d35c87b9aaec445a.js → [pageTypeId]-c300f963db847451.js} +1 -1
  20. package/out/_next/static/chunks/pages/{settings-25eb02893ed871b7.js → settings-039476a9a63d25a1.js} +1 -1
  21. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/{simulator-b47a72d5e94bd946.js → simulator-cfc19e3e799745bb.js} +1 -1
  22. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-58e6cb0f278ea03c.js +1 -0
  23. package/out/_next/static/chunks/pages/{slices-cc44eeccd58d23a9.js → slices-9894ce968d74baf6.js} +1 -1
  24. package/out/_next/static/css/82c8c4f05b25d3af.css +1 -0
  25. package/out/_next/static/lnoCw12ueMqf698VD8pfN/_buildManifest.js +1 -0
  26. package/out/changelog.html +1 -1
  27. package/out/changes.html +1 -1
  28. package/out/custom-types/[customTypeId].html +1 -1
  29. package/out/custom-types.html +1 -1
  30. package/out/index.html +1 -1
  31. package/out/labs.html +1 -1
  32. package/out/page-types/[pageTypeId].html +1 -1
  33. package/out/settings.html +1 -1
  34. package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  35. package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
  36. package/out/slices.html +1 -1
  37. package/package.json +11 -10
  38. package/src/domain/fields.ts +223 -0
  39. package/src/features/builder/AddFieldDropdown.tsx +119 -0
  40. package/src/features/onboarding/OnboardingGuide.tsx +45 -0
  41. package/src/features/onboarding/OnboardingProgressStepper.tsx +71 -0
  42. package/src/features/onboarding/OnboardingProvider.tsx +82 -0
  43. package/src/features/onboarding/OnboardingStepDialog/OnboardingStepDialog.tsx +46 -0
  44. package/src/features/onboarding/OnboardingStepDialog/OnboardingStepDialogContent.tsx +38 -0
  45. package/src/features/onboarding/OnboardingStepDialog/index.ts +1 -0
  46. package/src/features/onboarding/content.tsx +115 -0
  47. package/src/features/onboarding/types.ts +32 -0
  48. package/src/features/onboarding/useOnboardingExperiment.ts +6 -0
  49. package/src/hooks/useNestedGroupExperiment.ts +8 -0
  50. package/src/hooks/usePersistedState.ts +20 -3
  51. package/src/legacy/components/ListItem/index.tsx +1 -1
  52. package/src/legacy/components/Navigation/index.tsx +2 -0
  53. package/src/legacy/lib/builders/CustomTypeBuilder/TabZone/index.tsx +22 -4
  54. package/src/legacy/lib/builders/SliceBuilder/FieldZones/index.tsx +23 -8
  55. package/src/legacy/lib/builders/SliceBuilder/VariationsList/index.tsx +5 -2
  56. package/src/legacy/lib/builders/SliceBuilder/index.tsx +1 -1
  57. package/src/legacy/lib/builders/common/EditModal/index.jsx +1 -1
  58. package/src/legacy/lib/builders/common/Zone/Card/components/Hints/index.tsx +8 -1
  59. package/src/legacy/lib/builders/common/Zone/Card/components/NewField.tsx +1 -1
  60. package/src/legacy/lib/builders/common/Zone/Card/index.jsx +3 -1
  61. package/src/legacy/lib/builders/common/Zone/components/ZoneEmptyState/ZoneEmptyState.tsx +4 -13
  62. package/src/legacy/lib/builders/common/Zone/index.jsx +26 -31
  63. package/src/legacy/lib/builders/utils/index.ts +8 -0
  64. package/src/legacy/lib/models/common/Group.ts +51 -28
  65. package/src/legacy/lib/models/common/widgets/Boolean/index.ts +2 -4
  66. package/src/legacy/lib/models/common/widgets/Color/index.ts +2 -4
  67. package/src/legacy/lib/models/common/widgets/ContentRelationship/index.ts +0 -2
  68. package/src/legacy/lib/models/common/widgets/Date/index.ts +0 -2
  69. package/src/legacy/lib/models/common/widgets/Embed/index.ts +2 -4
  70. package/src/legacy/lib/models/common/widgets/GeoPoint/index.ts +2 -4
  71. package/src/legacy/lib/models/common/widgets/Group/ListItem/index.jsx +46 -26
  72. package/src/legacy/lib/models/common/widgets/Group/createGroupWidget.ts +81 -0
  73. package/src/legacy/lib/models/common/widgets/Group/index.tsx +72 -0
  74. package/src/legacy/lib/models/common/widgets/Image/index.ts +2 -4
  75. package/src/legacy/lib/models/common/widgets/Link/index.ts +2 -4
  76. package/src/legacy/lib/models/common/widgets/LinkToMedia/index.ts +2 -4
  77. package/src/legacy/lib/models/common/widgets/NestedGroup/index.tsx +40 -0
  78. package/src/legacy/lib/models/common/widgets/Number/index.ts +2 -4
  79. package/src/legacy/lib/models/common/widgets/Select/index.ts +2 -4
  80. package/src/legacy/lib/models/common/widgets/StructuredText/index.ts +0 -2
  81. package/src/legacy/lib/models/common/widgets/Text/index.ts +0 -2
  82. package/src/legacy/lib/models/common/widgets/Timestamp/index.ts +2 -4
  83. package/src/legacy/lib/models/common/widgets/UID/index.ts +2 -4
  84. package/src/legacy/lib/models/common/widgets/Widget.ts +10 -3
  85. package/src/legacy/lib/models/common/widgets/groupWidgets.ts +7 -0
  86. package/src/legacy/lib/models/common/widgets/index.ts +7 -31
  87. package/src/legacy/lib/models/common/widgets/nonGroupWidgets.ts +33 -0
  88. package/test/lib/builders/buildersUtils.test.ts +1 -1
  89. package/test/lib/models/common/widgets/index.test.ts +1 -1
  90. package/tsconfig.json +0 -1
  91. package/out/_next/static/JGphUg6eFq0-W11Pa7cMU/_buildManifest.js +0 -1
  92. package/out/_next/static/chunks/18539003-eda642ad962ef598.js +0 -22
  93. package/out/_next/static/chunks/264-4bb6f3fb14863ef3.js +0 -1
  94. package/out/_next/static/chunks/574-6039c48fbc93b4a8.js +0 -1
  95. package/out/_next/static/chunks/59b4e022-7a3b5554b806349f.js +0 -1
  96. package/out/_next/static/chunks/756-1e44fe84bedc262b.js +0 -10
  97. package/out/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js +0 -1
  98. package/out/_next/static/chunks/pages/_app-05ac13d573829b68.js +0 -532
  99. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-996e20b9b295a912.js +0 -1
  100. package/out/_next/static/css/b3bb731ce567d63f.css +0 -1
  101. package/src/legacy/lib/builders/common/SelectFieldTypeModal/FieldTypeCard.jsx +0 -51
  102. package/src/legacy/lib/builders/common/SelectFieldTypeModal/index.jsx +0 -84
  103. package/src/legacy/lib/models/common/widgets/Group/index.ts +0 -44
  104. package/src/legacy/lib/models/common/widgets/ctBuilderArray.ts +0 -20
  105. package/src/legacy/lib/models/common/widgets/groupBuilderArray.ts +0 -18
  106. package/src/legacy/lib/models/common/widgets/sliceBuilderArray.ts +0 -19
  107. package/src/legacy/lib/models/common/widgets/withGroup.ts +0 -2
  108. /package/out/_next/static/{JGphUg6eFq0-W11Pa7cMU → lnoCw12ueMqf698VD8pfN}/_ssgManifest.js +0 -0
@@ -0,0 +1,46 @@
1
+ import {
2
+ Dialog,
3
+ DialogActions,
4
+ DialogContent,
5
+ DialogHeader,
6
+ } from "@prismicio/editor-ui";
7
+
8
+ import { useOnboardingContext } from "@/features/onboarding/OnboardingProvider";
9
+ import { OnboardingStepDialogContent } from "@/features/onboarding/OnboardingStepDialog/OnboardingStepDialogContent";
10
+ import type { OnboardingStep } from "@/features/onboarding/types";
11
+
12
+ type OnboardingStepDialogProps = {
13
+ step: OnboardingStep;
14
+ isOpen: boolean;
15
+ onClose: () => void;
16
+ };
17
+
18
+ export const OnboardingStepDialog = ({
19
+ step,
20
+ isOpen,
21
+ onClose,
22
+ }: OnboardingStepDialogProps) => {
23
+ const { toggleStepComplete, isStepComplete } = useOnboardingContext();
24
+
25
+ const markAsDone = () => {
26
+ if (!isOpen) return;
27
+ toggleStepComplete(step.id);
28
+ onClose();
29
+ };
30
+
31
+ return (
32
+ <Dialog open={isOpen} onOpenChange={onClose}>
33
+ <DialogHeader title="Learn" />
34
+ <DialogContent>
35
+ <OnboardingStepDialogContent step={step} />
36
+ <DialogActions
37
+ ok={{
38
+ text: isStepComplete(step.id) ? "Undo step" : "Mark as done",
39
+ onClick: markAsDone,
40
+ }}
41
+ cancel={{ text: "Close" }}
42
+ />
43
+ </DialogContent>
44
+ </Dialog>
45
+ );
46
+ };
@@ -0,0 +1,38 @@
1
+ import { Box, ScrollArea, Text, Video } from "@prismicio/editor-ui";
2
+
3
+ import { getOnboardingStepsContent } from "@/features/onboarding/content";
4
+ import { useOnboardingContext } from "@/features/onboarding/OnboardingProvider";
5
+ import { OnboardingStep } from "@/features/onboarding/types";
6
+ import { useRepositoryInformation } from "@/hooks/useRepositoryInformation";
7
+
8
+ type OnboardingStepDialogContentProps = {
9
+ step: OnboardingStep;
10
+ };
11
+
12
+ export const OnboardingStepDialogContent = ({
13
+ step,
14
+ }: OnboardingStepDialogContentProps) => {
15
+ const { getStepIndex } = useOnboardingContext();
16
+ const { repositoryUrl } = useRepositoryInformation();
17
+
18
+ const {
19
+ content: Content,
20
+ videoUrl,
21
+ title,
22
+ } = getOnboardingStepsContent({ repositoryUrl })[step.id];
23
+
24
+ return (
25
+ <ScrollArea>
26
+ <Box as="article" flexDirection="column" padding={16} gap={16}>
27
+ <section>
28
+ <Text sx={{ marginBottom: 4 }} color="purple9" variant="bold">
29
+ Step {getStepIndex(step.id) + 1}
30
+ </Text>
31
+ <Text variant="h3">{title}</Text>
32
+ <Content />
33
+ </section>
34
+ <Video src={videoUrl} sizing="contain" autoPlay loop />
35
+ </Box>
36
+ </ScrollArea>
37
+ );
38
+ };
@@ -0,0 +1 @@
1
+ export { OnboardingStepDialog } from "./OnboardingStepDialog";
@@ -0,0 +1,115 @@
1
+ import { Text } from "@prismicio/editor-ui";
2
+
3
+ import type {
4
+ OnboardingStep,
5
+ OnboardingStepContentDefinition,
6
+ OnboardingStepType,
7
+ } from "@/features/onboarding/types";
8
+
9
+ export const onboardingSteps: OnboardingStep[] = [
10
+ {
11
+ id: "createPage",
12
+ title: "Create Your Page",
13
+ description: "Setup a new page.",
14
+ },
15
+ {
16
+ id: "codePage",
17
+ title: "Code your page",
18
+ description: "Build your page's structure",
19
+ },
20
+ {
21
+ id: "addSlice",
22
+ title: "Add a Slice",
23
+ description: "Insert reusable sections.",
24
+ },
25
+ {
26
+ id: "pushModels",
27
+ title: "Push Your Models",
28
+ description: "Deploy your models.",
29
+ },
30
+ {
31
+ id: "writeContent",
32
+ title: "Write Content",
33
+ description: "Add engaging content.",
34
+ },
35
+ ];
36
+
37
+ type GetOnboardingStepsContentProps = {
38
+ repositoryUrl: string;
39
+ };
40
+
41
+ export const getOnboardingStepsContent = ({
42
+ repositoryUrl,
43
+ }: GetOnboardingStepsContentProps): Record<
44
+ OnboardingStepType,
45
+ OnboardingStepContentDefinition
46
+ > => ({
47
+ createPage: {
48
+ videoUrl:
49
+ "https://res.cloudinary.com/dmtf1daqp/video/upload/v1700213517/IN-APP-GUIDE-SM/ADD_SLICE.mp4",
50
+ content: () => (
51
+ <Text>
52
+ Commodo irure ipsum exercitation consequat enim velit amet commodo.
53
+ Excepteur proident Lorem sunt enim amet tempor qui Lorem non non Lorem.
54
+ Ex sint elit ea. Proident veniam dolor cupidatat amet aute consectetur.
55
+ Non ad consectetur irure adipisicing aliquip. Ipsum nulla velit mollit
56
+ magna aliqua eu veniam. Commodo elit labore veniam nulla dolor aliqua
57
+ esse proident pariatur nostrud.
58
+ </Text>
59
+ ),
60
+ },
61
+ codePage: {
62
+ videoUrl:
63
+ "https://res.cloudinary.com/dmtf1daqp/video/upload/v1700213517/IN-APP-GUIDE-SM/CODE_SNIP.mp4",
64
+ content: () => (
65
+ <Text>
66
+ Nulla consequat occaecat ut ut ex culpa veniam sunt nisi nisi. Velit
67
+ excepteur excepteur do anim incididunt in cillum ullamco occaecat minim
68
+ reprehenderit eu enim. Nulla irure est fugiat aliqua elit excepteur
69
+ labore ipsum occaecat eu minim duis non sit. Ea eu irure dolore duis
70
+ labore ad. Quis sunt eu commodo sit nisi ullamco qui aliqua nostrud
71
+ labore nostrud ut nostrud nostrud.
72
+ </Text>
73
+ ),
74
+ },
75
+ addSlice: {
76
+ videoUrl:
77
+ "https://res.cloudinary.com/dmtf1daqp/video/upload/v1700213517/IN-APP-GUIDE-SM/PUSH.mp4",
78
+ content: () => (
79
+ <Text>
80
+ Minim anim velit laboris cupidatat cupidatat culpa labore sunt eiusmod.
81
+ Consequat culpa mollit enim dolore aliquip ex voluptate ex eiusmod
82
+ incididunt eu. Cillum magna cillum magna consectetur. Id aliquip
83
+ excepteur adipisicing officia excepteur et pariatur aliquip aliquip
84
+ laborum.
85
+ </Text>
86
+ ),
87
+ },
88
+ pushModels: {
89
+ videoUrl:
90
+ "https://res.cloudinary.com/dmtf1daqp/video/upload/v1700213517/IN-APP-GUIDE-SM/PREVIEW.mp4",
91
+ content: () => (
92
+ <Text>
93
+ Ipsum aliqua do consequat eiusmod id. Reprehenderit consectetur sit
94
+ officia consequat velit non officia aliquip laboris incididunt cillum
95
+ proident incididunt. Ad quis laborum tempor dolor duis ea cillum aliqua
96
+ occaecat. Sunt reprehenderit fugiat et ullamco proident pariatur
97
+ deserunt minim. Irure enim nulla et ad ut id anim elit. Voluptate culpa
98
+ esse qui et reprehenderit aute est.
99
+ </Text>
100
+ ),
101
+ },
102
+ writeContent: {
103
+ videoUrl:
104
+ "https://res.cloudinary.com/dmtf1daqp/video/upload/v1700213517/IN-APP-GUIDE-SM/WRITE.mp4",
105
+ content: () => (
106
+ <Text>
107
+ Open your{" "}
108
+ <Text href={repositoryUrl} underline>
109
+ Page Builder
110
+ </Text>
111
+ , create a page, add slices, save, and publish. Then, come back here.
112
+ </Text>
113
+ ),
114
+ },
115
+ });
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+
3
+ export const onboardingStepStatusesSchema = z.object({
4
+ createPage: z.boolean(),
5
+ codePage: z.boolean(),
6
+ addSlice: z.boolean(),
7
+ writeContent: z.boolean(),
8
+ pushModels: z.boolean(),
9
+ });
10
+
11
+ export type OnboardingStepStatuses = z.infer<
12
+ typeof onboardingStepStatusesSchema
13
+ >;
14
+
15
+ export type OnboardingStepType = keyof OnboardingStepStatuses;
16
+
17
+ export type OnboardingStep = {
18
+ id: OnboardingStepType;
19
+ title: string;
20
+ description: string;
21
+ };
22
+
23
+ export type OnboardingStepContentDefinition = {
24
+ title?: string;
25
+ content: () => JSX.Element;
26
+ videoUrl: string;
27
+ };
28
+
29
+ export type OnboardingStepContent = Record<
30
+ OnboardingStepType,
31
+ OnboardingStepContentDefinition
32
+ >;
@@ -0,0 +1,6 @@
1
+ import { useExperimentVariant } from "@/hooks/useExperimentVariant";
2
+
3
+ export const useOnboardingExperiment = () => {
4
+ const variant = useExperimentVariant("slice-machine-onboarding");
5
+ return { eligible: variant?.value === "on" };
6
+ };
@@ -0,0 +1,8 @@
1
+ import { useExperimentVariant } from "@/hooks/useExperimentVariant";
2
+
3
+ type UseNestedGroupExperimentReturnType = { eligible: boolean };
4
+
5
+ export function useNestedGroupExperiment(): UseNestedGroupExperimentReturnType {
6
+ const variant = useExperimentVariant("slicemachine-nested-groups");
7
+ return { eligible: variant?.value === "on" };
8
+ }
@@ -1,20 +1,37 @@
1
1
  import { Dispatch, SetStateAction, useEffect, useState } from "react";
2
+ import { ZodType, ZodTypeDef } from "zod";
2
3
 
3
4
  type PersistedState<T> = [T, Dispatch<SetStateAction<T>>];
4
5
 
5
6
  const SLICE_MACHINE_STORAGE_PREFIX = "slice-machine";
6
7
 
8
+ type UsePersistedStateOptions<T> = {
9
+ schema?: ZodType<T, ZodTypeDef, unknown>;
10
+ };
11
+
12
+ export function usePersistedState<T>(
13
+ key: string,
14
+ ): PersistedState<T | undefined>;
7
15
  export function usePersistedState<T>(
8
16
  key: string,
9
17
  defaultValue: T,
10
- ): PersistedState<T> {
18
+ options?: UsePersistedStateOptions<T>,
19
+ ): PersistedState<T>;
20
+ export function usePersistedState<T>(
21
+ key: string,
22
+ defaultValue?: T,
23
+ options?: UsePersistedStateOptions<T>,
24
+ ): PersistedState<T | undefined> {
25
+ const { schema } = options ?? {};
11
26
  const computedKey = `${SLICE_MACHINE_STORAGE_PREFIX}_${key}`;
12
27
 
13
- const [value, setValue] = useState<T>(() => {
28
+ const [value, setValue] = useState<T | undefined>(() => {
14
29
  try {
15
30
  const value = localStorage.getItem(computedKey);
16
31
 
17
- return value !== null ? (JSON.parse(value) as T) : defaultValue;
32
+ if (value == null) return defaultValue;
33
+ if (!schema) return JSON.parse(value) as T;
34
+ return schema.parse(JSON.parse(value));
18
35
  } catch (error) {
19
36
  console.warn(`Error reading localStorage key “${computedKey}”:`, error);
20
37
 
@@ -14,7 +14,7 @@ import Li from "../Li";
14
14
  import SliceMachineIconButton from "../SliceMachineIconButton";
15
15
  import ItemHeader from "./Header";
16
16
 
17
- type Item<F extends TabField> = { key: string; value: F };
17
+ export type Item<F extends TabField> = { key: string; value: F };
18
18
 
19
19
  interface ListItemProps<F extends TabField, S extends AnyObjectSchema> {
20
20
  item: Item<F>;
@@ -17,6 +17,7 @@ import { ErrorBoundary } from "@/ErrorBoundary";
17
17
  import { CUSTOM_TYPES_CONFIG } from "@/features/customTypes/customTypesConfig";
18
18
  import { CUSTOM_TYPES_MESSAGES } from "@/features/customTypes/customTypesMessages";
19
19
  import { MasterSliceLibraryPreviewModal } from "@/features/masterSliceLibrary/SliceLibraryPreviewModal";
20
+ import { OnboardingGuide } from "@/features/onboarding/OnboardingGuide";
20
21
  import { useGitIntegrationExperiment } from "@/features/settings/git/useGitIntegrationExperiment";
21
22
  import { useMarketingContent } from "@/hooks/useMarketingContent";
22
23
  import { useRepositoryInformation } from "@/hooks/useRepositoryInformation";
@@ -123,6 +124,7 @@ const Navigation: FC = () => {
123
124
  </ErrorBoundary>
124
125
 
125
126
  <SideNavList position="bottom">
127
+ <OnboardingGuide />
126
128
  {masterSliceLibrary !== undefined && (
127
129
  <SideNavListItem>
128
130
  <MasterSliceLibraryPreviewModal
@@ -30,7 +30,7 @@ import {
30
30
  TabFieldsModel,
31
31
  TabSM,
32
32
  } from "@/legacy/lib/models/common/CustomType";
33
- import ctBuilderArray from "@/legacy/lib/models/common/widgets/ctBuilderArray";
33
+ import { Widgets } from "@/legacy/lib/models/common/widgets";
34
34
  import type { AnyWidget } from "@/legacy/lib/models/common/widgets/Widget";
35
35
  import {
36
36
  ensureDnDDestination,
@@ -39,11 +39,30 @@ import {
39
39
  import { transformKeyAccessor } from "@/legacy/lib/utils/str";
40
40
  import { getContentTypeForTracking } from "@/utils/getContentTypeForTracking";
41
41
 
42
- import * as Widgets from "../../../../lib/models/common/widgets/withGroup";
43
42
  import EditModal from "../../common/EditModal";
44
43
  import Zone from "../../common/Zone";
45
44
  import SliceZone from "../SliceZone";
46
45
 
46
+ const widgetsArray = [
47
+ Widgets.UID,
48
+ Widgets.Image,
49
+ Widgets.Text,
50
+ Widgets.StructuredText,
51
+ Widgets.Link,
52
+ Widgets.Select,
53
+ Widgets.Boolean,
54
+ Widgets.Number,
55
+ Widgets.Color,
56
+ Widgets.Date,
57
+ Widgets.Embed,
58
+ Widgets.Timestamp,
59
+ Widgets.GeoPoint,
60
+ Widgets.ContentRelationship,
61
+ Widgets.LinkToMedia,
62
+ Widgets.Group,
63
+ Widgets.NestedGroup,
64
+ ];
65
+
47
66
  interface TabZoneProps {
48
67
  tabId: string;
49
68
  }
@@ -227,7 +246,7 @@ const TabZone: FC<TabZoneProps> = ({ tabId }) => {
227
246
  poolOfFieldsToCheck={poolOfFields}
228
247
  showHints={true}
229
248
  EditModal={EditModal}
230
- widgetsArray={ctBuilderArray}
249
+ widgetsArray={widgetsArray}
231
250
  onDeleteItem={onDeleteItem}
232
251
  onSave={onSave}
233
252
  onSaveNewField={onSaveNewField}
@@ -242,7 +261,6 @@ const TabZone: FC<TabZoneProps> = ({ tabId }) => {
242
261
  }
243
262
  testId="static-zone-content"
244
263
  isRepeatableCustomType={customType.repeatable}
245
- emptyStateActionTestId="add-Static-field"
246
264
  />
247
265
  ) : undefined}
248
266
 
@@ -27,9 +27,7 @@ import {
27
27
  SlicePrimaryFieldSM,
28
28
  WidgetsArea,
29
29
  } from "@/legacy/lib/models/common/Slice";
30
- import * as Widgets from "@/legacy/lib/models/common/widgets";
31
- import groupBuilderWidgetsArray from "@/legacy/lib/models/common/widgets/groupBuilderArray";
32
- import sliceBuilderWidgetsArray from "@/legacy/lib/models/common/widgets/sliceBuilderArray";
30
+ import { Widgets } from "@/legacy/lib/models/common/widgets";
33
31
  import { ensureDnDDestination } from "@/legacy/lib/utils";
34
32
  import { transformKeyAccessor } from "@/legacy/lib/utils/str";
35
33
  import { getContentTypeForTracking } from "@/utils/getContentTypeForTracking";
@@ -42,6 +40,25 @@ const dataTipText2 = `The repeatable zone is for a group<br/>
42
40
  of fields that you want to be able to repeat an<br/>
43
41
  indeterminate number of times, like FAQs`;
44
42
 
43
+ const itemsWidgetsArray = [
44
+ Widgets.Image,
45
+ Widgets.Text,
46
+ Widgets.StructuredText,
47
+ Widgets.Link,
48
+ Widgets.Select,
49
+ Widgets.Boolean,
50
+ Widgets.Number,
51
+ Widgets.Color,
52
+ Widgets.Date,
53
+ Widgets.Embed,
54
+ Widgets.Timestamp,
55
+ Widgets.GeoPoint,
56
+ Widgets.ContentRelationship,
57
+ Widgets.LinkToMedia,
58
+ ];
59
+
60
+ const primaryWidgetsArray = [Widgets.Group, ...itemsWidgetsArray];
61
+
45
62
  const FieldZones: FC = () => {
46
63
  const { slice, setSlice, variation } = useSliceState();
47
64
  const [
@@ -110,7 +127,7 @@ const FieldZones: FC = () => {
110
127
  label: string;
111
128
  widgetTypeName: keyof typeof Widgets;
112
129
  }) => {
113
- const widget = sliceBuilderWidgetsArray.find(
130
+ const widget = primaryWidgetsArray.find(
114
131
  (sliceBuilderWidget) =>
115
132
  sliceBuilderWidget.CUSTOM_NAME === widgetTypeName ||
116
133
  sliceBuilderWidget.TYPE_NAME === widgetTypeName,
@@ -188,7 +205,7 @@ const FieldZones: FC = () => {
188
205
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
189
206
  fields={variation.primary}
190
207
  EditModal={EditModal}
191
- widgetsArray={sliceBuilderWidgetsArray}
208
+ widgetsArray={primaryWidgetsArray}
192
209
  onDeleteItem={_onDeleteItem(WidgetsArea.Primary)}
193
210
  onSave={_onSave(WidgetsArea.Primary)}
194
211
  onSaveNewField={_onSaveNewField(WidgetsArea.Primary)}
@@ -206,7 +223,6 @@ const FieldZones: FC = () => {
206
223
  testId="static-zone-content"
207
224
  isRepeatableCustomType={undefined}
208
225
  emptyStateHeading={undefined}
209
- emptyStateActionTestId="add-Static-field"
210
226
  />
211
227
  {hasItems ? (
212
228
  <Zone
@@ -216,7 +232,7 @@ const FieldZones: FC = () => {
216
232
  isRepeatable
217
233
  title="Repeatable Zone"
218
234
  dataTip={dataTipText2}
219
- widgetsArray={groupBuilderWidgetsArray}
235
+ widgetsArray={itemsWidgetsArray}
220
236
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
221
237
  fields={variation.items}
222
238
  EditModal={EditModal}
@@ -235,7 +251,6 @@ const FieldZones: FC = () => {
235
251
  testId="slice-repeatable-zone"
236
252
  isRepeatableCustomType={undefined}
237
253
  emptyStateHeading="No fields"
238
- emptyStateActionTestId="add-Repeatable-field"
239
254
  />
240
255
  ) : null}
241
256
  <Dialog
@@ -60,7 +60,9 @@ export const VariationsList: FC<VariationsListProps> = (props) => {
60
60
  }}
61
61
  startIcon="add"
62
62
  color="grey"
63
- />
63
+ >
64
+ Add a variation
65
+ </Button>
64
66
  </Box>
65
67
  <div
66
68
  className={styles.hideScrollbar}
@@ -124,7 +126,7 @@ export const VariationsList: FC<VariationsListProps> = (props) => {
124
126
  // `Gradient`.
125
127
  sx={{ position: "relative" }}
126
128
  >
127
- Add a new variation
129
+ Add a variation
128
130
  </Button>
129
131
  </Box>
130
132
  </div>
@@ -203,6 +205,7 @@ export const SharedSliceCards = (props: SharedSliceCardsProps) => {
203
205
  <>
204
206
  {slice.model.variations.map((v) => (
205
207
  <div
208
+ key={v.id}
206
209
  style={
207
210
  width !== undefined
208
211
  ? { ...defaultCardStyle, width }
@@ -20,7 +20,7 @@ import { VariationsList } from "./VariationsList";
20
20
 
21
21
  export const SliceBuilder: FC = () => {
22
22
  const { slice, actionQueueStatus } = useSliceState();
23
- const horizontalScroll = useMediaQuery({ max: "medium" });
23
+ const horizontalScroll = useMediaQuery({ max: "large" });
24
24
 
25
25
  const contentDisplayProps = horizontalScroll
26
26
  ? { gridTemplateRows: "304px 1fr" }
@@ -11,7 +11,7 @@ import {
11
11
  createInitialValues,
12
12
  } from "@/legacy/lib/forms";
13
13
  import { DeprecatedMockConfigMessage } from "@/legacy/lib/models/common/DeprecatedMockConfigMessage";
14
- import * as Widgets from "@/legacy/lib/models/common/widgets/withGroup";
14
+ import { Widgets } from "@/legacy/lib/models/common/widgets";
15
15
  import { removeProp } from "@/legacy/lib/utils";
16
16
 
17
17
  import { findWidgetByConfigOrType } from "../../utils";
@@ -9,9 +9,15 @@ interface HintProps {
9
9
  show: boolean;
10
10
  item: Item;
11
11
  renderHintBase: RenderHintBaseFN;
12
+ hintItemName?: string;
12
13
  }
13
14
 
14
- const Hint: React.FC<HintProps> = ({ show, renderHintBase, item }) => {
15
+ const Hint: React.FC<HintProps> = ({
16
+ show,
17
+ renderHintBase,
18
+ item,
19
+ hintItemName,
20
+ }) => {
15
21
  const fieldPathString = renderHintBase({ item });
16
22
 
17
23
  // TODO: Call `swr`'s global `mutate` function when something changes to clear the cache.
@@ -20,6 +26,7 @@ const Hint: React.FC<HintProps> = ({ show, renderHintBase, item }) => {
20
26
  return await managerClient.snippets.readSnippets({
21
27
  fieldPath: fieldPathString.split("."),
22
28
  model: item.value,
29
+ itemName: hintItemName,
23
30
  });
24
31
  });
25
32
 
@@ -15,8 +15,8 @@ import {
15
15
  } from "@/legacy/lib/forms";
16
16
  import { validateId } from "@/legacy/lib/forms/defaults";
17
17
  import { InputType } from "@/legacy/lib/forms/fields";
18
+ import { Widgets } from "@/legacy/lib/models/common/widgets";
18
19
  import { AnyWidget } from "@/legacy/lib/models/common/widgets/Widget";
19
- import * as Widgets from "@/legacy/lib/models/common/widgets/withGroup";
20
20
  import { slugify } from "@/legacy/lib/utils/str";
21
21
 
22
22
  import { ErrorTooltip } from "./ErrorTooltip";
@@ -3,7 +3,7 @@ import { Box, Text } from "theme-ui";
3
3
 
4
4
  import Li from "@/legacy/components/Li";
5
5
  import ListItem from "@/legacy/components/ListItem";
6
- import * as Widgets from "@/legacy/lib/models/common/widgets/withGroup";
6
+ import { Widgets } from "@/legacy/lib/models/common/widgets";
7
7
 
8
8
  import { findWidgetByConfigOrType } from "../../../utils";
9
9
  import Hint from "./components/Hints";
@@ -103,6 +103,8 @@ const FieldZone = ({
103
103
  isRepeatable={isRepeatable}
104
104
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
105
105
  renderHintBase={renderHintBase}
106
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
107
+ hintItemName={widget.hintItemName}
106
108
  Widgets={Widgets}
107
109
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/strict-boolean-expressions
108
110
  typeName={widget.CUSTOM_NAME || widget.TYPE_NAME}
@@ -1,4 +1,4 @@
1
- import { Button, Text } from "@prismicio/editor-ui";
1
+ import { Text } from "@prismicio/editor-ui";
2
2
  import { FC, ReactNode } from "react";
3
3
 
4
4
  import styles from "./ZoneEmptyState.module.css";
@@ -6,16 +6,14 @@ import styles from "./ZoneEmptyState.module.css";
6
6
  type ZoneEmptyStateProps = {
7
7
  zoneType: "custom type" | "page type" | "slice";
8
8
  heading?: ReactNode;
9
- onActionClick: () => void;
10
- actionTestId?: string;
9
+ action: ReactNode;
11
10
  };
12
11
 
13
12
  export const ZoneEmptyState: FC<ZoneEmptyStateProps> = (props) => {
14
13
  const {
15
14
  zoneType,
16
15
  heading = `Your ${zoneType} has no fields yet`,
17
- onActionClick,
18
- actionTestId,
16
+ action,
19
17
  } = props;
20
18
 
21
19
  return (
@@ -26,14 +24,7 @@ export const ZoneEmptyState: FC<ZoneEmptyStateProps> = (props) => {
26
24
  A field is an input for content (e.g. text, images, links).
27
25
  </Text>
28
26
  </div>
29
- <Button
30
- color="grey"
31
- onClick={() => onActionClick()}
32
- data-testid={actionTestId}
33
- startIcon="add"
34
- >
35
- Add a field
36
- </Button>
27
+ {action}
37
28
  </div>
38
29
  );
39
30
  };