diff --git a/docs/concepts/01-interfaces.md b/docs/concepts/01-interfaces.md index c082e05a9..a82504e34 100644 --- a/docs/concepts/01-interfaces.md +++ b/docs/concepts/01-interfaces.md @@ -5,14 +5,13 @@ Slate works with pure JSON objects. All it requires is that those JSON objects c ```ts interface Text { text: string - marks: Mark[] [key: string]: any } ``` -Which means it must have a `text` property with a string of content, and a `marks` property with an array of formatting marks (or an empty array). +Which means it must have a `text` property with a string of content. -But other custom properties are also allowed, and completely up to you. This lets you tailor your data to your specific domain and use case, without Slate getting in the way. +But **any** other custom properties are also allowed, and completely up to you. This lets you tailor your data to your specific domain and use case, adding whatever formatting logic you'd like, without Slate getting in the way. This interface-based approach separates Slate from most other rich-text editors which require you to work with their hand-rolled "model" classes, and makes it much easier to reason about. It also means that it avoids startup time penalties related to "initializing" the data model. diff --git a/docs/concepts/02-nodes.md b/docs/concepts/02-nodes.md index 48b47aaa9..a51811aee 100644 --- a/docs/concepts/02-nodes.md +++ b/docs/concepts/02-nodes.md @@ -16,7 +16,6 @@ const editor = { children: [ { text: 'A line of text!', - marks: [], }, ], }, @@ -127,18 +126,17 @@ Text nodes are the lowest-level nodes in the tree, containing the text content o ```ts interface Text { text: string - marks: Mark[] [key: string]: any } ``` -We'll cover `Mark` objects shortly, but for now you can get an idea for them: +For example, a string of bold text: ```js const text = { text: 'A string of bold text', - marks: [{ type: 'bold' }], + bold: true, } ``` -Text nodes too can contain any custom properties you want, although it is rarer to need to do that. +Text nodes too can contain any custom properties you want, and that's how you implement custom formatting like **bold**, _italic_, `code`, etc. diff --git a/docs/concepts/03-locations.md b/docs/concepts/03-locations.md index bb2a153a0..d2cdc4ff8 100644 --- a/docs/concepts/03-locations.md +++ b/docs/concepts/03-locations.md @@ -20,7 +20,6 @@ const editor = { children: [ { text: 'A line of text!', - marks: [], }, ], }, @@ -107,7 +106,6 @@ const editor = { children: [ { text: 'A line of text!', - marks: [], }, ], }, diff --git a/docs/concepts/05-commands.md b/docs/concepts/04-commands.md similarity index 91% rename from docs/concepts/05-commands.md rename to docs/concepts/04-commands.md index e59a0e02a..a9de5b6ed 100644 --- a/docs/concepts/05-commands.md +++ b/docs/concepts/04-commands.md @@ -1,6 +1,6 @@ # Commands -While editing rich-text content, your users will be doing things like inserting text, deleteing text, splitting paragraphs, adding marks, etc. These edits are expressed using two concepts: commands and operations. +While editing rich-text content, your users will be doing things like inserting text, deleteing text, splitting paragraphs, adding formatting, etc. These edits are expressed using two concepts: commands and operations. Commands are the high-level actions that represent a specific intent of the user. Their interface is simply: @@ -25,12 +25,11 @@ editor.exec({ }) editor.exec({ - type: 'add_mark', - mark: { type: 'bold' }, + type: 'insert_break', }) ``` -But you can (and will!) also define your own custom commands that model your domain. For example, you might want to define a `wrap_quote` command, or a `insert_image` command depending on what types of content you allow. +But you can (and will!) also define your own custom commands that model your domain. For example, you might want to define a `wrap_quote` command, or a `insert_image` command, or a `format_bold` command depending on what types of content you allow. Commands always describe an action to be taken as if the user themselves was performing the action. For that reason, they never need to define a location to perform the command, because they always act on the user's current selection. diff --git a/docs/concepts/04-formatting.md b/docs/concepts/04-formatting.md deleted file mode 100644 index 66e099ac1..000000000 --- a/docs/concepts/04-formatting.md +++ /dev/null @@ -1,49 +0,0 @@ -# Formatting: Marks and Decorations - -We've already seen how `Element` objects can be extended with custom properties to add semantic meaning to your rich-text documents. But there are other kinds of formatting too. - -## `Mark` - -Marks are the lowest level of formatting that is applied directly to the text nodes of your document, for things like **bold**, _italic_ and `code`. Their interface is: - -```ts -interface Mark { - [key: string]: any -} -``` - -Which means that they are entirely composed of your domain-specific custom properties. For simple cases, it can suffice to use a `type` string: - -```js -const bold = { type: 'bold' } -const italic = { type: 'italic' } -``` - -There are multiple techniques you might choose to format or style text. You can implement styling based on inlines or marks. Unlike inlines, marks do not affect the structure of the nodes in the document. Marks simply attach themselves to the characters. - -Marks may be easier to reason about and manipulate because marks do not affect the structure of the document and are associated to the characters. Marks can be applied to characters no matter how the characters are nested in the document. If you can express it as a `Range`, you can add marks to it. Working with marks instead of inlines does not require you to edit the document's structure, split existing nodes, determine where nodes are in the hierarchy, or other more complex interactions. - -When marks are rendered, the characters are grouped into "leaves" of text that each contain the same set of marks applied to them. One disadvantage of marks is that you cannot guarantee how a set of marks will be ordered. - -This limitation with respect to the ordering of marks is similar to the DOM, where this is invalid: - -```html -text -``` - -Because the elements in the above example do not properly close themselves they are invalid. Instead, you would write the above HTML as follows: - -```html -text -``` - -If you happened to add another overlapping section of `` to that text, you might have to rearrange the closing tags yet again. Rendering marks in Slate is similar—you can't guarantee that even though a word has one mark applied that that mark will be contiguous, because it depends on how it overlaps with other marks. - -Of course, this mark ordering stuff sounds pretty complex. But, you do not have to think about it much, as long as you use marks and inlines for their intended purposes: - -- Marks represent **unordered**, character-level formatting. -- Inlines represent **contiguous**, semantic elements in the document. - -## Decorations - -Decorations are similar to marks, with each one applying to a range of content. However, they are computed at render-time based on the content itself. This is helpful for dynamic formatting like syntax highlighting or search keywords, where changes to the content (or some external data) has the potential to change the formatting. diff --git a/docs/concepts/06-operations.md b/docs/concepts/05-operations.md similarity index 98% rename from docs/concepts/06-operations.md rename to docs/concepts/05-operations.md index 0de73e6a1..88a454d30 100644 --- a/docs/concepts/06-operations.md +++ b/docs/concepts/05-operations.md @@ -17,7 +17,6 @@ editor.apply({ path: [0, 0], node: { text: 'A line of text!', - marks: [], }, }) diff --git a/docs/concepts/07-editor.md b/docs/concepts/06-editor.md similarity index 93% rename from docs/concepts/07-editor.md rename to docs/concepts/06-editor.md index 9c3a3f214..69c87754d 100644 --- a/docs/concepts/07-editor.md +++ b/docs/concepts/06-editor.md @@ -95,8 +95,8 @@ for (const [element, path] of Editor.elements(editor, { at: range })) { // ... } -// Iterate over every mark in every text node in the current selection. -for (const [mark, index, text, path] of Editor.marks(editor)) { +// Iterate over every point in every text node in the current selection. +for (const [point] of Editor.positions(editor)) { // ... } ``` @@ -110,8 +110,8 @@ Editor.insertNodes(editor, [element], { at: path }) // Split the nodes in half at a specific point. Editor.splitNodes(editor, { at: point }) -// Add a mark to all the text in a range. -Editor.addMarks(editor, mark, { at: range }) +// Add a quote format to all the block nodes in the selection. +Editor.setNodes(editor, { type: 'quote' }) ``` The editor-specific helpers are the ones you'll use most often when working with Slate editors, so it pays to become very familiar with them. diff --git a/docs/concepts/08-plugins.md b/docs/concepts/07-plugins.md similarity index 94% rename from docs/concepts/08-plugins.md rename to docs/concepts/07-plugins.md index a7068287b..2c636ea9b 100644 --- a/docs/concepts/08-plugins.md +++ b/docs/concepts/07-plugins.md @@ -13,8 +13,7 @@ const withImages = editor => { editor.exec = command => { if (command.type === 'insert_image') { const { url } = command - const text = { text: '', marks: [] } - const element = { type: 'image', url, children: [text] } + const element = { type: 'image', url, children: [{ text: '' }] } Editor.insertNodes(editor) } else { exec(command) diff --git a/docs/concepts/09-rendering.md b/docs/concepts/08-rendering.md similarity index 50% rename from docs/concepts/09-rendering.md rename to docs/concepts/08-rendering.md index 438e9aa29..09c02ba8c 100644 --- a/docs/concepts/09-rendering.md +++ b/docs/concepts/08-rendering.md @@ -2,7 +2,7 @@ One of the best parts of Slate is that it's built with React, so it fits right into your existing application. It doesn't re-invent its own view layer that you have to learn. It tries to keep everything as React-y as possible. -To that end, Slate gives you control over the rendering behavior of your custom elements and custom marks in your rich-text domain. +To that end, Slate gives you control over the rendering behavior of your custom nodes and properties in your rich-text domain. You can define these behaviors by passing "render props" to the top-level `` component. @@ -54,24 +54,58 @@ const renderElement = useCallback(props => { }, []) ``` -The same thing goes for a custom `renderMark` prop: +## Leaves + +When text-level formatting is rendered, the characters are grouped into "leaves" of text that each contain the same formatting applied to them. + +To customize the rendering of each leaf, you use a custom `renderLeaf` prop: ```jsx -const renderMark = useCallback(({ attributes, children, mark }) => { - switch (mark.type) { - case 'bold': - return {children} - case 'italic': - return {children} - } +const renderLeaf = useCallback(({ attributes, children, leaf }) => { + return ( + + {children} + + ) }, []) ``` -> 🤖 Be aware though that marks aren't guaranteed to be "contiguous". Which means even though a **word** is bolded, it's not guaranteed to render as a single `` element. If some of its characters are also italic, it might be split up into multiple elements—one `wo` and one `rd`. +Notice though how we've handled it slightly differently than `renderElement`. Since text formatting texts to be fairly simple, we've opted to ditch the `switch` statement and just toggle on/off a few styles instead. (But there's nothing preventing you from using custom components if you'd like!) + +One disadvantage of text-level formatting is that you cannot guarantee that any given format is "contiguous"—meaning that it stays as a single leaf. This limitation with respect to leaves is similar to the DOM, where this is invalid: + +```html +text +``` + +Because the elements in the above example do not properly close themselves they are invalid. Instead, you would write the above HTML as follows: + +```html +text +``` + +If you happened to add another overlapping section of `` to that text, you might have to rearrange the closing tags yet again. Rendering leaves in Slate is similar—you can't guarantee that even though a word has one type of formatting applied to it that that leaf will be contiguous, because it depends on how it overlaps with other formatting. + +Of course, this leaf stuff sounds pretty complex. But, you do not have to think about it much, as long as you use text-level formatting and element-level formatting for their intended purposes: + +- Text properties are for **non-contiguous**, character-level formatting. +- Element properties are for **contiguous**, semantic elements in the document. + +## Decorations + +Decorations are another type of text-level formatting. They are similar to regular old custom properties, except each one applies to a `Range` of the document instead of being associated with a given text node. + +However, decorations are computed at **render-time** based on the content itself. This is helpful for dynamic formatting like syntax highlighting or search keywords, where changes to the content (or some external data) has the potential to change the formatting. ## Toolbars, Menus, Overlays, and more! -In addition to controlling the rendering of elements and marks inside Slate, you can also retrieve the current editor context from inside other components using the `useSlate` hook. +In addition to controlling the rendering of nodes inside Slate, you can also retrieve the current editor context from inside other components using the `useSlate` hook. That way other components can execute commands, query the editor state, or anything else. diff --git a/docs/concepts/XX-migrating.md b/docs/concepts/XX-migrating.md index 78c374773..8cbd4a4d6 100644 --- a/docs/concepts/XX-migrating.md +++ b/docs/concepts/XX-migrating.md @@ -68,9 +68,13 @@ We now use the `beforeinput` event almost exclusively. Instead of having relying The core history logic has now finally been extracted into a standalone plugin. This makes it much easier for people to implement their own custom history behaviors. And it ensures that plugins have enough control to augment the editor in complex ways, because the history requires it. +### Mark-less + +Marks have been removed the Slate data model. Now that we have the ability to define custom properties right on the nodes themselves, you can model marks as custom properties of text nodes. For example bold can be modelled simply as a `bold: true` property. + ### Annotation-less -Similarly, annotations have been removed from Slate's core. They can be fully implemented now in userland by defining custom operations and rendering annotated ranges using decorations. But most cases should be using plain marks or plain decorations anyways. There were not that many use cases that benefitted from annotations. +Similarly, annotations have been removed from Slate's core. They can be fully implemented now in userland by defining custom operations and rendering annotated ranges using decorations. But most cases should be using custom text node properties or decorations anyways. There were not that many use cases that benefitted from annotations. ## Reductions @@ -79,23 +83,23 @@ One of the goals was to dramatically simplify a lot of the logic in Slate to mak To give you a sense for the change in total lines of code: ``` -slate 8,436 -> 4,038 (48%) -slate-react 3,905 -> 715 (18%) +slate 8,436 -> 3,724 (48%) +slate-react 3,905 -> 627 (18%) slate-base64-serializer 38 -> 0 slate-dev-benchmark 340 -> 0 slate-dev-environment 102 -> 0 slate-dev-test-utils 44 -> 0 -slate-history 0 -> 201 +slate-history 0 -> 209 slate-hotkeys 62 -> 0 slate-html-serializer 253 -> 0 -slate-hyperscript 447 -> 410 +slate-hyperscript 447 -> 345 slate-plain-serializer 56 -> 0 slate-prop-types 62 -> 0 slate-react-placeholder 62 -> 0 -slate-schema 0 -> 504 +slate-schema 0 -> 439 -total 13,807 -> 5,868 (43%) +total 13,807 -> 5,344 (39%) ``` It's quite a big difference! And that doesn't even include the dependencies that were shed in the process too. diff --git a/docs/walkthroughs/01-installing-slate.md b/docs/walkthroughs/01-installing-slate.md index 6a7021924..93ad54c41 100644 --- a/docs/walkthroughs/01-installing-slate.md +++ b/docs/walkthroughs/01-installing-slate.md @@ -93,7 +93,6 @@ const defaultValue = [ children: [ { text: 'A line of text in a paragraph.', - marks: [], }, ], }, diff --git a/docs/walkthroughs/04-applying-custom-formatting.md b/docs/walkthroughs/04-applying-custom-formatting.md index d52065356..d4a991b2b 100644 --- a/docs/walkthroughs/04-applying-custom-formatting.md +++ b/docs/walkthroughs/04-applying-custom-formatting.md @@ -41,7 +41,7 @@ const App = () => { } ``` -And now, we'll edit the `onKeyDown` handler to make it so that when you press `control-B`, it will add a "bold" mark to the currently selected text: +And now, we'll edit the `onKeyDown` handler to make it so that when you press `control-B`, it will add a `bold` format to the currently selected text: ```js const App = () => { @@ -78,10 +78,16 @@ const App = () => { break } - // When "B" is pressed, add a bold mark to the text. + // When "B" is pressed, bold the text in the selection. case 'b': { event.preventDefault() - Editor.addMarks(editor, { type: 'bold' }) + Editor.setNodes( + editor, + { bold: true }, + // Apply it to text nodes, and split the text node up if the + // selection is overlapping only part of it. + { match: 'text', split: true } + ) break } } @@ -94,18 +100,25 @@ const App = () => { Okay, so we've got the hotkey handler setup... but! If you happen to now try selecting text and hitting `Ctrl-B`, you won't notice any change. That's because we haven't told Slate how to render a "bold" mark. -For every mark type you want to add to your schema, you need to give Slate a "renderer" for that mark, just like elements. So let's define our `bold` mark: +For every format you want to add to your schema, Slate will break up the text content into "leaves", and you need to tell Slate how to read it, just like for elements. So let's define a `Leaf` component: ```js -// Define a React component to render bold text with. -const BoldMark = props => { - return {props.children} +// Define a React component to render leaves with bold text. +const Leaf = props => { + return ( + + {props.children} + + ) } ``` Pretty familiar, right? -And now, let's tell Slate about that mark. To do that, we'll pass in the `renderMark` prop to our editor. Also, let's allow our mark to be toggled by changing `addMark` to `toggleMark`. +And now, let's tell Slate about that leaf. To do that, we'll pass in the `renderLeaf` prop to our editor. Also, let's allow our formatting to be toggled by adding active-checking logic. ```js const App = () => { @@ -119,21 +132,17 @@ const App = () => { } }, []) - // Define a mark rendering function that is memoized with `useCallback`. - const renderMark = useCallback(props => { - switch (props.mark.type) { - case 'bold': { - return - } - } + // Define a leaf rendering function that is memoized with `useCallback`. + const renderLeaf = useCallback(props => { + return }, []) return ( { if (!event.ctrlKey) { return @@ -154,7 +163,11 @@ const App = () => { case 'b': { event.preventDefault() - Editor.addMarks(editor, { type: 'bold' }) + Editor.setNodes( + editor, + { bold: true }, + { match: 'text', split: true } + ) break } } @@ -164,8 +177,15 @@ const App = () => { ) } -const BoldMark = props => { - return {props.children} +const Leaf = props => { + return ( + + {props.children} + + ) } ``` diff --git a/docs/walkthroughs/05-executing-commands.md b/docs/walkthroughs/05-executing-commands.md index 9bf7e6fad..c49e5007c 100644 --- a/docs/walkthroughs/05-executing-commands.md +++ b/docs/walkthroughs/05-executing-commands.md @@ -22,19 +22,15 @@ const App = () => { } }, []) - const renderMark = useCallback(props => { - switch (props.mark.type) { - case 'bold': { - return - } - } + const renderLeaf = useCallback(props => { + return }, []) return ( { if (!event.ctrlKey) { return @@ -55,7 +51,11 @@ const App = () => { case 'b': { event.preventDefault() - Editor.addMarks(editor, { type: 'bold' }) + Editor.setNodes( + editor, + { bold: true }, + { match: 'text', split: true } + ) break } } @@ -66,7 +66,7 @@ const App = () => { } ``` -It has the concept of "code blocks" and "bold marks". But these things are all defined in one-off cases inside the `onKeyDown` handler. If you wanted to reuse that logic elsewhere you'd need to extract it. +It has the concept of "code blocks" and "bold formatting". But these things are all defined in one-off cases inside the `onKeyDown` handler. If you wanted to reuse that logic elsewhere you'd need to extract it. We can instead implement these domain-specific concepts by extending the `editor` object: @@ -88,19 +88,15 @@ const App = () => { } }, []) - const renderMark = useCallback(props => { - switch (props.mark.type) { - case 'bold': { - return - } - } + const renderLeaf = useCallback(props => { + return }, []) return ( { if (!event.ctrlKey) { return @@ -121,7 +117,11 @@ const App = () => { case 'b': { event.preventDefault() - Editor.addMarks(editor, [{ type: 'bold' }]) + Editor.setNodes( + editor, + { bold: true }, + { match: 'text', split: true } + ) break } } @@ -141,22 +141,19 @@ const withCustom = editor => { const { exec } = editor editor.exec = command => { - // Define a command to toggle the bold mark formatting. + // Define a command to toggle the bold formatting. if (command.type === 'toggle_bold_mark') { const isActive = CustomEditor.isBoldMarkActive(editor) - // Delegate to the existing `add_mark` and `remove_mark` commands, so that - // other plugins can override them if they need to still. - editor.exec({ - type: isActive ? 'remove_mark' : 'add_mark', - mark: { type: 'bold' }, - }) + Editor.setNodes( + editor, + { bold: isActive ? null : true }, + { match: 'text', split: true } + ) } // Define a command to toggle the code block formatting. else if (command.type === 'toggle_code_block') { const isActive = CustomEditor.isCodeBlockActive(editor) - // There is no `set_nodes` command, so we can transform the editor - // directly using the helper instead. Editor.setNodes( editor, { type: isActive ? null : 'code' }, @@ -173,24 +170,24 @@ const withCustom = editor => { return editor } -// Define our own custom set of helpers for common queries. +// Define our own custom set of helpers for active-checking queries. const CustomEditor = { isBoldMarkActive(editor) { - const [mark] = Editor.marks(editor, { - match: { type: 'bold' }, + const [match] = Editor.nodes(editor, { + match: { bold: true }, mode: 'universal', }) - return !!mark + return !!match }, isCodeBlockActive(editor) { - const [node] = Editor.nodes(editor, { + const [match] = Editor.nodes(editor, { match: { type: 'code' }, mode: 'highest', }) - return !!node + return !!match }, } @@ -205,19 +202,15 @@ const App = () => { } }, []) - const renderMark = useCallback(props => { - switch (props.mark.type) { - case 'bold': { - return - } - } + const renderLeaf = useCallback(props => { + return }, []) return ( { if (!event.ctrlKey) { @@ -258,12 +251,8 @@ const App = () => { } }, []) - const renderMark = useCallback(props => { - switch (props.mark.type) { - case 'bold': { - return - } - } + const renderLeaf = useCallback(props => { + return }, []) return ( @@ -290,7 +279,7 @@ const App = () => { { if (!event.ctrlKey) { return diff --git a/docs/walkthroughs/06-saving-to-a-database.md b/docs/walkthroughs/06-saving-to-a-database.md index 67b762016..8e0907a45 100644 --- a/docs/walkthroughs/06-saving-to-a-database.md +++ b/docs/walkthroughs/06-saving-to-a-database.md @@ -16,7 +16,6 @@ const defaultValue = [ children: [ { text: 'A line of text in a paragraph.', - marks: [], }, ], }, @@ -44,7 +43,6 @@ const defaultValue = [ children: [ { text: 'A line of text in a paragraph.', - marks: [], }, ], }, @@ -80,7 +78,6 @@ const defaultValue = existingValue || [ children: [ { text: 'A line of text in a paragraph.', - marks: [], }, ], }, @@ -129,7 +126,7 @@ const deserialize = string => { // Return a value array of children derived by splitting the string. return string.split('\n').map(line => { return { - children: [{ text: line, marks: [] }], + children: [{ text: line }], } }) } diff --git a/package.json b/package.json index 63fd95949..bb0ee644a 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "fix": "yarn fix:prettier && yarn fix:eslint", "fix:eslint": "yarn lint:eslint --fix", "fix:prettier": "yarn lint:prettier --write", - "lint": "yarn lint:eslint && yarn lint:prettier", + "lint": "yarn lint:eslint", "lint:eslint": "eslint \"./{packages,site}/**/*.{js,jsx,ts,tsx}\"", "lint:prettier": "prettier --list-different \"**/*.{css,md,js,jsx,json,ts,tsx}\"", "open": "open http://localhost:3000", diff --git a/packages/slate-history/test/undo/add_mark/block-across.js b/packages/slate-history/test/undo/add_mark/block-across.js deleted file mode 100644 index 0aaa17caf..000000000 --- a/packages/slate-history/test/undo/add_mark/block-across.js +++ /dev/null @@ -1,22 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from '../..' - -export const run = editor => { - editor.exec({ type: 'add_mark', mark: { key: 'a' } }) -} - -export const input = ( - - - o - ne - - - tw - o - - -) - -export const output = input diff --git a/packages/slate-history/test/undo/add_mark/mark-across.js b/packages/slate-history/test/undo/add_mark/mark-across.js deleted file mode 100644 index 4bee242a0..000000000 --- a/packages/slate-history/test/undo/add_mark/mark-across.js +++ /dev/null @@ -1,20 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from '../..' - -export const run = editor => { - editor.exec({ type: 'add_mark', mark: { key: 'a' } }) -} - -export const input = ( - - - - wo - - rd - - -) - -export const output = input diff --git a/packages/slate-history/test/undo/add_mark/mark-from.js b/packages/slate-history/test/undo/add_mark/mark-from.js deleted file mode 100644 index a08ede642..000000000 --- a/packages/slate-history/test/undo/add_mark/mark-from.js +++ /dev/null @@ -1,20 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from '../..' - -export const run = editor => { - editor.exec({ type: 'add_mark', mark: { key: 'a' } }) -} - -export const input = ( - - - - wo - - rd - - -) - -export const output = input diff --git a/packages/slate-history/test/undo/add_mark/text.js b/packages/slate-history/test/undo/add_mark/text.js deleted file mode 100644 index 740194ee6..000000000 --- a/packages/slate-history/test/undo/add_mark/text.js +++ /dev/null @@ -1,20 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from '../..' - -export const run = editor => { - editor.exec({ type: 'add_mark', mark: { key: 'a' } }) -} - -export const input = ( - - - - wo - - rd - - -) - -export const output = input diff --git a/packages/slate-history/test/undo/delete_backward/mark-across.js b/packages/slate-history/test/undo/delete_backward/mark-across.js deleted file mode 100644 index 465d76298..000000000 --- a/packages/slate-history/test/undo/delete_backward/mark-across.js +++ /dev/null @@ -1,27 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../..' - -export const run = editor => { - editor.delete() -} - -export const input = ( - - - - on - e - - - tw - o - - - -) - -export const output = input - -export const skip = true diff --git a/packages/slate-history/test/undo/remove_mark/basic.js b/packages/slate-history/test/undo/remove_mark/basic.js deleted file mode 100644 index 9cac93d9d..000000000 --- a/packages/slate-history/test/undo/remove_mark/basic.js +++ /dev/null @@ -1,21 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from '../..' - -export const run = editor => { - editor.exec({ type: 'remove_mark', mark: { key: true } }) -} - -export const input = ( - - - - - one - - - - -) - -export const output = input diff --git a/packages/slate-hyperscript/src/creators.ts b/packages/slate-hyperscript/src/creators.ts index f76ec4141..0b569b8da 100644 --- a/packages/slate-hyperscript/src/creators.ts +++ b/packages/slate-hyperscript/src/creators.ts @@ -1,9 +1,7 @@ import { Element, Descendant, - Mark, Node, - Path, Range, Text, Editor, @@ -37,7 +35,7 @@ const resolveDescendants = (children: any[]): Descendant[] => { const prev = nodes[nodes.length - 1] if (typeof child === 'string') { - const text = { text: child, marks: [] } + const text = { text: child } STRINGS.add(text) child = text } @@ -49,8 +47,7 @@ const resolveDescendants = (children: any[]): Descendant[] => { Text.isText(prev) && STRINGS.has(prev) && STRINGS.has(c) && - c.marks.every(m => Mark.exists(m, prev.marks)) && - prev.marks.every(m => Mark.exists(m, c.marks)) + Text.equals(prev, c, { loose: true }) ) { prev.text += c.text } else { @@ -143,43 +140,6 @@ export function createFragment( return resolveDescendants(children) } -/** - * Create a `Text` object with a mark applied. - */ - -export function createMark( - tagName: string, - attributes: { [key: string]: any }, - children: any[] -): Text { - const mark = { ...attributes } - const nodes = resolveDescendants(children) - - if (nodes.length > 1) { - throw new Error( - `The hyperscript tag must only contain a single node's worth of children.` - ) - } - - if (nodes.length === 0) { - return { text: '', marks: [mark] } - } - - const [node] = nodes - - if (!Text.isText(node)) { - throw new Error( - `The hyperscript tag must only contain text content as children.` - ) - } - - if (!Mark.exists(mark, node.marks)) { - node.marks.push(mark) - } - - return node -} - /** * Create a `Selection` object. */ @@ -237,7 +197,7 @@ export function createText( let [node] = nodes if (node == null) { - node = { text: '', marks: [] } + node = { text: '' } } if (!Text.isText(node)) { @@ -245,8 +205,8 @@ export function createText( The hyperscript tag can only contain text content as children.`) } - // COMPAT: Re-create the node, because if they used the tag we want to - // guarantee that it won't be merge with other string children. + // COMPAT: If they used the tag we want to guarantee that it won't be + // merge with other string children. STRINGS.delete(node) Object.assign(node, attributes) diff --git a/packages/slate-hyperscript/src/hyperscript.ts b/packages/slate-hyperscript/src/hyperscript.ts index d33f5b9a1..f12036415 100644 --- a/packages/slate-hyperscript/src/hyperscript.ts +++ b/packages/slate-hyperscript/src/hyperscript.ts @@ -1,5 +1,5 @@ import isPlainObject from 'is-plain-object' -import { Element, Mark } from 'slate' +import { Element } from 'slate' import { createAnchor, createCursor, @@ -7,7 +7,6 @@ import { createElement, createFocus, createFragment, - createMark, createSelection, createText, } from './creators' @@ -23,7 +22,6 @@ const DEFAULT_CREATORS = { element: createElement, focus: createFocus, fragment: createFragment, - mark: createMark, selection: createSelection, text: createText, } @@ -54,16 +52,13 @@ const createHyperscript = ( options: { creators?: HyperscriptCreators elements?: HyperscriptShorthands - marks?: HyperscriptShorthands } = {} ) => { - const { elements = {}, marks = {} } = options + const { elements = {} } = options const elementCreators = normalizeElements(elements) - const markCreators = normalizeMarks(marks) const creators = { ...DEFAULT_CREATORS, ...elementCreators, - ...markCreators, ...options.creators, } @@ -132,32 +127,4 @@ const normalizeElements = (elements: HyperscriptShorthands) => { return creators } -/** - * Normalize a dictionary of mark shorthands into creator functions. - */ - -const normalizeMarks = (marks: HyperscriptShorthands) => { - const creators: HyperscriptCreators = {} - - for (const tagName in marks) { - const props = marks[tagName] - - if (typeof props !== 'object') { - throw new Error( - `Properties specified for a hyperscript shorthand should be an object, but for the custom mark <${tagName}> tag you passed: ${props}` - ) - } - - creators[tagName] = ( - tagName: string, - attributes: { [key: string]: any }, - children: any[] - ) => { - return createMark('mark', { ...props, ...attributes }, children) - } - } - - return creators -} - export { createHyperscript, HyperscriptCreators, HyperscriptShorthands } diff --git a/packages/slate-hyperscript/src/tokens.ts b/packages/slate-hyperscript/src/tokens.ts index 1550c344e..0c63360ed 100644 --- a/packages/slate-hyperscript/src/tokens.ts +++ b/packages/slate-hyperscript/src/tokens.ts @@ -1,4 +1,4 @@ -import { Mark, Node, Path, Text } from 'slate' +import { Node, Path, Text } from 'slate' /** * A weak map to hold anchor tokens. @@ -23,23 +23,17 @@ export class Token {} */ export class AnchorToken extends Token { - focused: boolean - marks: Mark[] | null offset?: number path?: Path constructor( props: { - focused?: boolean - marks?: Mark[] | null offset?: number path?: Path } = {} ) { super() - const { focused = true, marks = null, offset, path } = props - this.focused = focused - this.marks = marks + const { offset, path } = props this.offset = offset this.path = path } @@ -50,23 +44,17 @@ export class AnchorToken extends Token { */ export class FocusToken extends Token { - focused: boolean - marks: Mark[] | null offset?: number path?: Path constructor( props: { - focused?: boolean - marks?: Mark[] | null offset?: number path?: Path } = {} ) { super() - const { focused = true, marks = null, offset, path } = props - this.focused = focused - this.marks = marks + const { offset, path } = props this.offset = offset this.path = path } diff --git a/packages/slate-hyperscript/test/fixtures/cursor-across-element.js b/packages/slate-hyperscript/test/fixtures/cursor-across-element.js index 18d8945c4..9c7b82dc6 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-across-element.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-across-element.js @@ -18,7 +18,6 @@ export const output = { children: [ { text: 'word', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-across-elements-empty.js b/packages/slate-hyperscript/test/fixtures/cursor-across-elements-empty.js index c701a428b..09c65f6ea 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-across-elements-empty.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-across-elements-empty.js @@ -23,7 +23,6 @@ export const output = { children: [ { text: '', - marks: [], }, ], }, @@ -31,7 +30,6 @@ export const output = { children: [ { text: '', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-across-elements-end.js b/packages/slate-hyperscript/test/fixtures/cursor-across-elements-end.js index 632bb4e7c..0c2457c63 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-across-elements-end.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-across-elements-end.js @@ -21,7 +21,6 @@ export const output = { children: [ { text: 'one', - marks: [], }, ], }, @@ -29,7 +28,6 @@ export const output = { children: [ { text: 'two', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-across-elements-middle.js b/packages/slate-hyperscript/test/fixtures/cursor-across-elements-middle.js index f2f7817b1..a1701770e 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-across-elements-middle.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-across-elements-middle.js @@ -21,7 +21,6 @@ export const output = { children: [ { text: 'one', - marks: [], }, ], }, @@ -29,7 +28,6 @@ export const output = { children: [ { text: 'two', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-across-elements-start.js b/packages/slate-hyperscript/test/fixtures/cursor-across-elements-start.js index 82a462351..73ae447ad 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-across-elements-start.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-across-elements-start.js @@ -21,7 +21,6 @@ export const output = { children: [ { text: 'one', - marks: [], }, ], }, @@ -29,7 +28,6 @@ export const output = { children: [ { text: 'two', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-element-empty.js b/packages/slate-hyperscript/test/fixtures/cursor-element-empty.js index adcb6f029..856e306af 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-element-empty.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-element-empty.js @@ -16,7 +16,6 @@ export const output = { children: [ { text: '', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-element-end.js b/packages/slate-hyperscript/test/fixtures/cursor-element-end.js index edc1949e7..0580f02d8 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-element-end.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-element-end.js @@ -17,7 +17,6 @@ export const output = { children: [ { text: 'one', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-element-middle.js b/packages/slate-hyperscript/test/fixtures/cursor-element-middle.js index f7c5879f3..0054ed12f 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-element-middle.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-element-middle.js @@ -17,7 +17,6 @@ export const output = { children: [ { text: 'one', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-element-nested-end.js b/packages/slate-hyperscript/test/fixtures/cursor-element-nested-end.js index cc966bbc3..7f72b09b8 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-element-nested-end.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-element-nested-end.js @@ -21,7 +21,6 @@ export const output = { children: [ { text: 'word', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-element-nested-middle.js b/packages/slate-hyperscript/test/fixtures/cursor-element-nested-middle.js index 34c13dec4..eb7dff7a8 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-element-nested-middle.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-element-nested-middle.js @@ -22,7 +22,6 @@ export const output = { children: [ { text: 'word', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-element-nested-start.js b/packages/slate-hyperscript/test/fixtures/cursor-element-nested-start.js index e6800f7dd..1f057c99f 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-element-nested-start.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-element-nested-start.js @@ -21,7 +21,6 @@ export const output = { children: [ { text: 'word', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-element-start.js b/packages/slate-hyperscript/test/fixtures/cursor-element-start.js index 3bf814e35..1bbbb28cc 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-element-start.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-element-start.js @@ -17,7 +17,6 @@ export const output = { children: [ { text: 'one', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/cursor-is-focused-false.js b/packages/slate-hyperscript/test/fixtures/cursor-is-focused-false.js deleted file mode 100644 index f2f8122df..000000000 --- a/packages/slate-hyperscript/test/fixtures/cursor-is-focused-false.js +++ /dev/null @@ -1,34 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const input = ( - - - - - -) - -export const output = { - children: [ - { - children: [ - { - text: '', - marks: [], - }, - ], - }, - ], - selection: { - anchor: { - path: [0, 0], - offset: 0, - }, - focus: { - path: [0, 0], - offset: 0, - }, - }, -} diff --git a/packages/slate-hyperscript/test/fixtures/cursor-mark-after.js b/packages/slate-hyperscript/test/fixtures/cursor-mark-after.js deleted file mode 100644 index 5d3ab96a3..000000000 --- a/packages/slate-hyperscript/test/fixtures/cursor-mark-after.js +++ /dev/null @@ -1,40 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const input = ( - - - one - - two - - -) - -export const output = { - children: [ - { - children: [ - { - text: 'one', - marks: [{}], - }, - { - text: 'two', - marks: [], - }, - ], - }, - ], - selection: { - anchor: { - path: [0, 0], - offset: 3, - }, - focus: { - path: [0, 0], - offset: 3, - }, - }, -} diff --git a/packages/slate-hyperscript/test/fixtures/cursor-mark-end.js b/packages/slate-hyperscript/test/fixtures/cursor-mark-end.js deleted file mode 100644 index 9a83cea64..000000000 --- a/packages/slate-hyperscript/test/fixtures/cursor-mark-end.js +++ /dev/null @@ -1,42 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const input = ( - - - - one - - - two - - -) - -export const output = { - children: [ - { - children: [ - { - text: 'one', - marks: [{}], - }, - { - text: 'two', - marks: [], - }, - ], - }, - ], - selection: { - anchor: { - path: [0, 0], - offset: 3, - }, - focus: { - path: [0, 0], - offset: 3, - }, - }, -} diff --git a/packages/slate-hyperscript/test/fixtures/cursor-mark-middle.js b/packages/slate-hyperscript/test/fixtures/cursor-mark-middle.js deleted file mode 100644 index 9fcbcb02d..000000000 --- a/packages/slate-hyperscript/test/fixtures/cursor-mark-middle.js +++ /dev/null @@ -1,42 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const input = ( - - - - o - ne - - two - - -) - -export const output = { - children: [ - { - children: [ - { - text: 'one', - marks: [{}], - }, - { - text: 'two', - marks: [], - }, - ], - }, - ], - selection: { - anchor: { - path: [0, 0], - offset: 1, - }, - focus: { - path: [0, 0], - offset: 1, - }, - }, -} diff --git a/packages/slate-hyperscript/test/fixtures/cursor-mark-start.js b/packages/slate-hyperscript/test/fixtures/cursor-mark-start.js deleted file mode 100644 index 845792c64..000000000 --- a/packages/slate-hyperscript/test/fixtures/cursor-mark-start.js +++ /dev/null @@ -1,42 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const input = ( - - - - - one - - two - - -) - -export const output = { - children: [ - { - children: [ - { - text: 'one', - marks: [{}], - }, - { - text: 'two', - marks: [], - }, - ], - }, - ], - selection: { - anchor: { - path: [0, 0], - offset: 0, - }, - focus: { - path: [0, 0], - offset: 0, - }, - }, -} diff --git a/packages/slate-hyperscript/test/fixtures/cursor-marks-empty.js b/packages/slate-hyperscript/test/fixtures/cursor-marks-empty.js deleted file mode 100644 index 808ee48d4..000000000 --- a/packages/slate-hyperscript/test/fixtures/cursor-marks-empty.js +++ /dev/null @@ -1,34 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const input = ( - - - - - -) - -export const output = { - children: [ - { - children: [ - { - text: '', - marks: [], - }, - ], - }, - ], - selection: { - anchor: { - path: [0, 0], - offset: 0, - }, - focus: { - path: [0, 0], - offset: 0, - }, - }, -} diff --git a/packages/slate-hyperscript/test/fixtures/cursor-text-empty.js b/packages/slate-hyperscript/test/fixtures/cursor-text-empty.js index 80433b43b..880c88ddf 100644 --- a/packages/slate-hyperscript/test/fixtures/cursor-text-empty.js +++ b/packages/slate-hyperscript/test/fixtures/cursor-text-empty.js @@ -18,7 +18,6 @@ export const output = { children: [ { text: '', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/element-custom.js b/packages/slate-hyperscript/test/fixtures/element-custom.js index ccf12256e..f2a7af668 100644 --- a/packages/slate-hyperscript/test/fixtures/element-custom.js +++ b/packages/slate-hyperscript/test/fixtures/element-custom.js @@ -15,7 +15,6 @@ export const output = { children: [ { text: 'word', - marks: [], }, ], } diff --git a/packages/slate-hyperscript/test/fixtures/element-nested-string.js b/packages/slate-hyperscript/test/fixtures/element-nested-string.js index 1275b0575..30cb39c1d 100644 --- a/packages/slate-hyperscript/test/fixtures/element-nested-string.js +++ b/packages/slate-hyperscript/test/fixtures/element-nested-string.js @@ -14,7 +14,6 @@ export const output = { children: [ { text: 'word', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/element-string.js b/packages/slate-hyperscript/test/fixtures/element-string.js index ee1d1af9f..72a26961b 100644 --- a/packages/slate-hyperscript/test/fixtures/element-string.js +++ b/packages/slate-hyperscript/test/fixtures/element-string.js @@ -8,7 +8,6 @@ export const output = { children: [ { text: 'word', - marks: [], }, ], } diff --git a/packages/slate-hyperscript/test/fixtures/element-text-empty.js b/packages/slate-hyperscript/test/fixtures/element-text-empty.js index 5a69fc3c6..6c87a8d60 100644 --- a/packages/slate-hyperscript/test/fixtures/element-text-empty.js +++ b/packages/slate-hyperscript/test/fixtures/element-text-empty.js @@ -12,7 +12,6 @@ export const output = { children: [ { text: '', - marks: [], }, ], } diff --git a/packages/slate-hyperscript/test/fixtures/element-text-string.js b/packages/slate-hyperscript/test/fixtures/element-text-string.js index 359bca922..01d6e5be1 100644 --- a/packages/slate-hyperscript/test/fixtures/element-text-string.js +++ b/packages/slate-hyperscript/test/fixtures/element-text-string.js @@ -12,7 +12,6 @@ export const output = { children: [ { text: 'word', - marks: [], }, ], } diff --git a/packages/slate-hyperscript/test/fixtures/fragment-element.js b/packages/slate-hyperscript/test/fixtures/fragment-element.js index b53bee58d..8fd31ea02 100644 --- a/packages/slate-hyperscript/test/fixtures/fragment-element.js +++ b/packages/slate-hyperscript/test/fixtures/fragment-element.js @@ -13,7 +13,6 @@ export const output = [ children: [ { text: 'word', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/fragment-string.js b/packages/slate-hyperscript/test/fixtures/fragment-string.js index ed98b5156..5549e933d 100644 --- a/packages/slate-hyperscript/test/fixtures/fragment-string.js +++ b/packages/slate-hyperscript/test/fixtures/fragment-string.js @@ -7,6 +7,5 @@ export const input = word export const output = [ { text: 'word', - marks: [], }, ] diff --git a/packages/slate-hyperscript/test/fixtures/mark-custom.js b/packages/slate-hyperscript/test/fixtures/mark-custom.js deleted file mode 100644 index 2d7383b4a..000000000 --- a/packages/slate-hyperscript/test/fixtures/mark-custom.js +++ /dev/null @@ -1,16 +0,0 @@ -/** @jsx jsx */ - -import { createHyperscript } from 'slate-hyperscript' - -const jsx = createHyperscript({ - marks: { - b: { type: 'bold' }, - }, -}) - -export const input = word - -export const output = { - text: 'word', - marks: [{ type: 'bold' }], -} diff --git a/packages/slate-hyperscript/test/fixtures/mark-nested-string.js b/packages/slate-hyperscript/test/fixtures/mark-nested-string.js deleted file mode 100644 index 9215175fa..000000000 --- a/packages/slate-hyperscript/test/fixtures/mark-nested-string.js +++ /dev/null @@ -1,14 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const input = ( - - word - -) - -export const output = { - text: 'word', - marks: [{ type: 'b' }, { type: 'a' }], -} diff --git a/packages/slate-hyperscript/test/fixtures/mark-string.js b/packages/slate-hyperscript/test/fixtures/mark-string.js deleted file mode 100644 index 5f7b9556c..000000000 --- a/packages/slate-hyperscript/test/fixtures/mark-string.js +++ /dev/null @@ -1,10 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const input = word - -export const output = { - text: 'word', - marks: [{}], -} diff --git a/packages/slate-hyperscript/test/fixtures/mark-text.js b/packages/slate-hyperscript/test/fixtures/mark-text.js deleted file mode 100644 index 035c230b4..000000000 --- a/packages/slate-hyperscript/test/fixtures/mark-text.js +++ /dev/null @@ -1,14 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const input = ( - - word - -) - -export const output = { - text: 'word', - marks: [{}], -} diff --git a/packages/slate-hyperscript/test/fixtures/selection.js b/packages/slate-hyperscript/test/fixtures/selection.js index 3b8404e77..b13fc4a0d 100644 --- a/packages/slate-hyperscript/test/fixtures/selection.js +++ b/packages/slate-hyperscript/test/fixtures/selection.js @@ -18,7 +18,6 @@ export const output = { children: [ { text: 'word', - marks: [], }, ], }, diff --git a/packages/slate-hyperscript/test/fixtures/text-empty.js b/packages/slate-hyperscript/test/fixtures/text-empty.js index 73592f94b..d6795e581 100644 --- a/packages/slate-hyperscript/test/fixtures/text-empty.js +++ b/packages/slate-hyperscript/test/fixtures/text-empty.js @@ -2,9 +2,9 @@ import { jsx } from 'slate-hyperscript' -export const input = +export const input = export const output = { text: '', - marks: [], + a: true, } diff --git a/packages/slate-hyperscript/test/fixtures/text-full.js b/packages/slate-hyperscript/test/fixtures/text-full.js index 357d4eca3..5640b2b90 100644 --- a/packages/slate-hyperscript/test/fixtures/text-full.js +++ b/packages/slate-hyperscript/test/fixtures/text-full.js @@ -2,9 +2,9 @@ import { jsx } from 'slate-hyperscript' -export const input = word +export const input = word export const output = { text: 'word', - marks: [], + a: true, } diff --git a/packages/slate-hyperscript/test/fixtures/text-nested.js b/packages/slate-hyperscript/test/fixtures/text-nested.js index 2ab51b6ae..836510280 100644 --- a/packages/slate-hyperscript/test/fixtures/text-nested.js +++ b/packages/slate-hyperscript/test/fixtures/text-nested.js @@ -3,12 +3,13 @@ import { jsx } from 'slate-hyperscript' export const input = ( - - word + + word ) export const output = { text: 'word', - marks: [], + a: true, + b: true, } diff --git a/packages/slate-react/src/components/children.tsx b/packages/slate-react/src/components/children.tsx index 1bfb963de..c67e85f8a 100644 --- a/packages/slate-react/src/components/children.tsx +++ b/packages/slate-react/src/components/children.tsx @@ -6,11 +6,7 @@ import TextComponent from './text' import { ReactEditor } from '..' import { useEditor } from '../hooks/use-editor' import { NODE_TO_INDEX, NODE_TO_PARENT } from '../utils/weak-maps' -import { - RenderDecorationProps, - RenderElementProps, - RenderMarkProps, -} from './editable' +import { RenderElementProps, RenderLeafProps } from './editable' /** * Children. @@ -20,18 +16,16 @@ const Children = (props: { decorate: (entry: NodeEntry) => Range[] decorations: Range[] node: Ancestor - renderDecoration?: (props: RenderDecorationProps) => JSX.Element renderElement?: (props: RenderElementProps) => JSX.Element - renderMark?: (props: RenderMarkProps) => JSX.Element + renderLeaf?: (props: RenderLeafProps) => JSX.Element selection: Range | null }) => { const { decorate, decorations, node, - renderDecoration, renderElement, - renderMark, + renderLeaf, selection, } = props const editor = useEditor() @@ -65,9 +59,8 @@ const Children = (props: { decorations={ds} element={n} key={key.id} - renderDecoration={renderDecoration} renderElement={renderElement} - renderMark={renderMark} + renderLeaf={renderLeaf} selection={sel} /> ) @@ -78,8 +71,7 @@ const Children = (props: { key={key.id} isLast={isLeafBlock && i === node.children.length} parent={node} - renderDecoration={renderDecoration} - renderMark={renderMark} + renderLeaf={renderLeaf} text={n} /> ) diff --git a/packages/slate-react/src/components/editable.tsx b/packages/slate-react/src/components/editable.tsx index f2478e60d..1ef3ebf55 100644 --- a/packages/slate-react/src/components/editable.tsx +++ b/packages/slate-react/src/components/editable.tsx @@ -5,7 +5,7 @@ import React, { useMemo, useCallback, } from 'react' -import { Editor, Element, NodeEntry, Node, Range, Text, Mark } from 'slate' +import { Editor, Element, NodeEntry, Node, Range, Text } from 'slate' import debounce from 'debounce' import scrollIntoView from 'scroll-into-view-if-needed' @@ -15,7 +15,6 @@ import { IS_FIREFOX, IS_SAFARI } from '../utils/environment' import { ReactEditor } from '..' import { ReadOnlyContext } from '../hooks/use-read-only' import { useSlate } from '../hooks/use-slate' -import { Leaf } from '../utils/leaf' import { DOMElement, DOMNode, @@ -34,20 +33,6 @@ import { PLACEHOLDER_SYMBOL, } from '../utils/weak-maps' -/** - * `RenderDecorationProps` are passed to the `renderDecoration` handler. - */ - -export interface RenderDecorationProps { - children: any - decoration: Range - leaf: Leaf - text: Text - attributes: { - 'data-slate-decoration': true - } -} - /** * `RenderElementProps` are passed to the `renderElement` handler. */ @@ -56,8 +41,8 @@ export interface RenderElementProps { children: any element: Element attributes: { - 'data-slate-inline'?: true 'data-slate-node': 'element' + 'data-slate-inline'?: true 'data-slate-void'?: true dir?: 'rtl' ref: any @@ -65,16 +50,15 @@ export interface RenderElementProps { } /** - * `RenderMarkProps` are passed to the `renderMark` handler. + * `RenderLeafProps` are passed to the `renderLeaf` handler. */ -export interface RenderMarkProps { +export interface RenderLeafProps { children: any - mark: Mark - leaf: Leaf + leaf: Text text: Text attributes: { - 'data-slate-mark': true + 'data-slate-leaf': true } } @@ -90,21 +74,19 @@ export const Editable = ( readOnly?: boolean role?: string style?: React.CSSProperties - renderDecoration?: (props: RenderDecorationProps) => JSX.Element renderElement?: (props: RenderElementProps) => JSX.Element - renderMark?: (props: RenderMarkProps) => JSX.Element + renderLeaf?: (props: RenderLeafProps) => JSX.Element } & React.TextareaHTMLAttributes ) => { const { + autoFocus, decorate = defaultDecorate, + onDOMBeforeInput: propsOnDOMBeforeInput, placeholder, readOnly = false, - renderDecoration, renderElement, - renderMark, - autoFocus, + renderLeaf, style = {}, - onDOMBeforeInput: propsOnDOMBeforeInput, ...attributes } = props const editor = useSlate() @@ -906,9 +888,8 @@ export const Editable = ( decorate={decorate} decorations={decorations} node={editor} - renderDecoration={renderDecoration} renderElement={renderElement} - renderMark={renderMark} + renderLeaf={renderLeaf} selection={editor.selection} /> diff --git a/packages/slate-react/src/components/element.tsx b/packages/slate-react/src/components/element.tsx index 1c5d97313..c6793716f 100644 --- a/packages/slate-react/src/components/element.tsx +++ b/packages/slate-react/src/components/element.tsx @@ -13,12 +13,7 @@ import { NODE_TO_INDEX, KEY_TO_ELEMENT, } from '../utils/weak-maps' -import { - RenderDecorationProps, - RenderElementProps, - RenderMarkProps, -} from './editable' -import { isRangeListEqual } from '../utils/leaf' +import { RenderElementProps, RenderLeafProps } from './editable' /** * Element. @@ -28,18 +23,16 @@ const Element = (props: { decorate: (entry: NodeEntry) => Range[] decorations: Range[] element: SlateElement - renderDecoration?: (props: RenderDecorationProps) => JSX.Element renderElement?: (props: RenderElementProps) => JSX.Element - renderMark?: (props: RenderMarkProps) => JSX.Element + renderLeaf?: (props: RenderLeafProps) => JSX.Element selection: Range | null }) => { const { decorate, decorations, element, - renderDecoration, renderElement = (p: RenderElementProps) => , - renderMark, + renderLeaf, selection, } = props const ref = useRef(null) @@ -53,9 +46,8 @@ const Element = (props: { decorate={decorate} decorations={decorations} node={element} - renderDecoration={renderDecoration} renderElement={renderElement} - renderMark={renderMark} + renderLeaf={renderLeaf} selection={selection} /> ) @@ -141,9 +133,8 @@ const MemoizedElement = React.memo(Element, (prev, next) => { return ( prev.decorate === next.decorate && prev.element === next.element && - prev.renderDecoration === next.renderDecoration && prev.renderElement === next.renderElement && - prev.renderMark === next.renderMark && + prev.renderLeaf === next.renderLeaf && isRangeListEqual(prev.decorations, next.decorations) && (prev.selection === next.selection || (!!prev.selection && @@ -167,4 +158,29 @@ export const DefaultElement = (props: RenderElementProps) => { ) } +/** + * Check if a list of ranges is equal to another. + * + * PERF: this requires the two lists to also have the ranges inside them in the + * same order, but this is an okay constraint for us since decorations are + * kept in order, and the odd case where they aren't is okay to re-render for. + */ + +const isRangeListEqual = (list: Range[], another: Range[]): boolean => { + if (list.length !== another.length) { + return false + } + + for (let i = 0; i < list.length; i++) { + const range = list[i] + const other = another[i] + + if (!Range.equals(range, other)) { + return false + } + } + + return true +} + export default MemoizedElement diff --git a/packages/slate-react/src/components/leaf.tsx b/packages/slate-react/src/components/leaf.tsx index 1c8907daa..8ab9fcd25 100644 --- a/packages/slate-react/src/components/leaf.tsx +++ b/packages/slate-react/src/components/leaf.tsx @@ -2,9 +2,8 @@ import React from 'react' import { Text, Element } from 'slate' import String from './string' -import { Leaf as SlateLeaf } from '../utils/leaf' import { PLACEHOLDER_SYMBOL } from '../utils/weak-maps' -import { RenderDecorationProps, RenderMarkProps } from './editable' +import { RenderLeafProps } from './editable' /** * Individual leaves in a text node with unique formatting. @@ -12,10 +11,9 @@ import { RenderDecorationProps, RenderMarkProps } from './editable' const Leaf = (props: { isLast: boolean - leaf: SlateLeaf + leaf: Text parent: Element - renderDecoration?: (props: RenderDecorationProps) => JSX.Element - renderMark?: (props: RenderMarkProps) => JSX.Element + renderLeaf?: (props: RenderLeafProps) => JSX.Element text: Text }) => { const { @@ -23,117 +21,64 @@ const Leaf = (props: { isLast, text, parent, - renderDecoration = (props: RenderDecorationProps) => ( - - ), - renderMark = (props: RenderMarkProps) => , + renderLeaf = (props: RenderLeafProps) => , } = props let children = ( ) + if (leaf[PLACEHOLDER_SYMBOL]) { + children = ( + + + {leaf.placeholder} + + {children} + + ) + } + // COMPAT: Having the `data-` attributes on these leaf elements ensures that // in certain misbehaving browsers they aren't weirdly cloned/destroyed by // contenteditable behaviors. (2019/05/08) - for (const mark of leaf.marks) { - const ret = renderMark({ - children, - leaf, - mark, - text, - attributes: { - 'data-slate-mark': true, - }, - }) - - if (ret) { - children = ret - } + const attributes: { + 'data-slate-leaf': true + } = { + 'data-slate-leaf': true, } - for (const decoration of leaf.decorations) { - const p = { - children, - decoration, - leaf, - text, - attributes: { - 'data-slate-decoration': true, - }, - } - - if (PLACEHOLDER_SYMBOL in decoration) { - // @ts-ignore - children = - } else { - // @ts-ignore - const ret = renderDecoration(p) - - if (ret) { - children = ret - } - } - } - - return {children} + return renderLeaf({ attributes, children, leaf, text }) } const MemoizedLeaf = React.memo(Leaf, (prev, next) => { return ( next.parent === prev.parent && next.isLast === prev.isLast && - next.renderDecoration === prev.renderDecoration && - next.renderMark === prev.renderMark && + next.renderLeaf === prev.renderLeaf && next.text === prev.text && - SlateLeaf.equals(next.leaf, prev.leaf) + Text.matches(next.leaf, prev.leaf) ) }) /** - * The default custom decoration renderer. + * The default custom leaf renderer. */ -export const DefaultDecoration = (props: RenderDecorationProps) => { +export const DefaultLeaf = (props: RenderLeafProps) => { const { attributes, children } = props return {children} } -/** - * The default custom mark renderer. - */ - -export const DefaultMark = (props: RenderMarkProps) => { - const { attributes, children } = props - return {children} -} - -/** - * A custom decoration for the default placeholder behavior. - */ - -const PlaceholderDecoration = (props: RenderDecorationProps) => { - const { decoration, attributes, children } = props - const { placeholder } = decoration - return ( - - - {placeholder} - - {children} - - ) -} - export default MemoizedLeaf diff --git a/packages/slate-react/src/components/string.tsx b/packages/slate-react/src/components/string.tsx index 9758a095a..b28edfdba 100644 --- a/packages/slate-react/src/components/string.tsx +++ b/packages/slate-react/src/components/string.tsx @@ -2,7 +2,6 @@ import React from 'react' import { Editor, Text, Path, Element, Node } from 'slate' import { ReactEditor, useEditor } from '..' -import { Leaf } from '../utils/leaf' /** * Leaf content strings. @@ -10,7 +9,7 @@ import { Leaf } from '../utils/leaf' const String = (props: { isLast: boolean - leaf: Leaf + leaf: Text parent: Element text: Text }) => { diff --git a/packages/slate-react/src/components/text.tsx b/packages/slate-react/src/components/text.tsx index fd06ea476..ec4597fab 100644 --- a/packages/slate-react/src/components/text.tsx +++ b/packages/slate-react/src/components/text.tsx @@ -2,9 +2,8 @@ import React, { useLayoutEffect, useRef } from 'react' import { Range, Element, Text as SlateText } from 'slate' import Leaf from './leaf' -import { Leaf as SlateLeaf } from '../utils/leaf' import { ReactEditor, useEditor } from '..' -import { RenderDecorationProps, RenderMarkProps } from './editable' +import { RenderLeafProps } from './editable' import { KEY_TO_ELEMENT, NODE_TO_ELEMENT, @@ -19,18 +18,10 @@ const Text = (props: { decorations: Range[] isLast: boolean parent: Element - renderDecoration?: (props: RenderDecorationProps) => JSX.Element - renderMark?: (props: RenderMarkProps) => JSX.Element + renderLeaf?: (props: RenderLeafProps) => JSX.Element text: SlateText }) => { - const { - decorations, - isLast, - parent, - renderDecoration, - renderMark, - text, - } = props + const { decorations, isLast, parent, renderLeaf, text } = props const editor = useEditor() const ref = useRef(null) const leaves = getLeaves(text, decorations) @@ -47,8 +38,7 @@ const Text = (props: { leaf={leaf} text={text} parent={parent} - renderDecoration={renderDecoration} - renderMark={renderMark} + renderLeaf={renderLeaf} /> ) } @@ -76,12 +66,12 @@ const Text = (props: { * Get the leaves for a text node given decorations. */ -const getLeaves = (node: SlateText, decorations: Range[]): SlateLeaf[] => { - const { text, marks } = node - let leaves: SlateLeaf[] = [{ text, marks, decorations: [] }] +const getLeaves = (node: SlateText, decorations: Range[]): SlateText[] => { + let leaves: SlateText[] = [{ ...node }] - const compile = (range: Range, key?: string) => { - const [start, end] = Range.edges(range) + for (const dec of decorations) { + const { anchor, focus, ...rest } = dec + const [start, end] = Range.edges(dec) const next = [] let o = 0 @@ -92,7 +82,7 @@ const getLeaves = (node: SlateText, decorations: Range[]): SlateLeaf[] => { // If the range encompases the entire leaf, add the range. if (start.offset <= offset && end.offset >= offset + length) { - leaf.decorations.push(range) + Object.assign(leaf, rest) next.push(leaf) continue } @@ -115,14 +105,18 @@ const getLeaves = (node: SlateText, decorations: Range[]): SlateLeaf[] => { let after if (end.offset < offset + length) { - ;[middle, after] = SlateLeaf.split(middle, end.offset - offset) + const off = end.offset - offset + after = { ...middle, text: middle.text.slice(off) } + middle = { ...middle, text: middle.text.slice(0, off) } } if (start.offset > offset) { - ;[before, middle] = SlateLeaf.split(middle, start.offset - offset) + const off = start.offset - offset + before = { ...middle, text: middle.text.slice(0, off) } + middle = { ...middle, text: middle.text.slice(off) } } - middle.decorations.push(range) + Object.assign(middle, rest) if (before) { next.push(before) @@ -138,28 +132,16 @@ const getLeaves = (node: SlateText, decorations: Range[]): SlateLeaf[] => { leaves = next } - for (const range of decorations) { - compile(range) - } - return leaves } const MemoizedText = React.memo(Text, (prev, next) => { - if ( + return ( next.parent === prev.parent && next.isLast === prev.isLast && - next.renderDecoration === prev.renderDecoration && - next.renderMark === prev.renderMark && + next.renderLeaf === prev.renderLeaf && next.text === prev.text - ) { - return SlateLeaf.equals( - { ...next.text, decorations: next.decorations }, - { ...prev.text, decorations: prev.decorations } - ) - } - - return false + ) }) export default MemoizedText diff --git a/packages/slate-react/src/index.ts b/packages/slate-react/src/index.ts index 96afb3f55..eeeea9704 100644 --- a/packages/slate-react/src/index.ts +++ b/packages/slate-react/src/index.ts @@ -1,6 +1,6 @@ export * from './components/editable' export { DefaultElement } from './components/element' -export { DefaultMark, DefaultDecoration } from './components/leaf' +export { DefaultLeaf } from './components/leaf' export * from './hooks/use-editor' export * from './hooks/use-focused' export * from './hooks/use-read-only' diff --git a/packages/slate-react/src/utils/leaf.ts b/packages/slate-react/src/utils/leaf.ts deleted file mode 100644 index 2fcb59f40..000000000 --- a/packages/slate-react/src/utils/leaf.ts +++ /dev/null @@ -1,113 +0,0 @@ -import isPlainObject from 'is-plain-object' -import { Range, Mark } from 'slate' - -/** - * The `Leaf` interface represents the individual leaves inside a text node, - * once decorations have been applied. - */ - -interface Leaf { - decorations: Range[] - marks: Mark[] - text: string -} - -namespace Leaf { - /** - * Check if two leaves are equal. - */ - - export const equals = (leaf: Leaf, another: Leaf): boolean => { - return ( - leaf.text === another.text && - leaf.decorations.length === another.decorations.length && - leaf.marks.length === another.marks.length && - leaf.marks.every(m => Mark.exists(m, another.marks)) && - another.marks.every(m => Mark.exists(m, leaf.marks)) && - isRangeListEqual(leaf.decorations, another.decorations) - ) - } - - /** - * Check if a value is a `Leaf` object. - */ - - export const isLeaf = (value: any): value is Leaf => { - return ( - isPlainObject(value) && - typeof value.text === 'string' && - Mark.isMarkSet(value.marks) && - Range.isRangeList(value.decorations) - ) - } - - /** - * Split a leaf into two at an offset. - */ - - export const split = (leaf: Leaf, offset: number): [Leaf, Leaf] => { - return [ - { - text: leaf.text.slice(0, offset), - marks: leaf.marks, - decorations: [...leaf.decorations], - }, - { - text: leaf.text.slice(offset), - marks: leaf.marks, - decorations: [...leaf.decorations], - }, - ] - } -} - -/** - * Check if a list of ranges is equal to another. - * - * PERF: this requires the two lists to also have the ranges inside them in the - * same order, but this is an okay constraint for us since decorations are - * kept in order, and the odd case where they aren't is okay to re-render for. - */ - -const isRangeListEqual = (list: Range[], another: Range[]): boolean => { - if (list.length !== another.length) { - return false - } - - for (let i = 0; i < list.length; i++) { - const range = list[i] - const other = another[i] - - if (!Range.equals(range, other)) { - return false - } - } - - return true -} - -/** - * Check if a map of ranges is equal to another. - */ - -const isRangeMapEqual = ( - map: Record, - another: Record -): boolean => { - if (Object.keys(map).length !== Object.keys(another).length) { - return false - } - - for (const key in map) { - const range = map[key] - const other = another[key] - - if (!Range.equals(range, other)) { - return false - } - } - - return true -} - -export { Leaf, isRangeListEqual, isRangeMapEqual } diff --git a/packages/slate-react/src/utils/weak-maps.ts b/packages/slate-react/src/utils/weak-maps.ts index 1ae71d08b..c2074fb3e 100644 --- a/packages/slate-react/src/utils/weak-maps.ts +++ b/packages/slate-react/src/utils/weak-maps.ts @@ -1,4 +1,4 @@ -import { Node, Ancestor, Editor } from 'slate' +import { Node, Ancestor, Editor, Text } from 'slate' import { Key } from './key' @@ -16,10 +16,11 @@ export const NODE_TO_PARENT: WeakMap = new WeakMap() */ export const EDITOR_TO_ELEMENT: WeakMap = new WeakMap() -export const NODE_TO_ELEMENT: WeakMap = new WeakMap() +export const EDITOR_TO_PLACEHOLDER: WeakMap = new WeakMap() export const ELEMENT_TO_NODE: WeakMap = new WeakMap() -export const NODE_TO_KEY: WeakMap = new WeakMap() export const KEY_TO_ELEMENT: WeakMap = new WeakMap() +export const NODE_TO_ELEMENT: WeakMap = new WeakMap() +export const NODE_TO_KEY: WeakMap = new WeakMap() /** * Weak maps for storing editor-related state. @@ -30,8 +31,4 @@ export const IS_FOCUSED: WeakMap = new WeakMap() export const IS_DRAGGING: WeakMap = new WeakMap() export const IS_CLICKING: WeakMap = new WeakMap() -/** - * Symbols. - */ - -export const PLACEHOLDER_SYMBOL = Symbol('placeholder') +export const PLACEHOLDER_SYMBOL = (Symbol('placeholder') as unknown) as string diff --git a/packages/slate-react/src/with-react.ts b/packages/slate-react/src/with-react.ts index c24b2cf5e..7ba3a680e 100644 --- a/packages/slate-react/src/with-react.ts +++ b/packages/slate-react/src/with-react.ts @@ -16,11 +16,8 @@ export const withReact = (editor: Editor): Editor => { const matches: [Path, Key][] = [] switch (op.type) { - case 'add_mark': case 'insert_text': - case 'remove_mark': case 'remove_text': - case 'set_mark': case 'set_node': { for (const [node, path] of Editor.levels(editor, { at: op.path })) { const key = ReactEditor.findKey(editor, node) diff --git a/packages/slate-schema/src/checkers.ts b/packages/slate-schema/src/checkers.ts index 484ec8151..e0e34c456 100644 --- a/packages/slate-schema/src/checkers.ts +++ b/packages/slate-schema/src/checkers.ts @@ -2,47 +2,14 @@ import { NodeEntry, Node, Text, - Mark, Editor, - MarkEntry, AncestorEntry, Descendant, DescendantEntry, } from 'slate' -import { MarkError, NodeError } from './errors' -import { NodeRule, MarkRule, ChildValidation } from './rules' - -/** - * Check a mark object. - */ - -export const checkMark = ( - editor: Editor, - entry: MarkEntry, - rule: MarkRule -): MarkError | undefined => { - const { validate: v } = rule - const [mark, index, node, path] = entry - - if ('properties' in v) { - for (const k in v.properties) { - const p = v.properties[k] - const value = mark[k] - - if ((typeof p === 'function' && !p(value)) || p !== value) { - return { - code: 'mark_property_invalid', - mark, - index, - node, - path, - property: k, - } - } - } - } -} +import { NodeError } from './errors' +import { NodeRule, ChildValidation } from './rules' /** * Check a node object. @@ -70,15 +37,6 @@ export const checkNode = ( } } - if ('marks' in v && v.marks != null) { - 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 } - } - } - } - if ('text' in v && v.text != null) { const text = Node.text(node) diff --git a/packages/slate-schema/src/errors.ts b/packages/slate-schema/src/errors.ts index e0d97a9d3..1a81dd829 100644 --- a/packages/slate-schema/src/errors.ts +++ b/packages/slate-schema/src/errors.ts @@ -1,4 +1,4 @@ -import { Ancestor, Descendant, Range, Mark, Node, Path, Text } from 'slate' +import { Ancestor, Descendant, Node, Path } from 'slate' export interface ChildInvalidError { code: 'child_invalid' @@ -56,23 +56,6 @@ export interface NodeTextInvalidError { text: string } -export interface MarkInvalidError { - code: 'mark_invalid' - node: Text - path: Path - mark: Mark - index: number -} - -export interface MarkPropertyInvalidError { - code: 'mark_property_invalid' - mark: Mark - index: number - node: Text - path: Path - property: string -} - export interface ParentInvalidError { code: 'parent_invalid' node: Ancestor @@ -86,19 +69,16 @@ export interface PreviousSiblingInvalidError { path: Path } -export type MarkError = MarkPropertyInvalidError - export type NodeError = | ChildInvalidError | ChildMaxInvalidError | ChildMinInvalidError | FirstChildInvalidError | LastChildInvalidError - | MarkInvalidError | NextSiblingInvalidError | NodePropertyInvalidError | NodeTextInvalidError | ParentInvalidError | PreviousSiblingInvalidError -export type SchemaError = MarkError | NodeError +export type SchemaError = NodeError diff --git a/packages/slate-schema/src/rules.ts b/packages/slate-schema/src/rules.ts index d0a4b799d..665a192f1 100644 --- a/packages/slate-schema/src/rules.ts +++ b/packages/slate-schema/src/rules.ts @@ -1,16 +1,5 @@ -import { Editor, NodeMatch, MarkMatch } from 'slate' -import { NodeError, MarkError } from './errors' - -export interface MarkValidation { - properties?: Record -} - -export interface MarkRule { - for: 'mark' - match: MarkMatch - validate: MarkValidation - normalize: (editor: Editor, error: MarkError) => void -} +import { Editor, NodeMatch } from 'slate' +import { NodeError } from './errors' export interface ChildValidation { match?: NodeMatch @@ -22,7 +11,6 @@ export interface NodeValidation { children?: ChildValidation[] first?: NodeMatch last?: NodeMatch - marks?: MarkMatch next?: NodeMatch parent?: NodeMatch previous?: NodeMatch @@ -37,4 +25,4 @@ export interface NodeRule { normalize: (editor: Editor, error: NodeError) => void } -export type SchemaRule = MarkRule | NodeRule +export type SchemaRule = NodeRule diff --git a/packages/slate-schema/src/with-schema.ts b/packages/slate-schema/src/with-schema.ts index b0c886f51..37f4e683c 100644 --- a/packages/slate-schema/src/with-schema.ts +++ b/packages/slate-schema/src/with-schema.ts @@ -1,6 +1,6 @@ import { Editor, Text, NodeEntry } from 'slate' -import { NodeRule, SchemaRule, MarkRule } from './rules' +import { NodeRule, SchemaRule } from './rules' import { NodeError } from './errors' import { checkNode, checkAncestor } from './checkers' @@ -14,23 +14,16 @@ export const withSchema = ( rules: SchemaRule[] = [] ): Editor => { const { normalizeNode } = editor - const markRules: MarkRule[] = [] - const nodeRules: NodeRule[] = [] + const nodeRules: NodeRule[] = rules const parentRules: NodeRule[] = [] for (const rule of rules) { - if (rule.for === 'mark') { - markRules.push(rule) - } else { - nodeRules.push(rule) - - if ( - 'parent' in rule.validate || - 'next' in rule.validate || - 'previous' in rule.validate - ) { - parentRules.push(rule) - } + if ( + 'parent' in rule.validate || + 'next' in rule.validate || + 'previous' in rule.validate + ) { + parentRules.push(rule) } } @@ -136,12 +129,6 @@ export const withSchema = ( break } - case 'mark_invalid': { - const { mark, path } = error - Editor.removeMarks(editor, [mark], { at: path }) - break - } - case 'parent_invalid': { const { path, index } = error const childPath = path.concat(index) diff --git a/packages/slate-schema/test/validations/marks/invalid-empty.js b/packages/slate-schema/test/validations/marks/invalid-empty.js deleted file mode 100644 index e3999bfd2..000000000 --- a/packages/slate-schema/test/validations/marks/invalid-empty.js +++ /dev/null @@ -1,27 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const schema = [ - { - for: 'node', - match: 'element', - validate: { - marks: [], - }, - }, -] - -export const input = ( - - - text - - -) - -export const output = ( - - text - -) diff --git a/packages/slate-schema/test/validations/marks/invalid-match.js b/packages/slate-schema/test/validations/marks/invalid-match.js deleted file mode 100644 index 742c7c097..000000000 --- a/packages/slate-schema/test/validations/marks/invalid-match.js +++ /dev/null @@ -1,27 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const schema = [ - { - for: 'node', - match: 'element', - validate: { - marks: [{ a: true }], - }, - }, -] - -export const input = ( - - - text - - -) - -export const output = ( - - text - -) diff --git a/packages/slate-schema/test/validations/marks/invalid-or.js b/packages/slate-schema/test/validations/marks/invalid-or.js deleted file mode 100644 index b558905f1..000000000 --- a/packages/slate-schema/test/validations/marks/invalid-or.js +++ /dev/null @@ -1,27 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const schema = [ - { - for: 'node', - match: 'element', - validate: { - marks: [{ a: true }, { b: true }], - }, - }, -] - -export const input = ( - - - text - - -) - -export const output = ( - - text - -) diff --git a/packages/slate-schema/test/validations/marks/valid.js b/packages/slate-schema/test/validations/marks/valid.js deleted file mode 100644 index 1a43f3aea..000000000 --- a/packages/slate-schema/test/validations/marks/valid.js +++ /dev/null @@ -1,23 +0,0 @@ -/** @jsx jsx */ - -import { jsx } from 'slate-hyperscript' - -export const schema = [ - { - for: 'node', - match: 'element', - validate: { - marks: [{ a: true }], - }, - }, -] - -export const input = ( - - - text - - -) - -export const output = input diff --git a/packages/slate/src/create-editor.ts b/packages/slate/src/create-editor.ts index 7426178b1..55993d4c5 100755 --- a/packages/slate/src/create-editor.ts +++ b/packages/slate/src/create-editor.ts @@ -88,11 +88,6 @@ export const createEditor = (): Editor => { if (Command.isCoreCommand(command)) { switch (command.type) { - case 'add_mark': { - Editor.addMarks(editor, command.mark) - break - } - case 'delete_backward': { if (selection && Range.isCollapsed(selection)) { Editor.delete(editor, { unit: command.unit, reverse: true }) @@ -136,11 +131,6 @@ export const createEditor = (): Editor => { Editor.insertText(editor, command.text) break } - - case 'remove_mark': { - Editor.removeMarks(editor, [command.mark]) - break - } } } }, @@ -154,7 +144,7 @@ export const createEditor = (): Editor => { // Ensure that block and inline nodes have at least one text child. if (Element.isElement(node) && node.children.length === 0) { - const child = { text: '', marks: [] } + const child = { text: '' } Editor.insertNodes(editor, child, { at: path.concat(0) }) return } @@ -194,23 +184,23 @@ export const createEditor = (): Editor => { // Ensure that inline nodes are surrounded by text nodes. if (editor.isInline(child)) { if (prev == null || !Text.isText(prev)) { - const newChild = { text: '', marks: [] } + const newChild = { text: '' } Editor.insertNodes(editor, newChild, { at: path.concat(n) }) n++ continue } if (isLast) { - const newChild = { text: '', marks: [] } + const newChild = { text: '' } Editor.insertNodes(editor, newChild, { at: path.concat(n + 1) }) n++ continue } } } else { - // Merge adjacent text nodes that are empty or have matching marks. + // Merge adjacent text nodes that are empty or match. if (prev != null && Text.isText(prev)) { - if (Text.matches(child, prev)) { + if (Text.equals(child, prev, { loose: true })) { Editor.mergeNodes(editor, { at: path.concat(n) }) n-- continue @@ -238,11 +228,8 @@ export const createEditor = (): Editor => { const getDirtyPaths = (op: Operation) => { switch (op.type) { - case 'add_mark': case 'insert_text': - case 'remove_mark': case 'remove_text': - case 'set_mark': case 'set_node': { const { path } = op return Path.levels(path) diff --git a/packages/slate/src/index.ts b/packages/slate/src/index.ts index f8b09a8ab..93f35da95 100755 --- a/packages/slate/src/index.ts +++ b/packages/slate/src/index.ts @@ -3,7 +3,6 @@ export * from './interfaces/command' export * from './interfaces/editor' export * from './interfaces/element' export * from './interfaces/location' -export * from './interfaces/mark' export * from './interfaces/node' export * from './interfaces/operation' export * from './interfaces/path' diff --git a/packages/slate/src/interfaces/command.ts b/packages/slate/src/interfaces/command.ts index f032908ba..f3ee7b099 100644 --- a/packages/slate/src/interfaces/command.ts +++ b/packages/slate/src/interfaces/command.ts @@ -1,5 +1,5 @@ import isPlainObject from 'is-plain-object' -import { Mark, Node, Range } from '..' +import { Node } from '..' /** * `Command` objects represent an action that a user is taking on the editor. @@ -20,32 +20,18 @@ export const Command = { return isPlainObject(value) && typeof value.type === 'string' }, - /** - * Check if a value is an `AddMarkCommand` object. - */ - - isAddMarkCommand(value: any): value is AddMarkCommand { - return ( - Command.isCommand(value) && - value.type === 'add_mark' && - Mark.isMark(value.mark) - ) - }, - /** * Check if a value is a `CoreCommand` object. */ isCoreCommand(value: any): value is CoreCommand { return ( - Command.isAddMarkCommand(value) || Command.isDeleteBackwardCommand(value) || Command.isDeleteForwardCommand(value) || Command.isDeleteFragmentCommand(value) || Command.isInsertTextCommand(value) || Command.isInsertFragmentCommand(value) || - Command.isInsertBreakCommand(value) || - Command.isRemoveMarkCommand(value) + Command.isInsertBreakCommand(value) ) }, @@ -124,27 +110,6 @@ export const Command = { typeof value.text === 'string' ) }, - - /** - * Check if a value is a `RemoveMarkCommand` object. - */ - - isRemoveMarkCommand(value: any): value is RemoveMarkCommand { - return ( - Command.isCommand(value) && - value.type === 'remove_mark' && - Mark.isMark(value.mark) - ) - }, -} - -/** - * The `AddMarkCommand` adds a mark to the current selection. - */ - -export interface AddMarkCommand { - type: 'add_mark' - mark: Mark } /** @@ -210,22 +175,12 @@ export interface InsertTextCommand { text: string } -/** - * The `RemoveMarkCommand` removes a mark in the current selection. - */ - -export interface RemoveMarkCommand { - type: 'remove_mark' - mark: Mark -} - /** * The `CoreCommand` union is a set of all of the commands that are recognized * by Slate's "core" out of the box. */ export type CoreCommand = - | AddMarkCommand | DeleteBackwardCommand | DeleteForwardCommand | DeleteFragmentCommand @@ -233,4 +188,3 @@ export type CoreCommand = | InsertFragmentCommand | InsertNodeCommand | InsertTextCommand - | RemoveMarkCommand diff --git a/packages/slate/src/interfaces/editor/index.ts b/packages/slate/src/interfaces/editor/index.ts index 56cebb4c5..d6a8aafab 100755 --- a/packages/slate/src/interfaces/editor/index.ts +++ b/packages/slate/src/interfaces/editor/index.ts @@ -4,8 +4,6 @@ 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' import { RangeQueries } from './queries/range' @@ -35,8 +33,6 @@ export const Editor = { ...GeneralQueries, ...GeneralTransforms, ...LocationQueries, - ...MarkQueries, - ...MarkTransforms, ...NodeQueries, ...NodeTransforms, ...RangeQueries, diff --git a/packages/slate/src/interfaces/editor/queries/location.ts b/packages/slate/src/interfaces/editor/queries/location.ts index 53ac6398c..8735bfbed 100644 --- a/packages/slate/src/interfaces/editor/queries/location.ts +++ b/packages/slate/src/interfaces/editor/queries/location.ts @@ -9,8 +9,6 @@ import { Element, ElementEntry, Location, - Mark, - MarkEntry, Node, NodeEntry, NodeMatch, @@ -21,46 +19,8 @@ import { Text, TextEntry, } from '../../..' -import { MarkMatch } from '../../mark' export const LocationQueries = { - /** - * Get the marks that are "active" at a location. These are the - * marks that will be added to any text that is inserted. - * - * The `union: true` option can be passed to create a union of marks across - * the text nodes in the selection, instead of creating an intersection, which - * is the default. - * - * Note: to obey common rich text behavior, if the selection is collapsed at - * the start of a text node and there are previous text nodes in the same - * block, it will carry those marks forward from the previous text node. This - * allows for continuation of marks from previous words. - */ - - activeMarks( - editor: Editor, - options: { - at?: Location - union?: boolean - hanging?: boolean - } = {} - ): Mark[] { - warning( - false, - 'The `Editor.activeMarks` helper is deprecated, use `Editor.marks` instead.' - ) - - return Array.from( - Editor.marks(editor, { - at: options.at, - mode: options.union ? 'distinct' : 'universal', - continuing: true, - }), - ([m]) => m - ) - }, - /** * Get the point after a location. */ @@ -305,116 +265,6 @@ export const LocationQueries = { yield* levels }, - /** - * Iterate through all of the text nodes in the Editor. - */ - - *marks( - editor: Editor, - options: { - at?: Location - match?: MarkMatch - mode?: 'all' | 'first' | 'distinct' | 'universal' - reverse?: boolean - continuing?: boolean - } = {} - ): Iterable { - const { match, mode = 'all', reverse = false, continuing = false } = options - let { at = editor.selection } = options - - if (!at) { - return - } - - // If the range is collapsed at the start of a text node, it should continue - // the marks from the previous text node in the same block. - if ( - continuing && - Range.isRange(at) && - Range.isCollapsed(at) && - at.anchor.offset === 0 - ) { - const { anchor } = at - const prev = Editor.previous(editor, anchor, 'text') - - if (prev && Path.isSibling(anchor.path, prev[1])) { - const [, prevPath] = prev - at = Editor.range(editor, prevPath) - } - } - - const universalMarks: Mark[] = [] - const distinctMarks: Mark[] = [] - const universalEntries: MarkEntry[] = [] - let first = true - - for (const entry of Editor.texts(editor, { reverse, at })) { - const [node, path] = entry - - if (mode === 'universal') { - if (first) { - for (let i = 0; i < node.marks.length; i++) { - const mark = node.marks[i] - const markEntry: MarkEntry = [mark, i, node, path] - - if (match == null || Editor.isMarkMatch(editor, markEntry, match)) { - universalMarks.push(mark) - universalEntries.push(markEntry) - } - } - - first = false - continue - } - - // PERF: If we're in universal mode and the eligible marks hits zero - // it can never increase again, so we can exit early. - if (universalMarks.length === 0) { - return - } - - for (let i = universalMarks.length - 1; i >= 0; i--) { - const existing = universalMarks[i] - - if (!Mark.exists(existing, node.marks)) { - universalMarks.splice(i, 1) - universalEntries.splice(i, 1) - } - } - } else { - for (let index = 0; index < node.marks.length; index++) { - const mark = node.marks[index] - const markEntry: MarkEntry = [mark, index, node, path] - - if (match != null && !Editor.isMarkMatch(editor, markEntry, match)) { - continue - } - - if (mode === 'distinct') { - if (Mark.exists(mark, distinctMarks)) { - continue - } else { - distinctMarks.push(mark) - } - } - - yield markEntry - - // After matching a mark, if we're in first mode skip to the next text. - if (mode === 'first') { - break - } - } - } - } - - // In universal mode, the marks are collected while iterating and we can - // only be certain of which are universal when we've finished. - if (mode === 'universal') { - yield* universalEntries - } - }, - /** * Get the first matching node in a single branch of the document. */ diff --git a/packages/slate/src/interfaces/editor/queries/mark.ts b/packages/slate/src/interfaces/editor/queries/mark.ts deleted file mode 100644 index cb9f55b2d..000000000 --- a/packages/slate/src/interfaces/editor/queries/mark.ts +++ /dev/null @@ -1,17 +0,0 @@ -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) - } - }, -} diff --git a/packages/slate/src/interfaces/editor/transforms/general.ts b/packages/slate/src/interfaces/editor/transforms/general.ts index a993c9812..4aecce673 100755 --- a/packages/slate/src/interfaces/editor/transforms/general.ts +++ b/packages/slate/src/interfaces/editor/transforms/general.ts @@ -2,7 +2,6 @@ import { createDraft, finishDraft, isDraft } from 'immer' import { Node, Editor, - Mark, Range, Point, Text, @@ -68,17 +67,6 @@ export const GeneralTransforms = { let selection = editor.selection && createDraft(editor.selection) switch (op.type) { - case 'add_mark': { - const { path, mark } = op - const node = Node.leaf(editor, path) - - if (!Mark.exists(mark, node.marks)) { - node.marks.push(mark) - } - - break - } - case 'insert_node': { const { path, node } = op const parent = Node.parent(editor, path) @@ -174,20 +162,6 @@ export const GeneralTransforms = { break } - case 'remove_mark': { - const { path, mark } = op - const node = Node.leaf(editor, path) - - for (let i = 0; i < node.marks.length; i++) { - if (Mark.matches(node.marks[i], mark)) { - node.marks.splice(i, 1) - break - } - } - - break - } - case 'remove_node': { const { path } = op const index = path[path.length - 1] @@ -238,20 +212,6 @@ export const GeneralTransforms = { break } - case 'set_mark': { - const { path, properties, newProperties } = op - const node = Node.leaf(editor, path) - - for (const mark of node.marks) { - if (Mark.matches(mark, properties)) { - Object.assign(mark, newProperties) - break - } - } - - break - } - case 'set_node': { const { path, newProperties } = op @@ -260,7 +220,21 @@ export const GeneralTransforms = { } const node = Node.get(editor, path) - Object.assign(node, newProperties) + + for (const key in newProperties) { + if (key === 'children' || key === 'text') { + throw new Error(`Cannot set the "${key}" property of nodes!`) + } + + const value = newProperties[key] + + if (value == null) { + delete node[key] + } else { + node[key] = value + } + } + break } diff --git a/packages/slate/src/interfaces/editor/transforms/mark.ts b/packages/slate/src/interfaces/editor/transforms/mark.ts deleted file mode 100644 index a2ad230c1..000000000 --- a/packages/slate/src/interfaces/editor/transforms/mark.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { Editor, Mark, Location, Range } from '../../..' - -export const MarkTransforms = { - /** - * Add a set of marks to the text nodes at a location. - */ - - addMarks( - editor: Editor, - mark: Mark | Mark[], - options: { - at?: Location - hanging?: boolean - } = {} - ) { - Editor.withoutNormalizing(editor, () => { - const at = splitLocation(editor, options) - - if (!at) { - return - } - - // De-dupe the marks being added to ensure the set is unique. - const marks = Array.isArray(mark) ? mark : [mark] - const set: Mark[] = [] - - for (const m of marks) { - if (!Mark.exists(m, set)) { - set.push(m) - } - } - - for (const [node, path] of Editor.texts(editor, { at })) { - for (const m of set) { - if (!Mark.exists(m, node.marks)) { - editor.apply({ type: 'add_mark', path, mark: m }) - } - } - } - }) - }, - - removeMarks( - editor: Editor, - mark: Mark | Mark[], - options: { - at?: Location - hanging?: boolean - } = {} - ) { - Editor.withoutNormalizing(editor, () => { - const at = splitLocation(editor, options) - - if (at) { - const marks = Array.isArray(mark) ? mark : [mark] - for (const [m, i, node, path] of Editor.marks(editor, { at })) { - if (Mark.exists(m, marks)) { - editor.apply({ type: 'remove_mark', path, mark: m }) - } - } - } - }) - }, - - setMarks( - editor: Editor, - mark: Mark | Mark[], - props: Partial, - options: { - at?: Location - hanging?: boolean - } = {} - ) { - Editor.withoutNormalizing(editor, () => { - const at = splitLocation(editor, options) - - if (at) { - const marks = Array.isArray(mark) ? mark : [mark] - for (const [m, i, node, path] of Editor.marks(editor, { at })) { - if (Mark.exists(m, marks)) { - const newProps = {} - - for (const k in props) { - if (props[k] !== m[k]) { - newProps[k] = props[k] - } - } - - if (Object.keys(newProps).length > 0) { - editor.apply({ - type: 'set_mark', - path, - properties: m, - newProperties: newProps, - }) - } - } - } - } - }) - }, -} - -/** - * Split the text nodes at a range's edges to prepare for adding/removing marks. - */ - -const splitLocation = ( - editor: Editor, - options: { - at?: Location - hanging?: boolean - } = {} -): Location | undefined => { - let { at = editor.selection, hanging = false } = options - - if (!at) { - return - } - - if (Range.isRange(at)) { - if (!hanging) { - at = Editor.unhangRange(editor, at) - } - - const rangeRef = Editor.rangeRef(editor, at, { affinity: 'inward' }) - const [start, end] = Range.edges(at) - Editor.splitNodes(editor, { at: end, match: 'text' }) - Editor.splitNodes(editor, { at: start, match: 'text' }) - const range = rangeRef.unref()! - - if (options.at == null) { - Editor.select(editor, range) - } - - return range - } - - return at -} diff --git a/packages/slate/src/interfaces/editor/transforms/node.ts b/packages/slate/src/interfaces/editor/transforms/node.ts index f2a1ae835..f16245121 100644 --- a/packages/slate/src/interfaces/editor/transforms/node.ts +++ b/packages/slate/src/interfaces/editor/transforms/node.ts @@ -270,7 +270,7 @@ export const NodeTransforms = { // Ensure that the nodes are equivalent, and figure out what the position // and extra properties of the merge will be. if (Text.isText(node) && Text.isText(prevNode)) { - const { text, marks, ...rest } = node + const { text, ...rest } = node position = prevNode.text.length properties = rest as Partial } else if (Element.isElement(node) && Element.isElement(prevNode)) { @@ -413,7 +413,7 @@ export const NodeTransforms = { }, /** - * Set new properties on the nodes ... + * Set new properties on the nodes at a location. */ setNodes( @@ -422,12 +422,14 @@ export const NodeTransforms = { options: { at?: Location match?: NodeMatch + mode?: 'all' | 'highest' hanging?: boolean + split?: boolean } = {} ) { Editor.withoutNormalizing(editor, () => { let { match, at = editor.selection } = options - const { hanging = false } = options + const { hanging = false, mode = 'highest', split = false } = options if (match == null) { if (Path.isPath(at)) { @@ -446,21 +448,29 @@ export const NodeTransforms = { at = Editor.unhangRange(editor, at) } - for (const [node, path] of Editor.nodes(editor, { - at, - match, - mode: 'highest', - })) { + if (split && Range.isRange(at)) { + const rangeRef = Editor.rangeRef(editor, at, { affinity: 'inward' }) + const [start, end] = Range.edges(at) + Editor.splitNodes(editor, { at: end, match }) + Editor.splitNodes(editor, { at: start, match }) + at = rangeRef.unref()! + + if (options.at == null) { + Editor.select(editor, at) + } + } + + for (const [node, path] of Editor.nodes(editor, { at, match, mode })) { const properties: Partial = {} const newProperties: Partial = {} + // You can't set properties on the editor node. + if (path.length === 0) { + continue + } + for (const k in props) { - if ( - k === 'marks' || - k === 'children' || - k === 'selection' || - k === 'text' - ) { + if (k === 'children' || k === 'text') { continue } @@ -540,7 +550,7 @@ export const NodeTransforms = { let after = Editor.after(editor, voidPath) if (!after) { - const text = { text: '', marks: [] } + const text = { text: '' } const afterPath = Path.next(voidPath) Editor.insertNodes(editor, text, { at: afterPath }) after = Editor.point(editor, afterPath)! @@ -581,7 +591,7 @@ export const NodeTransforms = { if (always || !beforeRef || !Editor.isEdge(editor, point, path)) { split = true - const { text, marks, children, ...properties } = node + const { text, children, ...properties } = node editor.apply({ type: 'split_node', path, diff --git a/packages/slate/src/interfaces/mark.ts b/packages/slate/src/interfaces/mark.ts deleted file mode 100755 index 778ac83c6..000000000 --- a/packages/slate/src/interfaces/mark.ts +++ /dev/null @@ -1,68 +0,0 @@ -import isPlainObject from 'is-plain-object' -import { Path, Text } from '..' - -/** - * `Mark` objects represent formatting that is applied to text in a Slate - * document. They appear in leaf text nodes in the document. - */ - -export interface Mark { - [key: string]: any -} - -export const Mark = { - /** - * Check if a mark exists in a set of marks. - */ - - exists(mark: Mark, marks: Mark[]): boolean { - return !!marks.find(f => Mark.matches(f, mark)) - }, - - /** - * Check if a value implements the `Mark` interface. - */ - - isMark(value: any): value is Mark { - return isPlainObject(value) - }, - - /** - * Check if a value is an array of `Mark` objects. - */ - - isMarkSet(value: any): value is Mark[] { - return Array.isArray(value) && (value.length === 0 || Mark.isMark(value[0])) - }, - - /** - * Check if a mark matches set of properties. - */ - - matches(mark: Mark, props: Partial): boolean { - for (const key in props) { - if (mark[key] !== props[key]) { - return false - } - } - - return true - }, -} - -/** - * `MarkEntry` tuples are returned when iterating through the marks in a text - * node. They include the index of the mark in the text node's marks array, as - * well as the text node and its path in the root node. - */ - -export type MarkEntry = [Mark, number, Text, Path] - -/** - * `MarkMatch` values are used as shorthands for matching mark objects. - */ - -export type MarkMatch = - | Partial - | ((entry: MarkEntry) => boolean) - | MarkMatch[] diff --git a/packages/slate/src/interfaces/node.ts b/packages/slate/src/interfaces/node.ts index a137c7eb0..30fd05919 100755 --- a/packages/slate/src/interfaces/node.ts +++ b/packages/slate/src/interfaces/node.ts @@ -1,14 +1,5 @@ import { produce } from 'immer' -import { - Editor, - Element, - ElementEntry, - MarkEntry, - Path, - Range, - Text, - TextEntry, -} from '..' +import { Editor, Element, ElementEntry, Path, Range, Text, TextEntry } from '..' /** * The `Node` union type represents all of the different types of nodes that @@ -372,27 +363,6 @@ export const Node = { } }, - /** - * Return an iterable of all the marks in all of the text nodes in a root node. - */ - - *marks( - root: Node, - options: { - from?: Path - to?: Path - reverse?: boolean - pass?: (node: NodeEntry) => boolean - } = {} - ): Iterable { - for (const [node, path] of Node.texts(root, options)) { - for (let i = 0; i < node.marks.length; i++) { - const mark = node.marks[i] - yield [mark, i, node, path] - } - } - }, - /** * Return an iterable of all the node entries of a root node. Each entry is * returned as a `[Node, Path]` tuple, with the path referring to the node's diff --git a/packages/slate/src/interfaces/operation.ts b/packages/slate/src/interfaces/operation.ts index adc00d432..3617408b2 100755 --- a/packages/slate/src/interfaces/operation.ts +++ b/packages/slate/src/interfaces/operation.ts @@ -1,13 +1,6 @@ -import { Mark, Node, Path, Range } from '..' +import { Node, Path, Range } from '..' import isPlainObject from 'is-plain-object' -type AddMarkOperation = { - type: 'add_mark' - path: Path - mark: Mark - [key: string]: any -} - type InsertNodeOperation = { type: 'insert_node' path: Path @@ -39,13 +32,6 @@ type MoveNodeOperation = { [key: string]: any } -type RemoveMarkOperation = { - type: 'remove_mark' - path: Path - mark: Mark - [key: string]: any -} - type RemoveNodeOperation = { type: 'remove_node' path: Path @@ -61,14 +47,6 @@ type RemoveTextOperation = { [key: string]: any } -type SetMarkOperation = { - type: 'set_mark' - path: Path - properties: Partial - newProperties: Partial - [key: string]: any -} - type SetNodeOperation = { type: 'set_node' path: Path @@ -113,11 +91,7 @@ type SplitNodeOperation = { * collaboration, and other features. */ -type Operation = - | NodeOperation - | MarkOperation - | SelectionOperation - | TextOperation +type Operation = NodeOperation | SelectionOperation | TextOperation type NodeOperation = | InsertNodeOperation @@ -127,8 +101,6 @@ type NodeOperation = | SetNodeOperation | SplitNodeOperation -type MarkOperation = AddMarkOperation | RemoveMarkOperation | SetMarkOperation - type SelectionOperation = SetSelectionOperation type TextOperation = InsertTextOperation | RemoveTextOperation @@ -142,14 +114,6 @@ const Operation = { return Operation.isOperation(value) && value.type.endsWith('_node') }, - /** - * Check of a value is a `MarkOperation` object. - */ - - isMarkOperation(value: any): value is MarkOperation { - return Operation.isOperation(value) && value.type.endsWith('_mark') - }, - /** * Check of a value is an `Operation` object. */ @@ -160,10 +124,6 @@ const Operation = { } switch (value.type) { - case 'add_mark': { - return Path.isPath(value.path) && Mark.isMark(value.mark) - } - case 'insert_node': { return Path.isPath(value.path) && Node.isNode(value.node) } @@ -189,10 +149,6 @@ const Operation = { return Path.isPath(value.path) && Path.isPath(value.newPath) } - case 'remove_mark': { - return Path.isPath(value.path) && Mark.isMark(value.mark) - } - case 'remove_node': { return Path.isPath(value.path) && Node.isNode(value.node) } @@ -205,14 +161,6 @@ const Operation = { ) } - case 'set_mark': { - return ( - Path.isPath(value.path) && - isPlainObject(value.properties) && - isPlainObject(value.newProperties) - ) - } - case 'set_node': { return ( Path.isPath(value.path) && @@ -285,10 +233,6 @@ const Operation = { inverse(op: Operation): Operation { switch (op.type) { - case 'add_mark': { - return { ...op, type: 'remove_mark' } - } - case 'insert_node': { return { ...op, type: 'remove_node' } } @@ -317,10 +261,6 @@ const Operation = { return { ...op, path: inversePath, newPath: inverseNewPath } } - case 'remove_mark': { - return { ...op, type: 'add_mark' } - } - case 'remove_node': { return { ...op, type: 'insert_node' } } @@ -329,7 +269,6 @@ const Operation = { return { ...op, type: 'insert_text' } } - case 'set_mark': case 'set_node': { const { properties, newProperties } = op return { ...op, properties: newProperties, newProperties: properties } @@ -363,15 +302,12 @@ const Operation = { } export { - AddMarkOperation, InsertNodeOperation, InsertTextOperation, MergeNodeOperation, MoveNodeOperation, - RemoveMarkOperation, RemoveNodeOperation, RemoveTextOperation, - SetMarkOperation, SetNodeOperation, SetSelectionOperation, SplitNodeOperation, diff --git a/packages/slate/src/interfaces/text.ts b/packages/slate/src/interfaces/text.ts index f9665b41c..bdcad9cc8 100755 --- a/packages/slate/src/interfaces/text.ts +++ b/packages/slate/src/interfaces/text.ts @@ -1,29 +1,58 @@ import isPlainObject from 'is-plain-object' -import { Mark, Path } from '..' +import { Path } from '..' /** * `Text` objects represent the nodes that contain the actual text content of a - * Slate document along with any formatting marks. They are always leaf nodes in - * the document tree as they cannot contain any children. + * Slate document along with any formatting properties. They are always leaf + * nodes in the document tree as they cannot contain any children. */ export interface Text { text: string - marks: Mark[] [key: string]: any } export const Text = { + /** + * Check if two text nodes are equal. + */ + + equals( + text: Text, + another: Text, + options: { loose?: boolean } = {} + ): boolean { + const { loose = false } = options + + for (const key in text) { + if (loose && key === 'text') { + continue + } + + if (text[key] !== another[key]) { + return false + } + } + + for (const key in another) { + if (loose && key === 'text') { + continue + } + + if (text[key] !== another[key]) { + return false + } + } + + return true + }, + /** * Check if a value implements the `Text` interface. */ isText(value: any): value is Text { - return ( - isPlainObject(value) && - typeof value.text === 'string' && - Array.isArray(value.marks) - ) + return isPlainObject(value) && typeof value.text === 'string' }, /** @@ -38,8 +67,7 @@ export const Text = { * Check if an text matches set of properties. * * Note: this is for matching custom properties, and it does not ensure that - * the `text` property are two nodes equal. However, if `marks` are passed it - * will ensure that the set of marks is exactly equal. + * the `text` property are two nodes equal. */ matches(text: Text, props: Partial): boolean { @@ -48,30 +76,6 @@ export const Text = { continue } - if (key === 'marks' && props.marks != null) { - const existing = text.marks - const { marks } = props - - // PERF: If the lengths aren't the same, we know it's not a match. - if (existing.length !== marks.length) { - return false - } - - for (const m of existing) { - if (!Mark.exists(m, marks)) { - return false - } - } - - for (const m of marks) { - if (!Mark.exists(m, existing)) { - return false - } - } - - continue - } - if (text[key] !== props[key]) { return false } diff --git a/packages/slate/test/interfaces/Element/isElement/text.js b/packages/slate/test/interfaces/Element/isElement/text.js index 9cad04b55..db753a2c6 100644 --- a/packages/slate/test/interfaces/Element/isElement/text.js +++ b/packages/slate/test/interfaces/Element/isElement/text.js @@ -2,7 +2,6 @@ import { Element } from 'slate' export const input = { text: '', - marks: [], } export const test = value => { diff --git a/packages/slate/test/interfaces/Element/isElementList/full-text.js b/packages/slate/test/interfaces/Element/isElementList/full-text.js index 16b0873a1..5cad89460 100644 --- a/packages/slate/test/interfaces/Element/isElementList/full-text.js +++ b/packages/slate/test/interfaces/Element/isElementList/full-text.js @@ -3,7 +3,6 @@ import { Element } from 'slate' export const input = [ { text: '', - marks: [], }, ] diff --git a/packages/slate/test/interfaces/Element/matches/custom-prop-partial-match.js b/packages/slate/test/interfaces/Element/matches/custom-prop-partial-match.js deleted file mode 100644 index cda750d7a..000000000 --- a/packages/slate/test/interfaces/Element/matches/custom-prop-partial-match.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - element: { children: [], type: 'bold', other: true }, - props: { type: 'bold' }, -} - -export const test = ({ element, props }) => { - return Mark.matches(element, props) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Element/matches/empty-partial-match.js b/packages/slate/test/interfaces/Element/matches/empty-partial-match.js deleted file mode 100644 index 5ffaceae5..000000000 --- a/packages/slate/test/interfaces/Element/matches/empty-partial-match.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - element: { children: [], type: 'bold' }, - props: {}, -} - -export const test = ({ mark, props }) => { - return Mark.matches(mark, props) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/exists/custom-prop-exists.js b/packages/slate/test/interfaces/Mark/exists/custom-prop-exists.js deleted file mode 100644 index ebd3b973c..000000000 --- a/packages/slate/test/interfaces/Mark/exists/custom-prop-exists.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: { type: 'bold' }, - marks: [{ type: 'bold' }], -} - -export const test = ({ mark, marks }) => { - return Mark.exists(mark, marks) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/exists/custom-prop-not-exists.js b/packages/slate/test/interfaces/Mark/exists/custom-prop-not-exists.js deleted file mode 100644 index a1921b3fd..000000000 --- a/packages/slate/test/interfaces/Mark/exists/custom-prop-not-exists.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: { type: 'bold' }, - marks: [{ type: 'italic' }], -} - -export const test = ({ mark, marks }) => { - return Mark.exists(mark, marks) -} - -export const output = false diff --git a/packages/slate/test/interfaces/Mark/exists/custom-prop-partial-exists.js b/packages/slate/test/interfaces/Mark/exists/custom-prop-partial-exists.js deleted file mode 100644 index 42100c998..000000000 --- a/packages/slate/test/interfaces/Mark/exists/custom-prop-partial-exists.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: { type: 'bold' }, - marks: [{ type: 'bold', other: true }], -} - -export const test = ({ mark, marks }) => { - return Mark.exists(mark, marks) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/exists/empty-mark-exists.js b/packages/slate/test/interfaces/Mark/exists/empty-mark-exists.js deleted file mode 100644 index 9dbe7b52d..000000000 --- a/packages/slate/test/interfaces/Mark/exists/empty-mark-exists.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: {}, - marks: [{}], -} - -export const test = ({ mark, marks }) => { - return Mark.exists(mark, marks) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/exists/empty-mark-partial-exists.js b/packages/slate/test/interfaces/Mark/exists/empty-mark-partial-exists.js deleted file mode 100644 index 481c6f05c..000000000 --- a/packages/slate/test/interfaces/Mark/exists/empty-mark-partial-exists.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: {}, - marks: [{ type: 'bold' }], -} - -export const test = ({ mark, marks }) => { - return Mark.exists(mark, marks) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/exists/empty-set.js b/packages/slate/test/interfaces/Mark/exists/empty-set.js deleted file mode 100644 index 0acc2aba0..000000000 --- a/packages/slate/test/interfaces/Mark/exists/empty-set.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: {}, - marks: [], -} - -export const test = ({ mark, marks }) => { - return Mark.exists(mark, marks) -} - -export const output = false diff --git a/packages/slate/test/interfaces/Mark/isMark/boolean.js b/packages/slate/test/interfaces/Mark/isMark/boolean.js deleted file mode 100644 index 9eda0c91a..000000000 --- a/packages/slate/test/interfaces/Mark/isMark/boolean.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Mark } from 'slate' - -export const input = true - -export const test = value => { - return Mark.isMark(value) -} - -export const output = false diff --git a/packages/slate/test/interfaces/Mark/isMark/custom-property.js b/packages/slate/test/interfaces/Mark/isMark/custom-property.js deleted file mode 100644 index 1fef893a9..000000000 --- a/packages/slate/test/interfaces/Mark/isMark/custom-property.js +++ /dev/null @@ -1,11 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - custom: 'value', -} - -export const test = value => { - return Mark.isMark(value) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/isMark/object.js b/packages/slate/test/interfaces/Mark/isMark/object.js deleted file mode 100644 index 21c32daf2..000000000 --- a/packages/slate/test/interfaces/Mark/isMark/object.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Mark } from 'slate' - -export const input = {} - -export const test = value => { - return Mark.isMark(value) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/isMarkSet/boolean.js b/packages/slate/test/interfaces/Mark/isMarkSet/boolean.js deleted file mode 100644 index 27c5e6344..000000000 --- a/packages/slate/test/interfaces/Mark/isMarkSet/boolean.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Mark } from 'slate' - -export const input = true - -export const test = value => { - return Mark.isMarkSet(value) -} - -export const output = false diff --git a/packages/slate/test/interfaces/Mark/isMarkSet/empty.js b/packages/slate/test/interfaces/Mark/isMarkSet/empty.js deleted file mode 100644 index a1469fe8f..000000000 --- a/packages/slate/test/interfaces/Mark/isMarkSet/empty.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Mark } from 'slate' - -export const input = [] - -export const test = value => { - return Mark.isMarkSet(value) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/isMarkSet/full.js b/packages/slate/test/interfaces/Mark/isMarkSet/full.js deleted file mode 100644 index 5e3e8faa1..000000000 --- a/packages/slate/test/interfaces/Mark/isMarkSet/full.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Mark } from 'slate' - -export const input = [{}] - -export const test = value => { - return Mark.isMarkSet(value) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/isMarkSet/object.js b/packages/slate/test/interfaces/Mark/isMarkSet/object.js deleted file mode 100644 index 424d46d24..000000000 --- a/packages/slate/test/interfaces/Mark/isMarkSet/object.js +++ /dev/null @@ -1,9 +0,0 @@ -import { Mark } from 'slate' - -export const input = {} - -export const test = value => { - return Mark.isMarkSet(value) -} - -export const output = false diff --git a/packages/slate/test/interfaces/Mark/matches/custom-prop-match.js b/packages/slate/test/interfaces/Mark/matches/custom-prop-match.js deleted file mode 100644 index b8c771524..000000000 --- a/packages/slate/test/interfaces/Mark/matches/custom-prop-match.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: { type: 'bold' }, - props: { type: 'bold' }, -} - -export const test = ({ mark, props }) => { - return Mark.matches(mark, props) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/matches/custom-prop-not-match.js b/packages/slate/test/interfaces/Mark/matches/custom-prop-not-match.js deleted file mode 100644 index 60b00f680..000000000 --- a/packages/slate/test/interfaces/Mark/matches/custom-prop-not-match.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: { type: 'bold' }, - props: { type: 'italic' }, -} - -export const test = ({ mark, props }) => { - return Mark.matches(mark, props) -} - -export const output = false diff --git a/packages/slate/test/interfaces/Mark/matches/custom-prop-partial-match.js b/packages/slate/test/interfaces/Mark/matches/custom-prop-partial-match.js deleted file mode 100644 index 40ad88d08..000000000 --- a/packages/slate/test/interfaces/Mark/matches/custom-prop-partial-match.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: { type: 'bold', other: true }, - props: { type: 'bold' }, -} - -export const test = ({ mark, props }) => { - return Mark.matches(mark, props) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/matches/empty-match.js b/packages/slate/test/interfaces/Mark/matches/empty-match.js deleted file mode 100644 index 0578f19ac..000000000 --- a/packages/slate/test/interfaces/Mark/matches/empty-match.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: {}, - props: {}, -} - -export const test = ({ mark, props }) => { - return Mark.matches(mark, props) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Mark/matches/empty-partial-match.js b/packages/slate/test/interfaces/Mark/matches/empty-partial-match.js deleted file mode 100644 index 5cb2bdaab..000000000 --- a/packages/slate/test/interfaces/Mark/matches/empty-partial-match.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Mark } from 'slate' - -export const input = { - mark: { type: 'bold' }, - props: {}, -} - -export const test = ({ mark, props }) => { - return Mark.matches(mark, props) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Node/isNode/text.js b/packages/slate/test/interfaces/Node/isNode/text.js index 49543108d..55f1a9a89 100644 --- a/packages/slate/test/interfaces/Node/isNode/text.js +++ b/packages/slate/test/interfaces/Node/isNode/text.js @@ -2,7 +2,6 @@ import { Node } from 'slate' export const input = { text: '', - marks: [], } export const test = value => { diff --git a/packages/slate/test/interfaces/Node/isNodeList/full-text.js b/packages/slate/test/interfaces/Node/isNodeList/full-text.js index c78b6f122..0d0131e53 100644 --- a/packages/slate/test/interfaces/Node/isNodeList/full-text.js +++ b/packages/slate/test/interfaces/Node/isNodeList/full-text.js @@ -3,7 +3,6 @@ import { Node } from 'slate' export const input = [ { text: '', - marks: [], }, ] diff --git a/packages/slate/test/interfaces/Node/marks/all.js b/packages/slate/test/interfaces/Node/marks/all.js deleted file mode 100644 index 5ca70867e..000000000 --- a/packages/slate/test/interfaces/Node/marks/all.js +++ /dev/null @@ -1,22 +0,0 @@ -/** @jsx jsx */ - -import { Node } from 'slate' -import { jsx } from 'slate-hyperscript' - -export const input = ( - - - one - two - - -) - -export const test = value => { - return Array.from(Node.marks(value)) -} - -export const output = [ - [{ key: 'a' }, 0, one, [0, 0]], - [{ key: 'b' }, 0, two, [0, 1]], -] diff --git a/packages/slate/test/interfaces/Node/marks/from.js b/packages/slate/test/interfaces/Node/marks/from.js deleted file mode 100644 index e9aac3f63..000000000 --- a/packages/slate/test/interfaces/Node/marks/from.js +++ /dev/null @@ -1,19 +0,0 @@ -/** @jsx jsx */ - -import { Node } from 'slate' -import { jsx } from 'slate-hyperscript' - -export const input = ( - - - one - two - - -) - -export const test = value => { - return Array.from(Node.marks(value, { from: [0, 1] })) -} - -export const output = [[{ key: 'b' }, 0, two, [0, 1]]] diff --git a/packages/slate/test/interfaces/Node/marks/reverse.js b/packages/slate/test/interfaces/Node/marks/reverse.js deleted file mode 100644 index 1a68bfb2f..000000000 --- a/packages/slate/test/interfaces/Node/marks/reverse.js +++ /dev/null @@ -1,22 +0,0 @@ -/** @jsx jsx */ - -import { Node } from 'slate' -import { jsx } from 'slate-hyperscript' - -export const input = ( - - - one - two - - -) - -export const test = value => { - return Array.from(Node.marks(value, { reverse: true })) -} - -export const output = [ - [{ key: 'b' }, 0, two, [0, 1]], - [{ key: 'a' }, 0, one, [0, 0]], -] diff --git a/packages/slate/test/interfaces/Node/marks/to.js b/packages/slate/test/interfaces/Node/marks/to.js deleted file mode 100644 index 91347943e..000000000 --- a/packages/slate/test/interfaces/Node/marks/to.js +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsx jsx */ - -import { Node } from 'slate' -import { jsx } from 'slate-hyperscript' - -export const input = ( - - - one - two - three - - -) - -export const test = value => { - return Array.from( - Node.marks(value, { - from: [0, 0], - to: [0, 1], - }) - ) -} - -export const output = [ - [{ key: 'a' }, 0, one, [0, 0]], - [{ key: 'b' }, 0, two, [0, 1]], -] diff --git a/packages/slate/test/interfaces/Operation/isOperation/add_mark.js b/packages/slate/test/interfaces/Operation/isOperation/add_mark.js deleted file mode 100644 index 88ffbb438..000000000 --- a/packages/slate/test/interfaces/Operation/isOperation/add_mark.js +++ /dev/null @@ -1,13 +0,0 @@ -import { Operation } from 'slate' - -export const input = { - type: 'add_mark', - path: [0], - mark: {}, -} - -export const test = value => { - return Operation.isOperation(value) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Operation/isOperation/custom-property.js b/packages/slate/test/interfaces/Operation/isOperation/custom-property.js index 1e52ca258..9888cce11 100644 --- a/packages/slate/test/interfaces/Operation/isOperation/custom-property.js +++ b/packages/slate/test/interfaces/Operation/isOperation/custom-property.js @@ -1,9 +1,10 @@ import { Operation } from 'slate' export const input = { - type: 'add_mark', + type: 'set_node', path: [0], - mark: {}, + properties: {}, + newProperties: {}, custom: true, } diff --git a/packages/slate/test/interfaces/Operation/isOperation/remove_mark.js b/packages/slate/test/interfaces/Operation/isOperation/remove_mark.js deleted file mode 100644 index c7d5527e2..000000000 --- a/packages/slate/test/interfaces/Operation/isOperation/remove_mark.js +++ /dev/null @@ -1,13 +0,0 @@ -import { Operation } from 'slate' - -export const input = { - type: 'remove_mark', - path: [0], - mark: {}, -} - -export const test = value => { - return Operation.isOperation(value) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Operation/isOperation/set_mark.js b/packages/slate/test/interfaces/Operation/isOperation/set_mark.js deleted file mode 100644 index b4ccf616c..000000000 --- a/packages/slate/test/interfaces/Operation/isOperation/set_mark.js +++ /dev/null @@ -1,14 +0,0 @@ -import { Operation } from 'slate' - -export const input = { - type: 'set_mark', - path: [0], - properties: {}, - newProperties: {}, -} - -export const test = value => { - return Operation.isOperation(value) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Operation/isOperation/without-type.js b/packages/slate/test/interfaces/Operation/isOperation/without-type.js index 00668d080..9c43861fa 100644 --- a/packages/slate/test/interfaces/Operation/isOperation/without-type.js +++ b/packages/slate/test/interfaces/Operation/isOperation/without-type.js @@ -2,7 +2,8 @@ import { Operation } from 'slate' export const input = { path: [0], - mark: {}, + properties: {}, + newProperties: {}, } export const test = value => { diff --git a/packages/slate/test/interfaces/Operation/isOperationList/full.js b/packages/slate/test/interfaces/Operation/isOperationList/full.js index c94c992dd..b97299d21 100644 --- a/packages/slate/test/interfaces/Operation/isOperationList/full.js +++ b/packages/slate/test/interfaces/Operation/isOperationList/full.js @@ -2,9 +2,10 @@ import { Operation } from 'slate' export const input = [ { - type: 'add_mark', + type: 'set_node', path: [0], - mark: {}, + properties: {}, + newProperties: {}, }, ] diff --git a/packages/slate/test/interfaces/Operation/isOperationList/operation.js b/packages/slate/test/interfaces/Operation/isOperationList/operation.js index 6e9516d65..81f2162a6 100644 --- a/packages/slate/test/interfaces/Operation/isOperationList/operation.js +++ b/packages/slate/test/interfaces/Operation/isOperationList/operation.js @@ -1,9 +1,10 @@ import { Operation } from 'slate' export const input = { - type: 'add_mark', + type: 'set_node', path: [0], - mark: {}, + properties: {}, + newProperties: {}, } export const test = value => { diff --git a/packages/slate/test/interfaces/Text/isText/custom-property.js b/packages/slate/test/interfaces/Text/isText/custom-property.js index 610c50e22..93702646b 100644 --- a/packages/slate/test/interfaces/Text/isText/custom-property.js +++ b/packages/slate/test/interfaces/Text/isText/custom-property.js @@ -2,7 +2,7 @@ import { Text } from 'slate' export const input = { text: '', - marks: [], + custom: true, } diff --git a/packages/slate/test/interfaces/Text/isText/marks-full.js b/packages/slate/test/interfaces/Text/isText/marks-full.js deleted file mode 100644 index 9bca478af..000000000 --- a/packages/slate/test/interfaces/Text/isText/marks-full.js +++ /dev/null @@ -1,12 +0,0 @@ -import { Text } from 'slate' - -export const input = { - text: '', - marks: [{}], -} - -export const test = value => { - return Text.isText(value) -} - -export const output = true diff --git a/packages/slate/test/interfaces/Text/isText/text-full.js b/packages/slate/test/interfaces/Text/isText/text-full.js index 0d0f662cb..6e511e180 100644 --- a/packages/slate/test/interfaces/Text/isText/text-full.js +++ b/packages/slate/test/interfaces/Text/isText/text-full.js @@ -2,7 +2,6 @@ import { Text } from 'slate' export const input = { text: 'string', - marks: [], } export const test = value => { diff --git a/packages/slate/test/interfaces/Text/isText/text.js b/packages/slate/test/interfaces/Text/isText/text.js index 6d78fb3dc..0724d61a4 100644 --- a/packages/slate/test/interfaces/Text/isText/text.js +++ b/packages/slate/test/interfaces/Text/isText/text.js @@ -2,7 +2,6 @@ import { Text } from 'slate' export const input = { text: '', - marks: [], } export const test = value => { diff --git a/packages/slate/test/interfaces/Text/isText/without-marks.js b/packages/slate/test/interfaces/Text/isText/without-marks.js deleted file mode 100644 index a3c34c02a..000000000 --- a/packages/slate/test/interfaces/Text/isText/without-marks.js +++ /dev/null @@ -1,11 +0,0 @@ -import { Text } from 'slate' - -export const input = { - text: '', -} - -export const test = value => { - return Text.isText(value) -} - -export const output = false diff --git a/packages/slate/test/interfaces/Text/isText/without-text.js b/packages/slate/test/interfaces/Text/isText/without-text.js index 0b39452b5..2ce196777 100644 --- a/packages/slate/test/interfaces/Text/isText/without-text.js +++ b/packages/slate/test/interfaces/Text/isText/without-text.js @@ -1,8 +1,6 @@ import { Text } from 'slate' -export const input = { - marks: [], -} +export const input = {} export const test = value => { return Text.isText(value) diff --git a/packages/slate/test/interfaces/Text/isTextList/full-text.js b/packages/slate/test/interfaces/Text/isTextList/full-text.js index 11541dc60..3bfb60c75 100644 --- a/packages/slate/test/interfaces/Text/isTextList/full-text.js +++ b/packages/slate/test/interfaces/Text/isTextList/full-text.js @@ -3,7 +3,6 @@ import { Text } from 'slate' export const input = [ { text: '', - marks: [], }, ] diff --git a/packages/slate/test/interfaces/Text/isTextList/text.js b/packages/slate/test/interfaces/Text/isTextList/text.js index 69848894b..58867e84a 100644 --- a/packages/slate/test/interfaces/Text/isTextList/text.js +++ b/packages/slate/test/interfaces/Text/isTextList/text.js @@ -2,7 +2,6 @@ import { Text } from 'slate' export const input = { text: '', - marks: [], } export const test = value => { diff --git a/packages/slate/test/interfaces/Text/matches/empty-true.js b/packages/slate/test/interfaces/Text/matches/empty-true.js new file mode 100644 index 000000000..8b9eddab8 --- /dev/null +++ b/packages/slate/test/interfaces/Text/matches/empty-true.js @@ -0,0 +1,12 @@ +import { Text } from 'slate' + +export const input = { + text: { text: '', bold: true }, + props: {}, +} + +export const test = ({ text, props }) => { + return Text.matches(text, props) +} + +export const output = true diff --git a/packages/slate/test/interfaces/Text/matches/match-false.js b/packages/slate/test/interfaces/Text/matches/match-false.js new file mode 100644 index 000000000..6473c0ab9 --- /dev/null +++ b/packages/slate/test/interfaces/Text/matches/match-false.js @@ -0,0 +1,12 @@ +import { Text } from 'slate' + +export const input = { + text: { text: '', bold: true }, + props: { italic: true }, +} + +export const test = ({ text, props }) => { + return Text.matches(text, props) +} + +export const output = false diff --git a/packages/slate/test/interfaces/Text/matches/match-true.js b/packages/slate/test/interfaces/Text/matches/match-true.js new file mode 100644 index 000000000..db4c5b820 --- /dev/null +++ b/packages/slate/test/interfaces/Text/matches/match-true.js @@ -0,0 +1,12 @@ +import { Text } from 'slate' + +export const input = { + text: { text: '', bold: true }, + props: { bold: true }, +} + +export const test = ({ text, props }) => { + return Text.matches(text, props) +} + +export const output = true diff --git a/packages/slate/test/interfaces/Text/matches/partial-false.js b/packages/slate/test/interfaces/Text/matches/partial-false.js new file mode 100644 index 000000000..f81ef1362 --- /dev/null +++ b/packages/slate/test/interfaces/Text/matches/partial-false.js @@ -0,0 +1,12 @@ +import { Text } from 'slate' + +export const input = { + text: { text: '', bold: true, italic: true }, + props: { underline: true }, +} + +export const test = ({ text, props }) => { + return Text.matches(text, props) +} + +export const output = false diff --git a/packages/slate/test/interfaces/Text/matches/partial-true.js b/packages/slate/test/interfaces/Text/matches/partial-true.js new file mode 100644 index 000000000..51f29204e --- /dev/null +++ b/packages/slate/test/interfaces/Text/matches/partial-true.js @@ -0,0 +1,12 @@ +import { Text } from 'slate' + +export const input = { + text: { text: '', bold: true, italic: true }, + props: { bold: true }, +} + +export const test = ({ text, props }) => { + return Text.matches(text, props) +} + +export const output = true diff --git a/packages/slate/test/normalization/text-merge-adjacent-without-marks.js b/packages/slate/test/normalization/text-merge-adjacent-match-empty.js similarity index 100% rename from packages/slate/test/normalization/text-merge-adjacent-without-marks.js rename to packages/slate/test/normalization/text-merge-adjacent-match-empty.js diff --git a/packages/slate/test/normalization/text-merge-adjacent-with-marks.js b/packages/slate/test/normalization/text-merge-adjacent-match.js similarity index 70% rename from packages/slate/test/normalization/text-merge-adjacent-with-marks.js rename to packages/slate/test/normalization/text-merge-adjacent-match.js index a5046513d..de012661d 100644 --- a/packages/slate/test/normalization/text-merge-adjacent-with-marks.js +++ b/packages/slate/test/normalization/text-merge-adjacent-match.js @@ -7,8 +7,8 @@ export const schema = {} export const input = ( - 1 - 2 + 1 + 2 ) @@ -16,7 +16,7 @@ export const input = ( export const output = ( - 12 + 12 ) diff --git a/packages/slate/test/queries/marks/continuing/continuing.js b/packages/slate/test/queries/marks/continuing/continuing.js deleted file mode 100644 index f140ed2c7..000000000 --- a/packages/slate/test/queries/marks/continuing/continuing.js +++ /dev/null @@ -1,23 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - one - - - two - - - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { continuing: true }), ([m]) => m) -} - -export const output = [{ key: 'a' }] diff --git a/packages/slate/test/queries/marks/mode-all/text-across-multiple.js b/packages/slate/test/queries/marks/mode-all/text-across-multiple.js deleted file mode 100644 index 4f2d1e4f0..000000000 --- a/packages/slate/test/queries/marks/mode-all/text-across-multiple.js +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - - - o - - - n - - - e - - - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor), ([m]) => m) -} - -export const output = [{ key: 'b' }, { key: 'a' }, { key: 'b' }, { key: 'a' }] diff --git a/packages/slate/test/queries/marks/mode-distinct/text-across-multiple.js b/packages/slate/test/queries/marks/mode-distinct/text-across-multiple.js deleted file mode 100644 index 398faa897..000000000 --- a/packages/slate/test/queries/marks/mode-distinct/text-across-multiple.js +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - - - o - - - n - - - e - - - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { mode: 'distinct' }), ([m]) => m) -} - -export const output = [{ key: 'b' }, { key: 'a' }] diff --git a/packages/slate/test/queries/marks/mode-universal/block-across-intersection.js b/packages/slate/test/queries/marks/mode-universal/block-across-intersection.js deleted file mode 100644 index 15df81adc..000000000 --- a/packages/slate/test/queries/marks/mode-universal/block-across-intersection.js +++ /dev/null @@ -1,29 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - - o - ne - - - - - - t - wo - - - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { mode: 'universal' }), ([m]) => m) -} - -export const output = [{ key: 'a' }] diff --git a/packages/slate/test/queries/marks/mode-universal/block-across.js b/packages/slate/test/queries/marks/mode-universal/block-across.js deleted file mode 100644 index 4baa80588..000000000 --- a/packages/slate/test/queries/marks/mode-universal/block-across.js +++ /dev/null @@ -1,31 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - - - o - ne - - - - - - - t - wo - - - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { mode: 'universal' }), ([m]) => m) -} - -export const output = [{ key: 'b' }, { key: 'a' }] diff --git a/packages/slate/test/queries/marks/mode-universal/block-intersection.js b/packages/slate/test/queries/marks/mode-universal/block-intersection.js deleted file mode 100644 index e30ab6ce5..000000000 --- a/packages/slate/test/queries/marks/mode-universal/block-intersection.js +++ /dev/null @@ -1,24 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - - o - - n - - e - - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { mode: 'universal' }), ([m]) => m) -} - -export const output = [] diff --git a/packages/slate/test/queries/marks/mode-universal/block-multiple-match.js b/packages/slate/test/queries/marks/mode-universal/block-multiple-match.js deleted file mode 100644 index bb3ccf63a..000000000 --- a/packages/slate/test/queries/marks/mode-universal/block-multiple-match.js +++ /dev/null @@ -1,26 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - - - o - ne - - - - -) - -export const run = editor => { - return Array.from( - Editor.marks(editor, { match: { key: 'a' }, mode: 'universal' }), - ([m]) => m - ) -} - -export const output = [{ key: 'a' }] diff --git a/packages/slate/test/queries/marks/mode-universal/block-multiple.js b/packages/slate/test/queries/marks/mode-universal/block-multiple.js deleted file mode 100644 index ea741fe9f..000000000 --- a/packages/slate/test/queries/marks/mode-universal/block-multiple.js +++ /dev/null @@ -1,23 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - - - o - ne - - - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { mode: 'universal' }), ([m]) => m) -} - -export const output = [{ key: 'b' }, { key: 'a' }] diff --git a/packages/slate/test/queries/marks/mode-universal/block-start.js b/packages/slate/test/queries/marks/mode-universal/block-start.js deleted file mode 100644 index 1d86c429a..000000000 --- a/packages/slate/test/queries/marks/mode-universal/block-start.js +++ /dev/null @@ -1,22 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - one - - - - two - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { mode: 'universal' }), ([m]) => m) -} - -export const output = [] diff --git a/packages/slate/test/queries/marks/mode-universal/inline-start.js b/packages/slate/test/queries/marks/mode-universal/inline-start.js deleted file mode 100644 index 711714636..000000000 --- a/packages/slate/test/queries/marks/mode-universal/inline-start.js +++ /dev/null @@ -1,23 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - one - - - two - - three - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { mode: 'universal' }), ([m]) => m) -} - -export const output = [] diff --git a/packages/slate/test/queries/marks/mode-universal/none.js b/packages/slate/test/queries/marks/mode-universal/none.js deleted file mode 100644 index 0b881618f..000000000 --- a/packages/slate/test/queries/marks/mode-universal/none.js +++ /dev/null @@ -1,19 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - o - ne - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { mode: 'universal' }), ([m]) => m) -} - -export const output = [] diff --git a/packages/slate/test/queries/marks/mode-universal/one.js b/packages/slate/test/queries/marks/mode-universal/one.js deleted file mode 100644 index 180e7dc6d..000000000 --- a/packages/slate/test/queries/marks/mode-universal/one.js +++ /dev/null @@ -1,21 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - - o - ne - - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { mode: 'universal' }), ([m]) => m) -} - -export const output = [{ key: 'a' }] diff --git a/packages/slate/test/queries/marks/mode-universal/selection-null.js b/packages/slate/test/queries/marks/mode-universal/selection-null.js deleted file mode 100644 index 004d4e32e..000000000 --- a/packages/slate/test/queries/marks/mode-universal/selection-null.js +++ /dev/null @@ -1,18 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const input = ( - - - one - - -) - -export const run = editor => { - return Array.from(Editor.marks(editor, { mode: 'universal' }), ([m]) => m) -} - -export const output = [] diff --git a/packages/slate/test/transforms/addMarks/path/basic.js b/packages/slate/test/transforms/addMarks/path/basic.js deleted file mode 100644 index 1149baaf0..000000000 --- a/packages/slate/test/transforms/addMarks/path/basic.js +++ /dev/null @@ -1,22 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.addMarks(editor, { key: 'a' }, { at: [0, 0] }) -} - -export const input = ( - - word - -) - -export const output = ( - - - word - - -) diff --git a/packages/slate/test/transforms/addMarks/range/basic.js b/packages/slate/test/transforms/addMarks/range/basic.js deleted file mode 100644 index 23687eb36..000000000 --- a/packages/slate/test/transforms/addMarks/range/basic.js +++ /dev/null @@ -1,31 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.addMarks( - editor, - { key: 'a' }, - { - at: { - anchor: { path: [0, 0], offset: 1 }, - focus: { path: [0, 0], offset: 3 }, - }, - } - ) -} - -export const input = ( - - word - -) - -export const output = ( - - - word - - -) diff --git a/packages/slate/test/transforms/addMarks/selection/block-across-edge-existing.js b/packages/slate/test/transforms/addMarks/selection/block-across-edge-existing.js deleted file mode 100644 index f4c5826c9..000000000 --- a/packages/slate/test/transforms/addMarks/selection/block-across-edge-existing.js +++ /dev/null @@ -1,46 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.addMarks(editor, { key: 'a' }) -} - -export const input = ( - - - wo - - - rd - - - - an - - other - - -) - -export const output = ( - - - wo - - - - rd - - - - - - an - - - other - - -) diff --git a/packages/slate/test/transforms/addMarks/selection/block-across-existing.js b/packages/slate/test/transforms/addMarks/selection/block-across-existing.js deleted file mode 100644 index 3b08badd1..000000000 --- a/packages/slate/test/transforms/addMarks/selection/block-across-existing.js +++ /dev/null @@ -1,50 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.addMarks(editor, { key: 'a' }) -} - -export const input = ( - - - - wo - - rd - - - - - an - - other - - - -) - -export const output = ( - - - wo - - - - rd - - - - - - - an - - - - other - - -) diff --git a/packages/slate/test/transforms/addMarks/selection/existing.js b/packages/slate/test/transforms/addMarks/selection/existing.js deleted file mode 100644 index c68103f68..000000000 --- a/packages/slate/test/transforms/addMarks/selection/existing.js +++ /dev/null @@ -1,36 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.addMarks(editor, { key: 'a' }) -} - -export const input = ( - - - - - wo - - rd - - - -) - -export const output = ( - - - - - - wo - - - - rd - - -) diff --git a/packages/slate/test/transforms/addMarks/selection/first-character.js b/packages/slate/test/transforms/addMarks/selection/first-character.js deleted file mode 100644 index 2c76fcfaa..000000000 --- a/packages/slate/test/transforms/addMarks/selection/first-character.js +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.addMarks(editor, { key: 'a' }) -} - -export const input = ( - - - w - ord - - -) - -export const output = ( - - - - w - - ord - - -) diff --git a/packages/slate/test/transforms/addMarks/selection/inline-across.js b/packages/slate/test/transforms/addMarks/selection/inline-across.js deleted file mode 100644 index 7ce3a22b5..000000000 --- a/packages/slate/test/transforms/addMarks/selection/inline-across.js +++ /dev/null @@ -1,58 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.addMarks(editor, { key: 'a' }) -} - -export const input = ( - - - - - wo - - rd - - - - - - - an - - other - - - - -) - -export const output = ( - - - - - wo - - - rd - - - - - - - - - an - - - other - - - - -) diff --git a/packages/slate/test/transforms/addMarks/selection/last-character.js b/packages/slate/test/transforms/addMarks/selection/last-character.js deleted file mode 100644 index 499273a43..000000000 --- a/packages/slate/test/transforms/addMarks/selection/last-character.js +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.addMarks(editor, { key: 'a' }) -} - -export const input = ( - - - wor - d - - -) - -export const output = ( - - - wor - - d - - - -) diff --git a/packages/slate/test/transforms/addMarks/selection/middle-character.js b/packages/slate/test/transforms/addMarks/selection/middle-character.js deleted file mode 100644 index e0c1ba2b0..000000000 --- a/packages/slate/test/transforms/addMarks/selection/middle-character.js +++ /dev/null @@ -1,29 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.addMarks(editor, { key: 'a' }) -} - -export const input = ( - - - wo - rd - - -) - -export const output = ( - - - w - - o - - rd - - -) diff --git a/packages/slate/test/transforms/delete/selection/mark-across.js b/packages/slate/test/transforms/delete/selection/mark-across.js deleted file mode 100644 index 7fe5e3197..000000000 --- a/packages/slate/test/transforms/delete/selection/mark-across.js +++ /dev/null @@ -1,32 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.delete(editor) -} - -export const input = ( - - - - - wo - - rd - - - two - - - -) - -export const output = ( - - - - - -) diff --git a/packages/slate/test/transforms/insertFragment/of-texts/with-mark.js b/packages/slate/test/transforms/insertFragment/of-texts/with-mark.js deleted file mode 100644 index 73fff1cad..000000000 --- a/packages/slate/test/transforms/insertFragment/of-texts/with-mark.js +++ /dev/null @@ -1,34 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.insertFragment( - editor, - - fragment - - ) -} - -export const input = ( - - - wo - - rd - - -) - -export const output = ( - - - wo - fragment - - rd - - -) diff --git a/packages/slate/test/transforms/insertFragment/of-texts/with-marks.js b/packages/slate/test/transforms/insertFragment/of-texts/with-marks.js deleted file mode 100644 index f7a108cc0..000000000 --- a/packages/slate/test/transforms/insertFragment/of-texts/with-marks.js +++ /dev/null @@ -1,38 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.insertFragment( - editor, - - one - two - three - - ) -} - -export const input = ( - - - wo - - rd - - -) - -export const output = ( - - - wo - one - two - three - - rd - - -) diff --git a/packages/slate/test/transforms/insertText/selection/block-across-with-mark.js b/packages/slate/test/transforms/insertText/selection/block-across-with-mark.js deleted file mode 100644 index 121c2816e..000000000 --- a/packages/slate/test/transforms/insertText/selection/block-across-with-mark.js +++ /dev/null @@ -1,35 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.insertText(editor, 'a') - Editor.insertText(editor, 'b') -} - -export const input = ( - - - - - one - - - - two - - - -) - -export const output = ( - - - ab - - - -) - -export const skip = true diff --git a/packages/slate/test/transforms/insertText/selection/mark-after.js b/packages/slate/test/transforms/insertText/selection/mark-after.js deleted file mode 100644 index c2875bfd8..000000000 --- a/packages/slate/test/transforms/insertText/selection/mark-after.js +++ /dev/null @@ -1,34 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.insertText(editor, 'a') -} - -export const input = ( - - - w - - or - - - d - - -) - -export const output = ( - - - w - - ora - - - d - - -) diff --git a/packages/slate/test/transforms/insertText/selection/mark-before.js b/packages/slate/test/transforms/insertText/selection/mark-before.js deleted file mode 100644 index 27fb0b521..000000000 --- a/packages/slate/test/transforms/insertText/selection/mark-before.js +++ /dev/null @@ -1,27 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.insertText(editor, 'a') -} - -export const input = ( - - - w - ord - - -) - -export const output = ( - - - wa - - ord - - -) diff --git a/packages/slate/test/transforms/insertText/selection/mark-empty.js b/packages/slate/test/transforms/insertText/selection/mark-empty.js deleted file mode 100644 index 805b22fb0..000000000 --- a/packages/slate/test/transforms/insertText/selection/mark-empty.js +++ /dev/null @@ -1,29 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.insertText(editor, 'Cat') -} - -export const input = ( - - - - - - - -) - -export const output = ( - - - - Cat - - - - -) diff --git a/packages/slate/test/transforms/insertText/selection/mark-middle.js b/packages/slate/test/transforms/insertText/selection/mark-middle.js deleted file mode 100644 index 60a799a30..000000000 --- a/packages/slate/test/transforms/insertText/selection/mark-middle.js +++ /dev/null @@ -1,33 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.insertText(editor, 'a') -} - -export const input = ( - - - w - - or - - d - - -) - -export const output = ( - - - w - - oa - r - - d - - -) diff --git a/packages/slate/test/transforms/removeMarks/path/basic.js b/packages/slate/test/transforms/removeMarks/path/basic.js deleted file mode 100644 index 7fcfc1f0e..000000000 --- a/packages/slate/test/transforms/removeMarks/path/basic.js +++ /dev/null @@ -1,22 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks(editor, { key: 'a' }, { at: [0, 0] }) -} - -export const input = ( - - - word - - -) - -export const output = ( - - word - -) diff --git a/packages/slate/test/transforms/removeMarks/range/basic.js b/packages/slate/test/transforms/removeMarks/range/basic.js deleted file mode 100644 index 1d6d2c81d..000000000 --- a/packages/slate/test/transforms/removeMarks/range/basic.js +++ /dev/null @@ -1,31 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks( - editor, - { key: 'a' }, - { - at: { - anchor: { path: [0, 1], offset: 0 }, - focus: { path: [0, 1], offset: 2 }, - }, - } - ) -} - -export const input = ( - - - word - - -) - -export const output = ( - - word - -) diff --git a/packages/slate/test/transforms/removeMarks/selection/across-blocks.js b/packages/slate/test/transforms/removeMarks/selection/across-blocks.js deleted file mode 100644 index 72ea66699..000000000 --- a/packages/slate/test/transforms/removeMarks/selection/across-blocks.js +++ /dev/null @@ -1,38 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks(editor, { key: 'a' }) -} - -export const input = ( - - - wo - - rd - - - an - - other - - -) - -export const output = ( - - - wo - - rd - - - an - - other - - -) diff --git a/packages/slate/test/transforms/removeMarks/selection/across-inlines.js b/packages/slate/test/transforms/removeMarks/selection/across-inlines.js deleted file mode 100644 index 887bfa039..000000000 --- a/packages/slate/test/transforms/removeMarks/selection/across-inlines.js +++ /dev/null @@ -1,54 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks(editor, { key: 'a' }) -} - -export const input = ( - - - - - wo - - rd - - - - - - - an - - other - - - - -) - -export const output = ( - - - - - wo - - rd - - - - - - - an - - other - - - - -) diff --git a/packages/slate/test/transforms/removeMarks/selection/collapsed-selection.js b/packages/slate/test/transforms/removeMarks/selection/collapsed-selection.js deleted file mode 100644 index e598f0195..000000000 --- a/packages/slate/test/transforms/removeMarks/selection/collapsed-selection.js +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.addMarks(editor, { key: 'a' }) - Editor.removeMarks(editor, { key: 'a' }) - Editor.insertText(editor, 'a') -} - -export const input = ( - - - - word - - -) - -export const output = ( - - - a - word - - -) diff --git a/packages/slate/test/transforms/removeMarks/selection/existing-marks.js b/packages/slate/test/transforms/removeMarks/selection/existing-marks.js deleted file mode 100644 index 712ca820e..000000000 --- a/packages/slate/test/transforms/removeMarks/selection/existing-marks.js +++ /dev/null @@ -1,36 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks(editor, { key: 'a' }) -} - -export const input = ( - - - - - wo - - - - rd - - - -) - -export const output = ( - - - - - wo - - rd - - - -) diff --git a/packages/slate/test/transforms/removeMarks/selection/first-character.js b/packages/slate/test/transforms/removeMarks/selection/first-character.js deleted file mode 100644 index 74c826c2e..000000000 --- a/packages/slate/test/transforms/removeMarks/selection/first-character.js +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks(editor, { key: 'a' }) -} - -export const input = ( - - - - w - - ord - - -) - -export const output = ( - - - w - ord - - -) diff --git a/packages/slate/test/transforms/removeMarks/selection/last-character.js b/packages/slate/test/transforms/removeMarks/selection/last-character.js deleted file mode 100644 index 548150152..000000000 --- a/packages/slate/test/transforms/removeMarks/selection/last-character.js +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks(editor, { key: 'a' }) -} - -export const input = ( - - - wor - - d - - - -) - -export const output = ( - - - wor - d - - -) diff --git a/packages/slate/test/transforms/removeMarks/selection/middle-character.js b/packages/slate/test/transforms/removeMarks/selection/middle-character.js deleted file mode 100644 index f773724e1..000000000 --- a/packages/slate/test/transforms/removeMarks/selection/middle-character.js +++ /dev/null @@ -1,30 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks(editor, { key: 'a' }) -} - -export const input = ( - - - w - - o - - - rd - - -) - -export const output = ( - - - wo - rd - - -) diff --git a/packages/slate/test/transforms/removeMarks/selection/part-of-mark-backward.js b/packages/slate/test/transforms/removeMarks/selection/part-of-mark-backward.js deleted file mode 100644 index 9d1e4e161..000000000 --- a/packages/slate/test/transforms/removeMarks/selection/part-of-mark-backward.js +++ /dev/null @@ -1,30 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks(editor, { key: 'a' }) -} - -export const input = ( - - - - wor - d - - - -) - -export const output = ( - - - wor - - d - - - -) diff --git a/packages/slate/test/transforms/removeMarks/selection/part-of-mark.js b/packages/slate/test/transforms/removeMarks/selection/part-of-mark.js deleted file mode 100644 index c5407d1a8..000000000 --- a/packages/slate/test/transforms/removeMarks/selection/part-of-mark.js +++ /dev/null @@ -1,30 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks(editor, { key: 'a' }) -} - -export const input = ( - - - - wor - d - - - -) - -export const output = ( - - - wor - - d - - - -) diff --git a/packages/slate/test/transforms/removeMarks/selection/whole-word.js b/packages/slate/test/transforms/removeMarks/selection/whole-word.js deleted file mode 100644 index 9204e60ec..000000000 --- a/packages/slate/test/transforms/removeMarks/selection/whole-word.js +++ /dev/null @@ -1,28 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.removeMarks(editor, { key: 'a' }) -} - -export const input = ( - - - - word - - - -) - -export const output = ( - - - - word - - - -) diff --git a/packages/slate/test/transforms/setMarks/path/basic.js b/packages/slate/test/transforms/setMarks/path/basic.js deleted file mode 100644 index e02e45fe8..000000000 --- a/packages/slate/test/transforms/setMarks/path/basic.js +++ /dev/null @@ -1,26 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.setMarks(editor, { existing: true }, { key: true }, { at: [0, 0] }) -} - -export const input = ( - - - word - - -) - -export const output = ( - - - - word - - - -) diff --git a/packages/slate/test/transforms/setMarks/range/basic.js b/packages/slate/test/transforms/setMarks/range/basic.js deleted file mode 100644 index 1fe9c6d77..000000000 --- a/packages/slate/test/transforms/setMarks/range/basic.js +++ /dev/null @@ -1,38 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.setMarks( - editor, - { key: 'a' }, - { thing: true }, - { - at: { - anchor: { path: [0, 1], offset: 0 }, - focus: { path: [0, 1], offset: 2 }, - }, - } - ) -} - -export const input = ( - - - word - - -) - -export const output = ( - - - w - - or - - d - - -) diff --git a/packages/slate/test/transforms/setMarks/selection/basic.js b/packages/slate/test/transforms/setNodes/split/text-remove.js similarity index 55% rename from packages/slate/test/transforms/setMarks/selection/basic.js rename to packages/slate/test/transforms/setNodes/split/text-remove.js index 60ea89f92..8313e5d2e 100644 --- a/packages/slate/test/transforms/setMarks/selection/basic.js +++ b/packages/slate/test/transforms/setNodes/split/text-remove.js @@ -4,17 +4,17 @@ import { Editor } from 'slate' import { jsx } from '../../..' export const run = editor => { - Editor.setMarks(editor, { key: 'a' }, { thing: true }) + Editor.setNodes(editor, { key: null }, { match: 'text', split: true }) } export const input = ( - - - word - - + + w + or + d + ) @@ -22,11 +22,13 @@ export const input = ( export const output = ( - + w + - word + or - + + d ) diff --git a/packages/slate/test/transforms/addMarks/selection/word.js b/packages/slate/test/transforms/setNodes/split/text.js similarity index 59% rename from packages/slate/test/transforms/addMarks/selection/word.js rename to packages/slate/test/transforms/setNodes/split/text.js index 0f3dd87be..d6cd0584c 100644 --- a/packages/slate/test/transforms/addMarks/selection/word.js +++ b/packages/slate/test/transforms/setNodes/split/text.js @@ -4,15 +4,15 @@ import { Editor } from 'slate' import { jsx } from '../../..' export const run = editor => { - Editor.addMarks(editor, { key: 'a' }) + Editor.setNodes(editor, { key: true }, { match: 'text', split: true }) } export const input = ( - - word - + w + or + d ) @@ -20,11 +20,13 @@ export const input = ( export const output = ( - + w + - word + or - + + d ) diff --git a/packages/slate/test/transforms/addMarks/selection/block-across.js b/packages/slate/test/transforms/setNodes/text/block-across.js similarity index 60% rename from packages/slate/test/transforms/addMarks/selection/block-across.js rename to packages/slate/test/transforms/setNodes/text/block-across.js index b0a3d290c..8c35aa34f 100644 --- a/packages/slate/test/transforms/addMarks/selection/block-across.js +++ b/packages/slate/test/transforms/setNodes/text/block-across.js @@ -4,20 +4,18 @@ import { Editor } from 'slate' import { jsx } from '../../..' export const run = editor => { - Editor.addMarks(editor, { key: 'a' }) + Editor.setNodes(editor, { key: true }, { match: 'text' }) } export const input = ( - wo - rd + word - an - - other + a + nother ) @@ -25,18 +23,16 @@ export const input = ( export const output = ( - wo - + - rd - + word + - - an - - - other + + a + nother + ) diff --git a/packages/slate/test/transforms/delete/selection/mark-whole.js b/packages/slate/test/transforms/setNodes/text/text.js similarity index 69% rename from packages/slate/test/transforms/delete/selection/mark-whole.js rename to packages/slate/test/transforms/setNodes/text/text.js index 1fe2c1b3e..dd5d54550 100644 --- a/packages/slate/test/transforms/delete/selection/mark-whole.js +++ b/packages/slate/test/transforms/setNodes/text/text.js @@ -4,17 +4,14 @@ import { Editor } from 'slate' import { jsx } from '../../..' export const run = editor => { - Editor.delete(editor) + Editor.setNodes(editor, { key: true }, { match: 'text' }) } export const input = ( - - - word - - + + word ) @@ -22,9 +19,10 @@ export const input = ( export const output = ( - + - + word + ) diff --git a/packages/slate/test/transforms/splitNodes/selection/mark.js b/packages/slate/test/transforms/splitNodes/selection/mark.js deleted file mode 100644 index 823c38e8e..000000000 --- a/packages/slate/test/transforms/splitNodes/selection/mark.js +++ /dev/null @@ -1,43 +0,0 @@ -/** @jsx jsx */ - -import { Editor } from 'slate' -import { jsx } from '../../..' - -export const run = editor => { - Editor.splitNodes(editor, { match: 'inline' }) -} - -export const input = ( - - - - - - wo - - rd - - - - - -) - -export const output = ( - - - - - wo - - - - - - rd - - - - - -) diff --git a/site/examples/Readme.md b/site/examples/Readme.md index be96867a1..91ce93786 100644 --- a/site/examples/Readme.md +++ b/site/examples/Readme.md @@ -11,7 +11,7 @@ This directory contains a set of examples that give you an idea for how you migh - [**Hovering menu**](./hovering-menu.js) — showing how a contextual hovering menu can be implemented. - [**Tables**](./tables.js) — showing how to nest blocks to render more advanced components. - [**Paste HTML**](./paste-html.js) — showing how to use an HTML serializer to handle pasted HTML. -- [**Code Highlighting**](./code-highlighting.js) — showing how to use decorations to dynamically mark text. +- [**Code Highlighting**](./code-highlighting.js) — showing how to use decorations to dynamically format text. - ...and more! If you have an idea for an example that shows a common use case, pull request it! diff --git a/site/examples/check-lists.js b/site/examples/check-lists.js index 730d23bc6..9f2bce2fc 100644 --- a/site/examples/check-lists.js +++ b/site/examples/check-lists.js @@ -137,77 +137,41 @@ const initialValue = [ { text: 'With Slate you can build complex block types that have their own embedded content and behaviors, like rendering checkboxes inside check list items!', - marks: [], }, ], }, { type: 'check-list-item', checked: true, - children: [ - { - text: 'Slide to the left.', - marks: [], - }, - ], + children: [{ text: 'Slide to the left.' }], }, { type: 'check-list-item', checked: true, - children: [ - { - text: 'Slide to the right.', - marks: [], - }, - ], + children: [{ text: 'Slide to the right.' }], }, { type: 'check-list-item', checked: false, - children: [ - { - text: 'Criss-cross.', - marks: [], - }, - ], + children: [{ text: 'Criss-cross.' }], }, { type: 'check-list-item', checked: true, - children: [ - { - text: 'Criss-cross!', - marks: [], - }, - ], + children: [{ text: 'Criss-cross!' }], }, { type: 'check-list-item', checked: false, - children: [ - { - text: 'Cha cha real smooth…', - marks: [], - }, - ], + children: [{ text: 'Cha cha real smooth…' }], }, { type: 'check-list-item', checked: false, - children: [ - { - text: "Let's go to work!", - marks: [], - }, - ], + children: [{ text: "Let's go to work!" }], }, { - children: [ - { - text: 'Try it out for yourself!', - marks: [], - }, - ], + children: [{ text: 'Try it out for yourself!' }], }, ] diff --git a/site/examples/embeds.js b/site/examples/embeds.js index 441b8e5d9..74d1adb7c 100644 --- a/site/examples/embeds.js +++ b/site/examples/embeds.js @@ -107,26 +107,19 @@ const initialValue = [ { text: 'In addition to simple image nodes, you can actually create complex embedded nodes. For example, this one contains an input element that lets you change the video being rendered!', - marks: [], }, ], }, { type: 'video', url: 'https://player.vimeo.com/video/26689853', - children: [ - { - text: '', - marks: [], - }, - ], + children: [{ text: '' }], }, { children: [ { text: 'Try it out! This editor is built to handle Vimeo embeds, but you could handle any type.', - marks: [], }, ], }, diff --git a/site/examples/forced-layout.js b/site/examples/forced-layout.js index 4e61896fc..5c15e6079 100644 --- a/site/examples/forced-layout.js +++ b/site/examples/forced-layout.js @@ -25,7 +25,7 @@ const schema = [ break } case 'child_min_invalid': { - const block = { type, children: [{ text: '', marks: [] }] } + const block = { type, children: [{ text: '' }] } Editor.insertNodes(editor, block, { at: path }) break } @@ -68,12 +68,7 @@ const Element = ({ attributes, children, element }) => { const initialValue = [ { type: 'title', - children: [ - { - text: 'Enforce Your Layout!', - marks: [], - }, - ], + children: [{ text: 'Enforce Your Layout!' }], }, { type: 'paragraph', @@ -81,7 +76,6 @@ const initialValue = [ { text: 'This example shows how to enforce your layout with schema-specific rules. This document will always have a title block at the top and at least one paragraph in the body. Try deleting them and see what happens!', - marks: [], }, ], }, diff --git a/site/examples/hovering-toolbar.js b/site/examples/hovering-toolbar.js index ee5a8fd24..889ca7697 100644 --- a/site/examples/hovering-toolbar.js +++ b/site/examples/hovering-toolbar.js @@ -9,23 +9,26 @@ import { Range } from 'slate' const HoveringMenuExample = () => { const editor = useMemo( - () => withMarks(withHistory(withReact(createEditor()))), + () => withFormatting(withHistory(withReact(createEditor()))), [] ) return ( } + renderLeaf={props => } placeholder="Enter some text..." onDOMBeforeInput={event => { switch (event.inputType) { case 'formatBold': - return editor.exec({ type: 'toggle_mark', mark: 'bold' }) + return editor.exec({ type: 'toggle_format', format: 'bold' }) case 'formatItalic': - return editor.exec({ type: 'toggle_mark', mark: 'italic' }) + return editor.exec({ type: 'toggle_format', format: 'italic' }) case 'formatUnderline': - return editor.exec({ type: 'toggle_mark', mark: 'underlined' }) + return editor.exec({ + type: 'toggle_format', + format: 'underlined', + }) } }} /> @@ -33,16 +36,19 @@ const HoveringMenuExample = () => { ) } -const withMarks = editor => { +const withFormatting = editor => { const { exec } = editor editor.exec = command => { switch (command.type) { - case 'toggle_mark': { - const { mark } = command - const isActive = isMarkActive(editor, mark.type) - const cmd = isActive ? 'remove_mark' : 'add_mark' - editor.exec({ type: cmd, mark }) + case 'toggle_format': { + const { format } = command + const isActive = isFormatActive(editor, format) + Editor.setNodes( + editor, + { [format]: isActive ? null : true }, + { match: 'text', split: true } + ) break } @@ -56,20 +62,28 @@ const withMarks = editor => { return editor } -const isMarkActive = (editor, type) => { - const [match] = Editor.marks(editor, { match: { type }, mode: 'universal' }) +const isFormatActive = (editor, format) => { + const [match] = Editor.nodes(editor, { + match: { [format]: true }, + mode: 'all', + }) return !!match } -const Mark = ({ attributes, children, mark }) => { - switch (mark.type) { - case 'bold': - return {children} - case 'italic': - return {children} - case 'underlined': - return {children} +const Leaf = ({ attributes, children, leaf }) => { + if (leaf.bold) { + children = {children} } + + if (leaf.italic) { + children = {children} + } + + if (leaf.underlined) { + children = {children} + } + + return {children} } const HoveringToolbar = () => { @@ -99,7 +113,6 @@ const HoveringToolbar = () => { const rect = domRange.getBoundingClientRect() el.style.opacity = 1 el.style.top = `${rect.top + window.pageYOffset - el.offsetHeight}px` - el.style.left = `${rect.left + window.pageXOffset - el.offsetWidth / 2 + @@ -123,23 +136,23 @@ const HoveringToolbar = () => { transition: opacity 0.75s; `} > - - - + + + ) } -const MarkButton = ({ type, icon }) => { +const FormatButton = ({ format, icon }) => { const editor = useSlate() return (