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:
parent
d8cc9fc46b
commit
9504c4472c
@ -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)
|
||||
|
154
site/examples/editable-voids.js
Normal file
154
site/examples/editable-voids.js
Normal 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
|
@ -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'],
|
||||
|
Loading…
x
Reference in New Issue
Block a user