@jant/core 0.6.13 → 0.6.15

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 (316) hide show
  1. package/bin/commands/import-site.js +81 -13
  2. package/bin/commands/migrate.js +55 -0
  3. package/bin/commands/posts/rebuild-html.js +184 -0
  4. package/bin/commands/site/snapshot/import.js +14 -10
  5. package/bin/lib/d1-query.js +23 -5
  6. package/bin/lib/migration-runner.js +29 -7
  7. package/bin/lib/node-database.js +32 -0
  8. package/bin/lib/site-snapshot.js +347 -46
  9. package/bin/lib/sql-export.js +1 -1
  10. package/bin/lib/thread-collection-migration.js +326 -0
  11. package/dist/app-BxCOR3Uc.js +6 -0
  12. package/dist/{app-HnzmsaqU.js → app-C-oi_t8W.js} +7419 -6350
  13. package/dist/client/.vite/manifest.json +3 -3
  14. package/dist/client/_assets/client-B_eGKN5p.css +2 -0
  15. package/dist/client/_assets/{client-3_OaxhTs.js → client-DxY5BFe8.js} +58 -37
  16. package/dist/client/_assets/client-auth-CakPESv9.js +5533 -0
  17. package/dist/{export-Dfbq9aot.js → export-CsFx6F_M.js} +1273 -131
  18. package/dist/{github-sync--PSoE-Ne.js → github-sync-Cq1pzzOI.js} +1 -1
  19. package/dist/{github-sync-BGTLx8Mf.js → github-sync-ppWXN3jb.js} +2 -2
  20. package/dist/index.js +3 -3
  21. package/dist/node.js +5 -5
  22. package/package.json +11 -10
  23. package/src/__tests__/bin/posts-rebuild-html.test.ts +137 -0
  24. package/src/__tests__/dev-navigation-defaults.test.ts +22 -0
  25. package/src/__tests__/export-hugo-build.test.ts +63 -4
  26. package/src/__tests__/export-import-roundtrip.test.ts +6 -4
  27. package/src/__tests__/export-service.test.ts +142 -9
  28. package/src/__tests__/helpers/app.ts +3 -0
  29. package/src/__tests__/helpers/export-fixtures.ts +2 -0
  30. package/src/__tests__/import-site-command.test.ts +65 -0
  31. package/src/__tests__/vite-config.test.ts +45 -0
  32. package/src/app.tsx +16 -3
  33. package/src/client/__tests__/collection-created-notice.test.ts +36 -0
  34. package/src/client/__tests__/collection-form-bridge.test.ts +10 -1
  35. package/src/client/__tests__/collection-page-actions.test.ts +71 -2
  36. package/src/client/__tests__/compose-bridge.test.ts +64 -0
  37. package/src/client/__tests__/feed-video-player.test.ts +16 -1
  38. package/src/client/__tests__/footnote-rail.test.ts +472 -0
  39. package/src/client/__tests__/hydrate-partial.test.ts +3 -0
  40. package/src/client/__tests__/toast.test.ts +18 -1
  41. package/src/client/collection-created-notice.ts +66 -0
  42. package/src/client/collection-form-bridge.ts +17 -0
  43. package/src/client/collection-navigation.ts +44 -0
  44. package/src/client/collection-page-actions.ts +57 -1
  45. package/src/client/components/__tests__/jant-collection-directory.test.ts +155 -6
  46. package/src/client/components/__tests__/jant-command-palette.test.ts +137 -10
  47. package/src/client/components/__tests__/jant-compose-dialog.test.ts +373 -5
  48. package/src/client/components/__tests__/jant-compose-editor.test.ts +97 -0
  49. package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +104 -0
  50. package/src/client/components/__tests__/jant-config-editor.test.ts +405 -0
  51. package/src/client/components/__tests__/jant-media-lightbox.test.ts +121 -0
  52. package/src/client/components/__tests__/jant-nav-manager.test.ts +538 -2
  53. package/src/client/components/__tests__/jant-post-form.test.ts +2 -2
  54. package/src/client/components/__tests__/jant-post-menu.test.ts +47 -5
  55. package/src/client/components/__tests__/jant-settings-avatar.test.ts +2 -2
  56. package/src/client/components/__tests__/jant-settings-general.test.ts +3 -3
  57. package/src/client/components/collection-manager-types.ts +9 -3
  58. package/src/client/components/compose-types.ts +8 -0
  59. package/src/client/components/jant-collection-directory.ts +165 -30
  60. package/src/client/components/jant-command-palette.ts +102 -71
  61. package/src/client/components/jant-compose-dialog.ts +86 -22
  62. package/src/client/components/jant-compose-editor.ts +13 -7
  63. package/src/client/components/jant-compose-fullscreen.ts +24 -4
  64. package/src/client/components/jant-config-editor.ts +722 -0
  65. package/src/client/components/jant-media-lightbox.ts +100 -18
  66. package/src/client/components/jant-nav-manager.ts +1283 -54
  67. package/src/client/components/jant-post-form.ts +3 -3
  68. package/src/client/components/jant-post-menu.ts +86 -74
  69. package/src/client/components/nav-manager-types.ts +51 -2
  70. package/src/client/components/post-form-types.ts +1 -1
  71. package/src/client/compose-bridge.ts +4 -1
  72. package/src/client/feed-video-player.ts +62 -2
  73. package/src/client/footnote-rail.ts +478 -0
  74. package/src/client/hydrate-partial.ts +2 -0
  75. package/src/client/media-lightbox-events.ts +63 -0
  76. package/src/client/site-header-fragment.ts +38 -0
  77. package/src/client/tiptap/__tests__/blockquote-editing.test.ts +201 -0
  78. package/src/client/tiptap/__tests__/clear-formatting.test.ts +168 -0
  79. package/src/client/tiptap/__tests__/footnotes.test.ts +284 -0
  80. package/src/client/tiptap/__tests__/list-editing.test.ts +447 -0
  81. package/src/client/tiptap/__tests__/markdown-clipboard.test.ts +872 -2
  82. package/src/client/tiptap/__tests__/table-controls.test.ts +263 -0
  83. package/src/client/tiptap/__tests__/table-size-picker.test.ts +179 -0
  84. package/src/client/tiptap/bubble-menu.ts +91 -13
  85. package/src/client/tiptap/continuous-lists.ts +102 -0
  86. package/src/client/tiptap/create-editor.ts +3 -0
  87. package/src/client/tiptap/extensions.ts +14 -5
  88. package/src/client/tiptap/footnotes.ts +156 -0
  89. package/src/client/tiptap/markdown-clipboard.ts +614 -12
  90. package/src/client/tiptap/slash-commands.ts +8 -1
  91. package/src/client/tiptap/structural-keymap.ts +211 -0
  92. package/src/client/tiptap/tab-indent.ts +8 -22
  93. package/src/client/tiptap/table-control-labels.ts +30 -0
  94. package/src/client/tiptap/table-controls.ts +537 -0
  95. package/src/client/tiptap/table-size-picker.ts +254 -0
  96. package/src/client/toast.ts +8 -6
  97. package/src/client-auth.ts +1 -0
  98. package/src/client.ts +1 -0
  99. package/src/db/__tests__/d1-query.test.ts +43 -1
  100. package/src/db/__tests__/migration-runner.test.ts +63 -0
  101. package/src/db/__tests__/migrations.test.ts +469 -0
  102. package/src/db/__tests__/thread-collection-migration.test.ts +364 -0
  103. package/src/db/migrations/0027_old_blue_blade.sql +39 -0
  104. package/src/db/migrations/0028_superb_post.sql +2 -0
  105. package/src/db/migrations/0029_boring_magma.sql +1 -0
  106. package/src/db/migrations/0030_typical_vivisector.sql +50 -0
  107. package/src/db/migrations/meta/0027_snapshot.json +2511 -0
  108. package/src/db/migrations/meta/0028_snapshot.json +2511 -0
  109. package/src/db/migrations/meta/0029_snapshot.json +2519 -0
  110. package/src/db/migrations/meta/0030_snapshot.json +2541 -0
  111. package/src/db/migrations/meta/_journal.json +28 -0
  112. package/src/db/migrations/pg/0025_moaning_epoch.sql +39 -0
  113. package/src/db/migrations/pg/0026_talented_killer_shrike.sql +2 -0
  114. package/src/db/migrations/pg/0027_short_cannonball.sql +1 -0
  115. package/src/db/migrations/pg/0028_perfect_sharon_carter.sql +27 -0
  116. package/src/db/migrations/pg/meta/0025_snapshot.json +3204 -0
  117. package/src/db/migrations/pg/meta/0026_snapshot.json +3204 -0
  118. package/src/db/migrations/pg/meta/0027_snapshot.json +3211 -0
  119. package/src/db/migrations/pg/meta/0028_snapshot.json +3248 -0
  120. package/src/db/migrations/pg/meta/_journal.json +28 -0
  121. package/src/db/pg/schema.ts +28 -20
  122. package/src/db/rehearsal-fixtures/demo-current.json +39 -4
  123. package/src/db/rehearsal-fixtures/demo-current.sql +121 -6
  124. package/src/db/schema.ts +28 -20
  125. package/src/i18n/__tests__/detect.test.ts +8 -2
  126. package/src/i18n/detect.ts +14 -5
  127. package/src/i18n/locales/public/en.po +133 -30
  128. package/src/i18n/locales/public/en.ts +1 -1
  129. package/src/i18n/locales/public/zh-Hans.po +128 -25
  130. package/src/i18n/locales/public/zh-Hans.ts +1 -1
  131. package/src/i18n/locales/public/zh-Hant.po +128 -25
  132. package/src/i18n/locales/public/zh-Hant.ts +1 -1
  133. package/src/i18n/locales/settings/en.po +513 -10
  134. package/src/i18n/locales/settings/en.ts +1 -1
  135. package/src/i18n/locales/settings/zh-Hans.po +515 -12
  136. package/src/i18n/locales/settings/zh-Hans.ts +1 -1
  137. package/src/i18n/locales/settings/zh-Hant.po +515 -12
  138. package/src/i18n/locales/settings/zh-Hant.ts +1 -1
  139. package/src/lib/__tests__/api-settings.test.ts +299 -0
  140. package/src/lib/__tests__/constants.test.ts +5 -0
  141. package/src/lib/__tests__/feed-policy.test.ts +25 -0
  142. package/src/lib/__tests__/footnotes-upgrade.test.ts +181 -0
  143. package/src/lib/__tests__/markdown-roundtrip-embed.test.ts +61 -0
  144. package/src/lib/__tests__/markdown-to-tiptap.test.ts +36 -4
  145. package/src/lib/__tests__/markdown.test.ts +8 -6
  146. package/src/lib/__tests__/navigation.test.ts +59 -2
  147. package/src/lib/__tests__/post-body-html.test.ts +176 -0
  148. package/src/lib/__tests__/post-display.test.ts +64 -0
  149. package/src/lib/__tests__/resolve-config.test.ts +113 -1
  150. package/src/lib/__tests__/summary.test.ts +82 -0
  151. package/src/lib/__tests__/timeline.test.ts +109 -70
  152. package/src/lib/__tests__/timezones.test.ts +31 -3
  153. package/src/lib/__tests__/tiptap-render.test.ts +268 -9
  154. package/src/lib/__tests__/tiptap-to-markdown.test.ts +6 -0
  155. package/src/lib/__tests__/view.test.ts +53 -0
  156. package/src/lib/__tests__/worker-response-cache.test.ts +18 -1
  157. package/src/lib/api-settings.ts +239 -12
  158. package/src/lib/collection-sort.ts +7 -5
  159. package/src/lib/constants.ts +2 -0
  160. package/src/lib/feed-path.ts +25 -0
  161. package/src/lib/feed-policy.ts +64 -0
  162. package/src/lib/footnotes.ts +264 -0
  163. package/src/lib/github-sync-site-config.ts +2 -0
  164. package/src/lib/hugo-markdown.ts +10 -3
  165. package/src/lib/jant-branding.ts +1 -0
  166. package/src/lib/markdown-manager.ts +202 -10
  167. package/src/lib/markdown.ts +10 -3
  168. package/src/lib/navigation.ts +16 -3
  169. package/src/lib/post-body-html.ts +131 -0
  170. package/src/lib/post-display.ts +7 -1
  171. package/src/lib/render.tsx +9 -2
  172. package/src/lib/resolve-config.ts +100 -16
  173. package/src/lib/schemas.ts +133 -1
  174. package/src/lib/settings-paths.ts +5 -0
  175. package/src/lib/site-skill.ts +78 -0
  176. package/src/lib/summary.ts +16 -5
  177. package/src/lib/timeline.ts +98 -122
  178. package/src/lib/timezones.ts +54 -14
  179. package/src/lib/tiptap-render.ts +355 -81
  180. package/src/lib/view.ts +30 -20
  181. package/src/lib/worker-response-cache.ts +11 -18
  182. package/src/middleware/__tests__/public-content-access.test.ts +91 -0
  183. package/src/middleware/config.ts +2 -2
  184. package/src/middleware/public-content-access.ts +87 -0
  185. package/src/node/__tests__/cli-export.test.ts +14 -0
  186. package/src/node/__tests__/cli-migrate.test.ts +6 -0
  187. package/src/node/__tests__/cli-site-snapshot.test.ts +205 -2
  188. package/src/node/__tests__/cli-snapshot-meta.test.ts +100 -0
  189. package/src/node/index.ts +2 -1
  190. package/src/preset.css +16 -2
  191. package/src/routes/__tests__/compose.test.ts +51 -0
  192. package/src/routes/__tests__/site-skill.test.ts +112 -0
  193. package/src/routes/api/__tests__/collections.test.ts +91 -19
  194. package/src/routes/api/__tests__/mcp.test.ts +65 -1
  195. package/src/routes/api/__tests__/nav-items.test.ts +91 -0
  196. package/src/routes/api/__tests__/public-access.test.ts +81 -0
  197. package/src/routes/api/__tests__/settings.test.ts +217 -0
  198. package/src/routes/api/collections.ts +22 -26
  199. package/src/routes/api/export.ts +2 -0
  200. package/src/routes/api/internal/__tests__/post-body-html.test.ts +163 -0
  201. package/src/routes/api/internal/__tests__/sites.test.ts +35 -2
  202. package/src/routes/api/internal/post-body-html.ts +43 -0
  203. package/src/routes/api/internal/sites.ts +24 -0
  204. package/src/routes/api/nav-items.ts +24 -1
  205. package/src/routes/api/posts.ts +2 -2
  206. package/src/routes/api/public/__tests__/archive.test.ts +35 -0
  207. package/src/routes/api/public/__tests__/posts.test.ts +208 -0
  208. package/src/routes/api/public/archive.ts +4 -0
  209. package/src/routes/api/public/posts.ts +41 -24
  210. package/src/routes/api/search.ts +3 -0
  211. package/src/routes/api/settings.ts +33 -0
  212. package/src/routes/auth/__tests__/setup.test.ts +7 -4
  213. package/src/routes/compose.tsx +2 -1
  214. package/src/routes/dash/settings.tsx +45 -2
  215. package/src/routes/feed/__tests__/feed.test.ts +210 -6
  216. package/src/routes/feed/feed.ts +23 -14
  217. package/src/routes/pages/__tests__/archive-params.test.ts +92 -3
  218. package/src/routes/pages/__tests__/collection-routing.test.ts +63 -5
  219. package/src/routes/pages/__tests__/collections.test.ts +9 -9
  220. package/src/routes/pages/__tests__/preview.test.ts +174 -0
  221. package/src/routes/pages/__tests__/search.test.ts +69 -0
  222. package/src/routes/pages/archive.tsx +27 -7
  223. package/src/routes/pages/collection.tsx +32 -19
  224. package/src/routes/pages/collections.tsx +6 -1
  225. package/src/routes/pages/page.tsx +83 -11
  226. package/src/routes/site-skill.ts +18 -0
  227. package/src/services/__tests__/auth.test.ts +7 -5
  228. package/src/services/__tests__/collection.test.ts +159 -44
  229. package/src/services/__tests__/navigation.test.ts +229 -21
  230. package/src/services/__tests__/post-timeline.test.ts +109 -30
  231. package/src/services/__tests__/post.test.ts +567 -5
  232. package/src/services/__tests__/search.test.ts +48 -1
  233. package/src/services/__tests__/settings.test.ts +8 -0
  234. package/src/services/__tests__/site-admin.test.ts +121 -1
  235. package/src/services/auth.ts +2 -2
  236. package/src/services/bootstrap.ts +3 -2
  237. package/src/services/collection.ts +226 -167
  238. package/src/services/export-theme/assets/client-site.css +1 -1
  239. package/src/services/export-theme/assets/client-site.js +46 -25
  240. package/src/services/export-theme/layouts/_default/list.html +18 -4
  241. package/src/services/export-theme/layouts/_default/rss.xml +8 -12
  242. package/src/services/export-theme/layouts/featured/list.html +5 -4
  243. package/src/services/export-theme/layouts/partials/featured-thread.html +56 -0
  244. package/src/services/export-theme/layouts/partials/footer.html +1 -1
  245. package/src/services/export-theme/layouts/partials/media-gallery.html +1 -0
  246. package/src/services/export-theme/styles/main.css +30 -2
  247. package/src/services/export.ts +91 -80
  248. package/src/services/mcp.ts +37 -27
  249. package/src/services/media.ts +1 -1
  250. package/src/services/navigation.ts +185 -46
  251. package/src/services/post.ts +874 -271
  252. package/src/services/search.ts +8 -2
  253. package/src/services/settings.ts +2 -10
  254. package/src/services/site-admin.ts +63 -43
  255. package/src/style-cjk-jp.css +1 -1
  256. package/src/style-cjk-kr.css +1 -1
  257. package/src/style-cjk-tc.css +1 -1
  258. package/src/style-cjk.css +1 -1
  259. package/src/styles/components.css +540 -0
  260. package/src/styles/site-media.css +111 -19
  261. package/src/styles/tokens.css +14 -9
  262. package/src/styles/ui.css +952 -64
  263. package/src/types/bindings.ts +3 -0
  264. package/src/types/config.ts +243 -12
  265. package/src/types/constants.ts +22 -1
  266. package/src/types/entities.ts +9 -8
  267. package/src/types/operations.ts +18 -10
  268. package/src/types/props.ts +8 -2
  269. package/src/types/raw-assets.d.ts +5 -0
  270. package/src/types/views.ts +16 -4
  271. package/src/ui/__tests__/font-themes.test.ts +42 -30
  272. package/src/ui/compose/ComposeDialog.tsx +92 -2
  273. package/src/ui/dash/appearance/NavigationContent.tsx +332 -4
  274. package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +23 -0
  275. package/src/ui/dash/settings/ConfigEditorContent.tsx +578 -0
  276. package/src/ui/dash/settings/GeneralContent.tsx +15 -5
  277. package/src/ui/dash/settings/SettingsRootContent.tsx +21 -1
  278. package/src/ui/dash/settings/__tests__/ConfigEditorContent.test.tsx +98 -0
  279. package/src/ui/dash/settings/__tests__/SettingsRootContent.test.tsx +15 -0
  280. package/src/ui/feed/CuratedThreadPreview.tsx +16 -4
  281. package/src/ui/feed/LinkCard.tsx +2 -12
  282. package/src/ui/feed/NoteCard.tsx +10 -20
  283. package/src/ui/feed/QuoteCard.tsx +2 -12
  284. package/src/ui/feed/ThreadPreview.tsx +26 -34
  285. package/src/ui/feed/TimelineFeed.tsx +2 -2
  286. package/src/ui/feed/__tests__/thread-preview.test.ts +197 -56
  287. package/src/ui/feed/__tests__/timeline-cards.test.ts +186 -6
  288. package/src/ui/feed/thread-preview-state.ts +5 -7
  289. package/src/ui/font-themes.ts +74 -26
  290. package/src/ui/layouts/BaseLayout.tsx +23 -9
  291. package/src/ui/layouts/SiteLayout.tsx +19 -13
  292. package/src/ui/layouts/__tests__/BaseLayout.test.tsx +64 -1
  293. package/src/ui/layouts/__tests__/SiteLayout.test.tsx +48 -0
  294. package/src/ui/pages/CollectionPage.tsx +101 -22
  295. package/src/ui/pages/CollectionsPage.tsx +3 -1
  296. package/src/ui/pages/PostPage.tsx +39 -12
  297. package/src/ui/pages/SearchPage.tsx +6 -14
  298. package/src/ui/pages/__tests__/ArchivePage.test.tsx +7 -0
  299. package/src/ui/pages/__tests__/PostPage.test.tsx +88 -0
  300. package/src/ui/shared/CollectionDirectory.tsx +13 -9
  301. package/src/ui/shared/CollectionsManager.tsx +17 -7
  302. package/src/ui/shared/DraftPreviewBar.tsx +33 -0
  303. package/src/ui/shared/HomePageBranding.tsx +2 -2
  304. package/src/ui/shared/MediaGallery.tsx +1 -0
  305. package/src/ui/shared/PostFooter.tsx +3 -1
  306. package/src/ui/shared/__tests__/home-page-branding.test.tsx +1 -1
  307. package/src/ui/shared/__tests__/media-gallery.test.ts +1 -0
  308. package/src/ui/shared/__tests__/navigation-labels.test.ts +2 -2
  309. package/src/ui/shared/__tests__/post-footer.test.ts +15 -0
  310. package/src/ui/shared/collection-management-labels.ts +33 -2
  311. package/src/ui/shared/navigation-labels.ts +2 -4
  312. package/src/ui/shared/post-article-attributes.ts +46 -0
  313. package/dist/app-CWJFPjuR.js +0 -6
  314. package/dist/client/_assets/client-DCrcHVJl.css +0 -2
  315. package/dist/client/_assets/client-auth-TsYq90xm.js +0 -4733
  316. package/src/client/tiptap/wrapping-input-rules.ts +0 -102
@@ -13,9 +13,10 @@ import type { PasteMediaOptions } from "./paste-media.js";
13
13
  import { BubbleMenu } from "./bubble-menu.js";
14
14
  import { LinkToolbar } from "./link-toolbar.js";
15
15
  import { ExitableMarks } from "./exitable-marks.js";
16
- import { TabIndent } from "./tab-indent.js";
16
+ import { CodeBlockIndent } from "./tab-indent.js";
17
+ import { StructuralKeymap } from "./structural-keymap.js";
18
+ import { ContinuousLists } from "./continuous-lists.js";
17
19
  import { LinkInputRules } from "./link-input-rules.js";
18
- import { WrappingInputRules } from "./wrapping-input-rules.js";
19
20
  import { InsertParagraphAround } from "./insert-paragraph-around.js";
20
21
  import { Footnotes } from "./footnotes.js";
21
22
  import type { FormattingToolbarMode } from "./toolbar-mode.js";
@@ -28,6 +29,8 @@ import { RehostImages } from "./rehost-images.js";
28
29
  import type { RehostImagesOptions } from "./rehost-images.js";
29
30
  import { MarkdownClipboard } from "./markdown-clipboard.js";
30
31
  import { ImageInputRules } from "./image-input-rules.js";
32
+ import { TableControls } from "./table-controls.js";
33
+ import type { TableControlLabels } from "./table-control-labels.js";
31
34
  import {
32
35
  MARKDOWN_MARKED_OPTIONS,
33
36
  createMarkdownContentExtensions,
@@ -39,6 +42,7 @@ export interface EditorExtensionOptions {
39
42
  pasteMedia?: PasteMediaOptions;
40
43
  rehostImages?: RehostImagesOptions;
41
44
  imageNodeLabels?: Partial<ImageNodeLabels>;
45
+ tableControlLabels?: TableControlLabels;
42
46
  }
43
47
 
44
48
  /**
@@ -83,10 +87,11 @@ export function createSettingsEditorExtensions(
83
87
  }),
84
88
  ReclaimModEnter,
85
89
  LinkInputRules,
86
- WrappingInputRules,
87
90
  MarkdownClipboard,
88
91
  ExitableMarks,
89
92
  InsertParagraphAround,
93
+ StructuralKeymap,
94
+ ContinuousLists,
90
95
  BubbleMenu.configure({
91
96
  toolbarMode: "compose",
92
97
  }),
@@ -116,9 +121,11 @@ export function createEditorExtensions(
116
121
  Footnotes,
117
122
  ImageInputRules,
118
123
  LinkInputRules,
119
- WrappingInputRules,
120
124
  MarkdownClipboard,
121
125
  SlashCommands,
126
+ ...(options.tableControlLabels
127
+ ? [TableControls.configure({ labels: options.tableControlLabels })]
128
+ : []),
122
129
  EmbedPaste,
123
130
  PasteMedia.configure(options.pasteMedia ?? {}),
124
131
  RehostImages.configure(options.rehostImages ?? {}),
@@ -128,6 +135,8 @@ export function createEditorExtensions(
128
135
  LinkToolbar,
129
136
  ExitableMarks,
130
137
  InsertParagraphAround,
131
- TabIndent,
138
+ StructuralKeymap,
139
+ ContinuousLists,
140
+ CodeBlockIndent,
132
141
  ];
133
142
  }
@@ -2,6 +2,7 @@ import { Extension, InputRule } from "@tiptap/core";
2
2
  import { Fragment, type Node as ProseMirrorNode } from "@tiptap/pm/model";
3
3
  import {
4
4
  NodeSelection,
5
+ Plugin,
5
6
  TextSelection,
6
7
  type EditorState,
7
8
  type Transaction,
@@ -195,6 +196,85 @@ function ensureFootnoteDefinition(
195
196
  return insertPos;
196
197
  }
197
198
 
199
+ function collectMissingFootnoteDefinitionLabels(
200
+ doc: ProseMirrorNode,
201
+ ): string[] {
202
+ const definedLabels = new Set<string>();
203
+ const queuedLabels = new Set<string>();
204
+ const missingLabels: string[] = [];
205
+
206
+ doc.forEach((node) => {
207
+ if (node.type.name !== "footnoteDefinition") {
208
+ return;
209
+ }
210
+
211
+ const label = normalizeFootnoteLabel(node.attrs.label);
212
+ if (label) {
213
+ definedLabels.add(getFootnoteLabelKey(label));
214
+ }
215
+ });
216
+
217
+ doc.descendants((node) => {
218
+ if (node.type.name !== "footnoteReference") {
219
+ return true;
220
+ }
221
+
222
+ const label = normalizeFootnoteLabel(node.attrs.label);
223
+ const labelKey = getFootnoteLabelKey(label);
224
+ if (label && !definedLabels.has(labelKey) && !queuedLabels.has(labelKey)) {
225
+ queuedLabels.add(labelKey);
226
+ missingLabels.push(label);
227
+ }
228
+
229
+ return true;
230
+ });
231
+
232
+ return missingLabels;
233
+ }
234
+
235
+ function buildEnsureFootnoteDefinitionsTransaction(
236
+ state: EditorState,
237
+ ): Transaction | null {
238
+ const missingLabels = collectMissingFootnoteDefinitionLabels(state.doc);
239
+ if (missingLabels.length === 0) {
240
+ return null;
241
+ }
242
+
243
+ const tr = state.tr;
244
+ for (const label of missingLabels) {
245
+ ensureFootnoteDefinition(state, tr, label);
246
+ }
247
+
248
+ return tr.docChanged ? tr : null;
249
+ }
250
+
251
+ function getSelectedFootnoteReferenceLabel(state: EditorState): string | null {
252
+ const { selection } = state;
253
+ if (
254
+ !(selection instanceof NodeSelection) ||
255
+ selection.node.type.name !== "footnoteReference"
256
+ ) {
257
+ return null;
258
+ }
259
+
260
+ return normalizeFootnoteLabel(selection.node.attrs.label) || null;
261
+ }
262
+
263
+ function buildNavigateToFootnoteDefinitionTransaction(
264
+ state: EditorState,
265
+ label: string,
266
+ ): Transaction | null {
267
+ const tr = state.tr;
268
+ const definitionPos = ensureFootnoteDefinition(state, tr, label);
269
+ if (definitionPos === null) {
270
+ return null;
271
+ }
272
+
273
+ setSelectionInsideInsertedFootnote(tr, definitionPos);
274
+ tr.scrollIntoView();
275
+ return tr;
276
+ }
277
+
198
278
  function ensureNonEmptyDoc(state: EditorState, tr: Transaction) {
199
279
  if (tr.doc.childCount > 0) {
200
280
  return;
@@ -603,6 +683,66 @@ declare module "@tiptap/core" {
603
683
  export const Footnotes = Extension.create({
604
684
  name: "footnotes",
605
685
 
686
+ onCreate() {
687
+ const tr = buildEnsureFootnoteDefinitionsTransaction(this.editor.state);
688
+ if (tr) {
689
+ this.editor.view.dispatch(tr);
690
+ }
691
+ },
692
+
693
+ addProseMirrorPlugins() {
694
+ return [
695
+ new Plugin({
696
+ appendTransaction: (transactions, _oldState, newState) => {
697
+ if (!transactions.some((transaction) => transaction.docChanged)) {
698
+ return null;
699
+ }
700
+
701
+ return buildEnsureFootnoteDefinitionsTransaction(newState);
702
+ },
703
+ props: {
704
+ handleClickOn: (view, _pos, node, _nodePos, _event, direct) => {
705
+ if (!direct || node.type.name !== "footnoteReference") {
706
+ return false;
707
+ }
708
+
709
+ const label = normalizeFootnoteLabel(node.attrs.label);
710
+ if (!label) {
711
+ return false;
712
+ }
713
+
714
+ const tr = buildNavigateToFootnoteDefinitionTransaction(
715
+ view.state,
716
+ label,
717
+ );
718
+ if (!tr) {
719
+ return false;
720
+ }
721
+
722
+ view.dispatch(tr);
723
+ view.focus();
724
+ return true;
725
+ },
726
+ handleClick: (view, pos) => {
727
+ const $pos = view.state.doc.resolve(pos);
728
+ if (
729
+ $pos.nodeBefore?.type.name !== "footnoteDefinition" ||
730
+ $pos.nodeAfter?.type.name !== "footnoteDefinition"
731
+ ) {
732
+ return false;
733
+ }
734
+
735
+ const tr = view.state.tr;
736
+ setSelectionInsideInsertedFootnote(tr, pos);
737
+ view.dispatch(tr.scrollIntoView());
738
+ view.focus();
739
+ return true;
740
+ },
741
+ },
742
+ }),
743
+ ];
744
+ },
745
+
606
746
  addCommands() {
607
747
  return {
608
748
  insertFootnote:
@@ -649,6 +789,22 @@ export const Footnotes = Extension.create({
649
789
  addKeyboardShortcuts() {
650
790
  return {
651
791
  Enter: ({ editor }) => {
792
+ const selectedReferenceLabel = getSelectedFootnoteReferenceLabel(
793
+ editor.state,
794
+ );
795
+ if (selectedReferenceLabel) {
796
+ const navigateTr = buildNavigateToFootnoteDefinitionTransaction(
797
+ editor.state,
798
+ selectedReferenceLabel,
799
+ );
800
+ if (!navigateTr) {
801
+ return false;
802
+ }
803
+
804
+ editor.view.dispatch(navigateTr);
805
+ return true;
806
+ }
807
+
652
808
  const tr = activateTrailingFootnoteAtParagraphEnd(editor.state);
653
809
  if (!tr) {
654
810
  return false;