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.
- package/out/404.html +1 -1
- package/out/_next/static/chunks/18539003-a6ba9867be2b3472.js +22 -0
- package/out/_next/static/chunks/{66-d37d30551288858b.js → 210-565d01ee9777d1a1.js} +2 -2
- package/out/_next/static/chunks/212-58a99ab312f8a03b.js +1 -0
- package/out/_next/static/chunks/448-7a6843206737d199.js +1 -0
- package/out/_next/static/chunks/465-695ac5fedef986eb.js +1 -0
- package/out/_next/static/chunks/574-0758e3f5869ddb55.js +1 -0
- package/out/_next/static/chunks/756-31b94074da5d5a1c.js +10 -0
- package/out/_next/static/chunks/816-96fc9a79308019c7.js +1 -0
- package/out/_next/static/chunks/pages/_app-7883d66a6a541392.js +532 -0
- package/out/_next/static/chunks/pages/changelog-f0cd26a9ae095e9e.js +1 -0
- package/out/_next/static/chunks/pages/changes-1a57f90433a0b5e2.js +1 -0
- package/out/_next/static/chunks/pages/custom-types/{[customTypeId]-74be2c0ac9c854c7.js → [customTypeId]-a6ff1618238b3510.js} +1 -1
- package/out/_next/static/chunks/pages/index-a0530bd55c7e1872.js +1 -0
- package/out/_next/static/chunks/pages/labs-7b0abeef69494aec.js +1 -0
- package/out/_next/static/chunks/pages/page-types/{[pageTypeId]-d35c87b9aaec445a.js → [pageTypeId]-c300f963db847451.js} +1 -1
- package/out/_next/static/chunks/pages/settings-f82286dde10f624c.js +1 -0
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-453f946e8879c829.js +1 -0
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-b530a5e0ac9d0391.js +1 -0
- package/out/_next/static/chunks/pages/slices-7411822d74f1f6c1.js +1 -0
- package/out/_next/static/css/3c76d732d00eda61.css +1 -0
- package/out/_next/static/l5Ux0jBx4vnuim2wotr_V/_buildManifest.js +1 -0
- package/out/changelog.html +1 -1
- package/out/changes.html +1 -1
- package/out/custom-types/[customTypeId].html +1 -1
- package/out/custom-types.html +1 -1
- package/out/index.html +1 -1
- package/out/labs.html +1 -1
- package/out/page-types/[pageTypeId].html +1 -1
- package/out/settings.html +1 -1
- package/out/slices/[lib]/[sliceName]/[variation]/simulator.html +1 -1
- package/out/slices/[lib]/[sliceName]/[variation].html +1 -1
- package/out/slices.html +1 -1
- package/package.json +9 -8
- package/src/hooks/useNestedGroupExperiment.ts +8 -0
- package/src/legacy/components/ListItem/index.tsx +1 -1
- package/src/legacy/lib/builders/CustomTypeBuilder/TabZone/index.tsx +21 -3
- package/src/legacy/lib/builders/SliceBuilder/FieldZones/index.tsx +23 -6
- package/src/legacy/lib/builders/SliceBuilder/VariationsList/index.tsx +4 -2
- package/src/legacy/lib/builders/SliceBuilder/index.tsx +1 -1
- package/src/legacy/lib/builders/common/EditModal/index.jsx +1 -1
- package/src/legacy/lib/builders/common/Zone/Card/components/NewField.tsx +1 -1
- package/src/legacy/lib/builders/common/Zone/Card/index.jsx +1 -1
- package/src/legacy/lib/builders/utils/index.ts +8 -0
- package/src/legacy/lib/models/common/Group.ts +51 -28
- package/src/legacy/lib/models/common/widgets/Group/ListItem/index.jsx +19 -7
- package/src/legacy/lib/models/common/widgets/Group/createGroupWidget.ts +80 -0
- package/src/legacy/lib/models/common/widgets/Group/index.tsx +68 -0
- package/src/legacy/lib/models/common/widgets/NestedGroup/index.tsx +32 -0
- package/src/legacy/lib/models/common/widgets/groupWidgets.ts +7 -0
- package/src/legacy/lib/models/common/widgets/index.ts +7 -31
- package/src/legacy/lib/models/common/widgets/nonGroupWidgets.ts +33 -0
- package/test/lib/builders/buildersUtils.test.ts +1 -1
- package/test/lib/models/common/widgets/index.test.ts +1 -1
- package/out/_next/static/ZT2vo2xSg8-Q7CNCV_bxP/_buildManifest.js +0 -1
- package/out/_next/static/chunks/18539003-eda642ad962ef598.js +0 -22
- package/out/_next/static/chunks/212-cbaa35389c0aacf1.js +0 -1
- package/out/_next/static/chunks/264-4bb6f3fb14863ef3.js +0 -1
- package/out/_next/static/chunks/465-47a6d2a5f66f521e.js +0 -1
- package/out/_next/static/chunks/574-6039c48fbc93b4a8.js +0 -1
- package/out/_next/static/chunks/756-1e44fe84bedc262b.js +0 -10
- package/out/_next/static/chunks/816-68d4db26c0adab2e.js +0 -1
- package/out/_next/static/chunks/pages/_app-0fffa4c502577b78.js +0 -532
- package/out/_next/static/chunks/pages/changelog-d309ea186a0e56bf.js +0 -1
- package/out/_next/static/chunks/pages/changes-1bb1a7b784a22151.js +0 -1
- package/out/_next/static/chunks/pages/index-785a0ab6e2a4fc27.js +0 -1
- package/out/_next/static/chunks/pages/labs-2e4f3a5f68e65b93.js +0 -1
- package/out/_next/static/chunks/pages/settings-25eb02893ed871b7.js +0 -1
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]/simulator-b47a72d5e94bd946.js +0 -1
- package/out/_next/static/chunks/pages/slices/[lib]/[sliceName]/[variation]-996e20b9b295a912.js +0 -1
- package/out/_next/static/chunks/pages/slices-cc44eeccd58d23a9.js +0 -1
- package/out/_next/static/css/b3bb731ce567d63f.css +0 -1
- package/src/legacy/lib/models/common/widgets/Group/index.ts +0 -44
- package/src/legacy/lib/models/common/widgets/ctBuilderArray.ts +0 -20
- package/src/legacy/lib/models/common/widgets/groupBuilderArray.ts +0 -18
- package/src/legacy/lib/models/common/widgets/sliceBuilderArray.ts +0 -19
- package/src/legacy/lib/models/common/widgets/withGroup.ts +0 -2
- /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
|
|
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={
|
|
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
|
|
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 =
|
|
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={
|
|
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={
|
|
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
|
|
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: "
|
|
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
|
|
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
|
|
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 {
|
|
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
|
-
|
|
9
|
-
t.
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
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
|
-
(
|
|
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
|
-
|
|
63
|
-
|
|
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={
|
|
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
|
+
});
|
|
@@ -1,33 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
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
|
|
10
|
+
import { NonGroupWidgets as Widgets } from "@/legacy/lib/models/common/widgets/nonGroupWidgets";
|
|
11
11
|
|
|
12
12
|
const widgetEntries = Object.entries(Widgets);
|
|
13
13
|
|