@crystallize/design-system 1.3.2 → 1.4.1

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 (246) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/TableComponent-I2YOOYOU.css +281 -0
  3. package/dist/TableComponent-QINOO453.mjs +1377 -0
  4. package/dist/arrow-clockwise-Z2G6UEGP.svg +1 -0
  5. package/dist/arrow-counterclockwise-2O5EYVJT.svg +1 -0
  6. package/dist/bg-color-HB2WDYGO.svg +1 -0
  7. package/dist/camera-CR7D2PNH.svg +1 -0
  8. package/dist/caret-right-fill-FFBNEXVX.svg +1 -0
  9. package/dist/chat-square-quote-CI6PUJHH.svg +1 -0
  10. package/dist/chevron-down-3FRWSIKS.svg +1 -0
  11. package/dist/chunk-VUXQZRSP.mjs +737 -0
  12. package/dist/clipboard-OSEFDF25.svg +1 -0
  13. package/dist/close-FH57ZMJF.svg +1 -0
  14. package/dist/code-SEVR6TIQ.svg +1 -0
  15. package/dist/copy-DMGDODUL.svg +1 -0
  16. package/dist/diagram-2-CEJUD2B4.svg +1 -0
  17. package/dist/download-JXUGIUCX.svg +1 -0
  18. package/dist/draggable-block-menu-KKHDNKJA.svg +1 -0
  19. package/dist/dropdown-more-BHZ5COKX.svg +1 -0
  20. package/dist/file-image-TIQPFJX4.svg +1 -0
  21. package/dist/filetype-gif-OG2BEYYK.svg +1 -0
  22. package/dist/font-color-J4GA3ZJO.svg +1 -0
  23. package/dist/font-family-ZU5N6TTE.svg +1 -0
  24. package/dist/gear-ICMT4NTP.svg +1 -0
  25. package/dist/horizontal-rule-N6RD2V7H.svg +1 -0
  26. package/dist/indent-MJ6JIMCK.svg +1 -0
  27. package/dist/index.css +2711 -315
  28. package/dist/index.d.ts +145 -40
  29. package/dist/index.js +10376 -1481
  30. package/dist/index.mjs +7609 -746
  31. package/dist/journal-code-XUT44HDV.svg +1 -0
  32. package/dist/justify-J7X5JEEX.svg +1 -0
  33. package/dist/link-W52N4JKZ.svg +1 -0
  34. package/dist/list-ol-2ZEUN4Z7.svg +1 -0
  35. package/dist/list-ul-DVKNUP47.svg +1 -0
  36. package/dist/lock-WCYOZOHW.svg +1 -0
  37. package/dist/lock-fill-JZSKOSHK.svg +1 -0
  38. package/dist/markdown-4BGQNLLT.svg +1 -0
  39. package/dist/mic-H5FNOMM7.svg +1 -0
  40. package/dist/outdent-2LUMUMIP.svg +1 -0
  41. package/dist/paint-bucket-VCISMZTH.svg +1 -0
  42. package/dist/palette-SWGFPRWZ.svg +1 -0
  43. package/dist/pencil-fill-STFSC26F.svg +1 -0
  44. package/dist/plug-HGGGEVS3.svg +1 -0
  45. package/dist/plug-fill-OTG3U4TN.svg +1 -0
  46. package/dist/plus-CQISIKEC.svg +1 -0
  47. package/dist/plus-slash-minus-N22JU4TI.svg +1 -0
  48. package/dist/prettier-WUJ7B5NV.svg +1 -0
  49. package/dist/prettier-error-DYJSLYDP.svg +1 -0
  50. package/dist/square-check-UTG6FU6D.svg +1 -0
  51. package/dist/success-YVXUMPEZ.svg +1 -0
  52. package/dist/table-BR6DI4ZQ.svg +1 -0
  53. package/dist/text-center-UQI6PAEF.svg +1 -0
  54. package/dist/text-left-KT2B6TR3.svg +1 -0
  55. package/dist/text-paragraph-MFTUIIQG.svg +1 -0
  56. package/dist/text-right-SKELPISG.svg +1 -0
  57. package/dist/trash-UOM6D7TD.svg +1 -0
  58. package/dist/type-bold-PY7COC3N.svg +1 -0
  59. package/dist/type-h1-6KJP7YOM.svg +1 -0
  60. package/dist/type-h2-VHI2USC3.svg +1 -0
  61. package/dist/type-h3-JIU77CHO.svg +1 -0
  62. package/dist/type-h4-P5EHKDAL.svg +1 -0
  63. package/dist/type-h5-CS2KYVRG.svg +1 -0
  64. package/dist/type-h6-J2O74LJZ.svg +1 -0
  65. package/dist/type-italic-3DSFOSG2.svg +1 -0
  66. package/dist/type-strikethrough-E2KKQFSX.svg +1 -0
  67. package/dist/type-subscript-BMPTRIBU.svg +1 -0
  68. package/dist/type-superscript-EDF6EPAA.svg +1 -0
  69. package/dist/type-underline-CBFA5VLF.svg +1 -0
  70. package/dist/upload-Q6KICGZW.svg +1 -0
  71. package/dist/user-EOI2NEFZ.svg +1 -0
  72. package/package.json +30 -6
  73. package/src/dialog/dialog.tsx +1 -0
  74. package/src/icon-button/icon-button.css +16 -14
  75. package/src/index.ts +4 -4
  76. package/src/input/input.css +1 -1
  77. package/src/input-with-label/input-with-label.css +1 -1
  78. package/src/rich-text-editor/appSettings.ts +28 -0
  79. package/src/rich-text-editor/context/SettingsContext.tsx +71 -0
  80. package/src/rich-text-editor/context/SharedAutocompleteContext.tsx +60 -0
  81. package/src/rich-text-editor/context/SharedHistoryContext.tsx +25 -0
  82. package/src/rich-text-editor/hooks/useReport.ts +64 -0
  83. package/src/rich-text-editor/images/cat-typing.gif +0 -0
  84. package/src/rich-text-editor/images/emoji/1F600.png +0 -0
  85. package/src/rich-text-editor/images/emoji/1F641.png +0 -0
  86. package/src/rich-text-editor/images/emoji/1F642.png +0 -0
  87. package/src/rich-text-editor/images/emoji/2764.png +0 -0
  88. package/src/rich-text-editor/images/emoji/LICENSE.md +5 -0
  89. package/src/rich-text-editor/images/icons/LICENSE.md +5 -0
  90. package/src/rich-text-editor/images/icons/arrow-clockwise.svg +1 -0
  91. package/src/rich-text-editor/images/icons/arrow-counterclockwise.svg +1 -0
  92. package/src/rich-text-editor/images/icons/bg-color.svg +1 -0
  93. package/src/rich-text-editor/images/icons/camera.svg +1 -0
  94. package/src/rich-text-editor/images/icons/card-checklist.svg +1 -0
  95. package/src/rich-text-editor/images/icons/caret-right-fill.svg +1 -0
  96. package/src/rich-text-editor/images/icons/chat-left-text.svg +1 -0
  97. package/src/rich-text-editor/images/icons/chat-right-dots.svg +1 -0
  98. package/src/rich-text-editor/images/icons/chat-right-text.svg +1 -0
  99. package/src/rich-text-editor/images/icons/chat-right.svg +1 -0
  100. package/src/rich-text-editor/images/icons/chat-square-quote.svg +1 -0
  101. package/src/rich-text-editor/images/icons/chevron-down.svg +1 -0
  102. package/src/rich-text-editor/images/icons/clipboard.svg +1 -0
  103. package/src/rich-text-editor/images/icons/close.svg +1 -0
  104. package/src/rich-text-editor/images/icons/code.svg +1 -0
  105. package/src/rich-text-editor/images/icons/comments.svg +1 -0
  106. package/src/rich-text-editor/images/icons/copy.svg +1 -0
  107. package/src/rich-text-editor/images/icons/diagram-2.svg +1 -0
  108. package/src/rich-text-editor/images/icons/download.svg +1 -0
  109. package/src/rich-text-editor/images/icons/draggable-block-menu.svg +1 -0
  110. package/src/rich-text-editor/images/icons/dropdown-more.svg +1 -0
  111. package/src/rich-text-editor/images/icons/figma.svg +1 -0
  112. package/src/rich-text-editor/images/icons/file-image.svg +1 -0
  113. package/src/rich-text-editor/images/icons/filetype-gif.svg +1 -0
  114. package/src/rich-text-editor/images/icons/font-color.svg +1 -0
  115. package/src/rich-text-editor/images/icons/font-family.svg +1 -0
  116. package/src/rich-text-editor/images/icons/gear.svg +1 -0
  117. package/src/rich-text-editor/images/icons/horizontal-rule.svg +1 -0
  118. package/src/rich-text-editor/images/icons/indent.svg +1 -0
  119. package/src/rich-text-editor/images/icons/journal-code.svg +1 -0
  120. package/src/rich-text-editor/images/icons/journal-text.svg +1 -0
  121. package/src/rich-text-editor/images/icons/justify.svg +1 -0
  122. package/src/rich-text-editor/images/icons/link.svg +1 -0
  123. package/src/rich-text-editor/images/icons/list-ol.svg +1 -0
  124. package/src/rich-text-editor/images/icons/list-ul.svg +1 -0
  125. package/src/rich-text-editor/images/icons/lock-fill.svg +1 -0
  126. package/src/rich-text-editor/images/icons/lock.svg +1 -0
  127. package/src/rich-text-editor/images/icons/markdown.svg +1 -0
  128. package/src/rich-text-editor/images/icons/mic.svg +1 -0
  129. package/src/rich-text-editor/images/icons/outdent.svg +1 -0
  130. package/src/rich-text-editor/images/icons/paint-bucket.svg +1 -0
  131. package/src/rich-text-editor/images/icons/palette.svg +1 -0
  132. package/src/rich-text-editor/images/icons/pencil-fill.svg +1 -0
  133. package/src/rich-text-editor/images/icons/plug-fill.svg +1 -0
  134. package/src/rich-text-editor/images/icons/plug.svg +1 -0
  135. package/src/rich-text-editor/images/icons/plus-slash-minus.svg +1 -0
  136. package/src/rich-text-editor/images/icons/plus.svg +1 -0
  137. package/src/rich-text-editor/images/icons/prettier-error.svg +1 -0
  138. package/src/rich-text-editor/images/icons/prettier.svg +1 -0
  139. package/src/rich-text-editor/images/icons/send.svg +1 -0
  140. package/src/rich-text-editor/images/icons/square-check.svg +1 -0
  141. package/src/rich-text-editor/images/icons/sticky.svg +1 -0
  142. package/src/rich-text-editor/images/icons/success.svg +1 -0
  143. package/src/rich-text-editor/images/icons/table.svg +1 -0
  144. package/src/rich-text-editor/images/icons/text-center.svg +1 -0
  145. package/src/rich-text-editor/images/icons/text-left.svg +1 -0
  146. package/src/rich-text-editor/images/icons/text-paragraph.svg +1 -0
  147. package/src/rich-text-editor/images/icons/text-right.svg +1 -0
  148. package/src/rich-text-editor/images/icons/trash.svg +1 -0
  149. package/src/rich-text-editor/images/icons/trash3.svg +1 -0
  150. package/src/rich-text-editor/images/icons/tweet.svg +1 -0
  151. package/src/rich-text-editor/images/icons/type-bold.svg +1 -0
  152. package/src/rich-text-editor/images/icons/type-h1.svg +1 -0
  153. package/src/rich-text-editor/images/icons/type-h2.svg +1 -0
  154. package/src/rich-text-editor/images/icons/type-h3.svg +1 -0
  155. package/src/rich-text-editor/images/icons/type-h4.svg +1 -0
  156. package/src/rich-text-editor/images/icons/type-h5.svg +1 -0
  157. package/src/rich-text-editor/images/icons/type-h6.svg +1 -0
  158. package/src/rich-text-editor/images/icons/type-italic.svg +1 -0
  159. package/src/rich-text-editor/images/icons/type-strikethrough.svg +1 -0
  160. package/src/rich-text-editor/images/icons/type-subscript.svg +1 -0
  161. package/src/rich-text-editor/images/icons/type-superscript.svg +1 -0
  162. package/src/rich-text-editor/images/icons/type-underline.svg +1 -0
  163. package/src/rich-text-editor/images/icons/upload.svg +1 -0
  164. package/src/rich-text-editor/images/icons/user.svg +1 -0
  165. package/src/rich-text-editor/images/icons/youtube.svg +1 -0
  166. package/src/rich-text-editor/images/image/LICENSE.md +5 -0
  167. package/src/rich-text-editor/images/landscape.jpg +0 -0
  168. package/src/rich-text-editor/images/logo.svg +1 -0
  169. package/src/rich-text-editor/images/yellow-flower-small.jpg +0 -0
  170. package/src/rich-text-editor/images/yellow-flower.jpg +0 -0
  171. package/src/rich-text-editor/index.ts +1 -0
  172. package/src/rich-text-editor/model/crystallize-rich-text-types/code.ts +39 -0
  173. package/src/rich-text-editor/model/crystallize-rich-text-types/headings.ts +12 -0
  174. package/src/rich-text-editor/model/crystallize-rich-text-types/index.ts +69 -0
  175. package/src/rich-text-editor/model/crystallize-rich-text-types/link.ts +9 -0
  176. package/src/rich-text-editor/model/crystallize-rich-text-types/table.ts +16 -0
  177. package/src/rich-text-editor/model/crystallize-to-lexical.ts +186 -0
  178. package/src/rich-text-editor/model/lexical-to-crystallize.ts +232 -0
  179. package/src/rich-text-editor/nodes/AutocompleteNode.tsx +96 -0
  180. package/src/rich-text-editor/nodes/BaseNodes.ts +45 -0
  181. package/src/rich-text-editor/nodes/KeywordNode.ts +73 -0
  182. package/src/rich-text-editor/nodes/TableCellNodes.ts +31 -0
  183. package/src/rich-text-editor/nodes/TableComponent.tsx +1547 -0
  184. package/src/rich-text-editor/nodes/TableNode.tsx +398 -0
  185. package/src/rich-text-editor/plugins/ActionsPlugin/index.tsx +83 -0
  186. package/src/rich-text-editor/plugins/AutoLinkPlugin/index.tsx +47 -0
  187. package/src/rich-text-editor/plugins/AutocompletePlugin/index.tsx +2536 -0
  188. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/CopyButton/index.tsx +60 -0
  189. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.css +14 -0
  190. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.tsx +140 -0
  191. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/index.css +46 -0
  192. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/index.tsx +155 -0
  193. package/src/rich-text-editor/plugins/CodeHighlightPlugin/index.ts +21 -0
  194. package/src/rich-text-editor/plugins/ComponentPickerPlugin/index.tsx +320 -0
  195. package/src/rich-text-editor/plugins/DragDropPastePlugin/index.ts +40 -0
  196. package/src/rich-text-editor/plugins/DraggableBlockPlugin/index.css +36 -0
  197. package/src/rich-text-editor/plugins/DraggableBlockPlugin/index.tsx +368 -0
  198. package/src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.css +40 -0
  199. package/src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.tsx +305 -0
  200. package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.css +128 -0
  201. package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +351 -0
  202. package/src/rich-text-editor/plugins/LinkPlugin/index.tsx +16 -0
  203. package/src/rich-text-editor/plugins/ListMaxIndentLevelPlugin/index.ts +86 -0
  204. package/src/rich-text-editor/plugins/MarkdownShortcutPlugin/index.tsx +16 -0
  205. package/src/rich-text-editor/plugins/MarkdownTransformers/index.ts +195 -0
  206. package/src/rich-text-editor/plugins/MaxLengthPlugin/index.tsx +49 -0
  207. package/src/rich-text-editor/plugins/SpeechToTextPlugin/index.ts +113 -0
  208. package/src/rich-text-editor/plugins/TabFocusPlugin/index.tsx +65 -0
  209. package/src/rich-text-editor/plugins/TableActionMenuPlugin/index.tsx +481 -0
  210. package/src/rich-text-editor/plugins/TableCellResizer/index.css +12 -0
  211. package/src/rich-text-editor/plugins/TableCellResizer/index.tsx +386 -0
  212. package/src/rich-text-editor/plugins/TablePlugin.tsx +190 -0
  213. package/src/rich-text-editor/plugins/ToolbarPlugin/index.tsx +726 -0
  214. package/src/rich-text-editor/plugins/TreeViewPlugin/index.tsx +25 -0
  215. package/src/rich-text-editor/plugins/TypingPerfPlugin/index.ts +117 -0
  216. package/src/rich-text-editor/rich-text-editor.css +1396 -0
  217. package/src/rich-text-editor/rich-text-editor.stories.tsx +385 -0
  218. package/src/rich-text-editor/rich-text-editor.tsx +228 -0
  219. package/src/rich-text-editor/tests/rich-text-editor-basic-rendering.test.tsx +47 -0
  220. package/src/rich-text-editor/tests/rich-text-editor-code.test.tsx +39 -0
  221. package/src/rich-text-editor/tests/rich-text-editor-model-basics.test.tsx +56 -0
  222. package/src/rich-text-editor/tests/rich-text-editor-model-conversions.test.tsx +195 -0
  223. package/src/rich-text-editor/tests/rich-text-editor-onchange.test.tsx +37 -0
  224. package/src/rich-text-editor/tests/rich-text-editor-quote.test.tsx +36 -0
  225. package/src/rich-text-editor/tests/rich-text-editor-text-formats.test.tsx +135 -0
  226. package/src/rich-text-editor/tests/rich-text-editor-typing.test.tsx +73 -0
  227. package/src/rich-text-editor/tests/utils.ts +23 -0
  228. package/src/rich-text-editor/themes/PlaygroundEditorTheme.css +433 -0
  229. package/src/rich-text-editor/themes/PlaygroundEditorTheme.ts +113 -0
  230. package/src/rich-text-editor/types.ts +5 -0
  231. package/src/rich-text-editor/ui/ContentEditable.css +13 -0
  232. package/src/rich-text-editor/ui/ContentEditable.tsx +15 -0
  233. package/src/rich-text-editor/ui/LinkPreview.css +57 -0
  234. package/src/rich-text-editor/ui/LinkPreview.tsx +169 -0
  235. package/src/rich-text-editor/utils/environment.ts +1 -0
  236. package/src/rich-text-editor/utils/getDOMRangeRect.ts +42 -0
  237. package/src/rich-text-editor/utils/getSelectedNode.ts +27 -0
  238. package/src/rich-text-editor/utils/guard.ts +10 -0
  239. package/src/rich-text-editor/utils/isMobileWidth.ts +7 -0
  240. package/src/rich-text-editor/utils/joinClasses.ts +13 -0
  241. package/src/rich-text-editor/utils/point.ts +55 -0
  242. package/src/rich-text-editor/utils/rect.ts +158 -0
  243. package/src/rich-text-editor/utils/setFloatingElemPosition.ts +46 -0
  244. package/src/rich-text-editor/utils/swipe.ts +127 -0
  245. package/src/rich-text-editor/utils/url.ts +33 -0
  246. package/src/Tokens.stories.tsx +0 -18
@@ -0,0 +1,398 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import * as React from 'react';
10
+ import { Suspense } from 'react';
11
+ import {
12
+ DecoratorNode,
13
+ type DOMConversionMap,
14
+ type DOMConversionOutput,
15
+ type DOMExportOutput,
16
+ type EditorConfig,
17
+ type LexicalEditor,
18
+ type LexicalNode,
19
+ type NodeKey,
20
+ type SerializedLexicalNode,
21
+ type Spread,
22
+ } from 'lexical';
23
+
24
+ export type Cell = {
25
+ colSpan: number;
26
+ json: string;
27
+ type: 'normal' | 'header';
28
+ id: string;
29
+ width: number | null;
30
+ };
31
+
32
+ export type Row = {
33
+ cells: Array<Cell>;
34
+ height: null | number;
35
+ id: string;
36
+ };
37
+
38
+ export type Rows = Array<Row>;
39
+
40
+ export const cellHTMLCache: Map<string, string> = new Map();
41
+ export const cellTextContentCache: Map<string, string> = new Map();
42
+
43
+ const emptyEditorJSON =
44
+ '{"root":{"children":[{"children":[],"direction":null,"format":"","indent":0,"type":"paragraph","version":1}],"direction":null,"format":"","indent":0,"type":"root","version":1}}';
45
+
46
+ const plainTextEditorJSON = (text: string) =>
47
+ text === ''
48
+ ? emptyEditorJSON
49
+ : `{"root":{"children":[{"children":[{"detail":0,"format":0,"mode":"normal","style":"","text":${text},"type":"text","version":1}],"direction":"ltr","format":"","indent":0,"type":"paragraph","version":1}],"direction":"ltr","format":"","indent":0,"type":"root","version":1}}`;
50
+
51
+ const TableComponent = React.lazy(
52
+ // @ts-ignore
53
+ () => import('./TableComponent'),
54
+ );
55
+
56
+ export function createUID(): string {
57
+ return Math.random()
58
+ .toString(36)
59
+ .replace(/[^a-z]+/g, '')
60
+ .substr(0, 5);
61
+ }
62
+
63
+ function createCell(type: 'normal' | 'header'): Cell {
64
+ return {
65
+ colSpan: 1,
66
+ id: createUID(),
67
+ json: emptyEditorJSON,
68
+ type,
69
+ width: null,
70
+ };
71
+ }
72
+
73
+ export function createRow(): Row {
74
+ return {
75
+ cells: [],
76
+ height: null,
77
+ id: createUID(),
78
+ };
79
+ }
80
+
81
+ export type SerializedTableNode = Spread<
82
+ {
83
+ rows: Rows;
84
+ type: 'tablesheet';
85
+ version: 1;
86
+ },
87
+ SerializedLexicalNode
88
+ >;
89
+
90
+ export function extractRowsFromHTML(tableElem: HTMLTableElement): Rows {
91
+ const rowElems = tableElem.querySelectorAll('tr');
92
+ const rows: Rows = [];
93
+ for (let y = 0; y < rowElems.length; y++) {
94
+ const rowElem = rowElems[y];
95
+ const cellElems = rowElem.querySelectorAll('td,th');
96
+ if (!cellElems || cellElems.length === 0) {
97
+ continue;
98
+ }
99
+ const cells: Array<Cell> = [];
100
+ for (let x = 0; x < cellElems.length; x++) {
101
+ const cellElem = cellElems[x] as HTMLElement;
102
+ const isHeader = cellElem.nodeName === 'TH';
103
+ const cell = createCell(isHeader ? 'header' : 'normal');
104
+ cell.json = plainTextEditorJSON(JSON.stringify(cellElem.innerText.replace(/\n/g, ' ')));
105
+ cells.push(cell);
106
+ }
107
+ const row = createRow();
108
+ row.cells = cells;
109
+ rows.push(row);
110
+ }
111
+ return rows;
112
+ }
113
+
114
+ function convertTableElement(domNode: HTMLElement): null | DOMConversionOutput {
115
+ const rowElems = domNode.querySelectorAll('tr');
116
+ if (!rowElems || rowElems.length === 0) {
117
+ return null;
118
+ }
119
+ const rows: Rows = [];
120
+ for (let y = 0; y < rowElems.length; y++) {
121
+ const rowElem = rowElems[y];
122
+ const cellElems = rowElem.querySelectorAll('td,th');
123
+ if (!cellElems || cellElems.length === 0) {
124
+ continue;
125
+ }
126
+ const cells: Array<Cell> = [];
127
+ for (let x = 0; x < cellElems.length; x++) {
128
+ const cellElem = cellElems[x] as HTMLElement;
129
+ const isHeader = cellElem.nodeName === 'TH';
130
+ const cell = createCell(isHeader ? 'header' : 'normal');
131
+ cell.json = plainTextEditorJSON(JSON.stringify(cellElem.innerText.replace(/\n/g, ' ')));
132
+ cells.push(cell);
133
+ }
134
+ const row = createRow();
135
+ row.cells = cells;
136
+ rows.push(row);
137
+ }
138
+ return { node: $createTableNode(rows) };
139
+ }
140
+
141
+ export function exportTableCellsToHTML(
142
+ rows: Rows,
143
+ rect?: { startX: number; endX: number; startY: number; endY: number },
144
+ ): HTMLElement {
145
+ const table = document.createElement('table');
146
+ const colGroup = document.createElement('colgroup');
147
+ const tBody = document.createElement('tbody');
148
+ const firstRow = rows[0];
149
+
150
+ for (let x = rect != null ? rect.startX : 0; x < (rect != null ? rect.endX + 1 : firstRow.cells.length); x++) {
151
+ const col = document.createElement('col');
152
+ colGroup.append(col);
153
+ }
154
+
155
+ for (let y = rect != null ? rect.startY : 0; y < (rect != null ? rect.endY + 1 : rows.length); y++) {
156
+ const row = rows[y];
157
+ const cells = row.cells;
158
+ const rowElem = document.createElement('tr');
159
+
160
+ for (let x = rect != null ? rect.startX : 0; x < (rect != null ? rect.endX + 1 : cells.length); x++) {
161
+ const cell = cells[x];
162
+ const cellElem = document.createElement(cell.type === 'header' ? 'th' : 'td');
163
+ cellElem.innerHTML = cellHTMLCache.get(cell.json) || '';
164
+ rowElem.appendChild(cellElem);
165
+ }
166
+ tBody.appendChild(rowElem);
167
+ }
168
+
169
+ table.appendChild(colGroup);
170
+ table.appendChild(tBody);
171
+ return table;
172
+ }
173
+
174
+ export class TableNode extends DecoratorNode<JSX.Element> {
175
+ __rows: Rows;
176
+
177
+ static getType(): string {
178
+ return 'tablesheet';
179
+ }
180
+
181
+ static clone(node: TableNode): TableNode {
182
+ return new TableNode(Array.from(node.__rows), node.__key);
183
+ }
184
+
185
+ static importJSON(serializedNode: SerializedTableNode): TableNode {
186
+ return $createTableNode(serializedNode.rows);
187
+ }
188
+
189
+ exportJSON(): SerializedTableNode {
190
+ return {
191
+ rows: this.__rows,
192
+ type: 'tablesheet',
193
+ version: 1,
194
+ };
195
+ }
196
+
197
+ static importDOM(): DOMConversionMap | null {
198
+ return {
199
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
200
+ table: (_node: Node) => ({
201
+ conversion: convertTableElement,
202
+ priority: 0,
203
+ }),
204
+ };
205
+ }
206
+
207
+ exportDOM(): DOMExportOutput {
208
+ return { element: exportTableCellsToHTML(this.__rows) };
209
+ }
210
+
211
+ constructor(rows?: Rows, key?: NodeKey) {
212
+ super(key);
213
+ this.__rows = rows || [];
214
+ }
215
+
216
+ createDOM(): HTMLElement {
217
+ return document.createElement('div');
218
+ }
219
+
220
+ updateDOM(): false {
221
+ return false;
222
+ }
223
+
224
+ mergeRows(startX: number, startY: number, mergeRows: Rows): void {
225
+ const self = this.getWritable();
226
+ const rows = self.__rows;
227
+ const endY = Math.min(rows.length, startY + mergeRows.length);
228
+ for (let y = startY; y < endY; y++) {
229
+ const row = rows[y];
230
+ const mergeRow = mergeRows[y - startY];
231
+ const cells = row.cells;
232
+ const cellsClone = Array.from(cells);
233
+ const rowClone = { ...row, cells: cellsClone };
234
+ const mergeCells = mergeRow.cells;
235
+ const endX = Math.min(cells.length, startX + mergeCells.length);
236
+ for (let x = startX; x < endX; x++) {
237
+ const cell = cells[x];
238
+ const mergeCell = mergeCells[x - startX];
239
+ const cellClone = { ...cell, json: mergeCell.json, type: mergeCell.type };
240
+ cellsClone[x] = cellClone;
241
+ }
242
+ rows[y] = rowClone;
243
+ }
244
+ }
245
+
246
+ updateCellJSON(x: number, y: number, json: string): void {
247
+ const self = this.getWritable();
248
+ const rows = self.__rows;
249
+ const row = rows[y];
250
+ const cells = row.cells;
251
+ const cell = cells[x];
252
+ const cellsClone = Array.from(cells);
253
+ const cellClone = { ...cell, json };
254
+ const rowClone = { ...row, cells: cellsClone };
255
+ cellsClone[x] = cellClone;
256
+ rows[y] = rowClone;
257
+ }
258
+
259
+ updateCellType(x: number, y: number, type: 'header' | 'normal'): void {
260
+ const self = this.getWritable();
261
+ const rows = self.__rows;
262
+ const row = rows[y];
263
+ const cells = row.cells;
264
+ const cell = cells[x];
265
+ const cellsClone = Array.from(cells);
266
+ const cellClone = { ...cell, type };
267
+ const rowClone = { ...row, cells: cellsClone };
268
+ cellsClone[x] = cellClone;
269
+ rows[y] = rowClone;
270
+ }
271
+
272
+ insertColumnAt(x: number): void {
273
+ const self = this.getWritable();
274
+ const rows = self.__rows;
275
+ for (let y = 0; y < rows.length; y++) {
276
+ const row = rows[y];
277
+ const cells = row.cells;
278
+ const cellsClone = Array.from(cells);
279
+ const rowClone = { ...row, cells: cellsClone };
280
+ const type = (cells[x] || cells[x - 1]).type;
281
+ cellsClone.splice(x, 0, createCell(type));
282
+ rows[y] = rowClone;
283
+ }
284
+ }
285
+
286
+ deleteColumnAt(x: number): void {
287
+ const self = this.getWritable();
288
+ const rows = self.__rows;
289
+ for (let y = 0; y < rows.length; y++) {
290
+ const row = rows[y];
291
+ const cells = row.cells;
292
+ const cellsClone = Array.from(cells);
293
+ const rowClone = { ...row, cells: cellsClone };
294
+ cellsClone.splice(x, 1);
295
+ rows[y] = rowClone;
296
+ }
297
+ }
298
+
299
+ addColumns(count: number): void {
300
+ const self = this.getWritable();
301
+ const rows = self.__rows;
302
+ for (let y = 0; y < rows.length; y++) {
303
+ const row = rows[y];
304
+ const cells = row.cells;
305
+ const cellsClone = Array.from(cells);
306
+ const rowClone = { ...row, cells: cellsClone };
307
+ const type = cells[cells.length - 1].type;
308
+ for (let x = 0; x < count; x++) {
309
+ cellsClone.push(createCell(type));
310
+ }
311
+ rows[y] = rowClone;
312
+ }
313
+ }
314
+
315
+ insertRowAt(y: number): void {
316
+ const self = this.getWritable();
317
+ const rows = self.__rows;
318
+ const prevRow = rows[y] || rows[y - 1];
319
+ const cellCount = prevRow.cells.length;
320
+ const row = createRow();
321
+ for (let x = 0; x < cellCount; x++) {
322
+ const cell = createCell(prevRow.cells[x].type);
323
+ row.cells.push(cell);
324
+ }
325
+ rows.splice(y, 0, row);
326
+ }
327
+
328
+ deleteRowAt(y: number): void {
329
+ const self = this.getWritable();
330
+ const rows = self.__rows;
331
+ rows.splice(y, 1);
332
+ }
333
+
334
+ addRows(count: number): void {
335
+ const self = this.getWritable();
336
+ const rows = self.__rows;
337
+ const prevRow = rows[rows.length - 1];
338
+ const cellCount = prevRow.cells.length;
339
+
340
+ for (let y = 0; y < count; y++) {
341
+ const row = createRow();
342
+ for (let x = 0; x < cellCount; x++) {
343
+ const cell = createCell(prevRow.cells[x].type);
344
+ row.cells.push(cell);
345
+ }
346
+ rows.push(row);
347
+ }
348
+ }
349
+
350
+ updateColumnWidth(x: number, width: number): void {
351
+ const self = this.getWritable();
352
+ const rows = self.__rows;
353
+ for (let y = 0; y < rows.length; y++) {
354
+ const row = rows[y];
355
+ const cells = row.cells;
356
+ const cellsClone = Array.from(cells);
357
+ const rowClone = { ...row, cells: cellsClone };
358
+ cellsClone[x].width = width;
359
+ rows[y] = rowClone;
360
+ }
361
+ }
362
+
363
+ decorate(_: LexicalEditor, config: EditorConfig): JSX.Element {
364
+ return (
365
+ <Suspense fallback="...">
366
+ <TableComponent nodeKey={this.__key} theme={config.theme} rows={this.__rows} />
367
+ </Suspense>
368
+ );
369
+ }
370
+
371
+ isInline(): false {
372
+ return false;
373
+ }
374
+ }
375
+
376
+ export function $isTableNode(node: LexicalNode | null | undefined): node is TableNode {
377
+ return node instanceof TableNode;
378
+ }
379
+
380
+ export function $createTableNode(rows: Rows): TableNode {
381
+ return new TableNode(rows);
382
+ }
383
+
384
+ export function $createTableNodeWithDimensions(
385
+ rowCount: number,
386
+ columnCount: number,
387
+ includeHeaders = true,
388
+ ): TableNode {
389
+ const rows: Rows = [];
390
+ for (let y = 0; y < columnCount; y++) {
391
+ const row: Row = createRow();
392
+ rows.push(row);
393
+ for (let x = 0; x < rowCount; x++) {
394
+ row.cells.push(createCell(includeHeaders === true && (y === 0 || x === 0) ? 'header' : 'normal'));
395
+ }
396
+ }
397
+ return new TableNode(rows);
398
+ }
@@ -0,0 +1,83 @@
1
+ /* eslint-disable @typescript-eslint/no-unused-vars */
2
+ /**
3
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ *
8
+ */
9
+
10
+ import { CLEAR_EDITOR_COMMAND, LexicalEditor } from 'lexical';
11
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
12
+
13
+ import { ActionMenu } from '../../../action-menu';
14
+ import { lexicalToCrystallizeRichText } from '../../model/lexical-to-crystallize';
15
+ import type { CrystallizeRichTextActionMenuItem } from '../../types';
16
+
17
+ async function exportFile(editor: LexicalEditor) {
18
+ const json = lexicalToCrystallizeRichText({ editorState: editor.getEditorState() });
19
+
20
+ const blob = new Blob([JSON.stringify(json, null, 1)], {
21
+ type: 'application/json',
22
+ });
23
+ const href = URL.createObjectURL(blob);
24
+
25
+ const link = document.createElement('a');
26
+ link.href = href;
27
+ link.download = 'crystallizeRichText.json';
28
+
29
+ document.body.appendChild(link);
30
+ link.click();
31
+ document.body.removeChild(link);
32
+
33
+ URL.revokeObjectURL(href);
34
+ }
35
+
36
+ export default function ActionsPlugin({
37
+ append,
38
+ prepend,
39
+ }: {
40
+ append?: CrystallizeRichTextActionMenuItem[];
41
+ prepend?: CrystallizeRichTextActionMenuItem[];
42
+ }): JSX.Element {
43
+ const [editor] = useLexicalComposerContext();
44
+ return (
45
+ <div className="z-50 flex items-center ">
46
+ <div></div>
47
+ <ActionMenu>
48
+ {!prepend
49
+ ? null
50
+ : prepend.map(actionItem => (
51
+ <ActionMenu.Item
52
+ key={actionItem.title}
53
+ onSelect={actionItem.action}
54
+ className={actionItem.type === 'danger' ? 'danger' : ''}
55
+ >
56
+ {actionItem.title}
57
+ </ActionMenu.Item>
58
+ ))}
59
+ <ActionMenu.Item onSelect={() => exportFile(editor)}>Export to JSON</ActionMenu.Item>
60
+ <ActionMenu.Item
61
+ className="danger"
62
+ onSelect={() => {
63
+ editor.dispatchCommand(CLEAR_EDITOR_COMMAND, undefined);
64
+ editor.focus();
65
+ }}
66
+ >
67
+ Clear paragraph
68
+ </ActionMenu.Item>
69
+ {!append
70
+ ? null
71
+ : append.map(actionItem => (
72
+ <ActionMenu.Item
73
+ key={actionItem.title}
74
+ onSelect={actionItem.action}
75
+ className={actionItem.type === 'danger' ? 'danger' : ''}
76
+ >
77
+ {actionItem.title}
78
+ </ActionMenu.Item>
79
+ ))}
80
+ </ActionMenu>
81
+ </div>
82
+ );
83
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ *
7
+ */
8
+
9
+ import { AutoLinkPlugin } from '@lexical/react/LexicalAutoLinkPlugin';
10
+ import * as React from 'react';
11
+
12
+ const URL_MATCHER =
13
+ /((https?:\/\/(www\.)?)|(www\.))[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/;
14
+
15
+ const EMAIL_MATCHER =
16
+ /(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;
17
+
18
+ const MATCHERS = [
19
+ (text: string) => {
20
+ const match = URL_MATCHER.exec(text);
21
+ if (match === null) {
22
+ return null;
23
+ }
24
+ const fullMatch = match[0];
25
+ return {
26
+ index: match.index,
27
+ length: fullMatch.length,
28
+ text: fullMatch,
29
+ url: fullMatch.startsWith('http') ? fullMatch : `https://${fullMatch}`,
30
+ };
31
+ },
32
+ (text: string) => {
33
+ const match = EMAIL_MATCHER.exec(text);
34
+ return (
35
+ match && {
36
+ index: match.index,
37
+ length: match[0].length,
38
+ text: match[0],
39
+ url: `mailto:${match[0]}`,
40
+ }
41
+ );
42
+ },
43
+ ];
44
+
45
+ export default function LexicalAutoLinkPlugin(): JSX.Element {
46
+ return <AutoLinkPlugin matchers={MATCHERS} />;
47
+ }