@crystallize/design-system 1.4.0 → 1.4.2

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 (380) hide show
  1. package/CHANGELOG.md +124 -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 +4209 -0
  28. package/dist/index.d.ts +450 -3
  29. package/dist/index.js +11526 -5
  30. package/dist/index.mjs +9437 -0
  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 +114 -79
  73. package/readme.md +9 -0
  74. package/src/action-menu/ActionMenu.stories.tsx +25 -0
  75. package/src/action-menu/action-item.tsx +16 -0
  76. package/src/action-menu/action-menu.css +38 -0
  77. package/src/action-menu/action-menu.tsx +25 -0
  78. package/src/action-menu/index.tsx +3 -0
  79. package/src/avatar/Avatar.stories.tsx +20 -0
  80. package/src/avatar/avatar.css +23 -0
  81. package/src/avatar/avatar.tsx +34 -0
  82. package/src/avatar/get-initials.ts +5 -0
  83. package/src/avatar/index.ts +1 -0
  84. package/src/button/Button.stories.tsx +105 -0
  85. package/src/button/button.css +116 -0
  86. package/src/button/button.tsx +136 -0
  87. package/src/button/index.ts +3 -0
  88. package/src/card/card.css +7 -0
  89. package/src/card/card.stories.tsx +24 -0
  90. package/src/card/card.tsx +27 -0
  91. package/src/card/index.ts +3 -0
  92. package/src/checkbox/checkbox.css +30 -0
  93. package/src/checkbox/checkbox.stories.tsx +62 -0
  94. package/src/checkbox/checkbox.test.tsx +16 -0
  95. package/src/checkbox/checkbox.tsx +28 -0
  96. package/src/checkbox/index.ts +1 -0
  97. package/src/colors/Colors.stories.tsx +127 -0
  98. package/src/colors/color-defaults.json +15 -0
  99. package/src/colors/color-pairing.json +12 -0
  100. package/src/colors/colors.json +158 -0
  101. package/src/colors/index.ts +1 -0
  102. package/src/colors/old-to-new.txt +19 -0
  103. package/src/colors/types.ts +29 -0
  104. package/src/dialog/Dialog.stories.tsx +168 -0
  105. package/src/dialog/Dialog.test.tsx +25 -0
  106. package/src/dialog/config.tsx +139 -0
  107. package/src/dialog/confirm-dialog.tsx +70 -0
  108. package/src/dialog/destroyFns.ts +1 -0
  109. package/src/dialog/dialog.css +27 -0
  110. package/src/dialog/dialog.tsx +95 -0
  111. package/src/dialog/index.tsx +40 -0
  112. package/src/dialog/types.ts +70 -0
  113. package/src/dropdown-menu/DropdownMenu.stories.tsx +38 -0
  114. package/src/dropdown-menu/dropdown-menu-item.tsx +15 -0
  115. package/src/dropdown-menu/dropdown-menu-label.tsx +10 -0
  116. package/src/dropdown-menu/dropdown-menu-root.tsx +33 -0
  117. package/src/dropdown-menu/dropdown-menu.css +20 -0
  118. package/src/dropdown-menu/index.ts +11 -0
  119. package/src/icon-button/IconButton.stories.tsx +45 -0
  120. package/src/icon-button/icon-button.css +50 -0
  121. package/src/icon-button/icon-button.tsx +39 -0
  122. package/src/icon-button/index.ts +3 -0
  123. package/src/iconography/Icon.stories.tsx +47 -0
  124. package/src/iconography/add.tsx +30 -0
  125. package/src/iconography/arrow.tsx +15 -0
  126. package/src/iconography/atom.tsx +59 -0
  127. package/src/iconography/cancel.tsx +26 -0
  128. package/src/iconography/catalogue.tsx +26 -0
  129. package/src/iconography/copy.tsx +24 -0
  130. package/src/iconography/crystal.tsx +93 -0
  131. package/src/iconography/customers.tsx +38 -0
  132. package/src/iconography/edit.tsx +30 -0
  133. package/src/iconography/error.tsx +40 -0
  134. package/src/iconography/fulfilment.tsx +58 -0
  135. package/src/iconography/glasses.tsx +62 -0
  136. package/src/iconography/graphQL.tsx +90 -0
  137. package/src/iconography/grid.tsx +84 -0
  138. package/src/iconography/hooks.tsx +26 -0
  139. package/src/iconography/image.tsx +47 -0
  140. package/src/iconography/index.ts +63 -0
  141. package/src/iconography/info.tsx +41 -0
  142. package/src/iconography/key.tsx +19 -0
  143. package/src/iconography/language.tsx +38 -0
  144. package/src/iconography/nail-polish.tsx +84 -0
  145. package/src/iconography/order.tsx +38 -0
  146. package/src/iconography/particle.tsx +88 -0
  147. package/src/iconography/percentage.tsx +44 -0
  148. package/src/iconography/price-tag.tsx +40 -0
  149. package/src/iconography/shapes.tsx +48 -0
  150. package/src/iconography/subscription.tsx +34 -0
  151. package/src/iconography/topics.tsx +58 -0
  152. package/src/iconography/triangle.tsx +27 -0
  153. package/src/iconography/usage.tsx +34 -0
  154. package/src/iconography/users.tsx +44 -0
  155. package/src/iconography/warning.tsx +51 -0
  156. package/src/index.css +14 -0
  157. package/src/index.ts +33 -0
  158. package/src/inline-radio/index.ts +1 -0
  159. package/src/inline-radio/inline-radio.css +36 -0
  160. package/src/inline-radio/inline-radio.stories.tsx +81 -0
  161. package/src/inline-radio/inline-radio.tsx +41 -0
  162. package/src/input/Input.stories.tsx +26 -0
  163. package/src/input/index.ts +1 -0
  164. package/src/input/input.css +7 -0
  165. package/src/input/input.tsx +20 -0
  166. package/src/input-with-label/InputWithLabel.stories.tsx +98 -0
  167. package/src/input-with-label/index.ts +3 -0
  168. package/src/input-with-label/input-with-label.css +35 -0
  169. package/src/input-with-label/input-with-label.tsx +59 -0
  170. package/src/label/index.ts +1 -0
  171. package/src/label/label.css +3 -0
  172. package/src/label/label.stories.tsx +19 -0
  173. package/src/label/label.tsx +13 -0
  174. package/src/progress/Progress.stories.tsx +26 -0
  175. package/src/progress/index.ts +1 -0
  176. package/src/progress/progress.css +7 -0
  177. package/src/progress/progress.tsx +17 -0
  178. package/src/radio/index.ts +1 -0
  179. package/src/radio/radio.css +20 -0
  180. package/src/radio/radio.stories.tsx +142 -0
  181. package/src/radio/radio.tsx +19 -0
  182. package/src/rich-text-editor/appSettings.ts +28 -0
  183. package/src/rich-text-editor/context/SettingsContext.tsx +71 -0
  184. package/src/rich-text-editor/context/SharedAutocompleteContext.tsx +60 -0
  185. package/src/rich-text-editor/context/SharedHistoryContext.tsx +25 -0
  186. package/src/rich-text-editor/hooks/useReport.ts +64 -0
  187. package/src/rich-text-editor/images/cat-typing.gif +0 -0
  188. package/src/rich-text-editor/images/emoji/1F600.png +0 -0
  189. package/src/rich-text-editor/images/emoji/1F641.png +0 -0
  190. package/src/rich-text-editor/images/emoji/1F642.png +0 -0
  191. package/src/rich-text-editor/images/emoji/2764.png +0 -0
  192. package/src/rich-text-editor/images/emoji/LICENSE.md +5 -0
  193. package/src/rich-text-editor/images/icons/LICENSE.md +5 -0
  194. package/src/rich-text-editor/images/icons/arrow-clockwise.svg +1 -0
  195. package/src/rich-text-editor/images/icons/arrow-counterclockwise.svg +1 -0
  196. package/src/rich-text-editor/images/icons/bg-color.svg +1 -0
  197. package/src/rich-text-editor/images/icons/camera.svg +1 -0
  198. package/src/rich-text-editor/images/icons/card-checklist.svg +1 -0
  199. package/src/rich-text-editor/images/icons/caret-right-fill.svg +1 -0
  200. package/src/rich-text-editor/images/icons/chat-left-text.svg +1 -0
  201. package/src/rich-text-editor/images/icons/chat-right-dots.svg +1 -0
  202. package/src/rich-text-editor/images/icons/chat-right-text.svg +1 -0
  203. package/src/rich-text-editor/images/icons/chat-right.svg +1 -0
  204. package/src/rich-text-editor/images/icons/chat-square-quote.svg +1 -0
  205. package/src/rich-text-editor/images/icons/chevron-down.svg +1 -0
  206. package/src/rich-text-editor/images/icons/clipboard.svg +1 -0
  207. package/src/rich-text-editor/images/icons/close.svg +1 -0
  208. package/src/rich-text-editor/images/icons/code.svg +1 -0
  209. package/src/rich-text-editor/images/icons/comments.svg +1 -0
  210. package/src/rich-text-editor/images/icons/copy.svg +1 -0
  211. package/src/rich-text-editor/images/icons/diagram-2.svg +1 -0
  212. package/src/rich-text-editor/images/icons/download.svg +1 -0
  213. package/src/rich-text-editor/images/icons/draggable-block-menu.svg +1 -0
  214. package/src/rich-text-editor/images/icons/dropdown-more.svg +1 -0
  215. package/src/rich-text-editor/images/icons/figma.svg +1 -0
  216. package/src/rich-text-editor/images/icons/file-image.svg +1 -0
  217. package/src/rich-text-editor/images/icons/filetype-gif.svg +1 -0
  218. package/src/rich-text-editor/images/icons/font-color.svg +1 -0
  219. package/src/rich-text-editor/images/icons/font-family.svg +1 -0
  220. package/src/rich-text-editor/images/icons/gear.svg +1 -0
  221. package/src/rich-text-editor/images/icons/horizontal-rule.svg +1 -0
  222. package/src/rich-text-editor/images/icons/indent.svg +1 -0
  223. package/src/rich-text-editor/images/icons/journal-code.svg +1 -0
  224. package/src/rich-text-editor/images/icons/journal-text.svg +1 -0
  225. package/src/rich-text-editor/images/icons/justify.svg +1 -0
  226. package/src/rich-text-editor/images/icons/link.svg +1 -0
  227. package/src/rich-text-editor/images/icons/list-ol.svg +1 -0
  228. package/src/rich-text-editor/images/icons/list-ul.svg +1 -0
  229. package/src/rich-text-editor/images/icons/lock-fill.svg +1 -0
  230. package/src/rich-text-editor/images/icons/lock.svg +1 -0
  231. package/src/rich-text-editor/images/icons/markdown.svg +1 -0
  232. package/src/rich-text-editor/images/icons/mic.svg +1 -0
  233. package/src/rich-text-editor/images/icons/outdent.svg +1 -0
  234. package/src/rich-text-editor/images/icons/paint-bucket.svg +1 -0
  235. package/src/rich-text-editor/images/icons/palette.svg +1 -0
  236. package/src/rich-text-editor/images/icons/pencil-fill.svg +1 -0
  237. package/src/rich-text-editor/images/icons/plug-fill.svg +1 -0
  238. package/src/rich-text-editor/images/icons/plug.svg +1 -0
  239. package/src/rich-text-editor/images/icons/plus-slash-minus.svg +1 -0
  240. package/src/rich-text-editor/images/icons/plus.svg +1 -0
  241. package/src/rich-text-editor/images/icons/prettier-error.svg +1 -0
  242. package/src/rich-text-editor/images/icons/prettier.svg +1 -0
  243. package/src/rich-text-editor/images/icons/send.svg +1 -0
  244. package/src/rich-text-editor/images/icons/square-check.svg +1 -0
  245. package/src/rich-text-editor/images/icons/sticky.svg +1 -0
  246. package/src/rich-text-editor/images/icons/success.svg +1 -0
  247. package/src/rich-text-editor/images/icons/table.svg +1 -0
  248. package/src/rich-text-editor/images/icons/text-center.svg +1 -0
  249. package/src/rich-text-editor/images/icons/text-left.svg +1 -0
  250. package/src/rich-text-editor/images/icons/text-paragraph.svg +1 -0
  251. package/src/rich-text-editor/images/icons/text-right.svg +1 -0
  252. package/src/rich-text-editor/images/icons/trash.svg +1 -0
  253. package/src/rich-text-editor/images/icons/trash3.svg +1 -0
  254. package/src/rich-text-editor/images/icons/tweet.svg +1 -0
  255. package/src/rich-text-editor/images/icons/type-bold.svg +1 -0
  256. package/src/rich-text-editor/images/icons/type-h1.svg +1 -0
  257. package/src/rich-text-editor/images/icons/type-h2.svg +1 -0
  258. package/src/rich-text-editor/images/icons/type-h3.svg +1 -0
  259. package/src/rich-text-editor/images/icons/type-h4.svg +1 -0
  260. package/src/rich-text-editor/images/icons/type-h5.svg +1 -0
  261. package/src/rich-text-editor/images/icons/type-h6.svg +1 -0
  262. package/src/rich-text-editor/images/icons/type-italic.svg +1 -0
  263. package/src/rich-text-editor/images/icons/type-strikethrough.svg +1 -0
  264. package/src/rich-text-editor/images/icons/type-subscript.svg +1 -0
  265. package/src/rich-text-editor/images/icons/type-superscript.svg +1 -0
  266. package/src/rich-text-editor/images/icons/type-underline.svg +1 -0
  267. package/src/rich-text-editor/images/icons/upload.svg +1 -0
  268. package/src/rich-text-editor/images/icons/user.svg +1 -0
  269. package/src/rich-text-editor/images/icons/youtube.svg +1 -0
  270. package/src/rich-text-editor/images/image/LICENSE.md +5 -0
  271. package/src/rich-text-editor/images/landscape.jpg +0 -0
  272. package/src/rich-text-editor/images/logo.svg +1 -0
  273. package/src/rich-text-editor/images/yellow-flower-small.jpg +0 -0
  274. package/src/rich-text-editor/images/yellow-flower.jpg +0 -0
  275. package/src/rich-text-editor/index.ts +1 -0
  276. package/src/rich-text-editor/model/crystallize-rich-text-types/code.ts +39 -0
  277. package/src/rich-text-editor/model/crystallize-rich-text-types/headings.ts +12 -0
  278. package/src/rich-text-editor/model/crystallize-rich-text-types/index.ts +69 -0
  279. package/src/rich-text-editor/model/crystallize-rich-text-types/link.ts +9 -0
  280. package/src/rich-text-editor/model/crystallize-rich-text-types/table.ts +16 -0
  281. package/src/rich-text-editor/model/crystallize-to-lexical.ts +186 -0
  282. package/src/rich-text-editor/model/lexical-to-crystallize.ts +232 -0
  283. package/src/rich-text-editor/nodes/AutocompleteNode.tsx +96 -0
  284. package/src/rich-text-editor/nodes/BaseNodes.ts +45 -0
  285. package/src/rich-text-editor/nodes/KeywordNode.ts +73 -0
  286. package/src/rich-text-editor/nodes/TableCellNodes.ts +31 -0
  287. package/src/rich-text-editor/nodes/TableComponent.tsx +1547 -0
  288. package/src/rich-text-editor/nodes/TableNode.tsx +398 -0
  289. package/src/rich-text-editor/plugins/ActionsPlugin/index.tsx +83 -0
  290. package/src/rich-text-editor/plugins/AutoLinkPlugin/index.tsx +47 -0
  291. package/src/rich-text-editor/plugins/AutocompletePlugin/index.tsx +2536 -0
  292. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/CopyButton/index.tsx +60 -0
  293. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.css +14 -0
  294. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/components/PrettierButton/index.tsx +140 -0
  295. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/index.css +46 -0
  296. package/src/rich-text-editor/plugins/CodeActionMenuPlugin/index.tsx +155 -0
  297. package/src/rich-text-editor/plugins/CodeHighlightPlugin/index.ts +21 -0
  298. package/src/rich-text-editor/plugins/ComponentPickerPlugin/index.tsx +320 -0
  299. package/src/rich-text-editor/plugins/DragDropPastePlugin/index.ts +40 -0
  300. package/src/rich-text-editor/plugins/DraggableBlockPlugin/index.css +36 -0
  301. package/src/rich-text-editor/plugins/DraggableBlockPlugin/index.tsx +368 -0
  302. package/src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.css +40 -0
  303. package/src/rich-text-editor/plugins/FloatingLinkEditorPlugin/index.tsx +305 -0
  304. package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.css +128 -0
  305. package/src/rich-text-editor/plugins/FloatingTextFormatToolbarPlugin/index.tsx +351 -0
  306. package/src/rich-text-editor/plugins/LinkPlugin/index.tsx +16 -0
  307. package/src/rich-text-editor/plugins/ListMaxIndentLevelPlugin/index.ts +86 -0
  308. package/src/rich-text-editor/plugins/MarkdownShortcutPlugin/index.tsx +16 -0
  309. package/src/rich-text-editor/plugins/MarkdownTransformers/index.ts +195 -0
  310. package/src/rich-text-editor/plugins/MaxLengthPlugin/index.tsx +49 -0
  311. package/src/rich-text-editor/plugins/SpeechToTextPlugin/index.ts +113 -0
  312. package/src/rich-text-editor/plugins/TabFocusPlugin/index.tsx +65 -0
  313. package/src/rich-text-editor/plugins/TableActionMenuPlugin/index.tsx +481 -0
  314. package/src/rich-text-editor/plugins/TableCellResizer/index.css +12 -0
  315. package/src/rich-text-editor/plugins/TableCellResizer/index.tsx +386 -0
  316. package/src/rich-text-editor/plugins/TablePlugin.tsx +190 -0
  317. package/src/rich-text-editor/plugins/ToolbarPlugin/index.tsx +726 -0
  318. package/src/rich-text-editor/plugins/TreeViewPlugin/index.tsx +25 -0
  319. package/src/rich-text-editor/plugins/TypingPerfPlugin/index.ts +117 -0
  320. package/src/rich-text-editor/rich-text-editor.css +1361 -0
  321. package/src/rich-text-editor/rich-text-editor.stories.tsx +385 -0
  322. package/src/rich-text-editor/rich-text-editor.tsx +228 -0
  323. package/src/rich-text-editor/tests/rich-text-editor-basic-rendering.test.tsx +47 -0
  324. package/src/rich-text-editor/tests/rich-text-editor-code.test.tsx +39 -0
  325. package/src/rich-text-editor/tests/rich-text-editor-model-basics.test.tsx +56 -0
  326. package/src/rich-text-editor/tests/rich-text-editor-model-conversions.test.tsx +195 -0
  327. package/src/rich-text-editor/tests/rich-text-editor-onchange.test.tsx +37 -0
  328. package/src/rich-text-editor/tests/rich-text-editor-quote.test.tsx +36 -0
  329. package/src/rich-text-editor/tests/rich-text-editor-text-formats.test.tsx +135 -0
  330. package/src/rich-text-editor/tests/rich-text-editor-typing.test.tsx +73 -0
  331. package/src/rich-text-editor/tests/utils.ts +23 -0
  332. package/src/rich-text-editor/themes/PlaygroundEditorTheme.css +433 -0
  333. package/src/rich-text-editor/themes/PlaygroundEditorTheme.ts +113 -0
  334. package/src/rich-text-editor/types.ts +5 -0
  335. package/src/rich-text-editor/ui/ContentEditable.css +13 -0
  336. package/src/rich-text-editor/ui/ContentEditable.tsx +15 -0
  337. package/src/rich-text-editor/ui/LinkPreview.css +57 -0
  338. package/src/rich-text-editor/ui/LinkPreview.tsx +169 -0
  339. package/src/rich-text-editor/utils/environment.ts +1 -0
  340. package/src/rich-text-editor/utils/getDOMRangeRect.ts +42 -0
  341. package/src/rich-text-editor/utils/getSelectedNode.ts +27 -0
  342. package/src/rich-text-editor/utils/guard.ts +10 -0
  343. package/src/rich-text-editor/utils/isMobileWidth.ts +7 -0
  344. package/src/rich-text-editor/utils/joinClasses.ts +13 -0
  345. package/src/rich-text-editor/utils/point.ts +55 -0
  346. package/src/rich-text-editor/utils/rect.ts +158 -0
  347. package/src/rich-text-editor/utils/setFloatingElemPosition.ts +46 -0
  348. package/src/rich-text-editor/utils/swipe.ts +127 -0
  349. package/src/rich-text-editor/utils/url.ts +33 -0
  350. package/src/select/index.ts +1 -0
  351. package/src/select/select-item.tsx +18 -0
  352. package/src/select/select-root.tsx +50 -0
  353. package/src/select/select.css +44 -0
  354. package/src/select/select.stories.tsx +74 -0
  355. package/src/select/select.ts +9 -0
  356. package/src/slider/Slider.stories.tsx +54 -0
  357. package/src/slider/index.ts +1 -0
  358. package/src/slider/slider.css +27 -0
  359. package/src/slider/slider.tsx +20 -0
  360. package/src/spinner/Spinner.stories.tsx +19 -0
  361. package/src/spinner/index.tsx +48 -0
  362. package/src/spinner/spinner.css +11 -0
  363. package/src/tag/Tag.stories.tsx +32 -0
  364. package/src/tag/index.ts +1 -0
  365. package/src/tag/tag.css +7 -0
  366. package/src/tag/tag.tsx +27 -0
  367. package/src/vite-env.d.ts +1 -0
  368. package/tailwind.config.cjs +51 -0
  369. package/LICENSE +0 -21
  370. package/README.md +0 -87
  371. package/dist/components/Button.d.ts +0 -11
  372. package/dist/components/Checkbox.d.ts +0 -29
  373. package/dist/components/Typography.d.ts +0 -14
  374. package/dist/design-system.cjs.development.js +0 -251
  375. package/dist/design-system.cjs.development.js.map +0 -1
  376. package/dist/design-system.cjs.production.min.js +0 -2
  377. package/dist/design-system.cjs.production.min.js.map +0 -1
  378. package/dist/design-system.esm.js +0 -245
  379. package/dist/design-system.esm.js.map +0 -1
  380. package/dist/styles/theme.d.ts +0 -2
@@ -0,0 +1,726 @@
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 { useCallback, useEffect, useState } from 'react';
10
+ import {
11
+ $createParagraphNode,
12
+ $getNodeByKey,
13
+ $getRoot,
14
+ $getSelection,
15
+ $isRangeSelection,
16
+ $isRootOrShadowRoot,
17
+ $isTextNode,
18
+ CAN_REDO_COMMAND,
19
+ CAN_UNDO_COMMAND,
20
+ COMMAND_PRIORITY_CRITICAL,
21
+ DEPRECATED_$isGridSelection,
22
+ FORMAT_TEXT_COMMAND,
23
+ REDO_COMMAND,
24
+ SELECTION_CHANGE_COMMAND,
25
+ UNDO_COMMAND,
26
+ type LexicalEditor,
27
+ type NodeKey,
28
+ } from 'lexical';
29
+ import {
30
+ $createCodeNode,
31
+ $isCodeNode,
32
+ CODE_LANGUAGE_FRIENDLY_NAME_MAP,
33
+ CODE_LANGUAGE_MAP,
34
+ getLanguageFriendlyName,
35
+ } from '@lexical/code';
36
+ import { $isLinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
37
+ import {
38
+ $isListNode,
39
+ INSERT_ORDERED_LIST_COMMAND,
40
+ INSERT_UNORDERED_LIST_COMMAND,
41
+ ListNode,
42
+ REMOVE_LIST_COMMAND,
43
+ } from '@lexical/list';
44
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';
45
+ import { $isDecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode';
46
+ import { INSERT_HORIZONTAL_RULE_COMMAND } from '@lexical/react/LexicalHorizontalRuleNode';
47
+ import { $createHeadingNode, $createQuoteNode, $isHeadingNode, HeadingTagType } from '@lexical/rich-text';
48
+ import { $selectAll, $setBlocksType_experimental } from '@lexical/selection';
49
+ import {
50
+ $findMatchingParent,
51
+ $getNearestBlockElementAncestorOrThrow,
52
+ $getNearestNodeOfType,
53
+ mergeRegister,
54
+ } from '@lexical/utils';
55
+
56
+ import { Button } from '../../../button';
57
+ import { Dialog } from '../../../dialog';
58
+ import { DropdownMenu } from '../../../dropdown-menu';
59
+ import { IconButton } from '../../../icon-button';
60
+ import { Icon } from '../../../iconography';
61
+ import type { CrystallizeRichTextActionMenuItem } from '../../types';
62
+ import { IS_APPLE } from '../../utils/environment';
63
+ import { getSelectedNode } from '../../utils/getSelectedNode';
64
+ import { sanitizeUrl } from '../../utils/url';
65
+ import { InsertNewTableDialog } from '../TablePlugin';
66
+ import ActionsPlugin from './../ActionsPlugin';
67
+
68
+ const blockTypeToBlockName = {
69
+ bullet: 'Bulleted List',
70
+ check: 'Check List',
71
+ code: 'Code Block',
72
+ h1: 'Heading 1',
73
+ h2: 'Heading 2',
74
+ h3: 'Heading 3',
75
+ h4: 'Heading 4',
76
+ h5: 'Heading 5',
77
+ h6: 'Heading 6',
78
+ number: 'Numbered List',
79
+ paragraph: 'Normal',
80
+ quote: 'Quote',
81
+ };
82
+
83
+ function getCodeLanguageOptions(): [string, string][] {
84
+ const options: [string, string][] = [];
85
+
86
+ for (const [lang, friendlyName] of Object.entries(CODE_LANGUAGE_FRIENDLY_NAME_MAP)) {
87
+ options.push([lang, friendlyName]);
88
+ }
89
+
90
+ return options;
91
+ }
92
+
93
+ const CODE_LANGUAGE_OPTIONS = getCodeLanguageOptions();
94
+
95
+ function dropDownActiveClass(active: boolean) {
96
+ if (active) return 'active dropdown-item-active';
97
+ else return '';
98
+ }
99
+
100
+ function BlockFormatDropDown({
101
+ editor,
102
+ blockType,
103
+ disabled = false,
104
+ }: {
105
+ blockType: keyof typeof blockTypeToBlockName;
106
+ editor: LexicalEditor;
107
+ disabled?: boolean;
108
+ }): JSX.Element {
109
+ const formatParagraph = () => {
110
+ if (blockType !== 'paragraph') {
111
+ editor.update(() => {
112
+ const selection = $getSelection();
113
+ if ($isRangeSelection(selection) || DEPRECATED_$isGridSelection(selection))
114
+ $setBlocksType_experimental(selection, () => $createParagraphNode());
115
+ });
116
+ }
117
+ };
118
+
119
+ const formatHeading = (headingSize: HeadingTagType) => {
120
+ if (blockType !== headingSize) {
121
+ editor.update(() => {
122
+ const selection = $getSelection();
123
+ if ($isRangeSelection(selection) || DEPRECATED_$isGridSelection(selection)) {
124
+ $setBlocksType_experimental(selection, () => $createHeadingNode(headingSize));
125
+ }
126
+ });
127
+ }
128
+ };
129
+
130
+ const formatBulletList = () => {
131
+ if (blockType !== 'bullet') {
132
+ editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined);
133
+ } else {
134
+ editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);
135
+ }
136
+ };
137
+
138
+ const formatNumberedList = () => {
139
+ if (blockType !== 'number') {
140
+ editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined);
141
+ } else {
142
+ editor.dispatchCommand(REMOVE_LIST_COMMAND, undefined);
143
+ }
144
+ };
145
+
146
+ const formatQuote = () => {
147
+ if (blockType !== 'quote') {
148
+ editor.update(() => {
149
+ const selection = $getSelection();
150
+ if ($isRangeSelection(selection) || DEPRECATED_$isGridSelection(selection)) {
151
+ $setBlocksType_experimental(selection, () => $createQuoteNode());
152
+ } else {
153
+ /**
154
+ * Will select the entire editor, in case it is not selected. This is added
155
+ * to get the unit tests working
156
+ */
157
+ $setBlocksType_experimental($getRoot().select(), () => $createQuoteNode());
158
+ }
159
+ });
160
+ }
161
+ };
162
+
163
+ const formatCode = () => {
164
+ if (blockType !== 'code') {
165
+ editor.update(() => {
166
+ let selection = $getSelection();
167
+
168
+ if ($isRangeSelection(selection) || DEPRECATED_$isGridSelection(selection)) {
169
+ if (selection.isCollapsed()) {
170
+ $setBlocksType_experimental(selection, () => $createCodeNode());
171
+ } else {
172
+ const textContent = selection.getTextContent();
173
+ const codeNode = $createCodeNode();
174
+ selection.insertNodes([codeNode]);
175
+ selection = $getSelection();
176
+ if ($isRangeSelection(selection)) selection.insertRawText(textContent);
177
+ }
178
+ } else {
179
+ /**
180
+ * Will select the entire editor, in case it is not selected. This is added
181
+ * to get the unit tests working
182
+ */
183
+ $setBlocksType_experimental($getRoot().select(), () => $createCodeNode());
184
+ }
185
+ });
186
+ }
187
+ };
188
+
189
+ return (
190
+ <DropdownMenu.Root
191
+ disabled={disabled}
192
+ style={{ zIndex: 1 }}
193
+ content={
194
+ <>
195
+ <DropdownMenu.Item onClick={formatParagraph}>
196
+ <i
197
+ className={`icon paragraph border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
198
+ blockType === 'paragraph' ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
199
+ }`}
200
+ />
201
+
202
+ <i className="icon paragraph" />
203
+ <span className={`${blockType === 'paragraph' ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
204
+ Normal
205
+ </span>
206
+ </DropdownMenu.Item>
207
+ <DropdownMenu.Item onClick={() => formatHeading('h1')}>
208
+ <i
209
+ className={`icon h1 border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
210
+ blockType === 'h1' ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
211
+ }`}
212
+ />
213
+ <span className={`${blockType === 'h1' ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
214
+ Heading 1
215
+ </span>
216
+ </DropdownMenu.Item>
217
+ <DropdownMenu.Item onClick={() => formatHeading('h2')}>
218
+ <i
219
+ className={`icon h2 border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
220
+ blockType === 'h2' ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
221
+ }`}
222
+ />
223
+ <span className={`${blockType === 'h2' ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
224
+ Heading 2
225
+ </span>
226
+ </DropdownMenu.Item>
227
+ <DropdownMenu.Item onClick={() => formatHeading('h3')}>
228
+ <i
229
+ className={`icon h3 border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
230
+ blockType === 'h3' ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
231
+ }`}
232
+ />
233
+ <span className={`${blockType === 'h3' ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
234
+ Heading 3
235
+ </span>
236
+ </DropdownMenu.Item>
237
+ <DropdownMenu.Item onClick={formatBulletList}>
238
+ <i
239
+ className={`icon bullet-list border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
240
+ blockType === 'bullet' ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
241
+ }`}
242
+ />
243
+ <span className={`${blockType === 'bullet' ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
244
+ Bullet List
245
+ </span>
246
+ </DropdownMenu.Item>
247
+ <DropdownMenu.Item onClick={formatNumberedList}>
248
+ <i
249
+ className={`icon numbered-list border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
250
+ blockType === 'number' ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
251
+ }`}
252
+ />
253
+ <span className={`${blockType === 'number' ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
254
+ Numbered List
255
+ </span>
256
+ </DropdownMenu.Item>
257
+ <DropdownMenu.Item onClick={formatQuote} data-testid="toggle-block-format-quote">
258
+ <i
259
+ className={`icon quote border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
260
+ blockType === 'quote' ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
261
+ }`}
262
+ />
263
+ <span className={`${blockType === 'quote' ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
264
+ Quote
265
+ </span>
266
+ </DropdownMenu.Item>
267
+ <DropdownMenu.Item onClick={formatCode} data-testid="toggle-block-format-code">
268
+ <i
269
+ className={`icon code border w-6 h-6 rounded-md bg-no-repeat bg-center bg-[length:18px_18px] ${
270
+ blockType === 'code' ? 'opacity-100 bg-purple-50-900' : 'opacity-60'
271
+ }`}
272
+ />
273
+ <span className={`${blockType === 'code' ? 'font-bold' : 'font-normal'} text-sm px-3 min-w-[150px]`}>
274
+ Code block
275
+ </span>
276
+ </DropdownMenu.Item>
277
+ </>
278
+ }
279
+ >
280
+ <Button
281
+ style={{ backgroundColor: 'transparent', padding: '0 8px' }}
282
+ aria-label="Formatting options for text style"
283
+ data-testid="toggle-block-format"
284
+ >
285
+ <i className={`icon ${blockType} border bg-no-repeat bg-center bg-[length:18px_18px] w-6 h-6`} />
286
+ <Icon.Arrow />
287
+ </Button>
288
+ </DropdownMenu.Root>
289
+ );
290
+ }
291
+
292
+ function Divider(): JSX.Element {
293
+ return <div className="divider" />;
294
+ }
295
+
296
+ export default function ToolbarPlugin({
297
+ actionsMenuPrepend,
298
+ actionsMenuAppend,
299
+ }: {
300
+ actionsMenuPrepend?: CrystallizeRichTextActionMenuItem[];
301
+ actionsMenuAppend?: CrystallizeRichTextActionMenuItem[];
302
+ }): JSX.Element {
303
+ const [editor] = useLexicalComposerContext();
304
+ const [activeEditor, setActiveEditor] = useState(editor);
305
+ const [blockType, setBlockType] = useState<keyof typeof blockTypeToBlockName>('paragraph');
306
+ const [selectedElementKey, setSelectedElementKey] = useState<NodeKey | null>(null);
307
+ const [isLink, setIsLink] = useState(false);
308
+ const [isBold, setIsBold] = useState(false);
309
+ const [isItalic, setIsItalic] = useState(false);
310
+ const [isUnderline, setIsUnderline] = useState(false);
311
+ const [isStrikethrough, setIsStrikethrough] = useState(false);
312
+ const [isSubscript, setIsSubscript] = useState(false);
313
+ const [isSuperscript, setIsSuperscript] = useState(false);
314
+ const [isCode, setIsCode] = useState(false);
315
+ const [canUndo, setCanUndo] = useState(false);
316
+ const [canRedo, setCanRedo] = useState(false);
317
+
318
+ const [codeLanguage, setCodeLanguage] = useState<string>('');
319
+ const [isEditable, setIsEditable] = useState(() => editor.isEditable());
320
+
321
+ const updateToolbar = useCallback(() => {
322
+ const selection = $getSelection();
323
+ if ($isRangeSelection(selection)) {
324
+ const anchorNode = selection.anchor.getNode();
325
+ let element =
326
+ anchorNode.getKey() === 'root'
327
+ ? anchorNode
328
+ : $findMatchingParent(anchorNode, e => {
329
+ const parent = e.getParent();
330
+ return parent !== null && $isRootOrShadowRoot(parent);
331
+ });
332
+
333
+ if (element === null) {
334
+ element = anchorNode.getTopLevelElementOrThrow();
335
+ }
336
+
337
+ const elementKey = element.getKey();
338
+ const elementDOM = activeEditor.getElementByKey(elementKey);
339
+
340
+ // Update text format
341
+ setIsBold(selection.hasFormat('bold'));
342
+ setIsItalic(selection.hasFormat('italic'));
343
+ setIsUnderline(selection.hasFormat('underline'));
344
+ setIsStrikethrough(selection.hasFormat('strikethrough'));
345
+ setIsSubscript(selection.hasFormat('subscript'));
346
+ setIsSuperscript(selection.hasFormat('superscript'));
347
+ setIsCode(selection.hasFormat('code'));
348
+
349
+ // Update links
350
+ const node = getSelectedNode(selection);
351
+ const parent = node.getParent();
352
+ if ($isLinkNode(parent) || $isLinkNode(node)) {
353
+ setIsLink(true);
354
+ } else {
355
+ setIsLink(false);
356
+ }
357
+
358
+ if (elementDOM !== null) {
359
+ setSelectedElementKey(elementKey);
360
+ if ($isListNode(element)) {
361
+ const parentList = $getNearestNodeOfType<ListNode>(anchorNode, ListNode);
362
+ const type = parentList ? parentList.getListType() : element.getListType();
363
+ setBlockType(type);
364
+ } else {
365
+ const type = $isHeadingNode(element) ? element.getTag() : element.getType();
366
+ if (type in blockTypeToBlockName) {
367
+ setBlockType(type as keyof typeof blockTypeToBlockName);
368
+ }
369
+ if ($isCodeNode(element)) {
370
+ const language = element.getLanguage() as keyof typeof CODE_LANGUAGE_MAP;
371
+ setCodeLanguage(language ? CODE_LANGUAGE_MAP[language] || language : '');
372
+ return;
373
+ }
374
+ }
375
+ }
376
+ }
377
+ }, [activeEditor]);
378
+
379
+ useEffect(() => {
380
+ return editor.registerCommand(
381
+ SELECTION_CHANGE_COMMAND,
382
+ (_payload, newEditor) => {
383
+ updateToolbar();
384
+ setActiveEditor(newEditor);
385
+ return false;
386
+ },
387
+ COMMAND_PRIORITY_CRITICAL,
388
+ );
389
+ }, [editor, updateToolbar]);
390
+
391
+ useEffect(() => {
392
+ return mergeRegister(
393
+ editor.registerEditableListener(editable => {
394
+ setIsEditable(editable);
395
+ }),
396
+ activeEditor.registerUpdateListener(({ editorState }) => {
397
+ editorState.read(() => {
398
+ updateToolbar();
399
+ });
400
+ }),
401
+ activeEditor.registerCommand<boolean>(
402
+ CAN_UNDO_COMMAND,
403
+ payload => {
404
+ setCanUndo(payload);
405
+ return false;
406
+ },
407
+ COMMAND_PRIORITY_CRITICAL,
408
+ ),
409
+ activeEditor.registerCommand<boolean>(
410
+ CAN_REDO_COMMAND,
411
+ payload => {
412
+ setCanRedo(payload);
413
+ return false;
414
+ },
415
+ COMMAND_PRIORITY_CRITICAL,
416
+ ),
417
+ );
418
+ }, [activeEditor, editor, updateToolbar]);
419
+
420
+ const clearFormatting = useCallback(() => {
421
+ activeEditor.update(() => {
422
+ const selection = $getSelection();
423
+ if ($isRangeSelection(selection)) {
424
+ $selectAll(selection);
425
+ selection.getNodes().forEach(node => {
426
+ if ($isTextNode(node)) {
427
+ node.setFormat(0);
428
+ node.setStyle('');
429
+ $getNearestBlockElementAncestorOrThrow(node).setFormat('');
430
+ }
431
+ if ($isDecoratorBlockNode(node)) {
432
+ node.setFormat('');
433
+ }
434
+ });
435
+ }
436
+ });
437
+ }, [activeEditor]);
438
+
439
+ const insertLink = useCallback(() => {
440
+ if (!isLink) {
441
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, sanitizeUrl('https://'));
442
+ } else {
443
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, null);
444
+ }
445
+ }, [editor, isLink]);
446
+
447
+ const onCodeLanguageSelect = useCallback(
448
+ (value: string) => {
449
+ activeEditor.update(() => {
450
+ if (selectedElementKey !== null) {
451
+ const node = $getNodeByKey(selectedElementKey);
452
+ if ($isCodeNode(node)) {
453
+ node.setLanguage(value);
454
+ }
455
+ }
456
+ });
457
+ },
458
+ [activeEditor, selectedElementKey],
459
+ );
460
+
461
+ return (
462
+ <div className="toolbar">
463
+ <div className="flex">
464
+ <IconButton
465
+ disabled={!canUndo || !isEditable}
466
+ onClick={() => {
467
+ activeEditor.dispatchCommand(UNDO_COMMAND, undefined);
468
+ }}
469
+ title={IS_APPLE ? 'Undo (⌘Z)' : 'Undo (Ctrl+Z)'}
470
+ type="button"
471
+ aria-label="Undo"
472
+ >
473
+ <i
474
+ className={`format icon undo border w-4 h-6 bg-no-repeat bg-center bg-[length:17px_17px] ${
475
+ canUndo ? 'opacity-100' : 'opacity-30'
476
+ }
477
+ `}
478
+ />
479
+ </IconButton>
480
+ <IconButton
481
+ disabled={!canRedo || !isEditable}
482
+ onClick={() => {
483
+ activeEditor.dispatchCommand(REDO_COMMAND, undefined);
484
+ }}
485
+ title={IS_APPLE ? 'Redo (⌘Y)' : 'Redo (Ctrl+Y)'}
486
+ type="button"
487
+ aria-label="Redo"
488
+ >
489
+ <i
490
+ className={`format icon redo border w-4 h-6 bg-no-repeat bg-center bg-[length:17px_17px] ${
491
+ canRedo ? 'opacity-100' : 'opacity-30'
492
+ }`}
493
+ />
494
+ </IconButton>
495
+ <Divider />
496
+ {blockType in blockTypeToBlockName && activeEditor === editor && (
497
+ <>
498
+ <BlockFormatDropDown disabled={!isEditable} blockType={blockType} editor={editor} />
499
+ <Divider />
500
+ </>
501
+ )}
502
+ {blockType === 'code' ? (
503
+ <>
504
+ <DropdownMenu.Root
505
+ disabled={!isEditable}
506
+ style={{ zIndex: 1 }}
507
+ content={
508
+ <>
509
+ {CODE_LANGUAGE_OPTIONS.map(([value, name]) => {
510
+ return (
511
+ <DropdownMenu.Item
512
+ className={`item ${dropDownActiveClass(value === codeLanguage)}`}
513
+ onClick={() => onCodeLanguageSelect(value)}
514
+ key={value}
515
+ >
516
+ <span
517
+ className={`text min-w-[200px] block text-sm px-3 ${
518
+ dropDownActiveClass(value === codeLanguage)
519
+ ? 'font-bold opacity-100'
520
+ : 'font-normal opacity-80'
521
+ }`}
522
+ >
523
+ {name}
524
+ </span>
525
+ </DropdownMenu.Item>
526
+ );
527
+ })}
528
+ </>
529
+ }
530
+ >
531
+ <Button aria-label="Select language" append={<Icon.Arrow />}>
532
+ <span className="font-medium text-sm">{getLanguageFriendlyName(codeLanguage)}</span>
533
+ </Button>
534
+ </DropdownMenu.Root>
535
+ </>
536
+ ) : (
537
+ <Dialog>
538
+ <div className="flex gap-1">
539
+ <IconButton
540
+ disabled={!isEditable}
541
+ title={IS_APPLE ? 'Bold (⌘B)' : 'Bold (Ctrl+B)'}
542
+ className={`${isBold ? 'opacity-100 !bg-purple-50-900' : 'opacity-60'}`}
543
+ type="button"
544
+ aria-label={`Format text as bold. Shortcut: ${IS_APPLE ? '⌘B' : 'Ctrl+B'}`}
545
+ data-testid="toggle-format-bold"
546
+ onClick={() => {
547
+ activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold');
548
+ }}
549
+ >
550
+ <i className={`format icon bold border w-full h-full bg-no-repeat bg-center bg-[length:18px_18px]`} />
551
+ </IconButton>
552
+ <IconButton
553
+ className={`${isItalic ? 'opacity-100 !bg-purple-50-900' : 'opacity-60'}`}
554
+ disabled={!isEditable}
555
+ onClick={() => {
556
+ activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic');
557
+ }}
558
+ title={IS_APPLE ? 'Italic (⌘I)' : 'Italic (Ctrl+I)'}
559
+ type="button"
560
+ aria-label={`Format text as italics. Shortcut: ${IS_APPLE ? '⌘I' : 'Ctrl+I'}`}
561
+ data-testid="toggle-format-emphasized"
562
+ >
563
+ <i className={`format icon italic border w-full h-full bg-no-repeat bg-center bg-[length:18px_18px]`} />
564
+ </IconButton>
565
+
566
+ <IconButton
567
+ className={`${isUnderline ? 'opacity-100 !bg-purple-50-900' : 'opacity-60'}`}
568
+ disabled={!isEditable}
569
+ onClick={() => {
570
+ activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline');
571
+ }}
572
+ title={IS_APPLE ? 'Underline (⌘U)' : 'Underline (Ctrl+U)'}
573
+ type="button"
574
+ aria-label={`Format text to underlined. Shortcut: ${IS_APPLE ? '⌘U' : 'Ctrl+U'}`}
575
+ data-testid="toggle-format-underlined"
576
+ >
577
+ <i
578
+ className={`format icon underline border w-full h-full bg-no-repeat bg-center bg-[length:18px_18px]`}
579
+ />
580
+ </IconButton>
581
+
582
+ <IconButton
583
+ className={`${isCode ? 'opacity-100 !bg-purple-50-900' : 'opacity-60'}`}
584
+ disabled={!isEditable}
585
+ onClick={() => {
586
+ activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, 'code');
587
+ }}
588
+ title="Insert code block"
589
+ type="button"
590
+ aria-label="Insert code block"
591
+ >
592
+ <i className={`format icon code border w-full h-full bg-no-repeat bg-center bg-[length:18px_18px]`} />
593
+ </IconButton>
594
+
595
+ <IconButton
596
+ className={`${isLink ? 'opacity-100 !bg-purple-50-900' : 'opacity-60'}`}
597
+ disabled={!isEditable}
598
+ onClick={insertLink}
599
+ aria-label="Insert link"
600
+ title="Insert link"
601
+ type="button"
602
+ >
603
+ <i className={`format icon link border w-full h-full bg-no-repeat bg-center bg-[length:18px_18px]`} />
604
+ </IconButton>
605
+
606
+ <DropdownMenu.Root
607
+ disabled={!isEditable}
608
+ style={{ zIndex: 1 }}
609
+ content={
610
+ <>
611
+ <DropdownMenu.Item
612
+ onClick={() => {
613
+ activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, 'strikethrough');
614
+ }}
615
+ title="Strikethrough"
616
+ aria-label="Format text with a strikethrough"
617
+ >
618
+ <i
619
+ className={`icon w-6 h-6 strikethrough border bg-no-repeat bg-center bg-[length:16px_16px] rounded-sm ${
620
+ isStrikethrough ? 'opacity-100 !bg-purple-50-900' : 'opacity-60'
621
+ }`}
622
+ />
623
+ <span className={`px-3 text-sm font-sans ${isStrikethrough ? 'font-medium' : 'font-normal'}`}>
624
+ Strikethrough
625
+ </span>
626
+ </DropdownMenu.Item>
627
+ <DropdownMenu.Item
628
+ onClick={() => {
629
+ activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, 'subscript');
630
+ }}
631
+ title="Subscript"
632
+ aria-label="Format text with a subscript"
633
+ >
634
+ <i
635
+ className={`icon w-6 h-6 subscript border bg-no-repeat bg-center bg-[length:16px_16px] rounded-sm ${
636
+ isSubscript ? 'opacity-100 !bg-purple-50-900' : 'opacity-60'
637
+ }`}
638
+ />
639
+ <span className={`px-3 text-sm font-sans ${isSubscript ? 'font-medium' : 'font-normal'}`}>
640
+ Subscript
641
+ </span>
642
+ </DropdownMenu.Item>
643
+ <DropdownMenu.Item
644
+ onClick={() => {
645
+ activeEditor.dispatchCommand(FORMAT_TEXT_COMMAND, 'superscript');
646
+ }}
647
+ title="Superscript"
648
+ aria-label="Format text with a superscript"
649
+ >
650
+ <i
651
+ className={`icon w-6 h-6 superscript border bg-no-repeat bg-center bg-[length:16px_16px] rounded-sm ${
652
+ isSuperscript ? 'opacity-100 !bg-purple-50-900' : 'opacity-60'
653
+ }`}
654
+ />
655
+ <span className={`px-3 text-sm font-sans ${isSuperscript ? 'bg-purple-50-900' : 'font-normal'}`}>
656
+ Superscript
657
+ </span>
658
+ </DropdownMenu.Item>
659
+ <DropdownMenu.Item
660
+ onClick={clearFormatting}
661
+ className="item"
662
+ title="Clear text formatting"
663
+ aria-label="Clear all text formatting"
664
+ >
665
+ <i className="icon w-6 h-6 clear border bg-no-repeat bg-center bg-[length:16px_16px] opacity-60" />
666
+ <span className="px-3 text-sm text-pink-600-300 font-sans font-normal">Clear Formatting</span>
667
+ </DropdownMenu.Item>
668
+ </>
669
+ }
670
+ >
671
+ <Button
672
+ style={{ backgroundColor: 'transparent', padding: '0 8px' }}
673
+ aria-label="Formatting options for additional text styles"
674
+ >
675
+ <i className={`icon dropdown-more border bg-no-repeat bg-center bg-[length:18px_18px] w-6 h-6`} />
676
+ <Icon.Arrow />
677
+ </Button>
678
+ </DropdownMenu.Root>
679
+ <Divider />
680
+ <DropdownMenu.Root
681
+ style={{ zIndex: 1 }}
682
+ disabled={!isEditable}
683
+ content={
684
+ <>
685
+ <DropdownMenu.Item
686
+ onClick={() => {
687
+ activeEditor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, undefined);
688
+ }}
689
+ >
690
+ <div className="flex items-center font-sans font-normal">
691
+ <i className="icon w-5 h-5 horizontal-rule border bg-no-repeat bg-center bg-[length:16px_16px] opacity-60" />
692
+ <span className="px-3 text-sm">Horizontal rule</span>
693
+ </div>
694
+ </DropdownMenu.Item>
695
+ <DropdownMenu.Item>
696
+ <Dialog.Trigger asChild>
697
+ <div className="flex items-center font-sans font-normal">
698
+ <i className="icon w-5 h-5 table border bg-no-repeat bg-center bg-[length:16px_16px] opacity-60" />
699
+ <span className="px-3 text-sm">Table</span>
700
+ </div>
701
+ </Dialog.Trigger>
702
+ </DropdownMenu.Item>
703
+ </>
704
+ }
705
+ >
706
+ <IconButton>
707
+ <i className="icon plus border w-full h-full bg-no-repeat bg-center bg-[length:20px_20px] " />
708
+ </IconButton>
709
+ </DropdownMenu.Root>
710
+ <Dialog.Content>
711
+ <Dialog.Title>Insert table</Dialog.Title>
712
+ <Dialog.Description>
713
+ Define your starting point of a table, you can add and remove columns and rows after creation.
714
+ </Dialog.Description>
715
+ <div className="items-center justify-between">
716
+ <InsertNewTableDialog activeEditor={activeEditor} />
717
+ </div>
718
+ </Dialog.Content>
719
+ </div>
720
+ </Dialog>
721
+ )}
722
+ </div>
723
+ <ActionsPlugin prepend={actionsMenuPrepend} append={actionsMenuAppend} />
724
+ </div>
725
+ );
726
+ }