Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8516fff

Browse files
authoredJan 15, 2025··
Merge pull request #580 from prezly/refactor/dev-19139-get-rid-of-extension-is-element-equal
[DEV-19139] Refactor - Drop `Extension.isElementEqual`
2 parents 68b7798 + 21adaf1 commit 8516fff

File tree

16 files changed

+132
-171
lines changed

16 files changed

+132
-171
lines changed
 

‎packages/slate-commons/src/types/Extension.ts

+1-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Element, Node } from 'slate';
1+
import type { Node } from 'slate';
22

33
import type { DecorateFactory } from './DecorateFactory';
44
import type { DeserializeHtml } from './DeserializeHtml';
@@ -12,12 +12,6 @@ export interface Extension {
1212
id: string;
1313
decorate?: DecorateFactory;
1414
deserialize?: DeserializeHtml;
15-
/**
16-
* Compare two elements.
17-
* `children` arrays can be omitted from the comparison,
18-
* as the outer code will compare them anyway.
19-
*/
20-
isElementEqual?: (node: Element, another: Element) => boolean | undefined;
2115
isInline?: (node: Node) => boolean;
2216
isRichBlock?: (node: Node) => boolean;
2317
isVoid?: (node: Node) => boolean;

‎packages/slate-editor/src/extensions/coverage/CoverageExtension.tsx

+6-12
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,18 @@ export const EXTENSION_ID = 'CoverageExtension';
1313

1414
export interface Parameters extends CoverageExtensionConfiguration {}
1515

16-
export const CoverageExtension = ({ dateFormat, fetchCoverage, onEdit, withLayoutOptions }: Parameters): Extension => ({
16+
export const CoverageExtension = ({
17+
dateFormat,
18+
fetchCoverage,
19+
onEdit,
20+
withLayoutOptions,
21+
}: Parameters): Extension => ({
1722
id: EXTENSION_ID,
1823
deserialize: {
1924
element: composeElementDeserializer({
2025
[COVERAGE_NODE_TYPE]: createDeserializeElement(parseSerializedElement),
2126
}),
2227
},
23-
isElementEqual: (node, another) => {
24-
if (isCoverageNode(node) && isCoverageNode(another)) {
25-
return (
26-
node.coverage.id === another.coverage.id &&
27-
node.layout === another.layout &&
28-
node.new_tab === another.new_tab &&
29-
node.show_thumbnail === another.show_thumbnail
30-
);
31-
}
32-
return undefined;
33-
},
3428
isRichBlock: isCoverageNode,
3529
isVoid: isCoverageNode,
3630
normalizeNode: normalizeRedundantCoverageAttributes,

‎packages/slate-editor/src/extensions/embed/EmbedExtension.tsx

-11
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { OEmbedInfo } from '@prezly/sdk';
22
import type { Extension } from '@prezly/slate-commons';
33
import { createDeserializeElement } from '@prezly/slate-commons';
4-
import { isEqual } from '@technically/lodash';
54
import React from 'react';
65
import type { RenderElementProps } from 'slate-react';
76

@@ -45,16 +44,6 @@ export const EmbedExtension = ({
4544
[EmbedNode.TYPE]: createDeserializeElement(parseSerializedElement),
4645
}),
4746
},
48-
isElementEqual: (node, another) => {
49-
if (EmbedNode.isEmbedNode(node) && EmbedNode.isEmbedNode(another)) {
50-
return (
51-
node.url === another.url &&
52-
node.layout === another.layout &&
53-
isEqual(node.oembed, another.oembed)
54-
);
55-
}
56-
return undefined;
57-
},
5847
isRichBlock: EmbedNode.isEmbedNode,
5948
isVoid: EmbedNode.isEmbedNode,
6049
normalizeNode: [fixUuidCollisions, normalizeRedundantEmbedAttributes],

‎packages/slate-editor/src/extensions/file-attachment/FileAttachmentExtension.tsx

+1-8
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import type { Extension } from '@prezly/slate-commons';
22
import { createDeserializeElement } from '@prezly/slate-commons';
33
import type { AttachmentNode } from '@prezly/slate-types';
44
import { ATTACHMENT_NODE_TYPE, isAttachmentNode } from '@prezly/slate-types';
5-
import { isEqual, noop } from '@technically/lodash';
5+
import { noop } from '@technically/lodash';
66
import type { SlateEditor } from '@udecode/plate-common';
77
import React from 'react';
88
import type { RenderElementProps } from 'slate-react';
@@ -31,13 +31,6 @@ export const FileAttachmentExtension = ({
3131
[ATTACHMENT_NODE_TYPE]: createDeserializeElement(parseSerializedElement),
3232
}),
3333
},
34-
isElementEqual: (node, another) => {
35-
if (isAttachmentNode(node) && isAttachmentNode(another)) {
36-
// Compare ignoring `uuid`
37-
return node.description === another.description && isEqual(node.file, another.file);
38-
}
39-
return undefined;
40-
},
4134
isRichBlock: isAttachmentNode,
4235
isVoid: isAttachmentNode,
4336
normalizeNode: normalizeRedundantFileAttachmentAttributes,

‎packages/slate-editor/src/extensions/galleries/GalleriesExtension.tsx

-12
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { Extension } from '@prezly/slate-commons';
22
import { createDeserializeElement } from '@prezly/slate-commons';
33
import type { GalleryLayout, GalleryNode, GalleryPadding } from '@prezly/slate-types';
44
import { GALLERY_NODE_TYPE, isGalleryNode } from '@prezly/slate-types';
5-
import { isEqual } from '@technically/lodash';
65
import type { SlateEditor } from '@udecode/plate-common';
76
import React from 'react';
87
import type { RenderElementProps } from 'slate-react';
@@ -62,17 +61,6 @@ export const GalleriesExtension = ({
6261
[GALLERY_NODE_TYPE]: createDeserializeElement(parseSerializedElement),
6362
}),
6463
},
65-
isElementEqual: (node, another) => {
66-
if (isGalleryNode(node) && isGalleryNode(another)) {
67-
return (
68-
node.layout === another.layout &&
69-
node.padding === another.padding &&
70-
node.thumbnail_size === another.thumbnail_size &&
71-
isEqual(node.images, another.images)
72-
);
73-
}
74-
return undefined;
75-
},
7664
isRichBlock: isGalleryNode,
7765
isVoid: isGalleryNode,
7866
normalizeNode: [normalizeInvalidGallery, normalizeRedundantGalleryAttributes],

‎packages/slate-editor/src/extensions/image/ImageExtension.tsx

+1-14
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { createDeserializeElement, EditorCommands } from '@prezly/slate-commons'
33
import type { ImageNode } from '@prezly/slate-types';
44
import { IMAGE_NODE_TYPE, isImageNode } from '@prezly/slate-types';
55
import { toProgressPromise, UploadcareImage } from '@prezly/uploadcare';
6-
import { isEqual, noop } from '@technically/lodash';
6+
import { noop } from '@technically/lodash';
77
import type { SlateEditor } from '@udecode/plate-common';
88
import { isHotkey } from 'is-hotkey';
99
import React from 'react';
@@ -101,19 +101,6 @@ export const ImageExtension = ({
101101
},
102102
}),
103103
},
104-
isElementEqual: (node, another) => {
105-
if (isImageNode(node) && isImageNode(another)) {
106-
return (
107-
node.href === another.href &&
108-
node.layout === another.layout &&
109-
node.align === another.align &&
110-
node.new_tab === another.new_tab &&
111-
node.width === another.width &&
112-
isEqual(node.file, another.file)
113-
);
114-
}
115-
return undefined;
116-
},
117104
isRichBlock: isImageNode,
118105
isVoid: (node) => {
119106
if (isImageNode(node)) {

‎packages/slate-editor/src/extensions/inline-contacts/InlineContactsExtension.tsx

-12
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Extension } from '@prezly/slate-commons';
22
import { createDeserializeElement } from '@prezly/slate-commons';
33
import { CONTACT_NODE_TYPE, isContactNode } from '@prezly/slate-types';
4-
import { isEqual } from '@technically/lodash';
54
import React from 'react';
65

76
import { composeElementDeserializer } from '#modules/html-deserialization';
@@ -24,17 +23,6 @@ export function InlineContactsExtension(): Extension {
2423
[CONTACT_NODE_TYPE]: createDeserializeElement(parseSerializedElement),
2524
}),
2625
},
27-
isElementEqual(element, another) {
28-
if (isContactNode(element) && isContactNode(another)) {
29-
// If these are contact references, then ContactInfo object is irrelevant
30-
if (element.reference || another.reference) {
31-
return element.reference === another.reference;
32-
}
33-
// Otherwise, compare ContactInfo ignoring node `uuid` and `reference`
34-
return isEqual(element.contact, another.contact);
35-
}
36-
return undefined;
37-
},
3826
isRichBlock: isContactNode,
3927
isVoid: isContactNode,
4028
normalizeNode: [normalizeContactNodeAttributes, normalizeContactInfoAttributes],

‎packages/slate-editor/src/extensions/placeholders/PlaceholdersExtension.tsx

-8
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,6 @@ export function PlaceholdersExtension({
8888
}: Parameters = {}): Extension {
8989
return {
9090
id: EXTENSION_ID,
91-
isElementEqual(element, another) {
92-
if (isPlaceholderNode(element) && isPlaceholderNode(another)) {
93-
// Consider placeholders equal, if they are of the same type
94-
// ignoring `uuid`
95-
return element.type === another.type;
96-
}
97-
return undefined;
98-
},
9991
isRichBlock: PlaceholderNode.isPlaceholderNode,
10092
isVoid: PlaceholderNode.isPlaceholderNode,
10193
normalizeNode: [

‎packages/slate-editor/src/extensions/press-contacts/PressContactsExtension.tsx

-16
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Extension } from '@prezly/slate-commons';
22
import { createDeserializeElement } from '@prezly/slate-commons';
33
import { CONTACT_NODE_TYPE, isContactNode } from '@prezly/slate-types';
4-
import { isEqual } from '@technically/lodash';
54
import React from 'react';
65

76
import { composeElementDeserializer } from '#modules/html-deserialization';
@@ -23,21 +22,6 @@ export const PressContactsExtension = (params: PressContactsExtensionParameters)
2322
[CONTACT_NODE_TYPE]: createDeserializeElement(parseSerializedElement),
2423
}),
2524
},
26-
isElementEqual(element, another) {
27-
if (isContactNode(element) && isContactNode(another)) {
28-
if (element.layout !== another.layout || element.show_avatar !== another.show_avatar) {
29-
return false;
30-
}
31-
32-
// If these are contact references, then ContactInfo object is irrelevant
33-
if (element.reference || another.reference) {
34-
return element.reference === another.reference;
35-
}
36-
// Otherwise, compare ContactInfo ignoring node `uuid` and `reference`
37-
return isEqual(element.contact, another.contact);
38-
}
39-
return undefined;
40-
},
4125
isRichBlock: isContactNode,
4226
isVoid: isContactNode,
4327
normalizeNode: [normalizeContactNodeAttributes, normalizeContactInfoAttributes],

‎packages/slate-editor/src/extensions/story-bookmark/StoryBookmarkExtension.tsx

-11
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,6 @@ export const StoryBookmarkExtension = (params: StoryBookmarkExtensionParameters)
1919
[STORY_BOOKMARK_NODE_TYPE]: createDeserializeElement(parseSerializedElement),
2020
}),
2121
},
22-
isElementEqual: (node, another) => {
23-
if (isStoryBookmarkNode(node) && isStoryBookmarkNode(another)) {
24-
return (
25-
node.story.uuid === another.story.uuid &&
26-
node.show_thumbnail === another.show_thumbnail &&
27-
node.new_tab === another.new_tab &&
28-
node.layout === another.layout
29-
);
30-
}
31-
return undefined;
32-
},
3322
isRichBlock: isStoryBookmarkNode,
3423
isVoid: isStoryBookmarkNode,
3524
normalizeNode: normalizeRedundantStoryBookmarkAttributes,

‎packages/slate-editor/src/extensions/story-embed/StoryEmbedExtension.tsx

-11
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,6 @@ export const StoryEmbedExtension = ({ render }: StoryEmbedExtensionParameters):
1919
[STORY_EMBED_NODE_TYPE]: createDeserializeElement(parseSerializedElement),
2020
}),
2121
},
22-
isElementEqual: (node, another) => {
23-
if (isStoryEmbedNode(node) && isStoryEmbedNode(another)) {
24-
return (
25-
node.story.uuid === another.story.uuid &&
26-
node.appearance === another.appearance &&
27-
node.position === another.position &&
28-
node.header_footer === another.header_footer
29-
);
30-
}
31-
return undefined;
32-
},
3322
isRichBlock: isStoryEmbedNode,
3423
isVoid: isStoryEmbedNode,
3524
normalizeNode: normalizeRedundantStoryEmbedAttributes,

‎packages/slate-editor/src/extensions/video/VideoExtension.tsx

-11
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { OEmbedInfo } from '@prezly/sdk';
22
import type { Extension } from '@prezly/slate-commons';
33
import { createDeserializeElement } from '@prezly/slate-commons';
44
import { VideoNode } from '@prezly/slate-types';
5-
import { isEqual } from '@technically/lodash';
65
import React from 'react';
76

87
import type { InfoText } from '#components';
@@ -37,16 +36,6 @@ export function VideoExtension({
3736
[VideoNode.TYPE]: createDeserializeElement(parseSerializedElement),
3837
}),
3938
},
40-
isElementEqual: (node, another) => {
41-
if (VideoNode.isVideoNode(node) && VideoNode.isVideoNode(another)) {
42-
return (
43-
node.url === another.url &&
44-
node.layout === another.layout &&
45-
isEqual(node.oembed, another.oembed)
46-
);
47-
}
48-
return undefined;
49-
},
5039
isRichBlock: VideoNode.isVideoNode,
5140
isVoid: VideoNode.isVideoNode,
5241
normalizeNode: normalizeRedundantVideoAttributes,

‎packages/slate-editor/src/extensions/web-bookmark/WebBookmarkExtension.tsx

-14
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { Extension } from '@prezly/slate-commons';
22
import { createDeserializeElement } from '@prezly/slate-commons';
33
import { BookmarkNode } from '@prezly/slate-types';
4-
import { isEqual } from '@technically/lodash';
54
import React from 'react';
65
import type { RenderElementProps } from 'slate-react';
76

@@ -28,19 +27,6 @@ export const WebBookmarkExtension = ({
2827
[BookmarkNode.TYPE]: createDeserializeElement(parseSerializedElement),
2928
}),
3029
},
31-
isElementEqual: (node, another) => {
32-
if (BookmarkNode.isBookmarkNode(node) && BookmarkNode.isBookmarkNode(another)) {
33-
// Compare ignoring `uuid` and `children`
34-
return (
35-
node.url === another.url &&
36-
node.show_thumbnail === another.show_thumbnail &&
37-
node.layout === another.layout &&
38-
node.new_tab === another.new_tab &&
39-
isEqual(node.oembed, another.oembed)
40-
);
41-
}
42-
return undefined;
43-
},
4430
isRichBlock: BookmarkNode.isBookmarkNode,
4531
isVoid: BookmarkNode.isBookmarkNode,
4632
normalizeNode: [unsetUnknownAttributes, normalizeUrlAttribute, fixUuidCollisions],

‎packages/slate-editor/src/modules/editor/createEditor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export function createEditor(
4040
withUserFriendlyDeleteBehavior,
4141
withDeserializeHtml(getExtensions),
4242
withRichBlocks(getExtensions),
43-
withElementsEqualityCheck(getExtensions),
43+
withElementsEqualityCheck,
4444
...overrides,
4545
])(baseEditor);
4646
}

‎packages/slate-editor/src/modules/editor/lib/isEditorValueEqual.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { isEqual } from '@technically/lodash';
2-
import { isVoid, type SlateEditor } from '@udecode/plate-common';
2+
import { type SlateEditor } from '@udecode/plate-common';
33
import type { Element, Text, Descendant } from 'slate';
44

5+
import type { ElementsEqualityCheckEditor } from '../plugins';
6+
57
export function isEditorValueEqual<T extends Descendant>(
6-
editor: SlateEditor,
8+
editor: SlateEditor & ElementsEqualityCheckEditor,
79
a: T[],
810
b: T[],
911
): boolean {
@@ -18,7 +20,7 @@ export function isEditorValueEqual<T extends Descendant>(
1820
if (!isNodeText && !isAnotherText) {
1921
const equal = editor.isElementEqual(node as Element, another as Element);
2022
if (typeof equal !== 'undefined') {
21-
if (isVoid(editor, node) || isVoid(editor, another)) {
23+
if (editor.isVoid(node) || editor.isVoid(another)) {
2224
// Do not compare void elements children
2325
return equal;
2426
}
@@ -49,14 +51,17 @@ function isText(node: Descendant): node is Text {
4951
// CACHE
5052

5153
const CACHE: WeakMap<
52-
SlateEditor,
54+
ElementsEqualityCheckEditor,
5355
WeakMap<Descendant, WeakMap<Descendant, boolean>>
5456
> = new WeakMap();
5557

56-
type WeakMatrix = WeakMap<SlateEditor, WeakMap<Descendant, WeakMap<Descendant, boolean>>>;
58+
type WeakMatrix = WeakMap<
59+
ElementsEqualityCheckEditor,
60+
WeakMap<Descendant, WeakMap<Descendant, boolean>>
61+
>;
5762
type NodesComparator = (node: Descendant, another: Descendant) => boolean;
5863

59-
function cached(editor: SlateEditor, fn: NodesComparator): NodesComparator {
64+
function cached(editor: ElementsEqualityCheckEditor, fn: NodesComparator): NodesComparator {
6065
return (node, another) => {
6166
const cached = get(CACHE, editor, node, another) ?? get(CACHE, editor, another, node);
6267

@@ -75,7 +80,7 @@ function cached(editor: SlateEditor, fn: NodesComparator): NodesComparator {
7580

7681
function get(
7782
matrix: WeakMatrix,
78-
editor: SlateEditor,
83+
editor: ElementsEqualityCheckEditor,
7984
node: Descendant,
8085
another: Descendant,
8186
): boolean | undefined {
@@ -84,7 +89,7 @@ function get(
8489

8590
function set(
8691
matrix: WeakMatrix,
87-
editor: SlateEditor,
92+
editor: ElementsEqualityCheckEditor,
8893
node: Descendant,
8994
another: Descendant,
9095
value: boolean,
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,21 @@
1-
import type { Extension } from '@prezly/slate-commons';
1+
import {
2+
BookmarkNode,
3+
isAttachmentNode,
4+
isContactNode,
5+
isCoverageNode,
6+
isGalleryNode,
7+
isImageNode,
8+
isStoryBookmarkNode,
9+
isStoryEmbedNode,
10+
VideoNode,
11+
} from '@prezly/slate-types';
12+
import { isEqual } from '@technically/lodash';
213
import type { SlateEditor } from '@udecode/plate-common';
314
import type { Element } from 'slate';
415

16+
import { EmbedNode } from '#extensions/embed';
17+
import { PlaceholderNode } from '#extensions/placeholders';
18+
519
export interface ElementsEqualityCheckEditor {
620
/**
721
* Compare two elements.
@@ -15,20 +29,100 @@ export interface ElementsEqualityCheckEditor {
1529
isElementEqual(node: Element, another: Element): boolean | undefined;
1630
}
1731

18-
export function withElementsEqualityCheck(getExtensions: () => Extension[]) {
19-
return function <T extends SlateEditor>(editor: T): T & ElementsEqualityCheckEditor {
20-
function isElementEqual(node: Element, another: Element): boolean | undefined {
21-
for (const extension of getExtensions()) {
22-
const ret = extension.isElementEqual?.(node, another);
23-
if (typeof ret !== 'undefined') {
24-
return ret;
25-
}
26-
}
27-
return undefined;
32+
export function withElementsEqualityCheck<T extends SlateEditor>(
33+
editor: T,
34+
): T & ElementsEqualityCheckEditor {
35+
return Object.assign(editor, {
36+
isElementEqual,
37+
});
38+
}
39+
40+
function isElementEqual(node: Element, another: Element): boolean | undefined {
41+
if (isAttachmentNode(node) && isAttachmentNode(another)) {
42+
// Compare ignoring `uuid`
43+
return node.description === another.description && isEqual(node.file, another.file);
44+
}
45+
if (BookmarkNode.isBookmarkNode(node) && BookmarkNode.isBookmarkNode(another)) {
46+
// Compare ignoring `uuid` and `children`
47+
return (
48+
node.url === another.url &&
49+
node.show_thumbnail === another.show_thumbnail &&
50+
node.layout === another.layout &&
51+
node.new_tab === another.new_tab &&
52+
isEqual(node.oembed, another.oembed)
53+
);
54+
}
55+
if (isContactNode(node) && isContactNode(another)) {
56+
if (node.layout !== another.layout || node.show_avatar !== another.show_avatar) {
57+
return false;
58+
}
59+
// If these are contact references, then ContactInfo object is irrelevant
60+
if (node.reference || another.reference) {
61+
return node.reference === another.reference;
2862
}
63+
// Otherwise, compare ContactInfo ignoring node `uuid` and `reference`
64+
return isEqual(node.contact, another.contact);
65+
}
66+
if (isCoverageNode(node) && isCoverageNode(another)) {
67+
return (
68+
node.coverage.id === another.coverage.id &&
69+
node.layout === another.layout &&
70+
node.new_tab === another.new_tab &&
71+
node.show_thumbnail === another.show_thumbnail
72+
);
73+
}
74+
if (EmbedNode.isEmbedNode(node) && EmbedNode.isEmbedNode(another)) {
75+
return (
76+
node.url === another.url &&
77+
node.layout === another.layout &&
78+
isEqual(node.oembed, another.oembed)
79+
);
80+
}
81+
if (isGalleryNode(node) && isGalleryNode(another)) {
82+
return (
83+
node.layout === another.layout &&
84+
node.padding === another.padding &&
85+
node.thumbnail_size === another.thumbnail_size &&
86+
isEqual(node.images, another.images)
87+
);
88+
}
89+
if (isImageNode(node) && isImageNode(another)) {
90+
return (
91+
node.href === another.href &&
92+
node.layout === another.layout &&
93+
node.align === another.align &&
94+
node.new_tab === another.new_tab &&
95+
node.width === another.width &&
96+
isEqual(node.file, another.file)
97+
);
98+
}
99+
if (PlaceholderNode.isPlaceholderNode(node) && PlaceholderNode.isPlaceholderNode(another)) {
100+
// Consider placeholders equal, if they are of the same type ignoring `uuid`
101+
return node.type === another.type;
102+
}
103+
if (isStoryBookmarkNode(node) && isStoryBookmarkNode(another)) {
104+
return (
105+
node.story.uuid === another.story.uuid &&
106+
node.show_thumbnail === another.show_thumbnail &&
107+
node.new_tab === another.new_tab &&
108+
node.layout === another.layout
109+
);
110+
}
111+
if (isStoryEmbedNode(node) && isStoryEmbedNode(another)) {
112+
return (
113+
node.story.uuid === another.story.uuid &&
114+
node.appearance === another.appearance &&
115+
node.position === another.position &&
116+
node.header_footer === another.header_footer
117+
);
118+
}
119+
if (VideoNode.isVideoNode(node) && VideoNode.isVideoNode(another)) {
120+
return (
121+
node.url === another.url &&
122+
node.layout === another.layout &&
123+
isEqual(node.oembed, another.oembed)
124+
);
125+
}
29126

30-
return Object.assign(editor, {
31-
isElementEqual,
32-
});
33-
};
127+
return undefined;
34128
}

0 commit comments

Comments
 (0)
Please sign in to comment.