More and more fixes
This commit is contained in:
@ -4,7 +4,7 @@ import { observable } from 'mobx';
|
|||||||
import { observer } from 'mobx-react';
|
import { observer } from 'mobx-react';
|
||||||
import { Value, Change } from 'slate';
|
import { Value, Change } from 'slate';
|
||||||
import { Editor } from 'slate-react';
|
import { Editor } from 'slate-react';
|
||||||
import type { SlateNodeProps } from './types';
|
import type { SlateNodeProps, Plugin } from './types';
|
||||||
import Plain from 'slate-plain-serializer';
|
import Plain from 'slate-plain-serializer';
|
||||||
import keydown from 'react-keydown';
|
import keydown from 'react-keydown';
|
||||||
import getDataTransferFiles from 'utils/getDataTransferFiles';
|
import getDataTransferFiles from 'utils/getDataTransferFiles';
|
||||||
@ -16,9 +16,10 @@ import Placeholder from './components/Placeholder';
|
|||||||
import Contents from './components/Contents';
|
import Contents from './components/Contents';
|
||||||
import Markdown from './serializer';
|
import Markdown from './serializer';
|
||||||
import createPlugins from './plugins';
|
import createPlugins from './plugins';
|
||||||
import insertImage from './insertImage';
|
import { insertImageFile } from './changes';
|
||||||
import renderMark from './marks';
|
import renderMark from './marks';
|
||||||
import createRenderNode from './nodes';
|
import createRenderNode from './nodes';
|
||||||
|
import schema from './schema';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@ -37,7 +38,7 @@ class MarkdownEditor extends Component {
|
|||||||
props: Props;
|
props: Props;
|
||||||
editor: Editor;
|
editor: Editor;
|
||||||
renderNode: SlateNodeProps => *;
|
renderNode: SlateNodeProps => *;
|
||||||
plugins: Object[];
|
plugins: Plugin[];
|
||||||
@observable editorValue: Value;
|
@observable editorValue: Value;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
@ -60,12 +61,11 @@ class MarkdownEditor extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
if (!this.props.readOnly) {
|
if (this.props.readOnly) return;
|
||||||
if (this.props.text) {
|
if (this.props.text) {
|
||||||
this.focusAtEnd();
|
this.focusAtEnd();
|
||||||
} else {
|
} else {
|
||||||
this.focusAtStart();
|
this.focusAtStart();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,8 +78,8 @@ class MarkdownEditor extends Component {
|
|||||||
onChange = (change: Change) => {
|
onChange = (change: Change) => {
|
||||||
if (this.editorValue !== change.value) {
|
if (this.editorValue !== change.value) {
|
||||||
this.props.onChange(Markdown.serialize(change.value));
|
this.props.onChange(Markdown.serialize(change.value));
|
||||||
|
this.editorValue = change.value;
|
||||||
}
|
}
|
||||||
this.editorValue = change.value;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
handleDrop = async (ev: SyntheticEvent) => {
|
handleDrop = async (ev: SyntheticEvent) => {
|
||||||
@ -100,15 +100,13 @@ class MarkdownEditor extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
insertImageFile = async (file: window.File) => {
|
insertImageFile = async (file: window.File) => {
|
||||||
this.editor.change(
|
this.editor.change(change =>
|
||||||
async change =>
|
change.call(
|
||||||
await insertImage(
|
insertImageFile,
|
||||||
change,
|
file,
|
||||||
file,
|
this.props.onImageUploadStart,
|
||||||
this.editor,
|
this.props.onImageUploadStop
|
||||||
this.props.onImageUploadStart,
|
)
|
||||||
this.props.onImageUploadStop
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -206,10 +204,12 @@ class MarkdownEditor extends Component {
|
|||||||
value={this.editorValue}
|
value={this.editorValue}
|
||||||
renderNode={this.renderNode}
|
renderNode={this.renderNode}
|
||||||
renderMark={renderMark}
|
renderMark={renderMark}
|
||||||
|
schema={schema}
|
||||||
onKeyDown={this.onKeyDown}
|
onKeyDown={this.onKeyDown}
|
||||||
onChange={this.onChange}
|
onChange={this.onChange}
|
||||||
onSave={onSave}
|
onSave={onSave}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
|
spellCheck={!readOnly}
|
||||||
/>
|
/>
|
||||||
<ClickablePadding
|
<ClickablePadding
|
||||||
onClick={!readOnly ? this.focusAtEnd : undefined}
|
onClick={!readOnly ? this.focusAtEnd : undefined}
|
||||||
|
@ -1,18 +1,46 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import uuid from 'uuid';
|
|
||||||
import uploadFile from 'utils/uploadFile';
|
|
||||||
import { Change } from 'slate';
|
import { Change } from 'slate';
|
||||||
import { Editor } from 'slate-react';
|
import uuid from 'uuid';
|
||||||
|
import EditList from './plugins/EditList';
|
||||||
|
import uploadFile from 'utils/uploadFile';
|
||||||
|
|
||||||
export default async function insertImageFile(
|
const { changes } = EditList;
|
||||||
|
|
||||||
|
type Options = {
|
||||||
|
type: string | Object,
|
||||||
|
wrapper?: string | Object,
|
||||||
|
append?: string | Object,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function splitAndInsertBlock(change: Change, options: Options) {
|
||||||
|
const { type, wrapper, append } = options;
|
||||||
|
const parent = change.value.document.getParent(change.value.startBlock.key);
|
||||||
|
|
||||||
|
// lists get some special treatment
|
||||||
|
if (parent && parent.type === 'list-item') {
|
||||||
|
change = changes.unwrapList(
|
||||||
|
changes
|
||||||
|
.splitListItem(change.collapseToStart())
|
||||||
|
.collapseToEndOfPreviousBlock()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
change = change.insertBlock(type);
|
||||||
|
|
||||||
|
if (wrapper) change = change.wrapBlock(wrapper);
|
||||||
|
if (append) change = change.insertBlock(append);
|
||||||
|
|
||||||
|
return change;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function insertImageFile(
|
||||||
change: Change,
|
change: Change,
|
||||||
file: window.File,
|
file: window.File,
|
||||||
editor: Editor,
|
|
||||||
onImageUploadStart: () => void,
|
onImageUploadStart: () => void,
|
||||||
onImageUploadStop: () => void
|
onImageUploadStop: () => void
|
||||||
) {
|
) {
|
||||||
onImageUploadStart();
|
onImageUploadStart();
|
||||||
|
console.log(file);
|
||||||
try {
|
try {
|
||||||
// load the file as a data URL
|
// load the file as a data URL
|
||||||
const id = uuid.v4();
|
const id = uuid.v4();
|
||||||
@ -27,6 +55,7 @@ export default async function insertImageFile(
|
|||||||
isVoid: true,
|
isVoid: true,
|
||||||
data: { src, id, alt, loading: true },
|
data: { src, id, alt, loading: true },
|
||||||
});
|
});
|
||||||
|
console.log('insertBlock', change);
|
||||||
});
|
});
|
||||||
reader.readAsDataURL(file);
|
reader.readAsDataURL(file);
|
||||||
|
|
||||||
@ -37,12 +66,12 @@ export default async function insertImageFile(
|
|||||||
// we dont use the original change provided to the callback here
|
// we dont use the original change provided to the callback here
|
||||||
// as the state may have changed significantly in the time it took to
|
// as the state may have changed significantly in the time it took to
|
||||||
// upload the file.
|
// upload the file.
|
||||||
const finalTransform = editor.value.change();
|
const placeholder = change.value.document.findDescendant(
|
||||||
const placeholder = editor.value.document.findDescendant(
|
|
||||||
node => node.data && node.data.get('id') === id
|
node => node.data && node.data.get('id') === id
|
||||||
);
|
);
|
||||||
|
console.log('placeholder', placeholder);
|
||||||
|
|
||||||
return finalTransform.setNodeByKey(placeholder.key, {
|
return change.setNodeByKey(placeholder.key, {
|
||||||
data: { src, alt, loading: false },
|
data: { src, alt, loading: false },
|
||||||
});
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
@ -10,12 +10,9 @@ export default class TodoItem extends Component {
|
|||||||
handleChange = (ev: SyntheticInputEvent) => {
|
handleChange = (ev: SyntheticInputEvent) => {
|
||||||
const checked = ev.target.checked;
|
const checked = ev.target.checked;
|
||||||
const { editor, node } = this.props;
|
const { editor, node } = this.props;
|
||||||
const change = editor
|
editor.change(change =>
|
||||||
.getState()
|
change.setNodeByKey(node.key, { data: { checked } })
|
||||||
.change()
|
);
|
||||||
.setNodeByKey(node.key, { data: { checked } });
|
|
||||||
|
|
||||||
editor.onChange(change);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -16,7 +16,7 @@ import ToolbarButton from './components/ToolbarButton';
|
|||||||
import type { SlateNodeProps } from '../../types';
|
import type { SlateNodeProps } from '../../types';
|
||||||
import { color } from 'shared/styles/constants';
|
import { color } from 'shared/styles/constants';
|
||||||
import { fadeIn } from 'shared/styles/animations';
|
import { fadeIn } from 'shared/styles/animations';
|
||||||
import { splitAndInsertBlock } from '../../transforms';
|
import { splitAndInsertBlock } from '../../changes';
|
||||||
|
|
||||||
type Props = SlateNodeProps & {
|
type Props = SlateNodeProps & {
|
||||||
onInsertImage: *,
|
onInsertImage: *,
|
||||||
@ -61,7 +61,7 @@ class BlockToolbar extends Component {
|
|||||||
editor.change(change => {
|
editor.change(change => {
|
||||||
splitAndInsertBlock(change, options);
|
splitAndInsertBlock(change, options);
|
||||||
|
|
||||||
change.value.document.nodes.forEach(node => {
|
editor.value.document.nodes.forEach(node => {
|
||||||
if (node.type === 'block-toolbar') {
|
if (node.type === 'block-toolbar') {
|
||||||
change.removeNodeByKey(node.key);
|
change.removeNodeByKey(node.key);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import ReactDOM from 'react-dom';
|
|||||||
import { observable, action } from 'mobx';
|
import { observable, action } from 'mobx';
|
||||||
import { observer, inject } from 'mobx-react';
|
import { observer, inject } from 'mobx-react';
|
||||||
import { withRouter } from 'react-router-dom';
|
import { withRouter } from 'react-router-dom';
|
||||||
import { Change } from 'slate';
|
|
||||||
import { Editor } from 'slate-react';
|
import { Editor } from 'slate-react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
import ArrowKeyNavigation from 'boundless-arrow-key-navigation';
|
import ArrowKeyNavigation from 'boundless-arrow-key-navigation';
|
||||||
@ -28,7 +27,6 @@ class LinkToolbar extends Component {
|
|||||||
link: Object,
|
link: Object,
|
||||||
documents: DocumentsStore,
|
documents: DocumentsStore,
|
||||||
onBlur: () => void,
|
onBlur: () => void,
|
||||||
onChange: Change => *,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@observable isEditing: boolean = false;
|
@observable isEditing: boolean = false;
|
||||||
|
@ -22,7 +22,7 @@ type Options = {
|
|||||||
onInsertImage: *,
|
onInsertImage: *,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function createRenderNode({ onChange, onInsertImage }: Options) {
|
export default function createRenderNode({ onInsertImage }: Options) {
|
||||||
return function renderNode(props: SlateNodeProps) {
|
return function renderNode(props: SlateNodeProps) {
|
||||||
const { attributes } = props;
|
const { attributes } = props;
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// @flow
|
// @flow
|
||||||
// import DropOrPasteImages from '@tommoor/slate-drop-or-paste-images';
|
import InsertImages from 'slate-drop-or-paste-images';
|
||||||
import PasteLinkify from 'slate-paste-linkify';
|
import PasteLinkify from 'slate-paste-linkify';
|
||||||
import CollapseOnEscape from 'slate-collapse-on-escape';
|
import CollapseOnEscape from 'slate-collapse-on-escape';
|
||||||
import TrailingBlock from 'slate-trailing-block';
|
import TrailingBlock from 'slate-trailing-block';
|
||||||
@ -8,7 +8,7 @@ import Prism from 'slate-prism';
|
|||||||
import EditList from './plugins/EditList';
|
import EditList from './plugins/EditList';
|
||||||
import KeyboardShortcuts from './plugins/KeyboardShortcuts';
|
import KeyboardShortcuts from './plugins/KeyboardShortcuts';
|
||||||
import MarkdownShortcuts from './plugins/MarkdownShortcuts';
|
import MarkdownShortcuts from './plugins/MarkdownShortcuts';
|
||||||
// import insertImage from './insertImage';
|
import { insertImageFile } from './changes';
|
||||||
|
|
||||||
const onlyInCode = node => node.type === 'code';
|
const onlyInCode = node => node.type === 'code';
|
||||||
|
|
||||||
@ -23,18 +23,17 @@ const createPlugins = ({ onImageUploadStart, onImageUploadStop }: Options) => {
|
|||||||
type: 'link',
|
type: 'link',
|
||||||
collapseTo: 'end',
|
collapseTo: 'end',
|
||||||
}),
|
}),
|
||||||
// DropOrPasteImages({
|
InsertImages({
|
||||||
// extensions: ['png', 'jpg', 'gif'],
|
extensions: ['png', 'jpg', 'gif'],
|
||||||
// applyTransform: (transform, file, editor) => {
|
insertImage(change, file) {
|
||||||
// return insertImage(
|
return change.call(
|
||||||
// transform,
|
insertImageFile,
|
||||||
// file,
|
file,
|
||||||
// editor,
|
onImageUploadStart,
|
||||||
// onImageUploadStart,
|
onImageUploadStop
|
||||||
// onImageUploadStop
|
);
|
||||||
// );
|
},
|
||||||
// },
|
}),
|
||||||
// }),
|
|
||||||
EditList,
|
EditList,
|
||||||
EditCode({
|
EditCode({
|
||||||
onlyIn: onlyInCode,
|
onlyIn: onlyInCode,
|
||||||
|
@ -4,4 +4,5 @@ import EditList from 'slate-edit-list';
|
|||||||
export default EditList({
|
export default EditList({
|
||||||
types: ['ordered-list', 'bulleted-list', 'todo-list'],
|
types: ['ordered-list', 'bulleted-list', 'todo-list'],
|
||||||
typeItem: 'list-item',
|
typeItem: 'list-item',
|
||||||
|
typeDefault: 'paragraph',
|
||||||
});
|
});
|
||||||
|
@ -182,8 +182,8 @@ export default function MarkdownShortcuts() {
|
|||||||
|
|
||||||
change.removeMarkByKey(
|
change.removeMarkByKey(
|
||||||
textNode.key,
|
textNode.key,
|
||||||
change.startOffset - charsInCodeBlock.size,
|
startOffset - charsInCodeBlock.size,
|
||||||
change.startOffset,
|
startOffset,
|
||||||
'code'
|
'code'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -210,10 +210,13 @@ export default function MarkdownShortcuts() {
|
|||||||
onEnter(ev: SyntheticKeyboardEvent, change: Change) {
|
onEnter(ev: SyntheticKeyboardEvent, change: Change) {
|
||||||
const { value } = change;
|
const { value } = change;
|
||||||
if (value.isExpanded) return;
|
if (value.isExpanded) return;
|
||||||
|
|
||||||
const { startBlock, startOffset, endOffset } = value;
|
const { startBlock, startOffset, endOffset } = value;
|
||||||
if (startOffset === 0 && startBlock.length === 0)
|
if (startOffset === 0 && startBlock.length === 0)
|
||||||
return this.onBackspace(ev, change);
|
return this.onBackspace(ev, change);
|
||||||
if (endOffset !== startBlock.length) return;
|
|
||||||
|
// Hitting enter at the end of the line reverts to standard behavior
|
||||||
|
if (endOffset === startBlock.length) return;
|
||||||
|
|
||||||
// Hitting enter while an image is selected should jump caret below and
|
// Hitting enter while an image is selected should jump caret below and
|
||||||
// insert a new paragraph
|
// insert a new paragraph
|
||||||
@ -225,19 +228,12 @@ export default function MarkdownShortcuts() {
|
|||||||
// Hitting enter in a heading or blockquote will split the node at that
|
// Hitting enter in a heading or blockquote will split the node at that
|
||||||
// point and make the new node a paragraph
|
// point and make the new node a paragraph
|
||||||
if (
|
if (
|
||||||
startBlock.type !== 'heading1' &&
|
startBlock.type.startsWith('heading') ||
|
||||||
startBlock.type !== 'heading2' &&
|
startBlock.type === 'block-quote'
|
||||||
startBlock.type !== 'heading3' &&
|
|
||||||
startBlock.type !== 'heading4' &&
|
|
||||||
startBlock.type !== 'heading5' &&
|
|
||||||
startBlock.type !== 'heading6' &&
|
|
||||||
startBlock.type !== 'block-quote'
|
|
||||||
) {
|
) {
|
||||||
return;
|
ev.preventDefault();
|
||||||
|
return change.splitBlock().setBlock('paragraph');
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.preventDefault();
|
|
||||||
change.splitBlock().setBlock('paragraph');
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,133 +1,82 @@
|
|||||||
// // @flow
|
// @flow
|
||||||
// import React from 'react';
|
import { Block, Change, Node, Mark } from 'slate';
|
||||||
// import Code from './components/Code';
|
|
||||||
// import HorizontalRule from './components/HorizontalRule';
|
const schema = {
|
||||||
// import InlineCode from './components/InlineCode';
|
blocks: {
|
||||||
// import Image from './components/Image';
|
heading1: { marks: [''] },
|
||||||
// import Link from './components/Link';
|
heading2: { marks: [''] },
|
||||||
// import ListItem from './components/ListItem';
|
heading3: { marks: [''] },
|
||||||
// import TodoList from './components/TodoList';
|
heading4: { marks: [''] },
|
||||||
// import {
|
heading5: { marks: [''] },
|
||||||
// Heading1,
|
heading6: { marks: [''] },
|
||||||
// Heading2,
|
'ordered-list': {
|
||||||
// Heading3,
|
nodes: [{ types: ['list-item'] }],
|
||||||
// Heading4,
|
},
|
||||||
// Heading5,
|
'bulleted-list': {
|
||||||
// Heading6,
|
nodes: [{ types: ['list-item'] }],
|
||||||
// } from './components/Heading';
|
},
|
||||||
// import Paragraph from './components/Paragraph';
|
table: {
|
||||||
// import BlockToolbar from './components/Toolbar/BlockToolbar';
|
nodes: [{ types: ['table-row', 'table-head', 'table-cell'] }],
|
||||||
// import type { Props, Node, Transform } from './types';
|
},
|
||||||
//
|
image: {
|
||||||
// type Options = {
|
isVoid: true,
|
||||||
// onInsertImage: Function,
|
},
|
||||||
// onChange: Function,
|
'horizontal-rule': {
|
||||||
// };
|
isVoid: true,
|
||||||
//
|
},
|
||||||
// const createSchema = ({ onInsertImage, onChange }: Options) => {
|
'block-toolbar': {
|
||||||
// return {
|
isVoid: true,
|
||||||
// marks: {
|
},
|
||||||
// bold: (props: Props) => <strong>{props.children}</strong>,
|
},
|
||||||
// code: (props: Props) => <InlineCode>{props.children}</InlineCode>,
|
document: {
|
||||||
// italic: (props: Props) => <em>{props.children}</em>,
|
nodes: [
|
||||||
// underlined: (props: Props) => <u>{props.children}</u>,
|
{ types: ['heading1'], min: 1, max: 1 },
|
||||||
// deleted: (props: Props) => <del>{props.children}</del>,
|
{
|
||||||
// added: (props: Props) => <mark>{props.children}</mark>,
|
types: [
|
||||||
// },
|
'paragraph',
|
||||||
//
|
'heading1',
|
||||||
// nodes: {
|
'heading2',
|
||||||
// 'block-toolbar': (props: Props) => (
|
'heading3',
|
||||||
// <BlockToolbar
|
'heading4',
|
||||||
// onChange={onChange}
|
'heading5',
|
||||||
// onInsertImage={onInsertImage}
|
'heading6',
|
||||||
// {...props}
|
'code',
|
||||||
// />
|
'horizontal-rule',
|
||||||
// ),
|
'image',
|
||||||
// paragraph: (props: Props) => <Paragraph {...props} />,
|
'bulleted-list',
|
||||||
// 'block-quote': (props: Props) => (
|
'ordered-list',
|
||||||
// <blockquote {...props.attributes}>{props.children}</blockquote>
|
'todo-list',
|
||||||
// ),
|
'block-toolbar',
|
||||||
// 'horizontal-rule': HorizontalRule,
|
'table',
|
||||||
// 'bulleted-list': (props: Props) => (
|
],
|
||||||
// <ul {...props.attributes}>{props.children}</ul>
|
min: 1,
|
||||||
// ),
|
},
|
||||||
// 'ordered-list': (props: Props) => (
|
],
|
||||||
// <ol {...props.attributes}>{props.children}</ol>
|
normalize: (
|
||||||
// ),
|
change: Change,
|
||||||
// 'todo-list': (props: Props) => (
|
reason: string,
|
||||||
// <TodoList {...props.attributes}>{props.children}</TodoList>
|
{
|
||||||
// ),
|
node,
|
||||||
// table: (props: Props) => (
|
child,
|
||||||
// <table {...props.attributes}>{props.children}</table>
|
mark,
|
||||||
// ),
|
index,
|
||||||
// 'table-row': (props: Props) => (
|
}: { node: Node, mark?: Mark, child: Node, index: number }
|
||||||
// <tr {...props.attributes}>{props.children}</tr>
|
) => {
|
||||||
// ),
|
switch (reason) {
|
||||||
// 'table-head': (props: Props) => (
|
case 'child_type_invalid': {
|
||||||
// <th {...props.attributes}>{props.children}</th>
|
return change.setNodeByKey(
|
||||||
// ),
|
child.key,
|
||||||
// 'table-cell': (props: Props) => (
|
index === 0 ? 'heading1' : 'paragraph'
|
||||||
// <td {...props.attributes}>{props.children}</td>
|
);
|
||||||
// ),
|
}
|
||||||
// code: Code,
|
case 'child_required': {
|
||||||
// image: Image,
|
const block = Block.create(index === 0 ? 'heading1' : 'paragraph');
|
||||||
// link: Link,
|
return change.insertNodeByKey(node.key, index, block);
|
||||||
// 'list-item': ListItem,
|
}
|
||||||
// heading1: (props: Props) => <Heading1 placeholder {...props} />,
|
default:
|
||||||
// heading2: (props: Props) => <Heading2 {...props} />,
|
}
|
||||||
// heading3: (props: Props) => <Heading3 {...props} />,
|
},
|
||||||
// heading4: (props: Props) => <Heading4 {...props} />,
|
},
|
||||||
// heading5: (props: Props) => <Heading5 {...props} />,
|
};
|
||||||
// heading6: (props: Props) => <Heading6 {...props} />,
|
|
||||||
// },
|
export default schema;
|
||||||
//
|
|
||||||
// rules: [
|
|
||||||
// // ensure first node is always a heading
|
|
||||||
// {
|
|
||||||
// match: (node: Node) => {
|
|
||||||
// return node.kind === 'document';
|
|
||||||
// },
|
|
||||||
// validate: (document: Node) => {
|
|
||||||
// const firstNode = document.nodes.first();
|
|
||||||
// return firstNode && firstNode.type === 'heading1' ? null : firstNode;
|
|
||||||
// },
|
|
||||||
// normalize: (transform: Transform, document: Node, firstNode: Node) => {
|
|
||||||
// transform.setBlock({ type: 'heading1' });
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
//
|
|
||||||
// // automatically removes any marks in first heading
|
|
||||||
// {
|
|
||||||
// match: (node: Node) => {
|
|
||||||
// return node.kind === 'heading1';
|
|
||||||
// },
|
|
||||||
// validate: (heading: Node) => {
|
|
||||||
// const hasMarks = heading.getMarks().isEmpty();
|
|
||||||
// const hasInlines = heading.getInlines().isEmpty();
|
|
||||||
//
|
|
||||||
// return !(hasMarks && hasInlines);
|
|
||||||
// },
|
|
||||||
// normalize: (transform: Transform, heading: Node) => {
|
|
||||||
// transform.unwrapInlineByKey(heading.key);
|
|
||||||
//
|
|
||||||
// heading.getMarks().forEach(mark => {
|
|
||||||
// heading.nodes.forEach(textNode => {
|
|
||||||
// if (textNode.kind === 'text') {
|
|
||||||
// transform.removeMarkByKey(
|
|
||||||
// textNode.key,
|
|
||||||
// 0,
|
|
||||||
// textNode.text.length,
|
|
||||||
// mark
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// });
|
|
||||||
//
|
|
||||||
// return transform;
|
|
||||||
// },
|
|
||||||
// },
|
|
||||||
// ],
|
|
||||||
// };
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// export default createSchema;
|
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
// @flow
|
|
||||||
import { Change } from 'slate';
|
|
||||||
import EditList from './plugins/EditList';
|
|
||||||
|
|
||||||
const { changes } = EditList;
|
|
||||||
|
|
||||||
type Options = {
|
|
||||||
type: string | Object,
|
|
||||||
wrapper?: string | Object,
|
|
||||||
append?: string | Object,
|
|
||||||
};
|
|
||||||
|
|
||||||
export function splitAndInsertBlock(change: Change, options: Options) {
|
|
||||||
const { type, wrapper, append } = options;
|
|
||||||
const { value } = change;
|
|
||||||
const { document } = value;
|
|
||||||
const parent = document.getParent(value.startBlock.key);
|
|
||||||
|
|
||||||
// lists get some special treatment
|
|
||||||
if (parent && parent.type === 'list-item') {
|
|
||||||
change = changes.unwrapList(
|
|
||||||
changes
|
|
||||||
.splitListItem(change.collapseToStart())
|
|
||||||
.collapseToEndOfPreviousBlock()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
change = change.insertBlock(type);
|
|
||||||
|
|
||||||
if (wrapper) change = change.wrapBlock(wrapper);
|
|
||||||
if (append) change = change.insertBlock(append);
|
|
||||||
|
|
||||||
return change;
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import { Value, Node } from 'slate';
|
import { Value, Change, Node } from 'slate';
|
||||||
import { Editor } from 'slate-react';
|
import { Editor } from 'slate-react';
|
||||||
|
|
||||||
export type SlateNodeProps = {
|
export type SlateNodeProps = {
|
||||||
@ -11,3 +11,9 @@ export type SlateNodeProps = {
|
|||||||
node: Node,
|
node: Node,
|
||||||
parent: Node,
|
parent: Node,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type Plugin = {
|
||||||
|
validateNode?: Node => *,
|
||||||
|
onClick?: SyntheticEvent => *,
|
||||||
|
onKeyDown?: (SyntheticKeyboardEvent, Change) => *,
|
||||||
|
};
|
||||||
|
@ -61,7 +61,6 @@
|
|||||||
"url": "git+ssh://git@github.com/outline/outline.git"
|
"url": "git+ssh://git@github.com/outline/outline.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tommoor/slate-drop-or-paste-images": "0.5.1",
|
|
||||||
"aws-sdk": "^2.135.0",
|
"aws-sdk": "^2.135.0",
|
||||||
"babel-core": "^6.24.1",
|
"babel-core": "^6.24.1",
|
||||||
"babel-eslint": "^7.2.3",
|
"babel-eslint": "^7.2.3",
|
||||||
@ -163,9 +162,10 @@
|
|||||||
"sequelize-encrypted": "0.1.0",
|
"sequelize-encrypted": "0.1.0",
|
||||||
"slate": "^0.29.0",
|
"slate": "^0.29.0",
|
||||||
"slate-collapse-on-escape": "^0.6.0",
|
"slate-collapse-on-escape": "^0.6.0",
|
||||||
|
"slate-drop-or-paste-images": "^0.8.0",
|
||||||
"slate-edit-code": "^0.13.2",
|
"slate-edit-code": "^0.13.2",
|
||||||
"slate-edit-list": "^0.10.1",
|
"slate-edit-list": "^0.10.1",
|
||||||
"slate-md-serializer": "1.0.1",
|
"slate-md-serializer": "^1.0.4",
|
||||||
"slate-paste-linkify": "^0.5.0",
|
"slate-paste-linkify": "^0.5.0",
|
||||||
"slate-plain-serializer": "^0.4.12",
|
"slate-plain-serializer": "^0.4.12",
|
||||||
"slate-prism": "^0.4.0",
|
"slate-prism": "^0.4.0",
|
||||||
|
36
yarn.lock
36
yarn.lock
@ -2,18 +2,6 @@
|
|||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
"@tommoor/slate-drop-or-paste-images@0.5.1":
|
|
||||||
version "0.5.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/@tommoor/slate-drop-or-paste-images/-/slate-drop-or-paste-images-0.5.1.tgz#67a8853bb59d3a449f2fe7c7071dc19fe3aff93d"
|
|
||||||
dependencies:
|
|
||||||
data-uri-to-blob "0.0.4"
|
|
||||||
es6-promise "^4.0.5"
|
|
||||||
image-to-data-uri "^1.0.0"
|
|
||||||
is-data-uri "^0.1.0"
|
|
||||||
is-image "^1.0.1"
|
|
||||||
is-url "^1.2.2"
|
|
||||||
mime-types "^2.1.11"
|
|
||||||
|
|
||||||
"@types/geojson@^1.0.0":
|
"@types/geojson@^1.0.0":
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-1.0.3.tgz#fbcf7fa5eb6dd108d51385cc6987ec1f24214523"
|
resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-1.0.3.tgz#fbcf7fa5eb6dd108d51385cc6987ec1f24214523"
|
||||||
@ -2172,10 +2160,6 @@ data-uri-regex@^0.1.2:
|
|||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/data-uri-regex/-/data-uri-regex-0.1.4.tgz#1e1db6c8397eca8a48ecdb55ad1b927ec0bbac2e"
|
resolved "https://registry.yarnpkg.com/data-uri-regex/-/data-uri-regex-0.1.4.tgz#1e1db6c8397eca8a48ecdb55ad1b927ec0bbac2e"
|
||||||
|
|
||||||
data-uri-to-blob@0.0.4:
|
|
||||||
version "0.0.4"
|
|
||||||
resolved "https://registry.yarnpkg.com/data-uri-to-blob/-/data-uri-to-blob-0.0.4.tgz#087a7bff42f41a6cc0b2e2fb7312a7c29904fbaa"
|
|
||||||
|
|
||||||
date-fns@^1.27.2:
|
date-fns@^1.27.2:
|
||||||
version "1.28.5"
|
version "1.28.5"
|
||||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.28.5.tgz#257cfc45d322df45ef5658665967ee841cd73faf"
|
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.28.5.tgz#257cfc45d322df45ef5658665967ee841cd73faf"
|
||||||
@ -8217,10 +8201,22 @@ slate-collapse-on-escape@^0.6.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
to-pascal-case "^1.0.0"
|
to-pascal-case "^1.0.0"
|
||||||
|
|
||||||
slate-dev-logger@^0.1.25, slate-dev-logger@^0.1.36:
|
slate-dev-logger@^0.1.0, slate-dev-logger@^0.1.25, slate-dev-logger@^0.1.36:
|
||||||
version "0.1.36"
|
version "0.1.36"
|
||||||
resolved "https://registry.npmjs.org/slate-dev-logger/-/slate-dev-logger-0.1.36.tgz#ecdb37dbf944dfc742bab23b6a20d5a0472db95e"
|
resolved "https://registry.npmjs.org/slate-dev-logger/-/slate-dev-logger-0.1.36.tgz#ecdb37dbf944dfc742bab23b6a20d5a0472db95e"
|
||||||
|
|
||||||
|
slate-drop-or-paste-images@^0.8.0:
|
||||||
|
version "0.8.0"
|
||||||
|
resolved "https://registry.npmjs.org/slate-drop-or-paste-images/-/slate-drop-or-paste-images-0.8.0.tgz#2c363a117688c1b57517ab9cd468c4060e09824e"
|
||||||
|
dependencies:
|
||||||
|
es6-promise "^4.0.5"
|
||||||
|
image-to-data-uri "^1.0.0"
|
||||||
|
is-data-uri "^0.1.0"
|
||||||
|
is-image "^1.0.1"
|
||||||
|
is-url "^1.2.2"
|
||||||
|
mime-types "^2.1.11"
|
||||||
|
slate-dev-logger "^0.1.0"
|
||||||
|
|
||||||
slate-edit-code@^0.13.2:
|
slate-edit-code@^0.13.2:
|
||||||
version "0.13.2"
|
version "0.13.2"
|
||||||
resolved "https://registry.npmjs.org/slate-edit-code/-/slate-edit-code-0.13.2.tgz#682a7640da076906e5b4a4c73ec0e46d31d92c62"
|
resolved "https://registry.npmjs.org/slate-edit-code/-/slate-edit-code-0.13.2.tgz#682a7640da076906e5b4a4c73ec0e46d31d92c62"
|
||||||
@ -8234,9 +8230,9 @@ slate-edit-list@^0.10.1:
|
|||||||
version "0.10.1"
|
version "0.10.1"
|
||||||
resolved "https://registry.npmjs.org/slate-edit-list/-/slate-edit-list-0.10.1.tgz#9c6a142a314b0ff22a327f1b50c8f5c85468cb17"
|
resolved "https://registry.npmjs.org/slate-edit-list/-/slate-edit-list-0.10.1.tgz#9c6a142a314b0ff22a327f1b50c8f5c85468cb17"
|
||||||
|
|
||||||
slate-md-serializer@1.0.1:
|
slate-md-serializer@^1.0.4:
|
||||||
version "1.0.1"
|
version "1.0.4"
|
||||||
resolved "https://registry.npmjs.org/slate-md-serializer/-/slate-md-serializer-1.0.1.tgz#10fb8118bf0b97addaf9d7fd77c1b19f3d767309"
|
resolved "https://registry.npmjs.org/slate-md-serializer/-/slate-md-serializer-1.0.4.tgz#519b819b436706a31d93a8e787657694c0c75d35"
|
||||||
|
|
||||||
slate-paste-linkify@^0.5.0:
|
slate-paste-linkify@^0.5.0:
|
||||||
version "0.5.0"
|
version "0.5.0"
|
||||||
|
Reference in New Issue
Block a user