Skip to content

Commit

Permalink
Document field normalization, fixes and tests (keystonejs#4556)
Browse files Browse the repository at this point in the history
* WIP

* Finish things

* Fix some stuff

* Some more things

* Remove debugger thing

* Improve backspace on start of lists

* Test infra

* More tests

* Tests for heading

* Divider tests

* code block tests

* List tests and fixes

* Some more tests

* columns tests

* Little columns test change

* First component-blocks test

* Clean up test utils

* Remove some dead code

* Normalization, insert break and delete backward tests for component blocks

* Fix things

* Cleanup some component-blocks things

* Split out component blocks

* Finish component block tests

* Blockquote button fixes and update TODO

* Heading fixes and TODO updates

* Linting

* Fix things

* Divider improvements

* Make caret transparent in divider

* Update packages-next/fields-document/src/DocumentEditor/component-blocks/form.tsx

* Fix an import

* Actually fix an import

* Fix another thing

* Add an import

Co-authored-by: Jed Watson <jed.watson@me.com>
  • Loading branch information
emmatown and JedWatson authored Dec 17, 2020
1 parent ba842d4 commit 7d85977
Show file tree
Hide file tree
Showing 40 changed files with 5,159 additions and 1,816 deletions.
5 changes: 0 additions & 5 deletions examples-next/basic/admin/fieldViews/Content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ const noticeIconMap = {
export const componentBlocks = {
hero: component({
component: props => {
console.log('title', props.title);
return (
<div
css={{
Expand Down Expand Up @@ -206,8 +205,6 @@ export const componentBlocks = {
},
label: 'Notice',
chromeless: true,
unwrapOnBackspaceAtStart: true,
exitOnEnterInEmptyLineAtEndOfChild: true,
props: {
intent: fields.select({
label: 'Intent',
Expand Down Expand Up @@ -282,8 +279,6 @@ export const componentBlocks = {
);
},
label: 'Quote',
unwrapOnBackspaceAtStart: true,
exitOnEnterInEmptyLineAtEndOfChild: true,
props: {
content: fields.child({ kind: 'block', placeholder: 'Quote...' }),
attribution: fields.child({ kind: 'inline', placeholder: 'Attribution...' }),
Expand Down
36 changes: 18 additions & 18 deletions packages-next/fields-document/TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,26 +23,26 @@
- [ ] supports alignment
- [x] supports links
- [ ] supports soft breaks
- [ ] toolbar behaves as a toggle
- [x] toolbar behaves as a toggle
- [x] you can convert existing blocks to headings
- [ ] inline marks and relationships are stripped when you convert a block into a heading
- [ ] inline marks and relationships are stripped when you convert a block into a heading - why?
- [x] you cannot insert nested headings
- [x] `enter` inserts a new paragraph after the block (including splitting remaining text)
- [ ] `backspace` at the start resets to Paragraph
- [ ] `backspace` at the start resets to Paragraph - sort of true?
- `Lists` (technically, these contain list item blocks)
- [x] contains list items and nested list blocks, no other blocks
- [x] supports links
- [x] supports all inline marks
- [ ] supports soft breaks
- [x] supports inline relationships
- [ ] toolbar behaves as a toggle
- [x] toolbar behaves as a toggle
- [x] `enter` inserts a new list item (including splitting remaining text)
- [x] `enter` in an empty+last-child list item resets to Paragraph after the outermost list block
- [ ] `backspace` at the start of a list item, or in an empty list item, unwraps the list item to the parent list or converts to a paragraph at the top level (including splitting list blocks if followed by more list items)
- [ ] `backspace` at the start of a list item, or in an empty list item, unwraps the list item to the parent list or converts to a paragraph at the top level (including splitting list blocks if followed by more list items) - wrong imo, this is the behaviour of enter. backspace goes to the previous list item
- [x] can be nested, including without any items at the parent level (weird, but ok)
- [x] `tab` indents the current list item into a nested list of the same type
- [ ] `shift+tab` unwraps the list up to the top level (but does not remove the outer list when you are at the top level).
- [ ] using the toolbar to switch list types converts the parent list of the selected list item (not all parents)
- [ ] `shift+tab` unwraps the list up to the top level (but does not remove the outer list when you are at the top level). - why not remove the outer list when at the top level?
- [x] using the toolbar to switch list types converts the parent list of the selected list item (not all parents)
- `Formats` are paragraph-like block types that you can insert, like `blockquote` and `code`.
- [x] contains paragraphs
- [x] supports links
Expand All @@ -57,19 +57,19 @@
- [ ] supports links, soft breaks, inline relationships and all inline marks
- `Divider` is a special block type you can insert that renders a horizontal line
- [x] Supports no children
- [ ] Can be selected by clicking on it (displays hilighted; `backspace` or `delete` removes it)
- [x] Can be selected by clicking on it (displays hilighted; `backspace` or `delete` removes it)
- `Layouts` are a special block type you can insert that contain almost any other block type, laid out horizontally in configurable columns
- [x] contains column blocks, which must contain at least one paragraph (or other block format)
- [x] can contain all built-in block formats
- [x] can contain inline and block relationships
- [ ] can conditionally contain component blocks (based on component config)
- [ ] cannot be nested
- [ ] can only be inserted at the top level of the document
- [x] cannot be nested
- [x] can only be inserted at the top level of the document
- [ ] `tab` at the end of a column moves the cursor to the start of the next column, or after the layout block
- [ ] `shift+tab` at the start of a column moves the cursor to the end of the previous column, or before the layout block
- [ ] layouts "trap" the selection - `enter` does not insert outside of the current column, and `backspace` does not remove columns or the layout block
- [ ] you can select a layout by clicking in its border or margin (displays hilighted; `backspace` or `delete` removes it)
- [ ] when a layout is the last node in a document, we ensure a paragraph exists after it (low priority)
- [x] when a layout is the last node in a document, we ensure a paragraph exists after it (low priority) - a paragraph must always be the last node in a document
- `Relationships` are a thing you can define, with one of three types which determine where it is available. They store a reference to an itemId and are (optionally) hydrated with additional data when the document field is queried. They are voids and contain no editable text.
- `inline` relationships can be inserted into paragraphs and lists, and appear inline (like the "mentions" pattern -- low priority)
- `block` relationships can be inserted like other blocks at the top level of the document, and inside layouts
Expand Down Expand Up @@ -159,7 +159,7 @@ type ComponentChildPropConfig = {

# Cleanup

- [ ] rename `columns` to `layouts`
- [ ] rename `columns` to `layouts` - do we still care about this on a code level?
- [ ] rename `link` config key to `links`
- [ ] nest the following in a `formatting` config key:
- `alignment`
Expand Down Expand Up @@ -235,15 +235,15 @@ type ComponentChildPropConfig = {

# UI Improvements

- [ ] Generate icons for layouts :tada:
- [x] Generate icons for layouts :tada:

- [ ] Hilight blocks in red when hovering over the "remove" toolbar button

- [ ] Only show the innermost toolbar when selection is inside multiple blocks with toolbars

- [ ] Selected style for component block elements

- [ ] Can we find a way to support placeholders for child props in component blocks?
- [x] Can we find a way to support placeholders for child props in component blocks?

- [ ] Caret position at boundary of inline marks

Expand Down Expand Up @@ -309,10 +309,10 @@ Note: the goal for these would be to allow content authors more flexibility, but
- [x] inside paragraphs
- [x] > followed by space converts to a block quote
- [x] inside paragraphs
- [ ] \`\`\` converts to a code block
- [ ] inside paragraphs
- [ ] \#{1,6} followed by space converts to a H{n} heading
- [x] \`\`\` converts to a code block
- [x] inside paragraphs
- [x] \#{1,6} followed by space converts to a H{n} heading
- [x] inside paragraphs
- [ ] inside headings
- [x] inside headings
- [x] \--- inserts a divider
- [x] inside paragraphs
6 changes: 5 additions & 1 deletion packages-next/fields-document/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,9 @@
"slate-history": "^0.59.0",
"slate-react": "npm:slate-react@^0.59.0"
},
"repository": "https://github.com/keystonejs/keystone/tree/master/packages-next/fields-document"
"repository": "https://github.com/keystonejs/keystone/tree/master/packages-next/fields-document",
"devDependencies": {
"array.prototype.flat": "^1.2.4",
"slate-hyperscript": "^0.59.0"
}
}
13 changes: 7 additions & 6 deletions packages-next/fields-document/src/DocumentEditor/Toolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import { Fragment, ReactNode, forwardRef, useState, memo, HTMLAttributes, useMemo } from 'react';
import { Editor, Transforms } from 'slate';
import { useSlate } from 'slate-react';
import { useEditor, useSlate } from 'slate-react';
import { applyRefs } from 'apply-ref';

import { jsx, useTheme } from '@keystone-ui/core';
Expand All @@ -20,7 +20,7 @@ import { MoreHorizontalIcon } from '@keystone-ui/icons/icons/MoreHorizontalIcon'
import { InlineDialog, ToolbarButton, ToolbarGroup, ToolbarSeparator } from './primitives';
import { linkButton } from './link';
import { BlockComponentsButtons } from './component-blocks';
import { Mark, isMarkActive, onlyContainerNodeInCurrentSelection, toggleMark } from './utils';
import { Mark, isMarkActive, toggleMark } from './utils';
import { ColumnsButton } from './columns';
import { ListButton } from './lists';
import { blockquoteButton } from './blockquote';
Expand Down Expand Up @@ -345,14 +345,15 @@ function InnerInsertBlockMenu({
blockTypes: DocumentFeatures['blockTypes'];
onClose: () => void;
}) {
const editor = useSlate();
const shouldInsertBlock = onlyContainerNodeInCurrentSelection(editor);
// useEditor does not update when the value/selection changes.
// that's fine for what it's being used for here
// because we're just inserting things on events, not reading things in render
const editor = useEditor();

return (
<ToolbarGroup direction="column">
{blockTypes.code && (
<ToolbarButton
isDisabled={!shouldInsertBlock}
onMouseDown={event => {
event.preventDefault();
insertCodeBlock(editor);
Expand All @@ -363,7 +364,7 @@ function InnerInsertBlockMenu({
</ToolbarButton>
)}
<RelationshipButton />
<BlockComponentsButtons onClose={onClose} shouldInsertBlock={shouldInsertBlock} />
<BlockComponentsButtons onClose={onClose} />
</ToolbarGroup>
);
}
Expand Down
158 changes: 158 additions & 0 deletions packages-next/fields-document/src/DocumentEditor/blockquote.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/** @jsx jsx */
import { jsx, makeEditor } from './tests/utils';

test('inserting a blockquote with a shortcut works', () => {
let editor = makeEditor(
<editor>
<paragraph>
<text>
{'>'}
<cursor />
</text>
</paragraph>
</editor>
);

editor.insertText(' ');
editor.insertText('some content');
expect(editor).toMatchInlineSnapshot(`
<editor>
<blockquote>
<paragraph>
<text>
some content
<cursor />
</text>
</paragraph>
</blockquote>
<paragraph>
<text>
</text>
</paragraph>
</editor>
`);
});

test('backspace at start of blockquote', () => {
let editor = makeEditor(
<editor>
<blockquote>
<paragraph>
<text>
<cursor />
some content
</text>
</paragraph>
</blockquote>
<paragraph>
<text />
</paragraph>
</editor>
);

editor.deleteBackward('character');
expect(editor).toMatchInlineSnapshot(`
<editor>
<paragraph>
<text>
<cursor />
some content
</text>
</paragraph>
<paragraph>
<text>
</text>
</paragraph>
</editor>
`);
});

test('enter on empty line at end of blockquote exits blockquote', () => {
let editor = makeEditor(
<editor>
<blockquote>
<paragraph>
<text>
<cursor />
some content
</text>
</paragraph>
</blockquote>
<paragraph>
<text />
</paragraph>
</editor>
);

editor.deleteBackward('character');
expect(editor).toMatchInlineSnapshot(`
<editor>
<paragraph>
<text>
<cursor />
some content
</text>
</paragraph>
<paragraph>
<text>
</text>
</paragraph>
</editor>
`);
});

test('enter on empty line in middle splits the blockquote', () => {
let editor = makeEditor(
<editor>
<blockquote>
<paragraph>
<text>some content</text>
</paragraph>
<paragraph>
<text>
<cursor />
</text>
</paragraph>
<paragraph>
<text>some content</text>
</paragraph>
</blockquote>
<paragraph>
<text />
</paragraph>
</editor>
);

editor.insertBreak();
expect(editor).toMatchInlineSnapshot(`
<editor>
<blockquote>
<paragraph>
<text>
some content
</text>
</paragraph>
</blockquote>
<paragraph>
<text>
<cursor />
</text>
</paragraph>
<blockquote>
<paragraph>
<text>
some content
</text>
</paragraph>
</blockquote>
<paragraph>
<text>
</text>
</paragraph>
</editor>
`);
});
Loading

0 comments on commit 7d85977

Please sign in to comment.