mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-20 14:11:35 +02:00
@@ -70,8 +70,9 @@ export const checkNode = (
|
||||
}
|
||||
|
||||
if ('marks' in v && v.marks != null) {
|
||||
for (const [mark, index, n, p] of Node.marks(node)) {
|
||||
if (!v.marks.some(m => Mark.matches(mark, m))) {
|
||||
for (const entry of Node.marks(node)) {
|
||||
if (!Editor.isMarkMatch(editor, entry, v.marks)) {
|
||||
const [mark, index, n, p] = entry
|
||||
return { code: 'mark_invalid', node: n, path: p, mark, index }
|
||||
}
|
||||
}
|
||||
|
@@ -13,19 +13,19 @@ export interface MarkRule {
|
||||
}
|
||||
|
||||
export interface ChildValidation {
|
||||
match?: NodeMatch | NodeMatch[]
|
||||
match?: NodeMatch
|
||||
min?: number
|
||||
max?: number
|
||||
}
|
||||
|
||||
export interface NodeValidation {
|
||||
children?: ChildValidation[]
|
||||
first?: NodeMatch[]
|
||||
last?: NodeMatch[]
|
||||
marks?: MarkMatch[]
|
||||
next?: NodeMatch[]
|
||||
parent?: NodeMatch[]
|
||||
previous?: NodeMatch[]
|
||||
first?: NodeMatch
|
||||
last?: NodeMatch
|
||||
marks?: MarkMatch
|
||||
next?: NodeMatch
|
||||
parent?: NodeMatch
|
||||
previous?: NodeMatch
|
||||
properties?: Record<string, any>
|
||||
text?: (text: string) => boolean
|
||||
}
|
||||
|
27
packages/slate-schema/test/validations/marks/invalid-or.js
Normal file
27
packages/slate-schema/test/validations/marks/invalid-or.js
Normal file
@@ -0,0 +1,27 @@
|
||||
/** @jsx jsx */
|
||||
|
||||
import { jsx } from 'slate-hyperscript'
|
||||
|
||||
export const schema = [
|
||||
{
|
||||
for: 'node',
|
||||
match: 'element',
|
||||
validate: {
|
||||
marks: [{ a: true }, { b: true }],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<element>
|
||||
<mark c>text</mark>
|
||||
</element>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const output = (
|
||||
<editor>
|
||||
<element>text</element>
|
||||
</editor>
|
||||
)
|
@@ -4,6 +4,7 @@ import { ElementQueries } from './queries/element'
|
||||
import { GeneralTransforms } from './transforms/general'
|
||||
import { GeneralQueries } from './queries/general'
|
||||
import { LocationQueries } from './queries/location'
|
||||
import { MarkQueries } from './queries/mark'
|
||||
import { MarkTransforms } from './transforms/mark'
|
||||
import { NodeTransforms } from './transforms/node'
|
||||
import { NodeQueries } from './queries/node'
|
||||
@@ -34,6 +35,7 @@ export const Editor = {
|
||||
...GeneralQueries,
|
||||
...GeneralTransforms,
|
||||
...LocationQueries,
|
||||
...MarkQueries,
|
||||
...MarkTransforms,
|
||||
...NodeQueries,
|
||||
...NodeTransforms,
|
||||
|
@@ -350,13 +350,6 @@ export const LocationQueries = {
|
||||
|
||||
for (const entry of Editor.texts(editor, { reverse, at })) {
|
||||
const [node, path] = entry
|
||||
const isMatch = (m: MarkMatch, entry: MarkEntry) => {
|
||||
if (typeof m === 'function') {
|
||||
return m(entry)
|
||||
} else {
|
||||
return Mark.matches(entry[0], m)
|
||||
}
|
||||
}
|
||||
|
||||
if (mode === 'universal') {
|
||||
if (first) {
|
||||
@@ -384,7 +377,7 @@ export const LocationQueries = {
|
||||
const mark = node.marks[index]
|
||||
const markEntry: MarkEntry = [mark, index, node, path]
|
||||
|
||||
if (match != null && !isMatch(match, markEntry)) {
|
||||
if (match != null && !Editor.isMarkMatch(editor, markEntry, match)) {
|
||||
continue
|
||||
}
|
||||
|
||||
|
17
packages/slate/src/interfaces/editor/queries/mark.ts
Normal file
17
packages/slate/src/interfaces/editor/queries/mark.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import { Editor, Mark, MarkEntry, MarkMatch } from '../../..'
|
||||
|
||||
export const MarkQueries = {
|
||||
/**
|
||||
* Check if a mark entry is a match.
|
||||
*/
|
||||
|
||||
isMarkMatch(editor: Editor, entry: MarkEntry, match: MarkMatch): boolean {
|
||||
if (Array.isArray(match)) {
|
||||
return match.some(m => Editor.isMarkMatch(editor, entry, m))
|
||||
} else if (typeof match === 'function') {
|
||||
return match(entry)
|
||||
} else {
|
||||
return Mark.matches(entry[0], match)
|
||||
}
|
||||
},
|
||||
}
|
@@ -5,20 +5,13 @@ export const NodeQueries = {
|
||||
* Check if a node entry is a match.
|
||||
*/
|
||||
|
||||
isMatch(editor: Editor, entry: NodeEntry, match: NodeMatch | NodeMatch[]) {
|
||||
const [node] = entry
|
||||
|
||||
// If match is an array, treat it as an OR condition.
|
||||
isMatch(editor: Editor, entry: NodeEntry, match: NodeMatch): boolean {
|
||||
if (Array.isArray(match)) {
|
||||
for (const m of match) {
|
||||
if (Editor.isMatch(editor, entry, m)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
return match.some(m => Editor.isMatch(editor, entry, m))
|
||||
}
|
||||
|
||||
const [node] = entry
|
||||
|
||||
switch (match) {
|
||||
case 'text':
|
||||
return Text.isText(node)
|
||||
@@ -27,11 +20,6 @@ export const NodeQueries = {
|
||||
case 'element':
|
||||
return Element.isElement(node)
|
||||
case 'inline':
|
||||
return (
|
||||
(Element.isElement(node) && editor.isInline(node)) ||
|
||||
Text.isText(node)
|
||||
)
|
||||
case 'inline-element':
|
||||
return Element.isElement(node) && editor.isInline(node)
|
||||
case 'block':
|
||||
return (
|
||||
|
@@ -48,7 +48,7 @@ export const NodeTransforms = {
|
||||
} else if (Text.isText(node)) {
|
||||
match = 'text'
|
||||
} else if (editor.isInline(node)) {
|
||||
match = 'inline'
|
||||
match = ['inline', 'text']
|
||||
} else {
|
||||
match = 'block'
|
||||
}
|
||||
@@ -682,7 +682,7 @@ export const NodeTransforms = {
|
||||
const path = at
|
||||
match = ([, p]) => Path.equals(p, path)
|
||||
} else if (editor.isInline(element)) {
|
||||
match = 'inline'
|
||||
match = ['inline', 'text']
|
||||
} else {
|
||||
match = 'block'
|
||||
}
|
||||
|
@@ -193,7 +193,7 @@ export const TextTransforms = {
|
||||
|
||||
// If the insert point is at the edge of an inline node, move it outside
|
||||
// instead since it will need to be split otherwise.
|
||||
const inlineElementMatch = Editor.match(editor, at, 'inline-element')
|
||||
const inlineElementMatch = Editor.match(editor, at, 'inline')
|
||||
|
||||
if (inlineElementMatch) {
|
||||
const [, inlinePath] = inlineElementMatch
|
||||
@@ -270,7 +270,7 @@ export const TextTransforms = {
|
||||
}
|
||||
}
|
||||
|
||||
const inlineMatch = Editor.match(editor, at, 'inline')!
|
||||
const inlineMatch = Editor.match(editor, at, ['inline', 'text'])!
|
||||
const [, inlinePath] = inlineMatch
|
||||
const isInlineStart = Editor.isStart(editor, at, inlinePath)
|
||||
const isInlineEnd = Editor.isEnd(editor, at, inlinePath)
|
||||
@@ -285,7 +285,10 @@ export const TextTransforms = {
|
||||
isInlineEnd ? Path.next(inlinePath) : inlinePath
|
||||
)
|
||||
|
||||
Editor.splitNodes(editor, { at, match: hasBlocks ? 'block' : 'inline' })
|
||||
Editor.splitNodes(editor, {
|
||||
at,
|
||||
match: hasBlocks ? 'block' : ['inline', 'text'],
|
||||
})
|
||||
|
||||
const startRef = Editor.pathRef(
|
||||
editor,
|
||||
@@ -296,13 +299,18 @@ export const TextTransforms = {
|
||||
|
||||
Editor.insertNodes(editor, starts, {
|
||||
at: startRef.current!,
|
||||
match: 'inline',
|
||||
match: ['inline', 'text'],
|
||||
})
|
||||
|
||||
Editor.insertNodes(editor, middles, {
|
||||
at: middleRef.current!,
|
||||
match: 'block',
|
||||
})
|
||||
Editor.insertNodes(editor, ends, { at: endRef.current!, match: 'inline' })
|
||||
|
||||
Editor.insertNodes(editor, ends, {
|
||||
at: endRef.current!,
|
||||
match: ['inline', 'text'],
|
||||
})
|
||||
|
||||
if (!options.at) {
|
||||
let path
|
||||
|
@@ -62,4 +62,7 @@ export type MarkEntry = [Mark, number, Text, Path]
|
||||
* `MarkMatch` values are used as shorthands for matching mark objects.
|
||||
*/
|
||||
|
||||
export type MarkMatch = Partial<Mark> | ((entry: MarkEntry) => boolean)
|
||||
export type MarkMatch =
|
||||
| Partial<Mark>
|
||||
| ((entry: MarkEntry) => boolean)
|
||||
| MarkMatch[]
|
||||
|
@@ -574,9 +574,9 @@ export type NodeMatch =
|
||||
| 'block'
|
||||
| 'element'
|
||||
| 'inline'
|
||||
| 'inline-element'
|
||||
| 'text'
|
||||
| 'editor'
|
||||
| 'void'
|
||||
| Partial<Node>
|
||||
| ((entry: NodeEntry) => boolean)
|
||||
| NodeMatch[]
|
||||
|
@@ -15,4 +15,4 @@ export const run = editor => {
|
||||
)
|
||||
}
|
||||
|
||||
export const output = [[<text>one</text>, [0, 0]]]
|
||||
export const output = []
|
||||
|
@@ -18,9 +18,6 @@ export const run = editor => {
|
||||
}
|
||||
|
||||
export const output = [
|
||||
[<text>one</text>, [0, 0]],
|
||||
[<inline>two</inline>, [0, 1]],
|
||||
[<text>three</text>, [0, 2]],
|
||||
[<inline>four</inline>, [0, 3]],
|
||||
[<text>five</text>, [0, 4]],
|
||||
]
|
||||
|
@@ -22,12 +22,10 @@ export const run = editor => {
|
||||
}
|
||||
|
||||
export const output = [
|
||||
[<text>one</text>, [0, 0]],
|
||||
[
|
||||
<inline>
|
||||
two<inline>three</inline>four
|
||||
</inline>,
|
||||
[0, 1],
|
||||
],
|
||||
[<text>five</text>, [0, 2]],
|
||||
]
|
||||
|
@@ -23,9 +23,6 @@ export const run = editor => {
|
||||
}
|
||||
|
||||
export const output = [
|
||||
[<text>five</text>, [0, 4]],
|
||||
[<inline>four</inline>, [0, 3]],
|
||||
[<text>three</text>, [0, 2]],
|
||||
[<inline>two</inline>, [0, 1]],
|
||||
[<text>one</text>, [0, 0]],
|
||||
]
|
||||
|
@@ -17,8 +17,4 @@ export const run = editor => {
|
||||
)
|
||||
}
|
||||
|
||||
export const output = [
|
||||
[<text>one</text>, [0, 0]],
|
||||
[<inline void>two</inline>, [0, 1]],
|
||||
[<text>three</text>, [0, 2]],
|
||||
]
|
||||
export const output = [[<inline void>two</inline>, [0, 1]]]
|
||||
|
@@ -17,8 +17,4 @@ export const run = editor => {
|
||||
)
|
||||
}
|
||||
|
||||
export const output = [
|
||||
[<text>one</text>, [0, 0]],
|
||||
[<inline>two</inline>, [0, 1]],
|
||||
[<text>three</text>, [0, 2]],
|
||||
]
|
||||
export const output = [[<inline>two</inline>, [0, 1]]]
|
||||
|
@@ -0,0 +1,26 @@
|
||||
/** @jsx jsx */
|
||||
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block>
|
||||
one<inline>two</inline>three<inline>four</inline>five
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const run = editor => {
|
||||
return Array.from(
|
||||
Editor.nodes(editor, { at: [], match: ['inline', 'text'], mode: 'highest' })
|
||||
)
|
||||
}
|
||||
|
||||
export const output = [
|
||||
[<text>one</text>, [0, 0]],
|
||||
[<inline>two</inline>, [0, 1]],
|
||||
[<text>three</text>, [0, 2]],
|
||||
[<inline>four</inline>, [0, 3]],
|
||||
[<text>five</text>, [0, 4]],
|
||||
]
|
@@ -0,0 +1,33 @@
|
||||
/** @jsx jsx */
|
||||
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block>
|
||||
one
|
||||
<inline>
|
||||
two<inline>three</inline>four
|
||||
</inline>
|
||||
five
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const run = editor => {
|
||||
return Array.from(
|
||||
Editor.nodes(editor, { at: [], match: ['inline', 'text'], mode: 'highest' })
|
||||
)
|
||||
}
|
||||
|
||||
export const output = [
|
||||
[<text>one</text>, [0, 0]],
|
||||
[
|
||||
<inline>
|
||||
two<inline>three</inline>four
|
||||
</inline>,
|
||||
[0, 1],
|
||||
],
|
||||
[<text>five</text>, [0, 2]],
|
||||
]
|
24
packages/slate/test/queries/nodes/match-multiple/inline.js
Normal file
24
packages/slate/test/queries/nodes/match-multiple/inline.js
Normal file
@@ -0,0 +1,24 @@
|
||||
/** @jsx jsx */
|
||||
|
||||
import { Editor } from 'slate'
|
||||
import { jsx } from '../../..'
|
||||
|
||||
export const input = (
|
||||
<editor>
|
||||
<block>
|
||||
one<inline>two</inline>three
|
||||
</block>
|
||||
</editor>
|
||||
)
|
||||
|
||||
export const run = editor => {
|
||||
return Array.from(
|
||||
Editor.nodes(editor, { at: [], match: ['inline', 'text'], mode: 'highest' })
|
||||
)
|
||||
}
|
||||
|
||||
export const output = [
|
||||
[<text>one</text>, [0, 0]],
|
||||
[<inline>two</inline>, [0, 1]],
|
||||
[<text>three</text>, [0, 2]],
|
||||
]
|
@@ -36,10 +36,10 @@ export const output = (
|
||||
<anchor />
|
||||
word
|
||||
</inline>
|
||||
<text key />
|
||||
<text />
|
||||
</block>
|
||||
<block>
|
||||
<text key />
|
||||
<text />
|
||||
<inline key>
|
||||
another
|
||||
<focus />
|
||||
|
@@ -36,7 +36,7 @@ export const output = (
|
||||
<anchor />
|
||||
word
|
||||
</inline>
|
||||
<text key />
|
||||
<text />
|
||||
</block>
|
||||
<block>
|
||||
<text />
|
||||
|
Reference in New Issue
Block a user