mirror of
https://github.com/ianstormtaylor/slate.git
synced 2025-08-29 18:09:49 +02:00
Improved Types (#4119)
* Experimental release to see if CustomTypes holds up through a publish * Add experimental release script * Fix lint * v0.60.5-alpha.0 * Allow null properties in setNodes * v0.60.6-alpha.0 * Revert null properties on Transforms.setNodes * v0.60.7-alpha.0 * Update examples to use custom Element and Text with discriminated unions * Add documentation for using TypeScript improvements * Be explicit about typescript version in package.json * Force lerna bootstrap to fix build issues on CI and fix a few type examples * Add slate devDependencies with * back * v0.60.7 * Switch to a non prerelease version to fix lerna not linking in root * Add documentation for not using prerelease versions and on how to create experimental releases * Try removing lerna bootstrap and see if it works
This commit is contained in:
@@ -80,6 +80,10 @@ If you only want to run a specific test or tests, you can run `yarn test --fgrep
|
||||
|
||||
## Publishing Releases
|
||||
|
||||
**Important**: When creating releases using Lerna with the instructions below, you will be given choices around how to increase version numbers. You should always use a `major`, `minor` or `patch` release and must never use a `prerelease`. If a prerelease is used, the root package will not link to the packages in the `packages` directory creating hard to diagnose issues.
|
||||
|
||||
### Publishing Normal `@latest` Release
|
||||
|
||||
Since we use [Lerna](https://lerna.js.org) to manage the Slate packages this is fairly easy, just run:
|
||||
|
||||
```shell
|
||||
@@ -90,7 +94,7 @@ And follow the prompts Lerna gives you.
|
||||
|
||||
Note that this will automatically run the prelease script first that will build, test and lint before attempting to publish.
|
||||
|
||||
## Publishing `@next` Releases
|
||||
### Publishing `@next` Release
|
||||
|
||||
If we are unsure as to the stability of a release because there are significant changes and/or particularly complex changes, release with the `@next` tag.
|
||||
|
||||
@@ -100,7 +104,15 @@ yarn release:next
|
||||
|
||||
And follow the prompts Lerna gives you.
|
||||
|
||||
## Running Prerelease Script
|
||||
### Publishing `@experimental` Release
|
||||
|
||||
If you need to create an experimental release to see how a published package will behave during an actual publish, release with the `@experimental` tag. End users should have no expectation that an `@experimental` release will be usable.
|
||||
|
||||
```shell
|
||||
yarn release:experimental
|
||||
```
|
||||
|
||||
### Running Prerelease Script
|
||||
|
||||
If we want to make sure that Slate code follows the preparations for a release but without actually publishing, run:
|
||||
|
||||
|
@@ -22,6 +22,7 @@
|
||||
- [Rendering](./concepts/08-rendering.md)
|
||||
- [Serializing](./concepts/09-serializing.md)
|
||||
- [Normalizing](./concepts/10-normalizing.md)
|
||||
- [TypeScript](./concepts/11-typescript.md)
|
||||
- [Migrating](./concepts/XX-migrating.md)
|
||||
|
||||
## API
|
||||
|
91
docs/concepts/11-typescript.md
Normal file
91
docs/concepts/11-typescript.md
Normal file
@@ -0,0 +1,91 @@
|
||||
# TypeScript
|
||||
|
||||
Slate supports typing of one Slate document model (eg. one set of custom `Element` and `Text` types).
|
||||
|
||||
If you need to support more than one document model, see the section Multiple Document Models.
|
||||
|
||||
## Defining Custom Element and Text Types
|
||||
|
||||
To define a custom `Element` or `Text` type, extend the `CustomTypes` interface in the `slate` module like this.
|
||||
|
||||
```ts
|
||||
declare module 'slate' {
|
||||
interface CustomTypes {
|
||||
Element: { type: 'paragraph'; children: Descendant[] }
|
||||
Text: { text: string; bold: boolean; italic: boolean }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Recommended Custom Element and Text
|
||||
|
||||
While you can define types directly in the `CustomTypes` interface, best practice is to:
|
||||
|
||||
- define and export each custom `Element`/`Text` type
|
||||
- merge these into and export `CustomElement`/`CustomText` type
|
||||
- Use the `CustomElement`/`CustomText` in the `CustomTypes` definition
|
||||
|
||||
These are best practices because elsewhere in your code, you may want to directly reference a specific `Element` type like a bullet or image.
|
||||
|
||||
Using best practices, the custom types will look something like:
|
||||
|
||||
```ts
|
||||
export type ParagraphElement = {
|
||||
type: 'paragraph'
|
||||
children: Descendant
|
||||
}
|
||||
|
||||
export type HeadingElement = {
|
||||
type: 'paragraph'
|
||||
level: number
|
||||
children: Descendant
|
||||
}
|
||||
|
||||
export type CustomElement = ParagraphElement | HeadingElement
|
||||
|
||||
export type FormattedText = { text: 'string'; bold: boolean; italic: boolean }
|
||||
|
||||
export type CustomText = FormattedText
|
||||
|
||||
declare module 'slate' {
|
||||
interface CustomTypes {
|
||||
Element: CustomElement
|
||||
Text: CustomText
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example, `CustomText` is equal to `FormattedText` but in a real editor, there can be more types of text like text in a code block which may not allow formatting for example.
|
||||
|
||||
## Why Is The Type Definition Unusual
|
||||
|
||||
Because it gets asked often, this section explains why Slate's type definition is atypical.
|
||||
|
||||
Slate needs to support a feature called type discrimination which is available when using union types (e.g. `ParagraphElement | HeadingElement`). This allows a user to narrow a type. If presented with code like `if (node.type === 'paragraph') { ... }` the inside of the block, will narrow the type of node to `ParagraphElement`.
|
||||
|
||||
Slate also needs a way to allow developers to get their custom types into Slate. This is done through declaration merging which is a feature of an `interface`.
|
||||
|
||||
Slate combines a union type and an interface to deliver this feature.
|
||||
|
||||
For more information see [Proposal: Add Custom TypeScript Types to Slate](https://github.com/ianstormtaylor/slate/issues/3725)
|
||||
|
||||
## Multiple Document Models
|
||||
|
||||
At the moment, Slate only supports types for a single document model at a time. For example, it cannot support a full Rich Text Editor for editing documents while also having a less featured Editor for editing comments.
|
||||
|
||||
Slate's TypeScript support was designed this way because some improved typing support was better than none. The goal is to also support typing for multiple editor definitions but this will depend on community support.
|
||||
|
||||
One workaround for support multiple document models is to create each editor in a separate package and then import them. This hasn't been tested but should work.
|
||||
|
||||
## Extending Other Types
|
||||
|
||||
Currently there is also support for extending:
|
||||
|
||||
- `Editor`
|
||||
- `Selection`
|
||||
- `Range`
|
||||
- `Point`
|
||||
|
||||
Feel free to extend these types but extended these types should be considered experimental. We are actively looking for better ways to implement this.
|
||||
|
||||
For some examples of how to extend these types, see `packages/slate-react/src/custom-types.ts` in the slate repository.
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"lerna": "2.7.1",
|
||||
"version": "0.60.4",
|
||||
"version": "0.60.7",
|
||||
"npmClient": "yarn",
|
||||
"useWorkspaces": true
|
||||
}
|
||||
|
@@ -19,8 +19,10 @@
|
||||
"prerelease": "cross-env NODE_ENV=production yarn build:rollup && yarn test && yarn lint",
|
||||
"release:publish:latext": "lerna publish",
|
||||
"release:publish:next": "lerna publish --dist-tag next",
|
||||
"release:publish:experimental": "lerna publish --dist-tag experimental",
|
||||
"release:latest": "yarn prerelease && lerna publish",
|
||||
"release:next": "yarn prerelease && lerna publish --dist-tag next",
|
||||
"release:experimental": "yarn prerelease && lerna publish --dist-tag experimental",
|
||||
"serve": "cd ./site && next",
|
||||
"start": "npm-run-all --parallel --print-label watch serve",
|
||||
"test": "mocha --require ./config/babel/register.cjs ./packages/*/test/index.js",
|
||||
@@ -91,6 +93,6 @@
|
||||
"slate-hyperscript": "*",
|
||||
"slate-react": "*",
|
||||
"source-map-loader": "^0.2.4",
|
||||
"typescript": "^3.7.2"
|
||||
"typescript": "3.9.7"
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "slate-history",
|
||||
"description": "An operation-based history implementation for Slate editors.",
|
||||
"version": "0.60.4",
|
||||
"version": "0.60.7",
|
||||
"license": "MIT",
|
||||
"repository": "git://github.com/ianstormtaylor/slate.git",
|
||||
"main": "dist/index.js",
|
||||
@@ -18,8 +18,8 @@
|
||||
"is-plain-object": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"slate": "^0.60.4",
|
||||
"slate-hyperscript": "^0.60.4"
|
||||
"slate": "^0.60.7",
|
||||
"slate-hyperscript": "^0.60.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"slate": ">=0.55.0"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "slate-hyperscript",
|
||||
"description": "A hyperscript helper for creating Slate documents.",
|
||||
"version": "0.60.4",
|
||||
"version": "0.60.7",
|
||||
"license": "MIT",
|
||||
"repository": "git://github.com/ianstormtaylor/slate.git",
|
||||
"main": "dist/index.js",
|
||||
@@ -17,7 +17,7 @@
|
||||
"is-plain-object": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"slate": "^0.60.4"
|
||||
"slate": "^0.60.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"slate": ">=0.55.0"
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "slate-react",
|
||||
"description": "Tools for building completely customizable richtext editors with React.",
|
||||
"version": "0.60.4",
|
||||
"version": "0.60.7",
|
||||
"license": "MIT",
|
||||
"repository": "git://github.com/ianstormtaylor/slate.git",
|
||||
"main": "dist/index.js",
|
||||
@@ -23,9 +23,9 @@
|
||||
"scroll-into-view-if-needed": "^2.2.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"slate": "^0.60.4",
|
||||
"slate-history": "^0.60.4",
|
||||
"slate-hyperscript": "^0.60.4"
|
||||
"slate": "^0.60.7",
|
||||
"slate-history": "^0.60.7",
|
||||
"slate-hyperscript": "^0.60.7"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8.0",
|
||||
|
@@ -1,12 +1,12 @@
|
||||
import { CustomTypes } from 'slate'
|
||||
import { BaseRange, BaseText } from 'slate'
|
||||
|
||||
declare module 'slate' {
|
||||
interface CustomTypes {
|
||||
Text: {
|
||||
placeholder: string
|
||||
}
|
||||
} & BaseText
|
||||
Range: {
|
||||
placeholder?: string
|
||||
}
|
||||
} & BaseRange
|
||||
}
|
||||
}
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "slate",
|
||||
"description": "A completely customizable framework for building rich text editors.",
|
||||
"version": "0.60.4",
|
||||
"version": "0.60.7",
|
||||
"license": "MIT",
|
||||
"repository": "git://github.com/ianstormtaylor/slate.git",
|
||||
"main": "dist/index.js",
|
||||
|
@@ -8,4 +8,4 @@ export interface CustomTypes {
|
||||
|
||||
export type ExtendedType<K extends string, B> = unknown extends CustomTypes[K]
|
||||
? B
|
||||
: B & CustomTypes[K]
|
||||
: CustomTypes[K]
|
||||
|
@@ -9,7 +9,7 @@ import { ExtendedType } from './custom-types'
|
||||
*/
|
||||
|
||||
export type BaseNode = Editor | Element | Text
|
||||
export type Node = ExtendedType<'Node', BaseNode>
|
||||
export type Node = Editor | Element | Text
|
||||
|
||||
export interface NodeInterface {
|
||||
ancestor: (root: Node, path: Path) => Ancestor
|
||||
@@ -317,7 +317,9 @@ export const Node: NodeInterface = {
|
||||
}
|
||||
}
|
||||
|
||||
if (Editor.isEditor(r)) delete r.selection
|
||||
if (Editor.isEditor(r)) {
|
||||
r.selection = null
|
||||
}
|
||||
})
|
||||
|
||||
return newRoot.children
|
||||
|
@@ -3,6 +3,8 @@ import { isBoldText } from './type-guards'
|
||||
|
||||
export const input: Text = {
|
||||
placeholder: 'heading',
|
||||
bold: false,
|
||||
italic: false,
|
||||
text: 'mytext',
|
||||
}
|
||||
|
||||
|
@@ -1,30 +1,72 @@
|
||||
import { Descendant, Element, Text, CustomTypes } from 'slate'
|
||||
// import { Descendant, Element, Text, CustomTypes, BaseText } from 'slate'
|
||||
|
||||
export interface HeadingElement {
|
||||
// export type HeadingElement = {
|
||||
// type: 'heading'
|
||||
// level: number
|
||||
// children: Descendant[]
|
||||
// }
|
||||
|
||||
// export type ListItemElement = {
|
||||
// type: 'list-item'
|
||||
// depth: number
|
||||
// children: Descendant[]
|
||||
// }
|
||||
|
||||
// export type CustomText = {
|
||||
// placeholder: string
|
||||
// bold: boolean
|
||||
// italic: boolean
|
||||
// text: string
|
||||
// }
|
||||
|
||||
// export type BoldCustomText = {
|
||||
// bold: boolean
|
||||
// text: string
|
||||
// }
|
||||
|
||||
// declare module 'slate' {
|
||||
// interface CustomTypes {
|
||||
// Element: HeadingElement | ListItemElement
|
||||
// Text: CustomText
|
||||
// }
|
||||
// }
|
||||
|
||||
import {
|
||||
BaseText,
|
||||
BaseEditor,
|
||||
BaseSelection,
|
||||
BasePoint,
|
||||
BaseRange,
|
||||
BaseElement,
|
||||
} from 'slate'
|
||||
// import { Prettify } from './prettify'
|
||||
|
||||
export type HeadingElement = {
|
||||
type: 'heading'
|
||||
level: number
|
||||
children: Descendant[]
|
||||
}
|
||||
} & BaseElement
|
||||
|
||||
export interface ListItemElement {
|
||||
export type ListItemElement = {
|
||||
type: 'list-item'
|
||||
depth: number
|
||||
children: Descendant[]
|
||||
}
|
||||
} & BaseElement
|
||||
|
||||
export interface CustomText {
|
||||
export type CustomText = {
|
||||
placeholder: string
|
||||
text: string
|
||||
}
|
||||
|
||||
export interface BoldCustomText {
|
||||
bold: boolean
|
||||
text: string
|
||||
}
|
||||
italic: boolean
|
||||
} & BaseText
|
||||
|
||||
export type CustomElement = HeadingElement | ListItemElement
|
||||
|
||||
declare module 'slate' {
|
||||
interface CustomTypes {
|
||||
Element: HeadingElement | ListItemElement
|
||||
Text: CustomText | BoldCustomText
|
||||
Editor: BaseEditor
|
||||
Element: CustomElement
|
||||
Text: CustomText
|
||||
Node: CustomElement | CustomText
|
||||
Point: BasePoint
|
||||
Range: BaseRange
|
||||
Selection: BaseSelection
|
||||
}
|
||||
}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
import { Element, Text } from 'slate'
|
||||
import { BoldCustomText, CustomText, HeadingElement } from './custom-types'
|
||||
import { CustomText, HeadingElement } from './custom-types'
|
||||
|
||||
export const isBoldText = (text: Text): text is BoldCustomText =>
|
||||
!!(text as BoldCustomText).bold
|
||||
export const isBoldText = (text: Text): text is CustomText =>
|
||||
!!(text as CustomText).bold
|
||||
|
||||
export const isCustomText = (text: Text): text is CustomText =>
|
||||
!!(text as CustomText).placeholder
|
||||
|
3568
packages/slate/tsconfig.tsbuildinfo
Normal file
3568
packages/slate/tsconfig.tsbuildinfo
Normal file
File diff suppressed because it is too large
Load Diff
@@ -20,7 +20,7 @@ import {
|
||||
import { css } from 'emotion'
|
||||
import { withHistory } from 'slate-history'
|
||||
|
||||
const initialValue: Descendant[] = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
|
@@ -17,7 +17,7 @@ import { withHistory } from 'slate-history'
|
||||
import { css } from 'emotion'
|
||||
|
||||
const CodeHighlightingExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const [language, setLanguage] = useState('html')
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
@@ -149,8 +149,9 @@ const Leaf = ({ attributes, children, leaf }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text: '<h1>Hi!</h1>',
|
||||
|
91
site/examples/custom-types.d.ts
vendored
91
site/examples/custom-types.d.ts
vendored
@@ -1,18 +1,87 @@
|
||||
import { Text, createEditor, Node, Element, Editor, Descendant } from 'slate'
|
||||
|
||||
export type BlockQuoteElement = { type: 'block-quote'; children: Descendant[] }
|
||||
|
||||
export type BulletedListElement = {
|
||||
type: 'bulleted-list'
|
||||
children: Descendant[]
|
||||
}
|
||||
|
||||
export type CheckListItemElement = {
|
||||
type: 'check-list-item'
|
||||
checked: boolean
|
||||
children: Descendant[]
|
||||
}
|
||||
|
||||
export type EditableVoidElement = {
|
||||
type: 'editable-void'
|
||||
children: EmptyText[]
|
||||
}
|
||||
|
||||
export type HeadingElement = { type: 'heading'; children: Descendant[] }
|
||||
|
||||
export type HeadingTwoElement = { type: 'heading-two'; children: Descendant[] }
|
||||
|
||||
export type ImageElement = {
|
||||
type: 'image'
|
||||
url: string
|
||||
children: EmptyText[]
|
||||
}
|
||||
|
||||
export type LinkElement = { type: 'link'; url: string; children: Descendant[] }
|
||||
|
||||
export type ListItemElement = { type: 'list-item'; children: Descendant[] }
|
||||
|
||||
export type MentionElement = {
|
||||
type: 'mention'
|
||||
character: string
|
||||
children: CustomText[]
|
||||
}
|
||||
|
||||
export type ParagraphElement = { type: 'paragraph'; children: Descendant[] }
|
||||
|
||||
export type TableElement = { type: 'table'; children: TableRow[] }
|
||||
|
||||
export type TableCellElement = { type: 'table-cell'; children: CustomText[] }
|
||||
|
||||
export type TableRowElement = { type: 'table-row'; children: TableCell[] }
|
||||
|
||||
export type TitleElement = { type: 'title'; children: Descendant[] }
|
||||
|
||||
export type VideoElement = { type: 'video'; url: string; children: EmptyText[] }
|
||||
|
||||
type CustomElement =
|
||||
| BlockQuoteElement
|
||||
| BulletedListElement
|
||||
| CheckListItemElement
|
||||
| EditableVoidElement
|
||||
| HeadingElement
|
||||
| HeadingTwoElement
|
||||
| ImageElement
|
||||
| LinkElement
|
||||
| ListItemElement
|
||||
| MentionElement
|
||||
| ParagraphElement
|
||||
| TableElement
|
||||
| TableRowElement
|
||||
| TableCellElement
|
||||
| TitleElement
|
||||
| VideoElement
|
||||
|
||||
export type CustomText = {
|
||||
bold?: boolean
|
||||
italic?: boolean
|
||||
code?: boolean
|
||||
text: string
|
||||
}
|
||||
|
||||
export type EmptyText = {
|
||||
text: string
|
||||
}
|
||||
|
||||
declare module 'slate' {
|
||||
interface CustomTypes {
|
||||
Element: CustomElement
|
||||
|
||||
Node: CustomNode
|
||||
Text: CustomText | EmptyText
|
||||
}
|
||||
}
|
||||
|
||||
interface CustomElement {
|
||||
type?: string
|
||||
checked?: boolean
|
||||
url?: string
|
||||
children: Descendant[]
|
||||
}
|
||||
|
||||
type CustomNode = Editor | CustomElement | Text
|
||||
|
@@ -1,14 +1,21 @@
|
||||
import React, { useState, useMemo } from 'react'
|
||||
import { Transforms, createEditor, Node } from 'slate'
|
||||
import {
|
||||
Transforms,
|
||||
createEditor,
|
||||
Node,
|
||||
Element as SlateElement,
|
||||
Descendant,
|
||||
} from 'slate'
|
||||
import { Slate, Editable, useSlateStatic, withReact } from 'slate-react'
|
||||
import { withHistory } from 'slate-history'
|
||||
import { css } from 'emotion'
|
||||
|
||||
import RichTextEditor from './richtext'
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
import { EditableVoidElement } from './custom-types'
|
||||
|
||||
const EditableVoidsExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(
|
||||
() => withEditableVoids(withHistory(withReact(createEditor()))),
|
||||
[]
|
||||
@@ -40,7 +47,10 @@ const withEditableVoids = editor => {
|
||||
|
||||
const insertEditableVoid = editor => {
|
||||
const text = { text: '' }
|
||||
const voidNode = { type: 'editable-void', children: [text] }
|
||||
const voidNode: EditableVoidElement = {
|
||||
type: 'editable-void',
|
||||
children: [text],
|
||||
}
|
||||
Transforms.insertNodes(editor, voidNode)
|
||||
}
|
||||
|
||||
@@ -49,7 +59,7 @@ const Element = props => {
|
||||
|
||||
switch (element.type) {
|
||||
case 'editable-void':
|
||||
return <EditableVoidElement {...props} />
|
||||
return <EditableVoid {...props} />
|
||||
default:
|
||||
return <p {...attributes}>{children}</p>
|
||||
}
|
||||
@@ -59,7 +69,7 @@ const unsetWidthStyle = css`
|
||||
width: unset;
|
||||
`
|
||||
|
||||
const EditableVoidElement = ({ attributes, children, element }) => {
|
||||
const EditableVoid = ({ attributes, children, element }) => {
|
||||
const [inputValue, setInputValue] = useState('')
|
||||
|
||||
return (
|
||||
@@ -127,7 +137,7 @@ const InsertEditableVoidButton = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
|
@@ -1,5 +1,11 @@
|
||||
import React, { useState, useMemo } from 'react'
|
||||
import { Transforms, createEditor, Node, Element as SlateElement } from 'slate'
|
||||
import {
|
||||
Transforms,
|
||||
createEditor,
|
||||
Node,
|
||||
Element as SlateElement,
|
||||
Descendant,
|
||||
} from 'slate'
|
||||
import {
|
||||
Slate,
|
||||
Editable,
|
||||
@@ -11,7 +17,7 @@ import {
|
||||
} from 'slate-react'
|
||||
|
||||
const EmbedsExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withEmbeds(withReact(createEditor())), [])
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
@@ -98,8 +104,9 @@ const UrlInput = ({ url, onChange }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
@@ -113,6 +120,7 @@ const initialValue = [
|
||||
children: [{ text: '' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
|
@@ -1,7 +1,14 @@
|
||||
import React, { useState, useCallback, useMemo } from 'react'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
import { Transforms, createEditor, Node, Element as SlateElement } from 'slate'
|
||||
import {
|
||||
Transforms,
|
||||
createEditor,
|
||||
Node,
|
||||
Element as SlateElement,
|
||||
Descendant,
|
||||
} from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
import { ParagraphElement, TitleElement } from './custom-types'
|
||||
|
||||
const withLayout = editor => {
|
||||
const { normalizeNode } = editor
|
||||
@@ -9,12 +16,18 @@ const withLayout = editor => {
|
||||
editor.normalizeNode = ([node, path]) => {
|
||||
if (path.length === 0) {
|
||||
if (editor.children.length < 1) {
|
||||
const title = { type: 'title', children: [{ text: 'Untitled' }] }
|
||||
const title: TitleElement = {
|
||||
type: 'title',
|
||||
children: [{ text: 'Untitled' }],
|
||||
}
|
||||
Transforms.insertNodes(editor, title, { at: path.concat(0) })
|
||||
}
|
||||
|
||||
if (editor.children.length < 2) {
|
||||
const paragraph = { type: 'paragraph', children: [{ text: '' }] }
|
||||
const paragraph: ParagraphElement = {
|
||||
type: 'paragraph',
|
||||
children: [{ text: '' }],
|
||||
}
|
||||
Transforms.insertNodes(editor, paragraph, { at: path.concat(1) })
|
||||
}
|
||||
|
||||
@@ -35,7 +48,7 @@ const withLayout = editor => {
|
||||
}
|
||||
|
||||
const ForcedLayoutExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const editor = useMemo(
|
||||
() => withLayout(withHistory(withReact(createEditor()))),
|
||||
@@ -62,7 +75,7 @@ const Element = ({ attributes, children, element }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'title',
|
||||
children: [{ text: 'Enforce Your Layout!' }],
|
||||
|
@@ -1,6 +1,14 @@
|
||||
import React, { useState, useMemo, useRef, useEffect } from 'react'
|
||||
import { Slate, Editable, ReactEditor, withReact, useSlate } from 'slate-react'
|
||||
import { Editor, Transforms, Text, createEditor, Node } from 'slate'
|
||||
import {
|
||||
Editor,
|
||||
Transforms,
|
||||
Text,
|
||||
createEditor,
|
||||
Node,
|
||||
Element,
|
||||
Descendant,
|
||||
} from 'slate'
|
||||
import { css } from 'emotion'
|
||||
import { withHistory } from 'slate-history'
|
||||
|
||||
@@ -8,7 +16,7 @@ import { Button, Icon, Menu, Portal } from '../components'
|
||||
import { Range } from 'slate'
|
||||
|
||||
const HoveringMenuExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
|
||||
return (
|
||||
@@ -140,8 +148,9 @@ const FormatButton = ({ format, icon }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: Element[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
@@ -154,6 +163,7 @@ const initialValue = [
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Try it out yourself! Just ' },
|
||||
{ text: 'select any piece of text and the menu will appear', bold: true },
|
||||
|
@@ -1,11 +1,11 @@
|
||||
import React, { useState, useMemo, useCallback } from 'react'
|
||||
import faker from 'faker'
|
||||
import { createEditor } from 'slate'
|
||||
import { Element as SlateElement, Node, createEditor, Descendant } from 'slate'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
|
||||
const HEADINGS = 100
|
||||
const PARAGRAPHS = 7
|
||||
const initialValue = []
|
||||
const initialValue: SlateElement[] = []
|
||||
|
||||
for (let h = 0; h < HEADINGS; h++) {
|
||||
initialValue.push({
|
||||
@@ -15,13 +15,14 @@ for (let h = 0; h < HEADINGS; h++) {
|
||||
|
||||
for (let p = 0; p < PARAGRAPHS; p++) {
|
||||
initialValue.push({
|
||||
type: 'paragraph',
|
||||
children: [{ text: faker.lorem.paragraph() }],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const HugeDocumentExample = () => {
|
||||
const [value, setValue] = useState(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
return (
|
||||
|
@@ -2,7 +2,13 @@ import React, { useCallback, useMemo, useState } from 'react'
|
||||
import { createPortal } from 'react-dom'
|
||||
import isHotkey from 'is-hotkey'
|
||||
import { Editable, withReact, useSlate, Slate, ReactEditor } from 'slate-react'
|
||||
import { Editor, createEditor, Node } from 'slate'
|
||||
import {
|
||||
Editor,
|
||||
Element as SlateElement,
|
||||
createEditor,
|
||||
Node,
|
||||
Descendant,
|
||||
} from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
@@ -15,7 +21,7 @@ const HOTKEYS = {
|
||||
}
|
||||
|
||||
const IFrameExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(
|
||||
({ attributes, children }) => <p {...attributes}>{children}</p>,
|
||||
[]
|
||||
@@ -117,7 +123,7 @@ const IFrame = ({ children, ...props }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
|
@@ -1,7 +1,13 @@
|
||||
import React, { useState, useMemo } from 'react'
|
||||
import imageExtensions from 'image-extensions'
|
||||
import isUrl from 'is-url'
|
||||
import { Node, Transforms, createEditor } from 'slate'
|
||||
import {
|
||||
Node,
|
||||
Transforms,
|
||||
createEditor,
|
||||
Element as SlateElement,
|
||||
Descendant,
|
||||
} from 'slate'
|
||||
import {
|
||||
Slate,
|
||||
Editable,
|
||||
@@ -14,9 +20,10 @@ import { withHistory } from 'slate-history'
|
||||
import { css } from 'emotion'
|
||||
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
import { ImageElement } from './custom-types'
|
||||
|
||||
const ImagesExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(
|
||||
() => withImages(withHistory(withReact(createEditor()))),
|
||||
[]
|
||||
@@ -72,7 +79,7 @@ const withImages = editor => {
|
||||
|
||||
const insertImage = (editor, url) => {
|
||||
const text = { text: '' }
|
||||
const image = { type: 'image', url, children: [text] }
|
||||
const image: ImageElement = { type: 'image', url, children: [text] }
|
||||
Transforms.insertNodes(editor, image)
|
||||
}
|
||||
|
||||
@@ -81,13 +88,13 @@ const Element = props => {
|
||||
|
||||
switch (element.type) {
|
||||
case 'image':
|
||||
return <ImageElement {...props} />
|
||||
return <Image {...props} />
|
||||
default:
|
||||
return <p {...attributes}>{children}</p>
|
||||
}
|
||||
}
|
||||
|
||||
const ImageElement = ({ attributes, children, element }) => {
|
||||
const Image = ({ attributes, children, element }) => {
|
||||
const selected = useSelected()
|
||||
const focused = useFocused()
|
||||
return (
|
||||
@@ -131,7 +138,7 @@ const isImageUrl = url => {
|
||||
return imageExtensions.includes(ext)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
|
@@ -8,13 +8,15 @@ import {
|
||||
Range,
|
||||
createEditor,
|
||||
Element as SlateElement,
|
||||
Descendant,
|
||||
} from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
import { LinkElement } from './custom-types'
|
||||
|
||||
import { Button, Icon, Toolbar } from '../components'
|
||||
|
||||
const LinkExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(
|
||||
() => withLinks(withHistory(withReact(createEditor()))),
|
||||
[]
|
||||
@@ -89,7 +91,7 @@ const wrapLink = (editor, url) => {
|
||||
|
||||
const { selection } = editor
|
||||
const isCollapsed = selection && Range.isCollapsed(selection)
|
||||
const link = {
|
||||
const link: LinkElement = {
|
||||
type: 'link',
|
||||
url,
|
||||
children: isCollapsed ? [{ text: url }] : [],
|
||||
@@ -133,8 +135,9 @@ const LinkButton = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text: 'In addition to block nodes, you can create inline nodes, like ',
|
||||
@@ -150,6 +153,7 @@ const initialValue = [
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import Prism from 'prismjs'
|
||||
import React, { useState, useCallback, useMemo } from 'react'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
import { Node, Text, createEditor } from 'slate'
|
||||
import { Node, Text, createEditor, Element, Descendant } from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
import { css } from 'emotion'
|
||||
|
||||
@@ -9,7 +9,7 @@ import { css } from 'emotion'
|
||||
;Prism.languages.markdown=Prism.languages.extend("markup",{}),Prism.languages.insertBefore("markdown","prolog",{blockquote:{pattern:/^>(?:[\t ]*>)*/m,alias:"punctuation"},code:[{pattern:/^(?: {4}|\t).+/m,alias:"keyword"},{pattern:/``.+?``|`[^`\n]+`/,alias:"keyword"}],title:[{pattern:/\w+.*(?:\r?\n|\r)(?:==+|--+)/,alias:"important",inside:{punctuation:/==+$|--+$/}},{pattern:/(^\s*)#+.+/m,lookbehind:!0,alias:"important",inside:{punctuation:/^#+|#+$/}}],hr:{pattern:/(^\s*)([*-])([\t ]*\2){2,}(?=\s*$)/m,lookbehind:!0,alias:"punctuation"},list:{pattern:/(^\s*)(?:[*+-]|\d+\.)(?=[\t ].)/m,lookbehind:!0,alias:"punctuation"},"url-reference":{pattern:/!?\[[^\]]+\]:[\t ]+(?:\S+|<(?:\\.|[^>\\])+>)(?:[\t ]+(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\)))?/,inside:{variable:{pattern:/^(!?\[)[^\]]+/,lookbehind:!0},string:/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*'|\((?:\\.|[^)\\])*\))$/,punctuation:/^[\[\]!:]|[<>]/},alias:"url"},bold:{pattern:/(^|[^\\])(\*\*|__)(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^\*\*|^__|\*\*$|__$/}},italic:{pattern:/(^|[^\\])([*_])(?:(?:\r?\n|\r)(?!\r?\n|\r)|.)+?\2/,lookbehind:!0,inside:{punctuation:/^[*_]|[*_]$/}},url:{pattern:/!?\[[^\]]+\](?:\([^\s)]+(?:[\t ]+"(?:\\.|[^"\\])*")?\)| ?\[[^\]\n]*\])/,inside:{variable:{pattern:/(!?\[)[^\]]+(?=\]$)/,lookbehind:!0},string:{pattern:/"(?:\\.|[^"\\])*"(?=\)$)/}}}}),Prism.languages.markdown.bold.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.italic.inside.url=Prism.util.clone(Prism.languages.markdown.url),Prism.languages.markdown.bold.inside.italic=Prism.util.clone(Prism.languages.markdown.italic),Prism.languages.markdown.italic.inside.bold=Prism.util.clone(Prism.languages.markdown.bold); // prettier-ignore
|
||||
|
||||
const MarkdownPreviewExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
const decorate = useCallback(([node, path]) => {
|
||||
@@ -109,8 +109,9 @@ const Leaf = ({ attributes, children, leaf }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: Element[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
@@ -119,9 +120,11 @@ const initialValue = [
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: '## Try it out!' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'Try it out for yourself!' }],
|
||||
},
|
||||
]
|
||||
|
@@ -8,8 +8,10 @@ import {
|
||||
Point,
|
||||
createEditor,
|
||||
Element as SlateElement,
|
||||
Descendant,
|
||||
} from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
import { BulletedListElement } from './custom-types'
|
||||
|
||||
const SHORTCUTS = {
|
||||
'*': 'list-item',
|
||||
@@ -25,7 +27,7 @@ const SHORTCUTS = {
|
||||
}
|
||||
|
||||
const MarkdownShortcutsExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const editor = useMemo(
|
||||
() => withShortcuts(withReact(withHistory(createEditor()))),
|
||||
@@ -71,7 +73,10 @@ const withShortcuts = editor => {
|
||||
})
|
||||
|
||||
if (type === 'list-item') {
|
||||
const list = { type: 'bulleted-list', children: [] }
|
||||
const list: BulletedListElement = {
|
||||
type: 'bulleted-list',
|
||||
children: [],
|
||||
}
|
||||
Transforms.wrapNodes(editor, list, {
|
||||
match: n =>
|
||||
!Editor.isEditor(n) &&
|
||||
@@ -156,7 +161,7 @@ const Element = ({ attributes, children, element }) => {
|
||||
}
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
|
@@ -1,5 +1,13 @@
|
||||
import React, { useMemo, useCallback, useRef, useEffect, useState } from 'react'
|
||||
import { Node, Editor, Transforms, Range, createEditor } from 'slate'
|
||||
import {
|
||||
Node,
|
||||
Editor,
|
||||
Transforms,
|
||||
Range,
|
||||
createEditor,
|
||||
Element as SlateElement,
|
||||
Descendant,
|
||||
} from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
import {
|
||||
Slate,
|
||||
@@ -11,10 +19,11 @@ import {
|
||||
} from 'slate-react'
|
||||
|
||||
import { Portal } from '../components'
|
||||
import { MentionElement } from './custom-types'
|
||||
|
||||
const MentionExample = () => {
|
||||
const ref = useRef<HTMLDivElement | null>()
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const [target, setTarget] = useState<Range | undefined>()
|
||||
const [index, setIndex] = useState(0)
|
||||
const [search, setSearch] = useState('')
|
||||
@@ -154,7 +163,11 @@ const withMentions = editor => {
|
||||
}
|
||||
|
||||
const insertMention = (editor, character) => {
|
||||
const mention = { type: 'mention', character, children: [{ text: '' }] }
|
||||
const mention: MentionElement = {
|
||||
type: 'mention',
|
||||
character,
|
||||
children: [{ text: '' }],
|
||||
}
|
||||
Transforms.insertNodes(editor, mention)
|
||||
Transforms.move(editor)
|
||||
}
|
||||
@@ -163,13 +176,13 @@ const Element = props => {
|
||||
const { attributes, children, element } = props
|
||||
switch (element.type) {
|
||||
case 'mention':
|
||||
return <MentionElement {...props} />
|
||||
return <Mention {...props} />
|
||||
default:
|
||||
return <p {...attributes}>{children}</p>
|
||||
}
|
||||
}
|
||||
|
||||
const MentionElement = ({ attributes, children, element }) => {
|
||||
const Mention = ({ attributes, children, element }) => {
|
||||
const selected = useSelected()
|
||||
const focused = useFocused()
|
||||
return (
|
||||
@@ -193,8 +206,9 @@ const MentionElement = ({ attributes, children, element }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
@@ -203,6 +217,7 @@ const initialValue = [
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Try mentioning characters, like ' },
|
||||
{
|
||||
|
@@ -1,6 +1,12 @@
|
||||
import React, { useState, useCallback, useMemo } from 'react'
|
||||
import { jsx } from 'slate-hyperscript'
|
||||
import { Node, Transforms, createEditor } from 'slate'
|
||||
import {
|
||||
Node,
|
||||
Transforms,
|
||||
createEditor,
|
||||
Element as SlateElement,
|
||||
Descendant,
|
||||
} from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
import { css } from 'emotion'
|
||||
import {
|
||||
@@ -80,7 +86,7 @@ export const deserialize = el => {
|
||||
}
|
||||
|
||||
const PasteHtmlExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(
|
||||
@@ -211,8 +217,9 @@ const Leaf = ({ attributes, children, leaf }) => {
|
||||
return <span {...attributes}>{children}</span>
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
@@ -228,9 +235,11 @@ const initialValue = [
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [{ text: 'This is an example of doing exactly that!' }],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
|
@@ -1,10 +1,10 @@
|
||||
import React, { useState, useMemo } from 'react'
|
||||
import { Node, createEditor } from 'slate'
|
||||
import { createEditor, Element, Descendant } from 'slate'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
import { withHistory } from 'slate-history'
|
||||
|
||||
const PlainTextExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
@@ -13,8 +13,9 @@ const PlainTextExample = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: Element[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'This is editable plain text, just like a <textarea>!' },
|
||||
],
|
||||
|
@@ -1,9 +1,9 @@
|
||||
import React, { useState, useMemo } from 'react'
|
||||
import { createEditor, Node } from 'slate'
|
||||
import { createEditor, Descendant, Element, Node } from 'slate'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
|
||||
const ReadOnlyExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const editor = useMemo(() => withReact(createEditor()), [])
|
||||
return (
|
||||
<Slate editor={editor} value={value} onChange={value => setValue(value)}>
|
||||
@@ -12,10 +12,13 @@ const ReadOnlyExample = () => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: Element[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'This is editable plain text, just like a <textarea>!' },
|
||||
{
|
||||
text: 'This is editable plain text, just like a <textarea>!',
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
@@ -5,6 +5,7 @@ import {
|
||||
Editor,
|
||||
Transforms,
|
||||
createEditor,
|
||||
Descendant,
|
||||
Node,
|
||||
Element as SlateElement,
|
||||
} from 'slate'
|
||||
@@ -22,7 +23,7 @@ const HOTKEYS = {
|
||||
const LIST_TYPES = ['numbered-list', 'bulleted-list']
|
||||
|
||||
const RichTextExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
@@ -175,7 +176,7 @@ const MarkButton = ({ format, icon }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: SlateElement[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
|
@@ -1,13 +1,13 @@
|
||||
import React, { useState, useCallback, useMemo } from 'react'
|
||||
import { Slate, Editable, withReact } from 'slate-react'
|
||||
import { Text, Node, createEditor } from 'slate'
|
||||
import { Text, Node, Descendant, createEditor } from 'slate'
|
||||
import { css } from 'emotion'
|
||||
import { withHistory } from 'slate-history'
|
||||
|
||||
import { Icon, Toolbar } from '../components'
|
||||
|
||||
const SearchHighlightingExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const [search, setSearch] = useState<string | undefined>()
|
||||
const editor = useMemo(() => withHistory(withReact(createEditor())), [])
|
||||
const decorate = useCallback(
|
||||
@@ -85,8 +85,9 @@ const Leaf = ({ attributes, children, leaf }) => {
|
||||
)
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: Descendant[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
@@ -97,6 +98,7 @@ const initialValue = [
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{ text: 'Try it out for yourself by typing in the search box above!' },
|
||||
],
|
||||
|
@@ -4,14 +4,14 @@ import {
|
||||
Editor,
|
||||
Range,
|
||||
Point,
|
||||
Node,
|
||||
Descendant,
|
||||
createEditor,
|
||||
Element as SlateElement,
|
||||
} from 'slate'
|
||||
import { withHistory } from 'slate-history'
|
||||
|
||||
const TablesExample = () => {
|
||||
const [value, setValue] = useState<Node[]>(initialValue)
|
||||
const [value, setValue] = useState<Descendant[]>(initialValue)
|
||||
const renderElement = useCallback(props => <Element {...props} />, [])
|
||||
const renderLeaf = useCallback(props => <Leaf {...props} />, [])
|
||||
const editor = useMemo(
|
||||
@@ -123,8 +123,9 @@ const Leaf = ({ attributes, children, leaf }) => {
|
||||
return <span {...attributes}>{children}</span>
|
||||
}
|
||||
|
||||
const initialValue = [
|
||||
const initialValue: Descendant[] = [
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
@@ -201,6 +202,7 @@ const initialValue = [
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'paragraph',
|
||||
children: [
|
||||
{
|
||||
text:
|
||||
|
@@ -10109,7 +10109,7 @@ typedarray@^0.0.6:
|
||||
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
|
||||
integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
|
||||
|
||||
typescript@^3.7.2:
|
||||
typescript@3.9.7:
|
||||
version "3.9.7"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa"
|
||||
integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==
|
||||
|
Reference in New Issue
Block a user