1
0
mirror of https://github.com/ianstormtaylor/slate.git synced 2025-04-13 18:01:53 +02:00

Fix inputs from not being able to be used within void nodes in Firefox and Added example of input and other editable void nodes (#3436)

This commit is contained in:
Ryan Mitts 2020-02-25 20:52:11 -08:00 committed by GitHub
parent d8cc9fc46b
commit 9504c4472c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 163 additions and 2 deletions

View File

@ -443,11 +443,16 @@ export const Editable = (props: EditableProps) => {
...style,
}}
onBeforeInput={useCallback(
(event: React.SyntheticEvent) => {
(event: React.FormEvent<HTMLDivElement>) => {
// COMPAT: Firefox doesn't support the `beforeinput` event, so we
// fall back to React's leaky polyfill instead just for it. It
// only works for the `insertText` input type.
if (IS_FIREFOX && !readOnly) {
if (
IS_FIREFOX &&
!readOnly &&
!isEventHandled(event, attributes.onBeforeInput) &&
hasEditableTarget(editor, event.target)
) {
event.preventDefault()
const text = (event as any).data as string
Editor.insertText(editor, text)

View File

@ -0,0 +1,154 @@
import React, { useState, useMemo } from 'react'
import { Transforms, createEditor } from 'slate'
import { Slate, Editable, useEditor, withReact } from 'slate-react'
import { withHistory } from 'slate-history'
import { css } from 'emotion'
import RichTextEditor from './richtext'
import { Button, Icon, Toolbar } from '../components'
const EditableVoidsExample = () => {
const [value, setValue] = useState(initialValue)
const editor = useMemo(
() => withEditableVoids(withHistory(withReact(createEditor()))),
[]
)
return (
<Slate editor={editor} value={value} onChange={setValue}>
<Toolbar>
<InsertEditableVoidButton />
</Toolbar>
<Editable
renderElement={props => <Element {...props} />}
placeholder="Enter some text..."
/>
</Slate>
)
}
const withEditableVoids = editor => {
const { isVoid } = editor
editor.isVoid = element => {
return element.type === 'editable-void' ? true : isVoid(element)
}
return editor
}
const insertEditableVoid = editor => {
const text = { text: '' }
const voidNode = { type: 'editable-void', children: [text] }
Transforms.insertNodes(editor, voidNode)
}
const Element = props => {
const { attributes, children, element } = props
switch (element.type) {
case 'editable-void':
return <EditableVoidElement {...props} />
default:
return <p {...attributes}>{children}</p>
}
}
const unsetWidthStyle = css`
width: unset;
`
const EditableVoidElement = ({ attributes, children, element }) => {
const [inputValue, setInputValue] = useState('')
return (
// Need contentEditable=false or Firefox has issues with certain input types.
<div {...attributes} contentEditable={false}>
<div
className={css`
box-shadow: 0 0 0 3px #ddd;
padding: 8px;
`}
>
<h4>Name:</h4>
<input
className={css`
margin: 8px 0;
`}
type="text"
value={inputValue}
onChange={e => {
setInputValue(e.target.value)
}}
/>
<h4>Left or right handed:</h4>
<input
className={unsetWidthStyle}
type="radio"
name="handedness"
value="left"
/>{' '}
Left
<br />
<input
className={unsetWidthStyle}
type="radio"
name="handedness"
value="right"
/>{' '}
Right
<h4>Tell us about yourself:</h4>
<div
className={css`
padding: 20px;
border: 2px solid #ddd;
`}
>
<RichTextEditor />
</div>
</div>
{children}
</div>
)
}
const InsertEditableVoidButton = () => {
const editor = useEditor()
return (
<Button
onMouseDown={event => {
event.preventDefault()
insertEditableVoid(editor)
}}
>
<Icon>add</Icon>
</Button>
)
}
const initialValue = [
{
type: 'paragraph',
children: [
{
text:
'In addition to nodes that contain editable text, you can insert void nodes, which can also contain editable elements, inputs, or an entire other Slate editor.',
},
],
},
{
type: 'editable-void',
children: [{ text: '' }],
},
{
type: 'paragraph',
children: [
{
text: '',
},
],
},
]
export default EditableVoidsExample

View File

@ -9,6 +9,7 @@ import ErrorBoundary from 'react-error-boundary'
import { Icon } from '../../components'
import CheckLists from '../../examples/check-lists'
import EditableVoids from '../../examples/editable-voids'
import Embeds from '../../examples/embeds'
import ForcedLayout from '../../examples/forced-layout'
import HoveringToolbar from '../../examples/hovering-toolbar'
@ -27,6 +28,7 @@ import Tables from '../../examples/tables'
const EXAMPLES = [
['Checklists', CheckLists, 'check-lists'],
['Editable Voids', EditableVoids, 'editable-voids'],
['Embeds', Embeds, 'embeds'],
['Forced Layout', ForcedLayout, 'forced-layout'],
['Hovering Toolbar', HoveringToolbar, 'hovering-toolbar'],