Editor.tsx 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. /*
  2. * <<
  3. * Davinci
  4. * ==
  5. * Copyright (C) 2016 - 2017 EDP
  6. * ==
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. * >>
  19. */
  20. import React, { useMemo, useImperativeHandle, useCallback } from 'react'
  21. import classnames from 'classnames'
  22. import { Editable, withReact, Slate, RenderLeafProps } from 'slate-react'
  23. import { createEditor, Node } from 'slate'
  24. import { withHistory } from 'slate-history'
  25. import { withHtml } from 'components/RichText/decorators'
  26. import { parseHtml } from 'components/RichText/util'
  27. import Toolbar from 'components/RichText/Toolbar'
  28. import { Element, withElements } from 'components/RichText/Element'
  29. import { Leaf } from 'components/RichText/Leaf'
  30. interface IEditorProps {
  31. value?: Node[] | string
  32. className?: string
  33. readOnly?: boolean
  34. toolbar?: React.ReactNode
  35. onFormatText?: (text: string) => string
  36. onChange?: (newVal: Node[]) => void
  37. }
  38. interface IEditorProps {
  39. value?: Node[] | string
  40. className?: string
  41. readOnly?: boolean
  42. toolbar?: React.ReactNode
  43. styles?: React.CSSProperties
  44. onFormatText?: (text: string) => string
  45. onChange?: (newVal: Node[]) => void
  46. }
  47. const Editor: React.FC<IEditorProps> = (props, ref) => {
  48. const {
  49. value,
  50. className,
  51. readOnly,
  52. toolbar,
  53. onFormatText,
  54. onChange,
  55. styles
  56. } = props
  57. const initialValue = useMemo(() => {
  58. let parsedValue: Node[]
  59. if (typeof value === 'string') {
  60. try {
  61. parsedValue = JSON.parse(value)
  62. } catch {
  63. parsedValue = parseHtml(value)
  64. }
  65. if (!parsedValue.length) {
  66. parsedValue.push({ text: '' })
  67. }
  68. } else {
  69. parsedValue = value
  70. }
  71. return parsedValue
  72. }, [value])
  73. const editor = useMemo(
  74. () => withElements(withHtml(withReact(withHistory(createEditor())))),
  75. []
  76. )
  77. const renderLeaf = useCallback(
  78. (props: RenderLeafProps) => {
  79. return <Leaf {...props} onFormatText={onFormatText} />
  80. },
  81. [onFormatText]
  82. )
  83. const cls = useMemo(
  84. () =>
  85. classnames({
  86. 'richtext': true,
  87. 'display-slide-layer-editor': true,
  88. [className]: !!className
  89. }),
  90. []
  91. )
  92. useImperativeHandle(ref, () => ({}))
  93. return (
  94. <div className={cls}>
  95. <Slate editor={editor} value={initialValue} onChange={onChange}>
  96. {toolbar === false ? null : toolbar || <Toolbar.Toolbar />}
  97. <Editable
  98. style={styles}
  99. renderElement={Element}
  100. renderLeaf={renderLeaf}
  101. readOnly={readOnly}
  102. spellCheck
  103. autoFocus={!!toolbar}
  104. />
  105. </Slate>
  106. </div>
  107. )
  108. }
  109. export default React.forwardRef(Editor)