@plaudit/gutenberg-api-extensions 2.95.0 → 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.
Files changed (103) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/lib/useful-types.d.ts +1 -4
  3. package/package.json +1 -2
  4. package/src/blocks/MoveError.ts +0 -7
  5. package/src/blocks/PathError.ts +0 -18
  6. package/src/blocks/SNPFlexibleItemsListComponent.tsx +0 -30
  7. package/src/blocks/SNPGroupComponent.tsx +0 -38
  8. package/src/blocks/SNPListComponent.tsx +0 -25
  9. package/src/blocks/SNPTreeContext.tsx +0 -13
  10. package/src/blocks/basic-custom-block-bindings-support.tsx +0 -248
  11. package/src/blocks/common-native-property-constructors.tsx +0 -927
  12. package/src/blocks/conditions.ts +0 -261
  13. package/src/blocks/csnp-api.ts +0 -221
  14. package/src/blocks/data-controller/actions.ts +0 -20
  15. package/src/blocks/data-controller/reducer.ts +0 -146
  16. package/src/blocks/data-controller/trigger-handlers.ts +0 -150
  17. package/src/blocks/data-controller/utils.ts +0 -415
  18. package/src/blocks/data-controller-manager.ts +0 -50
  19. package/src/blocks/data-controller.ts +0 -165
  20. package/src/blocks/hooks/built-in-suspendable-option-protocols/select.ts +0 -51
  21. package/src/blocks/hooks/built-in-suspendable-option-protocols/settings.ts +0 -70
  22. package/src/blocks/hooks/useSuspendableOptions.ts +0 -122
  23. package/src/blocks/index.ts +0 -23
  24. package/src/blocks/layered-styles-api.ts +0 -142
  25. package/src/blocks/layered-styles-impl.ts +0 -95
  26. package/src/blocks/layout/LaidOutProperty.tsx +0 -72
  27. package/src/blocks/layout/LaidOutPropertyRow.tsx +0 -28
  28. package/src/blocks/layout/NodeContext.tsx +0 -54
  29. package/src/blocks/layout/PanelRoot.tsx +0 -30
  30. package/src/blocks/layout/TabsRoot.tsx +0 -56
  31. package/src/blocks/layout/ToolsPanelContext.tsx +0 -22
  32. package/src/blocks/problematic-blocks-blocker.ts +0 -24
  33. package/src/blocks/problematic-variations-blocker.ts +0 -32
  34. package/src/blocks/shared-exportable-types.ts +0 -6
  35. package/src/blocks/shared-internal-types.ts +0 -18
  36. package/src/blocks/simple-block.tsx +0 -74
  37. package/src/blocks/simple-native-property-api.ts +0 -173
  38. package/src/blocks/simple-native-property-impl.tsx +0 -335
  39. package/src/blocks/simple-native-property-internal-shared.ts +0 -19
  40. package/src/blocks/snp-api.ts +0 -5
  41. package/src/blocks/snp-data-store.ts +0 -72
  42. package/src/blocks/utilities.ts +0 -66
  43. package/src/controls/AsynchronousFormTokenField.tsx +0 -86
  44. package/src/controls/BaseSortableItemsControl.tsx +0 -84
  45. package/src/controls/ExtendedFormTokenField.tsx +0 -144
  46. package/src/controls/ExtendedPostPicker.ts +0 -57
  47. package/src/controls/ExtendedRadioControl.tsx +0 -107
  48. package/src/controls/ExtendedTaxonomyPicker.tsx +0 -100
  49. package/src/controls/ExtendedTermPicker.tsx +0 -61
  50. package/src/controls/ExtendedTextareaControl.tsx +0 -65
  51. package/src/controls/ExtendedUserPicker.ts +0 -56
  52. package/src/controls/FileControl.tsx +0 -48
  53. package/src/controls/FullSizeToggleControl.tsx +0 -95
  54. package/src/controls/ImageControl.tsx +0 -143
  55. package/src/controls/InspectorPanel.tsx +0 -37
  56. package/src/controls/LazySuggestionsComboboxControl.tsx +0 -64
  57. package/src/controls/MultiSelectControl.tsx +0 -59
  58. package/src/controls/PickOne.tsx +0 -88
  59. package/src/controls/PromisableComponent.tsx +0 -56
  60. package/src/controls/ProperLinkControl.tsx +0 -98
  61. package/src/controls/SimpleToggle.tsx +0 -9
  62. package/src/controls/SortableFlexibleItemsControl.tsx +0 -37
  63. package/src/controls/SortableItemsControl.tsx +0 -22
  64. package/src/controls/basicNumericallyIdedItemPicker.tsx +0 -75
  65. package/src/controls/hooks/useImprovedTokenManager.ts +0 -163
  66. package/src/controls/hooks/useMultiSingleConversionLayer.ts +0 -17
  67. package/src/controls/hooks/useNonRenderingCounter.ts +0 -6
  68. package/src/controls/hooks/useOutputMemoizingFilter.ts +0 -16
  69. package/src/controls/hooks/useSortableItemsModel.ts +0 -196
  70. package/src/controls/hooks/useSuggestions.ts +0 -91
  71. package/src/controls/hooks/useTokenManager.ts +0 -177
  72. package/src/controls/index.ts +0 -24
  73. package/src/controls/shared.ts +0 -50
  74. package/src/controls/types.ts +0 -18
  75. package/src/editor/insert-sibling-or-child-block-shortcut.tsx +0 -60
  76. package/src/editor/install-insert-sole-allowed-block-shortcut-support.tsx +0 -51
  77. package/src/editor/simple-gutenberg-endpoints-api.ts +0 -31
  78. package/src/editor/simple-gutenberg-endpoints-impl.ts +0 -126
  79. package/src/index.ts +0 -30
  80. package/src/lib/compat-types.ts +0 -21
  81. package/src/lib/gutenberg-api-extensions-state/custom-block-bindings-support-logic.ts +0 -35
  82. package/src/lib/gutenberg-api-extensions-state/general-logic.ts +0 -41
  83. package/src/lib/gutenberg-api-extensions-state/layered-block-styles-logic.ts +0 -43
  84. package/src/lib/gutenberg-api-extensions-state/snp-logic.ts +0 -240
  85. package/src/lib/gutenberg-api-extensions-state.ts +0 -69
  86. package/src/lib/helpers.ts +0 -115
  87. package/src/lib/modified-fast-deep-equals.ts +0 -91
  88. package/src/lib/plaudit-icons/column-1.tsx +0 -6
  89. package/src/lib/plaudit-icons/column-2.tsx +0 -6
  90. package/src/lib/plaudit-icons/column-3.tsx +0 -6
  91. package/src/lib/plaudit-icons/placement-center.tsx +0 -3
  92. package/src/lib/plaudit-icons/placement-end.tsx +0 -3
  93. package/src/lib/plaudit-icons/placement-start.tsx +0 -3
  94. package/src/lib/plaudit-icons/placement-stretch.tsx +0 -3
  95. package/src/lib/plaudit-icons/plaudit-icon.tsx +0 -4
  96. package/src/lib/plaudit-icons/reusable-block-marker.tsx +0 -3
  97. package/src/lib/plaudit-icons.ts +0 -13
  98. package/src/lib/sectioned-cache-store.ts +0 -120
  99. package/src/lib/suspense/promise-handlers.ts +0 -72
  100. package/src/lib/suspense.tsx +0 -18
  101. package/src/lib/useful-types.ts +0 -82
  102. package/src/schemas/README.md +0 -1
  103. package/src/schemas/plaudit-block-schema.json +0 -818
@@ -1,261 +0,0 @@
1
- import {store as blocksStore, type BlockInstance} from "@wordpress/blocks";
2
- import {store as blockEditorStore} from "@wordpress/block-editor";
3
- import {select} from "@wordpress/data";
4
-
5
- import type {DataStore, NodePath, RawPath} from "./simple-native-property-api";
6
-
7
- export type CombinerOp = "and"|"or"|"not"|"nand"|"nor";
8
- export type CombinerConditionTest = {op: CombinerOp, conditions: ConditionStruct};
9
- export type PropertyConditionTest = {op: "=="|"!="|">"|"<"|">="|"<="|"in"|"!in"|"contains"|"!contains", property: string, value: any}|{op: "empty"|"!empty", property: string};
10
- export type ConditionTest = PropertyConditionTest|CombinerConditionTest;
11
- export type ConditionStruct = Array<ConditionTest|ConditionStruct>;
12
- export type ConditionFunction = (propertyValueResolver: (propertyPath: RawPath) => any) => boolean;
13
- export type Condition = ConditionFunction|ConditionStruct|undefined;
14
-
15
- export function isCombinerCondition(condition: ConditionTest): condition is CombinerConditionTest {
16
- return condition.op === "and" || condition.op === "or" || condition.op === "not" || condition.op === "nand" || condition.op === "nor";
17
- }
18
-
19
- export function testCondition(condition: Condition, propertyValueResolver: (propertyPath: RawPath) => any) {
20
- if (condition === undefined) {
21
- return true;
22
- }
23
- if (Array.isArray(condition)) {
24
- return condition.length === 0 || testConditionStruct(condition, propertyValueResolver, "or");
25
- }
26
- return condition(propertyValueResolver);
27
- }
28
- function performConditionTest(condition: ConditionTest, propertyValueResolver: (propertyPath: RawPath) => any): boolean {
29
- if (isCombinerCondition(condition)) {
30
- return testConditionStruct(condition.conditions, propertyValueResolver, condition.op);
31
- }
32
- const attrValue = propertyValueResolver(condition.property.split("."));
33
- if (!('value' in condition)) { // We negate this in order to ensure that unchecked values in the switch will throw a compile-time error
34
- return condition.op === "empty" ? !attrValue : !!attrValue;
35
- }
36
- switch (condition.op) {
37
- case "contains":
38
- return attrContains(condition.value, attrValue);
39
- case "!contains":
40
- return !attrContains(condition.value, attrValue);
41
- case "in":
42
- return isIn(condition.value, attrValue);
43
- case "!in":
44
- return !isIn(condition.value, attrValue);
45
- case "==":
46
- return attrValue == condition.value;
47
- case "!=":
48
- return attrValue != condition.value;
49
- case ">":
50
- return attrValue > condition.value;
51
- case "<":
52
- return attrValue < condition.value;
53
- case ">=":
54
- return attrValue >= condition.value;
55
- case "<=":
56
- return attrValue <= condition.value;
57
- }
58
- }
59
- function isIn(conditionValue: any, attrValue: any): boolean {
60
- if (typeof conditionValue === 'string') {
61
- return conditionValue.includes(attrValue?.toString());
62
- } else if (Array.isArray(conditionValue)) {
63
- return conditionValue.some(condVal => condVal == attrValue); // This is a "coercive" version of includes
64
- } else {
65
- if (conditionValue !== undefined) {
66
- console.error(`The in operators only support arrays and strings as their value. Received ${conditionValue} instead`);
67
- }
68
- return false;
69
- }
70
- }
71
- function attrContains(conditionValue: any, attrValue: any): boolean {
72
- if (typeof attrValue === 'string') {
73
- return attrValue.includes(conditionValue?.toString());
74
- } else if (Array.isArray(attrValue)) {
75
- return attrValue.some(attVal => attVal == conditionValue); // This is a "coercive" version of includes
76
- } else {
77
- if (attrValue !== undefined) {
78
- console.error(`The contains operators only support arrays and strings as their value. Received ${attrValue} instead`);
79
- }
80
- return false;
81
- }
82
- }
83
- function testConditionStruct(conditions: ConditionStruct, propertyValueResolver: (propertyPath: RawPath) => any, combiner: CombinerOp = "and"): boolean {
84
- switch (combiner) {
85
- case "and":
86
- for (const condition of conditions) {
87
- if (!(Array.isArray(condition) ? testConditionStruct(conditions, propertyValueResolver, "and") : performConditionTest(condition, propertyValueResolver))) {
88
- return false;
89
- }
90
- }
91
- return true;
92
- case "or":
93
- for (const condition of conditions) {
94
- if ((Array.isArray(condition) ? testConditionStruct(conditions, propertyValueResolver, "and") : performConditionTest(condition, propertyValueResolver))) {
95
- return true;
96
- }
97
- }
98
- return false;
99
- case "not":
100
- case "nand":
101
- for (const condition of conditions) {
102
- if (!(Array.isArray(condition) ? testConditionStruct(conditions, propertyValueResolver, "and") : performConditionTest(condition, propertyValueResolver))) {
103
- return true;
104
- }
105
- }
106
- return false;
107
- case "nor":
108
- for (const condition of conditions) {
109
- if ((Array.isArray(condition) ? testConditionStruct(conditions, propertyValueResolver, "and") : performConditionTest(condition, propertyValueResolver))) {
110
- return false;
111
- }
112
- }
113
- return true;
114
- }
115
- }
116
-
117
- export function resolveValueForCondition(propertyPath: RawPath, contextPath: RawPath, blockClientId: string, getDataStore: (property: string) => DataStore|undefined) {
118
- if (propertyPath[0] === "@block") {
119
- if (propertyPath.length >= 2) {
120
- const blockEditorSelect = select(blockEditorStore);
121
- if (typeof propertyPath[1] === 'string') {
122
- if (propertyPath[1] === 'parentClientId') {
123
- console.warn("Using parentClientId is deprecated. Please use clientId(1) instead.");
124
- return blockEditorSelect.getBlockParents(blockClientId, true)[0];
125
- }
126
- const potentialProperty = /^(anchor|attributes|className|clientId|name|variation)(?:\((\d+)\))?$/.exec(propertyPath[1]);
127
- if (potentialProperty !== null) {
128
- // This type is just the first group of the pattern's possible values
129
- const matchedProperty = potentialProperty[1] as ('anchor'|'attributes'|'className'|'clientId'|'name'|'variation');
130
- const index = potentialProperty[2] ? parseInt(potentialProperty[2]) : 0;
131
- const targetClientId = index ? blockEditorSelect.getBlockParents(blockClientId, true)[index - 1] : blockClientId;
132
- if (targetClientId === undefined || matchedProperty === "clientId") {
133
- // We handle the clientId property separately to avoid an unnecessary state lookup
134
- return targetClientId;
135
- }
136
-
137
- let targetBlockInstance: BlockInstance|null;
138
- if (index) {
139
- const targetBlockClientId = blockEditorSelect.getBlockParents(blockClientId, true)[index - 1];
140
- targetBlockInstance = targetBlockClientId ? blockEditorSelect.getBlock(targetBlockClientId) : null;
141
- } else {
142
- targetBlockInstance = blockEditorSelect.getBlock(blockClientId);
143
- }
144
- if (!targetBlockInstance) {
145
- return undefined;
146
- }
147
- if (matchedProperty === "attributes") {
148
- return walkToNodeWithLogging(targetBlockInstance.attributes, propertyPath.slice(2));
149
- }
150
-
151
- if (propertyPath.length > 2) {
152
- console.error(`@block.${matchedProperty} cannot have any additional terms in the path. They will be ignored.`);
153
- }
154
- switch (matchedProperty) {
155
- case "anchor":
156
- return targetBlockInstance.attributes["anchor"] ?? "";
157
- case "className":
158
- return targetBlockInstance.attributes["className"] ?? "";
159
- case "name":
160
- return targetBlockInstance.name;
161
- case "variation":
162
- return (select(blocksStore) as any).getActiveBlockVariation(targetBlockInstance.name, targetBlockInstance.attributes)?.name;
163
- }
164
- }
165
- }
166
- console.error(`Cannot resolve "${propertyPath[1]}" as a Block property.`);
167
- return undefined;
168
- }
169
- }
170
- const actualPath = resolveActualPathToValueForCondition(propertyPath, contextPath);
171
- if (actualPath === undefined) {
172
- return undefined;
173
- }
174
- const dataStore = getDataStore(actualPath[0]);
175
- return walkToNodeWithLogging(dataStore ? dataStore.getValue(actualPath[0]) : select(blockEditorStore).getBlockAttributes(blockClientId)?.[actualPath[0]], actualPath);
176
- }
177
-
178
- function resolveActualPathToValueForCondition(propertyPath: RawPath, contextPath: RawPath): NodePath|undefined {
179
- if (propertyPath.length === 0) {
180
- return undefined; //TODO: Log an error
181
- }
182
- let actualPath = [...contextPath];
183
-
184
- let sawRoot = false;
185
- let encounteredParents = 0;
186
- let relativePath: RawPath = [];
187
- for (let i = 0, nodeName: (typeof propertyPath[number])|undefined; i < propertyPath.length; i++) {
188
- nodeName = propertyPath[i];
189
- if (nodeName === '@root') {
190
- if (i > 0) {
191
- console.error("Encountered an improperly-placed '@root' name. '@root' must the first name in the path.", "It will be skipped.", `Preceding Part: ${relativePath.join(".")}`);
192
- }
193
- sawRoot = true;
194
- actualPath = [];
195
- } else if (nodeName === '@parent') {
196
- if (sawRoot) {
197
- console.error("Encountered a '@parent' name after encountering a '@root' name.", "It will be skipped.", `Preceding Part: ${relativePath.join(".")}`);
198
- } else if (relativePath.length > 0) {
199
- console.error("Encountered a '@parent' name after the first non-special name.", "It will be skipped.", `Preceding Part: ${relativePath.join(".")}`);
200
- } else {
201
- if (encounteredParents === actualPath.length - 1) { // The -1 is because we already remove the last node
202
- console.error("Encountered a '@parent' name that would attempt to resolve the parent of the root.", "It will be skipped.", `Preceding Part: ${relativePath.join(".")}`);
203
- }
204
- encounteredParents++;
205
- }
206
- } else if (nodeName !== undefined) {
207
- relativePath.push(nodeName);
208
- }
209
- }
210
- if (encounteredParents >= actualPath.length - 1) {
211
- actualPath = [];
212
- } else {
213
- actualPath = actualPath.slice(0, actualPath.length - encounteredParents - 1);
214
- }
215
-
216
- actualPath.push(...relativePath);
217
- if (actualPath.length === 0 || typeof actualPath[0] !== 'string') {
218
- console.error("Encountered an invalid path-resolution pair (context:", contextPath.join("."), ", property: ", propertyPath.join("."), ")");
219
- return undefined;
220
- }
221
- return actualPath as NodePath;
222
- }
223
-
224
- function walkToNodeWithLogging(value: any, propertyPath: RawPath) {
225
- for (let i = 1; i < propertyPath.length; i++) {
226
- if (value === null || value === undefined) {
227
- console.warn(
228
- `Encountered a ${value === null ? 'null' : 'undefined'} value while attempting to resolve a child value.`,
229
- `The property value will be treated as ${value === null ? 'null' : 'undefined'}`, `Property: ${propertyPath.join(".")}`, `Remainder: ${propertyPath.slice(i).join(".")}`
230
- );
231
- return value;
232
- } else if (typeof value !== 'object') {
233
- console.error(
234
- "Encountered a scalar value while attempting to resolve a child value.",
235
- "The scalar value will be used as the property value", `Property: ${propertyPath.join(".")}`, `Remainder: ${propertyPath.slice(i).join(".")}`
236
- );
237
- return value;
238
- } else {
239
- const name = propertyPath[i];
240
- if (Array.isArray(value)) {
241
- if (typeof name !== 'number') {
242
- console.error(
243
- "Encountered an array while attempting to resolve a named value.",
244
- "The array will be used as the property value", `Property: ${propertyPath.join(".")}`, `Remainder: ${propertyPath.slice(i).join(".")}`
245
- );
246
- return value;
247
- }
248
- } else {
249
- if (typeof name !== 'string') {
250
- console.error(
251
- "Encountered an object while attempting to resolve an index value.",
252
- "The object will be used as the property value", `Property: ${propertyPath.join(".")}`, `Remainder: ${propertyPath.slice(i).join(".")}`
253
- );
254
- return value;
255
- }
256
- }
257
- value = value[name];
258
- }
259
- }
260
- return value;
261
- }
@@ -1,221 +0,0 @@
1
- import type {BaseEntityRecords} from "@wordpress/core-data";
2
- import type {
3
- ColorPalette,
4
- DatePicker,
5
- DateTimePicker,
6
- RadioControl,
7
- RangeControl,
8
- TextareaControl,
9
- TextControl,
10
- ToggleControl,
11
- __experimentalToggleGroupControl as ToggleGroupControl,
12
- __experimentalToolsPanel as ToolsPanel
13
- } from "@wordpress/components";
14
-
15
- import {
16
- ExtendedPostPickerProps, ExtendedTaxonomyPickerProps, ExtendedTaxonomyPickerPropsMultiple, ExtendedTaxonomyPickerPropsSingle,
17
- ExtendedTermPickerProps, ExtendedTermPickerPropsMultiple, ExtendedTermPickerPropsSingle, ExtendedUserPickerProps, FileControl, FileControlProps,
18
- FlexibleItem, ImageControl, PickableOptions, ProperLinkControlProps, SortableItemsControlProps, TextareaControlPropsExtension
19
- } from "../controls";
20
- import type {IconName} from "./shared-exportable-types";
21
- import type {NormalSwitch, SmallSwitch} from "./shared-internal-types";
22
- import type {GenericSimpleNativeProperty, PDSimpleNativeProperty, SimpleNativeProperty, SimpleNativePropertyType} from "./simple-native-property-api";
23
-
24
- import type {ComponentPropsWithoutRef, CSSProperties, HTMLAttributes, ReactElement, ReactNode} from "react";
25
-
26
- export type CommonPropertyConfig<N extends typeof CSNPControlNames[number], T, C, V extends SimpleNativePropertyType> = Omit<GenericSimpleNativeProperty<T, V>, 'control'|'enum'|'type'|'label'>&{
27
- control: N
28
- label: string,
29
- help?: ReactNode,
30
- component?: Partial<C>,
31
- styleProperty?: string
32
- }
33
- export type CommonPropertyConfigWithEnum<N extends typeof CSNPControlNames[number], T, C, V extends SimpleNativePropertyType> = CommonPropertyConfig<N, T, C, V>&{enum?: T[]};
34
- export type ShareableSNPElements<T extends SimpleNativeProperty['type']> = Pick<SimpleNativeProperty, 'name'|'condition'|'alwaysStore'|'label'|'required'>&{type: T};
35
-
36
- export type CommonSimpleNativeProperty<N extends typeof CSNPControlNames[number], T, C, V extends SimpleNativePropertyType, A = {}> = CommonPropertyConfig<N, T, C, V> & A;
37
- export type CommonSimpleNativePropertyWithEnum<N extends typeof CSNPControlNames[number], T, C, V extends SimpleNativePropertyType, A = {}> = CommonPropertyConfigWithEnum<N, T, C, V> & A;
38
-
39
- type UnsuspendablePromisablePickableOptions<V extends string|number, T extends object = {}> = PickableOptions<V, T>|Promise<PickableOptions<V, T>>;
40
- export type SuspendablePromisablePickableOptions = `${string}://${string}`|`select:${string}:${string}${`:${string}`|''}`|`setting:${string}${`:${string}`|''}`|URL;
41
- export type PromisablePickableOptions<V extends string|number, T extends object = {}> = SuspendablePromisablePickableOptions|UnsuspendablePromisablePickableOptions<V, T>;
42
-
43
- type BaseConstantPropertyCSNPConfig = Omit<CommonSimpleNativeProperty<'constant', string|number|boolean|any[]|Record<string|number, unknown>|undefined,
44
- ComponentPropsWithoutRef<typeof TextControl>, SimpleNativePropertyType, { type: SimpleNativePropertyType }>, 'alwaysStore'>;
45
-
46
- export type ColorPaletteCSNPConfig = CommonSimpleNativePropertyWithEnum<'colorPalette', string, ComponentPropsWithoutRef<typeof ColorPalette>, 'string', {
47
- allowCustom?: boolean|undefined,
48
- clearable?: boolean|undefined,
49
- options: PromisablePickableOptions<string, {color?: CSSProperties['color']}>
50
- }>;
51
- export type ConstantPropertyCSNPConfig = Omit<BaseConstantPropertyCSNPConfig, 'default'>&Required<Pick<BaseConstantPropertyCSNPConfig, 'default'>>;
52
- export type DatePropertyCSNPConfig = CommonSimpleNativePropertyWithEnum<'date', number, ComponentPropsWithoutRef<typeof DateTimePicker>, 'number', {time: true}>
53
- |CommonSimpleNativePropertyWithEnum<'date', number, ComponentPropsWithoutRef<typeof DatePicker>, 'number', {time?: false|undefined}>;
54
-
55
- export type FilePropertyCSNPConfig = CommonSimpleNativeProperty<'file', number, Omit<ComponentPropsWithoutRef<typeof FileControl>, 'allowedTypes'>, 'number', Pick<FileControlProps, 'allowedTypes'>>;
56
-
57
- type NormalGroupPropertyCSNPConfig = CommonPropertyConfig<'group', Record<string, unknown>, HTMLAttributes<HTMLFieldSetElement>, 'object'>&{
58
- fields?: PDSimpleNativeProperty[],
59
- interface?: 'default'
60
- };
61
- type ToolsPanelPropertyCSNPConfig = CommonPropertyConfig<'group', Record<string, unknown>, ComponentPropsWithoutRef<typeof ToolsPanel>, 'object'>&{
62
- fields?: PDSimpleNativeProperty[],
63
- interface: 'toolsPanel'
64
- };
65
- export type GroupPropertyCSNPConfig = NormalGroupPropertyCSNPConfig|ToolsPanelPropertyCSNPConfig;
66
-
67
- export type ImagePropertyCSNPConfig = Omit<CommonPropertyConfig<'image', ImageData, {}, 'object'>, 'default'> & Partial<Pick<CommonPropertyConfig<'image', ImageData, {}, 'object'>, 'default'>> & {
68
- includeFocalPointPicker?: boolean,
69
- storage?: ComponentPropsWithoutRef<typeof ImageControl>['storage']
70
- };
71
-
72
- export type LinkPropertyCSNPConfig = CommonSimpleNativeProperty<'link', Record<string, unknown>, Omit<ProperLinkControlProps, 'settings'>, 'object',
73
- {settings?: ProperLinkControlProps['settings']|boolean}>;
74
-
75
- type ListPropertyConfigBase<T extends string|number|object, V extends 'string'|'number'|'object'> = CommonPropertyConfig<'list', T[], SortableItemsControlProps<T>, V>&{
76
- emptyValue?: T,
77
- min?: number,
78
- max?: number,
79
- listComponent?: ComponentPropsWithoutRef<typeof TextControl>
80
- };
81
- export type NumberListPropertyConfig = (ListPropertyConfigBase<number, 'number'>&{itemType: 'integer'|'int'})|(ListPropertyConfigBase<number, 'number'>&{itemType: 'float'});
82
- export type StringListPropertyConfig = ListPropertyConfigBase<string, 'string'>&{itemType?: 'string'};
83
- export type ObjectListPropertyConfig = ListPropertyConfigBase<object, 'object'>&{itemType: PDSimpleNativeProperty[]};
84
- export interface FlexibleItemsListPropertyConfig<T extends string = string> extends Omit<ListPropertyConfigBase<FlexibleItem<T>, 'object'>, 'emptyValue'> {
85
- sharedProperties?: PDSimpleNativeProperty[],
86
- itemType: Exclude<{[key in T]: {label: string, emptyValue?: object, properties: PDSimpleNativeProperty[]}}, any[]>
87
- }
88
- export type ListPropertyCSNPConfig = StringListPropertyConfig|NumberListPropertyConfig|ObjectListPropertyConfig|FlexibleItemsListPropertyConfig;
89
-
90
- export type MessagePropertyCSNPConfig = CommonSimpleNativeProperty<'message', string, {}, 'string'>;
91
-
92
- export type NumberPropertyCSNPConfig = CommonSimpleNativeProperty<'number', number, Omit<ComponentPropsWithoutRef<typeof TextControl>, 'type'>, 'number', {
93
- placeholder?: string|undefined, float?: boolean, min?: number, max?: number, step?: number|'any'
94
- }>;
95
- export type RadioPropertyCSNPConfig = CommonSimpleNativePropertyWithEnum<'radio', string, ComponentPropsWithoutRef<typeof RadioControl>, 'string', {
96
- allowCustom?: boolean,
97
- options: PromisablePickableOptions<string>
98
- }>;
99
- export type RangePropertyCSNPConfig = CommonSimpleNativePropertyWithEnum<'range', number, ComponentPropsWithoutRef<typeof RangeControl>, 'number', {
100
- min: number,
101
- max: number,
102
- step?: number
103
- }>;
104
- type SelectPropertyCSNPConfigSingle = CommonSimpleNativePropertyWithEnum<'select', string, never, 'string', {
105
- options: PromisablePickableOptions<string>,
106
- multiple?: false|undefined,
107
- clearable?: boolean|undefined
108
- }>;
109
- type SelectPropertyCSNPConfigMultiple = CommonSimpleNativeProperty<'select', string[], never, 'array', {
110
- options: PromisablePickableOptions<string>,
111
- multiple: true,
112
- expandOnFocus?: boolean,
113
- maxLength?: number
114
- }>;
115
- export type SelectPropertyCSNPConfig = SelectPropertyCSNPConfigSingle|SelectPropertyCSNPConfigMultiple;
116
- export type TextareaPropertyCSNPConfig = CommonSimpleNativeProperty<'textarea', string, ComponentPropsWithoutRef<typeof TextareaControl>, 'string', TextareaControlPropsExtension>;
117
- export type TextPropertyCSNPConfig = CommonSimpleNativeProperty<'text', string, ComponentPropsWithoutRef<typeof TextControl>, 'string', {placeholder?: string|undefined}>;
118
-
119
- type PostPropertyTypeSingle = CommonPropertyConfig<'post', number, ExtendedPostPickerProps, 'number'>&{postTypes?: string[], multiple?: false};
120
- type PostPropertyTypeMultiple = CommonPropertyConfig<'post', number[], ExtendedPostPickerProps, 'array'>&{postTypes?: string[], multiple: true};
121
- export type PostPropertyCSNPConfig = PostPropertyTypeSingle|PostPropertyTypeMultiple;
122
-
123
- type TaxonomyPropertyTypeSingle = CommonPropertyConfig<'taxonomy', string, ExtendedTaxonomyPickerProps, 'string'>&Omit<ExtendedTaxonomyPickerPropsSingle, 'onChange'>;
124
- type TaxonomyPropertyTypeMultiple = CommonPropertyConfig<'taxonomy', string[], ExtendedTaxonomyPickerProps, 'array'>&Omit<ExtendedTaxonomyPickerPropsMultiple, 'onChange'>;
125
- export type TaxonomyPropertyCSNPConfig = (TaxonomyPropertyTypeSingle|TaxonomyPropertyTypeMultiple)&{visibility?: Partial<BaseEntityRecords.TaxonomyVisibility>};
126
-
127
- type TermPropertyTypeSingle = CommonPropertyConfig<'term', string, ExtendedTermPickerProps, 'string'>&Omit<ExtendedTermPickerPropsSingle, 'onChange'>;
128
- type TermPropertyTypeMultiple = CommonPropertyConfig<'term', string[], ExtendedTermPickerProps, 'array'>&Omit<ExtendedTermPickerPropsMultiple, 'onChange'>;
129
- export type TermPropertyCSNPConfig = (TermPropertyTypeSingle|TermPropertyTypeMultiple);
130
-
131
- type ToggleGroupPropertyConfigBase<T extends string|number, V extends 'string'|'number'>
132
- = CommonPropertyConfig<'toggleGroup', T, ComponentPropsWithoutRef<typeof ToggleGroupControl>, V>&{options: PromisablePickableOptions<T, {icon?: ReactElement|IconName}>, clearable?: boolean, type?: V};
133
- type StringValuedToggleGroupConfig = ToggleGroupPropertyConfigBase<string, 'string'>;
134
- type NumberValuedToggleGroupConfig = ToggleGroupPropertyConfigBase<number, 'number'>;
135
- export type ToggleGroupPropertyCSNPConfig = StringValuedToggleGroupConfig|NumberValuedToggleGroupConfig;
136
-
137
- export type TogglePropertyCSNPConfig = (CommonPropertyConfig<'toggle', boolean, ComponentPropsWithoutRef<typeof ToggleControl>, 'boolean'>&{switch: SmallSwitch})
138
- |(CommonPropertyConfig<'toggle', boolean, ComponentPropsWithoutRef<typeof ToggleGroupControl>, 'boolean'>&{switch?: NormalSwitch});
139
-
140
- type UserPropertyTypeSingle = CommonPropertyConfig<'user', number, ExtendedUserPickerProps, 'number'>&{userRoles?: string[], multiple?: false};
141
- type UserPropertyTypeMultiple = CommonPropertyConfig<'user', number[], ExtendedUserPickerProps, 'array'>&{userRoles?: string[], multiple: true};
142
- export type UserPropertyCSNPConfig = UserPropertyTypeSingle|UserPropertyTypeMultiple;
143
-
144
- export type CSNPConfig = ColorPaletteCSNPConfig|ConstantPropertyCSNPConfig|DatePropertyCSNPConfig|FilePropertyCSNPConfig|GroupPropertyCSNPConfig
145
- |ImagePropertyCSNPConfig|LinkPropertyCSNPConfig|ListPropertyCSNPConfig|MessagePropertyCSNPConfig|NumberPropertyCSNPConfig|PostPropertyCSNPConfig|RadioPropertyCSNPConfig
146
- |RangePropertyCSNPConfig|SelectPropertyCSNPConfig|TaxonomyPropertyCSNPConfig|TermPropertyCSNPConfig|TextareaPropertyCSNPConfig|TextPropertyCSNPConfig
147
- |ToggleGroupPropertyCSNPConfig|TogglePropertyCSNPConfig|UserPropertyCSNPConfig;
148
-
149
- export const CSNPControlNames = [
150
- 'colorPalette', 'constant', 'date', 'file', 'group', 'image', 'link', 'list', 'message', 'number', 'post', 'radio', 'range', 'select', 'taxonomy', 'term',
151
- 'text', 'textarea', 'toggle', 'toggleGroup', 'user'
152
- ] as const;
153
-
154
- export function getPropType(config: PDSimpleNativeProperty): SimpleNativePropertyType {
155
- if (isCSNPConfig(config)) {
156
- switch (config.control) {
157
- case "colorPalette":
158
- return 'string';
159
- case "constant":
160
- return config.type;
161
- case "date":
162
- case "file":
163
- return 'number';
164
- case "group":
165
- case "image":
166
- case "link":
167
- return 'object';
168
- case "list":
169
- return 'array';
170
- case "message":
171
- return 'string';
172
- case "number":
173
- return 'number';
174
- case "post":
175
- return config.multiple ? 'array' : 'number';
176
- case "radio":
177
- return 'string';
178
- case "range":
179
- return 'number';
180
- case "select":
181
- case "taxonomy":
182
- case "term":
183
- return config.multiple ? 'array' : 'string';
184
- case "textarea":
185
- case "text":
186
- return 'string';
187
- case "toggle":
188
- return 'boolean';
189
- case "toggleGroup":
190
- return isStringValuedToggleGroupCSNPConfig(config) ? 'string' : 'number';
191
- case "user":
192
- return config.multiple ? 'array' : 'number';
193
- }
194
- } else {
195
- return config.type;
196
- }
197
- }
198
-
199
- export function isCSNPConfig(config: PDSimpleNativeProperty): config is CSNPConfig {
200
- return isNamedCSNPControl(config.control);
201
- }
202
-
203
- export function isNamedCSNPControl(control: PDSimpleNativeProperty['control']): control is typeof CSNPControlNames[number] {
204
- return typeof control === 'string' && CSNPControlNames.includes(control as any);
205
- }
206
-
207
- export function isStringValuedToggleGroupCSNPConfig(config: ToggleGroupPropertyCSNPConfig): config is StringValuedToggleGroupConfig {
208
- if (config.type) {
209
- return config.type === 'string';
210
- }
211
- if (config.default === undefined) {
212
- console.warn(`Encountered a toggleGroup SNP named "${config.name}" without a declared type or default.`,
213
- "It will be treated as if its values are strings.", config);
214
- return true;
215
- }
216
- return typeof config.default !== 'number';
217
- }
218
-
219
- export function isObjectListPropertyConfig(config: ListPropertyCSNPConfig): config is ObjectListPropertyConfig {
220
- return Array.isArray(config.itemType);
221
- }
@@ -1,20 +0,0 @@
1
- import type {HydratedLaidOutProperties} from "../simple-native-property-internal-shared";
2
- import type {DataStore} from "../simple-native-property-api";
3
- import {createGlobalAction, createPathedAction} from "./trigger-handlers";
4
-
5
- export const actions = {
6
- addProperties: createGlobalAction<{properties: HydratedLaidOutProperties, dataStore: DataStore}>('addProperties', {conditionChecks: true, changedByManagedControl: true}),
7
- checkConditions: createGlobalAction('checkConditions', {conditionChecks: true}), // This action is handled implicitly
8
- commitBatchAddedProperties: createGlobalAction('commitBatchAddedProperties'),
9
- markManagedControlChangeHandled: createGlobalAction('markManagedControlChangeHandled'),
10
- validateNodes: createGlobalAction('validateNodes'),
11
- node: {
12
- add: createPathedAction<{value?: any, subtype?: string}>('node/add', {conditionChecks: true, changedByManagedControl: true}),
13
- remove: createPathedAction('node/remove', {conditionChecks: true, changedByManagedControl: true}),
14
- move: createPathedAction<{from: number, to: number}|{from: string, to: string}>('node/move', {conditionChecks: true}),
15
- validate: createPathedAction('node/validate', {validation: true}), // This action is handled implicitly
16
- write: createPathedAction<{value?: any}>('node/write', {conditionChecks: true, validation: true, changedByManagedControl: true}),
17
- }
18
- } as const;
19
-
20
- export type DataControllerActions = ReturnType<typeof actions[Exclude<keyof typeof actions, 'node'>]|typeof actions['node'][keyof typeof actions['node']]>;
@@ -1,146 +0,0 @@
1
- import {createReducer} from "@reduxjs/toolkit";
2
- import {produce} from "immer";
3
-
4
- import {actions} from "./actions";
5
- import {DCStoreState, walkToNodeInValue} from "../data-controller";
6
- import {PathError} from "../PathError";
7
- import type {HydratedSimpleNativeProperty} from "../simple-native-property-api";
8
- import {triggerHandlers, validateFoundNode} from "./trigger-handlers";
9
- import {
10
- applyToTree, buildDefaultValueFromDefinition,
11
- buildNodeFromDataAndDefinition, getDataStore,
12
- moveNodeWithinParent,
13
- populateValueBasedOnDefinition, recordCloneableDefaultValueForNode, removeBackupForNode,
14
- removeFromParentNode, removeValueFromBackingDataStore,
15
- resolveParentNodeDefinition, TreeMutatorResult,
16
- walkToNode, writeValueToBackingDataStoreWithCorrections
17
- } from "./utils";
18
-
19
- export function buildReducer(blockClientId: string) {
20
- const initialState: DCStoreState = {
21
- treeRoot: {children: {}, rendered: true}, dataStores: {byProperty: {}, list: []}, blockClientId, changedByManagedControl: false, rerenderTrigger: 0,
22
- batchAddedPropertiesThatNeedWriteThrough: []
23
- };
24
-
25
- return createReducer(initialState, builder => {
26
- builder
27
- .addCase(actions.addProperties, (state, {payload: {properties, dataStore}, meta}) => {
28
- if (!state.dataStores.list.includes(dataStore)) {
29
- state.dataStores.list.push(dataStore);
30
- }
31
- for (const property of properties) {
32
- for (const prop of Array.isArray(property) ? property : [property]) {
33
- dataStore.addProperty(prop);
34
- state.dataStores.byProperty[prop.name] = dataStore;
35
- state.treeRoot.children[prop.name] = buildNodeFromDataAndDefinition(dataStore.getValue(prop.name), prop);
36
- }
37
- }
38
- return state;
39
- })
40
- .addCase(actions.validateNodes, state => {
41
- let hasChanged = false;
42
- applyToTree(state.treeRoot, (node, path) => {
43
- if (!node.rendered) {
44
- return TreeMutatorResult.SKIP_DESCENDANTS;
45
- }
46
-
47
- if (validateFoundNode(node, path, state)) {
48
- hasChanged = true;
49
- }
50
- return TreeMutatorResult.CONTINUE;
51
- });
52
- if (hasChanged) {
53
- state.rerenderTrigger++;
54
- }
55
- })
56
- .addCase(actions.markManagedControlChangeHandled, state => {
57
- state.changedByManagedControl = false;
58
- })
59
- .addCase(actions.commitBatchAddedProperties, state => {
60
- const batch = [...state.batchAddedPropertiesThatNeedWriteThrough];
61
- state.batchAddedPropertiesThatNeedWriteThrough = [];
62
- for (const batchAddedProperty of batch) {
63
- if (state.treeRoot.children[batchAddedProperty.name]?.rendered) {
64
- writeValueToBackingDataStoreWithCorrections([batchAddedProperty.name], state, buildDefaultValueFromDefinition(batchAddedProperty));
65
- }
66
- }
67
- })
68
- .addCase(actions.node.add, (state, {payload: {path, value, subtype}}) => {
69
- const parentDefinition = resolveParentNodeDefinition(state.treeRoot, path);
70
- if (!parentDefinition) {
71
- throw new Error("Cannot add children to a node without a definition");
72
- }
73
- const nodeNameOrIndex = path[path.length - 1];
74
- let parentDefinitionChildren: HydratedSimpleNativeProperty[] | undefined;
75
- if (Array.isArray(parentDefinition.children) || parentDefinition.children === undefined) {
76
- parentDefinitionChildren = parentDefinition.children;
77
- } else {
78
- const actualSubtype = value?.type ?? subtype;
79
- if (!actualSubtype || !parentDefinition.children[actualSubtype]) {
80
- throw new PathError("Unable to locate the definition of the named node because its type could not be resolved.", path);
81
- }
82
- parentDefinitionChildren = parentDefinition.children[actualSubtype];
83
- }
84
-
85
- if (typeof nodeNameOrIndex === 'string') {
86
- const definition = parentDefinitionChildren?.find(definition => definition.name === nodeNameOrIndex);
87
- if (definition === undefined) {
88
- throw new PathError("Unable to locate the definition of the named node.", path);
89
- }
90
- const data = populateValueBasedOnDefinition(value, parentDefinition);
91
- const builtNode = buildNodeFromDataAndDefinition(data, definition);
92
- const parentNode = walkToNode(state.treeRoot, path.slice(0, path.length - 1));
93
- if (parentNode.children === undefined) {
94
- parentNode.children = {[nodeNameOrIndex]: builtNode};
95
- } else {
96
- if (Array.isArray(parentNode.children)) {
97
- throw new PathError("Encountered a node with indexed descendants while expecting one with string-keyed descendants.", path);
98
- }
99
- parentNode.children[nodeNameOrIndex] = builtNode;
100
- }
101
- writeValueToBackingDataStoreWithCorrections(path, state, data);
102
- } else if (nodeNameOrIndex === undefined) {
103
- throw new PathError("Encountered an undefined name in a path.", path);
104
- } else {
105
- const data = populateValueBasedOnDefinition(value, parentDefinition);
106
- const builtNode = buildNodeFromDataAndDefinition(data, parentDefinition);
107
- const parentNode = walkToNode(state.treeRoot, path.slice(0, path.length - 1));
108
- if (parentNode.children === undefined) {
109
- parentNode.children = [];
110
- parentNode.children[nodeNameOrIndex] = builtNode;
111
- } else {
112
- if (!Array.isArray(parentNode.children)) {
113
- throw new PathError("Encountered a node with string-keyed descendants while expecting one with indexed descendants.", path);
114
- }
115
- parentNode.children[nodeNameOrIndex] = builtNode;
116
- }
117
- writeValueToBackingDataStoreWithCorrections(path, state, data);
118
- }
119
- })
120
- .addCase(actions.node.remove, (state, {payload: {path}}) => {
121
- const parentNode = walkToNode(state.treeRoot, path.slice(0, path.length - 1));
122
- removeFromParentNode(parentNode.children, path);
123
- removeValueFromBackingDataStore(getDataStore(path[0], state, true), path);
124
- removeBackupForNode(walkToNode(state.treeRoot, path));
125
- })
126
- .addCase(actions.node.move, (state, {payload: {path, ...action}}) => {
127
- // If from and to are the same, then this is a no-op, so we can just skip it
128
- if (action.from === action.to) {
129
- return;
130
- }
131
- state.changedByManagedControl = true;
132
- moveNodeWithinParent(walkToNode(state.treeRoot, path).children, path, action);
133
- const dataStore = getDataStore(path[0], state, true);
134
- dataStore.setValue(path[0], produce(dataStore.getValue(path[0]), (dsDraft: any) => {
135
- moveNodeWithinParent(walkToNodeInValue(dsDraft, path), path, action);
136
- }));
137
- })
138
- .addCase(actions.node.write, (state, {payload: {path, value}}) => {
139
- writeValueToBackingDataStoreWithCorrections(path, state, value);
140
- })
141
- ;
142
- for (const {attachTo} of Object.values(triggerHandlers)) {
143
- attachTo(builder);
144
- }
145
- });
146
- }