@intlayer/design-system 9.0.0-canary.0 → 9.0.0-canary.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (249) hide show
  1. package/dist/esm/api/hooks/ai.mjs +20 -1
  2. package/dist/esm/api/hooks/ai.mjs.map +1 -1
  3. package/dist/esm/api/hooks/asset.mjs +78 -0
  4. package/dist/esm/api/hooks/asset.mjs.map +1 -0
  5. package/dist/esm/api/index.mjs +6 -5
  6. package/dist/esm/api/useIntlayerAPI.mjs +6 -1
  7. package/dist/esm/api/useIntlayerAPI.mjs.map +1 -1
  8. package/dist/esm/components/Command/index.mjs +8 -8
  9. package/dist/esm/components/Command/index.mjs.map +1 -1
  10. package/dist/esm/components/ContentEditor/ContentEditorTextArea.mjs +1 -1
  11. package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs +132 -35
  12. package/dist/esm/components/DictionaryFieldEditor/ContentEditor.mjs.map +1 -1
  13. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs +33 -11
  14. package/dist/esm/components/DictionaryFieldEditor/ContentEditorView/TextEditor.mjs.map +1 -1
  15. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs +146 -35
  16. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.mjs.map +1 -1
  17. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/dictionaryCreationForm.content.mjs +308 -0
  18. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/dictionaryCreationForm.content.mjs.map +1 -1
  19. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.mjs +12 -2
  20. package/dist/esm/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.mjs.map +1 -1
  21. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs +460 -20
  22. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.mjs.map +1 -1
  23. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/dictionaryDetails.content.mjs +506 -0
  24. package/dist/esm/components/DictionaryFieldEditor/DictionaryDetails/dictionaryDetails.content.mjs.map +1 -1
  25. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs +10 -6
  26. package/dist/esm/components/DictionaryFieldEditor/DictionaryFieldEditor.mjs.map +1 -1
  27. package/dist/esm/components/DictionaryFieldEditor/NavigationView/NavigationViewNode.mjs +1 -1
  28. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs +9 -9
  29. package/dist/esm/components/DictionaryFieldEditor/SaveForm/SaveForm.mjs.map +1 -1
  30. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs +2 -2
  31. package/dist/esm/components/DictionaryFieldEditor/StructureView/StructureView.mjs.map +1 -1
  32. package/dist/esm/components/DictionaryFieldEditor/contentEditor.content.mjs +79 -0
  33. package/dist/esm/components/DictionaryFieldEditor/contentEditor.content.mjs.map +1 -0
  34. package/dist/esm/components/Form/Form.mjs +3 -43
  35. package/dist/esm/components/Form/Form.mjs.map +1 -1
  36. package/dist/esm/components/Form/elements/FormElement.mjs +2 -3
  37. package/dist/esm/components/Form/elements/FormElement.mjs.map +1 -1
  38. package/dist/esm/components/Form/elements/MultiselectElement.mjs +2 -3
  39. package/dist/esm/components/Form/elements/MultiselectElement.mjs.map +1 -1
  40. package/dist/esm/components/Form/elements/OTPElement.mjs +3 -4
  41. package/dist/esm/components/Form/elements/OTPElement.mjs.map +1 -1
  42. package/dist/esm/components/Form/elements/SelectElement.mjs +2 -3
  43. package/dist/esm/components/Form/elements/SelectElement.mjs.map +1 -1
  44. package/dist/esm/components/Form/elements/SwitchSelectorElement.mjs +2 -3
  45. package/dist/esm/components/Form/elements/SwitchSelectorElement.mjs.map +1 -1
  46. package/dist/esm/components/Form/index.mjs +21 -2
  47. package/dist/esm/components/Form/layout/FormItemLayout.mjs +8 -5
  48. package/dist/esm/components/Form/layout/FormItemLayout.mjs.map +1 -1
  49. package/dist/esm/components/LanguageBackground/LanguageBackground.mjs +3 -8
  50. package/dist/esm/components/LanguageBackground/LanguageBackground.mjs.map +1 -1
  51. package/dist/esm/components/LocaleSwitcherContentDropDown/LocaleSwitcherContent.mjs +1 -1
  52. package/dist/esm/components/MarkDownRender/MarkDownRender.mjs +1 -1
  53. package/dist/esm/components/MarkDownRender/MarkDownRender.mjs.map +1 -1
  54. package/dist/esm/components/MarkdownEditor/MarkdownEditor.mjs +113 -0
  55. package/dist/esm/components/MarkdownEditor/MarkdownEditor.mjs.map +1 -0
  56. package/dist/esm/components/MarkdownEditor/extensions.mjs +103 -0
  57. package/dist/esm/components/MarkdownEditor/extensions.mjs.map +1 -0
  58. package/dist/esm/components/MarkdownEditor/generative/AICompletionCommands.mjs +51 -0
  59. package/dist/esm/components/MarkdownEditor/generative/AICompletionCommands.mjs.map +1 -0
  60. package/dist/esm/components/MarkdownEditor/generative/AISelector.mjs +100 -0
  61. package/dist/esm/components/MarkdownEditor/generative/AISelector.mjs.map +1 -0
  62. package/dist/esm/components/MarkdownEditor/generative/AISelectorCommands.mjs +81 -0
  63. package/dist/esm/components/MarkdownEditor/generative/AISelectorCommands.mjs.map +1 -0
  64. package/dist/esm/components/MarkdownEditor/generative/GenerativeMenuSwitch.mjs +47 -0
  65. package/dist/esm/components/MarkdownEditor/generative/GenerativeMenuSwitch.mjs.map +1 -0
  66. package/dist/esm/components/MarkdownEditor/generative/useAICompletion.mjs +83 -0
  67. package/dist/esm/components/MarkdownEditor/generative/useAICompletion.mjs.map +1 -0
  68. package/dist/esm/components/MarkdownEditor/imageUpload.mjs +47 -0
  69. package/dist/esm/components/MarkdownEditor/imageUpload.mjs.map +1 -0
  70. package/dist/esm/components/MarkdownEditor/index.mjs +4 -0
  71. package/dist/esm/components/MarkdownEditor/markdownEditor.content.mjs +1140 -0
  72. package/dist/esm/components/MarkdownEditor/markdownEditor.content.mjs.map +1 -0
  73. package/dist/esm/components/MarkdownEditor/novel/components/editor-bubble-item.mjs +20 -0
  74. package/dist/esm/components/MarkdownEditor/novel/components/editor-bubble-item.mjs.map +1 -0
  75. package/dist/esm/components/MarkdownEditor/novel/components/editor-bubble.mjs +39 -0
  76. package/dist/esm/components/MarkdownEditor/novel/components/editor-bubble.mjs.map +1 -0
  77. package/dist/esm/components/MarkdownEditor/novel/components/editor-command-item.mjs +25 -0
  78. package/dist/esm/components/MarkdownEditor/novel/components/editor-command-item.mjs.map +1 -0
  79. package/dist/esm/components/MarkdownEditor/novel/components/editor-command.mjs +61 -0
  80. package/dist/esm/components/MarkdownEditor/novel/components/editor-command.mjs.map +1 -0
  81. package/dist/esm/components/MarkdownEditor/novel/components/editor.mjs +27 -0
  82. package/dist/esm/components/MarkdownEditor/novel/components/editor.mjs.map +1 -0
  83. package/dist/esm/components/MarkdownEditor/novel/components/index.mjs +8 -0
  84. package/dist/esm/components/MarkdownEditor/novel/extensions/ai-highlight.mjs +74 -0
  85. package/dist/esm/components/MarkdownEditor/novel/extensions/ai-highlight.mjs.map +1 -0
  86. package/dist/esm/components/MarkdownEditor/novel/extensions/custom-keymap.mjs +37 -0
  87. package/dist/esm/components/MarkdownEditor/novel/extensions/custom-keymap.mjs.map +1 -0
  88. package/dist/esm/components/MarkdownEditor/novel/extensions/image-resizer.mjs +49 -0
  89. package/dist/esm/components/MarkdownEditor/novel/extensions/image-resizer.mjs.map +1 -0
  90. package/dist/esm/components/MarkdownEditor/novel/extensions/index.mjs +51 -0
  91. package/dist/esm/components/MarkdownEditor/novel/extensions/index.mjs.map +1 -0
  92. package/dist/esm/components/MarkdownEditor/novel/extensions/slash-command.mjs +79 -0
  93. package/dist/esm/components/MarkdownEditor/novel/extensions/slash-command.mjs.map +1 -0
  94. package/dist/esm/components/MarkdownEditor/novel/extensions/updated-image.mjs +17 -0
  95. package/dist/esm/components/MarkdownEditor/novel/extensions/updated-image.mjs.map +1 -0
  96. package/dist/esm/components/MarkdownEditor/novel/index.mjs +17 -0
  97. package/dist/esm/components/MarkdownEditor/novel/plugins/index.mjs +3 -0
  98. package/dist/esm/components/MarkdownEditor/novel/plugins/upload-images.mjs +92 -0
  99. package/dist/esm/components/MarkdownEditor/novel/plugins/upload-images.mjs.map +1 -0
  100. package/dist/esm/components/MarkdownEditor/novel/utils/atoms.mjs +39 -0
  101. package/dist/esm/components/MarkdownEditor/novel/utils/atoms.mjs.map +1 -0
  102. package/dist/esm/components/MarkdownEditor/novel/utils/index.mjs +38 -0
  103. package/dist/esm/components/MarkdownEditor/novel/utils/index.mjs.map +1 -0
  104. package/dist/esm/components/MarkdownEditor/selectors/ColorSelector.mjs +176 -0
  105. package/dist/esm/components/MarkdownEditor/selectors/ColorSelector.mjs.map +1 -0
  106. package/dist/esm/components/MarkdownEditor/selectors/LinkSelector.mjs +95 -0
  107. package/dist/esm/components/MarkdownEditor/selectors/LinkSelector.mjs.map +1 -0
  108. package/dist/esm/components/MarkdownEditor/selectors/NodeSelector.mjs +139 -0
  109. package/dist/esm/components/MarkdownEditor/selectors/NodeSelector.mjs.map +1 -0
  110. package/dist/esm/components/MarkdownEditor/selectors/TextButtons.mjs +81 -0
  111. package/dist/esm/components/MarkdownEditor/selectors/TextButtons.mjs.map +1 -0
  112. package/dist/esm/components/MarkdownEditor/slashCommand.mjs +161 -0
  113. package/dist/esm/components/MarkdownEditor/slashCommand.mjs.map +1 -0
  114. package/dist/esm/components/Modal/Modal.mjs +2 -2
  115. package/dist/esm/components/Navbar/MobileNavbar.mjs +1 -1
  116. package/dist/esm/components/Pagination/Pagination.mjs +1 -1
  117. package/dist/esm/components/Pattern/GridDistortionPattern.mjs +275 -0
  118. package/dist/esm/components/Pattern/GridDistortionPattern.mjs.map +1 -0
  119. package/dist/esm/components/Pattern/index.mjs +2 -1
  120. package/dist/esm/components/RightDrawer/RightDrawer.mjs +3 -3
  121. package/dist/esm/components/Tab/Tab.mjs +1 -1
  122. package/dist/esm/components/Table/Table.mjs +1 -1
  123. package/dist/esm/components/Table/Table.mjs.map +1 -1
  124. package/dist/esm/components/Tag/index.mjs +0 -9
  125. package/dist/esm/components/Tag/index.mjs.map +1 -1
  126. package/dist/esm/components/Toaster/Toast.mjs +1 -1
  127. package/dist/esm/components/Toaster/Toast.mjs.map +1 -1
  128. package/dist/esm/components/index.mjs +27 -6
  129. package/dist/esm/hooks/index.mjs +8 -8
  130. package/dist/esm/hooks/useIsMounted.mjs +4 -2
  131. package/dist/esm/hooks/useIsMounted.mjs.map +1 -1
  132. package/dist/esm/routes.mjs +2 -1
  133. package/dist/esm/routes.mjs.map +1 -1
  134. package/dist/types/api/hooks/ai.d.ts +5 -1
  135. package/dist/types/api/hooks/ai.d.ts.map +1 -1
  136. package/dist/types/api/hooks/asset.d.ts +27 -0
  137. package/dist/types/api/hooks/asset.d.ts.map +1 -0
  138. package/dist/types/api/hooks/audit.d.ts +1 -1
  139. package/dist/types/api/index.d.ts +4 -3
  140. package/dist/types/api/useIntlayerAPI.d.ts +15 -3
  141. package/dist/types/api/useIntlayerAPI.d.ts.map +1 -1
  142. package/dist/types/components/Badge/index.d.ts +1 -1
  143. package/dist/types/components/Breadcrumb/index.d.ts +1 -1
  144. package/dist/types/components/Button/Button.d.ts +3 -3
  145. package/dist/types/components/CollapsibleTable/CollapsibleTable.d.ts +2 -2
  146. package/dist/types/components/Command/index.d.ts.map +1 -1
  147. package/dist/types/components/Container/index.d.ts +1 -1
  148. package/dist/types/components/DictionaryFieldEditor/ContentEditor.d.ts.map +1 -1
  149. package/dist/types/components/DictionaryFieldEditor/ContentEditorView/TextEditor.d.ts.map +1 -1
  150. package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/DictionaryCreationForm.d.ts.map +1 -1
  151. package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/dictionaryCreationForm.content.d.ts +308 -0
  152. package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/dictionaryCreationForm.content.d.ts.map +1 -1
  153. package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.d.ts +12 -1
  154. package/dist/types/components/DictionaryFieldEditor/DictionaryCreationForm/useDictionaryFormSchema.d.ts.map +1 -1
  155. package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.d.ts +2 -0
  156. package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/DictionaryDetailsForm.d.ts.map +1 -1
  157. package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/dictionaryDetails.content.d.ts +506 -0
  158. package/dist/types/components/DictionaryFieldEditor/DictionaryDetails/dictionaryDetails.content.d.ts.map +1 -1
  159. package/dist/types/components/DictionaryFieldEditor/DictionaryFieldEditor.d.ts +2 -1
  160. package/dist/types/components/DictionaryFieldEditor/DictionaryFieldEditor.d.ts.map +1 -1
  161. package/dist/types/components/DictionaryFieldEditor/contentEditor.content.d.ts +80 -0
  162. package/dist/types/components/DictionaryFieldEditor/contentEditor.content.d.ts.map +1 -0
  163. package/dist/types/components/Form/Form.d.ts +27 -47
  164. package/dist/types/components/Form/Form.d.ts.map +1 -1
  165. package/dist/types/components/Form/elements/FormElement.d.ts.map +1 -1
  166. package/dist/types/components/Form/elements/MultiselectElement.d.ts.map +1 -1
  167. package/dist/types/components/Form/elements/OTPElement.d.ts.map +1 -1
  168. package/dist/types/components/Form/elements/SelectElement.d.ts.map +1 -1
  169. package/dist/types/components/Form/elements/SwitchSelectorElement.d.ts.map +1 -1
  170. package/dist/types/components/Form/index.d.ts +22 -3
  171. package/dist/types/components/Form/layout/FormItemLayout.d.ts.map +1 -1
  172. package/dist/types/components/Input/Checkbox.d.ts +3 -3
  173. package/dist/types/components/Input/Input.d.ts +1 -1
  174. package/dist/types/components/Input/Radio.d.ts +3 -3
  175. package/dist/types/components/LanguageBackground/LanguageBackground.d.ts.map +1 -1
  176. package/dist/types/components/Link/Link.d.ts +1 -1
  177. package/dist/types/components/MarkdownEditor/MarkdownEditor.d.ts +31 -0
  178. package/dist/types/components/MarkdownEditor/MarkdownEditor.d.ts.map +1 -0
  179. package/dist/types/components/MarkdownEditor/extensions.d.ts +11 -0
  180. package/dist/types/components/MarkdownEditor/extensions.d.ts.map +1 -0
  181. package/dist/types/components/MarkdownEditor/generative/AICompletionCommands.d.ts +18 -0
  182. package/dist/types/components/MarkdownEditor/generative/AICompletionCommands.d.ts.map +1 -0
  183. package/dist/types/components/MarkdownEditor/generative/AISelector.d.ts +22 -0
  184. package/dist/types/components/MarkdownEditor/generative/AISelector.d.ts.map +1 -0
  185. package/dist/types/components/MarkdownEditor/generative/AISelectorCommands.d.ts +17 -0
  186. package/dist/types/components/MarkdownEditor/generative/AISelectorCommands.d.ts.map +1 -0
  187. package/dist/types/components/MarkdownEditor/generative/GenerativeMenuSwitch.d.ts +26 -0
  188. package/dist/types/components/MarkdownEditor/generative/GenerativeMenuSwitch.d.ts.map +1 -0
  189. package/dist/types/components/MarkdownEditor/generative/useAICompletion.d.ts +30 -0
  190. package/dist/types/components/MarkdownEditor/generative/useAICompletion.d.ts.map +1 -0
  191. package/dist/types/components/MarkdownEditor/imageUpload.d.ts +29 -0
  192. package/dist/types/components/MarkdownEditor/imageUpload.d.ts.map +1 -0
  193. package/dist/types/components/MarkdownEditor/index.d.ts +3 -0
  194. package/dist/types/components/MarkdownEditor/markdownEditor.content.d.ts +1135 -0
  195. package/dist/types/components/MarkdownEditor/markdownEditor.content.d.ts.map +1 -0
  196. package/dist/types/components/MarkdownEditor/novel/components/editor-bubble-item.d.ts +14 -0
  197. package/dist/types/components/MarkdownEditor/novel/components/editor-bubble-item.d.ts.map +1 -0
  198. package/dist/types/components/MarkdownEditor/novel/components/editor-bubble.d.ts +18 -0
  199. package/dist/types/components/MarkdownEditor/novel/components/editor-bubble.d.ts.map +1 -0
  200. package/dist/types/components/MarkdownEditor/novel/components/editor-command-item.d.ts +28 -0
  201. package/dist/types/components/MarkdownEditor/novel/components/editor-command-item.d.ts.map +1 -0
  202. package/dist/types/components/MarkdownEditor/novel/components/editor-command.d.ts +34 -0
  203. package/dist/types/components/MarkdownEditor/novel/components/editor-command.d.ts.map +1 -0
  204. package/dist/types/components/MarkdownEditor/novel/components/editor.d.ts +23 -0
  205. package/dist/types/components/MarkdownEditor/novel/components/editor.d.ts.map +1 -0
  206. package/dist/types/components/MarkdownEditor/novel/components/index.d.ts +8 -0
  207. package/dist/types/components/MarkdownEditor/novel/extensions/ai-highlight.d.ts +36 -0
  208. package/dist/types/components/MarkdownEditor/novel/extensions/ai-highlight.d.ts.map +1 -0
  209. package/dist/types/components/MarkdownEditor/novel/extensions/custom-keymap.d.ts +17 -0
  210. package/dist/types/components/MarkdownEditor/novel/extensions/custom-keymap.d.ts.map +1 -0
  211. package/dist/types/components/MarkdownEditor/novel/extensions/image-resizer.d.ts +7 -0
  212. package/dist/types/components/MarkdownEditor/novel/extensions/image-resizer.d.ts.map +1 -0
  213. package/dist/types/components/MarkdownEditor/novel/extensions/index.d.ts +30 -0
  214. package/dist/types/components/MarkdownEditor/novel/extensions/index.d.ts.map +1 -0
  215. package/dist/types/components/MarkdownEditor/novel/extensions/slash-command.d.ts +38 -0
  216. package/dist/types/components/MarkdownEditor/novel/extensions/slash-command.d.ts.map +1 -0
  217. package/dist/types/components/MarkdownEditor/novel/extensions/updated-image.d.ts +8 -0
  218. package/dist/types/components/MarkdownEditor/novel/extensions/updated-image.d.ts.map +1 -0
  219. package/dist/types/components/MarkdownEditor/novel/index.d.ts +16 -0
  220. package/dist/types/components/MarkdownEditor/novel/plugins/index.d.ts +2 -0
  221. package/dist/types/components/MarkdownEditor/novel/plugins/upload-images.d.ts +22 -0
  222. package/dist/types/components/MarkdownEditor/novel/plugins/upload-images.d.ts.map +1 -0
  223. package/dist/types/components/MarkdownEditor/novel/utils/atoms.d.ts +21 -0
  224. package/dist/types/components/MarkdownEditor/novel/utils/atoms.d.ts.map +1 -0
  225. package/dist/types/components/MarkdownEditor/novel/utils/index.d.ts +10 -0
  226. package/dist/types/components/MarkdownEditor/novel/utils/index.d.ts.map +1 -0
  227. package/dist/types/components/MarkdownEditor/selectors/ColorSelector.d.ts +17 -0
  228. package/dist/types/components/MarkdownEditor/selectors/ColorSelector.d.ts.map +1 -0
  229. package/dist/types/components/MarkdownEditor/selectors/LinkSelector.d.ts +15 -0
  230. package/dist/types/components/MarkdownEditor/selectors/LinkSelector.d.ts.map +1 -0
  231. package/dist/types/components/MarkdownEditor/selectors/NodeSelector.d.ts +22 -0
  232. package/dist/types/components/MarkdownEditor/selectors/NodeSelector.d.ts.map +1 -0
  233. package/dist/types/components/MarkdownEditor/selectors/TextButtons.d.ts +11 -0
  234. package/dist/types/components/MarkdownEditor/selectors/TextButtons.d.ts.map +1 -0
  235. package/dist/types/components/MarkdownEditor/slashCommand.d.ts +29 -0
  236. package/dist/types/components/MarkdownEditor/slashCommand.d.ts.map +1 -0
  237. package/dist/types/components/Pattern/GridDistortionPattern.d.ts +15 -0
  238. package/dist/types/components/Pattern/GridDistortionPattern.d.ts.map +1 -0
  239. package/dist/types/components/Pattern/index.d.ts +2 -1
  240. package/dist/types/components/SwitchSelector/SwitchSelector.d.ts +1 -1
  241. package/dist/types/components/SwitchSelector/VerticalSwitchSelector.d.ts +1 -1
  242. package/dist/types/components/Tag/index.d.ts +2 -2
  243. package/dist/types/components/Tag/index.d.ts.map +1 -1
  244. package/dist/types/components/Toaster/Toast.d.ts +1 -1
  245. package/dist/types/components/index.d.ts +24 -3
  246. package/dist/types/routes.d.ts +2 -1
  247. package/dist/types/routes.d.ts.map +1 -1
  248. package/package.json +63 -32
  249. package/src/components/MarkdownEditor/markdown-editor.css +297 -0
@@ -1 +1 @@
1
- {"version":3,"file":"MarkDownRender.mjs","names":[],"sources":["../../../../src/components/MarkDownRender/MarkDownRender.tsx"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { cn } from '@utils/cn';\nimport type { ComponentProps, ComponentPropsWithoutRef, FC } from 'react';\nimport { memo } from 'react';\nimport {\n type MarkdownRenderer as MarkdownRendererIntlayer,\n type ParsedMarkdown,\n renderMarkdown,\n} from 'react-intlayer/markdown';\n\nexport type { ParsedMarkdown };\n\nimport type { BundledLanguage } from 'shiki/bundle/web';\nimport { H1, H2, H3, H4, H5, H6 } from '../Headers';\nimport { Code } from '../IDE/Code';\nimport { CodeProvider } from '../IDE/CodeContext';\nimport { Link } from '../Link';\nimport { Tab } from '../Tab';\nimport { TabProvider } from '../Tab/TabContext';\nimport { Hr, SmartTable, Td, Th, Tr } from '../Table';\nimport { MarkDownIframe } from './MarkDownIframe';\n\n// Extracted, stable component renderers\nconst H1Renderer = (props: ComponentProps<'h1'>) => (\n <H1 isClickable className=\"mb-16 mb-8 text-text\" {...props} />\n);\nconst H2Renderer = (props: ComponentProps<'h2'>) => (\n <H2 isClickable className=\"mt-16 text-text\" {...props} />\n);\nconst H3Renderer = (props: ComponentProps<'h3'>) => (\n <H3 isClickable className=\"mt-5 text-text\" {...props} />\n);\nconst H4Renderer = (props: ComponentProps<'h4'>) => (\n <H4 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst H5Renderer = (props: ComponentProps<'h5'>) => (\n <H5 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst H6Renderer = (props: ComponentProps<'h6'>) => (\n <H6 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst StrongRenderer = (props: ComponentProps<'strong'>) => (\n <strong className=\"text-text\" {...props} />\n);\n\nconst MemoizedCodeBlock = memo(\n ({\n className,\n children,\n isDarkMode,\n lang, // Destructure html lang prop to prevent passing invalid BCP-47 language tag to Code component\n ...rest\n }: ComponentProps<'code'> & { isDarkMode?: boolean }) => {\n const content = String(children ?? '').replace(/\\n$/, '');\n const isBlock = !!className;\n\n if (!isBlock) {\n const decodedContent = content.replace(\n /&(?:amp;)?#(\\d+);/g,\n (_, code: string) => String.fromCharCode(parseInt(code, 10))\n );\n return (\n <code className=\"rounded-md border border-neutral/30 bg-card/60 box-decoration-clone px-1.5 py-0.5 font-mono text-sm\">\n {decodedContent}\n </code>\n );\n }\n\n const language = (className?.replace(/lang(?:uage)?-/, '') ||\n 'plaintext') as BundledLanguage;\n\n return (\n <Code {...rest} language={language} showHeader isDarkMode={isDarkMode}>\n {content}\n </Code>\n );\n },\n (prevProps, nextProps) =>\n prevProps.children === nextProps.children &&\n prevProps.className === nextProps.className &&\n prevProps.isDarkMode === nextProps.isDarkMode\n);\n\nconst createCodeRenderer = (isDarkMode?: boolean) => {\n return function CodeWrapper(props: ComponentProps<'code'>) {\n return <MemoizedCodeBlock {...props} isDarkMode={isDarkMode} />;\n };\n};\n\nconst BlockquoteRenderer = ({\n className,\n ...props\n}: ComponentProps<'blockquote'>) => (\n <blockquote\n className={cn(\n 'mt-5 gap-3 border-card border-l-4 pl-5 text-neutral [&_strong]:text-neutral',\n className\n )}\n {...props}\n />\n);\n\nconst UlRenderer = ({ className, ...props }: ComponentProps<'ul'>) => (\n <ul\n className={cn(\n 'mt-5 flex list-disc flex-col gap-3 pl-5 marker:text-neutral/80',\n className\n )}\n {...props}\n />\n);\n\nconst OlRenderer = ({ className, ...props }: ComponentProps<'ol'>) => (\n <ol\n className={cn(\n 'mt-5 flex list-decimal flex-col gap-3 pl-5 marker:text-neutral/80',\n className\n )}\n {...props}\n />\n);\n\nconst ImgRenderer = ({\n className,\n alt,\n src,\n ...props\n}: ComponentProps<'img'>) => (\n <img\n {...props}\n alt={alt ?? ''}\n loading=\"lazy\"\n className={cn('max-h-[80vh] max-w-full rounded-md', className)}\n src={\n src?.includes('github.com')\n ? src\n ?.replace('github.com', 'raw.githubusercontent.com')\n .replace('/blob/', '/') // GitHub raw URLs do not use /blob/\n : src\n }\n />\n);\n\nconst createLinkRenderer = (locale?: LocalesValues) => {\n return (props: ComponentProps<'a'>) => (\n <Link\n isExternalLink={props.href?.startsWith('http')}\n underlined\n locale={locale}\n label=\"\"\n color=\"text\"\n {...(props as any)}\n />\n );\n};\n\nconst PreRenderer = (props: ComponentProps<'pre'>) => <>{props.children}</>;\nconst TableRenderer = (props: ComponentProps<typeof SmartTable>) => (\n <SmartTable isRollable displayModal {...props} />\n);\n\nconst TabsRenderer = (props: ComponentProps<typeof Tab>) => (\n <Tab\n {...props}\n className=\"rounded-xl border border-card\"\n headerClassName=\"sticky rounded-xl top-24 z-5 bg-background/70 backdrop-blur overflow-x-auto\"\n />\n);\nconst ColumnsRenderer = ({\n className,\n ...props\n}: ComponentPropsWithoutRef<'div'>) => (\n <div className={cn('flex gap-4 max-md:flex-col', className)} {...props} />\n);\nconst ColumnRenderer = ({\n className,\n ...props\n}: ComponentPropsWithoutRef<'div'>) => (\n <div className={cn('flex-1', className)} {...props} />\n);\n\nconst Iframe = (props: ComponentProps<'iframe'>) => (\n <MarkDownIframe {...props} />\n);\n\n// Static configuration object for static renderers\nconst staticMarkdownComponents = {\n h1: H1Renderer,\n h2: H2Renderer,\n h3: H3Renderer,\n h4: H4Renderer,\n h5: H5Renderer,\n h6: H6Renderer,\n strong: StrongRenderer,\n blockquote: BlockquoteRenderer,\n ul: UlRenderer,\n ol: OlRenderer,\n img: ImgRenderer,\n pre: PreRenderer,\n table: TableRenderer,\n th: Th,\n tr: Tr,\n td: Td,\n hr: Hr,\n Tabs: TabsRenderer,\n Tab: Tab.Item,\n Columns: ColumnsRenderer,\n Column: ColumnRenderer,\n iframe: Iframe,\n};\n\n// Factory function to create components with dynamic props\nconst createMarkdownComponents = (\n isDarkMode?: boolean,\n locale?: LocalesValues\n) => ({\n ...staticMarkdownComponents,\n code: createCodeRenderer(isDarkMode),\n a: createLinkRenderer(locale),\n});\n\n// Export static renderers for backward compatibility\nexport const baseMarkdownComponents = staticMarkdownComponents;\n\ntype MarkdownRendererProps = {\n children: string | ParsedMarkdown;\n isDarkMode?: boolean;\n locale?: LocalesValues;\n forceBlock?: boolean;\n preserveFrontmatter?: boolean;\n tagfilter?: boolean;\n components?: ComponentProps<typeof MarkdownRendererIntlayer>['components'];\n wrapper?: ComponentProps<typeof MarkdownRendererIntlayer>['wrapper'];\n};\n\nexport const getIntlayerMarkdownOptions = (_isDarkMode?: boolean) => ({\n components: baseMarkdownComponents,\n});\n\nexport const MarkdownRenderer: FC<MarkdownRendererProps> = ({\n children,\n isDarkMode = false,\n locale,\n forceBlock,\n preserveFrontmatter,\n tagfilter,\n components: componentsProp,\n wrapper,\n}) => {\n const markdownComponents = createMarkdownComponents(isDarkMode, locale);\n\n const markdownContent = renderMarkdown(children, {\n components: {\n ...markdownComponents,\n ...componentsProp,\n },\n wrapper,\n forceBlock,\n preserveFrontmatter,\n tagfilter,\n });\n\n return (\n <CodeProvider>\n <TabProvider>{markdownContent}</TabProvider>\n </CodeProvider>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"MarkDownRender.mjs","names":[],"sources":["../../../../src/components/MarkDownRender/MarkDownRender.tsx"],"sourcesContent":["import type { LocalesValues } from '@intlayer/types/module_augmentation';\nimport { cn } from '@utils/cn';\nimport type { ComponentProps, ComponentPropsWithoutRef, FC } from 'react';\nimport { memo } from 'react';\nimport {\n type MarkdownRenderer as MarkdownRendererIntlayer,\n type ParsedMarkdown,\n renderMarkdown,\n} from 'react-intlayer/markdown';\n\nexport type { ParsedMarkdown };\n\nimport type { BundledLanguage } from 'shiki/bundle/web';\nimport { H1, H2, H3, H4, H5, H6 } from '../Headers';\nimport { Code } from '../IDE/Code';\nimport { CodeProvider } from '../IDE/CodeContext';\nimport { Link } from '../Link';\nimport { Tab } from '../Tab';\nimport { TabProvider } from '../Tab/TabContext';\nimport { Hr, SmartTable, Td, Th, Tr } from '../Table';\nimport { MarkDownIframe } from './MarkDownIframe';\n\n// Extracted, stable component renderers\nconst H1Renderer = (props: ComponentProps<'h1'>) => (\n <H1 isClickable className=\"mb-16 mb-8 text-text\" {...props} />\n);\nconst H2Renderer = (props: ComponentProps<'h2'>) => (\n <H2 isClickable className=\"mt-16 text-text\" {...props} />\n);\nconst H3Renderer = (props: ComponentProps<'h3'>) => (\n <H3 isClickable className=\"mt-5 text-text\" {...props} />\n);\nconst H4Renderer = (props: ComponentProps<'h4'>) => (\n <H4 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst H5Renderer = (props: ComponentProps<'h5'>) => (\n <H5 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst H6Renderer = (props: ComponentProps<'h6'>) => (\n <H6 isClickable className=\"mt-3 text-text\" {...props} />\n);\nconst StrongRenderer = (props: ComponentProps<'strong'>) => (\n <strong className=\"text-text\" {...props} />\n);\n\nconst MemoizedCodeBlock = memo(\n ({\n className,\n children,\n isDarkMode,\n lang, // Destructure html lang prop to prevent passing invalid BCP-47 language tag to Code component\n ...rest\n }: ComponentProps<'code'> & { isDarkMode?: boolean }) => {\n const content = String(children ?? '').replace(/\\n$/, '');\n const isBlock = !!className;\n\n if (!isBlock) {\n const decodedContent = content.replace(\n /&(?:amp;)?#(\\d+);/g,\n (_, code: string) => String.fromCharCode(parseInt(code, 10))\n );\n return (\n <code className=\"scale-80 rounded-md border border-neutral/30 bg-card/60 box-decoration-clone px-1.5 py-0.5 font-mono\">\n {decodedContent}\n </code>\n );\n }\n\n const language = (className?.replace(/lang(?:uage)?-/, '') ||\n 'plaintext') as BundledLanguage;\n\n return (\n <Code {...rest} language={language} showHeader isDarkMode={isDarkMode}>\n {content}\n </Code>\n );\n },\n (prevProps, nextProps) =>\n prevProps.children === nextProps.children &&\n prevProps.className === nextProps.className &&\n prevProps.isDarkMode === nextProps.isDarkMode\n);\n\nconst createCodeRenderer = (isDarkMode?: boolean) => {\n return function CodeWrapper(props: ComponentProps<'code'>) {\n return <MemoizedCodeBlock {...props} isDarkMode={isDarkMode} />;\n };\n};\n\nconst BlockquoteRenderer = ({\n className,\n ...props\n}: ComponentProps<'blockquote'>) => (\n <blockquote\n className={cn(\n 'mt-5 gap-3 border-card border-l-4 pl-5 text-neutral [&_strong]:text-neutral',\n className\n )}\n {...props}\n />\n);\n\nconst UlRenderer = ({ className, ...props }: ComponentProps<'ul'>) => (\n <ul\n className={cn(\n 'mt-5 flex list-disc flex-col gap-3 pl-5 marker:text-neutral/80',\n className\n )}\n {...props}\n />\n);\n\nconst OlRenderer = ({ className, ...props }: ComponentProps<'ol'>) => (\n <ol\n className={cn(\n 'mt-5 flex list-decimal flex-col gap-3 pl-5 marker:text-neutral/80',\n className\n )}\n {...props}\n />\n);\n\nconst ImgRenderer = ({\n className,\n alt,\n src,\n ...props\n}: ComponentProps<'img'>) => (\n <img\n {...props}\n alt={alt ?? ''}\n loading=\"lazy\"\n className={cn('max-h-[80vh] max-w-full rounded-md', className)}\n src={\n src?.includes('github.com')\n ? src\n ?.replace('github.com', 'raw.githubusercontent.com')\n .replace('/blob/', '/') // GitHub raw URLs do not use /blob/\n : src\n }\n />\n);\n\nconst createLinkRenderer = (locale?: LocalesValues) => {\n return (props: ComponentProps<'a'>) => (\n <Link\n isExternalLink={props.href?.startsWith('http')}\n underlined\n locale={locale}\n label=\"\"\n color=\"text\"\n {...(props as any)}\n />\n );\n};\n\nconst PreRenderer = (props: ComponentProps<'pre'>) => <>{props.children}</>;\nconst TableRenderer = (props: ComponentProps<typeof SmartTable>) => (\n <SmartTable isRollable displayModal {...props} />\n);\n\nconst TabsRenderer = (props: ComponentProps<typeof Tab>) => (\n <Tab\n {...props}\n className=\"rounded-xl border border-card\"\n headerClassName=\"sticky rounded-xl top-24 z-5 bg-background/70 backdrop-blur overflow-x-auto\"\n />\n);\nconst ColumnsRenderer = ({\n className,\n ...props\n}: ComponentPropsWithoutRef<'div'>) => (\n <div className={cn('flex gap-4 max-md:flex-col', className)} {...props} />\n);\nconst ColumnRenderer = ({\n className,\n ...props\n}: ComponentPropsWithoutRef<'div'>) => (\n <div className={cn('flex-1', className)} {...props} />\n);\n\nconst Iframe = (props: ComponentProps<'iframe'>) => (\n <MarkDownIframe {...props} />\n);\n\n// Static configuration object for static renderers\nconst staticMarkdownComponents = {\n h1: H1Renderer,\n h2: H2Renderer,\n h3: H3Renderer,\n h4: H4Renderer,\n h5: H5Renderer,\n h6: H6Renderer,\n strong: StrongRenderer,\n blockquote: BlockquoteRenderer,\n ul: UlRenderer,\n ol: OlRenderer,\n img: ImgRenderer,\n pre: PreRenderer,\n table: TableRenderer,\n th: Th,\n tr: Tr,\n td: Td,\n hr: Hr,\n Tabs: TabsRenderer,\n Tab: Tab.Item,\n Columns: ColumnsRenderer,\n Column: ColumnRenderer,\n iframe: Iframe,\n};\n\n// Factory function to create components with dynamic props\nconst createMarkdownComponents = (\n isDarkMode?: boolean,\n locale?: LocalesValues\n) => ({\n ...staticMarkdownComponents,\n code: createCodeRenderer(isDarkMode),\n a: createLinkRenderer(locale),\n});\n\n// Export static renderers for backward compatibility\nexport const baseMarkdownComponents = staticMarkdownComponents;\n\ntype MarkdownRendererProps = {\n children: string | ParsedMarkdown;\n isDarkMode?: boolean;\n locale?: LocalesValues;\n forceBlock?: boolean;\n preserveFrontmatter?: boolean;\n tagfilter?: boolean;\n components?: ComponentProps<typeof MarkdownRendererIntlayer>['components'];\n wrapper?: ComponentProps<typeof MarkdownRendererIntlayer>['wrapper'];\n};\n\nexport const getIntlayerMarkdownOptions = (_isDarkMode?: boolean) => ({\n components: baseMarkdownComponents,\n});\n\nexport const MarkdownRenderer: FC<MarkdownRendererProps> = ({\n children,\n isDarkMode = false,\n locale,\n forceBlock,\n preserveFrontmatter,\n tagfilter,\n components: componentsProp,\n wrapper,\n}) => {\n const markdownComponents = createMarkdownComponents(isDarkMode, locale);\n\n const markdownContent = renderMarkdown(children, {\n components: {\n ...markdownComponents,\n ...componentsProp,\n },\n wrapper,\n forceBlock,\n preserveFrontmatter,\n tagfilter,\n });\n\n return (\n <CodeProvider>\n <TabProvider>{markdownContent}</TabProvider>\n </CodeProvider>\n );\n};\n"],"mappings":"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"}
@@ -0,0 +1,113 @@
1
+ 'use client';
2
+
3
+ import { cn } from "../../utils/cn.mjs";
4
+ import { EditorCommand, EditorCommandList } from "./novel/components/editor-command.mjs";
5
+ import { EditorContent, EditorRoot } from "./novel/components/editor.mjs";
6
+ import { EditorBubble } from "./novel/components/editor-bubble.mjs";
7
+ import { EditorCommandEmpty, EditorCommandItem } from "./novel/components/editor-command-item.mjs";
8
+ import { ImageResizer } from "./novel/extensions/image-resizer.mjs";
9
+ import { handleCommandNavigation } from "./novel/extensions/slash-command.mjs";
10
+ import { handleImageDrop, handleImagePaste } from "./novel/plugins/upload-images.mjs";
11
+ import { createEditorUploadFn } from "./imageUpload.mjs";
12
+ import { defaultExtensions } from "./extensions.mjs";
13
+ import { GenerativeMenuSwitch } from "./generative/GenerativeMenuSwitch.mjs";
14
+ import { ColorSelector } from "./selectors/ColorSelector.mjs";
15
+ import { LinkSelector } from "./selectors/LinkSelector.mjs";
16
+ import { NodeSelector } from "./selectors/NodeSelector.mjs";
17
+ import { TextButtons } from "./selectors/TextButtons.mjs";
18
+ import { createSlashCommand } from "./slashCommand.mjs";
19
+ import { useMemo, useState } from "react";
20
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
21
+ import { useIntlayer } from "react-intlayer";
22
+
23
+ //#region src/components/MarkdownEditor/MarkdownEditor.tsx
24
+ const Divider = () => /* @__PURE__ */ jsx("div", { className: "h-full w-px shrink-0 bg-border" });
25
+ /**
26
+ * Notion-style WYSIWYG markdown editor built on Novel / Tiptap.
27
+ *
28
+ * Features a slash command menu, a formatting bubble menu (node / link / color
29
+ * / inline marks), image upload (drop / paste / slash), and an optional
30
+ * AI assistant wired to the Intlayer AI backend.
31
+ *
32
+ * The value contract is markdown: pass `defaultValue` as a markdown string and
33
+ * read changes from `onChange`.
34
+ */
35
+ const MarkdownEditor = ({ defaultValue, onChange, editable = true, enableAI = true, uploadImage, maxImageSizeMb, className }) => {
36
+ const [openAI, setOpenAI] = useState(false);
37
+ const content = useIntlayer("markdown-editor");
38
+ const uploadFn = useMemo(() => createEditorUploadFn({
39
+ uploadImage,
40
+ maxSizeMb: maxImageSizeMb
41
+ }), [uploadImage, maxImageSizeMb]);
42
+ const { extensions, suggestionItems } = useMemo(() => {
43
+ const { slashCommand, suggestionItems: items } = createSlashCommand(uploadFn, content);
44
+ return {
45
+ extensions: [...defaultExtensions, slashCommand],
46
+ suggestionItems: items
47
+ };
48
+ }, [uploadFn, content]);
49
+ const initialContent = defaultValue ?? "";
50
+ const handleUpdate = ({ editor }) => {
51
+ onChange?.(editor.storage.markdown.getMarkdown());
52
+ };
53
+ const toolbar = /* @__PURE__ */ jsxs(Fragment$1, { children: [
54
+ /* @__PURE__ */ jsx(NodeSelector, {}),
55
+ /* @__PURE__ */ jsx(Divider, {}),
56
+ /* @__PURE__ */ jsx(LinkSelector, {}),
57
+ /* @__PURE__ */ jsx(Divider, {}),
58
+ /* @__PURE__ */ jsx(TextButtons, {}),
59
+ /* @__PURE__ */ jsx(Divider, {}),
60
+ /* @__PURE__ */ jsx(ColorSelector, {})
61
+ ] });
62
+ return /* @__PURE__ */ jsx("div", {
63
+ className: "relative w-full",
64
+ children: /* @__PURE__ */ jsx(EditorRoot, { children: /* @__PURE__ */ jsxs(EditorContent, {
65
+ immediatelyRender: false,
66
+ editable,
67
+ initialContent,
68
+ extensions,
69
+ className: cn("min-h-[350px] w-full max-w-full", className),
70
+ editorProps: {
71
+ handleDOMEvents: { keydown: (_view, event) => handleCommandNavigation(event) },
72
+ handlePaste: (view, event) => handleImagePaste(view, event, uploadFn),
73
+ handleDrop: (view, event, _slice, moved) => handleImageDrop(view, event, moved, uploadFn),
74
+ attributes: { class: "max-w-full pl-6 focus:outline-none" }
75
+ },
76
+ onUpdate: handleUpdate,
77
+ slotAfter: /* @__PURE__ */ jsx(ImageResizer, {}),
78
+ children: [/* @__PURE__ */ jsxs(EditorCommand, {
79
+ className: "z-50 h-auto max-h-[330px] overflow-y-auto px-1 py-2 shadow-md transition-all",
80
+ children: [/* @__PURE__ */ jsx(EditorCommandEmpty, {
81
+ className: "px-2 text-muted-foreground",
82
+ children: content.noResults.value
83
+ }), /* @__PURE__ */ jsx(EditorCommandList, { children: suggestionItems.map((item) => /* @__PURE__ */ jsxs(EditorCommandItem, {
84
+ value: item.title,
85
+ onCommand: (val) => item.command?.(val),
86
+ className: "flex w-full items-center space-x-2 rounded-md px-2 py-1 text-left text-sm hover:bg-accent aria-selected:bg-accent",
87
+ children: [/* @__PURE__ */ jsx("div", {
88
+ className: "flex size-10 items-center justify-center rounded-md border border-card bg-background",
89
+ children: item.icon
90
+ }), /* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx("p", {
91
+ className: "font-medium",
92
+ children: item.title
93
+ }), /* @__PURE__ */ jsx("p", {
94
+ className: "text-muted-foreground text-xs",
95
+ children: item.description
96
+ })] })]
97
+ }, item.title)) })]
98
+ }), enableAI ? /* @__PURE__ */ jsx(GenerativeMenuSwitch, {
99
+ open: openAI,
100
+ onOpenChange: setOpenAI,
101
+ children: toolbar
102
+ }) : /* @__PURE__ */ jsx(EditorBubble, {
103
+ options: { placement: "top" },
104
+ className: "flex w-fit max-w-[90vw] rounded-lg border-[1.3px] border-neutral/20 bg-card/95 text-text shadow-xl backdrop-blur [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl",
105
+ children: toolbar
106
+ })]
107
+ }) })
108
+ });
109
+ };
110
+
111
+ //#endregion
112
+ export { MarkdownEditor };
113
+ //# sourceMappingURL=MarkdownEditor.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MarkdownEditor.mjs","names":[],"sources":["../../../../src/components/MarkdownEditor/MarkdownEditor.tsx"],"sourcesContent":["'use client';\n\nimport { cn } from '@utils/cn';\nimport { type FC, useMemo, useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { defaultExtensions } from './extensions';\nimport { GenerativeMenuSwitch } from './generative/GenerativeMenuSwitch';\nimport {\n type CreateEditorUploadFnOptions,\n createEditorUploadFn,\n} from './imageUpload';\nimport {\n EditorBubble,\n EditorCommand,\n EditorCommandEmpty,\n EditorCommandItem,\n EditorCommandList,\n EditorContent,\n type EditorInstance,\n EditorRoot,\n handleCommandNavigation,\n handleImageDrop,\n handleImagePaste,\n ImageResizer,\n type JSONContent,\n} from './novel';\nimport { ColorSelector } from './selectors/ColorSelector';\nimport { LinkSelector } from './selectors/LinkSelector';\nimport { NodeSelector } from './selectors/NodeSelector';\nimport { TextButtons } from './selectors/TextButtons';\nimport { createSlashCommand } from './slashCommand';\n\nconst Divider = () => <div className=\"h-full w-px shrink-0 bg-border\" />;\n\nexport type MarkdownEditorProps = {\n /** Initial markdown value. */\n defaultValue?: string;\n /** Called with the serialized markdown on every change. */\n onChange?: (markdown: string) => void;\n /** Whether the document can be edited. Defaults to `true`. */\n editable?: boolean;\n /** Enables the AI bubble menu (\"Ask AI\"). Defaults to `true`. */\n enableAI?: boolean;\n /**\n * Custom image uploader. When omitted, images are embedded inline as base64\n * data URLs (no backend required).\n */\n uploadImage?: CreateEditorUploadFnOptions['uploadImage'];\n /** Maximum allowed image size in megabytes. Defaults to `20`. */\n maxImageSizeMb?: number;\n /** Class applied to the editor surface. */\n className?: string;\n};\n\n/**\n * Notion-style WYSIWYG markdown editor built on Novel / Tiptap.\n *\n * Features a slash command menu, a formatting bubble menu (node / link / color\n * / inline marks), image upload (drop / paste / slash), and an optional\n * AI assistant wired to the Intlayer AI backend.\n *\n * The value contract is markdown: pass `defaultValue` as a markdown string and\n * read changes from `onChange`.\n */\nexport const MarkdownEditor: FC<MarkdownEditorProps> = ({\n defaultValue,\n onChange,\n editable = true,\n enableAI = true,\n uploadImage,\n maxImageSizeMb,\n className,\n}) => {\n const [openAI, setOpenAI] = useState(false);\n const content = useIntlayer('markdown-editor');\n\n const uploadFn = useMemo(\n () => createEditorUploadFn({ uploadImage, maxSizeMb: maxImageSizeMb }),\n [uploadImage, maxImageSizeMb]\n );\n\n const { extensions, suggestionItems } = useMemo(() => {\n const { slashCommand, suggestionItems: items } = createSlashCommand(\n uploadFn,\n content\n );\n\n return {\n extensions: [...defaultExtensions, slashCommand],\n suggestionItems: items,\n };\n }, [uploadFn, content]);\n\n const initialContent = (defaultValue ?? '') as unknown as JSONContent;\n\n const handleUpdate = ({ editor }: { editor: EditorInstance }) => {\n onChange?.(editor.storage.markdown.getMarkdown() as string);\n };\n\n const toolbar = (\n <>\n <NodeSelector />\n <Divider />\n <LinkSelector />\n <Divider />\n <TextButtons />\n <Divider />\n <ColorSelector />\n </>\n );\n\n return (\n <div className=\"relative w-full\">\n <EditorRoot>\n <EditorContent\n immediatelyRender={false}\n editable={editable}\n initialContent={initialContent}\n extensions={extensions}\n className={cn('min-h-[350px] w-full max-w-full', className)}\n editorProps={{\n handleDOMEvents: {\n keydown: (_view, event) => handleCommandNavigation(event),\n },\n handlePaste: (view, event) =>\n handleImagePaste(view, event, uploadFn),\n handleDrop: (view, event, _slice, moved) =>\n handleImageDrop(view, event, moved, uploadFn),\n attributes: {\n // Content typography (headings, lists, spacing) is defined in\n // `markdown-editor.css`, scoped to `.ProseMirror` — this project\n // has no Tailwind `prose` plugin.\n class: 'max-w-full pl-6 focus:outline-none',\n },\n }}\n onUpdate={handleUpdate}\n slotAfter={<ImageResizer />}\n >\n <EditorCommand className=\"z-50 h-auto max-h-[330px] overflow-y-auto px-1 py-2 shadow-md transition-all\">\n <EditorCommandEmpty className=\"px-2 text-muted-foreground\">\n {content.noResults.value}\n </EditorCommandEmpty>\n <EditorCommandList>\n {suggestionItems.map((item) => (\n <EditorCommandItem\n value={item.title}\n onCommand={(val) => item.command?.(val)}\n className=\"flex w-full items-center space-x-2 rounded-md px-2 py-1 text-left text-sm hover:bg-accent aria-selected:bg-accent\"\n key={item.title}\n >\n <div className=\"flex size-10 items-center justify-center rounded-md border border-card bg-background\">\n {item.icon}\n </div>\n <div>\n <p className=\"font-medium\">{item.title}</p>\n <p className=\"text-muted-foreground text-xs\">\n {item.description}\n </p>\n </div>\n </EditorCommandItem>\n ))}\n </EditorCommandList>\n </EditorCommand>\n\n {enableAI ? (\n <GenerativeMenuSwitch open={openAI} onOpenChange={setOpenAI}>\n {toolbar}\n </GenerativeMenuSwitch>\n ) : (\n <EditorBubble\n options={{ placement: 'top' }}\n className=\"flex w-fit max-w-[90vw] rounded-lg border-[1.3px] border-neutral/20 bg-card/95 text-text shadow-xl backdrop-blur [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl\"\n >\n {toolbar}\n </EditorBubble>\n )}\n </EditorContent>\n </EditorRoot>\n </div>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAM,gBAAgB,oBAAC,OAAD,EAAK,WAAU,kCAAmC;;;;;;;;;;;AAgCxE,MAAa,kBAA2C,EACtD,cACA,UACA,WAAW,MACX,WAAW,MACX,aACA,gBACA,gBACI;CACJ,MAAM,CAAC,QAAQ,aAAa,SAAS,MAAM;CAC3C,MAAM,UAAU,YAAY,kBAAkB;CAE9C,MAAM,WAAW,cACT,qBAAqB;EAAE;EAAa,WAAW;EAAgB,CAAC,EACtE,CAAC,aAAa,eAAe,CAC9B;CAED,MAAM,EAAE,YAAY,oBAAoB,cAAc;EACpD,MAAM,EAAE,cAAc,iBAAiB,UAAU,mBAC/C,UACA,QACD;AAED,SAAO;GACL,YAAY,CAAC,GAAG,mBAAmB,aAAa;GAChD,iBAAiB;GAClB;IACA,CAAC,UAAU,QAAQ,CAAC;CAEvB,MAAM,iBAAkB,gBAAgB;CAExC,MAAM,gBAAgB,EAAE,aAAyC;AAC/D,aAAW,OAAO,QAAQ,SAAS,aAAa,CAAW;;CAG7D,MAAM,UACJ;EACE,oBAAC,cAAD,EAAgB;EAChB,oBAAC,SAAD,EAAW;EACX,oBAAC,cAAD,EAAgB;EAChB,oBAAC,SAAD,EAAW;EACX,oBAAC,aAAD,EAAe;EACf,oBAAC,SAAD,EAAW;EACX,oBAAC,eAAD,EAAiB;EAChB;AAGL,QACE,oBAAC,OAAD;EAAK,WAAU;YACb,oBAAC,YAAD,YACE,qBAAC,eAAD;GACE,mBAAmB;GACT;GACM;GACJ;GACZ,WAAW,GAAG,mCAAmC,UAAU;GAC3D,aAAa;IACX,iBAAiB,EACf,UAAU,OAAO,UAAU,wBAAwB,MAAM,EAC1D;IACD,cAAc,MAAM,UAClB,iBAAiB,MAAM,OAAO,SAAS;IACzC,aAAa,MAAM,OAAO,QAAQ,UAChC,gBAAgB,MAAM,OAAO,OAAO,SAAS;IAC/C,YAAY,EAIV,OAAO,sCACR;IACF;GACD,UAAU;GACV,WAAW,oBAAC,cAAD,EAAgB;aAtB7B,CAwBE,qBAAC,eAAD;IAAe,WAAU;cAAzB,CACE,oBAAC,oBAAD;KAAoB,WAAU;eAC3B,QAAQ,UAAU;KACA,GACrB,oBAAC,mBAAD,YACG,gBAAgB,KAAK,SACpB,qBAAC,mBAAD;KACE,OAAO,KAAK;KACZ,YAAY,QAAQ,KAAK,UAAU,IAAI;KACvC,WAAU;eAHZ,CAME,oBAAC,OAAD;MAAK,WAAU;gBACZ,KAAK;MACF,GACN,qBAAC,OAAD,aACE,oBAAC,KAAD;MAAG,WAAU;gBAAe,KAAK;MAAU,GAC3C,oBAAC,KAAD;MAAG,WAAU;gBACV,KAAK;MACJ,EACA,IACY;OAXb,KAAK,MAWQ,CACpB,EACgB,EACN;OAEf,WACC,oBAAC,sBAAD;IAAsB,MAAM;IAAQ,cAAc;cAC/C;IACoB,IAEvB,oBAAC,cAAD;IACE,SAAS,EAAE,WAAW,OAAO;IAC7B,WAAU;cAET;IACY,EAEH;MACL;EACT"}
@@ -0,0 +1,103 @@
1
+ import CustomKeymap from "./novel/extensions/custom-keymap.mjs";
2
+ import UpdatedImage from "./novel/extensions/updated-image.mjs";
3
+ import { AIHighlight } from "./novel/extensions/ai-highlight.mjs";
4
+ import { CharacterCount, Color, GlobalDragHandle, HighlightExtension, HorizontalRule as Horizontal, MarkdownExtension, Placeholder as PlaceholderExtension, StarterKit, TaskItem, TaskList, TextStyle, TiptapImage, TiptapLink, TiptapUnderline, Youtube } from "./novel/extensions/index.mjs";
5
+ import { UploadImagesPlugin } from "./novel/plugins/upload-images.mjs";
6
+ import { cx } from "class-variance-authority";
7
+ import { CodeBlockShiki } from "tiptap-extension-code-block-shiki";
8
+
9
+ //#region src/components/MarkdownEditor/extensions.ts
10
+ const aiHighlight = AIHighlight;
11
+ const tiptapLink = TiptapLink.configure({ HTMLAttributes: { class: cx("text-muted-foreground underline underline-offset-[3px] hover:text-primary transition-colors cursor-pointer") } });
12
+ const tiptapImage = TiptapImage.extend({ addProseMirrorPlugins() {
13
+ return [UploadImagesPlugin({ imageClass: cx("opacity-40 rounded-lg border border-stone-200") })];
14
+ } }).configure({
15
+ allowBase64: true,
16
+ HTMLAttributes: { class: cx("rounded-lg border border-muted") }
17
+ });
18
+ const updatedImage = UpdatedImage.configure({ HTMLAttributes: { class: cx("rounded-lg border border-muted") } });
19
+ const taskList = TaskList.configure({ HTMLAttributes: { class: cx("not-prose pl-2") } });
20
+ const taskItem = TaskItem.configure({
21
+ HTMLAttributes: { class: cx("flex gap-2 items-start my-4") },
22
+ nested: true
23
+ });
24
+ const horizontalRule = Horizontal.configure({ HTMLAttributes: { class: cx("mt-4 mb-6 border-t border-muted-foreground") } });
25
+ const starterKit = StarterKit.configure({
26
+ bulletList: { HTMLAttributes: { class: cx("list-disc list-outside leading-3 -mt-2") } },
27
+ orderedList: { HTMLAttributes: { class: cx("list-decimal list-outside leading-3 -mt-2") } },
28
+ listItem: { HTMLAttributes: { class: cx("leading-normal -mb-2") } },
29
+ blockquote: { HTMLAttributes: { class: cx("border-l-4 border-primary") } },
30
+ codeBlock: false,
31
+ code: { HTMLAttributes: {
32
+ class: cx("rounded-md bg-muted px-1.5 py-1 font-mono font-medium"),
33
+ spellcheck: "false"
34
+ } },
35
+ horizontalRule: false,
36
+ dropcursor: {
37
+ color: "#DBEAFE",
38
+ width: 4
39
+ },
40
+ gapcursor: false
41
+ });
42
+ /**
43
+ * Code block with syntax highlighting powered by shiki (the same highlighter
44
+ * the rest of the design-system uses in `IDE/CodeBlockShiki` and
45
+ * `MarkDownRender`). Languages are lazy-loaded on demand and the dual
46
+ * `github-light` / `github-dark` themes emit `--shiki-dark` CSS variables that
47
+ * `markdown-editor.css` toggles under `[data-theme="dark"]`.
48
+ */
49
+ const codeBlock = CodeBlockShiki.configure({
50
+ defaultLanguage: null,
51
+ defaultTheme: "github-light",
52
+ themes: {
53
+ light: "github-light",
54
+ dark: "github-dark"
55
+ },
56
+ HTMLAttributes: { class: cx("rounded-md bg-muted text-muted-foreground border p-5 font-mono font-medium") }
57
+ });
58
+ const youtube = Youtube.configure({
59
+ HTMLAttributes: { class: cx("rounded-lg border border-muted") },
60
+ inline: false
61
+ });
62
+ const characterCount = CharacterCount.configure();
63
+ const markdownExtension = MarkdownExtension.configure({
64
+ html: true,
65
+ tightLists: true,
66
+ tightListClass: "tight",
67
+ bulletListMarker: "-",
68
+ linkify: false,
69
+ breaks: false,
70
+ transformPastedText: false,
71
+ transformCopiedText: false
72
+ });
73
+ /**
74
+ * Default Tiptap/Novel extensions powering the MarkdownEditor.
75
+ *
76
+ * The slash-command extension is intentionally not included here because it
77
+ * needs a runtime image-upload handler; it is appended by the editor itself.
78
+ */
79
+ const defaultExtensions = [
80
+ starterKit,
81
+ PlaceholderExtension,
82
+ tiptapLink,
83
+ tiptapImage,
84
+ updatedImage,
85
+ taskList,
86
+ taskItem,
87
+ horizontalRule,
88
+ aiHighlight,
89
+ codeBlock,
90
+ youtube,
91
+ characterCount,
92
+ TiptapUnderline,
93
+ markdownExtension,
94
+ HighlightExtension,
95
+ TextStyle,
96
+ Color,
97
+ CustomKeymap,
98
+ GlobalDragHandle
99
+ ];
100
+
101
+ //#endregion
102
+ export { defaultExtensions };
103
+ //# sourceMappingURL=extensions.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extensions.mjs","names":["HorizontalRule","Placeholder"],"sources":["../../../../src/components/MarkdownEditor/extensions.ts"],"sourcesContent":["import { cx } from 'class-variance-authority';\nimport { CodeBlockShiki } from 'tiptap-extension-code-block-shiki';\nimport {\n AIHighlight,\n CharacterCount,\n Color,\n CustomKeymap,\n GlobalDragHandle,\n HighlightExtension,\n HorizontalRule,\n MarkdownExtension,\n Placeholder,\n StarterKit,\n TaskItem,\n TaskList,\n TextStyle,\n TiptapImage,\n TiptapLink,\n TiptapUnderline,\n UpdatedImage,\n UploadImagesPlugin,\n Youtube,\n} from './novel';\n\nconst aiHighlight = AIHighlight;\n\nconst tiptapLink = TiptapLink.configure({\n HTMLAttributes: {\n class: cx(\n 'text-muted-foreground underline underline-offset-[3px] hover:text-primary transition-colors cursor-pointer'\n ),\n },\n});\n\nconst tiptapImage = TiptapImage.extend({\n addProseMirrorPlugins() {\n return [\n UploadImagesPlugin({\n imageClass: cx('opacity-40 rounded-lg border border-stone-200'),\n }),\n ];\n },\n}).configure({\n allowBase64: true,\n HTMLAttributes: {\n class: cx('rounded-lg border border-muted'),\n },\n});\n\nconst updatedImage = UpdatedImage.configure({\n HTMLAttributes: {\n class: cx('rounded-lg border border-muted'),\n },\n});\n\nconst taskList = TaskList.configure({\n HTMLAttributes: {\n class: cx('not-prose pl-2'),\n },\n});\n\nconst taskItem = TaskItem.configure({\n HTMLAttributes: {\n class: cx('flex gap-2 items-start my-4'),\n },\n nested: true,\n});\n\nconst horizontalRule = HorizontalRule.configure({\n HTMLAttributes: {\n class: cx('mt-4 mb-6 border-t border-muted-foreground'),\n },\n});\n\nconst starterKit = StarterKit.configure({\n bulletList: {\n HTMLAttributes: {\n class: cx('list-disc list-outside leading-3 -mt-2'),\n },\n },\n orderedList: {\n HTMLAttributes: {\n class: cx('list-decimal list-outside leading-3 -mt-2'),\n },\n },\n listItem: {\n HTMLAttributes: {\n class: cx('leading-normal -mb-2'),\n },\n },\n blockquote: {\n HTMLAttributes: {\n class: cx('border-l-4 border-primary'),\n },\n },\n // Disabled in favor of the shiki-powered `codeBlock` extension below.\n codeBlock: false,\n code: {\n HTMLAttributes: {\n class: cx('rounded-md bg-muted px-1.5 py-1 font-mono font-medium'),\n spellcheck: 'false',\n },\n },\n horizontalRule: false,\n dropcursor: {\n color: '#DBEAFE',\n width: 4,\n },\n gapcursor: false,\n});\n\n/**\n * Code block with syntax highlighting powered by shiki (the same highlighter\n * the rest of the design-system uses in `IDE/CodeBlockShiki` and\n * `MarkDownRender`). Languages are lazy-loaded on demand and the dual\n * `github-light` / `github-dark` themes emit `--shiki-dark` CSS variables that\n * `markdown-editor.css` toggles under `[data-theme=\"dark\"]`.\n */\nconst codeBlock = CodeBlockShiki.configure({\n defaultLanguage: null,\n defaultTheme: 'github-light',\n themes: {\n light: 'github-light',\n dark: 'github-dark',\n },\n HTMLAttributes: {\n class: cx(\n 'rounded-md bg-muted text-muted-foreground border p-5 font-mono font-medium'\n ),\n },\n});\n\nconst youtube = Youtube.configure({\n HTMLAttributes: {\n class: cx('rounded-lg border border-muted'),\n },\n inline: false,\n});\n\nconst characterCount = CharacterCount.configure();\n\nconst markdownExtension = MarkdownExtension.configure({\n html: true,\n tightLists: true,\n tightListClass: 'tight',\n bulletListMarker: '-',\n linkify: false,\n breaks: false,\n transformPastedText: false,\n transformCopiedText: false,\n});\n\n/**\n * Default Tiptap/Novel extensions powering the MarkdownEditor.\n *\n * The slash-command extension is intentionally not included here because it\n * needs a runtime image-upload handler; it is appended by the editor itself.\n */\nexport const defaultExtensions = [\n starterKit,\n Placeholder,\n tiptapLink,\n tiptapImage,\n updatedImage,\n taskList,\n taskItem,\n horizontalRule,\n aiHighlight,\n codeBlock,\n youtube,\n characterCount,\n TiptapUnderline,\n markdownExtension,\n HighlightExtension,\n TextStyle,\n Color,\n CustomKeymap,\n GlobalDragHandle,\n];\n"],"mappings":";;;;;;;;;AAwBA,MAAM,cAAc;AAEpB,MAAM,aAAa,WAAW,UAAU,EACtC,gBAAgB,EACd,OAAO,GACL,6GACD,EACF,EACF,CAAC;AAEF,MAAM,cAAc,YAAY,OAAO,EACrC,wBAAwB;AACtB,QAAO,CACL,mBAAmB,EACjB,YAAY,GAAG,gDAAgD,EAChE,CAAC,CACH;GAEJ,CAAC,CAAC,UAAU;CACX,aAAa;CACb,gBAAgB,EACd,OAAO,GAAG,iCAAiC,EAC5C;CACF,CAAC;AAEF,MAAM,eAAe,aAAa,UAAU,EAC1C,gBAAgB,EACd,OAAO,GAAG,iCAAiC,EAC5C,EACF,CAAC;AAEF,MAAM,WAAW,SAAS,UAAU,EAClC,gBAAgB,EACd,OAAO,GAAG,iBAAiB,EAC5B,EACF,CAAC;AAEF,MAAM,WAAW,SAAS,UAAU;CAClC,gBAAgB,EACd,OAAO,GAAG,8BAA8B,EACzC;CACD,QAAQ;CACT,CAAC;AAEF,MAAM,iBAAiBA,WAAe,UAAU,EAC9C,gBAAgB,EACd,OAAO,GAAG,6CAA6C,EACxD,EACF,CAAC;AAEF,MAAM,aAAa,WAAW,UAAU;CACtC,YAAY,EACV,gBAAgB,EACd,OAAO,GAAG,yCAAyC,EACpD,EACF;CACD,aAAa,EACX,gBAAgB,EACd,OAAO,GAAG,4CAA4C,EACvD,EACF;CACD,UAAU,EACR,gBAAgB,EACd,OAAO,GAAG,uBAAuB,EAClC,EACF;CACD,YAAY,EACV,gBAAgB,EACd,OAAO,GAAG,4BAA4B,EACvC,EACF;CAED,WAAW;CACX,MAAM,EACJ,gBAAgB;EACd,OAAO,GAAG,wDAAwD;EAClE,YAAY;EACb,EACF;CACD,gBAAgB;CAChB,YAAY;EACV,OAAO;EACP,OAAO;EACR;CACD,WAAW;CACZ,CAAC;;;;;;;;AASF,MAAM,YAAY,eAAe,UAAU;CACzC,iBAAiB;CACjB,cAAc;CACd,QAAQ;EACN,OAAO;EACP,MAAM;EACP;CACD,gBAAgB,EACd,OAAO,GACL,6EACD,EACF;CACF,CAAC;AAEF,MAAM,UAAU,QAAQ,UAAU;CAChC,gBAAgB,EACd,OAAO,GAAG,iCAAiC,EAC5C;CACD,QAAQ;CACT,CAAC;AAEF,MAAM,iBAAiB,eAAe,WAAW;AAEjD,MAAM,oBAAoB,kBAAkB,UAAU;CACpD,MAAM;CACN,YAAY;CACZ,gBAAgB;CAChB,kBAAkB;CAClB,SAAS;CACT,QAAQ;CACR,qBAAqB;CACrB,qBAAqB;CACtB,CAAC;;;;;;;AAQF,MAAa,oBAAoB;CAC/B;CACAC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD"}
@@ -0,0 +1,51 @@
1
+ 'use client';
2
+
3
+ import { Command } from "../../Command/index.mjs";
4
+ import { useEditor } from "../novel/components/index.mjs";
5
+ import { Check, TextQuote, TrashIcon } from "lucide-react";
6
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
+ import { useIntlayer } from "react-intlayer";
8
+
9
+ //#region src/components/MarkdownEditor/generative/AICompletionCommands.tsx
10
+ /**
11
+ * Command list shown once the AI has produced a completion: replace the
12
+ * selection, insert below, or discard.
13
+ */
14
+ const AICompletionCommands = ({ completion, onDiscard }) => {
15
+ const { editor } = useEditor();
16
+ const content = useIntlayer("markdown-editor");
17
+ if (!editor) return null;
18
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
19
+ /* @__PURE__ */ jsxs(Command.Group, { children: [/* @__PURE__ */ jsxs(Command.Item, {
20
+ value: "replace",
21
+ className: "gap-2 px-4",
22
+ onSelect: () => {
23
+ const { selection } = editor.view.state;
24
+ editor.chain().focus().insertContentAt({
25
+ from: selection.from,
26
+ to: selection.to
27
+ }, completion).run();
28
+ },
29
+ children: [/* @__PURE__ */ jsx(Check, { className: "size-4 text-muted-foreground" }), content.replaceSelection]
30
+ }), /* @__PURE__ */ jsxs(Command.Item, {
31
+ value: "insert",
32
+ className: "gap-2 px-4",
33
+ onSelect: () => {
34
+ const { selection } = editor.view.state;
35
+ editor.chain().focus().insertContentAt(selection.to + 1, completion).run();
36
+ },
37
+ children: [/* @__PURE__ */ jsx(TextQuote, { className: "size-4 text-muted-foreground" }), content.insertBelow]
38
+ })] }),
39
+ /* @__PURE__ */ jsx(Command.Separator, {}),
40
+ /* @__PURE__ */ jsx(Command.Group, { children: /* @__PURE__ */ jsxs(Command.Item, {
41
+ value: "discard",
42
+ className: "gap-2 px-4",
43
+ onSelect: onDiscard,
44
+ children: [/* @__PURE__ */ jsx(TrashIcon, { className: "size-4 text-muted-foreground" }), content.discard]
45
+ }) })
46
+ ] });
47
+ };
48
+
49
+ //#endregion
50
+ export { AICompletionCommands };
51
+ //# sourceMappingURL=AICompletionCommands.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AICompletionCommands.mjs","names":[],"sources":["../../../../../src/components/MarkdownEditor/generative/AICompletionCommands.tsx"],"sourcesContent":["'use client';\n\nimport { Command } from '@components/Command';\nimport { Check, TextQuote, TrashIcon } from 'lucide-react';\nimport { useIntlayer } from 'react-intlayer';\nimport { useEditor } from '../novel';\n\nexport type AICompletionCommandsProps = {\n completion: string;\n onDiscard: () => void;\n};\n\n/**\n * Command list shown once the AI has produced a completion: replace the\n * selection, insert below, or discard.\n */\nexport const AICompletionCommands = ({\n completion,\n onDiscard,\n}: AICompletionCommandsProps) => {\n const { editor } = useEditor();\n const content = useIntlayer('markdown-editor');\n\n if (!editor) return null;\n\n return (\n <>\n <Command.Group>\n <Command.Item\n value=\"replace\"\n className=\"gap-2 px-4\"\n onSelect={() => {\n const { selection } = editor.view.state;\n editor\n .chain()\n .focus()\n .insertContentAt(\n { from: selection.from, to: selection.to },\n completion\n )\n .run();\n }}\n >\n <Check className=\"size-4 text-muted-foreground\" />\n {content.replaceSelection}\n </Command.Item>\n <Command.Item\n value=\"insert\"\n className=\"gap-2 px-4\"\n onSelect={() => {\n const { selection } = editor.view.state;\n editor\n .chain()\n .focus()\n .insertContentAt(selection.to + 1, completion)\n .run();\n }}\n >\n <TextQuote className=\"size-4 text-muted-foreground\" />\n {content.insertBelow}\n </Command.Item>\n </Command.Group>\n <Command.Separator />\n <Command.Group>\n <Command.Item\n value=\"discard\"\n className=\"gap-2 px-4\"\n onSelect={onDiscard}\n >\n <TrashIcon className=\"size-4 text-muted-foreground\" />\n {content.discard}\n </Command.Item>\n </Command.Group>\n </>\n );\n};\n"],"mappings":";;;;;;;;;;;;;AAgBA,MAAa,wBAAwB,EACnC,YACA,gBAC+B;CAC/B,MAAM,EAAE,WAAW,WAAW;CAC9B,MAAM,UAAU,YAAY,kBAAkB;AAE9C,KAAI,CAAC,OAAQ,QAAO;AAEpB,QACE;EACE,qBAAC,QAAQ,OAAT,aACE,qBAAC,QAAQ,MAAT;GACE,OAAM;GACN,WAAU;GACV,gBAAgB;IACd,MAAM,EAAE,cAAc,OAAO,KAAK;AAClC,WACG,OAAO,CACP,OAAO,CACP,gBACC;KAAE,MAAM,UAAU;KAAM,IAAI,UAAU;KAAI,EAC1C,WACD,CACA,KAAK;;aAZZ,CAeE,oBAAC,OAAD,EAAO,WAAU,gCAAiC,GACjD,QAAQ,iBACI;MACf,qBAAC,QAAQ,MAAT;GACE,OAAM;GACN,WAAU;GACV,gBAAgB;IACd,MAAM,EAAE,cAAc,OAAO,KAAK;AAClC,WACG,OAAO,CACP,OAAO,CACP,gBAAgB,UAAU,KAAK,GAAG,WAAW,CAC7C,KAAK;;aATZ,CAYE,oBAAC,WAAD,EAAW,WAAU,gCAAiC,GACrD,QAAQ,YACI;KACD;EAChB,oBAAC,QAAQ,WAAT,EAAqB;EACrB,oBAAC,QAAQ,OAAT,YACE,qBAAC,QAAQ,MAAT;GACE,OAAM;GACN,WAAU;GACV,UAAU;aAHZ,CAKE,oBAAC,WAAD,EAAW,WAAU,gCAAiC,GACrD,QAAQ,QACI;MACD;EACf"}
@@ -0,0 +1,100 @@
1
+ 'use client';
2
+
3
+ import { toast } from "../../Toaster/useToast.mjs";
4
+ import { Loader } from "../../Loader/index.mjs";
5
+ import { Button } from "../../Button/Button.mjs";
6
+ import { Command, CommandRoot } from "../../Command/index.mjs";
7
+ import { MarkdownRenderer as MarkdownRenderer$1 } from "../../MarkDownRender/MarkDownRender.mjs";
8
+ import { useEditor } from "../novel/components/index.mjs";
9
+ import { addAIHighlight } from "../novel/extensions/ai-highlight.mjs";
10
+ import { AICompletionCommands } from "./AICompletionCommands.mjs";
11
+ import { AISelectorCommands } from "./AISelectorCommands.mjs";
12
+ import { useAICompletion } from "./useAICompletion.mjs";
13
+ import { useState } from "react";
14
+ import { ArrowUp, Sparkles } from "lucide-react";
15
+ import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
16
+ import { useIntlayer } from "react-intlayer";
17
+
18
+ //#region src/components/MarkdownEditor/generative/AISelector.tsx
19
+ /**
20
+ * The AI command palette shown inside the bubble menu. Lets the user run a
21
+ * preset transformation or a free-form prompt against the current selection,
22
+ * preview the markdown result, then replace / insert / discard it.
23
+ */
24
+ const AISelector = ({ onOpenChange, sendButtonVariant = "default", sendButtonColor = "text" }) => {
25
+ const { editor } = useEditor();
26
+ const [inputValue, setInputValue] = useState("");
27
+ const content = useIntlayer("markdown-editor");
28
+ const { completion, complete, isLoading, reset } = useAICompletion((error) => toast({
29
+ variant: "error",
30
+ title: content.aiError.value,
31
+ description: error.message
32
+ }));
33
+ if (!editor) return null;
34
+ const hasCompletion = completion.length > 0;
35
+ const getSelectionMarkdown = () => {
36
+ const slice = editor.state.selection.content();
37
+ return editor.storage.markdown.serializer.serialize(slice.content);
38
+ };
39
+ return /* @__PURE__ */ jsxs(CommandRoot, {
40
+ className: "w-[350px]",
41
+ children: [
42
+ hasCompletion && /* @__PURE__ */ jsx("div", {
43
+ className: "flex max-h-[400px]",
44
+ children: /* @__PURE__ */ jsx("div", {
45
+ className: "relative overflow-y-auto",
46
+ children: /* @__PURE__ */ jsx("div", {
47
+ className: "prose prose-sm dark:prose-invert p-2 px-4",
48
+ children: /* @__PURE__ */ jsx(MarkdownRenderer$1, { children: completion })
49
+ })
50
+ })
51
+ }),
52
+ isLoading && /* @__PURE__ */ jsxs("div", {
53
+ className: "flex h-12 w-full items-center px-4 font-medium text-sm text-text",
54
+ children: [
55
+ /* @__PURE__ */ jsx(Sparkles, { className: "mr-2 size-4 shrink-0" }),
56
+ content.aiThinking,
57
+ /* @__PURE__ */ jsx("div", {
58
+ className: "mt-1 ml-2",
59
+ children: /* @__PURE__ */ jsx(Loader, {})
60
+ })
61
+ ]
62
+ }),
63
+ !isLoading && /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs("div", {
64
+ className: "flex items-center gap-2 px-3 py-3",
65
+ children: [/* @__PURE__ */ jsx(Command.Input, {
66
+ value: inputValue,
67
+ onValueChange: setInputValue,
68
+ autoFocus: true,
69
+ placeholder: hasCompletion ? content.tellAI.value : content.askAIToEdit.value,
70
+ onFocus: () => addAIHighlight(editor)
71
+ }), /* @__PURE__ */ jsx(Button, {
72
+ label: content.send.value,
73
+ size: "icon-sm",
74
+ roundedSize: "full",
75
+ variant: sendButtonVariant,
76
+ color: sendButtonColor,
77
+ className: "size-7 shrink-0",
78
+ Icon: ArrowUp,
79
+ onClick: () => {
80
+ complete(completion || getSelectionMarkdown(), { body: {
81
+ option: "zap",
82
+ command: inputValue
83
+ } }).then(() => setInputValue(""));
84
+ }
85
+ })]
86
+ }), hasCompletion ? /* @__PURE__ */ jsx(AICompletionCommands, {
87
+ completion,
88
+ onDiscard: () => {
89
+ editor.chain().unsetHighlight().focus().run();
90
+ reset();
91
+ onOpenChange(false);
92
+ }
93
+ }) : /* @__PURE__ */ jsx(AISelectorCommands, { onSelect: (value, option) => complete(value, { body: { option } }) })] })
94
+ ]
95
+ });
96
+ };
97
+
98
+ //#endregion
99
+ export { AISelector };
100
+ //# sourceMappingURL=AISelector.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AISelector.mjs","names":["MarkdownRenderer"],"sources":["../../../../../src/components/MarkdownEditor/generative/AISelector.tsx"],"sourcesContent":["'use client';\n\nimport {\n Button,\n type ButtonColor,\n type ButtonVariant,\n} from '@components/Button';\nimport { Command, CommandRoot } from '@components/Command';\nimport { Loader } from '@components/Loader';\nimport { MarkdownRenderer } from '@components/MarkDownRender';\nimport { toast } from '@components/Toaster';\nimport { ArrowUp, Sparkles } from 'lucide-react';\nimport { useState } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { addAIHighlight, useEditor } from '../novel';\nimport { AICompletionCommands } from './AICompletionCommands';\nimport { AISelectorCommands } from './AISelectorCommands';\nimport { useAICompletion } from './useAICompletion';\n\nexport type AISelectorProps = {\n onOpenChange: (open: boolean) => void;\n /** Visual variant for the send button. @default \"default\" */\n sendButtonVariant?: ButtonVariant;\n /** Color theme for the send button. @default \"text\" */\n sendButtonColor?: ButtonColor;\n};\n\n/**\n * The AI command palette shown inside the bubble menu. Lets the user run a\n * preset transformation or a free-form prompt against the current selection,\n * preview the markdown result, then replace / insert / discard it.\n */\nexport const AISelector = ({\n onOpenChange,\n sendButtonVariant = 'default',\n sendButtonColor = 'text',\n}: AISelectorProps) => {\n const { editor } = useEditor();\n const [inputValue, setInputValue] = useState('');\n const content = useIntlayer('markdown-editor');\n\n const { completion, complete, isLoading, reset } = useAICompletion((error) =>\n toast({\n variant: 'error',\n title: content.aiError.value,\n description: error.message,\n })\n );\n\n if (!editor) return null;\n\n const hasCompletion = completion.length > 0;\n\n const getSelectionMarkdown = () => {\n const slice = editor.state.selection.content();\n return editor.storage.markdown.serializer.serialize(\n slice.content\n ) as string;\n };\n\n return (\n <CommandRoot className=\"w-[350px]\">\n {hasCompletion && (\n <div className=\"flex max-h-[400px]\">\n <div className=\"relative overflow-y-auto\">\n <div className=\"prose prose-sm dark:prose-invert p-2 px-4\">\n <MarkdownRenderer>{completion}</MarkdownRenderer>\n </div>\n </div>\n </div>\n )}\n\n {isLoading && (\n <div className=\"flex h-12 w-full items-center px-4 font-medium text-sm text-text\">\n <Sparkles className=\"mr-2 size-4 shrink-0\" />\n {content.aiThinking}\n <div className=\"mt-1 ml-2\">\n <Loader />\n </div>\n </div>\n )}\n\n {!isLoading && (\n <>\n <div className=\"flex items-center gap-2 px-3 py-3\">\n <Command.Input\n value={inputValue}\n onValueChange={setInputValue}\n autoFocus\n placeholder={\n hasCompletion ? content.tellAI.value : content.askAIToEdit.value\n }\n onFocus={() => addAIHighlight(editor)}\n />\n <Button\n label={content.send.value}\n size=\"icon-sm\"\n roundedSize=\"full\"\n variant={sendButtonVariant}\n color={sendButtonColor}\n className=\"size-7 shrink-0\"\n Icon={ArrowUp}\n onClick={() => {\n const text = completion || getSelectionMarkdown();\n complete(text, {\n body: { option: 'zap', command: inputValue },\n }).then(() => setInputValue(''));\n }}\n />\n </div>\n {hasCompletion ? (\n <AICompletionCommands\n completion={completion}\n onDiscard={() => {\n editor.chain().unsetHighlight().focus().run();\n reset();\n onOpenChange(false);\n }}\n />\n ) : (\n <AISelectorCommands\n onSelect={(value, option) =>\n complete(value, { body: { option } })\n }\n />\n )}\n </>\n )}\n </CommandRoot>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAgCA,MAAa,cAAc,EACzB,cACA,oBAAoB,WACpB,kBAAkB,aACG;CACrB,MAAM,EAAE,WAAW,WAAW;CAC9B,MAAM,CAAC,YAAY,iBAAiB,SAAS,GAAG;CAChD,MAAM,UAAU,YAAY,kBAAkB;CAE9C,MAAM,EAAE,YAAY,UAAU,WAAW,UAAU,iBAAiB,UAClE,MAAM;EACJ,SAAS;EACT,OAAO,QAAQ,QAAQ;EACvB,aAAa,MAAM;EACpB,CAAC,CACH;AAED,KAAI,CAAC,OAAQ,QAAO;CAEpB,MAAM,gBAAgB,WAAW,SAAS;CAE1C,MAAM,6BAA6B;EACjC,MAAM,QAAQ,OAAO,MAAM,UAAU,SAAS;AAC9C,SAAO,OAAO,QAAQ,SAAS,WAAW,UACxC,MAAM,QACP;;AAGH,QACE,qBAAC,aAAD;EAAa,WAAU;YAAvB;GACG,iBACC,oBAAC,OAAD;IAAK,WAAU;cACb,oBAAC,OAAD;KAAK,WAAU;eACb,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAACA,oBAAD,YAAmB,YAA8B;MAC7C;KACF;IACF;GAGP,aACC,qBAAC,OAAD;IAAK,WAAU;cAAf;KACE,oBAAC,UAAD,EAAU,WAAU,wBAAyB;KAC5C,QAAQ;KACT,oBAAC,OAAD;MAAK,WAAU;gBACb,oBAAC,QAAD,EAAU;MACN;KACF;;GAGP,CAAC,aACA,8CACE,qBAAC,OAAD;IAAK,WAAU;cAAf,CACE,oBAAC,QAAQ,OAAT;KACE,OAAO;KACP,eAAe;KACf;KACA,aACE,gBAAgB,QAAQ,OAAO,QAAQ,QAAQ,YAAY;KAE7D,eAAe,eAAe,OAAO;KACrC,GACF,oBAAC,QAAD;KACE,OAAO,QAAQ,KAAK;KACpB,MAAK;KACL,aAAY;KACZ,SAAS;KACT,OAAO;KACP,WAAU;KACV,MAAM;KACN,eAAe;AAEb,eADa,cAAc,sBAAsB,EAClC,EACb,MAAM;OAAE,QAAQ;OAAO,SAAS;OAAY,EAC7C,CAAC,CAAC,WAAW,cAAc,GAAG,CAAC;;KAElC,EACE;OACL,gBACC,oBAAC,sBAAD;IACc;IACZ,iBAAiB;AACf,YAAO,OAAO,CAAC,gBAAgB,CAAC,OAAO,CAAC,KAAK;AAC7C,YAAO;AACP,kBAAa,MAAM;;IAErB,IAEF,oBAAC,oBAAD,EACE,WAAW,OAAO,WAChB,SAAS,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAEvC,EAEH;GAEO"}
@@ -0,0 +1,81 @@
1
+ 'use client';
2
+
3
+ import { Command } from "../../Command/index.mjs";
4
+ import { useEditor } from "../novel/components/index.mjs";
5
+ import { getPrevText } from "../novel/utils/index.mjs";
6
+ import { ArrowDownWideNarrow, CheckCheck, RefreshCcwDot, StepForward, WrapText } from "lucide-react";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ import { useIntlayer } from "react-intlayer";
9
+
10
+ //#region src/components/MarkdownEditor/generative/AISelectorCommands.tsx
11
+ const options = [
12
+ {
13
+ value: "improve",
14
+ label: "Improve writing",
15
+ icon: RefreshCcwDot
16
+ },
17
+ {
18
+ value: "fix",
19
+ label: "Fix grammar",
20
+ icon: CheckCheck
21
+ },
22
+ {
23
+ value: "shorter",
24
+ label: "Make shorter",
25
+ icon: ArrowDownWideNarrow
26
+ },
27
+ {
28
+ value: "longer",
29
+ label: "Make longer",
30
+ icon: WrapText
31
+ }
32
+ ];
33
+ /**
34
+ * The default command list shown in the AI bubble before a completion exists:
35
+ * transforms applied to the current selection plus "continue writing".
36
+ */
37
+ const AISelectorCommands = ({ onSelect }) => {
38
+ const { editor } = useEditor();
39
+ const content = useIntlayer("markdown-editor");
40
+ if (!editor) return null;
41
+ const getOptionLabel = (value) => {
42
+ switch (value) {
43
+ case "improve": return content.improveWriting.value;
44
+ case "fix": return content.fixGrammar.value;
45
+ case "shorter": return content.makeShorter.value;
46
+ case "longer": return content.makeLonger.value;
47
+ default: return value;
48
+ }
49
+ };
50
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
51
+ /* @__PURE__ */ jsx(Command.Group, {
52
+ heading: content.editHeading.value,
53
+ children: options.map((option) => /* @__PURE__ */ jsxs(Command.Item, {
54
+ value: option.value,
55
+ className: "flex gap-2 px-4",
56
+ onSelect: (value) => {
57
+ const slice = editor.state.selection.content();
58
+ onSelect(editor.storage.markdown.serializer.serialize(slice.content), value);
59
+ },
60
+ children: [/* @__PURE__ */ jsx(option.icon, { className: "size-4 text-text" }), getOptionLabel(option.value)]
61
+ }, option.value))
62
+ }),
63
+ /* @__PURE__ */ jsx(Command.Separator, {}),
64
+ /* @__PURE__ */ jsx(Command.Group, {
65
+ heading: content.moreHeading.value,
66
+ children: /* @__PURE__ */ jsxs(Command.Item, {
67
+ value: "continue",
68
+ className: "gap-2 px-4",
69
+ onSelect: () => {
70
+ const pos = editor.state.selection.from;
71
+ onSelect(getPrevText(editor, pos), "continue");
72
+ },
73
+ children: [/* @__PURE__ */ jsx(StepForward, { className: "size-4 text-text" }), content.continueWriting]
74
+ })
75
+ })
76
+ ] });
77
+ };
78
+
79
+ //#endregion
80
+ export { AISelectorCommands };
81
+ //# sourceMappingURL=AISelectorCommands.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AISelectorCommands.mjs","names":[],"sources":["../../../../../src/components/MarkdownEditor/generative/AISelectorCommands.tsx"],"sourcesContent":["'use client';\n\nimport { Command } from '@components/Command';\nimport {\n ArrowDownWideNarrow,\n CheckCheck,\n RefreshCcwDot,\n StepForward,\n WrapText,\n} from 'lucide-react';\nimport { useIntlayer } from 'react-intlayer';\nimport { getPrevText, useEditor } from '../novel';\nimport type { AICompletionOption } from './useAICompletion';\n\nconst options: {\n value: Exclude<AICompletionOption, 'zap'>;\n label: string;\n icon: typeof RefreshCcwDot;\n}[] = [\n { value: 'improve', label: 'Improve writing', icon: RefreshCcwDot },\n { value: 'fix', label: 'Fix grammar', icon: CheckCheck },\n { value: 'shorter', label: 'Make shorter', icon: ArrowDownWideNarrow },\n { value: 'longer', label: 'Make longer', icon: WrapText },\n];\n\nexport type AISelectorCommandsProps = {\n onSelect: (value: string, option: AICompletionOption) => void;\n};\n\n/**\n * The default command list shown in the AI bubble before a completion exists:\n * transforms applied to the current selection plus \"continue writing\".\n */\nexport const AISelectorCommands = ({ onSelect }: AISelectorCommandsProps) => {\n const { editor } = useEditor();\n const content = useIntlayer('markdown-editor');\n\n if (!editor) return null;\n\n const getOptionLabel = (value: string) => {\n switch (value) {\n case 'improve':\n return content.improveWriting.value;\n case 'fix':\n return content.fixGrammar.value;\n case 'shorter':\n return content.makeShorter.value;\n case 'longer':\n return content.makeLonger.value;\n default:\n return value;\n }\n };\n\n return (\n <>\n <Command.Group heading={content.editHeading.value}>\n {options.map((option) => (\n <Command.Item\n key={option.value}\n value={option.value}\n className=\"flex gap-2 px-4\"\n onSelect={(value) => {\n const slice = editor.state.selection.content();\n const text = editor.storage.markdown.serializer.serialize(\n slice.content\n );\n onSelect(text, value as AICompletionOption);\n }}\n >\n <option.icon className=\"size-4 text-text\" />\n {getOptionLabel(option.value)}\n </Command.Item>\n ))}\n </Command.Group>\n <Command.Separator />\n <Command.Group heading={content.moreHeading.value}>\n <Command.Item\n value=\"continue\"\n className=\"gap-2 px-4\"\n onSelect={() => {\n const pos = editor.state.selection.from;\n const text = getPrevText(editor, pos);\n onSelect(text, 'continue');\n }}\n >\n <StepForward className=\"size-4 text-text\" />\n {content.continueWriting}\n </Command.Item>\n </Command.Group>\n </>\n );\n};\n"],"mappings":";;;;;;;;;;AAcA,MAAM,UAIA;CACJ;EAAE,OAAO;EAAW,OAAO;EAAmB,MAAM;EAAe;CACnE;EAAE,OAAO;EAAO,OAAO;EAAe,MAAM;EAAY;CACxD;EAAE,OAAO;EAAW,OAAO;EAAgB,MAAM;EAAqB;CACtE;EAAE,OAAO;EAAU,OAAO;EAAe,MAAM;EAAU;CAC1D;;;;;AAUD,MAAa,sBAAsB,EAAE,eAAwC;CAC3E,MAAM,EAAE,WAAW,WAAW;CAC9B,MAAM,UAAU,YAAY,kBAAkB;AAE9C,KAAI,CAAC,OAAQ,QAAO;CAEpB,MAAM,kBAAkB,UAAkB;AACxC,UAAQ,OAAR;GACE,KAAK,UACH,QAAO,QAAQ,eAAe;GAChC,KAAK,MACH,QAAO,QAAQ,WAAW;GAC5B,KAAK,UACH,QAAO,QAAQ,YAAY;GAC7B,KAAK,SACH,QAAO,QAAQ,WAAW;GAC5B,QACE,QAAO;;;AAIb,QACE;EACE,oBAAC,QAAQ,OAAT;GAAe,SAAS,QAAQ,YAAY;aACzC,QAAQ,KAAK,WACZ,qBAAC,QAAQ,MAAT;IAEE,OAAO,OAAO;IACd,WAAU;IACV,WAAW,UAAU;KACnB,MAAM,QAAQ,OAAO,MAAM,UAAU,SAAS;AAI9C,cAHa,OAAO,QAAQ,SAAS,WAAW,UAC9C,MAAM,QAEK,EAAE,MAA4B;;cAT/C,CAYE,oBAAC,OAAO,MAAR,EAAa,WAAU,oBAAqB,GAC3C,eAAe,OAAO,MAAM,CAChB;MAbR,OAAO,MAaC,CACf;GACY;EAChB,oBAAC,QAAQ,WAAT,EAAqB;EACrB,oBAAC,QAAQ,OAAT;GAAe,SAAS,QAAQ,YAAY;aAC1C,qBAAC,QAAQ,MAAT;IACE,OAAM;IACN,WAAU;IACV,gBAAgB;KACd,MAAM,MAAM,OAAO,MAAM,UAAU;AAEnC,cADa,YAAY,QAAQ,IACpB,EAAE,WAAW;;cAN9B,CASE,oBAAC,aAAD,EAAa,WAAU,oBAAqB,GAC3C,QAAQ,gBACI;;GACD;EACf"}
@@ -0,0 +1,47 @@
1
+ 'use client';
2
+
3
+ import { Button } from "../../Button/Button.mjs";
4
+ import { EditorBubble } from "../novel/components/editor-bubble.mjs";
5
+ import { useEditor } from "../novel/components/index.mjs";
6
+ import { removeAIHighlight } from "../novel/extensions/ai-highlight.mjs";
7
+ import { AISelector } from "./AISelector.mjs";
8
+ import { Fragment, useEffect } from "react";
9
+ import { Sparkles } from "lucide-react";
10
+ import { jsx, jsxs } from "react/jsx-runtime";
11
+ import { useIntlayer } from "react-intlayer";
12
+
13
+ //#region src/components/MarkdownEditor/generative/GenerativeMenuSwitch.tsx
14
+ /**
15
+ * Bubble menu that toggles between the regular formatting toolbar (its
16
+ * `children`) and the AI command palette.
17
+ */
18
+ const GenerativeMenuSwitch = ({ children, open, onOpenChange, sendButtonVariant, sendButtonColor }) => {
19
+ const { editor } = useEditor();
20
+ const content = useIntlayer("markdown-editor");
21
+ useEffect(() => {
22
+ if (!open && editor) removeAIHighlight(editor);
23
+ }, [open, editor]);
24
+ return /* @__PURE__ */ jsxs(EditorBubble, {
25
+ options: { placement: open ? "bottom-start" : "top" },
26
+ className: "flex w-fit max-w-[90vw] rounded-lg border-[1.3px] border-neutral/20 bg-card/95 text-text shadow-xl backdrop-blur [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl",
27
+ children: [open && /* @__PURE__ */ jsx(AISelector, {
28
+ onOpenChange,
29
+ sendButtonVariant,
30
+ sendButtonColor
31
+ }), !open && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Button, {
32
+ label: content.askAI.value,
33
+ variant: "hoverable",
34
+ color: "text",
35
+ size: "sm",
36
+ roundedSize: "none",
37
+ className: "gap-1 text-text",
38
+ Icon: Sparkles,
39
+ onClick: () => onOpenChange(true),
40
+ children: content.askAI
41
+ }), children] })]
42
+ });
43
+ };
44
+
45
+ //#endregion
46
+ export { GenerativeMenuSwitch };
47
+ //# sourceMappingURL=GenerativeMenuSwitch.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GenerativeMenuSwitch.mjs","names":[],"sources":["../../../../../src/components/MarkdownEditor/generative/GenerativeMenuSwitch.tsx"],"sourcesContent":["'use client';\n\nimport {\n Button,\n type ButtonColor,\n type ButtonVariant,\n} from '@components/Button';\nimport { Sparkles } from 'lucide-react';\nimport { Fragment, type ReactNode, useEffect } from 'react';\nimport { useIntlayer } from 'react-intlayer';\nimport { EditorBubble, removeAIHighlight, useEditor } from '../novel';\nimport { AISelector } from './AISelector';\n\nexport type GenerativeMenuSwitchProps = {\n children: ReactNode;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n /** Visual variant forwarded to the AI send button. @default \"default\" */\n sendButtonVariant?: ButtonVariant;\n /** Color theme forwarded to the AI send button. @default \"text\" */\n sendButtonColor?: ButtonColor;\n};\n\n/**\n * Bubble menu that toggles between the regular formatting toolbar (its\n * `children`) and the AI command palette.\n */\nexport const GenerativeMenuSwitch = ({\n children,\n open,\n onOpenChange,\n sendButtonVariant,\n sendButtonColor,\n}: GenerativeMenuSwitchProps) => {\n const { editor } = useEditor();\n const content = useIntlayer('markdown-editor');\n\n useEffect(() => {\n if (!open && editor) removeAIHighlight(editor);\n }, [open, editor]);\n\n return (\n <EditorBubble\n options={{ placement: open ? 'bottom-start' : 'top' }}\n className=\"flex w-fit max-w-[90vw] rounded-lg border-[1.3px] border-neutral/20 bg-card/95 text-text shadow-xl backdrop-blur [corner-shape:squircle] supports-[corner-shape:squircle]:rounded-xl\"\n >\n {open && (\n <AISelector\n onOpenChange={onOpenChange}\n sendButtonVariant={sendButtonVariant}\n sendButtonColor={sendButtonColor}\n />\n )}\n {!open && (\n <Fragment>\n <Button\n label={content.askAI.value}\n variant=\"hoverable\"\n color=\"text\"\n size=\"sm\"\n roundedSize=\"none\"\n className=\"gap-1 text-text\"\n Icon={Sparkles}\n onClick={() => onOpenChange(true)}\n >\n {content.askAI}\n </Button>\n {children}\n </Fragment>\n )}\n </EditorBubble>\n );\n};\n"],"mappings":";;;;;;;;;;;;;;;;;AA2BA,MAAa,wBAAwB,EACnC,UACA,MACA,cACA,mBACA,sBAC+B;CAC/B,MAAM,EAAE,WAAW,WAAW;CAC9B,MAAM,UAAU,YAAY,kBAAkB;AAE9C,iBAAgB;AACd,MAAI,CAAC,QAAQ,OAAQ,mBAAkB,OAAO;IAC7C,CAAC,MAAM,OAAO,CAAC;AAElB,QACE,qBAAC,cAAD;EACE,SAAS,EAAE,WAAW,OAAO,iBAAiB,OAAO;EACrD,WAAU;YAFZ,CAIG,QACC,oBAAC,YAAD;GACgB;GACK;GACF;GACjB,GAEH,CAAC,QACA,qBAAC,UAAD,aACE,oBAAC,QAAD;GACE,OAAO,QAAQ,MAAM;GACrB,SAAQ;GACR,OAAM;GACN,MAAK;GACL,aAAY;GACZ,WAAU;GACV,MAAM;GACN,eAAe,aAAa,KAAK;aAEhC,QAAQ;GACF,GACR,SACQ,IAEA"}