mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-12 10:14:02 +02:00
Optimize isText
, isElement
, isNodeList
and isEditor
(#5859)
* Remove the `isPlainObject` check from `isText` and `isElement` for performance * Optimise `isElement`, `isNodeList` and `isText` further * Update changeset * Fix changeset * Refactor object check into `isObject`
This commit is contained in:
8
.changeset/tough-pianos-train.md
Normal file
8
.changeset/tough-pianos-train.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
'slate': patch
|
||||||
|
'slate-history': patch
|
||||||
|
'slate-hyperscript': patch
|
||||||
|
'slate-react': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Optimize `isElement`, `isText`, `isNodeList` and `isEditor` by removing dependency on `is-plain-object` and by performing shallow checks by default. To perform a full check, including all descendants, pass the `{ deep: true }` option to `isElement`, `isNodeList` or `isEditor`.
|
@@ -13,9 +13,6 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"dist/"
|
"dist/"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
|
||||||
"is-plain-object": "^5.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/runtime": "^7.23.2",
|
"@babel/runtime": "^7.23.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import { isPlainObject } from 'is-plain-object'
|
import { Operation, Range, isObject } from 'slate'
|
||||||
import { Operation, Range } from 'slate'
|
|
||||||
|
|
||||||
interface Batch {
|
interface Batch {
|
||||||
operations: Operation[]
|
operations: Operation[]
|
||||||
@@ -24,7 +23,7 @@ export const History = {
|
|||||||
|
|
||||||
isHistory(value: any): value is History {
|
isHistory(value: any): value is History {
|
||||||
return (
|
return (
|
||||||
isPlainObject(value) &&
|
isObject(value) &&
|
||||||
Array.isArray(value.redos) &&
|
Array.isArray(value.redos) &&
|
||||||
Array.isArray(value.undos) &&
|
Array.isArray(value.undos) &&
|
||||||
(value.redos.length === 0 ||
|
(value.redos.length === 0 ||
|
||||||
|
@@ -13,9 +13,6 @@
|
|||||||
"files": [
|
"files": [
|
||||||
"dist/"
|
"dist/"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
|
||||||
"is-plain-object": "^5.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/runtime": "^7.23.2",
|
"@babel/runtime": "^7.23.2",
|
||||||
"slate": "^0.114.0",
|
"slate": "^0.114.0",
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import { isPlainObject } from 'is-plain-object'
|
import { Element, createEditor as makeEditor, isObject } from 'slate'
|
||||||
import { Element, createEditor as makeEditor } from 'slate'
|
|
||||||
import {
|
import {
|
||||||
createAnchor,
|
createAnchor,
|
||||||
createCursor,
|
createCursor,
|
||||||
@@ -86,7 +85,7 @@ const createFactory = <T extends HyperscriptCreators>(creators: T) => {
|
|||||||
attributes = {}
|
attributes = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isPlainObject(attributes)) {
|
if (!isObject(attributes)) {
|
||||||
children = [attributes].concat(children)
|
children = [attributes].concat(children)
|
||||||
attributes = {}
|
attributes = {}
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@
|
|||||||
"@juggle/resize-observer": "^3.4.0",
|
"@juggle/resize-observer": "^3.4.0",
|
||||||
"direction": "^1.0.4",
|
"direction": "^1.0.4",
|
||||||
"is-hotkey": "^0.2.0",
|
"is-hotkey": "^0.2.0",
|
||||||
"is-plain-object": "^5.0.0",
|
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"scroll-into-view-if-needed": "^3.1.0",
|
"scroll-into-view-if-needed": "^3.1.0",
|
||||||
"tiny-invariant": "1.3.1"
|
"tiny-invariant": "1.3.1"
|
||||||
|
@@ -15,7 +15,6 @@
|
|||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"immer": "^10.0.3",
|
"immer": "^10.0.3",
|
||||||
"is-plain-object": "^5.0.0",
|
|
||||||
"tiny-warning": "^1.0.3"
|
"tiny-warning": "^1.0.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@@ -1,20 +1,14 @@
|
|||||||
import { Editor, EditorInterface } from '../interfaces/editor'
|
import { Editor, EditorInterface } from '../interfaces/editor'
|
||||||
import { isPlainObject } from 'is-plain-object'
|
|
||||||
import { Range } from '../interfaces/range'
|
import { Range } from '../interfaces/range'
|
||||||
import { Node } from '../interfaces/node'
|
import { Node } from '../interfaces/node'
|
||||||
import { Operation } from '../interfaces/operation'
|
import { Operation } from '../interfaces/operation'
|
||||||
|
import { isObject } from '../utils'
|
||||||
const IS_EDITOR_CACHE = new WeakMap<object, boolean>()
|
|
||||||
|
|
||||||
export const isEditor: EditorInterface['isEditor'] = (
|
export const isEditor: EditorInterface['isEditor'] = (
|
||||||
value: any
|
value: any,
|
||||||
|
{ deep = false } = {}
|
||||||
): value is Editor => {
|
): value is Editor => {
|
||||||
const cachedIsEditor = IS_EDITOR_CACHE.get(value)
|
if (!isObject(value)) {
|
||||||
if (cachedIsEditor !== undefined) {
|
|
||||||
return cachedIsEditor
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isPlainObject(value)) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,10 +29,10 @@ export const isEditor: EditorInterface['isEditor'] = (
|
|||||||
typeof value.onChange === 'function' &&
|
typeof value.onChange === 'function' &&
|
||||||
typeof value.removeMark === 'function' &&
|
typeof value.removeMark === 'function' &&
|
||||||
typeof value.getDirtyPaths === 'function' &&
|
typeof value.getDirtyPaths === 'function' &&
|
||||||
(value.marks === null || isPlainObject(value.marks)) &&
|
(value.marks === null || isObject(value.marks)) &&
|
||||||
(value.selection === null || Range.isRange(value.selection)) &&
|
(value.selection === null || Range.isRange(value.selection)) &&
|
||||||
Node.isNodeList(value.children) &&
|
(!deep || Node.isNodeList(value.children)) &&
|
||||||
Operation.isOperationList(value.operations)
|
Operation.isOperationList(value.operations)
|
||||||
IS_EDITOR_CACHE.set(value, isEditor)
|
|
||||||
return isEditor
|
return isEditor
|
||||||
}
|
}
|
||||||
|
@@ -6,3 +6,4 @@ export * from './transforms-node'
|
|||||||
export * from './transforms-selection'
|
export * from './transforms-selection'
|
||||||
export * from './transforms-text'
|
export * from './transforms-text'
|
||||||
export * from './types'
|
export * from './types'
|
||||||
|
export * from './utils/is-object'
|
||||||
|
@@ -213,6 +213,10 @@ export interface EditorFragmentDeletionOptions {
|
|||||||
direction?: TextDirection
|
direction?: TextDirection
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface EditorIsEditorOptions {
|
||||||
|
deep?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export interface EditorLeafOptions {
|
export interface EditorLeafOptions {
|
||||||
depth?: number
|
depth?: number
|
||||||
edge?: LeafEdge
|
edge?: LeafEdge
|
||||||
@@ -469,7 +473,7 @@ export interface EditorInterface {
|
|||||||
/**
|
/**
|
||||||
* Check if a value is an `Editor` object.
|
* Check if a value is an `Editor` object.
|
||||||
*/
|
*/
|
||||||
isEditor: (value: any) => value is Editor
|
isEditor: (value: any, options?: EditorIsEditorOptions) => value is Editor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a value is a read-only `Element` object.
|
* Check if a value is a read-only `Element` object.
|
||||||
|
@@ -1,5 +1,12 @@
|
|||||||
import { isPlainObject } from 'is-plain-object'
|
import {
|
||||||
import { Ancestor, Descendant, Editor, ExtendedType, Node, Path } from '..'
|
Ancestor,
|
||||||
|
Descendant,
|
||||||
|
Editor,
|
||||||
|
ExtendedType,
|
||||||
|
Node,
|
||||||
|
Path,
|
||||||
|
isObject,
|
||||||
|
} from '..'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* `Element` objects are a type of node in a Slate document that contain other
|
* `Element` objects are a type of node in a Slate document that contain other
|
||||||
@@ -13,21 +20,31 @@ export interface BaseElement {
|
|||||||
|
|
||||||
export type Element = ExtendedType<'Element', BaseElement>
|
export type Element = ExtendedType<'Element', BaseElement>
|
||||||
|
|
||||||
|
export interface ElementIsElementOptions {
|
||||||
|
deep?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export interface ElementInterface {
|
export interface ElementInterface {
|
||||||
/**
|
/**
|
||||||
* Check if a value implements the 'Ancestor' interface.
|
* Check if a value implements the 'Ancestor' interface.
|
||||||
*/
|
*/
|
||||||
isAncestor: (value: any) => value is Ancestor
|
isAncestor: (
|
||||||
|
value: any,
|
||||||
|
options?: ElementIsElementOptions
|
||||||
|
) => value is Ancestor
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a value implements the `Element` interface.
|
* Check if a value implements the `Element` interface.
|
||||||
*/
|
*/
|
||||||
isElement: (value: any) => value is Element
|
isElement: (value: any, options?: ElementIsElementOptions) => value is Element
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a value is an array of `Element` objects.
|
* Check if a value is an array of `Element` objects.
|
||||||
*/
|
*/
|
||||||
isElementList: (value: any) => value is Element[]
|
isElementList: (
|
||||||
|
value: any,
|
||||||
|
options?: ElementIsElementOptions
|
||||||
|
) => value is Element[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a set of props is a partial of Element.
|
* Check if a set of props is a partial of Element.
|
||||||
@@ -56,24 +73,42 @@ export interface ElementInterface {
|
|||||||
/**
|
/**
|
||||||
* Shared the function with isElementType utility
|
* Shared the function with isElementType utility
|
||||||
*/
|
*/
|
||||||
const isElement = (value: any): value is Element => {
|
const isElement = (
|
||||||
return (
|
value: any,
|
||||||
isPlainObject(value) &&
|
{ deep = false }: ElementIsElementOptions = {}
|
||||||
Node.isNodeList(value.children) &&
|
): value is Element => {
|
||||||
!Editor.isEditor(value)
|
if (!isObject(value)) return false
|
||||||
)
|
|
||||||
|
// PERF: No need to use the full Editor.isEditor here
|
||||||
|
const isEditor = typeof value.apply === 'function'
|
||||||
|
if (isEditor) return false
|
||||||
|
|
||||||
|
const isChildrenValid = deep
|
||||||
|
? Node.isNodeList(value.children)
|
||||||
|
: Array.isArray(value.children)
|
||||||
|
|
||||||
|
return isChildrenValid
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-redeclare
|
// eslint-disable-next-line no-redeclare
|
||||||
export const Element: ElementInterface = {
|
export const Element: ElementInterface = {
|
||||||
isAncestor(value: any): value is Ancestor {
|
isAncestor(
|
||||||
return isPlainObject(value) && Node.isNodeList(value.children)
|
value: any,
|
||||||
|
{ deep = false }: ElementIsElementOptions = {}
|
||||||
|
): value is Ancestor {
|
||||||
|
return isObject(value) && Node.isNodeList(value.children, { deep })
|
||||||
},
|
},
|
||||||
|
|
||||||
isElement,
|
isElement,
|
||||||
|
|
||||||
isElementList(value: any): value is Element[] {
|
isElementList(
|
||||||
return Array.isArray(value) && value.every(val => Element.isElement(val))
|
value: any,
|
||||||
|
{ deep = false }: ElementIsElementOptions = {}
|
||||||
|
): value is Element[] {
|
||||||
|
return (
|
||||||
|
Array.isArray(value) &&
|
||||||
|
value.every(val => Element.isElement(val, { deep }))
|
||||||
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
isElementProps(props: any): props is Partial<Element> {
|
isElementProps(props: any): props is Partial<Element> {
|
||||||
|
@@ -32,6 +32,10 @@ export interface NodeElementsOptions {
|
|||||||
pass?: (node: NodeEntry) => boolean
|
pass?: (node: NodeEntry) => boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface NodeIsNodeOptions {
|
||||||
|
deep?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export interface NodeLevelsOptions {
|
export interface NodeLevelsOptions {
|
||||||
reverse?: boolean
|
reverse?: boolean
|
||||||
}
|
}
|
||||||
@@ -144,12 +148,12 @@ export interface NodeInterface {
|
|||||||
/**
|
/**
|
||||||
* Check if a value implements the `Node` interface.
|
* Check if a value implements the `Node` interface.
|
||||||
*/
|
*/
|
||||||
isNode: (value: any) => value is Node
|
isNode: (value: any, options?: NodeIsNodeOptions) => value is Node
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if a value is a list of `Node` objects.
|
* Check if a value is a list of `Node` objects.
|
||||||
*/
|
*/
|
||||||
isNodeList: (value: any) => value is Node[]
|
isNodeList: (value: any, options?: NodeIsNodeOptions) => value is Node[]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the last node entry in a root node from a path.
|
* Get the last node entry in a root node from a path.
|
||||||
@@ -211,8 +215,6 @@ export interface NodeInterface {
|
|||||||
) => Generator<NodeEntry<Text>, void, undefined>
|
) => Generator<NodeEntry<Text>, void, undefined>
|
||||||
}
|
}
|
||||||
|
|
||||||
const IS_NODE_LIST_CACHE = new WeakMap<any[], boolean>()
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-redeclare
|
// eslint-disable-next-line no-redeclare
|
||||||
export const Node: NodeInterface = {
|
export const Node: NodeInterface = {
|
||||||
ancestor(root: Node, path: Path): Ancestor {
|
ancestor(root: Node, path: Path): Ancestor {
|
||||||
@@ -437,23 +439,21 @@ export const Node: NodeInterface = {
|
|||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|
||||||
isNode(value: any): value is Node {
|
isNode(value: any, { deep = false }: NodeIsNodeOptions = {}): value is Node {
|
||||||
return (
|
return (
|
||||||
Text.isText(value) || Element.isElement(value) || Editor.isEditor(value)
|
Text.isText(value) ||
|
||||||
|
Element.isElement(value, { deep }) ||
|
||||||
|
Editor.isEditor(value, { deep })
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
|
||||||
isNodeList(value: any): value is Node[] {
|
isNodeList(
|
||||||
if (!Array.isArray(value)) {
|
value: any,
|
||||||
return false
|
{ deep = false }: NodeIsNodeOptions = {}
|
||||||
}
|
): value is Node[] {
|
||||||
const cachedResult = IS_NODE_LIST_CACHE.get(value)
|
return (
|
||||||
if (cachedResult !== undefined) {
|
Array.isArray(value) && value.every(val => Node.isNode(val, { deep }))
|
||||||
return cachedResult
|
)
|
||||||
}
|
|
||||||
const isNodeList = value.every(val => Node.isNode(val))
|
|
||||||
IS_NODE_LIST_CACHE.set(value, isNodeList)
|
|
||||||
return isNodeList
|
|
||||||
},
|
},
|
||||||
|
|
||||||
last(root: Node, path: Path): NodeEntry {
|
last(root: Node, path: Path): NodeEntry {
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import { ExtendedType, Node, Path, Range } from '..'
|
import { ExtendedType, Node, Path, Range, isObject } from '..'
|
||||||
import { isPlainObject } from 'is-plain-object'
|
|
||||||
|
|
||||||
export type BaseInsertNodeOperation = {
|
export type BaseInsertNodeOperation = {
|
||||||
type: 'insert_node'
|
type: 'insert_node'
|
||||||
@@ -178,7 +177,7 @@ export const Operation: OperationInterface = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
isOperation(value: any): value is Operation {
|
isOperation(value: any): value is Operation {
|
||||||
if (!isPlainObject(value)) {
|
if (!isObject(value)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +194,7 @@ export const Operation: OperationInterface = {
|
|||||||
return (
|
return (
|
||||||
typeof value.position === 'number' &&
|
typeof value.position === 'number' &&
|
||||||
Path.isPath(value.path) &&
|
Path.isPath(value.path) &&
|
||||||
isPlainObject(value.properties)
|
isObject(value.properties)
|
||||||
)
|
)
|
||||||
case 'move_node':
|
case 'move_node':
|
||||||
return Path.isPath(value.path) && Path.isPath(value.newPath)
|
return Path.isPath(value.path) && Path.isPath(value.newPath)
|
||||||
@@ -210,21 +209,20 @@ export const Operation: OperationInterface = {
|
|||||||
case 'set_node':
|
case 'set_node':
|
||||||
return (
|
return (
|
||||||
Path.isPath(value.path) &&
|
Path.isPath(value.path) &&
|
||||||
isPlainObject(value.properties) &&
|
isObject(value.properties) &&
|
||||||
isPlainObject(value.newProperties)
|
isObject(value.newProperties)
|
||||||
)
|
)
|
||||||
case 'set_selection':
|
case 'set_selection':
|
||||||
return (
|
return (
|
||||||
(value.properties === null && Range.isRange(value.newProperties)) ||
|
(value.properties === null && Range.isRange(value.newProperties)) ||
|
||||||
(value.newProperties === null && Range.isRange(value.properties)) ||
|
(value.newProperties === null && Range.isRange(value.properties)) ||
|
||||||
(isPlainObject(value.properties) &&
|
(isObject(value.properties) && isObject(value.newProperties))
|
||||||
isPlainObject(value.newProperties))
|
|
||||||
)
|
)
|
||||||
case 'split_node':
|
case 'split_node':
|
||||||
return (
|
return (
|
||||||
Path.isPath(value.path) &&
|
Path.isPath(value.path) &&
|
||||||
typeof value.position === 'number' &&
|
typeof value.position === 'number' &&
|
||||||
isPlainObject(value.properties)
|
isObject(value.properties)
|
||||||
)
|
)
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { isPlainObject } from 'is-plain-object'
|
|
||||||
import { produce } from 'immer'
|
import { produce } from 'immer'
|
||||||
import { ExtendedType, Operation, Path } from '..'
|
import { ExtendedType, Operation, Path, isObject } from '..'
|
||||||
import { TextDirection } from '../types/types'
|
import { TextDirection } from '../types/types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,7 +88,7 @@ export const Point: PointInterface = {
|
|||||||
|
|
||||||
isPoint(value: any): value is Point {
|
isPoint(value: any): value is Point {
|
||||||
return (
|
return (
|
||||||
isPlainObject(value) &&
|
isObject(value) &&
|
||||||
typeof value.offset === 'number' &&
|
typeof value.offset === 'number' &&
|
||||||
Path.isPath(value.path)
|
Path.isPath(value.path)
|
||||||
)
|
)
|
||||||
|
@@ -1,6 +1,5 @@
|
|||||||
import { produce } from 'immer'
|
import { produce } from 'immer'
|
||||||
import { isPlainObject } from 'is-plain-object'
|
import { ExtendedType, Operation, Path, Point, PointEntry, isObject } from '..'
|
||||||
import { ExtendedType, Operation, Path, Point, PointEntry } from '..'
|
|
||||||
import { RangeDirection } from '../types/types'
|
import { RangeDirection } from '../types/types'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -200,7 +199,7 @@ export const Range: RangeInterface = {
|
|||||||
|
|
||||||
isRange(value: any): value is Range {
|
isRange(value: any): value is Range {
|
||||||
return (
|
return (
|
||||||
isPlainObject(value) &&
|
isObject(value) &&
|
||||||
Point.isPoint(value.anchor) &&
|
Point.isPoint(value.anchor) &&
|
||||||
Point.isPoint(value.focus)
|
Point.isPoint(value.focus)
|
||||||
)
|
)
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
import { isPlainObject } from 'is-plain-object'
|
import { Range, isObject } from '..'
|
||||||
import { Path, Range } from '..'
|
|
||||||
import { ExtendedType } from '../types/custom-types'
|
import { ExtendedType } from '../types/custom-types'
|
||||||
import { isDeepEqual } from '../utils/deep-equal'
|
import { isDeepEqual } from '../utils/deep-equal'
|
||||||
|
|
||||||
@@ -93,7 +92,7 @@ export const Text: TextInterface = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
isText(value: any): value is Text {
|
isText(value: any): value is Text {
|
||||||
return isPlainObject(value) && typeof value.text === 'string'
|
return isObject(value) && typeof value.text === 'string'
|
||||||
},
|
},
|
||||||
|
|
||||||
isTextList(value: any): value is Text[] {
|
isTextList(value: any): value is Text[] {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
import { isPlainObject } from 'is-plain-object'
|
import { isObject } from './is-object'
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Custom deep equal comparison for Slate nodes.
|
Custom deep equal comparison for Slate nodes.
|
||||||
@@ -17,13 +17,13 @@ export const isDeepEqual = (
|
|||||||
for (const key in node) {
|
for (const key in node) {
|
||||||
const a = node[key]
|
const a = node[key]
|
||||||
const b = another[key]
|
const b = another[key]
|
||||||
if (isPlainObject(a) && isPlainObject(b)) {
|
if (Array.isArray(a) && Array.isArray(b)) {
|
||||||
if (!isDeepEqual(a, b)) return false
|
|
||||||
} else if (Array.isArray(a) && Array.isArray(b)) {
|
|
||||||
if (a.length !== b.length) return false
|
if (a.length !== b.length) return false
|
||||||
for (let i = 0; i < a.length; i++) {
|
for (let i = 0; i < a.length; i++) {
|
||||||
if (a[i] !== b[i]) return false
|
if (a[i] !== b[i]) return false
|
||||||
}
|
}
|
||||||
|
} else if (isObject(a) && isObject(b)) {
|
||||||
|
if (!isDeepEqual(a, b)) return false
|
||||||
} else if (a !== b) {
|
} else if (a !== b) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
export * from './deep-equal'
|
export * from './deep-equal'
|
||||||
export * from './get-default-insert-location'
|
export * from './get-default-insert-location'
|
||||||
|
export * from './is-object'
|
||||||
export * from './match-path'
|
export * from './match-path'
|
||||||
export * from './string'
|
export * from './string'
|
||||||
export * from './types'
|
export * from './types'
|
||||||
|
2
packages/slate/src/utils/is-object.ts
Normal file
2
packages/slate/src/utils/is-object.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
export const isObject = (value: any) =>
|
||||||
|
typeof value === 'object' && value !== null
|
@@ -13302,7 +13302,6 @@ __metadata:
|
|||||||
resolution: "slate-history@workspace:packages/slate-history"
|
resolution: "slate-history@workspace:packages/slate-history"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.23.2"
|
"@babel/runtime": "npm:^7.23.2"
|
||||||
is-plain-object: "npm:^5.0.0"
|
|
||||||
lodash: "npm:^4.17.21"
|
lodash: "npm:^4.17.21"
|
||||||
slate: "npm:^0.114.0"
|
slate: "npm:^0.114.0"
|
||||||
slate-hyperscript: "npm:^0.100.0"
|
slate-hyperscript: "npm:^0.100.0"
|
||||||
@@ -13317,7 +13316,6 @@ __metadata:
|
|||||||
resolution: "slate-hyperscript@workspace:packages/slate-hyperscript"
|
resolution: "slate-hyperscript@workspace:packages/slate-hyperscript"
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.23.2"
|
"@babel/runtime": "npm:^7.23.2"
|
||||||
is-plain-object: "npm:^5.0.0"
|
|
||||||
slate: "npm:^0.114.0"
|
slate: "npm:^0.114.0"
|
||||||
source-map-loader: "npm:^4.0.1"
|
source-map-loader: "npm:^4.0.1"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -13427,7 +13425,6 @@ __metadata:
|
|||||||
"@types/resize-observer-browser": "npm:^0.1.8"
|
"@types/resize-observer-browser": "npm:^0.1.8"
|
||||||
direction: "npm:^1.0.4"
|
direction: "npm:^1.0.4"
|
||||||
is-hotkey: "npm:^0.2.0"
|
is-hotkey: "npm:^0.2.0"
|
||||||
is-plain-object: "npm:^5.0.0"
|
|
||||||
lodash: "npm:^4.17.21"
|
lodash: "npm:^4.17.21"
|
||||||
react: "npm:^18.2.0"
|
react: "npm:^18.2.0"
|
||||||
react-dom: "npm:^18.2.0"
|
react-dom: "npm:^18.2.0"
|
||||||
@@ -13451,7 +13448,6 @@ __metadata:
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/runtime": "npm:^7.23.2"
|
"@babel/runtime": "npm:^7.23.2"
|
||||||
immer: "npm:^10.0.3"
|
immer: "npm:^10.0.3"
|
||||||
is-plain-object: "npm:^5.0.0"
|
|
||||||
lodash: "npm:^4.17.21"
|
lodash: "npm:^4.17.21"
|
||||||
slate-hyperscript: "npm:^0.100.0"
|
slate-hyperscript: "npm:^0.100.0"
|
||||||
source-map-loader: "npm:^4.0.1"
|
source-map-loader: "npm:^4.0.1"
|
||||||
|
Reference in New Issue
Block a user