@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
@@ -0,0 +1,104 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+
9
+ /**
10
+ * Client-only — pulls in every built-in extension along with their React
11
+ * decorators and modal components. The `/server` entry never imports
12
+ * this file.
13
+ */
14
+
15
+ import {
16
+ AutoFocusExtension,
17
+ ClearEditorExtension,
18
+ TabIndentationExtension,
19
+ } from '@lexical/extension'
20
+ import { CheckListExtension, ListExtension } from '@lexical/list'
21
+ import type { AnyLexicalExtensionArgument } from 'lexical'
22
+
23
+ import { AdmonitionExtension } from '../extensions/admonition/admonition-extension'
24
+ import { AutoEmbedExtension } from '../extensions/auto-embed/auto-embed-extension'
25
+ import { BylineFloatingUIExtension } from '../extensions/byline-floating-ui/byline-floating-ui-extension'
26
+ import { BylineToolbarExtension } from '../extensions/byline-toolbar/byline-toolbar-extension'
27
+ import { CodeHighlightExtension } from '../extensions/code-highlight/code-highlight-extension'
28
+ import { FloatingTextFormatExtension } from '../extensions/floating-text-format/floating-text-format-extension'
29
+ import { HorizontalRuleExtension } from '../extensions/horizontal-rule/horizontal-rule-extension'
30
+ import { InlineImageExtension } from '../extensions/inline-image/inline-image-extension'
31
+ import { LayoutExtension } from '../extensions/layout/layout-extension'
32
+ import { AutoLinkExtension } from '../extensions/link/auto-link-extension'
33
+ import { LinkExtension } from '../extensions/link/link-extension'
34
+ import { TableExtension } from '../extensions/table/table-extension'
35
+ import { VimeoExtension } from '../extensions/vimeo/vimeo-extension'
36
+ import { YouTubeExtension } from '../extensions/youtube/youtube-extension'
37
+ import { defaultEditorConfig } from './default'
38
+ import { ExtensionsList } from './extensions-list'
39
+ import type { EditorConfig } from './types'
40
+
41
+ /**
42
+ * Returns a fresh array of every Byline-built-in Lexical extension in
43
+ * their canonical order. Includes the `BylineToolbarExtension` registry
44
+ * itself so contributing extensions can attach their toolbar items via
45
+ * `peerDependencies`.
46
+ *
47
+ * Order matters: stock framework extensions (clear-editor, tab-indent,
48
+ * auto-focus) come first; toolbar contract sits ahead of any
49
+ * contributing extension; relation-bearing extensions (link, image)
50
+ * land near the end.
51
+ */
52
+ export function defaultExtensionsArray(): AnyLexicalExtensionArgument[] {
53
+ return [
54
+ // Always-on stock extensions.
55
+ ClearEditorExtension,
56
+ TabIndentationExtension,
57
+ AutoFocusExtension,
58
+
59
+ // Toolbar + floating-UI contracts — must be present before any
60
+ // extension that contributes items to them via `peerDependencies`.
61
+ BylineToolbarExtension,
62
+ BylineFloatingUIExtension,
63
+
64
+ // Block- / list-level features.
65
+ ListExtension,
66
+ CheckListExtension,
67
+ HorizontalRuleExtension,
68
+ LayoutExtension,
69
+ AdmonitionExtension,
70
+ CodeHighlightExtension,
71
+ TableExtension,
72
+
73
+ // Link & link-related.
74
+ LinkExtension,
75
+ AutoLinkExtension,
76
+
77
+ // Embeds & inline images.
78
+ InlineImageExtension,
79
+ YouTubeExtension,
80
+ VimeoExtension,
81
+ AutoEmbedExtension,
82
+
83
+ // Floating UIs (the text-format popover lives at the floating-UI layer
84
+ // rather than the toolbar contract, so it gets its own extension).
85
+ FloatingTextFormatExtension,
86
+ ]
87
+ }
88
+
89
+ /** Fresh `ExtensionsList` populated with the built-in extensions. */
90
+ export function defaultExtensionsList(): ExtensionsList {
91
+ return new ExtensionsList(defaultExtensionsArray())
92
+ }
93
+
94
+ /**
95
+ * Client-side default editor config — settings + lexical config + the
96
+ * full default extensions list. Used by `lexicalEditor((c) => ...)` as
97
+ * the seed before invoking the configure callback. Server-only modules
98
+ * (e.g. seeds) must import `defaultEditorConfig` from
99
+ * `@byline/richtext-lexical/server` instead.
100
+ */
101
+ export const defaultClientEditorConfig: EditorConfig = {
102
+ ...defaultEditorConfig,
103
+ extensions: defaultExtensionsList(),
104
+ }
@@ -10,41 +10,13 @@ export const defaultEditorLexicalConfig: LexicalEditorConfig = {
10
10
 
11
11
  export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
12
12
  options: {
13
- disableBeforeInput: false,
14
- autocomplete: false,
15
- charLimit: false,
16
- charLimitUtf8: false,
17
- collab: false,
18
- maxLength: false,
19
13
  richText: true,
20
- measureTypingPerf: false,
21
- showNestedEditorTreeView: false,
22
- showTableOfContents: false,
23
14
  showTreeView: false,
24
15
  textAlignment: true,
25
- tablePlugin: true,
26
- tableCellBackgroundColor: true,
27
- tableCellMerge: true,
28
- tableActionMenuPlugin: true,
29
- layoutPlugin: true,
30
- outputHTML: false,
31
- outputMarkdown: false,
32
- autoFocusPlugin: false,
33
- autoLinkPlugin: false,
34
- inlineImagePlugin: true,
35
- admonitionPlugin: true,
36
- checkListPlugin: true,
37
- listPlugin: true,
38
- codeHighlightPlugin: true,
39
- horizontalRulePlugin: true,
40
16
  markdownShortcutPlugin: false,
41
17
  undoRedo: true,
42
18
  textStyle: true,
43
19
  inlineCode: true,
44
- links: true,
45
- floatingLinkEditorPlugin: true,
46
- floatingTextFormatToolbarPlugin: false,
47
- autoEmbedPlugin: true,
48
20
  debug: false,
49
21
  },
50
22
  inlineImageUploadCollection: 'media',
@@ -52,6 +24,14 @@ export const DEFAULT_EDITOR_SETTINGS: EditorSettings = {
52
24
  embedRelationsOnSave: true,
53
25
  }
54
26
 
27
+ /**
28
+ * Server-safe editor config — settings + Lexical core config only. The
29
+ * `extensions` field is intentionally omitted because extension entries
30
+ * carry React-bearing decorators that would break tsx-loaded seeds and
31
+ * other server-side schema consumers. The client-side
32
+ * `defaultClientEditorConfig` (in `default-extensions.tsx`) layers the
33
+ * extensions list on top.
34
+ */
55
35
  export const defaultEditorConfig: EditorConfig = {
56
36
  settings: DEFAULT_EDITOR_SETTINGS,
57
37
  lexical: defaultEditorLexicalConfig,
@@ -3,8 +3,6 @@
3
3
  import type * as React from 'react'
4
4
  import { createContext, useCallback, useContext, useMemo, useState } from 'react'
5
5
 
6
- import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext'
7
-
8
6
  import { DEFAULT_EDITOR_SETTINGS } from './default'
9
7
  import type { EditorSettings, OptionName } from './types'
10
8
 
@@ -34,7 +32,6 @@ export const EditorConfigContext = ({
34
32
  const [config, setConfig] = useState(configFromProps ?? DEFAULT_EDITOR_SETTINGS)
35
33
  // State to store the UUID
36
34
  const [uuid] = useState(() => generateQuickGuid())
37
- const [editor] = useLexicalComposerContext()
38
35
 
39
36
  const setOption = useCallback((option: OptionName, value: boolean) => {
40
37
  setConfig((config) => {
@@ -43,10 +40,7 @@ export const EditorConfigContext = ({
43
40
  })
44
41
  }, [])
45
42
 
46
- const editorContext = useMemo(
47
- () => ({ setOption, config, uuid, editor }),
48
- [setOption, config, uuid, editor]
49
- )
43
+ const editorContext = useMemo(() => ({ setOption, config, uuid }), [setOption, config, uuid])
50
44
 
51
45
  return <Context.Provider value={editorContext}>{children}</Context.Provider>
52
46
  }
@@ -0,0 +1,107 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+
9
+ import {
10
+ type AnyLexicalExtension,
11
+ type AnyLexicalExtensionArgument,
12
+ configExtension,
13
+ type LexicalExtensionConfig,
14
+ } from 'lexical'
15
+
16
+ /**
17
+ * Chainable wrapper around an ordered list of Lexical extensions. Used
18
+ * inside the `lexicalEditor((c) => ...)` configure callback so site
19
+ * authors can add, remove, configure, or reorder extensions before the
20
+ * editor is built.
21
+ *
22
+ * Comparison is by extension `name` so a bare `LinkExtension` and a
23
+ * `configExtension(LinkExtension, {...})` tuple are treated as the same
24
+ * entry.
25
+ */
26
+ export class ExtensionsList {
27
+ private items: AnyLexicalExtensionArgument[]
28
+
29
+ constructor(items: ReadonlyArray<AnyLexicalExtensionArgument> = []) {
30
+ this.items = [...items]
31
+ }
32
+
33
+ /** Append `extension` to the end of the list. */
34
+ add(extension: AnyLexicalExtensionArgument): this {
35
+ this.items.push(extension)
36
+ return this
37
+ }
38
+
39
+ /**
40
+ * Remove every entry whose name matches `extension.name`. No-op when
41
+ * the extension isn't present.
42
+ */
43
+ remove(extension: AnyLexicalExtension): this {
44
+ const targetName = extension.name
45
+ this.items = this.items.filter((item) => extensionName(item) !== targetName)
46
+ return this
47
+ }
48
+
49
+ /** Replace `oldExtension` with `newExtension`, preserving position. */
50
+ replace(oldExtension: AnyLexicalExtension, newExtension: AnyLexicalExtensionArgument): this {
51
+ const targetName = oldExtension.name
52
+ let replaced = false
53
+ this.items = this.items.map((item) => {
54
+ if (!replaced && extensionName(item) === targetName) {
55
+ replaced = true
56
+ return newExtension
57
+ }
58
+ return item
59
+ })
60
+ if (!replaced) this.items.push(newExtension)
61
+ return this
62
+ }
63
+
64
+ /**
65
+ * Re-wrap an existing extension entry with a fresh `configExtension`
66
+ * binding the supplied config. If the extension isn't present, it is
67
+ * added. If it was already wrapped with `configExtension`, the wrapper
68
+ * is replaced rather than nested.
69
+ */
70
+ configure<Extension extends AnyLexicalExtension>(
71
+ extension: Extension,
72
+ config: Partial<LexicalExtensionConfig<Extension>>
73
+ ): this {
74
+ const wrapped = configExtension(extension, config)
75
+ return this.replace(extension, wrapped)
76
+ }
77
+
78
+ /** True when an entry with the same `name` is present. */
79
+ has(extension: AnyLexicalExtension): boolean {
80
+ const targetName = extension.name
81
+ return this.items.some((item) => extensionName(item) === targetName)
82
+ }
83
+
84
+ /** Independent copy — safe to hand to a configure callback. */
85
+ clone(): ExtensionsList {
86
+ return new ExtensionsList(this.items)
87
+ }
88
+
89
+ /** The list as a plain array, ready for `defineExtension({ dependencies })`. */
90
+ toArray(): AnyLexicalExtensionArgument[] {
91
+ return [...this.items]
92
+ }
93
+ }
94
+
95
+ function extensionName(item: AnyLexicalExtensionArgument): string | undefined {
96
+ if (Array.isArray(item)) {
97
+ const head = item[0]
98
+ if (head != null && typeof head === 'object' && 'name' in head) {
99
+ return (head as AnyLexicalExtension).name
100
+ }
101
+ return undefined
102
+ }
103
+ if (item != null && typeof item === 'object' && 'name' in item) {
104
+ return (item as AnyLexicalExtension).name
105
+ }
106
+ return undefined
107
+ }
@@ -1,45 +1,32 @@
1
1
  import type { EditorConfig as LexicalEditorConfig } from 'lexical'
2
2
 
3
+ import type { ExtensionsList } from './extensions-list'
4
+
5
+ /**
6
+ * Settings that aren't expressible as "is extension X present in the
7
+ * extensions list?" — toolbar / UI mode toggles, debug switches, the
8
+ * inline-image upload target, etc. Everything else now lives on
9
+ * {@link EditorConfig.extensions} and is manipulated via the chainable
10
+ * `lexicalEditor((c) => c.extensions.add(...).remove(...))` API.
11
+ */
3
12
  export type OptionName =
4
- | 'disableBeforeInput'
5
- | 'autocomplete'
6
- | 'charLimit'
7
- | 'charLimitUtf8'
8
- | 'collab'
9
- | 'maxLength'
10
13
  | 'richText'
11
- | 'measureTypingPerf'
12
- | 'showNestedEditorTreeView'
13
- | 'showTableOfContents'
14
14
  | 'showTreeView'
15
15
  | 'textAlignment'
16
- | 'tablePlugin'
17
- | 'tableCellBackgroundColor'
18
- | 'tableCellMerge'
19
- | 'tableActionMenuPlugin'
20
- | 'layoutPlugin'
21
- | 'outputHTML'
22
- | 'outputMarkdown'
23
- | 'autoFocusPlugin'
24
- | 'autoLinkPlugin'
25
- | 'inlineImagePlugin'
26
- | 'admonitionPlugin'
27
- | 'checkListPlugin'
28
- | 'listPlugin'
29
- | 'codeHighlightPlugin'
30
- | 'horizontalRulePlugin'
31
16
  | 'markdownShortcutPlugin'
32
17
  | 'undoRedo'
33
18
  | 'textStyle'
34
19
  | 'inlineCode'
35
- | 'links'
36
- | 'floatingLinkEditorPlugin'
37
- | 'floatingTextFormatToolbarPlugin'
38
- | 'autoEmbedPlugin'
39
20
  | 'debug'
40
21
 
41
22
  export interface EditorSettings {
42
23
  options: Record<OptionName, boolean>
24
+ /**
25
+ * Upload collection passed to the inline-image picker. Forwarded to
26
+ * `InlineImageExtension`'s config when the extensions list is built;
27
+ * setting it here is equivalent to
28
+ * `c.extensions.configure(InlineImageExtension, { collection })`.
29
+ */
43
30
  inlineImageUploadCollection: string
44
31
  placeholderText: string
45
32
  /**
@@ -64,4 +51,17 @@ export interface EditorSettingsOverride {
64
51
  export interface EditorConfig {
65
52
  settings: EditorSettings
66
53
  lexical: LexicalEditorConfig
54
+ /**
55
+ * Manipulable list of Lexical extensions wired into the editor. When
56
+ * omitted (server-safe `defaultEditorConfig` from `/server` does not
57
+ * carry one), the editor falls back to the package's built-in list at
58
+ * render time.
59
+ *
60
+ * Field-level `RichTextField.editorConfig` should not set this
61
+ * directly — extension references are not JSON-safe and would break
62
+ * tsx-loaded seeds. Per-field extension overrides go through a
63
+ * client-side wrapper component registered via
64
+ * `FieldAdminConfig.editor` (see `aiRichTextAdmin()` for the pattern).
65
+ */
66
+ extensions?: ExtensionsList
67
67
  }
@@ -11,16 +11,22 @@
11
11
  import type * as React from 'react'
12
12
  import { useMemo } from 'react'
13
13
 
14
- import type { InitialConfigType } from '@lexical/react/LexicalComposer'
15
- import { LexicalComposer } from '@lexical/react/LexicalComposer'
16
- import type { EditorState, LexicalEditor, SerializedEditorState } from 'lexical'
14
+ import { LexicalExtensionComposer } from '@lexical/react/LexicalExtensionComposer'
15
+ import {
16
+ type AnyLexicalExtensionArgument,
17
+ defineExtension,
18
+ type EditorState,
19
+ type LexicalEditor,
20
+ type SerializedEditorState,
21
+ } from 'lexical'
17
22
 
23
+ import { defaultExtensionsList } from './config/default-extensions'
18
24
  import { EditorConfigContext } from './config/editor-config-context'
19
25
  import { SharedHistoryContext } from './context/shared-history-context'
20
26
  import { SharedOnChangeContext } from './context/shared-on-change-context'
21
27
  import { Editor } from './editor'
28
+ import { InlineImageExtension } from './extensions/inline-image/inline-image-extension'
22
29
  import { Nodes } from './nodes'
23
- import { ToolbarExtensionsProvider } from './toolbar-extensions'
24
30
  import type { EditorConfig } from './config/types'
25
31
 
26
32
  // Catch any errors that occur during Lexical updates and log them
@@ -54,49 +60,79 @@ export function EditorContext(props: {
54
60
  children,
55
61
  } = props
56
62
 
57
- // useMemo for the initialConfig that depends on readOnly and value
58
- // biome-ignore lint/correctness/useExhaustiveDependencies: TODO: revisit
59
- const initialConfig = useMemo<InitialConfigType>(() => {
60
- return {
61
- editable: readOnly !== true,
62
- editorState: value != null ? JSON.stringify(value) : undefined,
63
+ const editable = readOnly !== true
64
+
65
+ // The root extension must be a referentially stable value across renders.
66
+ // Unlike the legacy LexicalComposer (which memoised the editor with [] deps
67
+ // and ignored subsequent initialConfig changes), LexicalExtensionComposer
68
+ // rebuilds the editor whenever the `extension` prop changes by reference —
69
+ // destroying editor state and history. So we deliberately compute this
70
+ // only on mount and capture readOnly / value / editorConfig from the first
71
+ // render. The `key={composerKey + editable}` below already forces a remount
72
+ // when readOnly toggles, so a fresh extension is built then.
73
+ // biome-ignore lint/correctness/useExhaustiveDependencies: capture-once on mount; remount via `key` handles editable transitions
74
+ const rootExtension = useMemo<AnyLexicalExtensionArgument>(() => {
75
+ // Source of truth for the extension graph: editorConfig.extensions,
76
+ // optionally manipulated by site code via lexicalEditor((c) => ...).
77
+ // Server-loaded EditorConfigs (e.g. via /server) carry no extensions
78
+ // field; in that case we materialise the package default here.
79
+ const extensionsList = editorConfig.extensions ?? defaultExtensionsList()
80
+
81
+ // Forward the inline-image upload collection from the settings facade
82
+ // onto the InlineImageExtension's typed config, but only when the
83
+ // user hasn't already configured the extension explicitly.
84
+ const dependencies = extensionsList
85
+ .clone()
86
+ .configure(InlineImageExtension, {
87
+ collection: editorConfig.settings.inlineImageUploadCollection,
88
+ })
89
+ .toArray()
90
+
91
+ return defineExtension({
92
+ name: '[root]',
63
93
  namespace: editorConfig.lexical.namespace,
64
94
  nodes: [...Nodes],
95
+ theme: editorConfig.lexical.theme,
96
+ editable,
97
+ $initialEditorState: value != null ? JSON.stringify(value) : undefined,
65
98
  onError: (error: Error) => {
66
99
  throw error
67
100
  },
68
- theme: editorConfig.lexical.theme,
69
- }
70
- // Important: do not add readOnly and value to the dependencies array.
71
- // This will cause the entire lexical editor to re-render if the document
72
- // is saved, which will cause the editor to lose focus.
73
-
74
- // NOTE: 2025-04-26: This is NOT the case for our version of the editor.
75
- // Without readOnly as a dependency, the editor will never transition
76
- // from readOnly to editable during form loading, when disabledFromField
77
- // in field-component will be briefly false.
78
- }, [editorConfig, readOnly])
79
-
80
- if (initialConfig == null) {
81
- return <p>Loading...</p>
82
- }
101
+ dependencies,
102
+ })
103
+ }, [])
83
104
 
105
+ // These three context providers MUST sit OUTSIDE LexicalExtensionComposer.
106
+ //
107
+ // LexicalExtensionComposer renders the editor's React decorator portals
108
+ // (the components mounted for AdmonitionNode, InlineImageNode, etc.) as
109
+ // a sibling of its `children` inside an internal EditorChildrenComponent,
110
+ // not as descendants of `children`. Any context provider we place inside
111
+ // the composer is invisible to those decorators — so nested editors
112
+ // wired through SharedOnChangeContext silently fail to propagate change
113
+ // events up to the parent, and SharedHistoryContext falls back to a
114
+ // local history state instead of being shared with the root editor.
115
+ //
116
+ // Hoisting these providers above the composer puts the node decorators
117
+ // back inside their React tree.
84
118
  return (
85
- <LexicalComposer initialConfig={initialConfig} key={composerKey + initialConfig.editable}>
86
- <EditorConfigContext config={editorConfig.settings}>
87
- <SharedOnChangeContext onChange={onChange}>
88
- <SharedHistoryContext>
89
- <ToolbarExtensionsProvider>
90
- <div className="editor-shell">
91
- {beforeEditor}
92
- <Editor minHeight={props.minHeight} maxHeight={props.maxHeight} />
93
- {afterEditor}
94
- {children}
95
- </div>
96
- </ToolbarExtensionsProvider>
97
- </SharedHistoryContext>
98
- </SharedOnChangeContext>
99
- </EditorConfigContext>
100
- </LexicalComposer>
119
+ <EditorConfigContext config={editorConfig.settings}>
120
+ <SharedOnChangeContext onChange={onChange}>
121
+ <SharedHistoryContext>
122
+ <LexicalExtensionComposer
123
+ extension={rootExtension}
124
+ contentEditable={null}
125
+ key={composerKey + editable}
126
+ >
127
+ <div className="editor-shell">
128
+ {beforeEditor}
129
+ <Editor minHeight={props.minHeight} maxHeight={props.maxHeight} />
130
+ {afterEditor}
131
+ {children}
132
+ </div>
133
+ </LexicalExtensionComposer>
134
+ </SharedHistoryContext>
135
+ </SharedOnChangeContext>
136
+ </EditorConfigContext>
101
137
  )
102
138
  }
@@ -12,19 +12,16 @@ import type * as React from 'react'
12
12
  import { memo, useCallback, useEffect, useMemo, useState } from 'react'
13
13
 
14
14
  import { TRANSFORMERS } from '@lexical/markdown'
15
- import { AutoFocusPlugin } from '@lexical/react/LexicalAutoFocusPlugin'
16
- import { CheckListPlugin } from '@lexical/react/LexicalCheckListPlugin'
17
- import { ClearEditorPlugin } from '@lexical/react/LexicalClearEditorPlugin'
18
15
  import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary'
19
16
  import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin'
20
- import { HorizontalRulePlugin } from '@lexical/react/LexicalHorizontalRulePlugin'
21
- import { ListPlugin } from '@lexical/react/LexicalListPlugin'
22
17
  import { MarkdownShortcutPlugin } from '@lexical/react/LexicalMarkdownShortcutPlugin'
23
18
  import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin'
24
19
  import { PlainTextPlugin } from '@lexical/react/LexicalPlainTextPlugin'
25
20
  import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin'
26
- import { TabIndentationPlugin } from '@lexical/react/LexicalTabIndentationPlugin'
27
- import { TablePlugin } from '@lexical/react/LexicalTablePlugin'
21
+ import {
22
+ useExtensionDependency,
23
+ useOptionalExtensionDependency,
24
+ } from '@lexical/react/useExtensionComponent'
28
25
  import type { EditorState, LexicalEditor } from 'lexical'
29
26
 
30
27
  import { useEditorConfig } from './config/editor-config-context'
@@ -32,23 +29,16 @@ import { ContentEditable } from './content-editable'
32
29
  import { useSharedHistoryContext } from './context/shared-history-context'
33
30
  import { useSharedOnChange } from './context/shared-on-change-context'
34
31
  import { Debug } from './debug'
35
- import { AdmonitionPlugin } from './plugins/admonition-plugin'
32
+ import {
33
+ BylineFloatingUIExtension,
34
+ selectFloatingUIItems,
35
+ } from './extensions/byline-floating-ui/byline-floating-ui-extension'
36
+ import { TableExtension as BylineTableExtension } from './extensions/table/table-extension'
36
37
  // import { AiPlugin } from './plugins/ai-plugin'
37
- import { AutoEmbedPlugin } from './plugins/auto-embed-plugin'
38
- import { CodeHighlightPlugin } from './plugins/code-highlight-plugin'
39
38
  // import { DragDropPaste } from './plugins/drag-drop-paste-plugin'
40
- import { FloatingTextFormatToolbarPlugin } from './plugins/floating-text-format-toolbar-plugin'
41
- import { InlineImagePlugin } from './plugins/inline-image-plugin'
42
- import { LayoutPlugin } from './plugins/layout-plugin/layout-plugin'
43
- import { AutoLinkPlugin } from './plugins/link-plugin/auto-link'
44
- import { LinkPlugin } from './plugins/link-plugin/link'
45
- import { FloatingLinkEditorPlugin } from './plugins/link-plugin/link/floating-link-editor'
46
- import { TableActionMenuPlugin } from './plugins/table-action-menu-plugin'
47
- import { TablePlugin as PayloadTablePlugin } from './plugins/table-plugin'
39
+ import { TablePlugin } from './plugins/table-plugin'
48
40
  import { ToolbarPlugin } from './plugins/toolbar-plugin'
49
41
  import { TreeViewPlugin } from './plugins/treeview-plugin'
50
- import { VimeoPlugin } from './plugins/vimeo-plugin'
51
- import { YouTubePlugin } from './plugins/youtube-plugin'
52
42
  import { CAN_USE_DOM } from './shared/canUseDOM'
53
43
  import { Placeholder } from './ui/placeholder'
54
44
 
@@ -75,31 +65,17 @@ export const Editor = memo(function Editor({
75
65
  const { historyState } = useSharedHistoryContext()
76
66
  const {
77
67
  config: {
78
- options: {
79
- debug,
80
- richText,
81
- showTreeView,
82
- autoFocusPlugin,
83
- tablePlugin,
84
- tableActionMenuPlugin,
85
- layoutPlugin,
86
- inlineImagePlugin,
87
- admonitionPlugin,
88
- links,
89
- autoLinkPlugin,
90
- checkListPlugin,
91
- listPlugin,
92
- codeHighlightPlugin,
93
- horizontalRulePlugin,
94
- markdownShortcutPlugin,
95
- floatingLinkEditorPlugin,
96
- floatingTextFormatToolbarPlugin,
97
- autoEmbedPlugin,
98
- },
68
+ options: { debug, richText, showTreeView, markdownShortcutPlugin },
99
69
  placeholderText,
100
- inlineImageUploadCollection,
101
70
  },
102
71
  } = useEditorConfig()
72
+ const hasTableExtension = useOptionalExtensionDependency(BylineTableExtension) !== undefined
73
+ // Merged floating-UI contributions from every extension in the graph.
74
+ // Removing a contributing extension (e.g. `c.extensions.remove(LinkExtension)`)
75
+ // automatically suppresses its floating UI — no separate boolean toggle.
76
+ const floatingUIItems = selectFloatingUIItems(
77
+ useExtensionDependency(BylineFloatingUIExtension).config.items
78
+ )
103
79
 
104
80
  const onRef = useCallback((_floatingAnchorElem: HTMLDivElement): void => {
105
81
  if (_floatingAnchorElem != null) {
@@ -154,7 +130,7 @@ export const Editor = memo(function Editor({
154
130
 
155
131
  const content = (
156
132
  <>
157
- {tablePlugin && <PayloadTablePlugin />}
133
+ {hasTableExtension && <TablePlugin />}
158
134
  {richText && <ToolbarPlugin />}
159
135
  <div
160
136
  className={`editor-container ${showTreeView ? 'tree-view' : ''} ${
@@ -162,11 +138,6 @@ export const Editor = memo(function Editor({
162
138
  }`}
163
139
  >
164
140
  {/* <DragDropPaste /> */}
165
- {autoFocusPlugin && <AutoFocusPlugin />}
166
- {links && <LinkPlugin />}
167
- {autoEmbedPlugin && <AutoEmbedPlugin />}
168
- <TabIndentationPlugin />
169
- {autoLinkPlugin && <AutoLinkPlugin />}
170
141
  <OnChangePlugin
171
142
  // Ignore any onChange event triggered by focus or selection only
172
143
  ignoreSelectionChange={true}
@@ -190,30 +161,12 @@ export const Editor = memo(function Editor({
190
161
  ErrorBoundary={LexicalErrorBoundary}
191
162
  />
192
163
  <HistoryPlugin externalHistoryState={historyState} />
193
- {inlineImagePlugin && <InlineImagePlugin collection={inlineImageUploadCollection} />}
194
- {admonitionPlugin && <AdmonitionPlugin />}
195
- {checkListPlugin && <CheckListPlugin />}
196
- {listPlugin && <ListPlugin />}
197
- {codeHighlightPlugin && <CodeHighlightPlugin />}
198
- {horizontalRulePlugin && <HorizontalRulePlugin />}
199
- {layoutPlugin && <LayoutPlugin />}
200
- {autoEmbedPlugin && <YouTubePlugin />}
201
- {autoEmbedPlugin && <VimeoPlugin />}
202
164
  {markdownShortcutPlugin && <MarkdownShortcutPlugin transformers={TRANSFORMERS} />}
203
- {tablePlugin && <TablePlugin hasCellMerge={true} hasCellBackgroundColor={true} />}
204
- {floatingAnchorElem != null && !isSmallWidthViewport && (
205
- <>
206
- {floatingLinkEditorPlugin && (
207
- <FloatingLinkEditorPlugin anchorElem={floatingAnchorElem} />
208
- )}
209
- {tableActionMenuPlugin && (
210
- <TableActionMenuPlugin anchorElem={floatingAnchorElem} cellMerge={false} />
211
- )}
212
- {floatingTextFormatToolbarPlugin && (
213
- <FloatingTextFormatToolbarPlugin anchorElem={floatingAnchorElem} />
214
- )}
215
- </>
216
- )}
165
+ {floatingAnchorElem != null &&
166
+ !isSmallWidthViewport &&
167
+ floatingUIItems.map(({ id, Component }) => (
168
+ <Component key={id} anchorElem={floatingAnchorElem} />
169
+ ))}
217
170
  </>
218
171
  ) : (
219
172
  <>
@@ -225,7 +178,6 @@ export const Editor = memo(function Editor({
225
178
  <HistoryPlugin externalHistoryState={historyState} />
226
179
  </>
227
180
  )}
228
- <ClearEditorPlugin />
229
181
  {debug && (
230
182
  <>
231
183
  <Debug />