1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-08-29 18:09:49 +02:00

Merge branch 'master' of github.com:ianstormtaylor/slate

This commit is contained in:
Ian Storm Taylor
2019-12-19 14:34:38 -05:00
9 changed files with 227 additions and 81 deletions

View File

@@ -76,7 +76,7 @@ If you have an idea for an example that shows a common use case, pull request it
## Documentation
If you're using Slate for the first time, check out the [Getting Started](http://docs.slatejs.org/walkthroughs/installing-slate) walkthroughs and the [Concepts](http://docs.slatejs.org/concepts) to familiarize yourself with Slate's architecture and mental models.
If you're using Slate for the first time, check out the [Getting Started](http://docs.slatejs.org/walkthroughs/01-installing-slate) walkthroughs and the [Concepts](http://docs.slatejs.org/concepts) to familiarize yourself with Slate's architecture and mental models.
- [**Walkthroughs**](http://docs.slatejs.org/walkthroughs)
- [**Concepts**](http://docs.slatejs.org/concepts)

View File

@@ -18,6 +18,6 @@ Since Slate knows nothing about your domain, it can't know how to parse pasted H
Slate's goal is to support all the modern browsers on both desktop and mobile devices.
However, right now Slate is in beta and is community-driven, so its support is not as robust as it could be. It's currently tested against the latest few versions of Chrome, Edge, Firefox and Safari on desktops. It is not regularly tested on mobile devices. And it does not work in Internet Explorer. If you want to add more browser or device support, we'd love for you to submit a pull request! Or in the case of incompatible browsers, build a plugin.
However, right now Slate is in beta and is community-driven, so its support is not as robust as it could be. It's currently tested against the latest few versions of Chrome, Edge, Firefox and Safari on desktops. And it does not work in Internet Explorer. On mobile, iOS devices are supported but not regularly tested. Chrome on Android is supported on Slate 0.47 but is not currently supported in Slate 0.50+. If you want to add more browser or device support, we'd love for you to submit a pull request! Or in the case of incompatible browsers, build a plugin.
For older browsers, such as IE11, a lot of the now standard native APIs aren't available. Slate's position on this is that it is up to the user to bring polyfills (like https://polyfill.io) when needed for things like `el.closest`, etc. Otherwise we'd have to bundle and maintain lots of polyfills that others may not even need in the first place.

View File

@@ -697,8 +697,8 @@ export const Editable = (props: EditableProps) => {
if (Hotkeys.isRedo(nativeEvent)) {
event.preventDefault()
if (editor.undo) {
editor.undo()
if (editor.redo) {
editor.redo()
}
return
@@ -707,8 +707,8 @@ export const Editable = (props: EditableProps) => {
if (Hotkeys.isUndo(nativeEvent)) {
event.preventDefault()
if (editor.redo) {
editor.redo()
if (editor.undo) {
editor.undo()
}
return

View File

@@ -25,7 +25,7 @@ const Text = (props: {
const { decorations, isLast, parent, renderLeaf, text } = props
const editor = useEditor()
const ref = useRef<HTMLSpanElement>(null)
const leaves = getLeaves(text, decorations)
const leaves = SlateText.decorations(text, decorations)
const key = ReactEditor.findKey(editor, text)
const children = []
@@ -63,79 +63,6 @@ const Text = (props: {
)
}
/**
* Get the leaves for a text node given decorations.
*/
const getLeaves = (node: SlateText, decorations: Range[]): SlateText[] => {
let leaves: SlateText[] = [{ ...node }]
for (const dec of decorations) {
const { anchor, focus, ...rest } = dec
const [start, end] = Range.edges(dec)
const next = []
let o = 0
for (const leaf of leaves) {
const { length } = leaf.text
const offset = o
o += length
// If the range encompases the entire leaf, add the range.
if (start.offset <= offset && end.offset >= offset + length) {
Object.assign(leaf, rest)
next.push(leaf)
continue
}
// If the range starts after the leaf, or ends before it, continue.
if (
start.offset > offset + length ||
end.offset < offset ||
(end.offset === offset && offset !== 0)
) {
next.push(leaf)
continue
}
// Otherwise we need to split the leaf, at the start, end, or both,
// and add the range to the middle intersecting section. Do the end
// split first since we don't need to update the offset that way.
let middle = leaf
let before
let after
if (end.offset < offset + length) {
const off = end.offset - offset
after = { ...middle, text: middle.text.slice(off) }
middle = { ...middle, text: middle.text.slice(0, off) }
}
if (start.offset > offset) {
const off = start.offset - offset
before = { ...middle, text: middle.text.slice(0, off) }
middle = { ...middle, text: middle.text.slice(off) }
}
Object.assign(middle, rest)
if (before) {
next.push(before)
}
next.push(middle)
if (after) {
next.push(after)
}
}
leaves = next
}
return leaves
}
const MemoizedText = React.memo(Text, (prev, next) => {
return (
next.parent === prev.parent &&

View File

@@ -1,5 +1,5 @@
import isPlainObject from 'is-plain-object'
import { Path } from '..'
import { Range } from '..'
/**
* `Text` objects represent the nodes that contain the actual text content of a
@@ -83,4 +83,77 @@ export const Text = {
return true
},
/**
* Get the leaves for a text node given decorations.
*/
decorations(node: Text, decorations: Range[]): Text[] {
let leaves: Text[] = [{ ...node }]
for (const dec of decorations) {
const { anchor, focus, ...rest } = dec
const [start, end] = Range.edges(dec)
const next = []
let o = 0
for (const leaf of leaves) {
const { length } = leaf.text
const offset = o
o += length
// If the range encompases the entire leaf, add the range.
if (start.offset <= offset && end.offset >= offset + length) {
Object.assign(leaf, rest)
next.push(leaf)
continue
}
// If the range starts after the leaf, or ends before it, continue.
if (
start.offset > offset + length ||
end.offset < offset ||
(end.offset === offset && offset !== 0)
) {
next.push(leaf)
continue
}
// Otherwise we need to split the leaf, at the start, end, or both,
// and add the range to the middle intersecting section. Do the end
// split first since we don't need to update the offset that way.
let middle = leaf
let before
let after
if (end.offset < offset + length) {
const off = end.offset - offset
after = { ...middle, text: middle.text.slice(off) }
middle = { ...middle, text: middle.text.slice(0, off) }
}
if (start.offset > offset) {
const off = start.offset - offset
before = { ...middle, text: middle.text.slice(0, off) }
middle = { ...middle, text: middle.text.slice(off) }
}
Object.assign(middle, rest)
if (before) {
next.push(before)
}
next.push(middle)
if (after) {
next.push(after)
}
}
leaves = next
}
return leaves
},
}

View File

@@ -0,0 +1,31 @@
import { Text } from 'slate'
export const input = [
{
anchor: {
path: [0],
offset: 2,
},
focus: {
path: [0],
offset: 3,
},
decoration: 'decoration',
},
]
export const test = decorations => {
return Text.decorations({ text: 'abc', mark: 'mark' }, decorations)
}
export const output = [
{
text: 'ab',
mark: 'mark',
},
{
text: 'c',
mark: 'mark',
decoration: 'decoration',
},
]

View File

@@ -0,0 +1,35 @@
import { Text } from 'slate'
export const input = [
{
anchor: {
path: [0],
offset: 1,
},
focus: {
path: [0],
offset: 2,
},
decoration: 'decoration',
},
]
export const test = decorations => {
return Text.decorations({ text: 'abc', mark: 'mark' }, decorations)
}
export const output = [
{
text: 'a',
mark: 'mark',
},
{
text: 'b',
mark: 'mark',
decoration: 'decoration',
},
{
text: 'c',
mark: 'mark',
},
]

View File

@@ -0,0 +1,49 @@
import { Text } from 'slate'
export const input = [
{
anchor: {
path: [0],
offset: 1,
},
focus: {
path: [0],
offset: 2,
},
decoration1: 'decoration1',
},
{
anchor: {
path: [0],
offset: 0,
},
focus: {
path: [0],
offset: 3,
},
decoration2: 'decoration2',
},
]
export const test = decorations => {
return Text.decorations({ text: 'abc', mark: 'mark' }, decorations)
}
export const output = [
{
text: 'a',
mark: 'mark',
decoration2: 'decoration2',
},
{
text: 'b',
mark: 'mark',
decoration1: 'decoration1',
decoration2: 'decoration2',
},
{
text: 'c',
mark: 'mark',
decoration2: 'decoration2',
},
]

View File

@@ -0,0 +1,31 @@
import { Text } from 'slate'
export const input = [
{
anchor: {
path: [0],
offset: 0,
},
focus: {
path: [0],
offset: 1,
},
decoration: 'decoration',
},
]
export const test = decorations => {
return Text.decorations({ text: 'abc', mark: 'mark' }, decorations)
}
export const output = [
{
text: 'a',
mark: 'mark',
decoration: 'decoration',
},
{
text: 'bc',
mark: 'mark',
},
]