@mirrormedia/lilith-draft-editor 1.0.0-beta → 1.0.0-beta4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/lib/draft-js/block-renderer/background-image-block.js +123 -0
  2. package/lib/draft-js/block-renderer/background-video-block.js +133 -0
  3. package/lib/draft-js/block-renderer/color-box-block.js +92 -0
  4. package/lib/draft-js/block-renderer/divider-block.js +24 -0
  5. package/lib/draft-js/block-renderer/embedded-code-block.js +63 -0
  6. package/lib/draft-js/block-renderer/image-block.js +47 -0
  7. package/lib/draft-js/block-renderer/info-box-block.js +89 -0
  8. package/lib/draft-js/block-renderer/media-block.js +65 -0
  9. package/lib/draft-js/block-renderer/related-post-block.js +51 -0
  10. package/lib/draft-js/block-renderer/side-index-block.js +103 -0
  11. package/lib/draft-js/block-renderer/slideshow-block.js +71 -0
  12. package/lib/draft-js/block-renderer/table-block.js +408 -0
  13. package/lib/draft-js/buttons/annotation.js +117 -0
  14. package/lib/draft-js/buttons/background-color.js +123 -0
  15. package/lib/draft-js/buttons/background-image.js +222 -0
  16. package/lib/draft-js/buttons/background-video.js +222 -0
  17. package/lib/draft-js/buttons/color-box.js +172 -0
  18. package/lib/draft-js/buttons/divider.js +63 -0
  19. package/lib/draft-js/buttons/embedded-code.js +109 -0
  20. package/lib/draft-js/buttons/enlarge.js +24 -0
  21. package/lib/draft-js/buttons/font-color.js +116 -0
  22. package/lib/draft-js/buttons/image.js +68 -0
  23. package/lib/draft-js/buttons/info-box.js +147 -0
  24. package/lib/draft-js/buttons/link.js +107 -0
  25. package/lib/draft-js/buttons/media.js +121 -0
  26. package/lib/draft-js/buttons/related-post.js +71 -0
  27. package/lib/draft-js/buttons/selector/align-selector.js +71 -0
  28. package/lib/draft-js/buttons/selector/image-selector.js +428 -0
  29. package/lib/draft-js/buttons/selector/pagination.js +82 -0
  30. package/lib/draft-js/buttons/selector/post-selector.js +317 -0
  31. package/lib/draft-js/buttons/selector/search-box.js +46 -0
  32. package/lib/draft-js/buttons/selector/video-selector.js +284 -0
  33. package/lib/draft-js/buttons/side-index.js +200 -0
  34. package/lib/draft-js/buttons/slideshow.js +71 -0
  35. package/lib/draft-js/buttons/table.js +67 -0
  36. package/lib/draft-js/buttons/text-align.js +88 -0
  37. package/lib/draft-js/editor/basic-editor.js +366 -0
  38. package/lib/draft-js/editor/block-renderer-fn.js +117 -0
  39. package/lib/draft-js/editor/entity-decorator.js +16 -0
  40. package/lib/draft-js/editor/modifier.js +68 -0
  41. package/lib/draft-js/entity-decorator/annotation-decorator.js +86 -0
  42. package/lib/draft-js/entity-decorator/link-decorator.js +39 -0
  43. package/lib/website/mirrormedia/custom/block-renderer/background-image-block.js +91 -0
  44. package/lib/website/mirrormedia/custom/block-renderer/background-video-block.js +91 -0
  45. package/lib/website/mirrormedia/custom/block-renderer/color-box-block.js +84 -0
  46. package/lib/website/mirrormedia/custom/block-renderer/info-box-block.js +84 -0
  47. package/lib/website/mirrormedia/custom/block-renderer/side-index-block.js +90 -0
  48. package/lib/website/mirrormedia/custom/block-renderer/table-block.js +408 -0
  49. package/lib/website/mirrormedia/custom/selector/align-selector.js +71 -0
  50. package/lib/website/mirrormedia/custom/selector/image-selector.js +427 -0
  51. package/lib/website/mirrormedia/custom/selector/pagination.js +82 -0
  52. package/lib/website/mirrormedia/custom/selector/post-selector.js +318 -0
  53. package/lib/website/mirrormedia/custom/selector/search-box.js +46 -0
  54. package/lib/website/mirrormedia/custom/selector/video-selector.js +282 -0
  55. package/lib/website/mirrormedia/draft-editor/block-renderer-fn.js +117 -0
  56. package/lib/website/mirrormedia/draft-editor/entity-decorator.js +18 -0
  57. package/lib/website/mirrormedia/draft-editor/index.js +799 -0
  58. package/lib/website/mirrormedia/index.js +1 -4
  59. package/lib/website/readr/custom/block-renderer/background-image-block.js +91 -0
  60. package/lib/website/readr/custom/block-renderer/background-video-block.js +91 -0
  61. package/lib/website/readr/custom/block-renderer/color-box-block.js +84 -0
  62. package/lib/website/readr/custom/block-renderer/info-box-block.js +84 -0
  63. package/lib/website/readr/custom/block-renderer/side-index-block.js +90 -0
  64. package/lib/website/readr/custom/block-renderer/table-block.js +408 -0
  65. package/lib/website/readr/custom/selector/align-selector.js +71 -0
  66. package/lib/website/readr/custom/selector/image-selector.js +427 -0
  67. package/lib/website/readr/custom/selector/pagination.js +82 -0
  68. package/lib/website/readr/custom/selector/post-selector.js +318 -0
  69. package/lib/website/readr/custom/selector/search-box.js +46 -0
  70. package/lib/website/readr/custom/selector/video-selector.js +282 -0
  71. package/lib/website/readr/draft-editor/block-renderer-fn.js +117 -0
  72. package/lib/website/readr/draft-editor/entity-decorator.js +18 -0
  73. package/lib/website/readr/draft-editor/index.js +799 -0
  74. package/lib/website/readr/index.js +1 -4
  75. package/package.json +3 -2
  76. package/lib/draft-js/block-renderer/background-image-block.tsx +0 -113
  77. package/lib/draft-js/block-renderer/background-video-block.tsx +0 -120
  78. package/lib/draft-js/block-renderer/color-box-block.tsx +0 -85
  79. package/lib/draft-js/block-renderer/divider-block.tsx +0 -12
  80. package/lib/draft-js/block-renderer/embedded-code-block.tsx +0 -65
  81. package/lib/draft-js/block-renderer/image-block.tsx +0 -41
  82. package/lib/draft-js/block-renderer/info-box-block.tsx +0 -85
  83. package/lib/draft-js/block-renderer/media-block.tsx +0 -36
  84. package/lib/draft-js/block-renderer/related-post-block.tsx +0 -47
  85. package/lib/draft-js/block-renderer/side-index-block.tsx +0 -113
  86. package/lib/draft-js/block-renderer/slideshow-block.tsx +0 -62
  87. package/lib/draft-js/block-renderer/table-block.tsx +0 -488
  88. package/lib/draft-js/buttons/annotation.tsx +0 -113
  89. package/lib/draft-js/buttons/background-color.tsx +0 -125
  90. package/lib/draft-js/buttons/background-image.tsx +0 -276
  91. package/lib/draft-js/buttons/background-video.tsx +0 -275
  92. package/lib/draft-js/buttons/color-box.tsx +0 -207
  93. package/lib/draft-js/buttons/divider.tsx +0 -56
  94. package/lib/draft-js/buttons/embedded-code.tsx +0 -126
  95. package/lib/draft-js/buttons/enlarge.tsx +0 -11
  96. package/lib/draft-js/buttons/font-color.tsx +0 -113
  97. package/lib/draft-js/buttons/image.tsx +0 -71
  98. package/lib/draft-js/buttons/info-box.tsx +0 -170
  99. package/lib/draft-js/buttons/link.tsx +0 -103
  100. package/lib/draft-js/buttons/media.tsx +0 -120
  101. package/lib/draft-js/buttons/related-post.tsx +0 -81
  102. package/lib/draft-js/buttons/selector/align-selector.tsx +0 -65
  103. package/lib/draft-js/buttons/selector/image-selector.tsx +0 -485
  104. package/lib/draft-js/buttons/selector/pagination.tsx +0 -83
  105. package/lib/draft-js/buttons/selector/post-selector.tsx +0 -367
  106. package/lib/draft-js/buttons/selector/search-box.tsx +0 -39
  107. package/lib/draft-js/buttons/selector/video-selector.tsx +0 -312
  108. package/lib/draft-js/buttons/side-index.tsx +0 -257
  109. package/lib/draft-js/buttons/slideshow.tsx +0 -81
  110. package/lib/draft-js/buttons/table.tsx +0 -63
  111. package/lib/draft-js/buttons/text-align.tsx +0 -88
  112. package/lib/draft-js/editor/basic-editor.tsx +0 -384
  113. package/lib/draft-js/editor/block-redender-fn.tsx +0 -77
  114. package/lib/draft-js/editor/entity-decorator.tsx +0 -7
  115. package/lib/draft-js/editor/modifier.tsx +0 -71
  116. package/lib/draft-js/entity-decorator/annotation-decorator.tsx +0 -81
  117. package/lib/draft-js/entity-decorator/link-decorator.tsx +0 -27
  118. package/lib/website/mirrormedia/custom/block-renderer/background-image-block.tsx +0 -128
  119. package/lib/website/mirrormedia/custom/block-renderer/background-video-block.tsx +0 -135
  120. package/lib/website/mirrormedia/custom/block-renderer/color-box-block.tsx +0 -98
  121. package/lib/website/mirrormedia/custom/block-renderer/divider-block.tsx +0 -12
  122. package/lib/website/mirrormedia/custom/block-renderer/embedded-code-block.tsx +0 -65
  123. package/lib/website/mirrormedia/custom/block-renderer/image-block.tsx +0 -41
  124. package/lib/website/mirrormedia/custom/block-renderer/info-box-block.tsx +0 -98
  125. package/lib/website/mirrormedia/custom/block-renderer/media-block.tsx +0 -36
  126. package/lib/website/mirrormedia/custom/block-renderer/related-post-block.tsx +0 -47
  127. package/lib/website/mirrormedia/custom/block-renderer/side-index-block.tsx +0 -125
  128. package/lib/website/mirrormedia/custom/block-renderer/slideshow-block.tsx +0 -62
  129. package/lib/website/mirrormedia/custom/block-renderer/table-block.tsx +0 -537
  130. package/lib/website/mirrormedia/custom/entity-decorator/annotation-decorator.tsx +0 -81
  131. package/lib/website/mirrormedia/custom/entity-decorator/link-decorator.tsx +0 -27
  132. package/lib/website/mirrormedia/custom/selector/align-selector.tsx +0 -65
  133. package/lib/website/mirrormedia/custom/selector/image-selector.tsx +0 -485
  134. package/lib/website/mirrormedia/custom/selector/pagination.tsx +0 -83
  135. package/lib/website/mirrormedia/custom/selector/post-selector.tsx +0 -367
  136. package/lib/website/mirrormedia/custom/selector/search-box.tsx +0 -39
  137. package/lib/website/mirrormedia/custom/selector/video-selector.tsx +0 -310
  138. package/lib/website/mirrormedia/draft-editor/block-redender-fn.tsx +0 -77
  139. package/lib/website/mirrormedia/draft-editor/entity-decorator.tsx +0 -7
  140. package/lib/website/mirrormedia/draft-editor/index.tsx +0 -909
  141. package/lib/website/mirrormedia/draft-renderer/block-redender-fn.tsx +0 -77
  142. package/lib/website/mirrormedia/draft-renderer/entity-decorator.tsx +0 -7
  143. package/lib/website/mirrormedia/draft-renderer/index-deprecated.tsx +0 -43
  144. package/lib/website/mirrormedia/draft-renderer/index.tsx +0 -150
  145. package/lib/website/readr/custom/block-renderer/background-image-block.tsx +0 -128
  146. package/lib/website/readr/custom/block-renderer/background-video-block.tsx +0 -135
  147. package/lib/website/readr/custom/block-renderer/color-box-block.tsx +0 -98
  148. package/lib/website/readr/custom/block-renderer/divider-block.tsx +0 -12
  149. package/lib/website/readr/custom/block-renderer/embedded-code-block.tsx +0 -65
  150. package/lib/website/readr/custom/block-renderer/image-block.tsx +0 -41
  151. package/lib/website/readr/custom/block-renderer/info-box-block.tsx +0 -98
  152. package/lib/website/readr/custom/block-renderer/media-block.tsx +0 -36
  153. package/lib/website/readr/custom/block-renderer/related-post-block.tsx +0 -47
  154. package/lib/website/readr/custom/block-renderer/side-index-block.tsx +0 -125
  155. package/lib/website/readr/custom/block-renderer/slideshow-block.tsx +0 -62
  156. package/lib/website/readr/custom/block-renderer/table-block.tsx +0 -537
  157. package/lib/website/readr/custom/entity-decorator/annotation-decorator.tsx +0 -81
  158. package/lib/website/readr/custom/entity-decorator/link-decorator.tsx +0 -27
  159. package/lib/website/readr/custom/selector/align-selector.tsx +0 -65
  160. package/lib/website/readr/custom/selector/image-selector.tsx +0 -485
  161. package/lib/website/readr/custom/selector/pagination.tsx +0 -83
  162. package/lib/website/readr/custom/selector/post-selector.tsx +0 -367
  163. package/lib/website/readr/custom/selector/search-box.tsx +0 -39
  164. package/lib/website/readr/custom/selector/video-selector.tsx +0 -310
  165. package/lib/website/readr/draft-editor/block-redender-fn.tsx +0 -77
  166. package/lib/website/readr/draft-editor/entity-decorator.tsx +0 -7
  167. package/lib/website/readr/draft-editor/index.tsx +0 -909
  168. package/lib/website/readr/draft-renderer/block-redender-fn.tsx +0 -77
  169. package/lib/website/readr/draft-renderer/entity-decorator.tsx +0 -7
  170. package/lib/website/readr/draft-renderer/index-deprecated.tsx +0 -43
  171. package/lib/website/readr/draft-renderer/index.tsx +0 -150
@@ -1,113 +0,0 @@
1
- import React, { useState } from 'react'
2
- import { ContentBlock, ContentState } from 'draft-js'
3
- import styled from 'styled-components'
4
- import { SideIndexInputOnChange, SideIndexInput } from '../buttons/side-index'
5
-
6
- const SideIndexBlockWrapper = styled.div`
7
- display: flex;
8
- align-items: center;
9
- `
10
-
11
- const SideIndexBlockButton = styled.div`
12
- cursor: pointer;
13
- margin-left: 20px;
14
- `
15
-
16
- const SideIndex = styled.span`
17
- font-size: 16px;
18
- margin-left: 20px;
19
- `
20
-
21
- type SideIndexBlockProps = {
22
- block: ContentBlock
23
- blockProps: {
24
- onEditStart: () => void
25
- onEditFinish: ({
26
- entityKey,
27
- entityData,
28
- }: {
29
- entityKey?: string
30
- entityData?: Record<string, unknown>
31
- }) => void
32
- }
33
- contentState: ContentState
34
- }
35
-
36
- export function SideIndexBlock(props: SideIndexBlockProps) {
37
- const [toShowInput, setToShowInput] = useState(false)
38
- const { block, blockProps, contentState } = props
39
- const { onEditStart, onEditFinish } = blockProps
40
- const entityKey = block.getEntityAt(0)
41
- const entity = contentState.getEntity(entityKey)
42
- const {
43
- h2Text,
44
- sideIndexText,
45
- sideIndexUrl,
46
- sideIndexImage,
47
- } = entity.getData()
48
- const onChange: SideIndexInputOnChange = ({
49
- h2Text,
50
- sideIndexText,
51
- sideIndexUrl,
52
- sideIndexImage,
53
- }) => {
54
- // close `SideIndexInput`
55
- setToShowInput(false)
56
- onEditFinish({
57
- entityKey,
58
- entityData: {
59
- h2Text,
60
- sideIndexText,
61
- sideIndexUrl,
62
- sideIndexImage,
63
- },
64
- })
65
- }
66
-
67
- let sideIndexBlock
68
- if (sideIndexUrl) {
69
- sideIndexBlock = (
70
- <a href={sideIndexUrl}>
71
- <SideIndex>側欄: {sideIndexText ? sideIndexText : h2Text}</SideIndex>
72
- </a>
73
- )
74
- } else {
75
- sideIndexBlock = (
76
- <h2>
77
- {h2Text}
78
- <SideIndex>側欄: {sideIndexText ? sideIndexText : h2Text}</SideIndex>
79
- </h2>
80
- )
81
- }
82
-
83
- return (
84
- <React.Fragment>
85
- <SideIndexInput
86
- h2Text={h2Text}
87
- sideIndexText={sideIndexText}
88
- sideIndexUrl={sideIndexUrl}
89
- sideIndexImage={sideIndexImage}
90
- onChange={onChange}
91
- onCancel={() => {
92
- onEditFinish({})
93
- setToShowInput(false)
94
- }}
95
- isOpen={toShowInput}
96
- />
97
- <SideIndexBlockWrapper>
98
- {sideIndexBlock}
99
- <SideIndexBlockButton
100
- onClick={() => {
101
- // call `onEditStart` prop as we are trying to update the SideIndex entity
102
- onEditStart()
103
- // open `SideIndexInput`
104
- setToShowInput(true)
105
- }}
106
- >
107
- <i className="fa-solid fa-pen"></i>
108
- <span>Modify</span>
109
- </SideIndexBlockButton>
110
- </SideIndexBlockWrapper>
111
- </React.Fragment>
112
- )
113
- }
@@ -1,62 +0,0 @@
1
- import React from 'react'
2
- import styled from 'styled-components'
3
- import { DraftEntityInstance } from 'draft-js'
4
-
5
- const Image = styled.img`
6
- width: 100%;
7
- `
8
-
9
- const SlideshowCount = styled.div`
10
- position: absolute;
11
- top: 50%;
12
- left: 50%;
13
- border-radius: 100%;
14
- border: black 1px solid;
15
- transform: translate(-50%, -50%);
16
- background-color: white;
17
- display: flex;
18
- align-items: center;
19
- justify-content: center;
20
- flex-direction: column;
21
- aspect-ratio: 1;
22
- min-height: 66px;
23
- padding: 10px;
24
- `
25
-
26
- const Figure = styled.figure`
27
- position: relative;
28
- margin-block: unset;
29
- margin-inline: unset;
30
- margin: 0 10px;
31
- `
32
-
33
- // support old version of slideshow without delay propertiy
34
- export function SlideshowBlock(entity: DraftEntityInstance) {
35
- const images = entity.getData()
36
- return (
37
- <Figure>
38
- <Image
39
- src={images?.[0]?.resized?.w800}
40
- onError={(e) => (e.currentTarget.src = images?.[0]?.imageFile?.url)}
41
- />
42
- <SlideshowCount>+{images.length}</SlideshowCount>
43
- </Figure>
44
- )
45
- }
46
-
47
- // 202206 latest version of slideshow, support delay property
48
- export function SlideshowBlockV2(entity: DraftEntityInstance) {
49
- const { images, delay } = entity.getData()
50
- return (
51
- <Figure>
52
- <Image
53
- src={images?.[0]?.resized?.w800}
54
- onError={(e) => (e.currentTarget.src = images?.[0]?.imageFile?.url)}
55
- />
56
- <SlideshowCount>
57
- <div>+{images.length}</div>
58
- {delay && <div>{`${delay}s`}</div>}
59
- </SlideshowCount>
60
- </Figure>
61
- )
62
- }
@@ -1,488 +0,0 @@
1
- import React, { useEffect, useRef, useState } from 'react'
2
- import styled from 'styled-components'
3
- import {
4
- ContentBlock,
5
- ContentState,
6
- Editor,
7
- EditorState,
8
- RawDraftContentState,
9
- convertFromRaw,
10
- convertToRaw,
11
- } from 'draft-js'
12
- import cloneDeep from 'lodash/cloneDeep'
13
-
14
- const _ = {
15
- cloneDeep,
16
- }
17
-
18
- enum ActionType {
19
- Insert = 'insert',
20
- Delete = 'delete',
21
- Update = 'update',
22
- }
23
-
24
- enum TableEnum {
25
- Row = 'row',
26
- Column = 'column',
27
- }
28
-
29
- type RawTableData = RawDraftContentState[][]
30
- type TableData = EditorState[][]
31
- type UpdateAction = {
32
- type: ActionType.Update
33
- cIndex: number
34
- rIndex: number
35
- value: EditorState
36
- }
37
- type InsertAction = {
38
- type: ActionType.Insert
39
- target: TableEnum.Row | TableEnum.Column
40
- index: number
41
- }
42
- type DeleteAction = {
43
- type: ActionType.Delete
44
- target: TableEnum.Row | TableEnum.Column
45
- index: number
46
- }
47
-
48
- type TableStyles = {
49
- rows: Record<string, string>[]
50
- columns?: Record<string, string>[]
51
- cells?: Record<string, string>[][]
52
- }
53
-
54
- function createEmptyRow(colLen = 0, emptyValue: EditorState): TableData {
55
- const rtn: EditorState[] = []
56
- for (let i = 0; i < colLen; i++) {
57
- rtn.push(emptyValue)
58
- }
59
- return rtn
60
- }
61
-
62
- function resolveTableStyles(
63
- action: InsertAction | DeleteAction,
64
- tableStyles: TableStyles
65
- ) {
66
- switch (action?.type) {
67
- case ActionType.Insert: {
68
- if (action.target === TableEnum.Row) {
69
- const rows = [
70
- ...tableStyles.rows.slice(0, action.index),
71
- {},
72
- ...tableStyles.rows.slice(action.index),
73
- ]
74
- return Object.assign({}, tableStyles, { rows })
75
- }
76
- // TODO: handle target === TableEnum.Column if needed
77
- return tableStyles
78
- }
79
- case ActionType.Delete: {
80
- if (action.target === TableEnum.Row) {
81
- const rows = [
82
- ...tableStyles.rows.slice(0, action.index),
83
- ...tableStyles.rows.slice(action.index + 1),
84
- ]
85
- return Object.assign({}, tableStyles, { rows })
86
- }
87
- // TODO: handle target === TableEnum.Column if needed
88
- return tableStyles
89
- }
90
- // TODO: handle action.type === ActionType.Update if needed
91
- default: {
92
- return tableStyles
93
- }
94
- }
95
- }
96
-
97
- function resolveTableData(
98
- action: UpdateAction | InsertAction | DeleteAction,
99
- tableData: TableData
100
- ): TableData {
101
- switch (action?.type) {
102
- case ActionType.Insert: {
103
- if (typeof action?.index !== 'number') {
104
- return tableData
105
- }
106
- if (action?.target === TableEnum.Column) {
107
- // add the new column at specific position in each row
108
- return tableData.map((r) => [
109
- ...r.slice(0, action?.index),
110
- EditorState.createEmpty(),
111
- ...r.slice(action?.index),
112
- ])
113
- }
114
- // add the new row
115
- return [
116
- ...tableData.slice(0, action?.index),
117
- createEmptyRow(tableData?.[0]?.length, EditorState.createEmpty()),
118
- ...tableData.slice(action?.index),
119
- ]
120
- }
121
- case ActionType.Delete: {
122
- if (typeof action?.index !== 'number') {
123
- return tableData
124
- }
125
- if (action?.target === 'column') {
126
- // delete the column at specific position in each row
127
- return tableData.map((r) => [
128
- ...r.slice(0, action.index),
129
- ...r.slice(action.index + 1),
130
- ])
131
- }
132
- // delete the column
133
- return [
134
- ...tableData.slice(0, action.index),
135
- ...tableData.slice(action.index + 1),
136
- ]
137
- }
138
- case ActionType.Update: {
139
- // The reason we copy the array is to make sure
140
- // that React component re-renders.
141
- const copiedData = [...tableData]
142
- if (
143
- typeof action?.rIndex !== 'number' ||
144
- typeof action?.cIndex !== 'number'
145
- ) {
146
- return copiedData
147
- }
148
- copiedData[action.rIndex][action.cIndex] = action?.value
149
- return copiedData
150
- }
151
- default: {
152
- return tableData
153
- }
154
- }
155
- }
156
-
157
- type TableBlockProps = {
158
- block: ContentBlock
159
- blockProps: {
160
- onEditStart: () => void
161
- onEditFinish: ({
162
- entityKey,
163
- entityData,
164
- }: {
165
- entityKey?: string
166
- entityData?: Record<string, unknown>
167
- }) => void
168
- getMainEditorReadOnly: () => boolean
169
- }
170
- contentState: ContentState
171
- }
172
-
173
- function convertTableDataFromRaw(rawTableData: RawTableData): TableData {
174
- return rawTableData.map((rowData) => {
175
- return rowData.map((colData) => {
176
- const contentState = convertFromRaw(colData)
177
- return EditorState.createWithContent(contentState)
178
- })
179
- })
180
- }
181
-
182
- function convertTableDataToRaw(tableData: TableData): RawTableData {
183
- return tableData.map((rowData) => {
184
- return rowData.map((colData) => {
185
- return convertToRaw(colData.getCurrentContent())
186
- })
187
- })
188
- }
189
-
190
- const Table = styled.div`
191
- display: table;
192
- width: 95%;
193
- border-collapse: collapse;
194
- `
195
-
196
- const Tr = styled.div`
197
- display: table-row;
198
- `
199
-
200
- const Td = styled.div`
201
- display: table-cell;
202
- border-width: 1px;
203
- min-width: 100px;
204
- min-height: 40px;
205
- padding: 10px;
206
- `
207
-
208
- const StyledFirstRow = styled.div`
209
- display: table-row;
210
- height: 10px;
211
-
212
- div {
213
- display: table-cell;
214
- position: relative;
215
- }
216
-
217
- span {
218
- cursor: pointer;
219
- line-height: 10px;
220
- }
221
-
222
- span:first-child {
223
- position: absolute;
224
- right: 50%;
225
- transform: translateX(50%);
226
- }
227
-
228
- span:first-child:before {
229
- content: '•';
230
- }
231
-
232
- span:first-child:hover:before {
233
- content: '➖';
234
- }
235
-
236
- span:last-child {
237
- position: absolute;
238
- right: -5px;
239
- }
240
-
241
- span:last-child:before {
242
- content: '•';
243
- }
244
-
245
- span:last-child:hover:before {
246
- content: '➕';
247
- }
248
- `
249
-
250
- const StyledFirstColumn = styled.div`
251
- display: table-cell;
252
- width: 10px;
253
- position: relative;
254
-
255
- span {
256
- cursor: pointer;
257
- }
258
-
259
- span:first-child {
260
- position: absolute;
261
- bottom: 50%;
262
- right: 0px;
263
- transform: translateY(50%);
264
- }
265
-
266
- span:first-child:before {
267
- content: '•';
268
- }
269
-
270
- span:first-child:hover:before {
271
- content: '➖';
272
- }
273
-
274
- span:last-child {
275
- position: absolute;
276
- bottom: -10px;
277
- right: 0px;
278
- }
279
-
280
- span:last-child:before {
281
- content: '•';
282
- }
283
-
284
- span:last-child:hover:before {
285
- content: '➕';
286
- }
287
- `
288
-
289
- const TableBlockContainer = styled.div`
290
- margin: 15px 0;
291
- position: relative;
292
- overflow: scroll;
293
- padding: 15px;
294
- `
295
-
296
- export const TableBlock = (props: TableBlockProps) => {
297
- const { block, blockProps, contentState } = props
298
- const { onEditStart, onEditFinish, getMainEditorReadOnly } = blockProps
299
- const entityKey = block.getEntityAt(0)
300
- const entity = contentState.getEntity(entityKey)
301
- const {
302
- tableData: rawTableData,
303
- tableStyles: _tableStyles,
304
- }: { tableData: RawTableData; tableStyles: TableStyles } = entity.getData()
305
- const [tableData, setTableData] = useState(
306
- convertTableDataFromRaw(rawTableData)
307
- )
308
- // deep clone `_tableStyles` to prevent updating the entity data directly
309
- const [tableStyles, setTableStyles] = useState(_.cloneDeep(_tableStyles))
310
- const tableRef = useRef(null)
311
-
312
- // `TableBlock` will render other inner/nested DraftJS Editors inside the main Editor.
313
- // However, main Editor's `readOnly` needs to be mutually exclusive with nested Editors' `readOnly`.
314
- // If the main Editor and nested Editor are editable (`readOnly={false}`) at the same time,
315
- // there will be a DraftJS Edtior Selection bug.
316
- const [cellEditorReadOnly, setCellEditorReadOnly] = useState(
317
- !getMainEditorReadOnly()
318
- )
319
-
320
- // The user clicks the table for editing
321
- const onTableClick = () => {
322
- // call `onEditStart` function to tell the main DraftJS Editor
323
- // that we are going to interact with the custom atomic block.
324
- onEditStart()
325
-
326
- // make nested DraftJS Editors editable
327
- setCellEditorReadOnly(false)
328
- }
329
-
330
- useEffect(
331
- () => {
332
- // The user clicks other places except the table,
333
- // so we think he/she doesn't want to edit the table anymore.
334
- // Therefore, we call `onEditFinish` function to pass modified table data
335
- // back to the main DraftJS Edtior.
336
- function handleClickOutside(event) {
337
- // `!cellEditorReadOnly` condition is needed.
338
- // If there are two tables in the main Editor,
339
- // this `handleClickOutside` will only handle the just updated one.
340
- if (
341
- tableRef.current &&
342
- !(tableRef.current as HTMLElement).contains(event.target) &&
343
- !cellEditorReadOnly
344
- ) {
345
- // make inner DraftJS Editors NOT editable
346
- setCellEditorReadOnly(true)
347
-
348
- // call `onEditFinish` function tell the main DraftJS Editor
349
- // that we are finishing interacting with the custom atomic block.
350
- onEditFinish({
351
- entityKey,
352
- entityData: {
353
- tableData: convertTableDataToRaw(tableData),
354
- tableStyles,
355
- },
356
- })
357
- }
358
- }
359
- console.debug(
360
- '(rich-text-editor/table): add click outside event listener'
361
- )
362
- document.addEventListener('mousedown', handleClickOutside)
363
- return () => {
364
- // Unbind the event listener on clean up
365
- console.debug(
366
- '(rich-text-editor/table): remove click outside event listener'
367
- )
368
- document.removeEventListener('mousedown', handleClickOutside)
369
- }
370
- },
371
- // Skip running effect if `tableData` and `cellEditorReadOnly` are not changed.
372
- [tableData, cellEditorReadOnly]
373
- )
374
-
375
- return (
376
- <TableBlockContainer>
377
- <Table key={entityKey} onClick={onTableClick} ref={tableRef}>
378
- <StyledFirstRow>
379
- {/* The following `div` is for the first empty column in rows */}
380
- <div />
381
- {tableData?.[0]?.map((colData, cIndex) => {
382
- return (
383
- <div key={`col_${cIndex + 1}`}>
384
- <span
385
- onClick={() => {
386
- const deleteColumn: DeleteAction = {
387
- type: ActionType.Delete,
388
- target: TableEnum.Column,
389
- index: cIndex,
390
- }
391
- const updatedTableData = resolveTableData(
392
- deleteColumn,
393
- tableData
394
- )
395
- setTableData(updatedTableData)
396
- }}
397
- />
398
- <span
399
- onClick={() => {
400
- const insertColumn: InsertAction = {
401
- type: ActionType.Insert,
402
- target: TableEnum.Column,
403
- index: cIndex + 1,
404
- }
405
- const updatedTableData = resolveTableData(
406
- insertColumn,
407
- tableData
408
- )
409
- setTableData(updatedTableData)
410
- }}
411
- />
412
- </div>
413
- )
414
- })}
415
- </StyledFirstRow>
416
- {tableData.map((rowData, rIndex) => {
417
- const colsJsx = rowData.map((colData, cIndex) => {
418
- return (
419
- <Td key={`col_${cIndex}`}>
420
- {/* TODO: add editor buttons if needed */}
421
- <Editor
422
- onChange={(editorState) => {
423
- const updateAction: UpdateAction = {
424
- type: ActionType.Update,
425
- cIndex,
426
- rIndex,
427
- value: editorState,
428
- }
429
- const updatedTableData = resolveTableData(
430
- updateAction,
431
- tableData
432
- )
433
- setTableData(updatedTableData)
434
- }}
435
- editorState={colData}
436
- readOnly={cellEditorReadOnly}
437
- />
438
- </Td>
439
- )
440
- })
441
- return (
442
- <React.Fragment key={`row_${rIndex}`}>
443
- <Tr style={tableStyles?.rows?.[rIndex]}>
444
- <StyledFirstColumn>
445
- <span
446
- onClick={() => {
447
- const deleteRowAction: DeleteAction = {
448
- type: ActionType.Delete,
449
- target: TableEnum.Row,
450
- index: rIndex,
451
- }
452
- const updatedTableData = resolveTableData(
453
- deleteRowAction,
454
- tableData
455
- )
456
- setTableData(updatedTableData)
457
- setTableStyles(
458
- resolveTableStyles(deleteRowAction, tableStyles)
459
- )
460
- }}
461
- />
462
- <span
463
- onClick={() => {
464
- const addRowAction: InsertAction = {
465
- type: ActionType.Insert,
466
- target: TableEnum.Row,
467
- index: rIndex + 1,
468
- }
469
- const updatedTableData = resolveTableData(
470
- addRowAction,
471
- tableData
472
- )
473
- setTableData(updatedTableData)
474
- setTableStyles(
475
- resolveTableStyles(addRowAction, tableStyles)
476
- )
477
- }}
478
- />
479
- </StyledFirstColumn>
480
- {colsJsx}
481
- </Tr>
482
- </React.Fragment>
483
- )
484
- })}
485
- </Table>
486
- </TableBlockContainer>
487
- )
488
- }