@plaudit/gutenberg-api-extensions 2.94.2 → 2.96.0
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/CHANGELOG.md +12 -0
- package/dist/lib/useful-types.d.ts +1 -4
- package/package.json +4 -4
- package/src/blocks/MoveError.ts +0 -7
- package/src/blocks/PathError.ts +0 -18
- package/src/blocks/SNPFlexibleItemsListComponent.tsx +0 -30
- package/src/blocks/SNPGroupComponent.tsx +0 -38
- package/src/blocks/SNPListComponent.tsx +0 -25
- package/src/blocks/SNPTreeContext.tsx +0 -13
- package/src/blocks/basic-custom-block-bindings-support.tsx +0 -248
- package/src/blocks/common-native-property-constructors.tsx +0 -927
- package/src/blocks/conditions.ts +0 -261
- package/src/blocks/csnp-api.ts +0 -221
- package/src/blocks/data-controller/actions.ts +0 -20
- package/src/blocks/data-controller/reducer.ts +0 -146
- package/src/blocks/data-controller/trigger-handlers.ts +0 -150
- package/src/blocks/data-controller/utils.ts +0 -415
- package/src/blocks/data-controller-manager.ts +0 -50
- package/src/blocks/data-controller.ts +0 -165
- package/src/blocks/hooks/built-in-suspendable-option-protocols/select.ts +0 -51
- package/src/blocks/hooks/built-in-suspendable-option-protocols/settings.ts +0 -70
- package/src/blocks/hooks/useSuspendableOptions.ts +0 -122
- package/src/blocks/index.ts +0 -23
- package/src/blocks/layered-styles-api.ts +0 -142
- package/src/blocks/layered-styles-impl.ts +0 -95
- package/src/blocks/layout/LaidOutProperty.tsx +0 -72
- package/src/blocks/layout/LaidOutPropertyRow.tsx +0 -28
- package/src/blocks/layout/NodeContext.tsx +0 -54
- package/src/blocks/layout/PanelRoot.tsx +0 -30
- package/src/blocks/layout/TabsRoot.tsx +0 -56
- package/src/blocks/layout/ToolsPanelContext.tsx +0 -22
- package/src/blocks/problematic-blocks-blocker.ts +0 -24
- package/src/blocks/problematic-variations-blocker.ts +0 -32
- package/src/blocks/shared-exportable-types.ts +0 -6
- package/src/blocks/shared-internal-types.ts +0 -18
- package/src/blocks/simple-block.tsx +0 -74
- package/src/blocks/simple-native-property-api.ts +0 -173
- package/src/blocks/simple-native-property-impl.tsx +0 -335
- package/src/blocks/simple-native-property-internal-shared.ts +0 -19
- package/src/blocks/snp-api.ts +0 -5
- package/src/blocks/snp-data-store.ts +0 -72
- package/src/blocks/utilities.ts +0 -66
- package/src/controls/AsynchronousFormTokenField.tsx +0 -86
- package/src/controls/BaseSortableItemsControl.tsx +0 -84
- package/src/controls/ExtendedFormTokenField.tsx +0 -144
- package/src/controls/ExtendedPostPicker.ts +0 -57
- package/src/controls/ExtendedRadioControl.tsx +0 -107
- package/src/controls/ExtendedTaxonomyPicker.tsx +0 -100
- package/src/controls/ExtendedTermPicker.tsx +0 -61
- package/src/controls/ExtendedTextareaControl.tsx +0 -65
- package/src/controls/ExtendedUserPicker.ts +0 -56
- package/src/controls/FileControl.tsx +0 -48
- package/src/controls/FullSizeToggleControl.tsx +0 -95
- package/src/controls/ImageControl.tsx +0 -143
- package/src/controls/InspectorPanel.tsx +0 -37
- package/src/controls/LazySuggestionsComboboxControl.tsx +0 -64
- package/src/controls/MultiSelectControl.tsx +0 -59
- package/src/controls/PickOne.tsx +0 -88
- package/src/controls/PromisableComponent.tsx +0 -56
- package/src/controls/ProperLinkControl.tsx +0 -98
- package/src/controls/SimpleToggle.tsx +0 -9
- package/src/controls/SortableFlexibleItemsControl.tsx +0 -37
- package/src/controls/SortableItemsControl.tsx +0 -22
- package/src/controls/basicNumericallyIdedItemPicker.tsx +0 -75
- package/src/controls/hooks/useImprovedTokenManager.ts +0 -163
- package/src/controls/hooks/useMultiSingleConversionLayer.ts +0 -17
- package/src/controls/hooks/useNonRenderingCounter.ts +0 -6
- package/src/controls/hooks/useOutputMemoizingFilter.ts +0 -16
- package/src/controls/hooks/useSortableItemsModel.ts +0 -196
- package/src/controls/hooks/useSuggestions.ts +0 -91
- package/src/controls/hooks/useTokenManager.ts +0 -177
- package/src/controls/index.ts +0 -24
- package/src/controls/shared.ts +0 -50
- package/src/controls/types.ts +0 -18
- package/src/editor/insert-sibling-or-child-block-shortcut.tsx +0 -60
- package/src/editor/install-insert-sole-allowed-block-shortcut-support.tsx +0 -51
- package/src/editor/simple-gutenberg-endpoints-api.ts +0 -31
- package/src/editor/simple-gutenberg-endpoints-impl.ts +0 -126
- package/src/index.ts +0 -30
- package/src/lib/compat-types.ts +0 -21
- package/src/lib/gutenberg-api-extensions-state/custom-block-bindings-support-logic.ts +0 -35
- package/src/lib/gutenberg-api-extensions-state/general-logic.ts +0 -41
- package/src/lib/gutenberg-api-extensions-state/layered-block-styles-logic.ts +0 -43
- package/src/lib/gutenberg-api-extensions-state/snp-logic.ts +0 -240
- package/src/lib/gutenberg-api-extensions-state.ts +0 -69
- package/src/lib/helpers.ts +0 -115
- package/src/lib/modified-fast-deep-equals.ts +0 -91
- package/src/lib/plaudit-icons/column-1.tsx +0 -6
- package/src/lib/plaudit-icons/column-2.tsx +0 -6
- package/src/lib/plaudit-icons/column-3.tsx +0 -6
- package/src/lib/plaudit-icons/placement-center.tsx +0 -3
- package/src/lib/plaudit-icons/placement-end.tsx +0 -3
- package/src/lib/plaudit-icons/placement-start.tsx +0 -3
- package/src/lib/plaudit-icons/placement-stretch.tsx +0 -3
- package/src/lib/plaudit-icons/plaudit-icon.tsx +0 -4
- package/src/lib/plaudit-icons/reusable-block-marker.tsx +0 -3
- package/src/lib/plaudit-icons.ts +0 -13
- package/src/lib/sectioned-cache-store.ts +0 -120
- package/src/lib/suspense/promise-handlers.ts +0 -72
- package/src/lib/suspense.tsx +0 -18
- package/src/lib/useful-types.ts +0 -82
- package/src/schemas/README.md +0 -1
- package/src/schemas/plaudit-block-schema.json +0 -818
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import {useMemo} from "@wordpress/element";
|
|
2
|
-
|
|
3
|
-
import {configureStore, type Middleware, Tuple} from "@reduxjs/toolkit";
|
|
4
|
-
|
|
5
|
-
import type {Dispatch} from "redux";
|
|
6
|
-
|
|
7
|
-
import {type Condition, resolveValueForCondition} from "./conditions";
|
|
8
|
-
import {PathError, PathErrorType} from "./PathError";
|
|
9
|
-
import type {DataController, DataStore, HydratedSimpleNativeProperty, NodePath} from "./simple-native-property-api";
|
|
10
|
-
|
|
11
|
-
import {actions, type DataControllerActions} from "./data-controller/actions";
|
|
12
|
-
import {buildReducer} from "./data-controller/reducer";
|
|
13
|
-
import {getDataStore, getOptionalValue, type UUID, walkToNode} from "./data-controller/utils";
|
|
14
|
-
|
|
15
|
-
type DescendantsWrapper = {[key: string]: DCNode}|DCNode[];
|
|
16
|
-
export type DCNode = {
|
|
17
|
-
backup?: UUID,
|
|
18
|
-
rendered?: boolean,
|
|
19
|
-
condition?: Condition,
|
|
20
|
-
children?: DescendantsWrapper,
|
|
21
|
-
definition?: HydratedSimpleNativeProperty<{uuid: UUID}>,
|
|
22
|
-
validationError?: string
|
|
23
|
-
};
|
|
24
|
-
export type DCStoreState = {
|
|
25
|
-
treeRoot: Omit<DCNode, 'children'>&{children: {[key: string]: DCNode}},
|
|
26
|
-
dataStores: {byProperty: {[key: string]: DataStore}, list: DataStore[]},
|
|
27
|
-
blockClientId: string,
|
|
28
|
-
changedByManagedControl: boolean,
|
|
29
|
-
rerenderTrigger: number,
|
|
30
|
-
batchAddedPropertiesThatNeedWriteThrough: HydratedSimpleNativeProperty<{uuid: UUID}>[]
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export function useDataController(blockClientId: string): DataController {
|
|
34
|
-
return useMemo(() => {
|
|
35
|
-
const reducer = buildReducer(blockClientId);
|
|
36
|
-
const store = configureStore<DCStoreState, DataControllerActions, Tuple<ReadonlyArray<Middleware<{}, DCStoreState, Dispatch<DataControllerActions>>>>>({reducer});
|
|
37
|
-
function getDataStoreImpl(property: string, required: true): DataStore;
|
|
38
|
-
function getDataStoreImpl(property: string, required?: undefined|false): DataStore|undefined;
|
|
39
|
-
function getDataStoreImpl(property: string, required?: boolean): DataStore|undefined {
|
|
40
|
-
return getDataStore(property, store.getState(), required);
|
|
41
|
-
}
|
|
42
|
-
const dataController: DataController = {
|
|
43
|
-
getDataStore: getDataStoreImpl,
|
|
44
|
-
getAllDataStores() {
|
|
45
|
-
return store.getState().dataStores.list;
|
|
46
|
-
},
|
|
47
|
-
makePropertyValueResolver(contextPath) {
|
|
48
|
-
return propertyPath => resolveValueForCondition(propertyPath, contextPath, blockClientId, getDataStoreImpl)
|
|
49
|
-
},
|
|
50
|
-
getValue(path) {
|
|
51
|
-
return getOptionalValue(path, store.getState());
|
|
52
|
-
},
|
|
53
|
-
setValue(path, value) {
|
|
54
|
-
store.dispatch(actions.node.write({path, value}));
|
|
55
|
-
},
|
|
56
|
-
addProperties(properties, dataStore, inBatch) {
|
|
57
|
-
store.dispatch(actions.addProperties({properties, dataStore}, inBatch));
|
|
58
|
-
},
|
|
59
|
-
addNode(path, value) {
|
|
60
|
-
try {
|
|
61
|
-
store.dispatch(actions.node.add({path, value}));
|
|
62
|
-
} catch (e) {
|
|
63
|
-
if (e instanceof PathError && e.errorType === PathErrorType.UNEXPECTED_LEAF) {
|
|
64
|
-
for (let i = e.errorIndex; i < path.length - 1; i++) {
|
|
65
|
-
store.dispatch(actions.node.add({path: path.slice(0, i) as NodePath, value}, true));
|
|
66
|
-
}
|
|
67
|
-
store.dispatch(actions.node.add({path, value}));
|
|
68
|
-
}
|
|
69
|
-
throw e;
|
|
70
|
-
}
|
|
71
|
-
},
|
|
72
|
-
removeNode(path) {
|
|
73
|
-
store.dispatch(actions.node.remove({path}));
|
|
74
|
-
},
|
|
75
|
-
moveNode(path, indices) {
|
|
76
|
-
store.dispatch(actions.node.move({path, ...indices}));
|
|
77
|
-
},
|
|
78
|
-
validateNode(path) {
|
|
79
|
-
store.dispatch(actions.node.validate({path}));
|
|
80
|
-
},
|
|
81
|
-
hasRenderedNode(properties) {
|
|
82
|
-
const rootNodes = store.getState().treeRoot.children;
|
|
83
|
-
for (const property of properties) {
|
|
84
|
-
if (Array.isArray(property)) {
|
|
85
|
-
for (const prop of property) {
|
|
86
|
-
if (rootNodes[prop.name]?.rendered) {
|
|
87
|
-
return true;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
} else if (rootNodes[property.name]?.rendered) {
|
|
91
|
-
return true;
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
return false;
|
|
95
|
-
},
|
|
96
|
-
hasValidationErrors(properties) {
|
|
97
|
-
if (properties === undefined) {
|
|
98
|
-
return testForValidationErrors(store.getState().treeRoot);
|
|
99
|
-
}
|
|
100
|
-
const rootNodes = store.getState().treeRoot.children;
|
|
101
|
-
for (const property of properties) {
|
|
102
|
-
if (Array.isArray(property)) {
|
|
103
|
-
for (const prop of property) {
|
|
104
|
-
if (testForValidationErrors(rootNodes[prop.name])) {
|
|
105
|
-
return true;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
} else if (testForValidationErrors(rootNodes[property.name])) {
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
return false;
|
|
113
|
-
},
|
|
114
|
-
getIsRendered(path) {
|
|
115
|
-
return walkToNode(store.getState().treeRoot, path).rendered ?? true;
|
|
116
|
-
},
|
|
117
|
-
getNode(path) {
|
|
118
|
-
return walkToNode(store.getState().treeRoot, path);
|
|
119
|
-
},
|
|
120
|
-
getValidationError(path) {
|
|
121
|
-
return walkToNode(store.getState().treeRoot, path).validationError;
|
|
122
|
-
},
|
|
123
|
-
getWasChangedByManagedControl() {
|
|
124
|
-
return store.getState().changedByManagedControl;
|
|
125
|
-
},
|
|
126
|
-
markManagedControlChangeHandled() {
|
|
127
|
-
store.dispatch(actions.markManagedControlChangeHandled({}));
|
|
128
|
-
},
|
|
129
|
-
checkConditions() {
|
|
130
|
-
store.dispatch(actions.checkConditions({}));
|
|
131
|
-
},
|
|
132
|
-
validateNodes() {
|
|
133
|
-
store.dispatch(actions.validateNodes({}));
|
|
134
|
-
},
|
|
135
|
-
commitBatchAddedProperties() {
|
|
136
|
-
store.dispatch(actions.commitBatchAddedProperties({}));
|
|
137
|
-
},
|
|
138
|
-
blockClientId
|
|
139
|
-
};
|
|
140
|
-
return dataController;
|
|
141
|
-
}, [blockClientId]);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function testForValidationErrors(node: DCNode|undefined) {
|
|
145
|
-
if (!node || !node.rendered) {
|
|
146
|
-
return false;
|
|
147
|
-
} else if (node.validationError) {
|
|
148
|
-
return true;
|
|
149
|
-
} else if (Array.isArray(node.children)) {
|
|
150
|
-
for (const child of node.children) {
|
|
151
|
-
if (testForValidationErrors(child)) {
|
|
152
|
-
return true;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
} else if (node.children !== undefined) {
|
|
156
|
-
for (const child of Object.values(node.children)) {
|
|
157
|
-
if (testForValidationErrors(child)) {
|
|
158
|
-
return true;
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return false;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export {walkToNodeInValue} from "./data-controller/utils";
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import {useSuspenseSelect} from "@wordpress/data";
|
|
2
|
-
import {useMemo} from "@wordpress/element";
|
|
3
|
-
import {addFilter} from "@wordpress/hooks";
|
|
4
|
-
|
|
5
|
-
import {produce} from "immer";
|
|
6
|
-
|
|
7
|
-
import {useNodeContext} from "../../layout/NodeContext";
|
|
8
|
-
|
|
9
|
-
export default function() {
|
|
10
|
-
addFilter(
|
|
11
|
-
'plaudit.gutenbergApiExtensions.simpleNativeProperties.suspendableOptions.resolve',
|
|
12
|
-
'plaudit/gutenberg-api-extensions/simple-native-properties/suspendable-options',
|
|
13
|
-
(options: unknown | undefined, selectorInfo: URL, {attributes}: { attributes: Record<string, any> | null }) => {
|
|
14
|
-
if (options !== undefined || selectorInfo.protocol !== "select:") {
|
|
15
|
-
return options;
|
|
16
|
-
}
|
|
17
|
-
const nodeContext = useNodeContext("get contextual options");
|
|
18
|
-
const trimmedAttributes = useMemo(() => {
|
|
19
|
-
if (selectorInfo.searchParams.has("attributes")) {
|
|
20
|
-
if (attributes === null) {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
return produce(attributes, draft => {
|
|
24
|
-
let current = draft;
|
|
25
|
-
for (const p of nodeContext.path.slice(0, nodeContext.path.length - 1)) {
|
|
26
|
-
if (typeof p === 'string') {
|
|
27
|
-
current = current.p;
|
|
28
|
-
} else {
|
|
29
|
-
current = current[p];
|
|
30
|
-
}
|
|
31
|
-
if (current === undefined) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
const lastItem = nodeContext.path[nodeContext.path.length - 1]!;
|
|
36
|
-
if (typeof lastItem === 'string') {
|
|
37
|
-
delete current[lastItem];
|
|
38
|
-
} else {
|
|
39
|
-
current.splice(lastItem, 1);
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
} else {
|
|
43
|
-
return undefined;
|
|
44
|
-
}
|
|
45
|
-
}, [attributes, nodeContext]);
|
|
46
|
-
return useSuspenseSelect(select => {
|
|
47
|
-
return (select(selectorInfo.hostname + selectorInfo.pathname) as any).get(selectorInfo.username, trimmedAttributes);
|
|
48
|
-
}, [selectorInfo, trimmedAttributes]);
|
|
49
|
-
}, 100_000
|
|
50
|
-
);
|
|
51
|
-
}
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import {useSettings} from "@wordpress/block-editor";
|
|
2
|
-
import {addFilter} from "@wordpress/hooks";
|
|
3
|
-
|
|
4
|
-
export default function() {
|
|
5
|
-
addFilter(
|
|
6
|
-
'plaudit.gutenbergApiExtensions.simpleNativeProperties.suspendableOptions.resolve',
|
|
7
|
-
'plaudit/gutenberg-api-extensions/simple-native-properties/suspendable-options',
|
|
8
|
-
(options: unknown | undefined, selectorInfo: URL) => {
|
|
9
|
-
return options === undefined && selectorInfo.protocol === "settings:" ? useSettings(selectorInfo.hostname)[0] : options;
|
|
10
|
-
}, 100_000
|
|
11
|
-
);
|
|
12
|
-
|
|
13
|
-
addFilter(
|
|
14
|
-
'plaudit.gutenbergApiExtensions.simpleNativeProperties.suspendableOptions.postProcess',
|
|
15
|
-
'plaudit/gutenberg-api-extensions/simple-native-properties/suspendable-options',
|
|
16
|
-
(options: unknown, selectorInfo: URL) => {
|
|
17
|
-
if (selectorInfo.protocol !== "settings:") {
|
|
18
|
-
return options;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if (!Array.isArray(options)) {
|
|
22
|
-
console.error(`The "settings" protocol for CSNPs only supports array-formatted values. ${selectorInfo} did not resolve to an array`);
|
|
23
|
-
return [];
|
|
24
|
-
}
|
|
25
|
-
const valueTransformer = getValueTransformer(selectorInfo);
|
|
26
|
-
return options
|
|
27
|
-
.filter((s): s is { name: string, slug: string } & ({ value: string | number, icon?: string } | { color: string }) => {
|
|
28
|
-
if (typeof s === 'object' && s && typeof s["name"] === 'string' && typeof s["slug"] === 'string') {
|
|
29
|
-
if (typeof s["value"] === 'string' || typeof s["value"] === 'number') {
|
|
30
|
-
if ("color" in s) {
|
|
31
|
-
console.error("Encountered an invalid setting value:", s);
|
|
32
|
-
return false;
|
|
33
|
-
}
|
|
34
|
-
} else if (typeof s["color"] !== 'string' || "value" in s) {
|
|
35
|
-
console.error("Encountered an invalid setting value:", s);
|
|
36
|
-
return false;
|
|
37
|
-
}
|
|
38
|
-
return true;
|
|
39
|
-
}
|
|
40
|
-
return false;
|
|
41
|
-
})
|
|
42
|
-
.map(s => {
|
|
43
|
-
const {slug, name: label, ...rest} = s;
|
|
44
|
-
return {...rest, value: valueTransformer(slug), label};
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
function getValueTransformer(selectorInfo: URL): (value: string) => string {
|
|
49
|
-
const valuePattern = getValuePatternAccountingForLegacyCode(selectorInfo);
|
|
50
|
-
if (!valuePattern) {
|
|
51
|
-
return value => value;
|
|
52
|
-
}
|
|
53
|
-
if (!valuePattern.includes("$slug")) {
|
|
54
|
-
throw new Error("Value patterns provided to the \"settings\" protocol MUST include '$slug'");
|
|
55
|
-
}
|
|
56
|
-
return value => valuePattern.replaceAll("$slug", value);
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function getValuePatternAccountingForLegacyCode(selectorInfo: URL) {
|
|
60
|
-
const res = selectorInfo.searchParams.get("value-pattern") || selectorInfo.searchParams.get("valuePattern");
|
|
61
|
-
if (!res) {
|
|
62
|
-
for (const key of selectorInfo.searchParams.keys()) {
|
|
63
|
-
if (key.includes("$slug")) {
|
|
64
|
-
return key;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
return res;
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import {store as blockEditorStore} from "@wordpress/block-editor";
|
|
2
|
-
import {MapSelect, useSelect} from "@wordpress/data";
|
|
3
|
-
import {useMemo} from "@wordpress/element";
|
|
4
|
-
import {applyFilters} from "@wordpress/hooks";
|
|
5
|
-
|
|
6
|
-
import type {CSNPConfig, PromisablePickableOptions, SuspendablePromisablePickableOptions} from "../csnp-api";
|
|
7
|
-
import type {PickableOptions} from "../../controls";
|
|
8
|
-
import {useNodeContext} from "../layout/NodeContext";
|
|
9
|
-
import {isPromise, use} from "../../lib/suspense/promise-handlers";
|
|
10
|
-
|
|
11
|
-
type RefablePromisablePickableOptions<T> = T extends {options: PromisablePickableOptions<infer V, infer T>} ? PickableOptions<V, T> : never;
|
|
12
|
-
export function isSuspendableOptions<V extends string|number, T extends object = {}>(thing: PromisablePickableOptions<V, T>|string): thing is SuspendablePromisablePickableOptions {
|
|
13
|
-
return typeof thing === 'string' || thing instanceof URL;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function useSuspendableOptions<T extends CSNPConfig&{options: PromisablePickableOptions<any>}>(config: T): RefablePromisablePickableOptions<T> {
|
|
17
|
-
const rawOptions = isPromise(config.options) ? use(config.options) : config.options;
|
|
18
|
-
if (isSuspendableOptions(rawOptions)) {
|
|
19
|
-
const selectorInfo = toSuspendableOptionsURI(rawOptions);
|
|
20
|
-
const nodeContext = useNodeContext("get contextual options");
|
|
21
|
-
const blockClientId = nodeContext.dataController.blockClientId;
|
|
22
|
-
|
|
23
|
-
const usesBlockAttributes = applyFilters('plaudit.gutenbergApiExtensions.simpleNativeProperties.suspendableOptions.usesBlockAttributes',
|
|
24
|
-
selectorInfo.searchParams.has("attributes"), selectorInfo, blockClientId);
|
|
25
|
-
|
|
26
|
-
// This if/else statement is present because actually passing attributes through to the selectors represents a SEVERE relative performance hit.
|
|
27
|
-
// At a minimum, it causes at least one additional full execution pass, and, due to how data can be cached, that pass is almost guaranteed to turn into at least one full render.
|
|
28
|
-
let mapSelect: (...args: Parameters<MapSelect>) => [Record<string, any>|null, string|null];
|
|
29
|
-
if (usesBlockAttributes) {
|
|
30
|
-
mapSelect = wrappedSelect => {
|
|
31
|
-
const selected = wrappedSelect(blockEditorStore);
|
|
32
|
-
return [selected.getBlockAttributes(blockClientId), selected.getBlockName(blockClientId)];
|
|
33
|
-
};
|
|
34
|
-
} else {
|
|
35
|
-
mapSelect = wrappedSelect => [null, wrappedSelect(blockEditorStore).getBlockName(blockClientId)];
|
|
36
|
-
}
|
|
37
|
-
const [attributes, blockName] = useSelect(mapSelect, [blockClientId]);
|
|
38
|
-
|
|
39
|
-
const potentiallyPromisedOptions = applyFilters('plaudit.gutenbergApiExtensions.simpleNativeProperties.suspendableOptions.resolve',
|
|
40
|
-
undefined, selectorInfo, {attributes, blockName});
|
|
41
|
-
if (potentiallyPromisedOptions === undefined) {
|
|
42
|
-
throw new Error(`Encountered an unsupported suspendable option request: ${rawOptions}`);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// selectorInfo is guaranteed to be valid by virtue of the checks performed while getting the handler
|
|
46
|
-
const options = potentiallyPromisedOptions && typeof potentiallyPromisedOptions === 'object' && 'then' in potentiallyPromisedOptions
|
|
47
|
-
? use(potentiallyPromisedOptions as Promise<unknown>) : potentiallyPromisedOptions;
|
|
48
|
-
|
|
49
|
-
return useMemo(() => {
|
|
50
|
-
return applyFilters('plaudit.gutenbergApiExtensions.simpleNativeProperties.suspendableOptions.postProcess', options, selectorInfo, {attributes, blockName});
|
|
51
|
-
}, [options, selectorInfo, attributes, blockName]) as RefablePromisablePickableOptions<T>;
|
|
52
|
-
} else {
|
|
53
|
-
return rawOptions as RefablePromisablePickableOptions<T>;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export type SuspendableOptionsHandler = (selectorInfo: URL, params: {attributes: Record<string, any>|null, blockName: string|null}) => any;
|
|
58
|
-
|
|
59
|
-
function toSuspendableOptionsURI(rawOptions: string|URL) {
|
|
60
|
-
if (rawOptions instanceof URL) {
|
|
61
|
-
return rawOptions;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return useMemo(() => {
|
|
65
|
-
try {
|
|
66
|
-
const res = new URL(rawOptions);
|
|
67
|
-
if (res.protocol === "select:") {
|
|
68
|
-
if (res.username && res.hostname) {
|
|
69
|
-
return res;
|
|
70
|
-
}
|
|
71
|
-
} else if (res.protocol === "setting:" || res.protocol === "settings:") {
|
|
72
|
-
if (res.protocol === "setting:") {
|
|
73
|
-
console.warn(`Encountered a Suspendable Option parameter using deprecated protocol:`, res.toString(), "\nThe \"setting\" protocol has been renamed to \"settings\"");
|
|
74
|
-
res.protocol = "settings:";
|
|
75
|
-
}
|
|
76
|
-
if (res.hostname) {
|
|
77
|
-
return res;
|
|
78
|
-
}
|
|
79
|
-
} else {
|
|
80
|
-
return res;
|
|
81
|
-
}
|
|
82
|
-
} catch {
|
|
83
|
-
// We're not throwing on an invalid URI here because we want a chance to run the deprecated-syntax handling logic
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
const selectorInfo = rawOptions.split(":") as [string, ...string[]];
|
|
87
|
-
let correctedRawOptions: string;
|
|
88
|
-
if (selectorInfo[0] === 'select') {
|
|
89
|
-
if (selectorInfo.length < 3 || !selectorInfo[1] || !selectorInfo[2]) {
|
|
90
|
-
throw new Error(`The "select" protocol for Suspendable Options must have at least 3 colon-delimited parts. Got: ${rawOptions}`);
|
|
91
|
-
}
|
|
92
|
-
// Deprecated: select:plaudit/simple-gutenberg-apis:plaudit-base.conditional-display.show-when-options:attributes
|
|
93
|
-
// Corrected: select://plaudit-base.conditional-display.show-when-options@plaudit/simple-gutenberg-apis?attributes
|
|
94
|
-
correctedRawOptions = `select://${selectorInfo[2]}@${selectorInfo[1]}`;
|
|
95
|
-
if (selectorInfo[3]) {
|
|
96
|
-
correctedRawOptions += "?" + selectorInfo[3];
|
|
97
|
-
}
|
|
98
|
-
} else if (selectorInfo[0] === 'setting' || selectorInfo[0] === 'settings') {
|
|
99
|
-
if (!selectorInfo[1]) {
|
|
100
|
-
throw new Error(`The "settings" protocol for Suspendable Options must have at least 2 colon-delimited parts. Got: ${rawOptions}`);
|
|
101
|
-
}
|
|
102
|
-
// Deprecated: setting:plaudit.markerDisplay:with-inherit
|
|
103
|
-
// Corrected: settings://plaudit.markerDisplay?with-inherit
|
|
104
|
-
correctedRawOptions = `settings://${selectorInfo[1]}`;
|
|
105
|
-
if (selectorInfo.length > 2) {
|
|
106
|
-
const query = selectorInfo.slice(2).join("&");
|
|
107
|
-
if (query.replaceAll("&", "").length > 0) {
|
|
108
|
-
correctedRawOptions += "?" + query;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
} else {
|
|
112
|
-
throw new Error(`Encountered an invalid suspendable options value: ${rawOptions}. Suspendable option values MUST be URIs.`);
|
|
113
|
-
}
|
|
114
|
-
console.warn(`Encountered a Suspendable Option parameter using deprecated syntax:`, rawOptions, "\nIt should be replaced with:", correctedRawOptions);
|
|
115
|
-
return new URL(correctedRawOptions);
|
|
116
|
-
}, [rawOptions]);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
import initSelectProtocol from "./built-in-suspendable-option-protocols/select";
|
|
120
|
-
import initSettingsProtocol from "./built-in-suspendable-option-protocols/settings";
|
|
121
|
-
initSelectProtocol();
|
|
122
|
-
initSettingsProtocol();
|
package/src/blocks/index.ts
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
export * from "./layered-styles-api";
|
|
2
|
-
export * from "./simple-block";
|
|
3
|
-
export * from "./shared-exportable-types";
|
|
4
|
-
export * from "./simple-native-property-api";
|
|
5
|
-
export * from "./snp-data-store";
|
|
6
|
-
export * from "./utilities";
|
|
7
|
-
|
|
8
|
-
export * from "./problematic-blocks-blocker";
|
|
9
|
-
export * from "./problematic-variations-blocker";
|
|
10
|
-
|
|
11
|
-
export type {SuspendableOptionsHandler} from "./hooks/useSuspendableOptions";
|
|
12
|
-
|
|
13
|
-
export {installCustomBlockBindingsSupport, registerCustomBlockBindingsSource} from "./basic-custom-block-bindings-support";
|
|
14
|
-
export type {DbSource, BlockName} from "../lib/useful-types"; // This is for backwards compatibility
|
|
15
|
-
|
|
16
|
-
import {installGutenbergExtensions} from "../index";
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* @deprecated use installGutenbergExtensions() instead
|
|
20
|
-
*/
|
|
21
|
-
export function installGutenbergBlockExtensions() {
|
|
22
|
-
installGutenbergExtensions();
|
|
23
|
-
}
|
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
ColorPaletteCSNPConfig,
|
|
3
|
-
CommonPropertyConfig,
|
|
4
|
-
RadioPropertyCSNPConfig,
|
|
5
|
-
SelectPropertyCSNPConfig,
|
|
6
|
-
ToggleGroupPropertyCSNPConfig,
|
|
7
|
-
TogglePropertyCSNPConfig
|
|
8
|
-
} from "./csnp-api";
|
|
9
|
-
import type {PickableOptions} from "../controls";
|
|
10
|
-
import {installGutenbergExtensions} from "../index";
|
|
11
|
-
import type {BlockName} from "../lib/useful-types";
|
|
12
|
-
import {registerSimpleNativeProperties, SimpleNativeProperty} from "./simple-native-property-api";
|
|
13
|
-
|
|
14
|
-
type BaseLayeredBlockStyleLayer = {
|
|
15
|
-
name: string;
|
|
16
|
-
title: string;
|
|
17
|
-
default?: string|undefined;
|
|
18
|
-
condition?: SimpleNativeProperty['condition']
|
|
19
|
-
alwaysStore?: boolean|undefined;
|
|
20
|
-
styleProperty?: string;
|
|
21
|
-
}&Pick<CommonPropertyConfig<any, any, any, any>, 'help'>
|
|
22
|
-
|
|
23
|
-
type LayeredBlockStyleColorLayer = BaseLayeredBlockStyleLayer&{
|
|
24
|
-
picker: 'color'|'colorPalette';
|
|
25
|
-
clearable?: boolean|undefined;
|
|
26
|
-
options: PickableOptions<string, {color?: string}>|ColorPaletteCSNPConfig['options'];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
type LayeredBlockStyleToggleLayer = BaseLayeredBlockStyleLayer&{picker: 'toggle'}&Pick<TogglePropertyCSNPConfig, 'switch'>
|
|
30
|
-
|
|
31
|
-
type LayeredBlockStyleToggleGroupLayer = BaseLayeredBlockStyleLayer&{
|
|
32
|
-
picker?: 'toggle-control'|'toggleGroup';
|
|
33
|
-
clearable?: boolean|undefined;
|
|
34
|
-
options: ToggleGroupPropertyCSNPConfig['options'];
|
|
35
|
-
}
|
|
36
|
-
type LayeredBlockStyleSelectOrRadioLayer = BaseLayeredBlockStyleLayer&{options: PickableOptions<string>}&({picker: 'select', clearable?: boolean|undefined}|{picker: 'radio'})
|
|
37
|
-
|
|
38
|
-
export type LayeredBlockStyleLayer = LayeredBlockStyleColorLayer|LayeredBlockStyleToggleLayer|LayeredBlockStyleToggleGroupLayer|LayeredBlockStyleSelectOrRadioLayer;
|
|
39
|
-
|
|
40
|
-
export interface LayeredBlockStylesConfig {
|
|
41
|
-
block: BlockName[]|BlockName;
|
|
42
|
-
layers: LayeredBlockStyleLayer[];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export function registerLayeredBlockStyles(config: LayeredBlockStylesConfig) {
|
|
46
|
-
registerSimpleNativeProperties({
|
|
47
|
-
block: config.block,
|
|
48
|
-
properties: {
|
|
49
|
-
group: 'layered-styles',
|
|
50
|
-
title: "Layered Styles",
|
|
51
|
-
properties: config.layers.map(layer => {
|
|
52
|
-
const sharedProps = {
|
|
53
|
-
name: layer.name,
|
|
54
|
-
label: layer.title,
|
|
55
|
-
condition: layer.condition,
|
|
56
|
-
alwaysStore: layer.alwaysStore ?? ((layer.default ?? '') !== ''),
|
|
57
|
-
styleProperty: layer.styleProperty
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
const clearable = "clearable" in layer && (layer.clearable ?? false);
|
|
61
|
-
let defaultValue: string|undefined;
|
|
62
|
-
if (clearable) {
|
|
63
|
-
if (layer.default) {
|
|
64
|
-
console.error(`Layered Style, "${layer.title}" on ${Array.isArray(config.block) ? config.block.join(', ') : config.block}`,
|
|
65
|
-
"is improperly configured with both clearable and a non-empty default.");
|
|
66
|
-
defaultValue = "";
|
|
67
|
-
} else {
|
|
68
|
-
defaultValue = layer.default;
|
|
69
|
-
}
|
|
70
|
-
} else {
|
|
71
|
-
defaultValue = layer.default;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
switch (layer.picker) {
|
|
75
|
-
case undefined:
|
|
76
|
-
case 'toggle-control':
|
|
77
|
-
case 'toggleGroup':
|
|
78
|
-
return {
|
|
79
|
-
...sharedProps,
|
|
80
|
-
clearable,
|
|
81
|
-
control: 'toggleGroup',
|
|
82
|
-
default: defaultValue,
|
|
83
|
-
options: layer.options,
|
|
84
|
-
help: layer.help
|
|
85
|
-
} as ToggleGroupPropertyCSNPConfig;
|
|
86
|
-
case 'color':
|
|
87
|
-
case 'colorPalette':
|
|
88
|
-
return {
|
|
89
|
-
...sharedProps,
|
|
90
|
-
allowCustom: false,
|
|
91
|
-
clearable,
|
|
92
|
-
control: 'colorPalette',
|
|
93
|
-
default: defaultValue,
|
|
94
|
-
options: layer.options,
|
|
95
|
-
help: layer.help
|
|
96
|
-
} as ColorPaletteCSNPConfig;
|
|
97
|
-
case 'radio':
|
|
98
|
-
return {
|
|
99
|
-
...sharedProps,
|
|
100
|
-
control: 'radio',
|
|
101
|
-
options: layer.options,
|
|
102
|
-
default: layer.default,
|
|
103
|
-
allowCustom: false,
|
|
104
|
-
help: layer.help
|
|
105
|
-
} as RadioPropertyCSNPConfig;
|
|
106
|
-
case 'select':
|
|
107
|
-
return {
|
|
108
|
-
...sharedProps,
|
|
109
|
-
clearable,
|
|
110
|
-
control: 'select',
|
|
111
|
-
default: defaultValue,
|
|
112
|
-
options: layer.options,
|
|
113
|
-
help: layer.help
|
|
114
|
-
} as SelectPropertyCSNPConfig;
|
|
115
|
-
case 'toggle':
|
|
116
|
-
return {
|
|
117
|
-
...sharedProps,
|
|
118
|
-
control: 'toggle',
|
|
119
|
-
default: defaultValue,
|
|
120
|
-
switch: layer.switch ?? {small: true},
|
|
121
|
-
help: layer.help,
|
|
122
|
-
transformer: {
|
|
123
|
-
to(input: unknown) {
|
|
124
|
-
return input !== undefined && input !== null ? (typeof input === 'boolean' ? input : input?.toString().toLowerCase() === 'true') : undefined;
|
|
125
|
-
},
|
|
126
|
-
from(value: boolean|undefined) {
|
|
127
|
-
return value?.toString();
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
} as TogglePropertyCSNPConfig
|
|
131
|
-
}
|
|
132
|
-
})
|
|
133
|
-
}
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* @deprecated use installGutenbergExtensions() instead.
|
|
139
|
-
*/
|
|
140
|
-
export function installLayeredBlockStylesSupport() {
|
|
141
|
-
installGutenbergExtensions();
|
|
142
|
-
}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import {select} from "@wordpress/data";
|
|
2
|
-
|
|
3
|
-
import {store as gutenbergApiExtensionsStore} from "../lib/gutenberg-api-extensions-state";
|
|
4
|
-
import type {ActualBlockEditProps} from "../lib/useful-types";
|
|
5
|
-
import type {PDSimpleNativeProperty} from "./simple-native-property-api";
|
|
6
|
-
import {makeHasPropClassName} from "./simple-native-property-impl";
|
|
7
|
-
import {SNPDataStore} from "./snp-data-store";
|
|
8
|
-
|
|
9
|
-
export class LayeredStylesDataStore extends SNPDataStore {
|
|
10
|
-
getAttribute(name: string): any {
|
|
11
|
-
if (name.startsWith("__plaudit/")) {
|
|
12
|
-
return this.getRawBlockAttributes()[name];
|
|
13
|
-
}
|
|
14
|
-
const layer = select(gutenbergApiExtensionsStore).blockStylesLayer(this.blockName, name);
|
|
15
|
-
if (layer === undefined) {
|
|
16
|
-
return undefined;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
return extractStyleLayerValueFromAttributes(this.getRawBlockAttributes(), layer.name) ?? layer.default;
|
|
20
|
-
}
|
|
21
|
-
setAttribute(name: string, rawValue: any) {
|
|
22
|
-
if (name.startsWith("__plaudit/")) {
|
|
23
|
-
this.setRawBlockAttributes({[name]: rawValue});
|
|
24
|
-
return;
|
|
25
|
-
}
|
|
26
|
-
const layers = select(gutenbergApiExtensionsStore).blockStylesLayers(this.blockName);
|
|
27
|
-
if (layers === undefined) {
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
const layer = layers[name];
|
|
31
|
-
if (layer === undefined) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
const className = this.getRawBlockAttributes()['className'];
|
|
35
|
-
|
|
36
|
-
const value = rawValue?.toString() || (layer.default ?? '');
|
|
37
|
-
const currentLayerClassPrefix = `style-${name}-`;
|
|
38
|
-
if (typeof className !== 'string' || !className) {
|
|
39
|
-
if (value.length) {
|
|
40
|
-
this.setRawBlockAttributes({
|
|
41
|
-
className: "styleProperty" in layer && layer.styleProperty
|
|
42
|
-
? `${currentLayerClassPrefix}${value} ${makeHasPropClassName(layer.name)}`
|
|
43
|
-
: `${currentLayerClassPrefix}${value}`
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
this.setRawBlockAttributes({className: this.incorporateLayerValue(Object.values(layers), layer, name, value, className)});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private incorporateLayerValue(layers: PDSimpleNativeProperty[], currentLayer: PDSimpleNativeProperty, name: string, value: string, className: string): string {
|
|
52
|
-
const classNames = className.split(/\s+/);
|
|
53
|
-
const layeredStyleClassPrefixes = layers.map(layer => `style-${layer.name}-`);
|
|
54
|
-
const nonLayerClasses = classNames
|
|
55
|
-
.filter(cn => !layeredStyleClassPrefixes.some(lc => cn.startsWith(lc)));
|
|
56
|
-
|
|
57
|
-
const layerPrefixPairs = layers
|
|
58
|
-
.filter(layer => layer.name !== name)
|
|
59
|
-
.map<[PDSimpleNativeProperty, string]>(layer => [layer, `style-${layer.name}-`]);
|
|
60
|
-
const layerClasses: string[] = [];
|
|
61
|
-
for (const [layer, prefix] of layerPrefixPairs) {
|
|
62
|
-
if (this.hasCachedValue(layer.name)) {
|
|
63
|
-
const layerValue = this.getCachedValue(layer.name);
|
|
64
|
-
if (layerValue) {
|
|
65
|
-
layerClasses.push(`${prefix}${layerValue}`);
|
|
66
|
-
}
|
|
67
|
-
} else {
|
|
68
|
-
const layerValueClass = classNames.find(cn => cn.startsWith(prefix));
|
|
69
|
-
if (layerValueClass) {
|
|
70
|
-
layerClasses.push(layerValueClass);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
if (value) {
|
|
75
|
-
layerClasses.push(`style-${name}-${value}`);
|
|
76
|
-
if ('styleProperty' in currentLayer && currentLayer.styleProperty) {
|
|
77
|
-
const hasPropClassName = makeHasPropClassName(currentLayer.name);
|
|
78
|
-
if (!nonLayerClasses.includes(hasPropClassName)) {
|
|
79
|
-
nonLayerClasses.push(hasPropClassName);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
return [...nonLayerClasses, ...layerClasses.sort()].join(' ');
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export function extractStyleLayerValueFromAttributes(attributes: ActualBlockEditProps['attributes'], layerName: string) {
|
|
88
|
-
const className = attributes['className'];
|
|
89
|
-
if (typeof className !== 'string') {
|
|
90
|
-
return undefined;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const currentLayerClassPrefix = `style-${layerName}-`;
|
|
94
|
-
return attributes['className']?.split(/\s+/).find(className => className.startsWith(currentLayerClassPrefix))?.substring(currentLayerClassPrefix.length);
|
|
95
|
-
}
|