@plaudit/gutenberg-api-extensions 2.90.1 → 2.91.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 +7 -0
- package/dist/blocks/common-native-property-constructors.js +18 -11
- package/dist/blocks/common-native-property-constructors.js.map +1 -1
- package/dist/blocks/data-controller/reducer.js +1 -4
- package/dist/blocks/data-controller/reducer.js.map +1 -1
- package/dist/blocks/data-controller/trigger-handlers.js +20 -11
- package/dist/blocks/data-controller/trigger-handlers.js.map +1 -1
- package/dist/blocks/data-controller/utils.js +9 -9
- package/dist/blocks/data-controller/utils.js.map +1 -1
- package/dist/blocks/data-controller-manager.d.ts +1 -1
- package/dist/blocks/data-controller-manager.js.map +1 -1
- package/dist/blocks/data-controller.d.ts +1 -1
- package/dist/blocks/data-controller.js.map +1 -1
- package/dist/blocks/hooks/useSuspendableOptions.js +1 -1
- package/dist/blocks/hooks/useSuspendableOptions.js.map +1 -1
- package/dist/blocks/simple-native-property-api.d.ts +1 -1
- package/dist/blocks/simple-native-property-impl.js +0 -1
- package/dist/blocks/simple-native-property-impl.js.map +1 -1
- package/dist/blocks/snp-data-store.d.ts +2 -2
- package/dist/blocks/snp-data-store.js +10 -15
- package/dist/blocks/snp-data-store.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/modified-fast-deep-equals.d.ts +4 -0
- package/dist/lib/modified-fast-deep-equals.js +91 -0
- package/dist/lib/modified-fast-deep-equals.js.map +1 -0
- package/package.json +2 -2
- package/src/blocks/common-native-property-constructors.tsx +18 -12
- package/src/blocks/data-controller/reducer.ts +1 -4
- package/src/blocks/data-controller/trigger-handlers.ts +22 -11
- package/src/blocks/data-controller/utils.ts +9 -9
- package/src/blocks/data-controller-manager.ts +2 -2
- package/src/blocks/data-controller.ts +2 -4
- package/src/blocks/hooks/useSuspendableOptions.ts +1 -1
- package/src/blocks/simple-native-property-api.ts +1 -1
- package/src/blocks/simple-native-property-impl.tsx +0 -1
- package/src/blocks/snp-data-store.ts +12 -15
- package/src/index.ts +5 -2
- package/src/lib/modified-fast-deep-equals.ts +91 -0
- package/styles/sortable-items-control.pcss +61 -55
|
@@ -276,7 +276,6 @@ function SNPPropsWrapper({blockSimpleNativePanelsAndTabs, blockEditProps, dataCo
|
|
|
276
276
|
}
|
|
277
277
|
dataController.checkConditions();
|
|
278
278
|
dataController.validateNodes();
|
|
279
|
-
dataController.commitBatchAddedProperties();
|
|
280
279
|
}, [blockSimpleNativePanelsAndTabs, dataController]); // We don't depend on blockEditProps here - that is handled by the following useEffect
|
|
281
280
|
|
|
282
281
|
// We have to reattach dataStores in the useMemo segment in order for Panel- and Tab-level conditions to work
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {store as blockEditorStore} from "@wordpress/block-editor";
|
|
2
2
|
import {dispatch, select} from "@wordpress/data";
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import {fastDeepEquals} from "../lib/modified-fast-deep-equals";
|
|
5
|
+
|
|
6
|
+
import type {UUID} from "./data-controller/utils";
|
|
5
7
|
import type {ActualBlockEditProps, BlockName} from "../lib/useful-types";
|
|
6
8
|
import type {DataStore, HydratedSimpleNativeProperty} from "./simple-native-property-api";
|
|
7
9
|
|
|
@@ -30,8 +32,14 @@ export abstract class SNPDataStore implements DataStore {
|
|
|
30
32
|
return this.attributeCache[attr] = existingValue;
|
|
31
33
|
}
|
|
32
34
|
setValue(attr: string, value: any) {
|
|
33
|
-
this.
|
|
34
|
-
|
|
35
|
+
const existingValue = this.getValue(attr);
|
|
36
|
+
if (!fastDeepEquals(existingValue, value)) {
|
|
37
|
+
this.attributeCache[attr] = value;
|
|
38
|
+
// WordPress doesn't handle saving and loading of empty objects consistently. As a result, we cannot safely write empty objects if the existing value is undefined
|
|
39
|
+
if (existingValue !== undefined || typeof value !== 'object' || !value || Object.entries(value).some(([, v]) => v !== undefined)) {
|
|
40
|
+
this.setAttribute(attr, value);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
35
43
|
}
|
|
36
44
|
handlesProperty(name: string): boolean {
|
|
37
45
|
return name in this.managedPropertyNames;
|
|
@@ -58,18 +66,7 @@ export abstract class SNPDataStore implements DataStore {
|
|
|
58
66
|
return attr in this.attributeCache;
|
|
59
67
|
}
|
|
60
68
|
|
|
61
|
-
addProperty(property: HydratedSimpleNativeProperty<{uuid: UUID}
|
|
62
|
-
if (this.managedPropertyNames[property.name]) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
if (this.getAttribute(property.name) === undefined) {
|
|
66
|
-
if (writeThroughOnUndefined) {
|
|
67
|
-
this.setValue(property.name, buildDefaultValueFromDefinition(property));
|
|
68
|
-
} else {
|
|
69
|
-
this.attributeCache[property.name] = buildDefaultValueFromDefinition(property);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
69
|
+
addProperty(property: HydratedSimpleNativeProperty<{uuid: UUID}>) {
|
|
73
70
|
this.managedPropertyNames[property.name] = true;
|
|
74
71
|
}
|
|
75
72
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import {installSimpleNativePropertiesSupport} from "./blocks/simple-native-property-impl";
|
|
2
|
-
import {installSimpleGutenbergApisSupport,
|
|
3
|
-
import {registerStore,
|
|
2
|
+
import {installSimpleGutenbergApisSupport, store as endpointStore} from "./editor/simple-gutenberg-endpoints-impl";
|
|
3
|
+
import {registerStore, store as apiStore} from "./lib/gutenberg-api-extensions-state";
|
|
4
4
|
|
|
5
5
|
export * from "./blocks";
|
|
6
6
|
export * from "./controls";
|
|
7
7
|
export * from "./editor/simple-gutenberg-endpoints-api";
|
|
8
8
|
export {TemporalLRUCache, useAdoptedStyleSheet} from "./lib/helpers";
|
|
9
|
+
export * from "./lib/modified-fast-deep-equals";
|
|
9
10
|
export * from "./lib/plaudit-icons";
|
|
10
11
|
export * as SectionedCacheStore from "./lib/sectioned-cache-store";
|
|
11
12
|
export * from "./lib/suspense";
|
|
12
13
|
export type * from "./lib/useful-types";
|
|
13
14
|
|
|
15
|
+
export {apiStore, endpointStore};
|
|
16
|
+
|
|
14
17
|
export function installGutenbergExtensions() {
|
|
15
18
|
if (!installGutenbergExtensions.called) {
|
|
16
19
|
installGutenbergExtensions.called = true;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is a modified copy of https://github.com/epoberezkin/fast-deep-equal that treats "not present" and "present but undefined" as equivalent
|
|
3
|
+
*/
|
|
4
|
+
export function fastDeepEquals(a: unknown, b: unknown) {
|
|
5
|
+
if (a === b) return true;
|
|
6
|
+
|
|
7
|
+
if (a && b && typeof a === 'object' && typeof b === 'object') {
|
|
8
|
+
if (a.constructor !== b.constructor) return false;
|
|
9
|
+
|
|
10
|
+
if (Array.isArray(a)) {
|
|
11
|
+
if (!Array.isArray(b)) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const length = a.length;
|
|
16
|
+
if (length !== b.length) return false;
|
|
17
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
18
|
+
if (!fastDeepEquals(a[i], b[i])) return false;
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
if (a instanceof Map) {
|
|
25
|
+
if (!(b instanceof Map)) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
for (const [key, value] of b.entries()) {
|
|
30
|
+
if (value !== undefined && !a.has(key)) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
for (const [key, value] of a.entries()) {
|
|
35
|
+
if (value !== undefined && !b.has(key)) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
if (!fastDeepEquals(value, b.get(key))) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (a instanceof Set) {
|
|
46
|
+
if (!(b instanceof Set)) {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
if (a.size !== b.size) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
for (const key of a.keys()) {
|
|
53
|
+
if (!b.has(key)) return false;
|
|
54
|
+
}
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (a instanceof RegExp) {
|
|
59
|
+
return b instanceof RegExp && a.source === b.source && a.flags === b.flags;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (a.valueOf !== Object.prototype.valueOf) return a.valueOf() === b.valueOf();
|
|
63
|
+
if (a.toString !== Object.prototype.toString) return a.toString() === b.toString();
|
|
64
|
+
|
|
65
|
+
for (const [key, value] of Object.entries(b)) {
|
|
66
|
+
if (value !== undefined && !(key in a)) {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
for (const [key, value] of Object.entries(a)) {
|
|
71
|
+
if (key === '_owner' && "$$typeof" in a) {
|
|
72
|
+
// React-specific: avoid traversing React elements' _owner.
|
|
73
|
+
// _owner contains circular references
|
|
74
|
+
// and is not needed when comparing the actual elements (and not their owners)
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (value !== undefined) {
|
|
78
|
+
if (!fastDeepEquals(value, b[key as keyof typeof b])) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
} else if (key in b && b[key as keyof typeof b] !== undefined) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return true;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// true if both NaN, false otherwise
|
|
90
|
+
return a!==a && b!==b;
|
|
91
|
+
}
|
|
@@ -1,71 +1,77 @@
|
|
|
1
|
-
.plaudit-sortable-items-container
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
.plaudit-sortable-items-container {
|
|
2
|
+
.drop-zone {
|
|
3
|
+
background-color: #ccc;
|
|
4
|
+
transition-property: height, padding;
|
|
5
|
+
transition-duration: 250ms;
|
|
6
|
+
transition-timing-function: cubic-bezier(0.075, 0.82, 0.165, 1);
|
|
7
|
+
overflow: hidden;
|
|
8
|
+
height: 20px;
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
10
|
+
&.plaudit-sortable-items-hidden {
|
|
11
|
+
height: 0;
|
|
12
|
+
padding: 0;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
14
15
|
|
|
15
|
-
.
|
|
16
|
-
|
|
17
|
-
}
|
|
18
|
-
.plaudit-sortable-items-container .floating {
|
|
19
|
-
position: fixed;
|
|
20
|
-
box-shadow: 5px 5px 10px rgba(0,0,0,0.5);
|
|
21
|
-
}
|
|
16
|
+
.dragging {
|
|
17
|
+
display: none !important;
|
|
18
|
+
}
|
|
22
19
|
|
|
23
|
-
.
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
border: 1px solid #ccc;
|
|
28
|
-
background: #fff;
|
|
29
|
-
}
|
|
30
|
-
.plaudit-sortable-items-container .plaudit-sortable-items-ordering-controls {
|
|
31
|
-
display: flex;
|
|
32
|
-
flex-direction: row;
|
|
33
|
-
gap: 0;
|
|
34
|
-
padding-right: 6px;
|
|
20
|
+
.floating {
|
|
21
|
+
position: fixed;
|
|
22
|
+
box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.5);
|
|
23
|
+
}
|
|
35
24
|
|
|
36
|
-
.plaudit-sortable-items-
|
|
25
|
+
.plaudit-sortable-items-row {
|
|
37
26
|
display: grid;
|
|
38
|
-
|
|
39
|
-
|
|
27
|
+
grid-template-areas: "HANDLE FIELD CONTROL";
|
|
28
|
+
grid-template-columns: auto 1fr auto;
|
|
29
|
+
border: 1px solid #ccc;
|
|
30
|
+
background: #fff;
|
|
31
|
+
}
|
|
40
32
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
.plaudit-sortable-items-ordering-controls {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: row;
|
|
36
|
+
gap: 0;
|
|
37
|
+
padding-right: 6px;
|
|
38
|
+
|
|
39
|
+
.plaudit-sortable-items-ordering-control {
|
|
40
|
+
display: grid;
|
|
41
|
+
place-content: center;
|
|
42
|
+
line-height: 1;
|
|
45
43
|
|
|
46
|
-
|
|
44
|
+
.components-button {
|
|
45
|
+
height: 16px;
|
|
46
|
+
min-width: 16px;
|
|
47
47
|
padding: 0;
|
|
48
|
-
|
|
48
|
+
|
|
49
|
+
span.dashIcon {
|
|
50
|
+
padding: 0;
|
|
51
|
+
width: 16px;
|
|
52
|
+
}
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
|
-
}
|
|
53
|
-
.plaudit-sortable-items-container .plaudit-sortable-items-presence-controls {
|
|
54
|
-
display: flex;
|
|
55
|
-
flex-direction: column;
|
|
56
|
-
margin-top: -4px;
|
|
57
56
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
.plaudit-sortable-items-presence-controls {
|
|
58
|
+
display: flex;
|
|
59
|
+
flex-direction: column;
|
|
60
|
+
margin-top: -4px;
|
|
61
|
+
|
|
62
|
+
button[aria-label="Insert After"] {
|
|
63
|
+
position: absolute;
|
|
64
|
+
top: 100%;
|
|
65
|
+
left: 50%;
|
|
66
|
+
width: 30px;
|
|
67
|
+
height: 30px;
|
|
68
|
+
transform: translate(-50%, -50%);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.plaudit-sortable-items-padded {
|
|
73
|
+
padding-block: 8px;
|
|
65
74
|
}
|
|
66
|
-
}
|
|
67
|
-
.plaudit-sortable-items-container .plaudit-sortable-items-padded {
|
|
68
|
-
padding-block-start: 8px;
|
|
69
75
|
}
|
|
70
76
|
|
|
71
77
|
.plaudit-sortable-items-buttons.flexible-items {
|