@byline/richtext-lexical 1.11.1 → 1.12.0

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 (256) hide show
  1. package/dist/field/apply-value-plugin.js +1 -3
  2. package/dist/field/config/default-extensions.d.ts +32 -0
  3. package/dist/field/config/default-extensions.js +49 -0
  4. package/dist/field/config/default.d.ts +8 -0
  5. package/dist/field/config/default.js +0 -28
  6. package/dist/field/config/editor-config-context.js +2 -6
  7. package/dist/field/config/extensions-list.d.ts +44 -0
  8. package/dist/field/config/extensions-list.js +55 -0
  9. package/dist/field/config/types.d.ts +28 -1
  10. package/dist/field/editor-context.d.ts +1 -1
  11. package/dist/field/editor-context.js +39 -35
  12. package/dist/field/editor.js +11 -57
  13. package/dist/field/{plugins/admonition-plugin/index.d.ts → extensions/admonition/admonition-extension.d.ts} +2 -1
  14. package/dist/field/{plugins/admonition-plugin/index.js → extensions/admonition/admonition-extension.js} +51 -4
  15. package/dist/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.d.ts +1 -1
  16. package/dist/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.js +1 -1
  17. package/dist/field/{nodes/admonition-node → extensions/admonition}/admonition-node.d.ts +1 -1
  18. package/dist/field/{plugins/admonition-plugin → extensions/admonition}/fields.d.ts +1 -1
  19. package/dist/field/{nodes/admonition-node → extensions/admonition}/index.js +1 -1
  20. package/dist/field/{plugins/admonition-plugin → extensions/admonition}/types.d.ts +1 -1
  21. package/dist/field/{plugins/auto-embed-plugin/index.d.ts → extensions/auto-embed/auto-embed-extension.d.ts} +1 -0
  22. package/dist/field/{plugins/auto-embed-plugin/index.js → extensions/auto-embed/auto-embed-extension.js} +47 -4
  23. package/dist/field/{plugins/auto-embed-plugin → extensions/auto-embed}/auto-embed-modal.d.ts +1 -1
  24. package/dist/field/extensions/byline-floating-ui/byline-floating-ui-extension.d.ts +68 -0
  25. package/dist/field/extensions/byline-floating-ui/byline-floating-ui-extension.js +19 -0
  26. package/dist/field/{nodes/admonition-node → extensions/byline-floating-ui}/index.d.ts +1 -2
  27. package/dist/field/extensions/byline-floating-ui/index.js +1 -0
  28. package/dist/field/extensions/byline-toolbar/byline-toolbar-extension.d.ts +69 -0
  29. package/dist/field/extensions/byline-toolbar/byline-toolbar-extension.js +19 -0
  30. package/dist/field/{nodes/inline-image-node → extensions/byline-toolbar}/index.d.ts +1 -2
  31. package/dist/field/extensions/byline-toolbar/index.js +1 -0
  32. package/dist/field/extensions/code-highlight/code-highlight-extension.d.ts +10 -0
  33. package/dist/field/extensions/code-highlight/code-highlight-extension.js +11 -0
  34. package/dist/field/extensions/floating-text-format/floating-text-format-extension.d.ts +18 -0
  35. package/dist/field/extensions/floating-text-format/floating-text-format-extension.js +17 -0
  36. package/dist/field/{plugins/floating-text-format-toolbar-plugin → extensions/floating-text-format}/index.js +1 -1
  37. package/dist/field/extensions/horizontal-rule/horizontal-rule-extension.d.ts +6 -0
  38. package/dist/field/extensions/horizontal-rule/horizontal-rule-extension.js +45 -0
  39. package/dist/field/{nodes/inline-image-node → extensions/inline-image}/index.js +1 -1
  40. package/dist/field/{plugins/inline-image-plugin/index.d.ts → extensions/inline-image/inline-image-extension.d.ts} +6 -3
  41. package/dist/field/{plugins/inline-image-plugin/index.js → extensions/inline-image/inline-image-extension.js} +57 -5
  42. package/dist/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node-component.d.ts +2 -2
  43. package/dist/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node-component.js +4 -4
  44. package/dist/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node.d.ts +2 -2
  45. package/dist/field/{nodes/inline-image-node/types.d.ts → extensions/inline-image/node-types.d.ts} +1 -1
  46. package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/types.d.ts +1 -1
  47. package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/utils.d.ts +1 -1
  48. package/dist/field/{plugins/layout-plugin/layout-plugin.d.ts → extensions/layout/layout-extension.d.ts} +1 -0
  49. package/dist/field/{plugins/layout-plugin/layout-plugin.js → extensions/layout/layout-extension.js} +53 -5
  50. package/dist/field/extensions/link/auto-link-extension.d.ts +12 -0
  51. package/dist/field/{plugins/link-plugin/auto-link/index.js → extensions/link/auto-link-extension.js} +14 -2
  52. package/dist/field/{plugins/link-plugin/auto-link → extensions/link}/auto-link-plugin.d.ts +1 -1
  53. package/dist/field/{plugins/link-plugin/auto-link → extensions/link}/auto-link-plugin.js +2 -2
  54. package/dist/field/{plugins/link-plugin → extensions}/link/floating-link-editor.css +2 -2
  55. package/dist/field/{plugins/link-plugin → extensions}/link/floating-link-editor.js +4 -4
  56. package/dist/field/extensions/link/index.d.ts +5 -0
  57. package/dist/field/extensions/link/index.js +5 -0
  58. package/dist/field/extensions/link/link-extension.d.ts +14 -0
  59. package/dist/field/extensions/link/link-extension.js +66 -0
  60. package/dist/field/{plugins/link-plugin/link/types.d.ts → extensions/link/link-modal-types.d.ts} +1 -1
  61. package/dist/field/{plugins/link-plugin → extensions}/link/link-modal.d.ts +1 -1
  62. package/dist/field/{plugins/link-plugin → extensions}/link/link-modal.js +3 -3
  63. package/dist/field/{nodes/link-nodes → extensions/link}/types.d.ts +1 -1
  64. package/dist/field/extensions/table/table-action-menu-plugin/index.d.ts +4 -0
  65. package/dist/field/{plugins → extensions/table}/table-action-menu-plugin/index.js +8 -6
  66. package/dist/field/extensions/table/table-extension.d.ts +17 -0
  67. package/dist/field/extensions/table/table-extension.js +58 -0
  68. package/dist/field/extensions/vimeo/vimeo-extension.d.ts +12 -0
  69. package/dist/field/extensions/vimeo/vimeo-extension.js +16 -0
  70. package/dist/field/extensions/youtube/youtube-extension.d.ts +12 -0
  71. package/dist/field/extensions/youtube/youtube-extension.js +16 -0
  72. package/dist/field/nodes/index.js +7 -7
  73. package/dist/field/plugins/table-plugin/index.js +5 -6
  74. package/dist/field/plugins/toolbar-plugin/index.js +40 -114
  75. package/dist/field/plugins/toolbar-plugin/toolbar-active-editor.d.ts +25 -0
  76. package/dist/field/plugins/toolbar-plugin/toolbar-active-editor.js +17 -0
  77. package/dist/field/themes/lexical-editor-theme.css +13 -3
  78. package/dist/field/themes/lexical-editor-theme.js +1 -0
  79. package/dist/index.d.ts +17 -1
  80. package/dist/index.js +16 -0
  81. package/dist/lexical-editor.d.ts +25 -13
  82. package/dist/lexical-editor.js +9 -1
  83. package/dist/richtext-field.js +6 -1
  84. package/dist/server.d.ts +2 -2
  85. package/dist/server.js +2 -2
  86. package/package.json +7 -10
  87. package/src/field/apply-value-plugin.tsx +6 -6
  88. package/src/field/config/default-extensions.ts +104 -0
  89. package/src/field/config/default.ts +8 -28
  90. package/src/field/config/editor-config-context.tsx +1 -7
  91. package/src/field/config/extensions-list.ts +107 -0
  92. package/src/field/config/types.ts +28 -28
  93. package/src/field/editor-context.tsx +77 -41
  94. package/src/field/editor.tsx +24 -72
  95. package/src/field/extensions/README.md +31 -0
  96. package/src/field/{plugins/admonition-plugin/index.tsx → extensions/admonition/admonition-extension.tsx} +45 -2
  97. package/src/field/{plugins/admonition-plugin → extensions/admonition}/admonition-modal.tsx +1 -1
  98. package/src/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.tsx +5 -5
  99. package/src/field/{nodes/admonition-node → extensions/admonition}/admonition-node.tsx +1 -1
  100. package/src/field/{plugins/admonition-plugin → extensions/admonition}/fields.ts +1 -1
  101. package/src/field/{nodes/admonition-node → extensions/admonition}/index.ts +5 -1
  102. package/src/field/{plugins/admonition-plugin → extensions/admonition}/types.ts +1 -1
  103. package/src/field/{plugins/auto-embed-plugin/index.tsx → extensions/auto-embed/auto-embed-extension.tsx} +46 -3
  104. package/src/field/{plugins/auto-embed-plugin → extensions/auto-embed}/auto-embed-modal.tsx +1 -1
  105. package/src/field/extensions/byline-floating-ui/byline-floating-ui-extension.ts +90 -0
  106. package/src/field/extensions/byline-floating-ui/index.ts +15 -0
  107. package/src/field/extensions/byline-toolbar/byline-toolbar-extension.ts +95 -0
  108. package/src/field/extensions/byline-toolbar/index.ts +15 -0
  109. package/src/field/extensions/code-highlight/code-highlight-extension.ts +18 -0
  110. package/src/field/extensions/floating-text-format/floating-text-format-extension.ts +39 -0
  111. package/src/field/{plugins/floating-text-format-toolbar-plugin → extensions/floating-text-format}/index.tsx +1 -1
  112. package/src/field/extensions/horizontal-rule/horizontal-rule-extension.tsx +57 -0
  113. package/src/field/{nodes/inline-image-node → extensions/inline-image}/index.ts +1 -1
  114. package/src/field/{plugins/inline-image-plugin/index.tsx → extensions/inline-image/inline-image-extension.tsx} +54 -6
  115. package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.tsx +1 -1
  116. package/src/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node-component.tsx +6 -6
  117. package/src/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node.tsx +2 -2
  118. package/src/field/{nodes/inline-image-node/types.ts → extensions/inline-image/node-types.ts} +1 -1
  119. package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/types.ts +1 -1
  120. package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/utils.ts +1 -1
  121. package/src/field/{plugins/layout-plugin/layout-plugin.tsx → extensions/layout/layout-extension.tsx} +47 -8
  122. package/src/field/{plugins/link-plugin/auto-link/index.tsx → extensions/link/auto-link-extension.tsx} +13 -3
  123. package/src/field/{plugins/link-plugin/auto-link → extensions/link}/auto-link-plugin.tsx +2 -2
  124. package/src/field/{plugins/link-plugin → extensions}/link/floating-link-editor.css +2 -2
  125. package/src/field/{plugins/link-plugin → extensions}/link/floating-link-editor.tsx +5 -5
  126. package/src/field/extensions/link/index.ts +5 -0
  127. package/src/field/extensions/link/link-extension.tsx +131 -0
  128. package/src/field/{plugins/link-plugin/link/types.ts → extensions/link/link-modal-types.ts} +1 -1
  129. package/src/field/{plugins/link-plugin → extensions}/link/link-modal.tsx +6 -6
  130. package/src/field/{nodes/link-nodes → extensions/link}/types.ts +1 -1
  131. package/src/field/{plugins → extensions/table}/table-action-menu-plugin/index.tsx +12 -8
  132. package/src/field/extensions/table/table-extension.tsx +86 -0
  133. package/src/field/extensions/vimeo/vimeo-extension.ts +36 -0
  134. package/src/field/extensions/youtube/youtube-extension.ts +37 -0
  135. package/src/field/nodes/index.ts +7 -7
  136. package/src/field/plugins/table-plugin/index.tsx +10 -10
  137. package/src/field/plugins/toolbar-plugin/index.tsx +59 -122
  138. package/src/field/plugins/toolbar-plugin/toolbar-active-editor.tsx +48 -0
  139. package/src/field/themes/lexical-editor-theme.css +18 -3
  140. package/src/field/themes/lexical-editor-theme.tsx +1 -0
  141. package/src/index.ts +45 -2
  142. package/src/lexical-editor.tsx +35 -14
  143. package/src/richtext-field.tsx +8 -1
  144. package/src/server.ts +4 -4
  145. package/dist/field/nodes/link-nodes/index.d.ts +0 -3
  146. package/dist/field/nodes/link-nodes/index.js +0 -3
  147. package/dist/field/plugins/code-highlight-plugin/index.d.ts +0 -9
  148. package/dist/field/plugins/code-highlight-plugin/index.js +0 -11
  149. package/dist/field/plugins/link-plugin/auto-link/index.d.ts +0 -9
  150. package/dist/field/plugins/link-plugin/link/index.d.ts +0 -1
  151. package/dist/field/plugins/link-plugin/link/index.js +0 -43
  152. package/dist/field/plugins/table-action-menu-plugin/index.d.ts +0 -5
  153. package/dist/field/plugins/vimeo-plugin/index.d.ts +0 -3
  154. package/dist/field/plugins/vimeo-plugin/index.js +0 -24
  155. package/dist/field/plugins/youtube-plugin/index.d.ts +0 -3
  156. package/dist/field/plugins/youtube-plugin/index.js +0 -24
  157. package/dist/field/toolbar-extensions.d.ts +0 -31
  158. package/dist/field/toolbar-extensions.js +0 -56
  159. package/src/field/nodes/link-nodes/index.ts +0 -3
  160. package/src/field/plugins/code-highlight-plugin/index.ts +0 -23
  161. package/src/field/plugins/link-plugin/link/index.tsx +0 -99
  162. package/src/field/plugins/vimeo-plugin/index.ts +0 -42
  163. package/src/field/plugins/youtube-plugin/index.ts +0 -43
  164. package/src/field/themes/lexical-editor-theme.js +0 -104
  165. package/src/field/toolbar-extensions.tsx +0 -93
  166. /package/dist/field/{plugins/admonition-plugin → extensions/admonition}/admonition-modal.css +0 -0
  167. /package/dist/field/{plugins/admonition-plugin → extensions/admonition}/admonition-modal.d.ts +0 -0
  168. /package/dist/field/{plugins/admonition-plugin → extensions/admonition}/admonition-modal.js +0 -0
  169. /package/dist/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.css +0 -0
  170. /package/dist/field/{nodes/admonition-node → extensions/admonition}/admonition-node.js +0 -0
  171. /package/dist/field/{plugins/admonition-plugin → extensions/admonition}/fields.js +0 -0
  172. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.css +0 -0
  173. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.d.ts +0 -0
  174. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.js +0 -0
  175. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/index.d.ts +0 -0
  176. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/index.js +0 -0
  177. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.css +0 -0
  178. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.d.ts +0 -0
  179. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.js +0 -0
  180. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.css +0 -0
  181. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.d.ts +0 -0
  182. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.js +0 -0
  183. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.css +0 -0
  184. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.d.ts +0 -0
  185. /package/dist/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.js +0 -0
  186. /package/dist/field/{nodes/admonition-node/types.d.ts → extensions/admonition/node-types.d.ts} +0 -0
  187. /package/dist/field/{nodes/admonition-node/types.js → extensions/admonition/node-types.js} +0 -0
  188. /package/dist/field/{nodes/inline-image-node → extensions/admonition}/types.js +0 -0
  189. /package/dist/field/{plugins/auto-embed-plugin → extensions/auto-embed}/auto-embed-modal.css +0 -0
  190. /package/dist/field/{plugins/auto-embed-plugin → extensions/auto-embed}/auto-embed-modal.js +0 -0
  191. /package/dist/field/{plugins/floating-text-format-toolbar-plugin → extensions/floating-text-format}/index.css +0 -0
  192. /package/dist/field/{plugins/floating-text-format-toolbar-plugin → extensions/floating-text-format}/index.d.ts +0 -0
  193. /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/fields.d.ts +0 -0
  194. /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/fields.js +0 -0
  195. /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.css +0 -0
  196. /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.d.ts +0 -0
  197. /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.js +0 -0
  198. /package/dist/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node-component.css +0 -0
  199. /package/dist/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node.js +0 -0
  200. /package/dist/field/{nodes/link-nodes/types.js → extensions/inline-image/node-types.js} +0 -0
  201. /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/populate.d.ts +0 -0
  202. /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/populate.js +0 -0
  203. /package/dist/field/{plugins/admonition-plugin → extensions/inline-image}/types.js +0 -0
  204. /package/dist/field/{plugins/inline-image-plugin → extensions/inline-image}/utils.js +0 -0
  205. /package/dist/field/{plugins/layout-plugin → extensions/layout}/insert-layout-modal.css +0 -0
  206. /package/dist/field/{plugins/layout-plugin → extensions/layout}/insert-layout-modal.d.ts +0 -0
  207. /package/dist/field/{plugins/layout-plugin → extensions/layout}/insert-layout-modal.js +0 -0
  208. /package/dist/field/{nodes/layout-container-node → extensions/layout}/layout-container-node.d.ts +0 -0
  209. /package/dist/field/{nodes/layout-container-node → extensions/layout}/layout-container-node.js +0 -0
  210. /package/dist/field/{nodes/layout-container-node → extensions/layout}/layout-item-node.d.ts +0 -0
  211. /package/dist/field/{nodes/layout-container-node → extensions/layout}/layout-item-node.js +0 -0
  212. /package/dist/field/{nodes/link-nodes → extensions/link}/auto-link-node.d.ts +0 -0
  213. /package/dist/field/{nodes/link-nodes → extensions/link}/auto-link-node.js +0 -0
  214. /package/dist/field/{plugins/link-plugin → extensions}/link/floating-link-editor.d.ts +0 -0
  215. /package/dist/field/{plugins/inline-image-plugin/types.js → extensions/link/link-modal-types.js} +0 -0
  216. /package/dist/field/{nodes/link-nodes → extensions/link}/link-node.d.ts +0 -0
  217. /package/dist/field/{nodes/link-nodes → extensions/link}/link-node.js +0 -0
  218. /package/dist/field/{plugins/link-plugin → extensions/link}/populate.d.ts +0 -0
  219. /package/dist/field/{plugins/link-plugin → extensions/link}/populate.js +0 -0
  220. /package/dist/field/{plugins/link-plugin → extensions}/link/types.js +0 -0
  221. /package/dist/field/{nodes/vimeo-node/index.d.ts → extensions/vimeo/vimeo-node.d.ts} +0 -0
  222. /package/dist/field/{nodes/vimeo-node/index.js → extensions/vimeo/vimeo-node.js} +0 -0
  223. /package/dist/field/{nodes/youtube-node/index.d.ts → extensions/youtube/youtube-node.d.ts} +0 -0
  224. /package/dist/field/{nodes/youtube-node/index.js → extensions/youtube/youtube-node.js} +0 -0
  225. /package/src/field/{plugins/admonition-plugin → extensions/admonition}/admonition-modal.css +0 -0
  226. /package/src/field/{nodes/admonition-node → extensions/admonition}/admonition-node-component.css +0 -0
  227. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.css +0 -0
  228. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.js +0 -0
  229. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/danger-icon.tsx +0 -0
  230. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/index.js +0 -0
  231. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/index.ts +0 -0
  232. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.css +0 -0
  233. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.js +0 -0
  234. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/note-icon.tsx +0 -0
  235. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.css +0 -0
  236. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.js +0 -0
  237. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/tip-icon.tsx +0 -0
  238. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.css +0 -0
  239. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.js +0 -0
  240. /package/src/field/{nodes/admonition-node → extensions/admonition}/icons/warning-icon.tsx +0 -0
  241. /package/src/field/{nodes/admonition-node/types.ts → extensions/admonition/node-types.ts} +0 -0
  242. /package/src/field/{plugins/auto-embed-plugin → extensions/auto-embed}/auto-embed-modal.css +0 -0
  243. /package/src/field/{plugins/floating-text-format-toolbar-plugin → extensions/floating-text-format}/index.css +0 -0
  244. /package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/fields.ts +0 -0
  245. /package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/inline-image-modal.css +0 -0
  246. /package/src/field/{nodes/inline-image-node → extensions/inline-image}/inline-image-node-component.css +0 -0
  247. /package/src/field/{plugins/inline-image-plugin → extensions/inline-image}/populate.ts +0 -0
  248. /package/src/field/{plugins/layout-plugin → extensions/layout}/insert-layout-modal.css +0 -0
  249. /package/src/field/{plugins/layout-plugin → extensions/layout}/insert-layout-modal.tsx +0 -0
  250. /package/src/field/{nodes/layout-container-node → extensions/layout}/layout-container-node.ts +0 -0
  251. /package/src/field/{nodes/layout-container-node → extensions/layout}/layout-item-node.ts +0 -0
  252. /package/src/field/{nodes/link-nodes → extensions/link}/auto-link-node.ts +0 -0
  253. /package/src/field/{nodes/link-nodes → extensions/link}/link-node.ts +0 -0
  254. /package/src/field/{plugins/link-plugin → extensions/link}/populate.ts +0 -0
  255. /package/src/field/{nodes/vimeo-node/index.tsx → extensions/vimeo/vimeo-node.tsx} +0 -0
  256. /package/src/field/{nodes/youtube-node/index.tsx → extensions/youtube/youtube-node.tsx} +0 -0
@@ -14,6 +14,8 @@ import type * as React from 'react'
14
14
  import { useCallback, useEffect, useState } from 'react'
15
15
 
16
16
  import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
17
+ import { ReactExtension } from '@lexical/react/ReactExtension'
18
+ import { useExtensionDependency } from '@lexical/react/useExtensionComponent'
17
19
  import { $wrapNodeInElement, mergeRegister } from '@lexical/utils'
18
20
  import {
19
21
  $createParagraphNode,
@@ -22,19 +24,25 @@ import {
22
24
  $isRootOrShadowRoot,
23
25
  COMMAND_PRIORITY_EDITOR,
24
26
  COMMAND_PRIORITY_NORMAL,
27
+ configExtension,
25
28
  createCommand,
29
+ declarePeerDependency,
30
+ defineExtension,
26
31
  type LexicalCommand,
27
32
  type LexicalEditor,
28
33
  type NodeKey,
34
+ safeCast,
29
35
  } from 'lexical'
30
36
 
37
+ import { useToolbarActiveEditor } from '../../plugins/toolbar-plugin/toolbar-active-editor'
38
+ import { DropDownItem } from '../../ui/dropdown'
31
39
  import {
32
- $createInlineImageNode,
33
- $isInlineImageNode,
34
- InlineImageNode,
35
- } from '../../nodes/inline-image-node'
40
+ type BylineToolbarConfig,
41
+ BylineToolbarExtension,
42
+ } from '../byline-toolbar/byline-toolbar-extension'
36
43
  import { InlineImageModal } from './inline-image-modal'
37
- import type { InlineImageAttributes } from '../../nodes/inline-image-node/types'
44
+ import { $createInlineImageNode, $isInlineImageNode, InlineImageNode } from './inline-image-node'
45
+ import type { InlineImageAttributes } from './node-types'
38
46
  import type { InlineImageData } from './types'
39
47
 
40
48
  export type InsertInlineImagePayload = Readonly<InlineImageAttributes>
@@ -102,8 +110,9 @@ function readNodeAsInitialData(
102
110
  return data
103
111
  }
104
112
 
105
- export function InlineImagePlugin({ collection }: { collection: string }): React.JSX.Element {
113
+ export function InlineImagePlugin(): React.JSX.Element {
106
114
  const [editor] = useLexicalComposerContext()
115
+ const { collection } = useExtensionDependency(InlineImageExtension).config
107
116
  const [modalState, setModalState] = useState<ModalState>(CLOSED_STATE)
108
117
 
109
118
  useEffect(() => {
@@ -200,3 +209,42 @@ export function InlineImagePlugin({ collection }: { collection: string }): React
200
209
  />
201
210
  )
202
211
  }
212
+
213
+ export interface InlineImageConfig {
214
+ /** Upload collection that the inline-image modal targets. Required. */
215
+ collection: string
216
+ }
217
+
218
+ function InlineImageInsertItem(): React.JSX.Element {
219
+ const editor = useToolbarActiveEditor()
220
+ return (
221
+ <DropDownItem
222
+ onClick={() => {
223
+ editor.dispatchCommand(OPEN_INLINE_IMAGE_MODAL_COMMAND, null)
224
+ }}
225
+ className="item"
226
+ >
227
+ <i className="icon image" />
228
+ <span className="text">Inline Image</span>
229
+ </DropDownItem>
230
+ )
231
+ }
232
+
233
+ export const InlineImageExtension = defineExtension({
234
+ name: '@byline/richtext-lexical/InlineImage',
235
+ nodes: () => [InlineImageNode],
236
+ config: safeCast<InlineImageConfig>({ collection: '' }),
237
+ dependencies: [configExtension(ReactExtension, { decorators: [<InlineImagePlugin key="d" />] })],
238
+ peerDependencies: [
239
+ declarePeerDependency<typeof BylineToolbarExtension>(BylineToolbarExtension.name, {
240
+ items: [
241
+ {
242
+ id: '@byline/richtext-lexical/InlineImage/insert',
243
+ placement: 'insert-menu',
244
+ order: 40,
245
+ node: <InlineImageInsertItem />,
246
+ },
247
+ ],
248
+ } satisfies Partial<BylineToolbarConfig>),
249
+ ],
250
+ })
@@ -32,7 +32,7 @@ import { useModalFormState } from '../../shared/useModalFormState'
32
32
  import { isAltTextValid, positionOptions } from './fields'
33
33
  import { deriveImageSizes, getPreferredSize } from './utils'
34
34
  import type { DocumentRelation } from '../../nodes/document-relation'
35
- import type { Position } from '../../nodes/inline-image-node/types'
35
+ import type { Position } from './node-types'
36
36
  import type { InlineImageData, InlineImageModalProps } from './types'
37
37
 
38
38
  interface FormState {
@@ -39,14 +39,14 @@ import {
39
39
  import ContentEditableInline from '../../content-editable-inline'
40
40
  import { useSharedHistoryContext } from '../../context/shared-history-context'
41
41
  import { useSharedOnChange } from '../../context/shared-on-change-context'
42
- import { FloatingTextFormatToolbarPlugin } from '../../plugins/floating-text-format-toolbar-plugin/index'
43
- import { OPEN_INLINE_IMAGE_MODAL_COMMAND } from '../../plugins/inline-image-plugin'
44
- import { LinkPlugin } from '../../plugins/link-plugin/link'
45
- import { FloatingLinkEditorPlugin } from '../../plugins/link-plugin/link/floating-link-editor'
46
42
  import PlaceholderInline from '../../ui/placeholder-inline'
43
+ import { FloatingTextFormatToolbarPlugin } from '../floating-text-format'
44
+ import { FloatingLinkEditorPlugin } from '../link/floating-link-editor'
45
+ import { LinkPlugin } from '../link/link-extension'
46
+ import { OPEN_INLINE_IMAGE_MODAL_COMMAND } from './inline-image-extension'
47
47
  import { $isInlineImageNode } from './inline-image-node'
48
- import type { DocumentRelation } from '../document-relation'
49
- import type { Position } from './types'
48
+ import type { DocumentRelation } from '../../nodes/document-relation'
49
+ import type { Position } from './node-types'
50
50
 
51
51
  import './inline-image-node-component.css'
52
52
 
@@ -22,8 +22,8 @@ import type {
22
22
  } from 'lexical'
23
23
  import { $applyNodeReplacement, createEditor, DecoratorNode } from 'lexical'
24
24
 
25
- import type { DocumentRelation } from '../document-relation'
26
- import type { InlineImageAttributes, Position, SerializedInlineImageNode } from './types'
25
+ import type { DocumentRelation } from '../../nodes/document-relation'
26
+ import type { InlineImageAttributes, Position, SerializedInlineImageNode } from './node-types'
27
27
 
28
28
  const InlineImageComponent = React.lazy(async () => await import('./inline-image-node-component'))
29
29
 
@@ -14,7 +14,7 @@ import type {
14
14
  Spread,
15
15
  } from 'lexical'
16
16
 
17
- import type { DocumentRelation } from '../document-relation'
17
+ import type { DocumentRelation } from '../../nodes/document-relation'
18
18
 
19
19
  export type Position = 'left' | 'right' | 'full' | 'wide' | 'default' | undefined
20
20
 
@@ -7,7 +7,7 @@
7
7
  */
8
8
 
9
9
  import type { DocumentRelation } from '../../nodes/document-relation'
10
- import type { Position } from '../../nodes/inline-image-node/types'
10
+ import type { Position } from './node-types'
11
11
 
12
12
  /**
13
13
  * The form-shape carried into / out of the inline image modal. Mirrors
@@ -8,7 +8,7 @@
8
8
 
9
9
  import type { StoredFileValue } from '@byline/core'
10
10
 
11
- import type { Position } from '../../nodes/inline-image-node/types'
11
+ import type { Position } from './node-types'
12
12
 
13
13
  /**
14
14
  * Maps an editor `position` choice to a media-collection variant name.
@@ -3,6 +3,7 @@
3
3
  import * as React from 'react'
4
4
  import { useEffect } from 'react'
5
5
 
6
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
6
7
  /**
7
8
  * Copyright (c) Meta Platforms, Inc. and affiliates.
8
9
  *
@@ -10,7 +11,7 @@ import { useEffect } from 'react'
10
11
  * LICENSE file in the root directory of this source tree.
11
12
  *
12
13
  */
13
- import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
14
+ import { ReactExtension } from '@lexical/react/ReactExtension'
14
15
  import { $insertNodeToNearestRoot, mergeRegister } from '@lexical/utils'
15
16
  import type { ElementNode, LexicalCommand, LexicalNode, NodeKey } from 'lexical'
16
17
  import {
@@ -18,20 +19,25 @@ import {
18
19
  $getNodeByKey,
19
20
  COMMAND_PRIORITY_EDITOR,
20
21
  COMMAND_PRIORITY_NORMAL,
22
+ configExtension,
21
23
  createCommand,
24
+ declarePeerDependency,
25
+ defineExtension,
22
26
  } from 'lexical'
23
27
 
28
+ import { useToolbarActiveEditor } from '../../plugins/toolbar-plugin/toolbar-active-editor'
29
+ import { DropDownItem } from '../../ui/dropdown'
30
+ import {
31
+ type BylineToolbarConfig,
32
+ BylineToolbarExtension,
33
+ } from '../byline-toolbar/byline-toolbar-extension'
34
+ import { InsertLayoutModal } from './insert-layout-modal'
24
35
  import {
25
36
  $createLayoutContainerNode,
26
37
  $isLayoutContainerNode,
27
38
  LayoutContainerNode,
28
- } from '../../nodes/layout-container-node/layout-container-node'
29
- import {
30
- $createLayoutItemNode,
31
- $isLayoutItemNode,
32
- LayoutItemNode,
33
- } from '../../nodes/layout-container-node/layout-item-node'
34
- import { InsertLayoutModal } from './insert-layout-modal'
39
+ } from './layout-container-node'
40
+ import { $createLayoutItemNode, $isLayoutItemNode, LayoutItemNode } from './layout-item-node'
35
41
 
36
42
  export const OPEN_INSERT_LAYOUT_MODAL_COMMAND = createCommand('OPEN_INSERT_LAYOUT_MODAL_COMMAND')
37
43
 
@@ -160,3 +166,36 @@ export function LayoutPlugin(): React.JSX.Element {
160
166
  function getItemsCountFromTemplate(template: string): number {
161
167
  return template.trim().split(/\s+/).length
162
168
  }
169
+
170
+ function LayoutInsertItem(): React.JSX.Element {
171
+ const editor = useToolbarActiveEditor()
172
+ return (
173
+ <DropDownItem
174
+ onClick={() => {
175
+ editor.dispatchCommand(OPEN_INSERT_LAYOUT_MODAL_COMMAND, null)
176
+ }}
177
+ className="item"
178
+ >
179
+ <i className="icon columns" />
180
+ <span className="text">Columns Layout</span>
181
+ </DropDownItem>
182
+ )
183
+ }
184
+
185
+ export const LayoutExtension = defineExtension({
186
+ name: '@byline/richtext-lexical/Layout',
187
+ nodes: () => [LayoutContainerNode, LayoutItemNode],
188
+ dependencies: [configExtension(ReactExtension, { decorators: [<LayoutPlugin key="d" />] })],
189
+ peerDependencies: [
190
+ declarePeerDependency<typeof BylineToolbarExtension>(BylineToolbarExtension.name, {
191
+ items: [
192
+ {
193
+ id: '@byline/richtext-lexical/Layout/insert',
194
+ placement: 'insert-menu',
195
+ order: 20,
196
+ node: <LayoutInsertItem />,
197
+ },
198
+ ],
199
+ } satisfies Partial<BylineToolbarConfig>),
200
+ ],
201
+ })
@@ -1,15 +1,20 @@
1
1
  'use client'
2
2
 
3
3
  /**
4
- * Copyright (c) Meta Platforms, Inc. and affiliates.
4
+ * This Source Code is subject to the terms of the Mozilla Public
5
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
7
  *
6
- * This source code is licensed under the MIT license found in the
7
- * LICENSE file in the root directory of this source tree.
8
+ * Copyright (c) Infonomic Company Limited
8
9
  *
10
+ * Portions Copyright (c) Meta Platforms, Inc. and affiliates.
9
11
  */
10
12
 
11
13
  import type * as React from 'react'
12
14
 
15
+ import { ReactExtension } from '@lexical/react/ReactExtension'
16
+ import { configExtension, defineExtension } from 'lexical'
17
+
13
18
  import {
14
19
  createLinkMatcherWithRegExp,
15
20
  AutoLinkPlugin as LexicalAutoLinkPlugin,
@@ -33,3 +38,8 @@ const MATCHERS = [
33
38
  export function AutoLinkPlugin(): React.JSX.Element {
34
39
  return <LexicalAutoLinkPlugin matchers={MATCHERS} />
35
40
  }
41
+
42
+ export const AutoLinkExtension = defineExtension({
43
+ name: '@byline/richtext-lexical/AutoLink',
44
+ dependencies: [configExtension(ReactExtension, { decorators: [<AutoLinkPlugin key="d" />] })],
45
+ })
@@ -15,6 +15,7 @@ import { mergeRegister } from '@lexical/utils'
15
15
  import type { ElementNode, LexicalEditor, LexicalNode } from 'lexical'
16
16
  import { $createTextNode, $isElementNode, $isLineBreakNode, $isTextNode, TextNode } from 'lexical'
17
17
 
18
+ import invariant from '../../shared/invariant'
18
19
  import {
19
20
  $createAutoLinkNode,
20
21
  $isAutoLinkNode,
@@ -22,8 +23,7 @@ import {
22
23
  AutoLinkNode,
23
24
  type CustomLinkAttributes,
24
25
  type LinkAttributes,
25
- } from '../../../nodes/link-nodes'
26
- import invariant from '../../../shared/invariant'
26
+ } from '.'
27
27
 
28
28
  type ChangeHandler = (url: string | null, prevUrl: string | null) => void
29
29
 
@@ -67,7 +67,7 @@
67
67
  }
68
68
 
69
69
  .link-editor div.link-edit {
70
- background-image: url(../../../images/icons/pencil-fill.svg);
70
+ background-image: url(../../images/icons/pencil-fill.svg);
71
71
  background-size: 16px;
72
72
  background-position: center;
73
73
  background-repeat: no-repeat;
@@ -81,7 +81,7 @@
81
81
  }
82
82
 
83
83
  .link-editor div.link-trash {
84
- background-image: url(../../../images/icons/trash.svg);
84
+ background-image: url(../../images/icons/trash.svg);
85
85
  background-size: 16px;
86
86
  background-position: center;
87
87
  background-repeat: no-repeat;
@@ -29,18 +29,18 @@ import {
29
29
  } from 'lexical'
30
30
  import { createPortal } from 'react-dom'
31
31
 
32
+ import { getSelectedNode } from '../../utils/getSelectedNode'
33
+ import { setFloatingElemPositionForLinkEditor } from '../../utils/setFloatingElemPositionForLinkEditor'
34
+ import { sanitizeUrl } from '../../utils/url'
32
35
  import {
33
36
  $isAutoLinkNode,
34
37
  $isLinkNode,
35
38
  type LinkAttributes,
36
39
  OPEN_LINK_MODAL_COMMAND,
37
40
  TOGGLE_LINK_COMMAND,
38
- } from '../../../nodes/link-nodes'
39
- import { getSelectedNode } from '../../../utils/getSelectedNode'
40
- import { setFloatingElemPositionForLinkEditor } from '../../../utils/setFloatingElemPositionForLinkEditor'
41
- import { sanitizeUrl } from '../../../utils/url'
41
+ } from '.'
42
42
  import { LinkModal } from './link-modal'
43
- import type { LinkData } from './types'
43
+ import type { LinkData } from './link-modal-types'
44
44
 
45
45
  import './floating-link-editor.css'
46
46
 
@@ -0,0 +1,5 @@
1
+ export { AutoLinkExtension } from './auto-link-extension'
2
+ export * from './auto-link-node'
3
+ export { LinkExtension, registerLink } from './link-extension'
4
+ export * from './link-node'
5
+ export * from './types'
@@ -0,0 +1,131 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * This Source Code is subject to the terms of the Mozilla Public
5
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
+ *
8
+ * Copyright (c) Infonomic Company Limited
9
+ *
10
+ * Portions Copyright (c) Meta Platforms, Inc. and affiliates.
11
+ */
12
+
13
+ import { useEffect } from 'react'
14
+
15
+ import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
16
+ import { mergeRegister } from '@lexical/utils'
17
+ import {
18
+ $getSelection,
19
+ $isElementNode,
20
+ $isRangeSelection,
21
+ COMMAND_PRIORITY_LOW,
22
+ declarePeerDependency,
23
+ defineExtension,
24
+ type LexicalEditor,
25
+ PASTE_COMMAND,
26
+ } from 'lexical'
27
+
28
+ import { validateUrl } from '../../utils/url'
29
+ import {
30
+ type BylineFloatingUIConfig,
31
+ BylineFloatingUIExtension,
32
+ } from '../byline-floating-ui/byline-floating-ui-extension'
33
+ import { $toggleLink, AutoLinkNode, type LinkAttributes, LinkNode, TOGGLE_LINK_COMMAND } from '.'
34
+ import { FloatingLinkEditorPlugin } from './floating-link-editor'
35
+
36
+ /**
37
+ * Registers Byline's custom link command + paste handling on `editor`.
38
+ * Shared between the LinkPlugin React shell (used inside nested composers)
39
+ * and the LinkExtension's `register` phase (used by the top-level editor).
40
+ */
41
+ export function registerLink(editor: LexicalEditor): () => void {
42
+ return mergeRegister(
43
+ editor.registerCommand(
44
+ TOGGLE_LINK_COMMAND,
45
+ (payload: LinkAttributes | null) => {
46
+ if (payload === null) {
47
+ $toggleLink(payload)
48
+ return true
49
+ }
50
+
51
+ // For custom links, accept either a fully-formed URL or a
52
+ // root-relative path (starts with `/`). Drop the command when the
53
+ // URL is unusable so the toolbar doesn't insert garbage.
54
+ if (payload.linkType === 'custom') {
55
+ const url = payload.url ?? ''
56
+ if (!url.startsWith('/') && !validateUrl(url)) {
57
+ return false
58
+ }
59
+ }
60
+
61
+ $toggleLink(payload)
62
+ return true
63
+ },
64
+ COMMAND_PRIORITY_LOW
65
+ ),
66
+
67
+ editor.registerCommand(
68
+ PASTE_COMMAND,
69
+ (event) => {
70
+ const selection = $getSelection()
71
+ if (
72
+ !$isRangeSelection(selection) ||
73
+ selection.isCollapsed() ||
74
+ !(event instanceof ClipboardEvent) ||
75
+ event.clipboardData == null
76
+ ) {
77
+ return false
78
+ }
79
+ const clipboardText = event.clipboardData.getData('text')
80
+ if (!validateUrl(clipboardText)) {
81
+ return false
82
+ }
83
+ // Don't auto-link when the selection spans block-level nodes.
84
+ if (selection.getNodes().some((node) => $isElementNode(node))) {
85
+ return false
86
+ }
87
+ editor.dispatchCommand(TOGGLE_LINK_COMMAND, {
88
+ linkType: 'custom',
89
+ url: clipboardText,
90
+ })
91
+ event.preventDefault()
92
+ return true
93
+ },
94
+ COMMAND_PRIORITY_LOW
95
+ )
96
+ )
97
+ }
98
+
99
+ /**
100
+ * Legacy React shell — still used inside the inline-image nested composer
101
+ * (`inline-image-node-component.tsx`) where the nested editor needs link
102
+ * behaviour wired up. The top-level editor uses `LinkExtension` instead.
103
+ */
104
+ export function LinkPlugin(): null {
105
+ const [editor] = useLexicalComposerContext()
106
+
107
+ useEffect(() => {
108
+ if (!editor.hasNodes([LinkNode])) {
109
+ throw new Error('LinkPlugin: LinkNode not registered on editor')
110
+ }
111
+ return registerLink(editor)
112
+ }, [editor])
113
+
114
+ return null
115
+ }
116
+
117
+ export const LinkExtension = defineExtension({
118
+ name: '@byline/richtext-lexical/Link',
119
+ nodes: () => [LinkNode, AutoLinkNode],
120
+ register: registerLink,
121
+ peerDependencies: [
122
+ declarePeerDependency<typeof BylineFloatingUIExtension>(BylineFloatingUIExtension.name, {
123
+ items: [
124
+ {
125
+ id: '@byline/richtext-lexical/Link/floating-editor',
126
+ Component: FloatingLinkEditorPlugin,
127
+ },
128
+ ],
129
+ } satisfies Partial<BylineFloatingUIConfig>),
130
+ ],
131
+ })
@@ -1,4 +1,4 @@
1
- import type { LinkAttributes } from '../../../nodes/link-nodes'
1
+ import type { LinkAttributes } from '.'
2
2
 
3
3
  /**
4
4
  * The payload of a link node
@@ -28,12 +28,12 @@ import {
28
28
  type SelectValue,
29
29
  } from '@byline/ui/react'
30
30
 
31
- import { useEditorConfig } from '../../../config/editor-config-context'
32
- import { useModalFormState } from '../../../shared/useModalFormState'
33
- import { validateUrl } from '../../../utils/url'
34
- import type { DocumentRelation } from '../../../nodes/document-relation'
35
- import type { LinkAttributes } from '../../../nodes/link-nodes'
36
- import type { LinkData, LinkModalProps } from './types'
31
+ import { useEditorConfig } from '../../config/editor-config-context'
32
+ import { useModalFormState } from '../../shared/useModalFormState'
33
+ import { validateUrl } from '../../utils/url'
34
+ import type { DocumentRelation } from '../../nodes/document-relation'
35
+ import type { LinkAttributes } from '.'
36
+ import type { LinkData, LinkModalProps } from './link-modal-types'
37
37
 
38
38
  interface FormState {
39
39
  text: string
@@ -1,6 +1,6 @@
1
1
  import type { SerializedElementNode, Spread } from 'lexical'
2
2
 
3
- import type { DocumentRelation } from '../document-relation'
3
+ import type { DocumentRelation } from '../../nodes/document-relation'
4
4
 
5
5
  interface BaseLinkAttributes {
6
6
  newTab?: boolean
@@ -14,6 +14,7 @@ import type * as React from 'react'
14
14
  import { type ReactPortal, useCallback, useEffect, useRef, useState } from 'react'
15
15
 
16
16
  import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
17
+ import { useExtensionDependency } from '@lexical/react/useExtensionComponent'
17
18
  import { useLexicalEditable } from '@lexical/react/useLexicalEditable'
18
19
  import {
19
20
  $deleteTableColumnAtSelection,
@@ -31,6 +32,7 @@ import {
31
32
  $unmergeCell,
32
33
  getTableObserverFromTableElement,
33
34
  type HTMLTableElementWithWithTableSelectionState,
35
+ TableExtension as LexicalTableExtension,
34
36
  TableCellHeaderStates,
35
37
  TableCellNode,
36
38
  type TableRowNode,
@@ -48,9 +50,9 @@ import {
48
50
  } from 'lexical'
49
51
  import { createPortal } from 'react-dom'
50
52
 
51
- import useModal from '../../hooks/use-modal'
52
- import invariant from '../../shared/invariant'
53
- import ColorPicker from '../../ui/color-picker'
53
+ import useModal from '../../../hooks/use-modal'
54
+ import invariant from '../../../shared/invariant'
55
+ import ColorPicker from '../../../ui/color-picker'
54
56
 
55
57
  function computeSelectionCount(selection: TableSelection): {
56
58
  columns: number
@@ -788,16 +790,18 @@ function TableCellActionMenuContainer({
788
790
  }
789
791
 
790
792
  export function TableActionMenuPlugin({
791
- anchorElem = document.body,
792
- cellMerge = false,
793
+ anchorElem,
793
794
  }: {
794
- anchorElem?: HTMLElement
795
- cellMerge?: boolean
795
+ anchorElem: HTMLElement
796
796
  }): null | ReactPortal {
797
797
  const isEditable = useLexicalEditable()
798
+ // Read the upstream `@lexical/table` config so the cell-merge UI lives
799
+ // in lockstep with `c.extensions.configure(LexicalTableExtension, {...})`
800
+ // instead of needing a separate prop wired from `Editor.tsx`.
801
+ const { hasCellMerge } = useExtensionDependency(LexicalTableExtension).config
798
802
  return createPortal(
799
803
  isEditable ? (
800
- <TableCellActionMenuContainer anchorElem={anchorElem} cellMerge={cellMerge} />
804
+ <TableCellActionMenuContainer anchorElem={anchorElem} cellMerge={hasCellMerge ?? false} />
801
805
  ) : null,
802
806
  anchorElem
803
807
  )
@@ -0,0 +1,86 @@
1
+ 'use client'
2
+
3
+ /**
4
+ * This Source Code is subject to the terms of the Mozilla Public
5
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
6
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7
+ *
8
+ * Copyright (c) Infonomic Company Limited
9
+ */
10
+
11
+ import { TableExtension as LexicalTableExtension } from '@lexical/table'
12
+ import { configExtension, declarePeerDependency, defineExtension } from 'lexical'
13
+
14
+ import { OPEN_TABLE_MODAL_COMMAND } from '../../plugins/table-plugin'
15
+ import { useToolbarActiveEditor } from '../../plugins/toolbar-plugin/toolbar-active-editor'
16
+ import { DropDownItem } from '../../ui/dropdown'
17
+ import {
18
+ type BylineFloatingUIConfig,
19
+ BylineFloatingUIExtension,
20
+ } from '../byline-floating-ui/byline-floating-ui-extension'
21
+ import {
22
+ type BylineToolbarConfig,
23
+ BylineToolbarExtension,
24
+ } from '../byline-toolbar/byline-toolbar-extension'
25
+ import { TableActionMenuPlugin } from './table-action-menu-plugin'
26
+
27
+ function TableInsertItem(): React.JSX.Element {
28
+ const editor = useToolbarActiveEditor()
29
+ return (
30
+ <DropDownItem
31
+ onClick={() => {
32
+ editor.dispatchCommand(OPEN_TABLE_MODAL_COMMAND, null)
33
+ }}
34
+ className="item"
35
+ >
36
+ <i className="icon table" />
37
+ <span className="text">Table</span>
38
+ </DropDownItem>
39
+ )
40
+ }
41
+
42
+ /**
43
+ * Byline wrapper around `@lexical/table`'s `TableExtension`. Forwards
44
+ * cell-merge / cell-background-color config to the upstream extension
45
+ * via `configExtension` and contributes the "Insert table" toolbar item.
46
+ *
47
+ * Override the upstream config with:
48
+ * ```ts
49
+ * lexicalEditor((c) => {
50
+ * c.extensions.configure(LexicalTableExtension, {
51
+ * hasCellMerge: false,
52
+ * hasCellBackgroundColor: false,
53
+ * })
54
+ * return c
55
+ * })
56
+ * ```
57
+ */
58
+ export const TableExtension = defineExtension({
59
+ name: '@byline/richtext-lexical/Table',
60
+ dependencies: [
61
+ configExtension(LexicalTableExtension, {
62
+ hasCellMerge: true,
63
+ hasCellBackgroundColor: true,
64
+ }),
65
+ ],
66
+ peerDependencies: [
67
+ declarePeerDependency<typeof BylineToolbarExtension>(BylineToolbarExtension.name, {
68
+ items: [
69
+ {
70
+ id: '@byline/richtext-lexical/Table/insert',
71
+ placement: 'insert-menu',
72
+ order: 50,
73
+ node: <TableInsertItem />,
74
+ },
75
+ ],
76
+ } satisfies Partial<BylineToolbarConfig>),
77
+ declarePeerDependency<typeof BylineFloatingUIExtension>(BylineFloatingUIExtension.name, {
78
+ items: [
79
+ {
80
+ id: '@byline/richtext-lexical/Table/action-menu',
81
+ Component: TableActionMenuPlugin,
82
+ },
83
+ ],
84
+ } satisfies Partial<BylineFloatingUIConfig>),
85
+ ],
86
+ })