slice-machine-ui 2.2.2-beta.1 → 2.2.2-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/next.config.mjs +11 -1
- package/out/404.html +1 -1
- package/out/_next/static/KD7BhDNRF_N5IlJuDq1eR/_buildManifest.js +1 -0
- package/out/_next/static/chunks/18539003-36b102fa41de015e.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-dfeb0e6aa3079da1.js +1 -0
- package/out/_next/static/chunks/756-98ae0a6e755f46f2.js +10 -0
- package/out/_next/static/chunks/816-96fc9a79308019c7.js +1 -0
- package/out/_next/static/chunks/pages/_app-6c8c02648847371c.js +536 -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/ee6cd1a80767d31e.css +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 -9
- 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/Hints/index.tsx +8 -1
- package/src/legacy/lib/builders/common/Zone/Card/components/NewField.tsx +1 -1
- package/src/legacy/lib/builders/common/Zone/Card/index.jsx +3 -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 +22 -8
- package/src/legacy/lib/models/common/widgets/Group/createGroupWidget.ts +83 -0
- package/src/legacy/lib/models/common/widgets/Group/index.tsx +72 -0
- package/src/legacy/lib/models/common/widgets/NestedGroup/index.tsx +40 -0
- package/src/legacy/lib/models/common/widgets/Widget.ts +10 -1
- 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/JGphUg6eFq0-W11Pa7cMU/_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-05ac13d573829b68.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/{JGphUg6eFq0-W11Pa7cMU → KD7BhDNRF_N5IlJuDq1eR}/_ssgManifest.js +0 -0
|
@@ -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";
|
|
@@ -9,9 +9,15 @@ interface HintProps {
|
|
|
9
9
|
show: boolean;
|
|
10
10
|
item: Item;
|
|
11
11
|
renderHintBase: RenderHintBaseFN;
|
|
12
|
+
hintItemName?: string;
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
const Hint: React.FC<HintProps> = ({
|
|
15
|
+
const Hint: React.FC<HintProps> = ({
|
|
16
|
+
show,
|
|
17
|
+
renderHintBase,
|
|
18
|
+
item,
|
|
19
|
+
hintItemName,
|
|
20
|
+
}) => {
|
|
15
21
|
const fieldPathString = renderHintBase({ item });
|
|
16
22
|
|
|
17
23
|
// TODO: Call `swr`'s global `mutate` function when something changes to clear the cache.
|
|
@@ -20,6 +26,7 @@ const Hint: React.FC<HintProps> = ({ show, renderHintBase, item }) => {
|
|
|
20
26
|
return await managerClient.snippets.readSnippets({
|
|
21
27
|
fieldPath: fieldPathString.split("."),
|
|
22
28
|
model: item.value,
|
|
29
|
+
itemName: hintItemName,
|
|
23
30
|
});
|
|
24
31
|
});
|
|
25
32
|
|
|
@@ -15,8 +15,8 @@ import {
|
|
|
15
15
|
} from "@/legacy/lib/forms";
|
|
16
16
|
import { validateId } from "@/legacy/lib/forms/defaults";
|
|
17
17
|
import { InputType } from "@/legacy/lib/forms/fields";
|
|
18
|
+
import { Widgets } from "@/legacy/lib/models/common/widgets";
|
|
18
19
|
import { AnyWidget } from "@/legacy/lib/models/common/widgets/Widget";
|
|
19
|
-
import * as Widgets from "@/legacy/lib/models/common/widgets/withGroup";
|
|
20
20
|
import { slugify } from "@/legacy/lib/utils/str";
|
|
21
21
|
|
|
22
22
|
import { ErrorTooltip } from "./ErrorTooltip";
|
|
@@ -3,7 +3,7 @@ import { Box, Text } from "theme-ui";
|
|
|
3
3
|
|
|
4
4
|
import Li from "@/legacy/components/Li";
|
|
5
5
|
import ListItem from "@/legacy/components/ListItem";
|
|
6
|
-
import
|
|
6
|
+
import { Widgets } from "@/legacy/lib/models/common/widgets";
|
|
7
7
|
|
|
8
8
|
import { findWidgetByConfigOrType } from "../../../utils";
|
|
9
9
|
import Hint from "./components/Hints";
|
|
@@ -103,6 +103,8 @@ const FieldZone = ({
|
|
|
103
103
|
isRepeatable={isRepeatable}
|
|
104
104
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
105
105
|
renderHintBase={renderHintBase}
|
|
106
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
107
|
+
hintItemName={widget.hintItemName}
|
|
106
108
|
Widgets={Widgets}
|
|
107
109
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/strict-boolean-expressions
|
|
108
110
|
typeName={widget.CUSTOM_NAME || widget.TYPE_NAME}
|
|
@@ -1,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,17 @@ 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,
|
|
31
|
+
hintBase,
|
|
30
32
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
31
33
|
parentSnapshot,
|
|
32
34
|
showHints,
|
|
@@ -86,7 +88,7 @@ const CustomListItem = ({
|
|
|
86
88
|
group: Groups.fromSM(groupItem.value),
|
|
87
89
|
previousFieldId: previousKey,
|
|
88
90
|
newFieldId: newKey,
|
|
89
|
-
field: value,
|
|
91
|
+
field: value.type === GroupFieldType ? Groups.fromSM(value) : value,
|
|
90
92
|
});
|
|
91
93
|
|
|
92
94
|
saveItem({
|
|
@@ -215,6 +217,8 @@ const CustomListItem = ({
|
|
|
215
217
|
key: item.key,
|
|
216
218
|
enterEditMode,
|
|
217
219
|
deleteItem: onDeleteItem,
|
|
220
|
+
saveItem: onSaveField,
|
|
221
|
+
showHints,
|
|
218
222
|
renderFieldAccessor: (key) =>
|
|
219
223
|
`item${transformKeyAccessor(item.key)}`,
|
|
220
224
|
// 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
|
|
@@ -232,13 +236,25 @@ const CustomListItem = ({
|
|
|
232
236
|
isRepeatable={isRepeatable}
|
|
233
237
|
renderHintBase={({ item }) =>
|
|
234
238
|
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions, @typescript-eslint/no-unsafe-member-access
|
|
235
|
-
|
|
239
|
+
`${hintBase}${transformKeyAccessor(item.key)}`
|
|
236
240
|
}
|
|
241
|
+
hintItemName={widget.hintItemName}
|
|
237
242
|
Widgets={Widgets}
|
|
238
243
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
239
244
|
typeName={widget.CUSTOM_NAME || widget.TYPE_NAME}
|
|
240
245
|
/>
|
|
241
246
|
);
|
|
247
|
+
|
|
248
|
+
if (widget.CustomListItem) {
|
|
249
|
+
const { CustomListItem } = widget;
|
|
250
|
+
return (
|
|
251
|
+
<CustomListItem
|
|
252
|
+
{...props}
|
|
253
|
+
HintElement={HintElement}
|
|
254
|
+
/>
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
242
258
|
return (
|
|
243
259
|
<ListItem {...props} HintElement={HintElement} />
|
|
244
260
|
);
|
|
@@ -270,7 +286,7 @@ const CustomListItem = ({
|
|
|
270
286
|
data={{ isOpen: selectMode }}
|
|
271
287
|
close={() => setSelectMode(false)}
|
|
272
288
|
onSelect={onSelectFieldType}
|
|
273
|
-
widgetsArray={
|
|
289
|
+
widgetsArray={widgetsArray}
|
|
274
290
|
/>
|
|
275
291
|
<EditModal
|
|
276
292
|
data={editModalData}
|
|
@@ -282,6 +298,4 @@ const CustomListItem = ({
|
|
|
282
298
|
</Fragment>
|
|
283
299
|
);
|
|
284
300
|
};
|
|
285
|
-
|
|
286
|
-
export default CustomListItem;
|
|
287
301
|
/* eslint-enable */
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
hintItemName: string;
|
|
39
|
+
customName?: string;
|
|
40
|
+
};
|
|
41
|
+
type CreateTopGroupWidgetArgs = CreateGroupWidgetArgsBase<GroupSM>;
|
|
42
|
+
type CreateNestedGroupWidgetArgs = CreateGroupWidgetArgsBase<NestedGroupSM> & {
|
|
43
|
+
customName: "NestedGroup";
|
|
44
|
+
};
|
|
45
|
+
type CreateGroupWidgetArgs =
|
|
46
|
+
| CreateTopGroupWidgetArgs
|
|
47
|
+
| CreateNestedGroupWidgetArgs;
|
|
48
|
+
|
|
49
|
+
export function createGroupWidget(
|
|
50
|
+
args: CreateTopGroupWidgetArgs,
|
|
51
|
+
): Widget<GroupSM, SchemaType>;
|
|
52
|
+
|
|
53
|
+
export function createGroupWidget(
|
|
54
|
+
args: CreateNestedGroupWidgetArgs,
|
|
55
|
+
): Widget<NestedGroupSM, SchemaType>;
|
|
56
|
+
|
|
57
|
+
export function createGroupWidget({
|
|
58
|
+
schemaTypeRegex,
|
|
59
|
+
customListItem,
|
|
60
|
+
customName,
|
|
61
|
+
hintItemName,
|
|
62
|
+
}: CreateGroupWidgetArgs):
|
|
63
|
+
| Widget<GroupSM, SchemaType>
|
|
64
|
+
| Widget<NestedGroupSM, SchemaType> {
|
|
65
|
+
return {
|
|
66
|
+
Meta,
|
|
67
|
+
Form,
|
|
68
|
+
FormFields,
|
|
69
|
+
schema: createSchema(schemaTypeRegex),
|
|
70
|
+
create: (label: string) => ({
|
|
71
|
+
type: "Group",
|
|
72
|
+
config: {
|
|
73
|
+
label,
|
|
74
|
+
repeat: true,
|
|
75
|
+
fields: [],
|
|
76
|
+
},
|
|
77
|
+
}),
|
|
78
|
+
CustomListItem: customListItem,
|
|
79
|
+
TYPE_NAME: "Group",
|
|
80
|
+
CUSTOM_NAME: customName,
|
|
81
|
+
hintItemName,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
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 hintItemName = "item";
|
|
52
|
+
|
|
53
|
+
const GroupListItem = (props: GroupListItemProps<GroupSM>): JSX.Element => {
|
|
54
|
+
const nestedGroupExperiment = useNestedGroupExperiment();
|
|
55
|
+
const maybeFilteredWidgetsArray = nestedGroupExperiment.eligible
|
|
56
|
+
? widgetsArray
|
|
57
|
+
: widgetsArray.filter((widget) => widget.CUSTOM_NAME !== "NestedGroup");
|
|
58
|
+
return (
|
|
59
|
+
<CustomListItem
|
|
60
|
+
Widgets={Widgets}
|
|
61
|
+
widgetsArray={maybeFilteredWidgetsArray}
|
|
62
|
+
hintBase={hintItemName}
|
|
63
|
+
{...props}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
export const GroupWidget = createGroupWidget({
|
|
69
|
+
schemaTypeRegex: /^Group$/,
|
|
70
|
+
customListItem: GroupListItem,
|
|
71
|
+
hintItemName,
|
|
72
|
+
});
|
|
@@ -0,0 +1,40 @@
|
|
|
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 hintItemName = "subItem";
|
|
25
|
+
|
|
26
|
+
const NestedGroupListItem = (props: GroupListItemProps<NestedGroupSM>) => (
|
|
27
|
+
<CustomListItem
|
|
28
|
+
Widgets={Widgets}
|
|
29
|
+
widgetsArray={widgetsArray}
|
|
30
|
+
hintBase={hintItemName}
|
|
31
|
+
{...props}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
export const NestedGroupWidget = createGroupWidget({
|
|
36
|
+
schemaTypeRegex: /^NestedGroup$/,
|
|
37
|
+
customListItem: NestedGroupListItem,
|
|
38
|
+
customName: "NestedGroup",
|
|
39
|
+
hintItemName,
|
|
40
|
+
});
|
|
@@ -3,8 +3,9 @@ import { IconType } from "react-icons";
|
|
|
3
3
|
import { AnyObjectSchema } from "yup";
|
|
4
4
|
|
|
5
5
|
import { TabField } from "@/legacy/lib/models/common/CustomType";
|
|
6
|
+
import { GroupSM, NestedGroupSM } from "@/legacy/lib/models/common/Group";
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
interface WidgetBase<F extends TabField, S extends AnyObjectSchema> {
|
|
8
9
|
TYPE_NAME: FieldType;
|
|
9
10
|
create: (label: string) => F;
|
|
10
11
|
Meta: {
|
|
@@ -23,5 +24,13 @@ export interface Widget<F extends TabField, S extends AnyObjectSchema> {
|
|
|
23
24
|
prepareInitialValues?: (props: F["config"]) => F["config"];
|
|
24
25
|
}
|
|
25
26
|
|
|
27
|
+
export type Widget<F extends TabField, S extends AnyObjectSchema> = F extends
|
|
28
|
+
| GroupSM
|
|
29
|
+
| NestedGroupSM
|
|
30
|
+
? WidgetBase<F, S> & {
|
|
31
|
+
hintItemName: string;
|
|
32
|
+
}
|
|
33
|
+
: WidgetBase<F, S>;
|
|
34
|
+
|
|
26
35
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-explicit-any, @typescript-eslint/no-explicit-any
|
|
27
36
|
export type AnyWidget = Widget<any, any>;
|