@portabletext/editor 1.0.1 → 1.0.3
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/README.md +9 -2
- package/lib/index.d.mts +22 -97
- package/lib/index.d.ts +22 -97
- package/lib/index.esm.js +1065 -1377
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +1128 -1430
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +1065 -1377
- package/lib/index.mjs.map +1 -1
- package/package.json +40 -22
- package/src/editor/Editable.tsx +32 -38
- package/src/editor/components/Synchronizer.tsx +1 -1
- package/src/editor/plugins/__tests__/createWithInsertData.test.tsx +166 -0
- package/src/editor/plugins/createWithInsertData.ts +34 -1
- package/src/editor/plugins/createWithPatches.ts +2 -2
- package/src/editor/plugins/createWithUndoRedo.ts +1 -1
- package/src/index.ts +1 -2
- package/src/types/editor.ts +4 -3
- package/src/utils/__tests__/dmpToOperations.test.ts +1 -1
- package/src/utils/applyPatch.ts +8 -8
- package/src/utils/operationToPatches.ts +2 -2
- package/src/utils/validateValue.ts +1 -1
- package/src/patch/PatchEvent.ts +0 -33
- package/src/patch/applyPatch.ts +0 -29
- package/src/patch/array.ts +0 -89
- package/src/patch/arrayInsert.ts +0 -27
- package/src/patch/object.ts +0 -39
- package/src/patch/patches.ts +0 -53
- package/src/patch/primitive.ts +0 -43
- package/src/patch/string.ts +0 -51
- package/src/types/patch.ts +0 -65
- package/src/utils/patches.ts +0 -36
package/src/patch/applyPatch.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import {isObject, isString} from 'lodash'
|
|
2
|
-
|
|
3
|
-
import applyArrayPatch from './array'
|
|
4
|
-
import applyObjectPatch from './object'
|
|
5
|
-
import applyPrimitivePatch from './primitive'
|
|
6
|
-
import applyStringPatch from './string'
|
|
7
|
-
|
|
8
|
-
export function applyAll(value: any, patches: any[]) {
|
|
9
|
-
return patches.reduce(_apply, value)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
function applyPatch(value: string, patch: {type: string; path: any[]; value: any}) {
|
|
13
|
-
if (Array.isArray(value)) {
|
|
14
|
-
return applyArrayPatch(value, patch as any)
|
|
15
|
-
}
|
|
16
|
-
if (isString(value)) {
|
|
17
|
-
return applyStringPatch(value, patch)
|
|
18
|
-
}
|
|
19
|
-
if (isObject(value)) {
|
|
20
|
-
return applyObjectPatch(value, patch)
|
|
21
|
-
}
|
|
22
|
-
return applyPrimitivePatch(value, patch)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export default function _apply(value: string, patch: {type: string; path: any[]; value: any}) {
|
|
26
|
-
const res = applyPatch(value, patch)
|
|
27
|
-
// console.log('applyPatch(%o, %o) : %o (noop? %o)', value, patch, res, value === res)
|
|
28
|
-
return res
|
|
29
|
-
}
|
package/src/patch/array.ts
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import {type PathSegment} from '@sanity/types'
|
|
2
|
-
import {findIndex} from 'lodash'
|
|
3
|
-
|
|
4
|
-
import applyPatch from './applyPatch'
|
|
5
|
-
import insert from './arrayInsert'
|
|
6
|
-
|
|
7
|
-
const hasOwn = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty)
|
|
8
|
-
|
|
9
|
-
function move(arr: any[], from: number, to: any) {
|
|
10
|
-
const nextValue = arr.slice()
|
|
11
|
-
const val = nextValue[from]
|
|
12
|
-
nextValue.splice(from, 1)
|
|
13
|
-
nextValue.splice(to, 0, val)
|
|
14
|
-
return nextValue
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function findTargetIndex(array: any[], pathSegment: PathSegment) {
|
|
18
|
-
if (typeof pathSegment === 'number') {
|
|
19
|
-
return pathSegment
|
|
20
|
-
}
|
|
21
|
-
const index = findIndex(array, pathSegment)
|
|
22
|
-
return index === -1 ? false : index
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export default function apply(
|
|
26
|
-
value: any,
|
|
27
|
-
patch: {type: any; path: any; value: any; position: any; items: any},
|
|
28
|
-
) {
|
|
29
|
-
const nextValue = value.slice() // make a copy for internal mutation
|
|
30
|
-
|
|
31
|
-
if (patch.path.length === 0) {
|
|
32
|
-
// its directed to me
|
|
33
|
-
if (patch.type === 'setIfMissing') {
|
|
34
|
-
if (!Array.isArray(patch.value)) {
|
|
35
|
-
// eslint-disable-line max-depth
|
|
36
|
-
throw new Error('Cannot set value of an array to a non-array')
|
|
37
|
-
}
|
|
38
|
-
return value === undefined ? patch.value : value
|
|
39
|
-
} else if (patch.type === 'set') {
|
|
40
|
-
if (!Array.isArray(patch.value)) {
|
|
41
|
-
// eslint-disable-line max-depth
|
|
42
|
-
throw new Error('Cannot set value of an array to a non-array')
|
|
43
|
-
}
|
|
44
|
-
return patch.value
|
|
45
|
-
} else if (patch.type === 'unset') {
|
|
46
|
-
return undefined
|
|
47
|
-
} else if (patch.type === 'move') {
|
|
48
|
-
if (!patch.value || !hasOwn(patch.value, 'from') || !hasOwn(patch.value, 'to')) {
|
|
49
|
-
// eslint-disable-line max-depth
|
|
50
|
-
throw new Error(
|
|
51
|
-
`Invalid value of 'move' patch. Expected a value with "from" and "to" indexes, instead got: ${JSON.stringify(
|
|
52
|
-
patch.value,
|
|
53
|
-
)}`,
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
return move(nextValue, patch.value.from, patch.value.to)
|
|
57
|
-
}
|
|
58
|
-
throw new Error(`Invalid array operation: ${patch.type}`)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
const [head, ...tail] = patch.path
|
|
62
|
-
|
|
63
|
-
const index = findTargetIndex(value, head)
|
|
64
|
-
|
|
65
|
-
// If the given selector could not be found, return as-is
|
|
66
|
-
if (index === false) {
|
|
67
|
-
return nextValue
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (tail.length === 0) {
|
|
71
|
-
if (patch.type === 'insert') {
|
|
72
|
-
const {position, items} = patch
|
|
73
|
-
return insert(value, position, index, items)
|
|
74
|
-
} else if (patch.type === 'unset') {
|
|
75
|
-
if (typeof index !== 'number') {
|
|
76
|
-
throw new Error(`Expected array index to be a number, instead got "${index}"`)
|
|
77
|
-
}
|
|
78
|
-
nextValue.splice(index, 1)
|
|
79
|
-
return nextValue
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// The patch is not directed to me
|
|
84
|
-
nextValue[index] = applyPatch(nextValue[index], {
|
|
85
|
-
...patch,
|
|
86
|
-
path: tail,
|
|
87
|
-
})
|
|
88
|
-
return nextValue
|
|
89
|
-
}
|
package/src/patch/arrayInsert.ts
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
export const BEFORE = 'before'
|
|
2
|
-
export const AFTER = 'after'
|
|
3
|
-
|
|
4
|
-
export default function insert(array: any[], position: string, index: number, ...args: any[]) {
|
|
5
|
-
if (position !== BEFORE && position !== AFTER) {
|
|
6
|
-
throw new Error(`Invalid position "${position}", must be either ${BEFORE} or ${AFTER}`)
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const items = flatten(...args)
|
|
10
|
-
|
|
11
|
-
if (array.length === 0) {
|
|
12
|
-
return items
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const len = array.length
|
|
16
|
-
const idx = Math.abs((len + index) % len) % len
|
|
17
|
-
|
|
18
|
-
const normalizedIdx = position === 'after' ? idx + 1 : idx
|
|
19
|
-
|
|
20
|
-
const copy = array.slice()
|
|
21
|
-
copy.splice(normalizedIdx, 0, ...flatten(items))
|
|
22
|
-
return copy
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function flatten(...values: any[]) {
|
|
26
|
-
return values.reduce((prev, item) => prev.concat(item), [])
|
|
27
|
-
}
|
package/src/patch/object.ts
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import {clone, isObject, omit} from 'lodash'
|
|
2
|
-
|
|
3
|
-
import applyPatch from './applyPatch'
|
|
4
|
-
|
|
5
|
-
export default function apply(value: any, patch: {type: any; path: any; value: any}) {
|
|
6
|
-
const nextValue = clone(value)
|
|
7
|
-
if (patch.path.length === 0) {
|
|
8
|
-
// its directed to me
|
|
9
|
-
if (patch.type === 'set') {
|
|
10
|
-
if (!isObject(patch.value)) {
|
|
11
|
-
// eslint-disable-line max-depth
|
|
12
|
-
throw new Error('Cannot set value of an object to a non-object')
|
|
13
|
-
}
|
|
14
|
-
return patch.value
|
|
15
|
-
} else if (patch.type === 'unset') {
|
|
16
|
-
return undefined
|
|
17
|
-
} else if (patch.type === 'setIfMissing') {
|
|
18
|
-
// console.log('IS IT missing?', value)
|
|
19
|
-
return value === undefined ? patch.value : value
|
|
20
|
-
}
|
|
21
|
-
throw new Error(`Invalid object operation: ${patch.type}`)
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// The patch is not directed to me
|
|
25
|
-
const [head, ...tail] = patch.path
|
|
26
|
-
if (typeof head !== 'string') {
|
|
27
|
-
throw new Error(`Expected field name to be a string, instad got: ${head}`)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (tail.length === 0 && patch.type === 'unset') {
|
|
31
|
-
return omit(nextValue, head)
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
nextValue[head] = applyPatch(nextValue[head], {
|
|
35
|
-
...patch,
|
|
36
|
-
path: tail,
|
|
37
|
-
})
|
|
38
|
-
return nextValue
|
|
39
|
-
}
|
package/src/patch/patches.ts
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import {makePatches, stringifyPatches} from '@sanity/diff-match-patch'
|
|
2
|
-
import {type Path, type PathSegment} from '@sanity/types'
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
type DiffMatchPatch,
|
|
6
|
-
type InsertPatch,
|
|
7
|
-
type InsertPosition,
|
|
8
|
-
type SetIfMissingPatch,
|
|
9
|
-
type SetPatch,
|
|
10
|
-
type UnsetPatch,
|
|
11
|
-
} from '../types/patch'
|
|
12
|
-
|
|
13
|
-
export function setIfMissing(value: any, path: Path = []): SetIfMissingPatch {
|
|
14
|
-
return {
|
|
15
|
-
type: 'setIfMissing',
|
|
16
|
-
path,
|
|
17
|
-
value,
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function diffMatchPatch(
|
|
22
|
-
currentValue: string,
|
|
23
|
-
nextValue: string,
|
|
24
|
-
path: Path = [],
|
|
25
|
-
): DiffMatchPatch {
|
|
26
|
-
const patches = makePatches(currentValue, nextValue)
|
|
27
|
-
const patch = stringifyPatches(patches)
|
|
28
|
-
return {type: 'diffMatchPatch', path, value: patch}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export function insert(items: any[], position: InsertPosition, path: Path = []): InsertPatch {
|
|
32
|
-
return {
|
|
33
|
-
type: 'insert',
|
|
34
|
-
path,
|
|
35
|
-
position,
|
|
36
|
-
items,
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function set(value: any, path: Path = []): SetPatch {
|
|
41
|
-
return {type: 'set', path, value}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function unset(path: Path = []): UnsetPatch {
|
|
45
|
-
return {type: 'unset', path}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function prefixPath<T extends {path: Path}>(patch: T, segment: PathSegment): T {
|
|
49
|
-
return {
|
|
50
|
-
...patch,
|
|
51
|
-
path: [segment, ...patch.path],
|
|
52
|
-
}
|
|
53
|
-
}
|
package/src/patch/primitive.ts
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
const OPERATIONS: Record<string, any> = {
|
|
2
|
-
replace(_currentValue: any, nextValue: any) {
|
|
3
|
-
return nextValue
|
|
4
|
-
},
|
|
5
|
-
set(_currentValue: any, nextValue: any) {
|
|
6
|
-
return nextValue
|
|
7
|
-
},
|
|
8
|
-
setIfMissing(currentValue: any, nextValue: any) {
|
|
9
|
-
return currentValue === undefined ? nextValue : currentValue
|
|
10
|
-
},
|
|
11
|
-
unset(_currentValue: any, _nextValue: any) {
|
|
12
|
-
return undefined
|
|
13
|
-
},
|
|
14
|
-
inc(currentValue: any, nextValue: any) {
|
|
15
|
-
return currentValue + nextValue
|
|
16
|
-
},
|
|
17
|
-
dec(currentValue: any, nextValue: any) {
|
|
18
|
-
return currentValue - nextValue
|
|
19
|
-
},
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const SUPPORTED_PATCH_TYPES = Object.keys(OPERATIONS)
|
|
23
|
-
|
|
24
|
-
export default function apply(value: any, patch: any) {
|
|
25
|
-
if (!SUPPORTED_PATCH_TYPES.includes(patch.type)) {
|
|
26
|
-
throw new Error(
|
|
27
|
-
`Received patch of unsupported type: "${JSON.stringify(
|
|
28
|
-
patch.type,
|
|
29
|
-
)}" for primitives. This is most likely a bug.`,
|
|
30
|
-
)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
if (patch.path.length > 0) {
|
|
34
|
-
throw new Error(
|
|
35
|
-
`Cannot apply deep operations on primitive values. Received patch with type "${
|
|
36
|
-
patch.type
|
|
37
|
-
}" and path "${patch.path
|
|
38
|
-
.map((path: any) => JSON.stringify(path))
|
|
39
|
-
.join('.')} that targeted the value "${JSON.stringify(value)}"`,
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
return OPERATIONS[patch.type](value, patch.value)
|
|
43
|
-
}
|
package/src/patch/string.ts
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import {applyPatches, parsePatch} from '@sanity/diff-match-patch'
|
|
2
|
-
|
|
3
|
-
type fn = (oldVal: any, newVal: any) => any
|
|
4
|
-
const OPERATIONS: Record<string, fn> = {
|
|
5
|
-
replace(currentValue: any, nextValue: any) {
|
|
6
|
-
return nextValue
|
|
7
|
-
},
|
|
8
|
-
set(currentValue: any, nextValue: any) {
|
|
9
|
-
return nextValue
|
|
10
|
-
},
|
|
11
|
-
setIfMissing(currentValue: undefined, nextValue: any) {
|
|
12
|
-
return currentValue === undefined ? nextValue : currentValue
|
|
13
|
-
},
|
|
14
|
-
unset(currentValue: any, nextValue: any) {
|
|
15
|
-
return undefined
|
|
16
|
-
},
|
|
17
|
-
diffMatchPatch(currentValue: string, nextValue: string): string {
|
|
18
|
-
const [result] = applyPatches(parsePatch(nextValue), currentValue, {
|
|
19
|
-
allowExceedingIndices: true,
|
|
20
|
-
})
|
|
21
|
-
return result
|
|
22
|
-
},
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const SUPPORTED_PATCH_TYPES = Object.keys(OPERATIONS)
|
|
26
|
-
|
|
27
|
-
export default function apply(
|
|
28
|
-
value: string,
|
|
29
|
-
patch: {type: string; path: any[]; value: any},
|
|
30
|
-
): string {
|
|
31
|
-
if (!SUPPORTED_PATCH_TYPES.includes(patch.type)) {
|
|
32
|
-
throw new Error(
|
|
33
|
-
`Received patch of unsupported type: "${JSON.stringify(
|
|
34
|
-
patch.type,
|
|
35
|
-
)}" for string. This is most likely a bug.`,
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (patch.path.length > 0) {
|
|
40
|
-
throw new Error(
|
|
41
|
-
`Cannot apply deep operations on string values. Received patch with type "${
|
|
42
|
-
patch.type
|
|
43
|
-
}" and path "${patch.path.join('.')} that targeted the value "${JSON.stringify(value)}"`,
|
|
44
|
-
)
|
|
45
|
-
}
|
|
46
|
-
const func = OPERATIONS[patch.type]
|
|
47
|
-
if (func) {
|
|
48
|
-
return func(value, patch.value)
|
|
49
|
-
}
|
|
50
|
-
throw new Error('Unknown patch type')
|
|
51
|
-
}
|
package/src/types/patch.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import {type Path} from '@sanity/types'
|
|
2
|
-
|
|
3
|
-
export type JSONValue = number | string | boolean | {[key: string]: JSONValue} | JSONValue[]
|
|
4
|
-
|
|
5
|
-
export type Origin = 'remote' | 'local' | 'internal'
|
|
6
|
-
|
|
7
|
-
export type IncPatch = {
|
|
8
|
-
path: Path
|
|
9
|
-
origin?: Origin
|
|
10
|
-
type: 'inc'
|
|
11
|
-
value: JSONValue
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export type DecPatch = {
|
|
15
|
-
path: Path
|
|
16
|
-
origin?: Origin
|
|
17
|
-
type: 'dec'
|
|
18
|
-
value: JSONValue
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export type SetPatch = {
|
|
22
|
-
path: Path
|
|
23
|
-
type: 'set'
|
|
24
|
-
origin?: Origin
|
|
25
|
-
value: JSONValue
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export type SetIfMissingPatch = {
|
|
29
|
-
path: Path
|
|
30
|
-
origin?: Origin
|
|
31
|
-
type: 'setIfMissing'
|
|
32
|
-
value: JSONValue
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
export type UnsetPatch = {
|
|
36
|
-
path: Path
|
|
37
|
-
origin?: Origin
|
|
38
|
-
type: 'unset'
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export type InsertPosition = 'before' | 'after' | 'replace'
|
|
42
|
-
|
|
43
|
-
export type InsertPatch = {
|
|
44
|
-
path: Path
|
|
45
|
-
origin?: Origin
|
|
46
|
-
type: 'insert'
|
|
47
|
-
position: InsertPosition
|
|
48
|
-
items: JSONValue[]
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export type DiffMatchPatch = {
|
|
52
|
-
path: Path
|
|
53
|
-
type: 'diffMatchPatch'
|
|
54
|
-
origin?: Origin
|
|
55
|
-
value: string
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
export type Patch =
|
|
59
|
-
| SetPatch
|
|
60
|
-
| SetIfMissingPatch
|
|
61
|
-
| UnsetPatch
|
|
62
|
-
| InsertPatch
|
|
63
|
-
| DiffMatchPatch
|
|
64
|
-
| IncPatch
|
|
65
|
-
| DecPatch
|
package/src/utils/patches.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import {isEqual} from 'lodash'
|
|
2
|
-
|
|
3
|
-
import {type Patch} from '../types/patch'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Try to compact a set of patches
|
|
7
|
-
*
|
|
8
|
-
*/
|
|
9
|
-
export function compactPatches(patches: Patch[]) {
|
|
10
|
-
// If the last patch is unsetting everything, just do that
|
|
11
|
-
const lastPatch = patches.slice(-1)[0]
|
|
12
|
-
if (lastPatch && lastPatch.type === 'unset' && lastPatch.path.length === 0) {
|
|
13
|
-
return [lastPatch]
|
|
14
|
-
}
|
|
15
|
-
let finalPatches = patches
|
|
16
|
-
// Run through the patches and remove any redundant ones.
|
|
17
|
-
finalPatches = finalPatches.filter((patch, index) => {
|
|
18
|
-
if (!patch) {
|
|
19
|
-
return false
|
|
20
|
-
}
|
|
21
|
-
const nextPatch = finalPatches[index + 1]
|
|
22
|
-
if (
|
|
23
|
-
nextPatch &&
|
|
24
|
-
nextPatch.type === 'set' &&
|
|
25
|
-
patch.type === 'set' &&
|
|
26
|
-
isEqual(patch.path, nextPatch.path)
|
|
27
|
-
) {
|
|
28
|
-
return false
|
|
29
|
-
}
|
|
30
|
-
return true
|
|
31
|
-
})
|
|
32
|
-
if (finalPatches.length !== patches.length) {
|
|
33
|
-
return finalPatches
|
|
34
|
-
}
|
|
35
|
-
return patches
|
|
36
|
-
}
|