slice-machine-ui 2.2.2-beta.7 → 2.2.2-beta.9

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 (58) hide show
  1. package/out/404.html +1 -1
  2. package/out/_next/static/chunks/{18539003-36b102fa41de015e.js → 18539003-e38c98b473d02623.js} +15 -15
  3. package/out/_next/static/chunks/{448-7a6843206737d199.js → 448-a070e845a4500277.js} +1 -1
  4. package/out/_next/static/chunks/574-a391e2fe8084b1c3.js +1 -0
  5. package/out/_next/static/chunks/59b4e022-8e544a511d670317.js +1 -0
  6. package/out/_next/static/chunks/{756-98ae0a6e755f46f2.js → 756-0b198fb40a3e6ae2.js} +1 -1
  7. package/out/_next/static/chunks/f36c6662-1f3a854183168b10.js +1 -0
  8. package/out/_next/static/chunks/pages/{_app-0f0734868b7ca036.js → _app-6fdb10a504e07048.js} +136 -128
  9. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-7009aed51761c5eb.js +1 -0
  10. package/out/_next/static/css/82c8c4f05b25d3af.css +1 -0
  11. package/out/_next/static/{rR92D-aW4fdcXgyhx4sDS → uy_u3vlXV2zWs0MNOVlac}/_buildManifest.js +1 -1
  12. package/out/changelog.html +1 -1
  13. package/out/changes.html +1 -1
  14. package/out/custom-types/[customTypeId].html +1 -1
  15. package/out/custom-types.html +1 -1
  16. package/out/index.html +1 -1
  17. package/out/labs.html +1 -1
  18. package/out/page-types/[pageTypeId].html +1 -1
  19. package/out/settings.html +1 -1
  20. package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  21. package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
  22. package/out/slices.html +1 -1
  23. package/package.json +6 -6
  24. package/src/domain/fields.ts +223 -0
  25. package/src/features/builder/AddFieldDropdown.tsx +119 -0
  26. package/src/legacy/lib/builders/CustomTypeBuilder/TabZone/index.tsx +9 -9
  27. package/src/legacy/lib/builders/SliceBuilder/FieldZones/index.tsx +7 -9
  28. package/src/legacy/lib/builders/SliceBuilder/VariationsList/index.tsx +1 -0
  29. package/src/legacy/lib/builders/common/Zone/components/ZoneEmptyState/ZoneEmptyState.tsx +4 -13
  30. package/src/legacy/lib/builders/common/Zone/index.jsx +26 -31
  31. package/src/legacy/lib/models/common/widgets/Boolean/index.ts +2 -4
  32. package/src/legacy/lib/models/common/widgets/Color/index.ts +2 -4
  33. package/src/legacy/lib/models/common/widgets/ContentRelationship/index.ts +0 -2
  34. package/src/legacy/lib/models/common/widgets/Date/index.ts +0 -2
  35. package/src/legacy/lib/models/common/widgets/Embed/index.ts +2 -4
  36. package/src/legacy/lib/models/common/widgets/GeoPoint/index.ts +2 -4
  37. package/src/legacy/lib/models/common/widgets/Group/ListItem/index.jsx +25 -19
  38. package/src/legacy/lib/models/common/widgets/Group/createGroupWidget.ts +2 -4
  39. package/src/legacy/lib/models/common/widgets/Group/index.tsx +8 -8
  40. package/src/legacy/lib/models/common/widgets/Image/index.ts +2 -4
  41. package/src/legacy/lib/models/common/widgets/Link/index.ts +2 -4
  42. package/src/legacy/lib/models/common/widgets/LinkToMedia/index.ts +2 -4
  43. package/src/legacy/lib/models/common/widgets/NestedGroup/index.tsx +7 -7
  44. package/src/legacy/lib/models/common/widgets/Number/index.ts +2 -4
  45. package/src/legacy/lib/models/common/widgets/Select/index.ts +2 -4
  46. package/src/legacy/lib/models/common/widgets/StructuredText/index.ts +0 -2
  47. package/src/legacy/lib/models/common/widgets/Text/index.ts +0 -2
  48. package/src/legacy/lib/models/common/widgets/Timestamp/index.ts +2 -4
  49. package/src/legacy/lib/models/common/widgets/UID/index.ts +2 -4
  50. package/src/legacy/lib/models/common/widgets/Widget.ts +0 -2
  51. package/out/_next/static/chunks/574-dfeb0e6aa3079da1.js +0 -1
  52. package/out/_next/static/chunks/59b4e022-7a3b5554b806349f.js +0 -1
  53. package/out/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js +0 -1
  54. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-b530a5e0ac9d0391.js +0 -1
  55. package/out/_next/static/css/ee6cd1a80767d31e.css +0 -1
  56. package/src/legacy/lib/builders/common/SelectFieldTypeModal/FieldTypeCard.jsx +0 -51
  57. package/src/legacy/lib/builders/common/SelectFieldTypeModal/index.jsx +0 -84
  58. /package/out/_next/static/{rR92D-aW4fdcXgyhx4sDS → uy_u3vlXV2zWs0MNOVlac}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/ee6cd1a80767d31e.css" as="style"/><link rel="stylesheet" href="/_next/static/css/ee6cd1a80767d31e.css" data-n-g=""/><link rel="preload" href="/_next/static/css/8d1871dce67a3b49.css" as="style"/><link rel="stylesheet" href="/_next/static/css/8d1871dce67a3b49.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-0f0734868b7ca036.js" defer=""></script><script src="/_next/static/chunks/59b4e022-7a3b5554b806349f.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/f36c6662-03bb5e9d9aa0b0aa.js" defer=""></script><script src="/_next/static/chunks/4c744e84-e3161d754618373f.js" defer=""></script><script src="/_next/static/chunks/065a3ddb-9a38ca0d60f0bf2f.js" defer=""></script><script src="/_next/static/chunks/1cc2734a-2c5b6c0367fcde86.js" defer=""></script><script src="/_next/static/chunks/183-6ad1d7303abecd2b.js" defer=""></script><script src="/_next/static/chunks/50-8d014b6d3cc35e30.js" defer=""></script><script src="/_next/static/chunks/543-f8766685f7f451e2.js" defer=""></script><script src="/_next/static/chunks/696-b992b9e1ce75777e.js" defer=""></script><script src="/_next/static/chunks/816-96fc9a79308019c7.js" defer=""></script><script src="/_next/static/chunks/574-dfeb0e6aa3079da1.js" defer=""></script><script src="/_next/static/chunks/152-c40fcb226b0df27f.js" defer=""></script><script src="/_next/static/chunks/pages/slices/%5Blib%5D/%5BsliceName%5D/%5Bvariation%5D-b530a5e0ac9d0391.js" defer=""></script><script src="/_next/static/rR92D-aW4fdcXgyhx4sDS/_buildManifest.js" defer=""></script><script src="/_next/static/rR92D-aW4fdcXgyhx4sDS/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices/[lib]/[sliceName]/[variation]","query":{},"buildId":"rR92D-aW4fdcXgyhx4sDS","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/82c8c4f05b25d3af.css" as="style"/><link rel="stylesheet" href="/_next/static/css/82c8c4f05b25d3af.css" data-n-g=""/><link rel="preload" href="/_next/static/css/8d1871dce67a3b49.css" as="style"/><link rel="stylesheet" href="/_next/static/css/8d1871dce67a3b49.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-6fdb10a504e07048.js" defer=""></script><script src="/_next/static/chunks/59b4e022-8e544a511d670317.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/f36c6662-1f3a854183168b10.js" defer=""></script><script src="/_next/static/chunks/4c744e84-e3161d754618373f.js" defer=""></script><script src="/_next/static/chunks/065a3ddb-9a38ca0d60f0bf2f.js" defer=""></script><script src="/_next/static/chunks/1cc2734a-2c5b6c0367fcde86.js" defer=""></script><script src="/_next/static/chunks/183-6ad1d7303abecd2b.js" defer=""></script><script src="/_next/static/chunks/50-8d014b6d3cc35e30.js" defer=""></script><script src="/_next/static/chunks/543-f8766685f7f451e2.js" defer=""></script><script src="/_next/static/chunks/696-b992b9e1ce75777e.js" defer=""></script><script src="/_next/static/chunks/816-96fc9a79308019c7.js" defer=""></script><script src="/_next/static/chunks/574-a391e2fe8084b1c3.js" defer=""></script><script src="/_next/static/chunks/152-c40fcb226b0df27f.js" defer=""></script><script src="/_next/static/chunks/pages/slices/%5Blib%5D/%5BsliceName%5D/%5Bvariation%5D-7009aed51761c5eb.js" defer=""></script><script src="/_next/static/uy_u3vlXV2zWs0MNOVlac/_buildManifest.js" defer=""></script><script src="/_next/static/uy_u3vlXV2zWs0MNOVlac/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices/[lib]/[sliceName]/[variation]","query":{},"buildId":"uy_u3vlXV2zWs0MNOVlac","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
package/out/slices.html CHANGED
@@ -1 +1 @@
1
- <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/ee6cd1a80767d31e.css" as="style"/><link rel="stylesheet" href="/_next/static/css/ee6cd1a80767d31e.css" data-n-g=""/><link rel="preload" href="/_next/static/css/f01f60095c76c7fb.css" as="style"/><link rel="stylesheet" href="/_next/static/css/f01f60095c76c7fb.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-0f0734868b7ca036.js" defer=""></script><script src="/_next/static/chunks/59b4e022-7a3b5554b806349f.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/50-8d014b6d3cc35e30.js" defer=""></script><script src="/_next/static/chunks/816-96fc9a79308019c7.js" defer=""></script><script src="/_next/static/chunks/152-c40fcb226b0df27f.js" defer=""></script><script src="/_next/static/chunks/pages/slices-7411822d74f1f6c1.js" defer=""></script><script src="/_next/static/rR92D-aW4fdcXgyhx4sDS/_buildManifest.js" defer=""></script><script src="/_next/static/rR92D-aW4fdcXgyhx4sDS/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices","query":{},"buildId":"rR92D-aW4fdcXgyhx4sDS","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1
+ <!DOCTYPE html><html><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="/_next/static/css/82c8c4f05b25d3af.css" as="style"/><link rel="stylesheet" href="/_next/static/css/82c8c4f05b25d3af.css" data-n-g=""/><link rel="preload" href="/_next/static/css/f01f60095c76c7fb.css" as="style"/><link rel="stylesheet" href="/_next/static/css/f01f60095c76c7fb.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="/_next/static/chunks/webpack-2f903acb0cccbf9e.js" defer=""></script><script src="/_next/static/chunks/framework-cdccea7a52cc6e81.js" defer=""></script><script src="/_next/static/chunks/main-207ecb3e9b995dd9.js" defer=""></script><script src="/_next/static/chunks/pages/_app-6fdb10a504e07048.js" defer=""></script><script src="/_next/static/chunks/59b4e022-8e544a511d670317.js" defer=""></script><script src="/_next/static/chunks/c8eae200-966ce352f7b5d2b9.js" defer=""></script><script src="/_next/static/chunks/50-8d014b6d3cc35e30.js" defer=""></script><script src="/_next/static/chunks/816-96fc9a79308019c7.js" defer=""></script><script src="/_next/static/chunks/152-c40fcb226b0df27f.js" defer=""></script><script src="/_next/static/chunks/pages/slices-7411822d74f1f6c1.js" defer=""></script><script src="/_next/static/uy_u3vlXV2zWs0MNOVlac/_buildManifest.js" defer=""></script><script src="/_next/static/uy_u3vlXV2zWs0MNOVlac/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/slices","query":{},"buildId":"uy_u3vlXV2zWs0MNOVlac","runtimeConfig":{"sentryEnvironment":"beta"},"nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slice-machine-ui",
3
- "version": "2.2.2-beta.7",
3
+ "version": "2.2.2-beta.9",
4
4
  "license": "MIT",
5
5
  "description": "A visual builder for your Slice Models with all the tools you need to generate data models and mock CMS content locally.",
6
6
  "repository": {
@@ -35,16 +35,16 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "@radix-ui/react-visually-hidden": "1.0.3",
38
- "@slicemachine/manager": "0.19.4-beta.7",
39
- "start-slicemachine": "0.12.23-beta.7"
38
+ "@slicemachine/manager": "0.19.4-beta.9",
39
+ "start-slicemachine": "0.12.23-beta.9"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@emotion/react": "11.11.1",
43
43
  "@extractus/oembed-extractor": "3.1.8",
44
44
  "@prismicio/client": "7.6.0",
45
- "@prismicio/editor-fields": "0.4.30",
46
- "@prismicio/editor-support": "0.4.30",
47
- "@prismicio/editor-ui": "0.4.30",
45
+ "@prismicio/editor-fields": "0.4.32",
46
+ "@prismicio/editor-support": "0.4.32",
47
+ "@prismicio/editor-ui": "0.4.32",
48
48
  "@prismicio/mock": "0.3.3",
49
49
  "@prismicio/mocks": "2.3.0",
50
50
  "@prismicio/simulator": "0.1.4",
@@ -0,0 +1,223 @@
1
+ import { IconName } from "@prismicio/editor-ui";
2
+ import {
3
+ FieldType,
4
+ NestableFieldTypes,
5
+ } from "@prismicio/types-internal/lib/customtypes";
6
+
7
+ interface BaseField {
8
+ description: string;
9
+ icon: IconName;
10
+ name: string;
11
+ thumbnail: string;
12
+ type: FieldType;
13
+ variant?: FieldVariant;
14
+ }
15
+
16
+ export type NestableFieldVariant = "ContentRelationship" | "LinkToMedia";
17
+ export type GroupFieldVariant = "NestedGroup";
18
+ export type FieldVariant = NestableFieldVariant | GroupFieldVariant;
19
+
20
+ export interface NestableField extends BaseField {
21
+ type: NestableFieldTypes;
22
+ variant?: NestableFieldVariant;
23
+ }
24
+
25
+ export interface UIDField extends BaseField {
26
+ type: "UID";
27
+ variant?: never;
28
+ }
29
+
30
+ export interface GroupField extends BaseField {
31
+ type: "Group";
32
+ variant?: "NestedGroup";
33
+ }
34
+
35
+ export type Field = NestableField | UIDField | GroupField;
36
+
37
+ /**
38
+ * Nestable fields
39
+ */
40
+
41
+ export const booleanField: NestableField = {
42
+ name: "Boolean",
43
+ description: "A true or false toggle.",
44
+ icon: "toggleOff",
45
+ thumbnail:
46
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295526/DEV_TOOLS/SM_FIELDS/Type_Boolean_cbwg8k.png",
47
+ type: "Boolean",
48
+ };
49
+
50
+ export const colorField: NestableField = {
51
+ name: "Color",
52
+ description: "A color in hex format.",
53
+ icon: "colorLens",
54
+ thumbnail:
55
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295521/DEV_TOOLS/SM_FIELDS/Type_Color_nyoeit.png",
56
+ type: "Color",
57
+ };
58
+
59
+ export const dateField: NestableField = {
60
+ name: "Date",
61
+ description: "A date without time.",
62
+ icon: "dateRange",
63
+ thumbnail:
64
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295525/DEV_TOOLS/SM_FIELDS/Type_Date_dsuaeq.png",
65
+ type: "Date",
66
+ };
67
+
68
+ export const embedField: NestableField = {
69
+ name: "Embed",
70
+ description: "A video, song, or oEmbed link.",
71
+ icon: "code",
72
+ thumbnail:
73
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295523/DEV_TOOLS/SM_FIELDS/Type_Embed_wwssvd.png",
74
+ type: "Embed",
75
+ };
76
+
77
+ export const geoPointField: NestableField = {
78
+ name: "Geopoint",
79
+ description: "A geographical coordinate.",
80
+ icon: "place",
81
+ thumbnail:
82
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295522/DEV_TOOLS/SM_FIELDS/Type_GeoPoint_lpq0sm.png",
83
+ type: "GeoPoint",
84
+ };
85
+
86
+ export const imageField: NestableField = {
87
+ name: "Image",
88
+ description: "A responsive image.",
89
+ icon: "image",
90
+ thumbnail:
91
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295520/DEV_TOOLS/SM_FIELDS/Type_Image_zyatxy.png",
92
+ type: "Image",
93
+ };
94
+
95
+ export const LinkField: NestableField = {
96
+ name: "Link",
97
+ description: "A link to a website, asset, or document.",
98
+ icon: "link",
99
+ thumbnail:
100
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295528/DEV_TOOLS/SM_FIELDS/Type_Link_bgslgy.png",
101
+ type: "Link",
102
+ };
103
+
104
+ export const contentRelationshipField: NestableField = {
105
+ name: "Content Relationship",
106
+ description: "A reference to a Prismic document.",
107
+ icon: "settingsEthernet",
108
+ thumbnail:
109
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295527/DEV_TOOLS/SM_FIELDS/Type_Content_RelationShip_s4z4nh.png",
110
+ type: "Link",
111
+ variant: "ContentRelationship",
112
+ };
113
+
114
+ export const LinkToMediaField: NestableField = {
115
+ name: "Link To Media",
116
+ description: "A link to a media asset.",
117
+ icon: "attachFile",
118
+ thumbnail:
119
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295519/DEV_TOOLS/SM_FIELDS/Type_LinkToMedia_m2p0ce.png",
120
+ type: "Link",
121
+ variant: "LinkToMedia",
122
+ };
123
+
124
+ export const numberField: NestableField = {
125
+ name: "Number",
126
+ description: "An integer or float.",
127
+ icon: "pin",
128
+ thumbnail:
129
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295522/DEV_TOOLS/SM_FIELDS/Type_Number_o3olop.png",
130
+ type: "Number",
131
+ };
132
+
133
+ export const selectField: NestableField = {
134
+ name: "Select",
135
+ description: "A dropdown of options.",
136
+ icon: "arrowDropDownCircle",
137
+ thumbnail:
138
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295527/DEV_TOOLS/SM_FIELDS/Type_Select_bedjei.png",
139
+ type: "Select",
140
+ };
141
+
142
+ export const richTextField: NestableField = {
143
+ name: "Rich Text",
144
+ description: "Text with formatting options.",
145
+ icon: "textFields",
146
+ thumbnail:
147
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295530/DEV_TOOLS/SM_FIELDS/Type_Rich_Text_fxdyar.png",
148
+ type: "StructuredText",
149
+ };
150
+
151
+ export const textField: NestableField = {
152
+ name: "Text",
153
+ description: "A text string without formatting.",
154
+ icon: "title",
155
+ thumbnail:
156
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295529/DEV_TOOLS/SM_FIELDS/Type_Key_Text_xrqf45.png",
157
+ type: "Text",
158
+ };
159
+
160
+ export const timestampField: NestableField = {
161
+ name: "Timestamp",
162
+ description: "A date and time.",
163
+ icon: "schedule",
164
+ thumbnail:
165
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295524/DEV_TOOLS/SM_FIELDS/Type_Timestamp_fkr5iw.png",
166
+ type: "Timestamp",
167
+ };
168
+
169
+ export const nestableFields: NestableField[] = [
170
+ imageField,
171
+ textField,
172
+ richTextField,
173
+ booleanField,
174
+ numberField,
175
+ selectField,
176
+ LinkField,
177
+ LinkToMediaField,
178
+ colorField,
179
+ dateField,
180
+ timestampField,
181
+ embedField,
182
+ geoPointField,
183
+ contentRelationshipField,
184
+ ];
185
+
186
+ /**
187
+ * UID
188
+ */
189
+
190
+ export const UIDField: UIDField = {
191
+ name: "UID",
192
+ description: "Unique Identifier",
193
+ icon: "tag",
194
+ thumbnail:
195
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721295519/DEV_TOOLS/SM_FIELDS/Type_UID_hrwzug.png",
196
+ type: "UID",
197
+ };
198
+
199
+ /**
200
+ * Group
201
+ */
202
+
203
+ export const groupField: GroupField = {
204
+ name: "Repeatable Group",
205
+ description: "A set of fields that editors can repeat.",
206
+ icon: "createNewFolder",
207
+ thumbnail:
208
+ "https://res.cloudinary.com/dmtf1daqp/image/upload/v1721314577/DEV_TOOLS/SM_FIELDS/Type_Group_uwwco0.png",
209
+ type: "Group",
210
+ };
211
+
212
+ export const nestedGroupField: GroupField = {
213
+ ...groupField,
214
+ variant: "NestedGroup",
215
+ };
216
+
217
+ export const groupFields: GroupField[] = [groupField, nestedGroupField];
218
+
219
+ /**
220
+ * All fields
221
+ */
222
+
223
+ export const fields = [...nestableFields, UIDField, ...groupFields];
@@ -0,0 +1,119 @@
1
+ import {
2
+ Button,
3
+ DropdownMenu,
4
+ DropdownMenuContent,
5
+ DropdownMenuItem,
6
+ DropdownMenuLabel,
7
+ DropdownMenuTrigger,
8
+ Icon,
9
+ Image,
10
+ Text,
11
+ Tooltip,
12
+ } from "@prismicio/editor-ui";
13
+ import { FieldType } from "@prismicio/types-internal/lib/customtypes";
14
+
15
+ import {
16
+ Field,
17
+ FieldVariant,
18
+ groupField,
19
+ nestableFields,
20
+ UIDField,
21
+ } from "@/domain/fields";
22
+
23
+ interface AddFieldDropdownProps {
24
+ disabled: boolean;
25
+ onSelectField: (fieldType: FieldType | FieldVariant) => void;
26
+ fields: Field[];
27
+ triggerDataTestId?: string;
28
+ }
29
+
30
+ export function AddFieldDropdown(props: AddFieldDropdownProps) {
31
+ const {
32
+ disabled,
33
+ onSelectField,
34
+ fields,
35
+ triggerDataTestId = "add-field",
36
+ } = props;
37
+
38
+ const singleFieldsToRender = fields.filter(
39
+ (field) =>
40
+ nestableFields.some(
41
+ (nestableField) => nestableField.name === field.name,
42
+ ) || field.name === UIDField.name,
43
+ );
44
+ const groupFieldToRender = fields.find(
45
+ (field) => field.name === groupField.name,
46
+ );
47
+
48
+ return (
49
+ <DropdownMenu>
50
+ <DropdownMenuTrigger disabled={disabled}>
51
+ <Button startIcon="add" color="grey" data-testid={triggerDataTestId}>
52
+ Add a field
53
+ </Button>
54
+ </DropdownMenuTrigger>
55
+ <DropdownMenuContent align="end" maxHeight={400} collisionPadding={8}>
56
+ <DropdownMenuLabel>Single fields</DropdownMenuLabel>
57
+ {singleFieldsToRender.map((field) => (
58
+ <AddFieldDropdownItem field={field} onSelectField={onSelectField} />
59
+ ))}
60
+
61
+ {groupFieldToRender && (
62
+ <>
63
+ <DropdownMenuLabel>Set of fields</DropdownMenuLabel>
64
+ {
65
+ <AddFieldDropdownItem
66
+ field={groupFieldToRender}
67
+ onSelectField={onSelectField}
68
+ />
69
+ }
70
+ </>
71
+ )}
72
+ </DropdownMenuContent>
73
+ </DropdownMenu>
74
+ );
75
+ }
76
+
77
+ interface AddFieldDropdownItemProps {
78
+ onSelectField: AddFieldDropdownProps["onSelectField"];
79
+ field: Field;
80
+ }
81
+
82
+ function AddFieldDropdownItem(props: AddFieldDropdownItemProps) {
83
+ const { field, onSelectField } = props;
84
+ const { type, variant, name, icon, description, thumbnail } = field;
85
+
86
+ return (
87
+ <DropdownMenuItem
88
+ key={`${type}${variant ? `-${variant}` : ""}`}
89
+ startIcon={<Icon name={icon} size="large" />}
90
+ description={description}
91
+ onSelect={() => onSelectField(variant ?? type)}
92
+ renderTooltip={(trigger) => (
93
+ <Tooltip
94
+ visible
95
+ variant="custom"
96
+ content={
97
+ <>
98
+ <Image
99
+ src={thumbnail}
100
+ sx={{
101
+ height: 170,
102
+ width: 278,
103
+ borderRadius: 4,
104
+ }}
105
+ />
106
+ <Text color="white">How it will look for content editors.</Text>
107
+ </>
108
+ }
109
+ side="left"
110
+ sideOffset={4}
111
+ >
112
+ {trigger}
113
+ </Tooltip>
114
+ )}
115
+ >
116
+ {name}
117
+ </DropdownMenuItem>
118
+ );
119
+ }
@@ -45,21 +45,22 @@ import SliceZone from "../SliceZone";
45
45
 
46
46
  const widgetsArray = [
47
47
  Widgets.UID,
48
- Widgets.Group,
49
- Widgets.StructuredText,
50
48
  Widgets.Image,
49
+ Widgets.Text,
50
+ Widgets.StructuredText,
51
51
  Widgets.Link,
52
- Widgets.LinkToMedia,
53
- Widgets.ContentRelationship,
54
52
  Widgets.Select,
55
53
  Widgets.Boolean,
54
+ Widgets.Number,
55
+ Widgets.Color,
56
56
  Widgets.Date,
57
- Widgets.Timestamp,
58
57
  Widgets.Embed,
59
- Widgets.Number,
58
+ Widgets.Timestamp,
60
59
  Widgets.GeoPoint,
61
- Widgets.Color,
62
- Widgets.Text,
60
+ Widgets.ContentRelationship,
61
+ Widgets.LinkToMedia,
62
+ Widgets.Group,
63
+ Widgets.NestedGroup,
63
64
  ];
64
65
 
65
66
  interface TabZoneProps {
@@ -260,7 +261,6 @@ const TabZone: FC<TabZoneProps> = ({ tabId }) => {
260
261
  }
261
262
  testId="static-zone-content"
262
263
  isRepeatableCustomType={customType.repeatable}
263
- emptyStateActionTestId="add-Static-field"
264
264
  />
265
265
  ) : undefined}
266
266
 
@@ -41,20 +41,20 @@ const dataTipText2 = `The repeatable zone is for a group<br/>
41
41
  indeterminate number of times, like FAQs`;
42
42
 
43
43
  const itemsWidgetsArray = [
44
- Widgets.StructuredText,
45
44
  Widgets.Image,
45
+ Widgets.Text,
46
+ Widgets.StructuredText,
46
47
  Widgets.Link,
47
- Widgets.LinkToMedia,
48
- Widgets.ContentRelationship,
49
48
  Widgets.Select,
50
49
  Widgets.Boolean,
50
+ Widgets.Number,
51
+ Widgets.Color,
51
52
  Widgets.Date,
52
- Widgets.Timestamp,
53
53
  Widgets.Embed,
54
- Widgets.Number,
54
+ Widgets.Timestamp,
55
55
  Widgets.GeoPoint,
56
- Widgets.Color,
57
- Widgets.Text,
56
+ Widgets.ContentRelationship,
57
+ Widgets.LinkToMedia,
58
58
  ];
59
59
 
60
60
  const primaryWidgetsArray = [Widgets.Group, ...itemsWidgetsArray];
@@ -223,7 +223,6 @@ const FieldZones: FC = () => {
223
223
  testId="static-zone-content"
224
224
  isRepeatableCustomType={undefined}
225
225
  emptyStateHeading={undefined}
226
- emptyStateActionTestId="add-Static-field"
227
226
  />
228
227
  {hasItems ? (
229
228
  <Zone
@@ -252,7 +251,6 @@ const FieldZones: FC = () => {
252
251
  testId="slice-repeatable-zone"
253
252
  isRepeatableCustomType={undefined}
254
253
  emptyStateHeading="No fields"
255
- emptyStateActionTestId="add-Repeatable-field"
256
254
  />
257
255
  ) : null}
258
256
  <Dialog
@@ -205,6 +205,7 @@ export const SharedSliceCards = (props: SharedSliceCardsProps) => {
205
205
  <>
206
206
  {slice.model.variations.map((v) => (
207
207
  <div
208
+ key={v.id}
208
209
  style={
209
210
  width !== undefined
210
211
  ? { ...defaultCardStyle, width }
@@ -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
  };
@@ -1,13 +1,14 @@
1
- import { Button, Switch, Text } from "@prismicio/editor-ui";
1
+ import { Switch, Text } from "@prismicio/editor-ui";
2
2
  import { array, arrayOf, bool, func, object, shape, string } from "prop-types";
3
3
  import { useState } from "react";
4
4
  import { BaseStyles } from "theme-ui";
5
5
 
6
6
  import { telemetry } from "@/apiClient";
7
7
  import { ListHeader } from "@/components/List";
8
+ import { fields as allFields } from "@/domain/fields";
9
+ import { AddFieldDropdown } from "@/features/builder/AddFieldDropdown";
8
10
  import { getContentTypeForTracking } from "@/utils/getContentTypeForTracking";
9
11
 
10
- import SelectFieldTypeModal from "../SelectFieldTypeModal";
11
12
  import Card from "./Card";
12
13
  import NewField from "./Card/components/NewField";
13
14
  import { ZoneEmptyState } from "./components/ZoneEmptyState";
@@ -32,7 +33,6 @@ const Zone = ({
32
33
  testId,
33
34
  isRepeatableCustomType,
34
35
  emptyStateHeading,
35
- emptyStateActionTestId,
36
36
  }) => {
37
37
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
38
38
  const widgetsArrayWithCondUid = (() => {
@@ -50,7 +50,6 @@ const Zone = ({
50
50
 
51
51
  const [showHints, setShowHints] = useState(false);
52
52
  const [editModalData, setEditModalData] = useState({ isOpen: false });
53
- const [selectModalData, setSelectModalData] = useState({ isOpen: false });
54
53
  const [newFieldData, setNewFieldData] = useState(null);
55
54
 
56
55
  /** @param {[string, import("@prismicio/types-internal/lib/customtypes").NestableWidget]} field */
@@ -68,22 +67,38 @@ const Zone = ({
68
67
  contentType: getContentTypeForTracking(window.location.pathname),
69
68
  });
70
69
  };
71
- const enterSelectMode = () => {
72
- setSelectModalData({ isOpen: true });
73
- };
74
70
 
75
71
  const closeEditModal = () => {
76
72
  setEditModalData({ isOpen: false });
77
73
  };
78
- const closeSelectModal = () => setSelectModalData({ isOpen: false });
79
74
 
80
75
  const onSelectFieldType = (widgetTypeName) => {
81
76
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-assignment
82
77
  setNewFieldData({ widgetTypeName, fields });
83
- setSelectModalData({ isOpen: false });
84
78
  };
85
79
 
86
80
  const onCancelNewField = () => setNewFieldData(null);
81
+ const addFieldDropdown = (
82
+ <AddFieldDropdown
83
+ disabled={newFieldData !== null}
84
+ onSelectField={onSelectFieldType}
85
+ fields={
86
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
87
+ widgetsArrayWithCondUid.filter(Boolean).map((widget) => {
88
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
89
+ const { TYPE_NAME, CUSTOM_NAME } = widget;
90
+ return allFields.find(
91
+ (f) =>
92
+ f.type === TYPE_NAME &&
93
+ (CUSTOM_NAME === undefined || f.variant === CUSTOM_NAME),
94
+ );
95
+ })
96
+ }
97
+ triggerDataTestId={
98
+ Boolean(isRepeatable) ? "add-field-in-items" : undefined
99
+ }
100
+ />
101
+ );
87
102
 
88
103
  return (
89
104
  <>
@@ -103,18 +118,7 @@ const Zone = ({
103
118
  style={{ flexShrink: 0 }}
104
119
  data-testid="code-snippets-switch"
105
120
  />
106
- <Button
107
- data-testid={`add-${
108
- // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
109
- isRepeatable ? "Repeatable" : "Static"
110
- }-field`}
111
- onClick={enterSelectMode}
112
- startIcon="add"
113
- color="grey"
114
- disabled={newFieldData !== null}
115
- >
116
- Add a field
117
- </Button>
121
+ {addFieldDropdown}
118
122
  </>
119
123
  ) : undefined
120
124
  }
@@ -129,9 +133,8 @@ const Zone = ({
129
133
  zoneType={getResolvedZoneType(zoneType, zoneTypeFormat)}
130
134
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
131
135
  heading={emptyStateHeading}
132
- onActionClick={() => enterSelectMode()}
133
136
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
134
- actionTestId={emptyStateActionTestId}
137
+ action={addFieldDropdown}
135
138
  />
136
139
  ) : // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/strict-boolean-expressions
137
140
  fields.length > 0 || newFieldData ? (
@@ -153,7 +156,6 @@ const Zone = ({
153
156
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-assignment
154
157
  renderHintBase={renderHintBase}
155
158
  enterEditMode={enterEditMode}
156
- enterSelectMode={enterSelectMode}
157
159
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
158
160
  onDragEnd={onDragEnd}
159
161
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -194,13 +196,6 @@ const Zone = ({
194
196
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
195
197
  zoneType={zoneType}
196
198
  />
197
- <SelectFieldTypeModal
198
- data={selectModalData}
199
- close={closeSelectModal}
200
- onSelect={onSelectFieldType}
201
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
202
- widgetsArray={widgetsArrayWithCondUid}
203
- />
204
199
  </>
205
200
  );
206
201
  };