context.ts 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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, { useCallback } from 'react'
  21. import { Editor, Transforms, Element, Node } from 'slate'
  22. import { useSlate } from 'slate-react'
  23. import {
  24. ElementType,
  25. ElementTypes,
  26. TextStyles,
  27. TextProperties
  28. } from './Element'
  29. import { BlockProperties, BlockAlignments } from './Element/constants'
  30. const ListTypes: ElementType[] = [
  31. ElementTypes.NumberedList,
  32. ElementTypes.BulletedList
  33. ]
  34. export const useEditorContext = () => {
  35. const editor = useSlate()
  36. const isElementActive = useCallback(
  37. (elementType: ElementType) => {
  38. const [match] = Editor.nodes(editor, {
  39. match: (n) => n.type === elementType
  40. })
  41. return !!match
  42. },
  43. [editor]
  44. )
  45. const isTextStyleActive = useCallback(
  46. (textStyle: TextStyles) => {
  47. const marks = Editor.marks(editor)
  48. if (!marks) {
  49. return false
  50. }
  51. return !!marks[textStyle]
  52. },
  53. [editor]
  54. )
  55. const isTextPropertyActive = useCallback(
  56. (
  57. textProperty: TextProperties,
  58. value?: string | number
  59. ): boolean | string | number => {
  60. const marks = Editor.marks(editor)
  61. if (!marks) {
  62. return false
  63. }
  64. if (value !== undefined) {
  65. return marks[textProperty] === value
  66. }
  67. return marks[textProperty]
  68. },
  69. [editor]
  70. )
  71. const isBlockPropertyActive = useCallback(
  72. (
  73. blockProperty: BlockProperties,
  74. value?: BlockAlignments
  75. ): boolean | BlockAlignments => {
  76. const [match] = Editor.nodes(editor, {
  77. at: editor.selection,
  78. match: (n) => Editor.isBlock(editor, n),
  79. mode: 'lowest'
  80. })
  81. if (!match) {
  82. return false
  83. }
  84. const node = match[0]
  85. const active = value ? node[blockProperty] === value : node[blockProperty]
  86. return active
  87. },
  88. [editor]
  89. )
  90. const isListElement = useCallback(
  91. (elementType: ElementType) => {
  92. return ListTypes.includes(elementType)
  93. },
  94. [editor]
  95. )
  96. const toggleElement = useCallback(
  97. (elementType: ElementType) => {
  98. const isActive = isElementActive(elementType)
  99. const isList = isListElement(elementType)
  100. Transforms.unwrapNodes(editor, {
  101. match: (n) => isListElement(n.type),
  102. split: true
  103. })
  104. Transforms.setNodes(editor, {
  105. type: isActive
  106. ? ElementTypes.Paragraph
  107. : isList
  108. ? ElementTypes.ListItem
  109. : elementType
  110. })
  111. if (!isActive && isList) {
  112. const element = { type: elementType, children: [] }
  113. Transforms.wrapNodes(editor, element)
  114. }
  115. },
  116. [editor]
  117. )
  118. const toggleTextStyle = useCallback(
  119. (textStyle: TextStyles) => {
  120. const isActive = isTextStyleActive(textStyle)
  121. isActive
  122. ? Editor.removeMark(editor, textStyle)
  123. : Editor.addMark(editor, textStyle, true)
  124. },
  125. [editor]
  126. )
  127. const clearTextFormat = useCallback(() => {
  128. Object.values(TextStyles).forEach((style) => {
  129. Editor.removeMark(editor, style)
  130. })
  131. Object.values(TextProperties).forEach((property) => {
  132. Editor.removeMark(editor, property)
  133. })
  134. }, [editor])
  135. const toggleTextProperty = useCallback(
  136. (textProperty: TextProperties, value: string | number) => {
  137. const isActive = isTextPropertyActive(textProperty)
  138. isActive
  139. ? Editor.removeMark(editor, textProperty)
  140. : Editor.addMark(editor, textProperty, value)
  141. if (value) {
  142. Editor.addMark(editor, textProperty, value)
  143. }
  144. },
  145. [editor]
  146. )
  147. const toggleBlockProperty = useCallback(
  148. (blockProperty: BlockProperties, value: BlockAlignments) => {
  149. const [match] = Editor.nodes(editor, {
  150. at: editor.selection,
  151. match: (n) => Editor.isBlock(editor, n),
  152. mode: 'lowest'
  153. })
  154. Transforms.setNodes(editor, { [blockProperty]: value })
  155. },
  156. [editor]
  157. )
  158. const insertElement = useCallback(
  159. (elementType: ElementType, value: string, children?: Node[]) => {
  160. const element: Element = {
  161. type: elementType,
  162. children: children || [{ text: '' }]
  163. }
  164. switch (elementType) {
  165. case ElementTypes.Image:
  166. case ElementTypes.Link:
  167. element.url = value
  168. break
  169. }
  170. Transforms.insertNodes(editor, element)
  171. },
  172. [editor]
  173. )
  174. return {
  175. isElementActive,
  176. isTextStyleActive,
  177. isTextPropertyActive,
  178. isBlockPropertyActive,
  179. isListElement,
  180. toggleElement,
  181. toggleTextStyle,
  182. toggleTextProperty,
  183. toggleBlockProperty,
  184. insertElement,
  185. clearTextFormat
  186. }
  187. }
  188. export const EditorContext = React.createContext<
  189. ReturnType<typeof useEditorContext>
  190. >(null)