@plaudit/gutenberg-api-extensions 2.43.2 → 2.44.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/build/blocks/MoveError.d.ts +10 -0
- package/build/blocks/MoveError.js +6 -0
- package/build/blocks/MoveError.js.map +1 -0
- package/build/blocks/PathError.d.ts +12 -0
- package/build/blocks/PathError.js +18 -0
- package/build/blocks/PathError.js.map +1 -0
- package/build/blocks/{snp-group-component.d.ts → SNPGroupComponent.d.ts} +6 -7
- package/build/blocks/SNPGroupComponent.js +6 -0
- package/build/blocks/SNPGroupComponent.js.map +1 -0
- package/build/blocks/SNPListComponent.d.ts +8 -0
- package/build/blocks/SNPListComponent.js +15 -0
- package/build/blocks/SNPListComponent.js.map +1 -0
- package/build/blocks/SNPTreeContext.d.ts +10 -0
- package/build/blocks/SNPTreeContext.js +15 -0
- package/build/blocks/SNPTreeContext.js.map +1 -0
- package/build/blocks/common-native-property-constructors.d.ts +14 -8
- package/build/blocks/common-native-property-constructors.js +128 -92
- package/build/blocks/common-native-property-constructors.js.map +1 -1
- package/build/blocks/conditions.d.ts +21 -0
- package/build/blocks/conditions.js +155 -0
- package/build/blocks/conditions.js.map +1 -0
- package/build/blocks/data-controller-manager.d.ts +8 -0
- package/build/blocks/data-controller-manager.js +38 -0
- package/build/blocks/data-controller-manager.js.map +1 -0
- package/build/blocks/data-controller.d.ts +62 -0
- package/build/blocks/data-controller.js +641 -0
- package/build/blocks/data-controller.js.map +1 -0
- package/build/blocks/full-size-toggle-control.d.ts +3 -3
- package/build/blocks/full-size-toggle-control.js +35 -32
- package/build/blocks/full-size-toggle-control.js.map +1 -1
- package/build/blocks/layered-styles-api.d.ts +3 -3
- package/build/blocks/layered-styles-api.js +2 -1
- package/build/blocks/layered-styles-api.js.map +1 -1
- package/build/blocks/layered-styles-impl.js +2 -4
- package/build/blocks/layered-styles-impl.js.map +1 -1
- package/build/blocks/layout/LaidOutProperty.d.ts +6 -0
- package/build/blocks/layout/LaidOutProperty.js +28 -0
- package/build/blocks/layout/LaidOutProperty.js.map +1 -0
- package/build/blocks/layout/LaidOutPropertyRow.d.ts +6 -0
- package/build/blocks/layout/LaidOutPropertyRow.js +12 -0
- package/build/blocks/layout/LaidOutPropertyRow.js.map +1 -0
- package/build/blocks/layout/NodeContext.d.ts +44 -0
- package/build/blocks/layout/NodeContext.js +37 -0
- package/build/blocks/layout/NodeContext.js.map +1 -0
- package/build/blocks/layout/PanelRoot.d.ts +5 -0
- package/build/blocks/layout/PanelRoot.js +23 -0
- package/build/blocks/layout/PanelRoot.js.map +1 -0
- package/build/blocks/layout/TabsRoot.d.ts +7 -0
- package/build/blocks/layout/TabsRoot.js +45 -0
- package/build/blocks/layout/TabsRoot.js.map +1 -0
- package/build/blocks/simple-block.js +6 -10
- package/build/blocks/simple-block.js.map +1 -1
- package/build/blocks/simple-native-property-api.d.ts +63 -28
- package/build/blocks/simple-native-property-api.js +9 -2
- package/build/blocks/simple-native-property-api.js.map +1 -1
- package/build/blocks/simple-native-property-impl.d.ts +0 -6
- package/build/blocks/simple-native-property-impl.js +121 -189
- package/build/blocks/simple-native-property-impl.js.map +1 -1
- package/build/blocks/simple-native-property-internal-shared.d.ts +30 -0
- package/build/blocks/simple-native-property-internal-shared.js +22 -0
- package/build/blocks/simple-native-property-internal-shared.js.map +1 -0
- package/build/blocks/snp-data-store.d.ts +8 -9
- package/build/blocks/snp-data-store.js +56 -31
- package/build/blocks/snp-data-store.js.map +1 -1
- package/build/controls/AsynchronousFormTokenField.d.ts +3 -3
- package/build/controls/AsynchronousFormTokenField.js +4 -18
- package/build/controls/AsynchronousFormTokenField.js.map +1 -1
- package/build/controls/ExtendedPostPicker.d.ts +3 -3
- package/build/controls/ExtendedPostPicker.js +4 -3
- package/build/controls/ExtendedPostPicker.js.map +1 -1
- package/build/controls/ExtendedRadioControl.d.ts +3 -3
- package/build/controls/ExtendedRadioControl.js +3 -11
- package/build/controls/ExtendedRadioControl.js.map +1 -1
- package/build/controls/ImageControl.d.ts +4 -2
- package/build/controls/ImageControl.js +16 -23
- package/build/controls/ImageControl.js.map +1 -1
- package/build/controls/InspectorPanel.d.ts +2 -2
- package/build/controls/InspectorPanel.js +4 -6
- package/build/controls/InspectorPanel.js.map +1 -1
- package/build/controls/LazySuggestionsComboboxControl.d.ts +1 -2
- package/build/controls/LazySuggestionsComboboxControl.js +3 -9
- package/build/controls/LazySuggestionsComboboxControl.js.map +1 -1
- package/build/controls/MultiSelectControl.d.ts +3 -3
- package/build/controls/MultiSelectControl.js +2 -2
- package/build/controls/MultiSelectControl.js.map +1 -1
- package/build/controls/PickOne.d.ts +5 -5
- package/build/controls/PickOne.js +7 -8
- package/build/controls/PickOne.js.map +1 -1
- package/build/controls/PromisableComponent.d.ts +1 -1
- package/build/controls/PromisableComponent.js +3 -3
- package/build/controls/PromisableComponent.js.map +1 -1
- package/build/controls/ProperLinkControl.d.ts +3 -3
- package/build/controls/ProperLinkControl.js +6 -9
- package/build/controls/ProperLinkControl.js.map +1 -1
- package/build/controls/SimpleToggle.d.ts +1 -2
- package/build/controls/SimpleToggle.js +2 -2
- package/build/controls/SimpleToggle.js.map +1 -1
- package/build/controls/SortableItemsControl.d.ts +7 -4
- package/build/controls/SortableItemsControl.js +12 -24
- package/build/controls/SortableItemsControl.js.map +1 -1
- package/build/controls/hooks/useTokenManager.js.map +1 -1
- package/build/editor/post-featured-image.js +29 -31
- package/build/editor/post-featured-image.js.map +1 -1
- package/build/lib/plaudit-icons/column-1.d.ts +1 -2
- package/build/lib/plaudit-icons/column-1.js +2 -3
- package/build/lib/plaudit-icons/column-1.js.map +1 -1
- package/build/lib/plaudit-icons/column-2.d.ts +1 -2
- package/build/lib/plaudit-icons/column-2.js +2 -3
- package/build/lib/plaudit-icons/column-2.js.map +1 -1
- package/build/lib/plaudit-icons/column-3.d.ts +1 -2
- package/build/lib/plaudit-icons/column-3.js +2 -3
- package/build/lib/plaudit-icons/column-3.js.map +1 -1
- package/build/lib/plaudit-icons/placement-center.d.ts +1 -2
- package/build/lib/plaudit-icons/placement-center.js +2 -3
- package/build/lib/plaudit-icons/placement-center.js.map +1 -1
- package/build/lib/plaudit-icons/placement-end.d.ts +1 -2
- package/build/lib/plaudit-icons/placement-end.js +2 -3
- package/build/lib/plaudit-icons/placement-end.js.map +1 -1
- package/build/lib/plaudit-icons/placement-start.d.ts +1 -2
- package/build/lib/plaudit-icons/placement-start.js +2 -3
- package/build/lib/plaudit-icons/placement-start.js.map +1 -1
- package/build/lib/plaudit-icons/placement-stretch.d.ts +1 -2
- package/build/lib/plaudit-icons/placement-stretch.js +2 -3
- package/build/lib/plaudit-icons/placement-stretch.js.map +1 -1
- package/build/lib/plaudit-icons/plaudit-icon.d.ts +1 -2
- package/build/lib/plaudit-icons/plaudit-icon.js +2 -3
- package/build/lib/plaudit-icons/plaudit-icon.js.map +1 -1
- package/build/lib/plaudit-icons/reusable-block-marker.d.ts +1 -2
- package/build/lib/plaudit-icons/reusable-block-marker.js +2 -3
- package/build/lib/plaudit-icons/reusable-block-marker.js.map +1 -1
- package/package.json +6 -2
- package/styles/editor.pcss +47 -0
- package/build/blocks/base-data-store.d.ts +0 -19
- package/build/blocks/base-data-store.js +0 -151
- package/build/blocks/base-data-store.js.map +0 -1
- package/build/blocks/data-store-list-holder.d.ts +0 -10
- package/build/blocks/data-store-list-holder.js +0 -55
- package/build/blocks/data-store-list-holder.js.map +0 -1
- package/build/blocks/object-data-store.d.ts +0 -15
- package/build/blocks/object-data-store.js +0 -41
- package/build/blocks/object-data-store.js.map +0 -1
- package/build/blocks/snp-group-component.js +0 -17
- package/build/blocks/snp-group-component.js.map +0 -1
|
@@ -0,0 +1,641 @@
|
|
|
1
|
+
import { useMemo } from "@wordpress/element";
|
|
2
|
+
import { configureStore } from "@reduxjs/toolkit";
|
|
3
|
+
import { produce } from "immer";
|
|
4
|
+
import { resolveValueForCondition, testCondition } from "./conditions";
|
|
5
|
+
import { MoveError } from "./MoveError";
|
|
6
|
+
import { PathError, PathErrorType } from "./PathError";
|
|
7
|
+
export function useDataController(blockClientId) {
|
|
8
|
+
return useMemo(() => {
|
|
9
|
+
const initialState = { treeRoot: { children: {}, rendered: true }, dataStores: { byProperty: {}, list: [] }, blockClientId };
|
|
10
|
+
const store = configureStore({
|
|
11
|
+
reducer(state = initialState, action) {
|
|
12
|
+
switch (action.type) {
|
|
13
|
+
case "addProperties":
|
|
14
|
+
return produce(state, (draft) => {
|
|
15
|
+
if (!draft.dataStores.list.includes(action.dataStore)) {
|
|
16
|
+
draft.dataStores.list.push(action.dataStore);
|
|
17
|
+
}
|
|
18
|
+
for (const property of action.properties) {
|
|
19
|
+
if (Array.isArray(property)) {
|
|
20
|
+
for (const prop of property) {
|
|
21
|
+
draft.dataStores.byProperty[prop.name] = action.dataStore;
|
|
22
|
+
draft.treeRoot.children[prop.name] = buildNodeFromDataAndDefinition(action.dataStore.getValue(prop.name), prop);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
draft.dataStores.byProperty[property.name] = action.dataStore;
|
|
27
|
+
draft.treeRoot.children[property.name] = buildNodeFromDataAndDefinition(action.dataStore.getValue(property.name), property);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
if (!action.inBatch) {
|
|
31
|
+
performConditionChecks(draft, state, blockClientId);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
case "checkConditions":
|
|
35
|
+
return produce(state, (draft) => performConditionChecks(draft, state, blockClientId));
|
|
36
|
+
case "validateNodes":
|
|
37
|
+
return produce(state, (draft) => {
|
|
38
|
+
applyToTree(draft.treeRoot, (node, path) => {
|
|
39
|
+
if (!node.rendered) {
|
|
40
|
+
return TreeMutatorResult.SKIP_DESCENDANTS;
|
|
41
|
+
}
|
|
42
|
+
validateFoundNode(node, path, draft);
|
|
43
|
+
return TreeMutatorResult.CONTINUE;
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const { path, type } = action;
|
|
48
|
+
switch (type) {
|
|
49
|
+
case "addNode":
|
|
50
|
+
const parentDefinition = resolveParentNodeDefinition(state.treeRoot, path);
|
|
51
|
+
if (!parentDefinition) {
|
|
52
|
+
throw new Error("Cannot add children to a node without a definition");
|
|
53
|
+
}
|
|
54
|
+
const nodeName = path[path.length - 1];
|
|
55
|
+
if (typeof nodeName === 'string') {
|
|
56
|
+
const definition = parentDefinition.children?.find(definition => definition.name === nodeName);
|
|
57
|
+
if (definition === undefined) {
|
|
58
|
+
throw new PathError("Unable to locate the definition of the named node.", path);
|
|
59
|
+
}
|
|
60
|
+
const data = populateValueBasedOnDefinition(action.value, parentDefinition);
|
|
61
|
+
const builtNode = buildNodeFromDataAndDefinition(data, definition);
|
|
62
|
+
return produce(state, (draft) => {
|
|
63
|
+
const parentNode = walkToNode(draft.treeRoot, path.slice(0, path.length - 1));
|
|
64
|
+
if (parentNode.children === undefined) {
|
|
65
|
+
parentNode.children = { [nodeName]: builtNode };
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
if (Array.isArray(parentNode.children)) {
|
|
69
|
+
throw new PathError("Encountered a node with indexed descendants while expecting one with string-keyed descendants.", path);
|
|
70
|
+
}
|
|
71
|
+
parentNode.children[nodeName] = builtNode;
|
|
72
|
+
}
|
|
73
|
+
writeValueToBackingDataStoreWithCorrections(path, state, data);
|
|
74
|
+
if (!action.inBatch) {
|
|
75
|
+
performConditionChecks(draft, state, blockClientId);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
else if (nodeName === undefined) {
|
|
80
|
+
throw new PathError("Encountered an undefined name in a path.", path);
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const data = populateValueBasedOnDefinition(action.value, parentDefinition);
|
|
84
|
+
const builtNode = buildNodeFromDataAndDefinition(data, parentDefinition);
|
|
85
|
+
return produce(state, (draft) => {
|
|
86
|
+
const parentNode = walkToNode(draft.treeRoot, path.slice(0, path.length - 1));
|
|
87
|
+
if (parentNode.children === undefined) {
|
|
88
|
+
parentNode.children = [];
|
|
89
|
+
parentNode.children[nodeName] = builtNode;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
if (!Array.isArray(parentNode.children)) {
|
|
93
|
+
throw new PathError("Encountered a node with string-keyed descendants while expecting one with indexed descendants.", path);
|
|
94
|
+
}
|
|
95
|
+
parentNode.children[nodeName] = builtNode;
|
|
96
|
+
}
|
|
97
|
+
writeValueToBackingDataStoreWithCorrections(path, state, data);
|
|
98
|
+
if (!action.inBatch) {
|
|
99
|
+
performConditionChecks(draft, state, blockClientId);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
case "removeNode":
|
|
104
|
+
return produce(state, (draft) => {
|
|
105
|
+
const parentNode = walkToNode(draft.treeRoot, path.slice(0, path.length - 1));
|
|
106
|
+
removeFromParentNode(parentNode.children, path);
|
|
107
|
+
removeValueFromBackingDataStore(getDataStore(path[0], state), path);
|
|
108
|
+
if (!action.inBatch) {
|
|
109
|
+
performConditionChecks(draft, state, blockClientId);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
case "moveNode":
|
|
113
|
+
// If from and to are the same, then this is a no-op, so we can just skip it
|
|
114
|
+
if (action.from === action.to) {
|
|
115
|
+
return state;
|
|
116
|
+
}
|
|
117
|
+
return produce(state, (draft) => {
|
|
118
|
+
moveNodeWithinParent(walkToNode(draft.treeRoot, path).children, path, action);
|
|
119
|
+
const dataStore = getDataStore(path[0], state);
|
|
120
|
+
dataStore.setValue(path[0], produce(dataStore.getValue(path[0]), (dsDraft) => {
|
|
121
|
+
moveNodeWithinParent(walkToNodeInValue(dsDraft, path), path, action);
|
|
122
|
+
}));
|
|
123
|
+
if (!action.inBatch) {
|
|
124
|
+
performConditionChecks(draft, state, blockClientId);
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
case "validateNode":
|
|
128
|
+
return produce(state, (draft) => validateNode(path, draft)); //TODO: Write something to the block metadata on validation change to force an update
|
|
129
|
+
case "writeValue":
|
|
130
|
+
writeValueToBackingDataStoreWithCorrections(path, state, action.value);
|
|
131
|
+
if (!action.inBatch) {
|
|
132
|
+
return produce(state, (draft) => {
|
|
133
|
+
validateNode(path, draft);
|
|
134
|
+
performConditionChecks(draft, state, blockClientId);
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
return state;
|
|
138
|
+
}
|
|
139
|
+
return state; // WordPress likes hammering redux stores with invalid actions for some reason, so we have to have this
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
function getDataStoreImpl(property, required) {
|
|
143
|
+
return required ? getDataStore(property, store.getState(), true) : getDataStore(property, store.getState(), false);
|
|
144
|
+
}
|
|
145
|
+
const dataController = {
|
|
146
|
+
dispatch(action) {
|
|
147
|
+
return store.dispatch(action);
|
|
148
|
+
},
|
|
149
|
+
getDataStore: getDataStoreImpl,
|
|
150
|
+
getAllDataStores() {
|
|
151
|
+
return store.getState().dataStores.list;
|
|
152
|
+
},
|
|
153
|
+
makePropertyValueResolver(contextPath) {
|
|
154
|
+
return propertyPath => resolveValueForCondition(propertyPath, contextPath, blockClientId, getDataStoreImpl);
|
|
155
|
+
},
|
|
156
|
+
getValue(path) {
|
|
157
|
+
return getOptionalValue(path, store.getState());
|
|
158
|
+
},
|
|
159
|
+
setValue(path, value) {
|
|
160
|
+
store.dispatch({ type: "writeValue", path, value });
|
|
161
|
+
},
|
|
162
|
+
addProperties(properties, dataStore, inBatch) {
|
|
163
|
+
store.dispatch({ type: "addProperties", properties, dataStore, inBatch });
|
|
164
|
+
},
|
|
165
|
+
addNode(path, value) {
|
|
166
|
+
try {
|
|
167
|
+
store.dispatch({ type: "addNode", path, value });
|
|
168
|
+
}
|
|
169
|
+
catch (e) {
|
|
170
|
+
if (e instanceof PathError && e.errorType === PathErrorType.UNEXPECTED_LEAF) {
|
|
171
|
+
for (let i = e.errorIndex; i < path.length - 1; i++) {
|
|
172
|
+
store.dispatch({ type: "addNode", path: path.slice(0, i), inBatch: true });
|
|
173
|
+
}
|
|
174
|
+
store.dispatch({ type: "addNode", path, value });
|
|
175
|
+
}
|
|
176
|
+
throw e;
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
removeNode(path) {
|
|
180
|
+
store.dispatch({ type: "removeNode", path });
|
|
181
|
+
},
|
|
182
|
+
moveNode(path, indices) {
|
|
183
|
+
store.dispatch({ type: "moveNode", path, ...indices });
|
|
184
|
+
},
|
|
185
|
+
hasRenderedNode(properties) {
|
|
186
|
+
const rootNodes = store.getState().treeRoot.children;
|
|
187
|
+
for (const property of properties) {
|
|
188
|
+
if (Array.isArray(property)) {
|
|
189
|
+
for (const prop of property) {
|
|
190
|
+
if (rootNodes[prop.name]?.rendered) {
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
else if (rootNodes[property.name]?.rendered) {
|
|
196
|
+
return true;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return false;
|
|
200
|
+
},
|
|
201
|
+
hasValidationErrors(properties) {
|
|
202
|
+
if (properties === undefined) {
|
|
203
|
+
return testForValidationErrors(store.getState().treeRoot);
|
|
204
|
+
}
|
|
205
|
+
const rootNodes = store.getState().treeRoot.children;
|
|
206
|
+
for (const property of properties) {
|
|
207
|
+
if (Array.isArray(property)) {
|
|
208
|
+
for (const prop of property) {
|
|
209
|
+
if (testForValidationErrors(rootNodes[prop.name])) {
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
else if (testForValidationErrors(rootNodes[property.name])) {
|
|
215
|
+
return true;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return false;
|
|
219
|
+
},
|
|
220
|
+
getIsRendered(path) {
|
|
221
|
+
return walkToNode(store.getState().treeRoot, path).rendered ?? true;
|
|
222
|
+
},
|
|
223
|
+
getNode(path) {
|
|
224
|
+
return walkToNode(store.getState().treeRoot, path);
|
|
225
|
+
},
|
|
226
|
+
getValidationError(path) {
|
|
227
|
+
return walkToNode(store.getState().treeRoot, path).validationError;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
return dataController;
|
|
231
|
+
}, [blockClientId]);
|
|
232
|
+
}
|
|
233
|
+
function getOptionalValue(path, state) {
|
|
234
|
+
try {
|
|
235
|
+
return walkToNodeInValue(getDataStore(path[0], state).getValue(path[0]), path);
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
if (e instanceof PathError) {
|
|
239
|
+
return undefined;
|
|
240
|
+
}
|
|
241
|
+
throw e;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
function testForValidationErrors(node) {
|
|
245
|
+
if (!node || !node.rendered) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
else if (node.validationError) {
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
else if (Array.isArray(node.children)) {
|
|
252
|
+
for (const child of node.children) {
|
|
253
|
+
if (testForValidationErrors(child)) {
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
else if (node.children !== undefined) {
|
|
259
|
+
for (const child of Object.values(node.children)) {
|
|
260
|
+
if (testForValidationErrors(child)) {
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
function validateNode(path, draft) {
|
|
268
|
+
validateFoundNode(walkToNode(draft.treeRoot, path), path, draft);
|
|
269
|
+
}
|
|
270
|
+
function removeFromParentNode(parentNode, path) {
|
|
271
|
+
if (typeof parentNode !== 'object' || parentNode === undefined || parentNode === null) {
|
|
272
|
+
throw new PathError("Encountered a non-existent node while expecting one.", path);
|
|
273
|
+
}
|
|
274
|
+
const nodeName = path[path.length - 1];
|
|
275
|
+
if (typeof nodeName === 'string') {
|
|
276
|
+
if (Array.isArray(parentNode)) {
|
|
277
|
+
throw new PathError("Encountered a node with indexed descendants while expecting one with string-keyed descendants.", path, path.length - 1);
|
|
278
|
+
}
|
|
279
|
+
delete parentNode[nodeName];
|
|
280
|
+
}
|
|
281
|
+
else if (nodeName === undefined) {
|
|
282
|
+
throw new PathError("Encountered an undefined name in a path.", path);
|
|
283
|
+
}
|
|
284
|
+
else {
|
|
285
|
+
if (!Array.isArray(parentNode)) {
|
|
286
|
+
throw new PathError("Encountered a node with string-keyed descendants while expecting one with indexed descendants.", path, path.length - 1);
|
|
287
|
+
}
|
|
288
|
+
parentNode.splice(nodeName, 1);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
function moveNodeWithinParent(parentNode, path, move) {
|
|
292
|
+
if (typeof parentNode !== 'object' || parentNode === undefined || parentNode === null) {
|
|
293
|
+
throw new PathError("Encountered a non-existent node while expecting one.", path);
|
|
294
|
+
}
|
|
295
|
+
if (isNumericMove(move)) {
|
|
296
|
+
if (!Array.isArray(parentNode)) {
|
|
297
|
+
throw new MoveError("Attempted to move a child of a node with string-keyed descendants by index", path, move);
|
|
298
|
+
}
|
|
299
|
+
if (move.from > move.to) {
|
|
300
|
+
parentNode.splice(move.to, 0, ...parentNode.splice(move.from, 1));
|
|
301
|
+
}
|
|
302
|
+
else { //We know that
|
|
303
|
+
parentNode.splice(move.to - 1, 0, ...parentNode.splice(move.from, 1));
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
else {
|
|
307
|
+
if (Array.isArray(parentNode)) {
|
|
308
|
+
throw new MoveError("Attempted to move a child of a node with indexed descendants by string-key", path, move);
|
|
309
|
+
}
|
|
310
|
+
if (parentNode[move.to] !== undefined) {
|
|
311
|
+
throw new MoveError("Attempted to move a string-keyed child to the same key as another", path, move);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function isNumericMove(move) {
|
|
316
|
+
return typeof move.from === 'number' && typeof move.to === 'number';
|
|
317
|
+
}
|
|
318
|
+
function resolveParentNodeDefinition(root, path) {
|
|
319
|
+
if (path.length < 2) {
|
|
320
|
+
throw new PathError("Unable to get the parent node of a path with less than two nodes", path, path.length - 1, PathErrorType.INSUFFICIENT_LENGTH);
|
|
321
|
+
}
|
|
322
|
+
return walkToNode(root, path.slice(0, path.length - (typeof path[path.length - 2] === 'number' ? 2 : 1))).definition;
|
|
323
|
+
}
|
|
324
|
+
function buildDefaultValueFromDefinition(definition, forArrayEntry = false) {
|
|
325
|
+
if (definition === undefined) {
|
|
326
|
+
return undefined;
|
|
327
|
+
}
|
|
328
|
+
else if (definition.default !== undefined || !definition.children?.length) {
|
|
329
|
+
return definition.default;
|
|
330
|
+
}
|
|
331
|
+
else if (forArrayEntry) {
|
|
332
|
+
if (definition.type !== 'array' && definition.type !== 'object') {
|
|
333
|
+
return undefined;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
else if (definition.type === 'array') {
|
|
337
|
+
return [];
|
|
338
|
+
}
|
|
339
|
+
else if (definition.type !== 'object') {
|
|
340
|
+
return undefined;
|
|
341
|
+
}
|
|
342
|
+
return Object.fromEntries(definition.children.map(def => [def.name, buildDefaultValueFromDefinition(def)]));
|
|
343
|
+
}
|
|
344
|
+
function populateValueBasedOnDefinition(value, definition, forArrayEntry = false) {
|
|
345
|
+
if (!definition?.children?.length) {
|
|
346
|
+
return value;
|
|
347
|
+
}
|
|
348
|
+
else if (value === null || value === undefined) {
|
|
349
|
+
return buildDefaultValueFromDefinition(definition, forArrayEntry);
|
|
350
|
+
}
|
|
351
|
+
else if (typeof value !== 'object') {
|
|
352
|
+
return value;
|
|
353
|
+
}
|
|
354
|
+
else if (Array.isArray(value)) {
|
|
355
|
+
return value;
|
|
356
|
+
}
|
|
357
|
+
return { ...value, ...Object.fromEntries(definition.children.map(def => [def.name, populateValueBasedOnDefinition(value[def.name], def)])) };
|
|
358
|
+
}
|
|
359
|
+
function walkToNode(root, path) {
|
|
360
|
+
let current = root;
|
|
361
|
+
for (let i = 0; i < path.length; i++) {
|
|
362
|
+
current = descendIntoDCNodeChild(current, path, i);
|
|
363
|
+
}
|
|
364
|
+
return current;
|
|
365
|
+
}
|
|
366
|
+
function descendIntoDCNodeChild(current, path, i) {
|
|
367
|
+
if (current?.children === undefined) {
|
|
368
|
+
throw new PathError("Encountered a leaf node while expecting one with descendants.", path, i, PathErrorType.UNEXPECTED_LEAF);
|
|
369
|
+
}
|
|
370
|
+
const pathNode = path[i];
|
|
371
|
+
if (typeof pathNode === 'string') {
|
|
372
|
+
if (Array.isArray(current.children)) {
|
|
373
|
+
throw new PathError("Encountered a node with indexed descendants while expecting one with string-keyed descendants.", path, i);
|
|
374
|
+
}
|
|
375
|
+
current = current.children[pathNode];
|
|
376
|
+
}
|
|
377
|
+
else if (pathNode === undefined) {
|
|
378
|
+
throw new PathError("Encountered an undefined name in a path.", path, i);
|
|
379
|
+
}
|
|
380
|
+
else {
|
|
381
|
+
if (!Array.isArray(current.children)) {
|
|
382
|
+
throw new PathError("Encountered a node with string-keyed descendants while expecting one with indexed descendants.", path, i);
|
|
383
|
+
}
|
|
384
|
+
current = current.children[pathNode];
|
|
385
|
+
}
|
|
386
|
+
if (current === undefined) {
|
|
387
|
+
throw new PathError("Encountered a non-existent node while expecting one.", path, i, PathErrorType.UNEXPECTED_LEAF);
|
|
388
|
+
}
|
|
389
|
+
return current;
|
|
390
|
+
}
|
|
391
|
+
function performConditionChecks(draft, state, blockClientId) {
|
|
392
|
+
const propertyValueResolverBuilder = path => propertyPath => resolveValueForCondition(propertyPath, path, blockClientId, property => getDataStore(property, draft, false));
|
|
393
|
+
applyToTree(draft.treeRoot, (node, path) => {
|
|
394
|
+
const condition = node.condition;
|
|
395
|
+
if (condition === undefined) {
|
|
396
|
+
node.rendered = true;
|
|
397
|
+
return TreeMutatorResult.CONTINUE;
|
|
398
|
+
}
|
|
399
|
+
else {
|
|
400
|
+
const newRendered = testCondition(condition, propertyValueResolverBuilder(path));
|
|
401
|
+
if (newRendered !== node.rendered) {
|
|
402
|
+
const dataStore = getDataStore(path[0], state);
|
|
403
|
+
let currentValue;
|
|
404
|
+
try {
|
|
405
|
+
currentValue = walkToNodeInValue(dataStore.getValue(path[0]), path);
|
|
406
|
+
}
|
|
407
|
+
catch (e) {
|
|
408
|
+
if (!(e instanceof PathError)) {
|
|
409
|
+
throw e;
|
|
410
|
+
}
|
|
411
|
+
currentValue = undefined;
|
|
412
|
+
}
|
|
413
|
+
if (!newRendered) {
|
|
414
|
+
// Create a backup if we are transitioning from rendered -> unrendered
|
|
415
|
+
node.backup = currentValue;
|
|
416
|
+
removeValueFromBackingDataStore(dataStore, path);
|
|
417
|
+
}
|
|
418
|
+
else if (currentValue === undefined) {
|
|
419
|
+
// Restore from backup if we are transitioning from unrendered -> rendered
|
|
420
|
+
const stateNode = walkToNode(state.treeRoot, path);
|
|
421
|
+
writeValueToBackingDataStore(dataStore, path, stateNode.backup ?? buildDefaultValueFromDefinition(stateNode.definition));
|
|
422
|
+
}
|
|
423
|
+
node.rendered = newRendered;
|
|
424
|
+
}
|
|
425
|
+
return node.rendered ? TreeMutatorResult.CONTINUE : TreeMutatorResult.SKIP_DESCENDANTS;
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
function validateFoundNode(node, path, draft) {
|
|
430
|
+
const definition = node.definition;
|
|
431
|
+
if (definition) {
|
|
432
|
+
let validationError;
|
|
433
|
+
const value = getOptionalValue(path, draft);
|
|
434
|
+
if (definition.required && !value) {
|
|
435
|
+
validationError = `"${definition.label || definition.name}" is required.`;
|
|
436
|
+
}
|
|
437
|
+
else {
|
|
438
|
+
validationError = definition.validator?.(value) ?? "";
|
|
439
|
+
}
|
|
440
|
+
if (node.validationError !== validationError) {
|
|
441
|
+
const dataStore = getDataStore(path[0], draft);
|
|
442
|
+
dataStore.blockEditProps.setAttributes({ __plauditGAEValidationTicker: (dataStore.blockEditProps.attributes['__plauditGAEValidationTicker'] ?? 0) + 1 });
|
|
443
|
+
node.validationError = validationError;
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
function getDataStore(property, state, throwOnError = true) {
|
|
448
|
+
let dataStore = state.dataStores.byProperty[property];
|
|
449
|
+
if (dataStore) {
|
|
450
|
+
return dataStore;
|
|
451
|
+
}
|
|
452
|
+
dataStore = state.dataStores.list.find(dataStore => dataStore.handlesProperty(property));
|
|
453
|
+
console.warn(`Unable to locate the DataStore for ${property} via the byProperty map, but did find a DataStore that handles that property. This should not be possible.`);
|
|
454
|
+
if (!dataStore) {
|
|
455
|
+
if (throwOnError) {
|
|
456
|
+
throw new Error(`Unable to resolve the dataStore for ${property} on block ${state.blockClientId}`);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return dataStore;
|
|
460
|
+
}
|
|
461
|
+
function removeValueFromBackingDataStore(dataStore, path) {
|
|
462
|
+
const dsValue = dataStore.getValue(path[0]);
|
|
463
|
+
if (path.length === 1) {
|
|
464
|
+
dataStore.setValue(path[0], undefined);
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
dataStore.setValue(path[0], produce(dsValue, (dsValueDraft) => {
|
|
468
|
+
const nodeParent = walkToNodeInValue(dsValueDraft, path.slice(0, path.length - 1));
|
|
469
|
+
const nodeName = path[path.length - 1];
|
|
470
|
+
if (typeof nodeName === 'string') {
|
|
471
|
+
delete nodeParent[nodeName];
|
|
472
|
+
}
|
|
473
|
+
else if (nodeName === undefined) {
|
|
474
|
+
throw new PathError("Encountered an undefined name in a path.", path);
|
|
475
|
+
}
|
|
476
|
+
else {
|
|
477
|
+
nodeParent.splice(nodeName, 1);
|
|
478
|
+
}
|
|
479
|
+
}));
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
function writeValueToBackingDataStoreWithCorrections(path, state, value) {
|
|
483
|
+
if (typeof value === 'number' && Number.isNaN(value)) {
|
|
484
|
+
value = undefined; // This ensures that NaN's don't get stored
|
|
485
|
+
}
|
|
486
|
+
const rootDCNode = state.treeRoot.children[path[0]];
|
|
487
|
+
if (rootDCNode === undefined) {
|
|
488
|
+
throw new PathError("Encountered a path pointing to a non-existent root node.", path, 0);
|
|
489
|
+
}
|
|
490
|
+
const dataStore = getDataStore(path[0], state);
|
|
491
|
+
if (path.length === 1) {
|
|
492
|
+
dataStore.setValue(path[0], value ?? buildDefaultValueFromDefinition(rootDCNode.definition));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
dataStore.setValue(path[0], produce(dataStore.getValue(path[0]), (dsValueDraft) => {
|
|
496
|
+
let currentDSValue = dsValueDraft;
|
|
497
|
+
let closestUsableDefinition = rootDCNode.definition;
|
|
498
|
+
let currentDCNode = rootDCNode;
|
|
499
|
+
for (let i = 1; i < path.length - 1; i++) {
|
|
500
|
+
const nodeName = path[i];
|
|
501
|
+
currentDCNode = descendIntoDCNodeChild(currentDCNode, path, i);
|
|
502
|
+
if (typeof nodeName === 'string') {
|
|
503
|
+
//We only update the definition being used when we descend into a new node proper
|
|
504
|
+
closestUsableDefinition = currentDCNode.definition;
|
|
505
|
+
}
|
|
506
|
+
else if (nodeName === undefined) {
|
|
507
|
+
throw new PathError("Encountered an undefined name in a path.", path, i);
|
|
508
|
+
}
|
|
509
|
+
let nextDSValue = descendIntoDSValueNodeChild(currentDSValue, path, i);
|
|
510
|
+
if (nextDSValue === undefined) {
|
|
511
|
+
currentDSValue[nodeName] = buildDefaultValueFromDefinition(closestUsableDefinition);
|
|
512
|
+
currentDSValue = descendIntoDSValueNodeChild(currentDSValue, path, i);
|
|
513
|
+
if (currentDSValue === undefined) {
|
|
514
|
+
throw new PathError("Encountered a leaf node while expecting one with descendants.", path, i, PathErrorType.UNEXPECTED_LEAF);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
else {
|
|
518
|
+
currentDSValue = nextDSValue;
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
const nodeName = path[path.length - 1];
|
|
522
|
+
if (nodeName === undefined) {
|
|
523
|
+
throw new PathError("Encountered an undefined name in a path.", path);
|
|
524
|
+
}
|
|
525
|
+
currentDSValue[nodeName] = value;
|
|
526
|
+
}));
|
|
527
|
+
}
|
|
528
|
+
function writeValueToBackingDataStore(dataStore, path, value) {
|
|
529
|
+
if (typeof value === 'number' && Number.isNaN(value)) {
|
|
530
|
+
value = undefined; // This ensures that NaN's don't get stored
|
|
531
|
+
}
|
|
532
|
+
const dsValue = dataStore.getValue(path[0]);
|
|
533
|
+
if (path.length === 1) {
|
|
534
|
+
dataStore.setValue(path[0], value);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
dataStore.setValue(path[0], produce(dsValue, (dsValueDraft) => {
|
|
538
|
+
const nodeParent = walkToNodeInValue(dsValueDraft, path.slice(0, path.length - 1));
|
|
539
|
+
const nodeName = path[path.length - 1];
|
|
540
|
+
if (nodeName === undefined) {
|
|
541
|
+
throw new PathError("Encountered an undefined name in a path.", path);
|
|
542
|
+
}
|
|
543
|
+
nodeParent[nodeName] = value;
|
|
544
|
+
}));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* @param dsValue a value from a {@link DataStore}
|
|
549
|
+
* @param path this is expected to be the entire path (including the node that was used to get {@link dsValue}
|
|
550
|
+
*/
|
|
551
|
+
export function walkToNodeInValue(dsValue, path) {
|
|
552
|
+
let current = dsValue;
|
|
553
|
+
for (let i = 1; i < path.length; i++) {
|
|
554
|
+
if (current === undefined) {
|
|
555
|
+
throw new PathError("Encountered a leaf node while expecting one with descendants.", path, i, PathErrorType.UNEXPECTED_LEAF);
|
|
556
|
+
}
|
|
557
|
+
current = descendIntoDSValueNodeChild(current, path, i);
|
|
558
|
+
}
|
|
559
|
+
return current;
|
|
560
|
+
}
|
|
561
|
+
function descendIntoDSValueNodeChild(current, path, i) {
|
|
562
|
+
const pathNode = path[i];
|
|
563
|
+
if (typeof pathNode === 'string') {
|
|
564
|
+
if (Array.isArray(current)) {
|
|
565
|
+
throw new PathError("Encountered a node with indexed descendants while expecting one with string-keyed descendants.", path, i);
|
|
566
|
+
}
|
|
567
|
+
current = current[pathNode];
|
|
568
|
+
}
|
|
569
|
+
else if (pathNode === undefined) {
|
|
570
|
+
throw new PathError("Encountered an undefined name in a path.", path, i);
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
if (!Array.isArray(current)) {
|
|
574
|
+
throw new PathError("Encountered a node with string-keyed descendants while expecting one with indexed descendants.", path, i);
|
|
575
|
+
}
|
|
576
|
+
current = current[pathNode];
|
|
577
|
+
}
|
|
578
|
+
return current;
|
|
579
|
+
}
|
|
580
|
+
var TreeMutatorResult;
|
|
581
|
+
(function (TreeMutatorResult) {
|
|
582
|
+
TreeMutatorResult[TreeMutatorResult["STOP"] = 0] = "STOP";
|
|
583
|
+
TreeMutatorResult[TreeMutatorResult["CONTINUE"] = 1] = "CONTINUE";
|
|
584
|
+
TreeMutatorResult[TreeMutatorResult["SKIP_DESCENDANTS"] = 2] = "SKIP_DESCENDANTS";
|
|
585
|
+
})(TreeMutatorResult || (TreeMutatorResult = {}));
|
|
586
|
+
function applyToTree(tree, mutator, path = []) {
|
|
587
|
+
if (tree.children === undefined) {
|
|
588
|
+
return TreeMutatorResult.CONTINUE;
|
|
589
|
+
}
|
|
590
|
+
const steps = Array.isArray(tree.children)
|
|
591
|
+
? tree.children.map((node, index) => [path.toSpliced(path.length, 0, index), node])
|
|
592
|
+
: Object.entries(tree.children).map(([name, node]) => [path.toSpliced(path.length, 0, name), node]);
|
|
593
|
+
for (const [nodePath, node] of steps) {
|
|
594
|
+
const mutatorRes = mutator(node, nodePath);
|
|
595
|
+
if (!mutatorRes) {
|
|
596
|
+
return TreeMutatorResult.STOP;
|
|
597
|
+
}
|
|
598
|
+
else if (mutatorRes === TreeMutatorResult.CONTINUE) {
|
|
599
|
+
if (!applyToTree(node, mutator, nodePath)) {
|
|
600
|
+
return TreeMutatorResult.STOP;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return TreeMutatorResult.CONTINUE;
|
|
605
|
+
}
|
|
606
|
+
function buildNodeFromDataAndDefinition(data, definition) {
|
|
607
|
+
const children = definition.children;
|
|
608
|
+
if (children) {
|
|
609
|
+
if (data === undefined || data === null) {
|
|
610
|
+
if (definition.type === 'array') {
|
|
611
|
+
return { rendered: true, condition: definition.condition, definition, validationError: "", children: [] };
|
|
612
|
+
}
|
|
613
|
+
else if (definition.type === 'object') {
|
|
614
|
+
return {
|
|
615
|
+
rendered: true, condition: definition.condition, definition, validationError: "",
|
|
616
|
+
children: Object.fromEntries(children.map(def => [def.name, buildNodeFromDataAndDefinition(undefined, def)]))
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
else if (typeof data === 'object') {
|
|
621
|
+
if (Array.isArray(data)) {
|
|
622
|
+
return {
|
|
623
|
+
rendered: true, condition: definition.condition, definition, validationError: "", children: data.map(item => {
|
|
624
|
+
return {
|
|
625
|
+
children: Object.fromEntries(children.map(def => [def.name, buildNodeFromDataAndDefinition(item[def.name], def)])),
|
|
626
|
+
rendered: true, validationError: ""
|
|
627
|
+
};
|
|
628
|
+
})
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
return {
|
|
633
|
+
rendered: true, condition: definition.condition, definition, validationError: "",
|
|
634
|
+
children: Object.fromEntries(children.map(def => [def.name, buildNodeFromDataAndDefinition(data[def.name], def)]))
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return { rendered: true, condition: definition.condition, definition, validationError: "" };
|
|
640
|
+
}
|
|
641
|
+
//# sourceMappingURL=data-controller.js.map
|