betterstart-cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (369) hide show
  1. package/README.md +5 -0
  2. package/dist/assets/adapters/next/integrations/mailchimp/actions/mailchimp.ts +38 -0
  3. package/dist/assets/adapters/next/integrations/mailchimp/integration.ts +33 -0
  4. package/dist/assets/adapters/next/integrations/r2/actions/r2.ts +77 -0
  5. package/dist/assets/adapters/next/integrations/r2/integration.ts +39 -0
  6. package/dist/assets/adapters/next/integrations/resend/actions/resend.ts +138 -0
  7. package/dist/assets/adapters/next/integrations/resend/integration.ts +36 -0
  8. package/dist/assets/adapters/next/plugins/blog/plugin.ts +17 -0
  9. package/dist/assets/adapters/next/plugins/blog/schemas/posts.json +169 -0
  10. package/dist/assets/adapters/next/templates/init/admin-globals.css +677 -0
  11. package/dist/assets/adapters/next/templates/init/api/auth-route.ts +3 -0
  12. package/dist/assets/adapters/next/templates/init/api/upload-route.ts +132 -0
  13. package/dist/assets/adapters/next/templates/init/components/layouts/admin-header.tsx +32 -0
  14. package/dist/assets/adapters/next/templates/init/components/layouts/admin-nav-link.tsx +23 -0
  15. package/dist/assets/adapters/next/templates/init/components/layouts/admin-providers.tsx +33 -0
  16. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-branding-rsc.tsx +8 -0
  17. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-branding-skeleton.tsx +10 -0
  18. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-nav-link-skeleton.tsx +11 -0
  19. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-nav-link.tsx +12 -0
  20. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-user-menu-skeleton.tsx +15 -0
  21. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar-user-menu.tsx +90 -0
  22. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sidebar.tsx +78 -0
  23. package/dist/assets/adapters/next/templates/init/components/layouts/admin-sign-out.tsx +44 -0
  24. package/dist/assets/adapters/next/templates/init/components/layouts/content-skeleton.tsx +44 -0
  25. package/dist/assets/adapters/next/templates/init/components/layouts/sidebar-branding.tsx +41 -0
  26. package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table-pagination.tsx +139 -0
  27. package/dist/assets/adapters/next/templates/init/components/shared/data-table/data-table.tsx +236 -0
  28. package/dist/assets/adapters/next/templates/init/components/shared/delete-dialog.tsx +67 -0
  29. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/copyable-code-block.tsx +104 -0
  30. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/dev-mode-code-mirror.tsx +68 -0
  31. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/dev-mode-types.ts +75 -0
  32. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/lifecycle-hooks-tab.tsx +111 -0
  33. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/plain-code-fallback.tsx +11 -0
  34. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode/snippets-tab.tsx +125 -0
  35. package/dist/assets/adapters/next/templates/init/components/shared/dev-mode-integrate.tsx +108 -0
  36. package/dist/assets/adapters/next/templates/init/components/shared/entity-filters-bar.tsx +184 -0
  37. package/dist/assets/adapters/next/templates/init/components/shared/entity-metadata.tsx +93 -0
  38. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-version-item.tsx +55 -0
  39. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-version-restore-dialog.tsx +80 -0
  40. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-button.tsx +74 -0
  41. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-current-row.tsx +48 -0
  42. package/dist/assets/adapters/next/templates/init/components/shared/entity-versions/entity-versions-drawer.tsx +79 -0
  43. package/dist/assets/adapters/next/templates/init/components/shared/media/edit-media-dialog-content.tsx +222 -0
  44. package/dist/assets/adapters/next/templates/init/components/shared/media/edit-media-dialog.tsx +56 -0
  45. package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-dialog.tsx +83 -0
  46. package/dist/assets/adapters/next/templates/init/components/shared/media/media-delete-drawer.tsx +148 -0
  47. package/dist/assets/adapters/next/templates/init/components/shared/media/media-empty-state.tsx +45 -0
  48. package/dist/assets/adapters/next/templates/init/components/shared/media/media-filters-bar.tsx +129 -0
  49. package/dist/assets/adapters/next/templates/init/components/shared/media/media-gallery-dialog.tsx +182 -0
  50. package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-item.tsx +56 -0
  51. package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid-pagination.tsx +114 -0
  52. package/dist/assets/adapters/next/templates/init/components/shared/media/media-grid.tsx +44 -0
  53. package/dist/assets/adapters/next/templates/init/components/shared/media/media-preview.tsx +69 -0
  54. package/dist/assets/adapters/next/templates/init/components/shared/media/media-url-importer.tsx +139 -0
  55. package/dist/assets/adapters/next/templates/init/components/shared/page-header.tsx +46 -0
  56. package/dist/assets/adapters/next/templates/init/components/shared/search-input.tsx +88 -0
  57. package/dist/assets/adapters/next/templates/init/components/shared/sort-indicator.tsx +24 -0
  58. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-dialog.tsx +242 -0
  59. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-drag-overlay-item.tsx +15 -0
  60. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-item.tsx +32 -0
  61. package/dist/assets/adapters/next/templates/init/components/shared/sort-order-types.ts +9 -0
  62. package/dist/assets/adapters/next/templates/init/data/navigation.ts +43 -0
  63. package/dist/assets/adapters/next/templates/init/drizzle.config.ts +36 -0
  64. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-blockquote.ts +251 -0
  65. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-code-block.ts +258 -0
  66. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-color-highlight.ts +347 -0
  67. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-media-insertion.ts +59 -0
  68. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-mobile-toolbar.ts +17 -0
  69. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-slash-menu.ts +116 -0
  70. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-source-mode.tsx +638 -0
  71. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor-table-add-controls.ts +174 -0
  72. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-content-editor.ts +288 -0
  73. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-heading-dropdown-menu.ts +127 -0
  74. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-heading.ts +269 -0
  75. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-is-breakpoint.ts +32 -0
  76. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-link-popover.ts +278 -0
  77. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-list-dropdown-menu.ts +199 -0
  78. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-list.ts +290 -0
  79. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-mark.ts +199 -0
  80. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-menu-navigation.ts +221 -0
  81. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-tiptap-editor.ts +46 -0
  82. package/dist/assets/adapters/next/templates/init/hooks/content-editor/use-undo-redo.ts +169 -0
  83. package/dist/assets/adapters/next/templates/init/hooks/use-admin-theme.tsx +74 -0
  84. package/dist/assets/adapters/next/templates/init/hooks/use-copy-to-clipboard.ts +48 -0
  85. package/dist/assets/adapters/next/templates/init/hooks/use-dev-mode-integration.ts +43 -0
  86. package/dist/assets/adapters/next/templates/init/hooks/use-entity-versions.ts +32 -0
  87. package/dist/assets/adapters/next/templates/init/hooks/use-failed-image-url.ts +21 -0
  88. package/dist/assets/adapters/next/templates/init/hooks/use-local-storage.ts +46 -0
  89. package/dist/assets/adapters/next/templates/init/hooks/use-media-filters-bar.ts +72 -0
  90. package/dist/assets/adapters/next/templates/init/hooks/use-media.ts +102 -0
  91. package/dist/assets/adapters/next/templates/init/hooks/use-mobile.ts +19 -0
  92. package/dist/assets/adapters/next/templates/init/hooks/use-page-boundary-blur-visibility.ts +59 -0
  93. package/dist/assets/adapters/next/templates/init/hooks/use-page-scroll-threshold.ts +27 -0
  94. package/dist/assets/adapters/next/templates/init/hooks/use-table-utils.ts +315 -0
  95. package/dist/assets/adapters/next/templates/init/hooks/use-upload.ts +321 -0
  96. package/dist/assets/adapters/next/templates/init/hooks/use-users.ts +12 -0
  97. package/dist/assets/adapters/next/templates/init/lib/actions/auth/auth.ts +58 -0
  98. package/dist/assets/adapters/next/templates/init/lib/actions/auth/client.ts +12 -0
  99. package/dist/assets/adapters/next/templates/init/lib/actions/auth/middleware.ts +46 -0
  100. package/dist/assets/adapters/next/templates/init/lib/actions/email/form-delivery.ts +72 -0
  101. package/dist/assets/adapters/next/templates/init/lib/actions/email/index.ts +4 -0
  102. package/dist/assets/adapters/next/templates/init/lib/actions/email/is-email-delivery-configured.ts +5 -0
  103. package/dist/assets/adapters/next/templates/init/lib/actions/email/none.ts +24 -0
  104. package/dist/assets/adapters/next/templates/init/lib/actions/email/provider.ts +6 -0
  105. package/dist/assets/adapters/next/templates/init/lib/actions/email/send-email.ts +6 -0
  106. package/dist/assets/adapters/next/templates/init/lib/actions/email/send-password-reset-email.ts +10 -0
  107. package/dist/assets/adapters/next/templates/init/lib/actions/email/types.ts +25 -0
  108. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/get-entity-versions.ts +48 -0
  109. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/index.ts +10 -0
  110. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/internal-create-entity-version.ts +43 -0
  111. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/internal-delete-entity-versions.ts +19 -0
  112. package/dist/assets/adapters/next/templates/init/lib/actions/entity-versions/types.ts +26 -0
  113. package/dist/assets/adapters/next/templates/init/lib/actions/forms/get-all-form-settings.ts +21 -0
  114. package/dist/assets/adapters/next/templates/init/lib/actions/forms/get-form-settings.ts +27 -0
  115. package/dist/assets/adapters/next/templates/init/lib/actions/forms/index.ts +9 -0
  116. package/dist/assets/adapters/next/templates/init/lib/actions/forms/test-form-webhook.ts +40 -0
  117. package/dist/assets/adapters/next/templates/init/lib/actions/forms/types.ts +26 -0
  118. package/dist/assets/adapters/next/templates/init/lib/actions/forms/upsert-form-settings.ts +40 -0
  119. package/dist/assets/adapters/next/templates/init/lib/actions/media/create-media.ts +39 -0
  120. package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media-bulk.ts +29 -0
  121. package/dist/assets/adapters/next/templates/init/lib/actions/media/delete-media.ts +22 -0
  122. package/dist/assets/adapters/next/templates/init/lib/actions/media/get-media-by-id.ts +18 -0
  123. package/dist/assets/adapters/next/templates/init/lib/actions/media/get-media-by-ids.ts +25 -0
  124. package/dist/assets/adapters/next/templates/init/lib/actions/media/get-media.ts +71 -0
  125. package/dist/assets/adapters/next/templates/init/lib/actions/media/index.ts +14 -0
  126. package/dist/assets/adapters/next/templates/init/lib/actions/media/types.ts +31 -0
  127. package/dist/assets/adapters/next/templates/init/lib/actions/media/update-media.ts +35 -0
  128. package/dist/assets/adapters/next/templates/init/lib/actions/profile/index.ts +4 -0
  129. package/dist/assets/adapters/next/templates/init/lib/actions/profile/invalidate-users-cache.ts +14 -0
  130. package/dist/assets/adapters/next/templates/init/lib/actions/profile/is-email-configured.ts +7 -0
  131. package/dist/assets/adapters/next/templates/init/lib/actions/profile/types.ts +4 -0
  132. package/dist/assets/adapters/next/templates/init/lib/actions/profile/update-email.ts +57 -0
  133. package/dist/assets/adapters/next/templates/init/lib/actions/storage/index.ts +2 -0
  134. package/dist/assets/adapters/next/templates/init/lib/actions/storage/local.ts +31 -0
  135. package/dist/assets/adapters/next/templates/init/lib/actions/storage/provider.ts +6 -0
  136. package/dist/assets/adapters/next/templates/init/lib/actions/storage/save-upload.ts +11 -0
  137. package/dist/assets/adapters/next/templates/init/lib/actions/storage/types.ts +18 -0
  138. package/dist/assets/adapters/next/templates/init/lib/actions/upload/index.ts +9 -0
  139. package/dist/assets/adapters/next/templates/init/lib/actions/upload/types.ts +17 -0
  140. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-file.ts +11 -0
  141. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-files.ts +92 -0
  142. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-image-from-url.ts +22 -0
  143. package/dist/assets/adapters/next/templates/init/lib/actions/upload/upload-media-from-url.ts +133 -0
  144. package/dist/assets/adapters/next/templates/init/lib/actions/users/create-user.ts +55 -0
  145. package/dist/assets/adapters/next/templates/init/lib/actions/users/delete-user.ts +24 -0
  146. package/dist/assets/adapters/next/templates/init/lib/actions/users/get-users.ts +49 -0
  147. package/dist/assets/adapters/next/templates/init/lib/actions/users/index.ts +12 -0
  148. package/dist/assets/adapters/next/templates/init/lib/actions/users/types.ts +43 -0
  149. package/dist/assets/adapters/next/templates/init/lib/actions/users/update-user-role.ts +28 -0
  150. package/dist/assets/adapters/next/templates/init/lib/db/client.ts +13 -0
  151. package/dist/assets/adapters/next/templates/init/lib/db/core/schema.ts +160 -0
  152. package/dist/assets/adapters/next/templates/init/lib/db/schema.ts +1 -0
  153. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/index.ts +19 -0
  154. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/register.local.ts +2 -0
  155. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/register.ts +9 -0
  156. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/registry.ts +55 -0
  157. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/runner.ts +51 -0
  158. package/dist/assets/adapters/next/templates/init/lib/lifecycle-hooks/types.ts +39 -0
  159. package/dist/assets/adapters/next/templates/init/pages/account-layout.tsx +11 -0
  160. package/dist/assets/adapters/next/templates/init/pages/account-shell-rsc.tsx +30 -0
  161. package/dist/assets/adapters/next/templates/init/pages/admin-layout.tsx +24 -0
  162. package/dist/assets/adapters/next/templates/init/pages/auth-gate-rsc.tsx +6 -0
  163. package/dist/assets/adapters/next/templates/init/pages/authenticated-layout.tsx +18 -0
  164. package/dist/assets/adapters/next/templates/init/pages/dashboard-page.tsx +121 -0
  165. package/dist/assets/adapters/next/templates/init/pages/forgot-password-form.tsx +124 -0
  166. package/dist/assets/adapters/next/templates/init/pages/forgot-password-page-skeleton.tsx +24 -0
  167. package/dist/assets/adapters/next/templates/init/pages/forgot-password-page.tsx +21 -0
  168. package/dist/assets/adapters/next/templates/init/pages/login-form.tsx +131 -0
  169. package/dist/assets/adapters/next/templates/init/pages/login-page-rsc.tsx +14 -0
  170. package/dist/assets/adapters/next/templates/init/pages/login-page-skeleton.tsx +26 -0
  171. package/dist/assets/adapters/next/templates/init/pages/login-page.tsx +21 -0
  172. package/dist/assets/adapters/next/templates/init/pages/media/media-page-content.tsx +273 -0
  173. package/dist/assets/adapters/next/templates/init/pages/media/media-page-skeleton.tsx +7 -0
  174. package/dist/assets/adapters/next/templates/init/pages/media/media-page.tsx +11 -0
  175. package/dist/assets/adapters/next/templates/init/pages/minimal-account-shell.tsx +25 -0
  176. package/dist/assets/adapters/next/templates/init/pages/profile/profile-form.tsx +281 -0
  177. package/dist/assets/adapters/next/templates/init/pages/profile/profile-page.tsx +31 -0
  178. package/dist/assets/adapters/next/templates/init/pages/reset-password-form.tsx +161 -0
  179. package/dist/assets/adapters/next/templates/init/pages/reset-password-page-skeleton.tsx +26 -0
  180. package/dist/assets/adapters/next/templates/init/pages/reset-password-page.tsx +21 -0
  181. package/dist/assets/adapters/next/templates/init/pages/users/columns.tsx +170 -0
  182. package/dist/assets/adapters/next/templates/init/pages/users/create-user-dialog.tsx +221 -0
  183. package/dist/assets/adapters/next/templates/init/pages/users/delete-user-dialog.tsx +172 -0
  184. package/dist/assets/adapters/next/templates/init/pages/users/edit-role-dialog.tsx +91 -0
  185. package/dist/assets/adapters/next/templates/init/pages/users/users-page-content.tsx +25 -0
  186. package/dist/assets/adapters/next/templates/init/pages/users/users-page-skeleton.tsx +7 -0
  187. package/dist/assets/adapters/next/templates/init/pages/users/users-page.tsx +11 -0
  188. package/dist/assets/adapters/next/templates/init/pages/users/users-table.tsx +221 -0
  189. package/dist/assets/adapters/next/templates/init/types/auth.ts +71 -0
  190. package/dist/assets/adapters/next/templates/init/types/index.ts +108 -0
  191. package/dist/assets/adapters/next/templates/init/types/navigation.ts +11 -0
  192. package/dist/assets/adapters/next/templates/init/types/table-meta.ts +14 -0
  193. package/dist/assets/adapters/next/templates/init/utils/auth/roles.ts +17 -0
  194. package/dist/assets/adapters/next/templates/init/utils/date/date.ts +90 -0
  195. package/dist/assets/adapters/next/templates/init/utils/dev-mode/code-block-height.ts +9 -0
  196. package/dist/assets/adapters/next/templates/init/utils/editor/content-editor-rich-extensions.ts +824 -0
  197. package/dist/assets/adapters/next/templates/init/utils/editor/content-editor.ts +316 -0
  198. package/dist/assets/adapters/next/templates/init/utils/editor/editor-view.ts +19 -0
  199. package/dist/assets/adapters/next/templates/init/utils/editor/markdown.ts +542 -0
  200. package/dist/assets/adapters/next/templates/init/utils/editor/node-attrs.ts +25 -0
  201. package/dist/assets/adapters/next/templates/init/utils/editor/slash-commands.ts +148 -0
  202. package/dist/assets/adapters/next/templates/init/utils/editor/source-media.ts +11 -0
  203. package/dist/assets/adapters/next/templates/init/utils/editor/table-add-controls.ts +91 -0
  204. package/dist/assets/adapters/next/templates/init/utils/editor/table-bubble.ts +172 -0
  205. package/dist/assets/adapters/next/templates/init/utils/editor/table-input.ts +5 -0
  206. package/dist/assets/adapters/next/templates/init/utils/editor/task-item.ts +19 -0
  207. package/dist/assets/adapters/next/templates/init/utils/editor/tiptap.ts +991 -0
  208. package/dist/assets/adapters/next/templates/init/utils/email/form-delivery.ts +104 -0
  209. package/dist/assets/adapters/next/templates/init/utils/media/fallback.ts +37 -0
  210. package/dist/assets/adapters/next/templates/init/utils/media/media.ts +91 -0
  211. package/dist/assets/adapters/next/templates/init/utils/media/query.ts +96 -0
  212. package/dist/assets/adapters/next/templates/init/utils/navigation/order.ts +6 -0
  213. package/dist/assets/adapters/next/templates/init/utils/navigation/sidebar.ts +26 -0
  214. package/dist/assets/adapters/next/templates/init/utils/page/boundary.ts +32 -0
  215. package/dist/assets/adapters/next/templates/init/utils/seo/seo.ts +90 -0
  216. package/dist/assets/adapters/next/templates/init/utils/shared/cn.ts +6 -0
  217. package/dist/assets/adapters/next/templates/init/utils/storage/local.ts +9 -0
  218. package/dist/assets/adapters/next/templates/init/utils/table/table.ts +10 -0
  219. package/dist/assets/adapters/next/templates/init/utils/text/text.ts +4 -0
  220. package/dist/assets/adapters/next/templates/init/utils/theme/system.ts +6 -0
  221. package/dist/assets/adapters/next/templates/init/utils/upload/remote.ts +55 -0
  222. package/dist/assets/adapters/next/templates/init/utils/upload/upload.ts +26 -0
  223. package/dist/assets/adapters/next/templates/init/utils/user/user.ts +11 -0
  224. package/dist/assets/adapters/next/templates/init/utils/validation/validation.ts +114 -0
  225. package/dist/assets/adapters/next/templates/init/utils/webhook/webhook.ts +28 -0
  226. package/dist/assets/shared-assets/react-admin/custom/content-editor/editor-toolbar.tsx +25 -0
  227. package/dist/assets/shared-assets/react-admin/custom/content-editor/horizontal-rule-button.tsx +22 -0
  228. package/dist/assets/shared-assets/react-admin/custom/content-editor/index.tsx +142 -0
  229. package/dist/assets/shared-assets/react-admin/custom/content-editor/main-toolbar-content.tsx +118 -0
  230. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-bubble-menu.tsx +80 -0
  231. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-button.tsx +22 -0
  232. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-editor-controls.tsx +117 -0
  233. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-popover-button.tsx +59 -0
  234. package/dist/assets/shared-assets/react-admin/custom/content-editor/math-popover.tsx +6 -0
  235. package/dist/assets/shared-assets/react-admin/custom/content-editor/media-gallery-block.tsx +31 -0
  236. package/dist/assets/shared-assets/react-admin/custom/content-editor/mobile-toolbar-content.tsx +56 -0
  237. package/dist/assets/shared-assets/react-admin/custom/content-editor/mode-toggle-button.tsx +29 -0
  238. package/dist/assets/shared-assets/react-admin/custom/content-editor/remove-table-part-icon.tsx +17 -0
  239. package/dist/assets/shared-assets/react-admin/custom/content-editor/selection-bubble-menu.tsx +105 -0
  240. package/dist/assets/shared-assets/react-admin/custom/content-editor/slash-command-menu.tsx +65 -0
  241. package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode-dropdown-button.tsx +52 -0
  242. package/dist/assets/shared-assets/react-admin/custom/content-editor/source-mode.tsx +360 -0
  243. package/dist/assets/shared-assets/react-admin/custom/content-editor/table-add-controls.tsx +46 -0
  244. package/dist/assets/shared-assets/react-admin/custom/content-editor/table-bubble-menu.tsx +290 -0
  245. package/dist/assets/shared-assets/react-admin/custom/content-editor/table-button.tsx +116 -0
  246. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-extension/node-background-extension.ts +138 -0
  247. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/horizontal-rule-node/horizontal-rule-node-extension.ts +10 -0
  248. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/media-gallery-placeholder-node/index.tsx +1 -0
  249. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/media-gallery-placeholder-node/media-gallery-placeholder-node-extension.ts +117 -0
  250. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/media-gallery-placeholder-node/media-gallery-placeholder-node.tsx +63 -0
  251. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/index.tsx +1 -0
  252. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/removable-image-node-extension.ts +11 -0
  253. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/removable-image-node/removable-image-node.tsx +168 -0
  254. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-node/task-item-node/task-item-node-extension.tsx +142 -0
  255. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/blockquote-button/blockquote-button.tsx +114 -0
  256. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/blockquote-button/index.tsx +1 -0
  257. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/code-block-button/code-block-button.tsx +112 -0
  258. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/code-block-button/index.tsx +1 -0
  259. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-button/color-highlight-button.tsx +185 -0
  260. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-button/index.tsx +1 -0
  261. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover-button.tsx +40 -0
  262. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover-content.tsx +130 -0
  263. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/color-highlight-popover.tsx +98 -0
  264. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/highlight-color-button.tsx +75 -0
  265. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/highlight-colors.ts +24 -0
  266. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/index.tsx +1 -0
  267. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/color-highlight-popover/source-color-highlight-popover.tsx +65 -0
  268. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/control-options.ts +27 -0
  269. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu-item.tsx +35 -0
  270. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/heading-dropdown-menu.tsx +119 -0
  271. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/heading-dropdown-menu/index.tsx +1 -0
  272. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/index.tsx +1 -0
  273. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-button.tsx +39 -0
  274. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-content.tsx +13 -0
  275. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-control-popover.tsx +90 -0
  276. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-main.tsx +96 -0
  277. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/link-popover/link-popover.tsx +121 -0
  278. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/index.tsx +1 -0
  279. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/list-dropdown-menu-item.tsx +44 -0
  280. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/list-dropdown-menu/list-dropdown-menu.tsx +115 -0
  281. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/mark-button/index.tsx +1 -0
  282. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/mark-button/mark-button.tsx +117 -0
  283. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/undo-redo-button/index.tsx +1 -0
  284. package/dist/assets/shared-assets/react-admin/custom/content-editor/tiptap-ui/undo-redo-button/undo-redo-button.tsx +115 -0
  285. package/dist/assets/shared-assets/react-admin/custom/date-picker.tsx +70 -0
  286. package/dist/assets/shared-assets/react-admin/custom/date-range-picker.tsx +216 -0
  287. package/dist/assets/shared-assets/react-admin/custom/dynamic-list-field.tsx +111 -0
  288. package/dist/assets/shared-assets/react-admin/custom/gallery-field.tsx +124 -0
  289. package/dist/assets/shared-assets/react-admin/custom/gallery-thumbnail.tsx +39 -0
  290. package/dist/assets/shared-assets/react-admin/custom/icon-picker.tsx +377 -0
  291. package/dist/assets/shared-assets/react-admin/custom/icons-column-skeleton.tsx +16 -0
  292. package/dist/assets/shared-assets/react-admin/custom/icons-data.ts +8 -0
  293. package/dist/assets/shared-assets/react-admin/custom/logo.tsx +115 -0
  294. package/dist/assets/shared-assets/react-admin/custom/media-gallery-field.tsx +182 -0
  295. package/dist/assets/shared-assets/react-admin/custom/page-skeleton.tsx +11 -0
  296. package/dist/assets/shared-assets/react-admin/custom/placeholder-card.tsx +34 -0
  297. package/dist/assets/shared-assets/react-admin/custom/placeholder.tsx +25 -0
  298. package/dist/assets/shared-assets/react-admin/custom/progressive-blur.tsx +62 -0
  299. package/dist/assets/shared-assets/react-admin/custom/sortable-gallery-item.tsx +68 -0
  300. package/dist/assets/shared-assets/react-admin/custom/upload-dropzone.tsx +107 -0
  301. package/dist/assets/shared-assets/react-admin/dependencies.ts +73 -0
  302. package/dist/assets/shared-assets/react-admin/schema.json +1670 -0
  303. package/dist/assets/shared-assets/react-admin/ui/accordion.tsx +86 -0
  304. package/dist/assets/shared-assets/react-admin/ui/alert-dialog.tsx +178 -0
  305. package/dist/assets/shared-assets/react-admin/ui/alert.tsx +72 -0
  306. package/dist/assets/shared-assets/react-admin/ui/aspect-ratio.tsx +9 -0
  307. package/dist/assets/shared-assets/react-admin/ui/avatar.tsx +95 -0
  308. package/dist/assets/shared-assets/react-admin/ui/badge.tsx +48 -0
  309. package/dist/assets/shared-assets/react-admin/ui/breadcrumb.tsx +99 -0
  310. package/dist/assets/shared-assets/react-admin/ui/button-group.tsx +76 -0
  311. package/dist/assets/shared-assets/react-admin/ui/button.tsx +66 -0
  312. package/dist/assets/shared-assets/react-admin/ui/calendar.tsx +184 -0
  313. package/dist/assets/shared-assets/react-admin/ui/card.tsx +94 -0
  314. package/dist/assets/shared-assets/react-admin/ui/carousel.tsx +239 -0
  315. package/dist/assets/shared-assets/react-admin/ui/chart.tsx +336 -0
  316. package/dist/assets/shared-assets/react-admin/ui/checkbox.tsx +28 -0
  317. package/dist/assets/shared-assets/react-admin/ui/collapsible.tsx +21 -0
  318. package/dist/assets/shared-assets/react-admin/ui/combobox.tsx +272 -0
  319. package/dist/assets/shared-assets/react-admin/ui/command.tsx +180 -0
  320. package/dist/assets/shared-assets/react-admin/ui/context-menu.tsx +243 -0
  321. package/dist/assets/shared-assets/react-admin/ui/dialog.tsx +141 -0
  322. package/dist/assets/shared-assets/react-admin/ui/direction.tsx +20 -0
  323. package/dist/assets/shared-assets/react-admin/ui/drawer.tsx +119 -0
  324. package/dist/assets/shared-assets/react-admin/ui/dropdown-menu.tsx +253 -0
  325. package/dist/assets/shared-assets/react-admin/ui/empty.tsx +93 -0
  326. package/dist/assets/shared-assets/react-admin/ui/field.tsx +234 -0
  327. package/dist/assets/shared-assets/react-admin/ui/form.tsx +172 -0
  328. package/dist/assets/shared-assets/react-admin/ui/hover-card.tsx +37 -0
  329. package/dist/assets/shared-assets/react-admin/ui/input-group.tsx +134 -0
  330. package/dist/assets/shared-assets/react-admin/ui/input-otp.tsx +85 -0
  331. package/dist/assets/shared-assets/react-admin/ui/input.tsx +18 -0
  332. package/dist/assets/shared-assets/react-admin/ui/item.tsx +180 -0
  333. package/dist/assets/shared-assets/react-admin/ui/kbd.tsx +26 -0
  334. package/dist/assets/shared-assets/react-admin/ui/label.tsx +20 -0
  335. package/dist/assets/shared-assets/react-admin/ui/menubar.tsx +259 -0
  336. package/dist/assets/shared-assets/react-admin/ui/native-select.tsx +54 -0
  337. package/dist/assets/shared-assets/react-admin/ui/navigation-menu.tsx +159 -0
  338. package/dist/assets/shared-assets/react-admin/ui/pagination.tsx +111 -0
  339. package/dist/assets/shared-assets/react-admin/ui/popover.tsx +75 -0
  340. package/dist/assets/shared-assets/react-admin/ui/progress.tsx +30 -0
  341. package/dist/assets/shared-assets/react-admin/ui/radio-group.tsx +43 -0
  342. package/dist/assets/shared-assets/react-admin/ui/resizable.tsx +41 -0
  343. package/dist/assets/shared-assets/react-admin/ui/scroll-area.tsx +54 -0
  344. package/dist/assets/shared-assets/react-admin/ui/select.tsx +183 -0
  345. package/dist/assets/shared-assets/react-admin/ui/separator.tsx +27 -0
  346. package/dist/assets/shared-assets/react-admin/ui/sheet.tsx +129 -0
  347. package/dist/assets/shared-assets/react-admin/ui/sidebar.tsx +688 -0
  348. package/dist/assets/shared-assets/react-admin/ui/skeleton.tsx +13 -0
  349. package/dist/assets/shared-assets/react-admin/ui/slider.tsx +53 -0
  350. package/dist/assets/shared-assets/react-admin/ui/sonner.tsx +45 -0
  351. package/dist/assets/shared-assets/react-admin/ui/spinner.tsx +15 -0
  352. package/dist/assets/shared-assets/react-admin/ui/switch.tsx +32 -0
  353. package/dist/assets/shared-assets/react-admin/ui/table.tsx +101 -0
  354. package/dist/assets/shared-assets/react-admin/ui/tabs.tsx +79 -0
  355. package/dist/assets/shared-assets/react-admin/ui/textarea.tsx +17 -0
  356. package/dist/assets/shared-assets/react-admin/ui/toggle-group.tsx +85 -0
  357. package/dist/assets/shared-assets/react-admin/ui/toggle.tsx +45 -0
  358. package/dist/assets/shared-assets/react-admin/ui/tooltip.tsx +51 -0
  359. package/dist/chunk-MUZQCVQA.js +306 -0
  360. package/dist/chunk-MUZQCVQA.js.map +1 -0
  361. package/dist/cli.d.ts +2 -0
  362. package/dist/cli.js +23437 -0
  363. package/dist/cli.js.map +1 -0
  364. package/dist/index.d.ts +90 -0
  365. package/dist/index.js +8 -0
  366. package/dist/index.js.map +1 -0
  367. package/dist/template-reader-YKWE2C7O.js +13 -0
  368. package/dist/template-reader-YKWE2C7O.js.map +1 -0
  369. package/package.json +74 -0
@@ -0,0 +1,824 @@
1
+ 'use client'
2
+
3
+ import {
4
+ getContentEditorHighlightColorName,
5
+ getContentEditorHighlightColorValue,
6
+ isContentEditorHighlightColor
7
+ } from '@admin/utils/editor/content-editor'
8
+ import { Mark, mergeAttributes, Node as TiptapNode } from '@tiptap/core'
9
+ import { Highlight } from '@tiptap/extension-highlight'
10
+ import type { Node as ProseMirrorNode } from '@tiptap/pm/model'
11
+ import type { EditorView } from '@tiptap/pm/view'
12
+ import katex from 'katex'
13
+
14
+ type RawContentKind = 'html' | 'math'
15
+ type InlineMathDelimiter = '$' | '\\('
16
+
17
+ interface RawContentMatch {
18
+ kind: RawContentKind
19
+ raw: string
20
+ }
21
+
22
+ interface InlineMathMatch {
23
+ raw: string
24
+ text: string
25
+ delimiter: InlineMathDelimiter
26
+ }
27
+
28
+ interface RawContentToken {
29
+ raw?: string
30
+ text?: string
31
+ delimiter?: string
32
+ kind?: string
33
+ }
34
+
35
+ interface RawContentBlockNodeViewOptions {
36
+ getPos: () => number | undefined
37
+ node: ProseMirrorNode
38
+ view: EditorView
39
+ }
40
+
41
+ const rawHtmlBlockTags = [
42
+ 'article',
43
+ 'aside',
44
+ 'audio',
45
+ 'details',
46
+ 'div',
47
+ 'figure',
48
+ 'iframe',
49
+ 'section',
50
+ 'table',
51
+ 'video'
52
+ ].join('|')
53
+
54
+ const selfClosingHtmlBlockTags = ['br', 'hr', 'img'].join('|')
55
+
56
+ const mathBlockEnvironmentNames = new Set([
57
+ 'align',
58
+ 'align*',
59
+ 'aligned',
60
+ 'alignedat',
61
+ 'alignedat*',
62
+ 'array',
63
+ 'bmatrix',
64
+ 'cases',
65
+ 'equation',
66
+ 'equation*',
67
+ 'gather',
68
+ 'gather*',
69
+ 'gathered',
70
+ 'matrix',
71
+ 'multline',
72
+ 'multline*',
73
+ 'pmatrix',
74
+ 'smallmatrix',
75
+ 'split',
76
+ 'vmatrix'
77
+ ])
78
+
79
+ const blockedHtmlPreviewTags = new Set(['embed', 'link', 'meta', 'object', 'script', 'style'])
80
+
81
+ const urlAttributes = new Set(['href', 'src'])
82
+
83
+ export const ContentEditorUnderline = Mark.create({
84
+ name: 'underline',
85
+
86
+ parseHTML() {
87
+ return [{ tag: 'u' }]
88
+ },
89
+
90
+ renderHTML({ HTMLAttributes }) {
91
+ return ['u', mergeAttributes(HTMLAttributes), 0]
92
+ },
93
+
94
+ markdownOptions: {
95
+ htmlReopen: {
96
+ open: '<u>',
97
+ close: '</u>'
98
+ }
99
+ },
100
+
101
+ renderMarkdown: (node, helpers) => {
102
+ return `<u>${helpers.renderChildren(node)}</u>`
103
+ }
104
+ })
105
+
106
+ export const ContentEditorHighlight = Highlight.extend({
107
+ parseHTML() {
108
+ return [
109
+ {
110
+ tag: 'span[data-highlight-color]',
111
+ getAttrs: (element) => {
112
+ if (!(element instanceof HTMLElement)) return false
113
+
114
+ const color = element.getAttribute('data-highlight-color')
115
+ if (!color || !isContentEditorHighlightColor(color)) return false
116
+
117
+ return {
118
+ color: getContentEditorHighlightColorValue(color)
119
+ }
120
+ }
121
+ }
122
+ ]
123
+ },
124
+
125
+ renderMarkdown: (node, helpers) => {
126
+ const color = getContentEditorHighlightColorName(node.attrs?.color)
127
+ return `<span data-highlight-color="${color}">${helpers.renderChildren(node)}</span>`
128
+ },
129
+ parseMarkdown: null as never,
130
+ markdownTokenizer: null as never
131
+ })
132
+
133
+ export const ContentEditorSubscript = createHtmlMark('subscript', 'sub')
134
+ export const ContentEditorSuperscript = createHtmlMark('superscript', 'sup')
135
+ export const ContentEditorKeyboard = createHtmlMark('keyboard', 'kbd')
136
+
137
+ export const ContentEditorInlineMath = TiptapNode.create({
138
+ name: 'inlineMath',
139
+ group: 'inline',
140
+ inline: true,
141
+ atom: true,
142
+ selectable: true,
143
+
144
+ addAttributes() {
145
+ return {
146
+ raw: {
147
+ default: ''
148
+ },
149
+ delimiter: {
150
+ default: '$'
151
+ }
152
+ }
153
+ },
154
+
155
+ parseHTML() {
156
+ return [
157
+ {
158
+ tag: 'span[data-content-editor-inline-math]',
159
+ getAttrs: (element) => {
160
+ if (!(element instanceof HTMLElement)) return false
161
+
162
+ return {
163
+ raw: element.dataset.raw ?? element.textContent ?? '',
164
+ delimiter: element.dataset.delimiter === '\\(' ? '\\(' : '$'
165
+ }
166
+ }
167
+ }
168
+ ]
169
+ },
170
+
171
+ renderHTML({ HTMLAttributes, node }) {
172
+ const raw = getStringAttr(node.attrs.raw)
173
+ const delimiter = getInlineMathDelimiter(node.attrs.delimiter)
174
+
175
+ return [
176
+ 'span',
177
+ mergeAttributes(HTMLAttributes, {
178
+ 'data-content-editor-inline-math': '',
179
+ 'data-raw': raw,
180
+ 'data-delimiter': delimiter
181
+ }),
182
+ raw
183
+ ]
184
+ },
185
+
186
+ parseMarkdown: (token) => {
187
+ const mathToken = getRawContentToken(token)
188
+
189
+ return {
190
+ type: 'inlineMath',
191
+ attrs: {
192
+ raw: mathToken.text ?? mathToken.raw ?? '',
193
+ delimiter: getInlineMathDelimiter(mathToken.delimiter)
194
+ }
195
+ }
196
+ },
197
+
198
+ renderMarkdown: (node) => {
199
+ const raw = getStringAttr(node.attrs?.raw)
200
+ const delimiter = getInlineMathDelimiter(node.attrs?.delimiter)
201
+
202
+ if (delimiter === '\\(') {
203
+ return `\\(${raw}\\)`
204
+ }
205
+
206
+ return `$${raw}$`
207
+ },
208
+
209
+ markdownTokenizer: {
210
+ name: 'inlineMath',
211
+ level: 'inline',
212
+ start: findInlineMathStart,
213
+ tokenize(src) {
214
+ const match = matchInlineMath(src)
215
+ if (!match) return undefined
216
+
217
+ return {
218
+ type: 'inlineMath',
219
+ raw: match.raw,
220
+ text: match.text,
221
+ delimiter: match.delimiter
222
+ }
223
+ }
224
+ },
225
+
226
+ addNodeView() {
227
+ return ({ node }) => {
228
+ return new InlineMathNodeView(node)
229
+ }
230
+ }
231
+ })
232
+
233
+ export const ContentEditorRawContentBlock = TiptapNode.create({
234
+ name: 'rawContentBlock',
235
+ group: 'block',
236
+ atom: true,
237
+ selectable: true,
238
+
239
+ addAttributes() {
240
+ return {
241
+ kind: {
242
+ default: 'html'
243
+ },
244
+ raw: {
245
+ default: ''
246
+ }
247
+ }
248
+ },
249
+
250
+ parseHTML() {
251
+ return [
252
+ {
253
+ tag: 'div[data-content-editor-raw-block]',
254
+ getAttrs: (element) => {
255
+ if (!(element instanceof HTMLElement)) return false
256
+
257
+ return {
258
+ kind: getRawContentKind(element.dataset.contentEditorRawBlock),
259
+ raw: element.dataset.raw ?? ''
260
+ }
261
+ }
262
+ }
263
+ ]
264
+ },
265
+
266
+ renderHTML({ HTMLAttributes, node }) {
267
+ const raw = getStringAttr(node.attrs.raw)
268
+ const kind = getRawContentKind(node.attrs.kind)
269
+
270
+ return [
271
+ 'div',
272
+ mergeAttributes(HTMLAttributes, {
273
+ 'data-content-editor-raw-block': kind,
274
+ 'data-raw': raw
275
+ })
276
+ ]
277
+ },
278
+
279
+ parseMarkdown: (token) => {
280
+ const rawToken = getRawContentToken(token)
281
+
282
+ return {
283
+ type: 'rawContentBlock',
284
+ attrs: {
285
+ kind: getRawContentKind(rawToken.kind),
286
+ raw: rawToken.raw ?? rawToken.text ?? ''
287
+ }
288
+ }
289
+ },
290
+
291
+ renderMarkdown: (node) => {
292
+ return getStringAttr(node.attrs?.raw)
293
+ },
294
+
295
+ markdownTokenizer: {
296
+ name: 'rawContentBlock',
297
+ level: 'block',
298
+ start: findRawContentStart,
299
+ tokenize(src) {
300
+ const match = matchRawContentBlock(src)
301
+ if (!match) return undefined
302
+
303
+ return {
304
+ type: 'rawContentBlock',
305
+ raw: match.raw,
306
+ text: match.raw,
307
+ kind: match.kind
308
+ }
309
+ }
310
+ },
311
+
312
+ addNodeView() {
313
+ return ({ getPos, node, view }) => {
314
+ return new RawContentBlockNodeView({ getPos, node, view })
315
+ }
316
+ }
317
+ })
318
+
319
+ class RawContentBlockNodeView {
320
+ readonly dom: HTMLElement
321
+ private readonly preview: HTMLElement
322
+ private readonly abortController = new AbortController()
323
+ private currentRaw: string
324
+ private node: ProseMirrorNode
325
+
326
+ constructor(private readonly options: RawContentBlockNodeViewOptions) {
327
+ this.node = options.node
328
+ this.currentRaw = getStringAttr(options.node.attrs.raw)
329
+
330
+ const kind = getRawContentKind(options.node.attrs.kind)
331
+ this.dom = document.createElement('div')
332
+ this.dom.dataset.contentEditorRawBlock = kind
333
+ this.dom.dataset.raw = this.currentRaw
334
+ this.dom.contentEditable = 'false'
335
+ this.dom.className =
336
+ 'content-editor-raw-block not-prose my-4 overflow-hidden rounded-md border bg-muted/20'
337
+
338
+ this.preview = document.createElement('div')
339
+ this.preview.contentEditable = 'true'
340
+ this.preview.dataset.contentEditorRawEditable = 'true'
341
+ this.preview.setAttribute('role', 'textbox')
342
+ this.preview.setAttribute('aria-label', 'Editable rendered HTML')
343
+ this.preview.spellcheck = true
344
+ this.preview.className =
345
+ 'content-editor-raw-block-preview overflow-auto p-4 outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50'
346
+ this.render(this.currentRaw, kind)
347
+
348
+ this.preview.addEventListener('input', this.handleInput, {
349
+ signal: this.abortController.signal
350
+ })
351
+ this.preview.addEventListener('blur', this.handleInput, {
352
+ signal: this.abortController.signal
353
+ })
354
+ this.dom.append(this.preview)
355
+ }
356
+
357
+ update(node: ProseMirrorNode) {
358
+ if (node.type !== this.node.type) return false
359
+
360
+ this.node = node
361
+ const nextKind = getRawContentKind(node.attrs.kind)
362
+ const nextRaw = getStringAttr(node.attrs.raw)
363
+ this.dom.dataset.contentEditorRawBlock = nextKind
364
+ this.dom.dataset.raw = nextRaw
365
+
366
+ if (nextRaw !== this.currentRaw) {
367
+ this.currentRaw = nextRaw
368
+ this.render(nextRaw, nextKind)
369
+ }
370
+
371
+ return true
372
+ }
373
+
374
+ stopEvent(event: Event) {
375
+ const kind = getRawContentKind(this.node.attrs.kind)
376
+
377
+ return (
378
+ kind !== 'math' &&
379
+ event.target instanceof globalThis.Node &&
380
+ this.preview.contains(event.target)
381
+ )
382
+ }
383
+
384
+ ignoreMutation() {
385
+ return true
386
+ }
387
+
388
+ destroy() {
389
+ this.abortController.abort()
390
+ }
391
+
392
+ private readonly handleInput = () => {
393
+ const kind = getRawContentKind(this.node.attrs.kind)
394
+ if (kind === 'math') return
395
+
396
+ const nextRaw = serializeRawContentPreview(this.preview, kind)
397
+
398
+ if (nextRaw === this.currentRaw) return
399
+
400
+ this.currentRaw = nextRaw
401
+ this.dom.dataset.raw = nextRaw
402
+
403
+ const position = this.options.getPos()
404
+ if (typeof position !== 'number') return
405
+
406
+ this.options.view.dispatch(
407
+ this.options.view.state.tr.setNodeMarkup(position, undefined, {
408
+ ...this.node.attrs,
409
+ raw: nextRaw
410
+ })
411
+ )
412
+ }
413
+
414
+ private render(raw: string, kind: RawContentKind) {
415
+ this.preview.contentEditable = kind === 'math' ? 'false' : 'true'
416
+ this.preview.setAttribute(
417
+ 'aria-label',
418
+ kind === 'math' ? 'Rendered LaTeX' : 'Editable rendered HTML'
419
+ )
420
+ this.preview.innerHTML = renderRawContentPreview(raw, kind)
421
+ }
422
+ }
423
+
424
+ class InlineMathNodeView {
425
+ readonly dom: HTMLElement
426
+ private currentRaw: string
427
+ private currentDelimiter: InlineMathDelimiter
428
+ private node: ProseMirrorNode
429
+
430
+ constructor(node: ProseMirrorNode) {
431
+ this.node = node
432
+ this.currentRaw = getStringAttr(node.attrs.raw)
433
+ this.currentDelimiter = getInlineMathDelimiter(node.attrs.delimiter)
434
+ this.dom = document.createElement('span')
435
+ this.dom.dataset.contentEditorInlineMath = ''
436
+ this.dom.contentEditable = 'false'
437
+ this.dom.className = 'content-editor-inline-math rounded-[3px] px-0.5'
438
+ this.render()
439
+ }
440
+
441
+ update(node: ProseMirrorNode) {
442
+ if (node.type !== this.node.type) return false
443
+
444
+ this.node = node
445
+ const nextRaw = getStringAttr(node.attrs.raw)
446
+ const nextDelimiter = getInlineMathDelimiter(node.attrs.delimiter)
447
+
448
+ if (nextRaw !== this.currentRaw || nextDelimiter !== this.currentDelimiter) {
449
+ this.currentRaw = nextRaw
450
+ this.currentDelimiter = nextDelimiter
451
+ this.render()
452
+ }
453
+
454
+ return true
455
+ }
456
+
457
+ ignoreMutation() {
458
+ return true
459
+ }
460
+
461
+ private render() {
462
+ this.dom.dataset.raw = this.currentRaw
463
+ this.dom.dataset.delimiter = this.currentDelimiter
464
+ this.dom.innerHTML = renderLatex(this.currentRaw, false)
465
+ }
466
+ }
467
+
468
+ function createHtmlMark(name: string, tag: 'kbd' | 'sub' | 'sup') {
469
+ return Mark.create({
470
+ name,
471
+
472
+ parseHTML() {
473
+ return [{ tag }]
474
+ },
475
+
476
+ renderHTML({ HTMLAttributes }) {
477
+ return [tag, mergeAttributes(HTMLAttributes), 0]
478
+ },
479
+
480
+ markdownOptions: {
481
+ htmlReopen: {
482
+ open: `<${tag}>`,
483
+ close: `</${tag}>`
484
+ }
485
+ },
486
+
487
+ renderMarkdown: (node, helpers) => {
488
+ return `<${tag}>${helpers.renderChildren(node)}</${tag}>`
489
+ }
490
+ })
491
+ }
492
+
493
+ function findRawContentStart(src: string) {
494
+ const indexes = [
495
+ src.search(/^\\\[/m),
496
+ src.search(/^\$\$/m),
497
+ src.search(/^\\begin\{/m),
498
+ src.search(new RegExp(`^<(${rawHtmlBlockTags})\\b`, 'im')),
499
+ src.search(new RegExp(`^<(${selfClosingHtmlBlockTags})\\b`, 'im'))
500
+ ].filter((index) => index >= 0)
501
+
502
+ return indexes.length > 0 ? Math.min(...indexes) : -1
503
+ }
504
+
505
+ function matchRawContentBlock(src: string): RawContentMatch | null {
506
+ return matchBlockMath(src) ?? matchHtmlBlock(src) ?? null
507
+ }
508
+
509
+ function matchBlockMath(src: string): RawContentMatch | null {
510
+ const bracketMatch = /^\\\[[\s\S]*?\\\][ \t]*(?:\n|$)/.exec(src)
511
+ if (bracketMatch) {
512
+ return {
513
+ kind: 'math',
514
+ raw: bracketMatch[0].trimEnd()
515
+ }
516
+ }
517
+
518
+ const dollarMatch = /^\$\$[\s\S]*?\$\$[ \t]*(?:\n|$)/.exec(src)
519
+ if (dollarMatch) {
520
+ return {
521
+ kind: 'math',
522
+ raw: dollarMatch[0].trimEnd()
523
+ }
524
+ }
525
+
526
+ const environmentMatch = /^\\begin\{([^}]+)\}[\s\S]*?\\end\{\1\}[ \t]*(?:\n|$)/.exec(src)
527
+ if (environmentMatch && mathBlockEnvironmentNames.has(environmentMatch[1])) {
528
+ return {
529
+ kind: 'math',
530
+ raw: environmentMatch[0].trimEnd()
531
+ }
532
+ }
533
+
534
+ return null
535
+ }
536
+
537
+ function matchHtmlBlock(src: string): RawContentMatch | null {
538
+ const pairedTagMatch = new RegExp(
539
+ `^<(${rawHtmlBlockTags})\\b[\\s\\S]*?<\\/\\1>[ \\t]*(?:\\n|$)`,
540
+ 'i'
541
+ ).exec(src)
542
+
543
+ if (pairedTagMatch) {
544
+ return {
545
+ kind: 'html',
546
+ raw: pairedTagMatch[0].trimEnd()
547
+ }
548
+ }
549
+
550
+ const selfClosingMatch = new RegExp(
551
+ `^<(${selfClosingHtmlBlockTags})\\b[^>]*(?:\\/?>)[ \\t]*(?:\\n|$)`,
552
+ 'i'
553
+ ).exec(src)
554
+
555
+ if (!selfClosingMatch) return null
556
+
557
+ return {
558
+ kind: 'html',
559
+ raw: selfClosingMatch[0].trimEnd()
560
+ }
561
+ }
562
+
563
+ function renderRawContentPreview(raw: string, kind: RawContentKind) {
564
+ if (kind === 'math') {
565
+ return renderLatex(getBlockMathExpression(raw), true)
566
+ }
567
+
568
+ if (/^<details\b/i.test(raw.trim())) {
569
+ return renderDetailsPreview(raw)
570
+ }
571
+
572
+ return sanitizeHtmlPreview(raw)
573
+ }
574
+
575
+ function serializeRawContentPreview(preview: HTMLElement, kind: RawContentKind) {
576
+ if (kind === 'math') {
577
+ return ''
578
+ }
579
+
580
+ return sanitizeHtmlPreview(preview.innerHTML).trim()
581
+ }
582
+
583
+ function findInlineMathStart(src: string) {
584
+ const dollarIndex = findUnescapedCharacter(src, '$', 0)
585
+ const parenIndex = findUnescapedSequence(src, '\\(', 0)
586
+ const indexes = [dollarIndex, parenIndex].filter((index) => index >= 0)
587
+
588
+ return indexes.length > 0 ? Math.min(...indexes) : -1
589
+ }
590
+
591
+ function matchInlineMath(src: string): InlineMathMatch | null {
592
+ if (src.startsWith('\\(')) {
593
+ const closingIndex = findUnescapedSequence(src, '\\)', 2)
594
+ if (closingIndex === -1) return null
595
+
596
+ return {
597
+ raw: src.slice(0, closingIndex + 2),
598
+ text: src.slice(2, closingIndex),
599
+ delimiter: '\\('
600
+ }
601
+ }
602
+
603
+ if (!src.startsWith('$') || src.startsWith('$$')) return null
604
+
605
+ if (src[1] && /\s/u.test(src[1])) return null
606
+
607
+ let closingIndex = 1
608
+
609
+ while (closingIndex < src.length) {
610
+ closingIndex = findUnescapedCharacter(src, '$', closingIndex)
611
+ if (closingIndex === -1) return null
612
+
613
+ const text = src.slice(1, closingIndex)
614
+ if (isValidDollarInlineMath(src, text, closingIndex)) {
615
+ return {
616
+ raw: src.slice(0, closingIndex + 1),
617
+ text,
618
+ delimiter: '$'
619
+ }
620
+ }
621
+
622
+ closingIndex++
623
+ }
624
+
625
+ return null
626
+ }
627
+
628
+ function isValidDollarInlineMath(src: string, text: string, closingIndex: number) {
629
+ if (!text.trim() || text.includes('\n')) return false
630
+ if (/^\s|\s$/u.test(text)) return false
631
+
632
+ const nextCharacter = src[closingIndex + 1]
633
+ if (nextCharacter && nextCharacter.trim() !== '' && !Number.isNaN(Number(nextCharacter))) {
634
+ return false
635
+ }
636
+
637
+ return true
638
+ }
639
+
640
+ function findUnescapedCharacter(value: string, character: string, start: number) {
641
+ for (let index = start; index < value.length; index++) {
642
+ if (value[index] !== character) continue
643
+ if (isEscaped(value, index)) continue
644
+ return index
645
+ }
646
+
647
+ return -1
648
+ }
649
+
650
+ function findUnescapedSequence(value: string, sequence: string, start: number) {
651
+ let index = value.indexOf(sequence, start)
652
+
653
+ while (index !== -1) {
654
+ if (!isEscaped(value, index)) return index
655
+ index = value.indexOf(sequence, index + sequence.length)
656
+ }
657
+
658
+ return -1
659
+ }
660
+
661
+ function isEscaped(value: string, index: number) {
662
+ let slashCount = 0
663
+
664
+ for (let offset = index - 1; offset >= 0 && value[offset] === '\\'; offset--) {
665
+ slashCount++
666
+ }
667
+
668
+ return slashCount % 2 === 1
669
+ }
670
+
671
+ function getBlockMathExpression(raw: string) {
672
+ const value = raw.trim()
673
+
674
+ if (value.startsWith('\\[') && value.endsWith('\\]')) {
675
+ return value.slice(2, -2).trim()
676
+ }
677
+
678
+ if (value.startsWith('$$') && value.endsWith('$$')) {
679
+ return value.slice(2, -2).trim()
680
+ }
681
+
682
+ return value
683
+ }
684
+
685
+ function renderLatex(expression: string, displayMode: boolean) {
686
+ if (!expression.trim()) return ''
687
+
688
+ try {
689
+ return katex.renderToString(expression, {
690
+ displayMode,
691
+ output: 'htmlAndMathml',
692
+ strict: 'ignore',
693
+ throwOnError: false,
694
+ trust: false
695
+ })
696
+ } catch {
697
+ return `<span class="text-destructive">${escapeHtml(expression)}</span>`
698
+ }
699
+ }
700
+
701
+ function renderDetailsPreview(raw: string) {
702
+ const match =
703
+ /^<details\b[^>]*>\s*<summary\b[^>]*>([\s\S]*?)<\/summary>([\s\S]*?)<\/details>$/i.exec(
704
+ raw.trim()
705
+ )
706
+
707
+ if (!match) {
708
+ return sanitizeHtmlPreview(raw)
709
+ }
710
+
711
+ const summary = escapeHtml(stripHtml(match[1]).trim())
712
+ const body = renderSimpleMarkdownBody(match[2])
713
+
714
+ return sanitizeHtmlPreview(`<details><summary>${summary}</summary>${body}</details>`)
715
+ }
716
+
717
+ function renderSimpleMarkdownBody(markdown: string) {
718
+ const lines = markdown.trim().split('\n')
719
+ const blocks: string[] = []
720
+ let paragraph: string[] = []
721
+ let listItems: string[] = []
722
+
723
+ const flushParagraph = () => {
724
+ if (paragraph.length === 0) return
725
+ blocks.push(`<p>${escapeHtml(paragraph.join(' ').trim())}</p>`)
726
+ paragraph = []
727
+ }
728
+
729
+ const flushList = () => {
730
+ if (listItems.length === 0) return
731
+ blocks.push(`<ul>${listItems.map((item) => `<li>${escapeHtml(item)}</li>`).join('')}</ul>`)
732
+ listItems = []
733
+ }
734
+
735
+ for (const line of lines) {
736
+ const trimmedLine = line.trim()
737
+ if (!trimmedLine) {
738
+ flushParagraph()
739
+ flushList()
740
+ continue
741
+ }
742
+
743
+ const listMatch = /^[-*]\s+(.+)$/.exec(trimmedLine)
744
+ if (listMatch) {
745
+ flushParagraph()
746
+ listItems.push(listMatch[1])
747
+ continue
748
+ }
749
+
750
+ flushList()
751
+ paragraph.push(trimmedLine)
752
+ }
753
+
754
+ flushParagraph()
755
+ flushList()
756
+
757
+ return blocks.join('')
758
+ }
759
+
760
+ function sanitizeHtmlPreview(html: string) {
761
+ const template = document.createElement('template')
762
+ template.innerHTML = html
763
+ const elementsToRemove: Element[] = []
764
+ const walker = document.createTreeWalker(template.content, NodeFilter.SHOW_ELEMENT)
765
+
766
+ while (walker.nextNode()) {
767
+ const element = walker.currentNode as HTMLElement
768
+ const tagName = element.tagName.toLowerCase()
769
+
770
+ if (blockedHtmlPreviewTags.has(tagName)) {
771
+ elementsToRemove.push(element)
772
+ continue
773
+ }
774
+
775
+ for (const attr of Array.from(element.attributes)) {
776
+ const attrName = attr.name.toLowerCase()
777
+ const attrValue = attr.value.trim().toLowerCase()
778
+
779
+ if (
780
+ attrName.startsWith('on') ||
781
+ attrName === 'srcdoc' ||
782
+ (urlAttributes.has(attrName) && attrValue.startsWith('javascript:'))
783
+ ) {
784
+ element.removeAttribute(attr.name)
785
+ }
786
+ }
787
+ }
788
+
789
+ for (const element of elementsToRemove) {
790
+ element.remove()
791
+ }
792
+
793
+ return template.innerHTML
794
+ }
795
+
796
+ function stripHtml(value: string) {
797
+ return value.replace(/<[^>]+>/g, '')
798
+ }
799
+
800
+ function getRawContentToken(token: unknown): RawContentToken {
801
+ if (!token || typeof token !== 'object') return {}
802
+ return token as RawContentToken
803
+ }
804
+
805
+ function getInlineMathDelimiter(value: unknown): InlineMathDelimiter {
806
+ return value === '\\(' ? '\\(' : '$'
807
+ }
808
+
809
+ function getRawContentKind(value: unknown): RawContentKind {
810
+ return value === 'math' ? value : 'html'
811
+ }
812
+
813
+ function getStringAttr(value: unknown) {
814
+ return typeof value === 'string' ? value : ''
815
+ }
816
+
817
+ function escapeHtml(value: string) {
818
+ return value
819
+ .replaceAll('&', '&amp;')
820
+ .replaceAll('<', '&lt;')
821
+ .replaceAll('>', '&gt;')
822
+ .replaceAll('"', '&quot;')
823
+ .replaceAll("'", '&#39;')
824
+ }