slice-machine-ui 2.2.1 → 2.2.2-alpha.lg-advanced-groups.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/out/404.html +1 -1
  2. package/out/_next/static/chunks/18539003-a6ba9867be2b3472.js +22 -0
  3. package/out/_next/static/chunks/{66-d37d30551288858b.js → 210-565d01ee9777d1a1.js} +2 -2
  4. package/out/_next/static/chunks/212-58a99ab312f8a03b.js +1 -0
  5. package/out/_next/static/chunks/448-7a6843206737d199.js +1 -0
  6. package/out/_next/static/chunks/465-695ac5fedef986eb.js +1 -0
  7. package/out/_next/static/chunks/574-0758e3f5869ddb55.js +1 -0
  8. package/out/_next/static/chunks/756-31b94074da5d5a1c.js +10 -0
  9. package/out/_next/static/chunks/816-96fc9a79308019c7.js +1 -0
  10. package/out/_next/static/chunks/pages/_app-7883d66a6a541392.js +532 -0
  11. package/out/_next/static/chunks/pages/changelog-f0cd26a9ae095e9e.js +1 -0
  12. package/out/_next/static/chunks/pages/changes-1a57f90433a0b5e2.js +1 -0
  13. package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-74be2c0ac9c854c7.js → [customTypeId]-a6ff1618238b3510.js} +1 -1
  14. package/out/_next/static/chunks/pages/index-a0530bd55c7e1872.js +1 -0
  15. package/out/_next/static/chunks/pages/labs-7b0abeef69494aec.js +1 -0
  16. package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-d35c87b9aaec445a.js → [pageTypeId]-c300f963db847451.js} +1 -1
  17. package/out/_next/static/chunks/pages/settings-f82286dde10f624c.js +1 -0
  18. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-453f946e8879c829.js +1 -0
  19. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-b530a5e0ac9d0391.js +1 -0
  20. package/out/_next/static/chunks/pages/slices-7411822d74f1f6c1.js +1 -0
  21. package/out/_next/static/css/3c76d732d00eda61.css +1 -0
  22. package/out/_next/static/l5Ux0jBx4vnuim2wotr_V/_buildManifest.js +1 -0
  23. package/out/changelog.html +1 -1
  24. package/out/changes.html +1 -1
  25. package/out/custom-types/[customTypeId].html +1 -1
  26. package/out/custom-types.html +1 -1
  27. package/out/index.html +1 -1
  28. package/out/labs.html +1 -1
  29. package/out/page-types/[pageTypeId].html +1 -1
  30. package/out/settings.html +1 -1
  31. package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
  32. package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
  33. package/out/slices.html +1 -1
  34. package/package.json +9 -8
  35. package/src/hooks/useNestedGroupExperiment.ts +8 -0
  36. package/src/legacy/components/ListItem/index.tsx +1 -1
  37. package/src/legacy/lib/builders/CustomTypeBuilder/TabZone/index.tsx +21 -3
  38. package/src/legacy/lib/builders/SliceBuilder/FieldZones/index.tsx +23 -6
  39. package/src/legacy/lib/builders/SliceBuilder/VariationsList/index.tsx +4 -2
  40. package/src/legacy/lib/builders/SliceBuilder/index.tsx +1 -1
  41. package/src/legacy/lib/builders/common/EditModal/index.jsx +1 -1
  42. package/src/legacy/lib/builders/common/Zone/Card/components/NewField.tsx +1 -1
  43. package/src/legacy/lib/builders/common/Zone/Card/index.jsx +1 -1
  44. package/src/legacy/lib/builders/utils/index.ts +8 -0
  45. package/src/legacy/lib/models/common/Group.ts +51 -28
  46. package/src/legacy/lib/models/common/widgets/Group/ListItem/index.jsx +19 -7
  47. package/src/legacy/lib/models/common/widgets/Group/createGroupWidget.ts +80 -0
  48. package/src/legacy/lib/models/common/widgets/Group/index.tsx +68 -0
  49. package/src/legacy/lib/models/common/widgets/NestedGroup/index.tsx +32 -0
  50. package/src/legacy/lib/models/common/widgets/groupWidgets.ts +7 -0
  51. package/src/legacy/lib/models/common/widgets/index.ts +7 -31
  52. package/src/legacy/lib/models/common/widgets/nonGroupWidgets.ts +33 -0
  53. package/test/lib/builders/buildersUtils.test.ts +1 -1
  54. package/test/lib/models/common/widgets/index.test.ts +1 -1
  55. package/out/_next/static/ZT2vo2xSg8-Q7CNCV_bxP/_buildManifest.js +0 -1
  56. package/out/_next/static/chunks/18539003-eda642ad962ef598.js +0 -22
  57. package/out/_next/static/chunks/212-cbaa35389c0aacf1.js +0 -1
  58. package/out/_next/static/chunks/264-4bb6f3fb14863ef3.js +0 -1
  59. package/out/_next/static/chunks/465-47a6d2a5f66f521e.js +0 -1
  60. package/out/_next/static/chunks/574-6039c48fbc93b4a8.js +0 -1
  61. package/out/_next/static/chunks/756-1e44fe84bedc262b.js +0 -10
  62. package/out/_next/static/chunks/816-68d4db26c0adab2e.js +0 -1
  63. package/out/_next/static/chunks/pages/_app-0fffa4c502577b78.js +0 -532
  64. package/out/_next/static/chunks/pages/changelog-d309ea186a0e56bf.js +0 -1
  65. package/out/_next/static/chunks/pages/changes-1bb1a7b784a22151.js +0 -1
  66. package/out/_next/static/chunks/pages/index-785a0ab6e2a4fc27.js +0 -1
  67. package/out/_next/static/chunks/pages/labs-2e4f3a5f68e65b93.js +0 -1
  68. package/out/_next/static/chunks/pages/settings-25eb02893ed871b7.js +0 -1
  69. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-b47a72d5e94bd946.js +0 -1
  70. package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-996e20b9b295a912.js +0 -1
  71. package/out/_next/static/chunks/pages/slices-cc44eeccd58d23a9.js +0 -1
  72. package/out/_next/static/css/b3bb731ce567d63f.css +0 -1
  73. package/src/legacy/lib/models/common/widgets/Group/index.ts +0 -44
  74. package/src/legacy/lib/models/common/widgets/ctBuilderArray.ts +0 -20
  75. package/src/legacy/lib/models/common/widgets/groupBuilderArray.ts +0 -18
  76. package/src/legacy/lib/models/common/widgets/sliceBuilderArray.ts +0 -19
  77. package/src/legacy/lib/models/common/widgets/withGroup.ts +0 -2
  78. /package/out/_next/static/{ZT2vo2xSg8-Q7CNCV_bxP → l5Ux0jBx4vnuim2wotr_V}/_ssgManifest.js +0 -0
@@ -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>;
@@ -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,29 @@ 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.Group,
49
+ Widgets.StructuredText,
50
+ Widgets.Image,
51
+ Widgets.Link,
52
+ Widgets.LinkToMedia,
53
+ Widgets.ContentRelationship,
54
+ Widgets.Select,
55
+ Widgets.Boolean,
56
+ Widgets.Date,
57
+ Widgets.Timestamp,
58
+ Widgets.Embed,
59
+ Widgets.Number,
60
+ Widgets.GeoPoint,
61
+ Widgets.Color,
62
+ Widgets.Text,
63
+ ];
64
+
47
65
  interface TabZoneProps {
48
66
  tabId: string;
49
67
  }
@@ -227,7 +245,7 @@ const TabZone: FC<TabZoneProps> = ({ tabId }) => {
227
245
  poolOfFieldsToCheck={poolOfFields}
228
246
  showHints={true}
229
247
  EditModal={EditModal}
230
- widgetsArray={ctBuilderArray}
248
+ widgetsArray={widgetsArray}
231
249
  onDeleteItem={onDeleteItem}
232
250
  onSave={onSave}
233
251
  onSaveNewField={onSaveNewField}
@@ -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.StructuredText,
45
+ Widgets.Image,
46
+ Widgets.Link,
47
+ Widgets.LinkToMedia,
48
+ Widgets.ContentRelationship,
49
+ Widgets.Select,
50
+ Widgets.Boolean,
51
+ Widgets.Date,
52
+ Widgets.Timestamp,
53
+ Widgets.Embed,
54
+ Widgets.Number,
55
+ Widgets.GeoPoint,
56
+ Widgets.Color,
57
+ Widgets.Text,
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)}
@@ -216,7 +233,7 @@ const FieldZones: FC = () => {
216
233
  isRepeatable
217
234
  title="Repeatable Zone"
218
235
  dataTip={dataTipText2}
219
- widgetsArray={groupBuilderWidgetsArray}
236
+ widgetsArray={itemsWidgetsArray}
220
237
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
221
238
  fields={variation.items}
222
239
  EditModal={EditModal}
@@ -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>
@@ -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";
@@ -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";
@@ -1,3 +1,5 @@
1
+ import { GroupFieldType } from "@prismicio/types-internal/lib/customtypes/widgets";
2
+
1
3
  import { TabField } from "@/legacy/lib/models/common/CustomType";
2
4
 
3
5
  interface Widgets {
@@ -21,6 +23,12 @@ export const findWidgetByConfigOrType = (
21
23
  return widgets.Link;
22
24
  }
23
25
  }
26
+ // The Group & NestedGroup widgets share the "Group" type. They are never
27
+ // in the same widget group, so this will use whichever is provided. For example,
28
+ // in the custom list item for Group, we always pass NestedGroup as the Group widget.
29
+ if (type === GroupFieldType) {
30
+ return widgets.Group ?? widgets.NestedGroup;
31
+ }
24
32
 
25
33
  return widgets[type];
26
34
  };
@@ -1,32 +1,49 @@
1
- import { Group } from "@prismicio/types-internal/lib/customtypes/widgets";
1
+ import { NestableWidget } from "@prismicio/types-internal/lib/customtypes";
2
+ import {
3
+ Group,
4
+ GroupFieldType,
5
+ } from "@prismicio/types-internal/lib/customtypes/widgets";
2
6
  import { StringOrNull } from "@prismicio/types-internal/lib/validators";
3
7
  import { getOrElseW } from "fp-ts/lib/Either";
4
8
  import * as t from "io-ts";
5
9
 
6
10
  import { FieldsSM } from "./Fields";
7
11
 
8
- export const GroupConfig = t.exact(
9
- t.partial({
10
- label: StringOrNull,
11
- repeat: t.boolean,
12
- fields: FieldsSM,
13
- }),
14
- );
15
- export type GroupConfig = t.TypeOf<typeof GroupConfig>;
16
-
17
- export const GroupSM = t.exact(
18
- t.intersection([
19
- t.type({
20
- type: t.literal("Group"),
21
- }),
12
+ const createGroupConfig = <TFields extends t.Mixed>(fields: TFields) =>
13
+ t.exact(
22
14
  t.partial({
23
- fieldset: StringOrNull,
24
- icon: t.string,
25
- description: t.string,
26
- config: GroupConfig,
15
+ label: StringOrNull,
16
+ repeat: t.boolean,
17
+ fields,
27
18
  }),
28
- ]),
19
+ );
20
+
21
+ const createGroupSM = <TFields extends t.Mixed>(fields: TFields) =>
22
+ t.exact(
23
+ t.intersection([
24
+ t.type({
25
+ type: t.literal("Group"),
26
+ }),
27
+ t.partial({
28
+ fieldset: StringOrNull,
29
+ icon: t.string,
30
+ description: t.string,
31
+ config: createGroupConfig(fields),
32
+ }),
33
+ ]),
34
+ );
35
+
36
+ export const NestedGroupSM = createGroupSM(FieldsSM);
37
+ export type NestedGroupSM = t.TypeOf<typeof NestedGroupSM>;
38
+
39
+ const GroupFieldsSM = t.array(
40
+ t.type({
41
+ key: t.string,
42
+ value: t.union([NestableWidget, NestedGroupSM]),
43
+ }),
29
44
  );
45
+
46
+ export const GroupSM = createGroupSM(GroupFieldsSM);
30
47
  export type GroupSM = t.TypeOf<typeof GroupSM>;
31
48
 
32
49
  export const Groups = {
@@ -34,10 +51,13 @@ export const Groups = {
34
51
  const fields = (() => {
35
52
  if (!group.config?.fields) return;
36
53
 
37
- return group.config.fields.reduce(
38
- (acc, { key, value }) => ({ ...acc, [key]: value }),
39
- {},
40
- );
54
+ return group.config.fields.reduce((acc, { key, value }) => {
55
+ if (value.type === GroupFieldType) {
56
+ return { ...acc, [key]: Groups.fromSM(value) };
57
+ } else {
58
+ return { ...acc, [key]: value };
59
+ }
60
+ }, {});
41
61
  })();
42
62
 
43
63
  return getOrElseW(() => {
@@ -58,10 +78,13 @@ export const Groups = {
58
78
  if (!group.config?.fields) return;
59
79
 
60
80
  // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
61
- return Object.entries(group.config?.fields || {}).map(([key, value]) => ({
62
- key,
63
- value,
64
- }));
81
+ return Object.entries(group.config?.fields || {}).map(([key, value]) => {
82
+ if (value.type === GroupFieldType) {
83
+ return { key, value: Groups.toSM(value) };
84
+ } else {
85
+ return { key, value };
86
+ }
87
+ });
65
88
  })();
66
89
 
67
90
  return getOrElseW(() => {
@@ -1,3 +1,4 @@
1
+ import { GroupFieldType } from "@prismicio/types-internal/lib/customtypes/widgets";
1
2
  import { Fragment, useState } from "react";
2
3
  import { DragDropContext, Droppable } from "react-beautiful-dnd";
3
4
  import { flushSync } from "react-dom";
@@ -17,16 +18,16 @@ import Hint from "@/legacy/lib/builders/common/Zone/Card/components/Hints";
17
18
  import NewField from "@/legacy/lib/builders/common/Zone/Card/components/NewField";
18
19
  import { findWidgetByConfigOrType } from "@/legacy/lib/builders/utils";
19
20
  import { Groups } from "@/legacy/lib/models/common/Group";
20
- import * as Widgets from "@/legacy/lib/models/common/widgets";
21
- import groupBuilderWidgetsArray from "@/legacy/lib/models/common/widgets/groupBuilderArray";
22
21
  import { ensureDnDDestination } from "@/legacy/lib/utils";
23
22
  import { transformKeyAccessor } from "@/legacy/lib/utils/str";
24
23
  import { getContentTypeForTracking } from "@/utils/getContentTypeForTracking";
25
24
 
26
25
  /* eslint-disable */
27
- const CustomListItem = ({
26
+ export const CustomListItem = ({
28
27
  tabId,
29
28
  widget,
29
+ Widgets,
30
+ widgetsArray,
30
31
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
31
32
  parentSnapshot,
32
33
  showHints,
@@ -86,7 +87,7 @@ const CustomListItem = ({
86
87
  group: Groups.fromSM(groupItem.value),
87
88
  previousFieldId: previousKey,
88
89
  newFieldId: newKey,
89
- field: value,
90
+ field: value.type === GroupFieldType ? Groups.fromSM(value) : value,
90
91
  });
91
92
 
92
93
  saveItem({
@@ -215,6 +216,8 @@ const CustomListItem = ({
215
216
  key: item.key,
216
217
  enterEditMode,
217
218
  deleteItem: onDeleteItem,
219
+ saveItem: onSaveField,
220
+ showHints,
218
221
  renderFieldAccessor: (key) =>
219
222
  `item${transformKeyAccessor(item.key)}`,
220
223
  // eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/restrict-template-expressions
@@ -239,6 +242,17 @@ const CustomListItem = ({
239
242
  typeName={widget.CUSTOM_NAME || widget.TYPE_NAME}
240
243
  />
241
244
  );
245
+
246
+ if (widget.CustomListItem) {
247
+ const { CustomListItem } = widget;
248
+ return (
249
+ <CustomListItem
250
+ {...props}
251
+ HintElement={HintElement}
252
+ />
253
+ );
254
+ }
255
+
242
256
  return (
243
257
  <ListItem {...props} HintElement={HintElement} />
244
258
  );
@@ -270,7 +284,7 @@ const CustomListItem = ({
270
284
  data={{ isOpen: selectMode }}
271
285
  close={() => setSelectMode(false)}
272
286
  onSelect={onSelectFieldType}
273
- widgetsArray={groupBuilderWidgetsArray}
287
+ widgetsArray={widgetsArray}
274
288
  />
275
289
  <EditModal
276
290
  data={editModalData}
@@ -282,6 +296,4 @@ const CustomListItem = ({
282
296
  </Fragment>
283
297
  );
284
298
  };
285
-
286
- export default CustomListItem;
287
299
  /* eslint-enable */
@@ -0,0 +1,80 @@
1
+ import { MdPlaylistAdd } from "react-icons/md";
2
+ import * as yup from "yup";
3
+
4
+ import { TabField } from "@/legacy/lib/models/common/CustomType";
5
+ import {
6
+ type GroupSM,
7
+ type NestedGroupSM,
8
+ } from "@/legacy/lib/models/common/Group";
9
+ import { type Widget } from "@/legacy/lib/models/common/widgets/Widget";
10
+
11
+ import { type GroupListItemProps } from ".";
12
+ import Form, { FormFields } from "./Form";
13
+
14
+ const Meta = {
15
+ icon: MdPlaylistAdd,
16
+ title: "Group",
17
+ description: "A repeatable set of fields",
18
+ };
19
+
20
+ const createSchema = (typeRegex: RegExp) =>
21
+ yup.object().shape({
22
+ type: yup
23
+ .string()
24
+ .matches(typeRegex, { excludeEmptyString: true })
25
+ .required(),
26
+ config: yup.object().shape({
27
+ fields: yup.array(),
28
+ label: yup.string(),
29
+ placeholder: yup.string(),
30
+ repeat: yup.boolean().optional(),
31
+ }),
32
+ });
33
+ export type SchemaType = ReturnType<typeof createSchema>;
34
+
35
+ type CreateGroupWidgetArgsBase<T extends TabField> = {
36
+ schemaTypeRegex: RegExp;
37
+ customListItem: (props: GroupListItemProps<T>) => JSX.Element;
38
+ customName?: string;
39
+ };
40
+ type CreateTopGroupWidgetArgs = CreateGroupWidgetArgsBase<GroupSM>;
41
+ type CreateNestedGroupWidgetArgs = CreateGroupWidgetArgsBase<NestedGroupSM> & {
42
+ customName: "NestedGroup";
43
+ };
44
+ type CreateGroupWidgetArgs =
45
+ | CreateTopGroupWidgetArgs
46
+ | CreateNestedGroupWidgetArgs;
47
+
48
+ export function createGroupWidget(
49
+ args: CreateTopGroupWidgetArgs,
50
+ ): Widget<GroupSM, SchemaType>;
51
+
52
+ export function createGroupWidget(
53
+ args: CreateNestedGroupWidgetArgs,
54
+ ): Widget<NestedGroupSM, SchemaType>;
55
+
56
+ export function createGroupWidget({
57
+ schemaTypeRegex,
58
+ customListItem,
59
+ customName,
60
+ }: CreateGroupWidgetArgs):
61
+ | Widget<GroupSM, SchemaType>
62
+ | Widget<NestedGroupSM, SchemaType> {
63
+ return {
64
+ Meta,
65
+ Form,
66
+ FormFields,
67
+ schema: createSchema(schemaTypeRegex),
68
+ create: (label: string) => ({
69
+ type: "Group",
70
+ config: {
71
+ label,
72
+ repeat: true,
73
+ fields: [],
74
+ },
75
+ }),
76
+ CustomListItem: customListItem,
77
+ TYPE_NAME: "Group",
78
+ CUSTOM_NAME: customName,
79
+ };
80
+ }
@@ -0,0 +1,68 @@
1
+ import { type DroppableStateSnapshot } from "react-beautiful-dnd";
2
+
3
+ import { useNestedGroupExperiment } from "@/hooks/useNestedGroupExperiment";
4
+ import { type Item } from "@/legacy/components/ListItem";
5
+ import { type TabField } from "@/legacy/lib/models/common/CustomType";
6
+ import { type GroupSM } from "@/legacy/lib/models/common/Group";
7
+ import { Widgets } from "@/legacy/lib/models/common/widgets/groupWidgets";
8
+ import { type Widget } from "@/legacy/lib/models/common/widgets/Widget";
9
+
10
+ import { createGroupWidget, type SchemaType } from "./createGroupWidget";
11
+ import { CustomListItem } from "./ListItem";
12
+
13
+ const widgetsArray = [
14
+ Widgets.NestedGroup,
15
+ Widgets.StructuredText,
16
+ Widgets.Image,
17
+ Widgets.Link,
18
+ Widgets.LinkToMedia,
19
+ Widgets.ContentRelationship,
20
+ Widgets.Select,
21
+ Widgets.Boolean,
22
+ Widgets.Date,
23
+ Widgets.Timestamp,
24
+ Widgets.Embed,
25
+ Widgets.Number,
26
+ Widgets.GeoPoint,
27
+ Widgets.Color,
28
+ Widgets.Text,
29
+ ];
30
+
31
+ export interface GroupListItemProps<F extends TabField> {
32
+ tabId: string;
33
+ widget: Widget<F, SchemaType>;
34
+ parentSnapshot: DroppableStateSnapshot;
35
+ showHints: boolean;
36
+ isRepeatable: boolean;
37
+ item: Item<F>;
38
+ draggableId: string;
39
+ saveItem: ({
40
+ apiId,
41
+ newKey,
42
+ value,
43
+ }: {
44
+ apiId: string;
45
+ newKey: string;
46
+ value: F;
47
+ }) => void;
48
+ HintElement: JSX.Element;
49
+ }
50
+
51
+ const GroupListItem = (props: GroupListItemProps<GroupSM>): JSX.Element => {
52
+ const nestedGroupExperiment = useNestedGroupExperiment();
53
+ const maybeFilteredWidgetsArray = nestedGroupExperiment.eligible
54
+ ? widgetsArray
55
+ : widgetsArray.filter((widget) => widget.CUSTOM_NAME !== "NestedGroup");
56
+ return (
57
+ <CustomListItem
58
+ Widgets={Widgets}
59
+ widgetsArray={maybeFilteredWidgetsArray}
60
+ {...props}
61
+ />
62
+ );
63
+ };
64
+
65
+ export const GroupWidget = createGroupWidget({
66
+ schemaTypeRegex: /^Group$/,
67
+ customListItem: GroupListItem,
68
+ });
@@ -0,0 +1,32 @@
1
+ import { type NestedGroupSM } from "@/legacy/lib/models/common/Group";
2
+ import { type GroupListItemProps } from "@/legacy/lib/models/common/widgets/Group";
3
+ import { createGroupWidget } from "@/legacy/lib/models/common/widgets/Group/createGroupWidget";
4
+ import { CustomListItem } from "@/legacy/lib/models/common/widgets/Group/ListItem";
5
+ import { NonGroupWidgets as Widgets } from "@/legacy/lib/models/common/widgets/nonGroupWidgets";
6
+
7
+ const widgetsArray = [
8
+ Widgets.StructuredText,
9
+ Widgets.Image,
10
+ Widgets.Link,
11
+ Widgets.LinkToMedia,
12
+ Widgets.ContentRelationship,
13
+ Widgets.Select,
14
+ Widgets.Boolean,
15
+ Widgets.Date,
16
+ Widgets.Timestamp,
17
+ Widgets.Embed,
18
+ Widgets.Number,
19
+ Widgets.GeoPoint,
20
+ Widgets.Color,
21
+ Widgets.Text,
22
+ ];
23
+
24
+ const NestedGroupListItem = (props: GroupListItemProps<NestedGroupSM>) => (
25
+ <CustomListItem Widgets={Widgets} widgetsArray={widgetsArray} {...props} />
26
+ );
27
+
28
+ export const NestedGroupWidget = createGroupWidget({
29
+ schemaTypeRegex: /^NestedGroup$/,
30
+ customListItem: NestedGroupListItem,
31
+ customName: "NestedGroup",
32
+ });
@@ -0,0 +1,7 @@
1
+ import { NestedGroupWidget as NestedGroup } from "./NestedGroup";
2
+ import { NonGroupWidgets } from "./nonGroupWidgets";
3
+
4
+ export const Widgets = {
5
+ ...NonGroupWidgets,
6
+ NestedGroup,
7
+ };
@@ -1,33 +1,9 @@
1
- import { BooleanWidget } from "./Boolean";
2
- import { ColorWidget } from "./Color";
3
- import { ContentRelationshipWidget } from "./ContentRelationship";
4
- import { DateWidget } from "./Date";
5
- import { EmbedWidget } from "./Embed";
6
- import { GeoPointWidget } from "./GeoPoint";
7
- import { ImageWidget } from "./Image";
8
- import { LinkWidget } from "./Link";
9
- import { LinkToMediaWidget } from "./LinkToMedia";
10
- import { NumberWidget } from "./Number";
11
- import { SelectWidget } from "./Select";
12
- import { StructuredTextWidget } from "./StructuredText";
13
- import { TextWidget } from "./Text";
14
- import { TimestampWidget } from "./Timestamp";
15
- import { UIDWidget } from "./UID";
1
+ import { GroupWidget as Group } from "./Group";
2
+ import { NestedGroupWidget as NestedGroup } from "./NestedGroup";
3
+ import { NonGroupWidgets } from "./nonGroupWidgets";
16
4
 
17
- export {
18
- BooleanWidget as Boolean,
19
- ColorWidget as Color,
20
- ContentRelationshipWidget as ContentRelationship,
21
- DateWidget as Date,
22
- EmbedWidget as Embed,
23
- GeoPointWidget as GeoPoint,
24
- ImageWidget as Image,
25
- LinkWidget as Link,
26
- LinkToMediaWidget as LinkToMedia,
27
- NumberWidget as Number,
28
- SelectWidget as Select,
29
- StructuredTextWidget as StructuredText,
30
- TextWidget as Text,
31
- TimestampWidget as Timestamp,
32
- UIDWidget as UID,
5
+ export const Widgets = {
6
+ Group,
7
+ NestedGroup,
8
+ ...NonGroupWidgets,
33
9
  };
@@ -0,0 +1,33 @@
1
+ import { BooleanWidget } from "./Boolean";
2
+ import { ColorWidget } from "./Color";
3
+ import { ContentRelationshipWidget } from "./ContentRelationship";
4
+ import { DateWidget } from "./Date";
5
+ import { EmbedWidget } from "./Embed";
6
+ import { GeoPointWidget } from "./GeoPoint";
7
+ import { ImageWidget } from "./Image";
8
+ import { LinkWidget } from "./Link";
9
+ import { LinkToMediaWidget } from "./LinkToMedia";
10
+ import { NumberWidget } from "./Number";
11
+ import { SelectWidget } from "./Select";
12
+ import { StructuredTextWidget } from "./StructuredText";
13
+ import { TextWidget } from "./Text";
14
+ import { TimestampWidget } from "./Timestamp";
15
+ import { UIDWidget } from "./UID";
16
+
17
+ export const NonGroupWidgets = {
18
+ Boolean: BooleanWidget,
19
+ Color: ColorWidget,
20
+ ContentRelationship: ContentRelationshipWidget,
21
+ Date: DateWidget,
22
+ Embed: EmbedWidget,
23
+ GeoPoint: GeoPointWidget,
24
+ Image: ImageWidget,
25
+ Link: LinkWidget,
26
+ LinkToMedia: LinkToMediaWidget,
27
+ Number: NumberWidget,
28
+ Select: SelectWidget,
29
+ StructuredText: StructuredTextWidget,
30
+ Text: TextWidget,
31
+ Timestamp: TimestampWidget,
32
+ UID: UIDWidget,
33
+ };
@@ -1,7 +1,7 @@
1
1
  import { describe, expect, test } from "vitest";
2
2
 
3
3
  import { findWidgetByConfigOrType } from "@/legacy/lib/builders/utils";
4
- import * as Widgets from "@/legacy/lib/models/common/widgets/withGroup";
4
+ import { Widgets } from "@/legacy/lib/models/common/widgets";
5
5
 
6
6
  const dumbConfig = {
7
7
  label: "",
@@ -7,7 +7,7 @@ import {
7
7
  CustomTypes,
8
8
  CustomTypeSM,
9
9
  } from "@/legacy/lib/models/common/CustomType";
10
- import * as Widgets from "@/legacy/lib/models/common/widgets";
10
+ import { NonGroupWidgets as Widgets } from "@/legacy/lib/models/common/widgets/nonGroupWidgets";
11
11
 
12
12
  const widgetEntries = Object.entries(Widgets);
13
13