@jant/core 0.6.14 → 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.
- package/bin/commands/import-site.js +81 -13
- package/bin/commands/migrate.js +55 -0
- package/bin/commands/posts/rebuild-html.js +184 -0
- package/bin/commands/site/snapshot/import.js +14 -10
- package/bin/lib/d1-query.js +23 -5
- package/bin/lib/migration-runner.js +29 -7
- package/bin/lib/node-database.js +32 -0
- package/bin/lib/site-snapshot.js +347 -46
- package/bin/lib/sql-export.js +1 -1
- package/bin/lib/thread-collection-migration.js +326 -0
- package/dist/app-BxCOR3Uc.js +6 -0
- package/dist/{app-2i7-WQHg.js → app-C-oi_t8W.js} +7408 -6343
- package/dist/client/.vite/manifest.json +3 -3
- package/dist/client/_assets/client-B_eGKN5p.css +2 -0
- package/dist/client/_assets/{client-BvID5ucz.js → client-DxY5BFe8.js} +58 -37
- package/dist/client/_assets/client-auth-CakPESv9.js +5533 -0
- package/dist/{export-DWn149b7.js → export-CsFx6F_M.js} +1259 -125
- package/dist/{github-sync-Ckk0sJxK.js → github-sync-Cq1pzzOI.js} +1 -1
- package/dist/{github-sync-C0zyF6XS.js → github-sync-ppWXN3jb.js} +2 -2
- package/dist/index.js +3 -3
- package/dist/node.js +5 -5
- package/package.json +11 -10
- package/src/__tests__/bin/posts-rebuild-html.test.ts +137 -0
- package/src/__tests__/dev-navigation-defaults.test.ts +22 -0
- package/src/__tests__/export-hugo-build.test.ts +63 -4
- package/src/__tests__/export-import-roundtrip.test.ts +6 -4
- package/src/__tests__/export-service.test.ts +142 -9
- package/src/__tests__/helpers/app.ts +3 -0
- package/src/__tests__/helpers/export-fixtures.ts +2 -0
- package/src/__tests__/import-site-command.test.ts +65 -0
- package/src/__tests__/vite-config.test.ts +45 -0
- package/src/app.tsx +16 -3
- package/src/client/__tests__/collection-created-notice.test.ts +36 -0
- package/src/client/__tests__/collection-form-bridge.test.ts +10 -1
- package/src/client/__tests__/collection-page-actions.test.ts +71 -2
- package/src/client/__tests__/compose-bridge.test.ts +64 -0
- package/src/client/__tests__/feed-video-player.test.ts +16 -1
- package/src/client/__tests__/footnote-rail.test.ts +472 -0
- package/src/client/__tests__/hydrate-partial.test.ts +3 -0
- package/src/client/__tests__/toast.test.ts +18 -1
- package/src/client/collection-created-notice.ts +66 -0
- package/src/client/collection-form-bridge.ts +17 -0
- package/src/client/collection-navigation.ts +44 -0
- package/src/client/collection-page-actions.ts +57 -1
- package/src/client/components/__tests__/jant-collection-directory.test.ts +155 -6
- package/src/client/components/__tests__/jant-compose-dialog.test.ts +370 -5
- package/src/client/components/__tests__/jant-compose-editor.test.ts +97 -0
- package/src/client/components/__tests__/jant-compose-fullscreen.test.ts +104 -0
- package/src/client/components/__tests__/jant-config-editor.test.ts +405 -0
- package/src/client/components/__tests__/jant-media-lightbox.test.ts +121 -0
- package/src/client/components/__tests__/jant-nav-manager.test.ts +538 -2
- package/src/client/components/__tests__/jant-post-form.test.ts +2 -2
- package/src/client/components/__tests__/jant-post-menu.test.ts +47 -5
- package/src/client/components/__tests__/jant-settings-avatar.test.ts +2 -2
- package/src/client/components/__tests__/jant-settings-general.test.ts +3 -3
- package/src/client/components/collection-manager-types.ts +9 -3
- package/src/client/components/compose-types.ts +8 -0
- package/src/client/components/jant-collection-directory.ts +165 -30
- package/src/client/components/jant-command-palette.ts +2 -1
- package/src/client/components/jant-compose-dialog.ts +85 -21
- package/src/client/components/jant-compose-editor.ts +13 -7
- package/src/client/components/jant-compose-fullscreen.ts +24 -4
- package/src/client/components/jant-config-editor.ts +722 -0
- package/src/client/components/jant-media-lightbox.ts +100 -18
- package/src/client/components/jant-nav-manager.ts +1283 -54
- package/src/client/components/jant-post-form.ts +3 -3
- package/src/client/components/jant-post-menu.ts +86 -74
- package/src/client/components/nav-manager-types.ts +51 -2
- package/src/client/components/post-form-types.ts +1 -1
- package/src/client/compose-bridge.ts +4 -1
- package/src/client/feed-video-player.ts +62 -2
- package/src/client/footnote-rail.ts +478 -0
- package/src/client/hydrate-partial.ts +2 -0
- package/src/client/media-lightbox-events.ts +63 -0
- package/src/client/site-header-fragment.ts +38 -0
- package/src/client/tiptap/__tests__/blockquote-editing.test.ts +201 -0
- package/src/client/tiptap/__tests__/clear-formatting.test.ts +168 -0
- package/src/client/tiptap/__tests__/list-editing.test.ts +447 -0
- package/src/client/tiptap/__tests__/markdown-clipboard.test.ts +727 -4
- package/src/client/tiptap/__tests__/table-controls.test.ts +263 -0
- package/src/client/tiptap/__tests__/table-size-picker.test.ts +179 -0
- package/src/client/tiptap/bubble-menu.ts +88 -10
- package/src/client/tiptap/continuous-lists.ts +102 -0
- package/src/client/tiptap/create-editor.ts +3 -0
- package/src/client/tiptap/extensions.ts +14 -5
- package/src/client/tiptap/markdown-clipboard.ts +608 -11
- package/src/client/tiptap/slash-commands.ts +8 -1
- package/src/client/tiptap/structural-keymap.ts +211 -0
- package/src/client/tiptap/tab-indent.ts +8 -22
- package/src/client/tiptap/table-control-labels.ts +30 -0
- package/src/client/tiptap/table-controls.ts +537 -0
- package/src/client/tiptap/table-size-picker.ts +254 -0
- package/src/client/toast.ts +8 -6
- package/src/client-auth.ts +1 -0
- package/src/client.ts +1 -0
- package/src/db/__tests__/d1-query.test.ts +43 -1
- package/src/db/__tests__/migration-runner.test.ts +63 -0
- package/src/db/__tests__/migrations.test.ts +469 -0
- package/src/db/__tests__/thread-collection-migration.test.ts +364 -0
- package/src/db/migrations/0027_old_blue_blade.sql +39 -0
- package/src/db/migrations/0028_superb_post.sql +2 -0
- package/src/db/migrations/0029_boring_magma.sql +1 -0
- package/src/db/migrations/0030_typical_vivisector.sql +50 -0
- package/src/db/migrations/meta/0027_snapshot.json +2511 -0
- package/src/db/migrations/meta/0028_snapshot.json +2511 -0
- package/src/db/migrations/meta/0029_snapshot.json +2519 -0
- package/src/db/migrations/meta/0030_snapshot.json +2541 -0
- package/src/db/migrations/meta/_journal.json +28 -0
- package/src/db/migrations/pg/0025_moaning_epoch.sql +39 -0
- package/src/db/migrations/pg/0026_talented_killer_shrike.sql +2 -0
- package/src/db/migrations/pg/0027_short_cannonball.sql +1 -0
- package/src/db/migrations/pg/0028_perfect_sharon_carter.sql +27 -0
- package/src/db/migrations/pg/meta/0025_snapshot.json +3204 -0
- package/src/db/migrations/pg/meta/0026_snapshot.json +3204 -0
- package/src/db/migrations/pg/meta/0027_snapshot.json +3211 -0
- package/src/db/migrations/pg/meta/0028_snapshot.json +3248 -0
- package/src/db/migrations/pg/meta/_journal.json +28 -0
- package/src/db/pg/schema.ts +28 -20
- package/src/db/rehearsal-fixtures/demo-current.json +39 -4
- package/src/db/rehearsal-fixtures/demo-current.sql +121 -6
- package/src/db/schema.ts +28 -20
- package/src/i18n/__tests__/detect.test.ts +8 -2
- package/src/i18n/detect.ts +14 -5
- package/src/i18n/locales/public/en.po +133 -30
- package/src/i18n/locales/public/en.ts +1 -1
- package/src/i18n/locales/public/zh-Hans.po +128 -25
- package/src/i18n/locales/public/zh-Hans.ts +1 -1
- package/src/i18n/locales/public/zh-Hant.po +128 -25
- package/src/i18n/locales/public/zh-Hant.ts +1 -1
- package/src/i18n/locales/settings/en.po +513 -10
- package/src/i18n/locales/settings/en.ts +1 -1
- package/src/i18n/locales/settings/zh-Hans.po +515 -12
- package/src/i18n/locales/settings/zh-Hans.ts +1 -1
- package/src/i18n/locales/settings/zh-Hant.po +515 -12
- package/src/i18n/locales/settings/zh-Hant.ts +1 -1
- package/src/lib/__tests__/api-settings.test.ts +299 -0
- package/src/lib/__tests__/constants.test.ts +5 -0
- package/src/lib/__tests__/feed-policy.test.ts +25 -0
- package/src/lib/__tests__/footnotes-upgrade.test.ts +181 -0
- package/src/lib/__tests__/markdown-roundtrip-embed.test.ts +61 -0
- package/src/lib/__tests__/markdown-to-tiptap.test.ts +32 -4
- package/src/lib/__tests__/markdown.test.ts +8 -6
- package/src/lib/__tests__/navigation.test.ts +59 -2
- package/src/lib/__tests__/post-body-html.test.ts +176 -0
- package/src/lib/__tests__/post-display.test.ts +64 -0
- package/src/lib/__tests__/resolve-config.test.ts +113 -1
- package/src/lib/__tests__/summary.test.ts +82 -0
- package/src/lib/__tests__/timeline.test.ts +109 -70
- package/src/lib/__tests__/timezones.test.ts +31 -3
- package/src/lib/__tests__/tiptap-render.test.ts +268 -9
- package/src/lib/__tests__/tiptap-to-markdown.test.ts +6 -0
- package/src/lib/__tests__/view.test.ts +53 -0
- package/src/lib/__tests__/worker-response-cache.test.ts +18 -1
- package/src/lib/api-settings.ts +239 -12
- package/src/lib/collection-sort.ts +7 -5
- package/src/lib/constants.ts +2 -0
- package/src/lib/feed-path.ts +25 -0
- package/src/lib/feed-policy.ts +64 -0
- package/src/lib/footnotes.ts +264 -0
- package/src/lib/github-sync-site-config.ts +2 -0
- package/src/lib/hugo-markdown.ts +10 -3
- package/src/lib/jant-branding.ts +1 -0
- package/src/lib/markdown-manager.ts +188 -5
- package/src/lib/markdown.ts +10 -3
- package/src/lib/navigation.ts +16 -3
- package/src/lib/post-body-html.ts +131 -0
- package/src/lib/post-display.ts +7 -1
- package/src/lib/render.tsx +9 -2
- package/src/lib/resolve-config.ts +100 -16
- package/src/lib/schemas.ts +133 -1
- package/src/lib/settings-paths.ts +5 -0
- package/src/lib/site-skill.ts +78 -0
- package/src/lib/summary.ts +16 -5
- package/src/lib/timeline.ts +98 -122
- package/src/lib/timezones.ts +54 -14
- package/src/lib/tiptap-render.ts +355 -81
- package/src/lib/view.ts +30 -20
- package/src/lib/worker-response-cache.ts +11 -18
- package/src/middleware/__tests__/public-content-access.test.ts +91 -0
- package/src/middleware/config.ts +2 -2
- package/src/middleware/public-content-access.ts +87 -0
- package/src/node/__tests__/cli-export.test.ts +14 -0
- package/src/node/__tests__/cli-migrate.test.ts +6 -0
- package/src/node/__tests__/cli-site-snapshot.test.ts +205 -2
- package/src/node/__tests__/cli-snapshot-meta.test.ts +100 -0
- package/src/node/index.ts +2 -1
- package/src/preset.css +16 -2
- package/src/routes/__tests__/compose.test.ts +51 -0
- package/src/routes/__tests__/site-skill.test.ts +112 -0
- package/src/routes/api/__tests__/collections.test.ts +91 -19
- package/src/routes/api/__tests__/mcp.test.ts +65 -1
- package/src/routes/api/__tests__/nav-items.test.ts +91 -0
- package/src/routes/api/__tests__/public-access.test.ts +81 -0
- package/src/routes/api/__tests__/settings.test.ts +217 -0
- package/src/routes/api/collections.ts +22 -26
- package/src/routes/api/export.ts +2 -0
- package/src/routes/api/internal/__tests__/post-body-html.test.ts +163 -0
- package/src/routes/api/internal/__tests__/sites.test.ts +35 -2
- package/src/routes/api/internal/post-body-html.ts +43 -0
- package/src/routes/api/internal/sites.ts +24 -0
- package/src/routes/api/nav-items.ts +24 -1
- package/src/routes/api/posts.ts +2 -2
- package/src/routes/api/public/__tests__/archive.test.ts +35 -0
- package/src/routes/api/public/__tests__/posts.test.ts +208 -0
- package/src/routes/api/public/archive.ts +4 -0
- package/src/routes/api/public/posts.ts +41 -24
- package/src/routes/api/search.ts +3 -0
- package/src/routes/api/settings.ts +33 -0
- package/src/routes/auth/__tests__/setup.test.ts +7 -4
- package/src/routes/compose.tsx +2 -1
- package/src/routes/dash/settings.tsx +45 -2
- package/src/routes/feed/__tests__/feed.test.ts +210 -6
- package/src/routes/feed/feed.ts +23 -14
- package/src/routes/pages/__tests__/archive-params.test.ts +92 -3
- package/src/routes/pages/__tests__/collection-routing.test.ts +63 -5
- package/src/routes/pages/__tests__/collections.test.ts +9 -9
- package/src/routes/pages/__tests__/preview.test.ts +174 -0
- package/src/routes/pages/__tests__/search.test.ts +69 -0
- package/src/routes/pages/archive.tsx +27 -7
- package/src/routes/pages/collection.tsx +32 -19
- package/src/routes/pages/collections.tsx +6 -1
- package/src/routes/pages/page.tsx +83 -11
- package/src/routes/site-skill.ts +18 -0
- package/src/services/__tests__/auth.test.ts +7 -5
- package/src/services/__tests__/collection.test.ts +159 -44
- package/src/services/__tests__/navigation.test.ts +229 -21
- package/src/services/__tests__/post-timeline.test.ts +109 -30
- package/src/services/__tests__/post.test.ts +567 -5
- package/src/services/__tests__/search.test.ts +48 -1
- package/src/services/__tests__/settings.test.ts +8 -0
- package/src/services/__tests__/site-admin.test.ts +121 -1
- package/src/services/auth.ts +2 -2
- package/src/services/bootstrap.ts +3 -2
- package/src/services/collection.ts +226 -167
- package/src/services/export-theme/assets/client-site.css +1 -1
- package/src/services/export-theme/assets/client-site.js +46 -25
- package/src/services/export-theme/layouts/_default/list.html +18 -4
- package/src/services/export-theme/layouts/_default/rss.xml +8 -12
- package/src/services/export-theme/layouts/featured/list.html +5 -4
- package/src/services/export-theme/layouts/partials/featured-thread.html +56 -0
- package/src/services/export-theme/layouts/partials/footer.html +1 -1
- package/src/services/export-theme/layouts/partials/media-gallery.html +1 -0
- package/src/services/export-theme/styles/main.css +30 -2
- package/src/services/export.ts +91 -80
- package/src/services/mcp.ts +37 -27
- package/src/services/media.ts +1 -1
- package/src/services/navigation.ts +185 -46
- package/src/services/post.ts +874 -271
- package/src/services/search.ts +8 -2
- package/src/services/settings.ts +2 -10
- package/src/services/site-admin.ts +63 -43
- package/src/style-cjk-jp.css +1 -1
- package/src/style-cjk-kr.css +1 -1
- package/src/style-cjk-tc.css +1 -1
- package/src/style-cjk.css +1 -1
- package/src/styles/components.css +540 -0
- package/src/styles/site-media.css +111 -19
- package/src/styles/tokens.css +14 -9
- package/src/styles/ui.css +829 -29
- package/src/types/bindings.ts +3 -0
- package/src/types/config.ts +243 -12
- package/src/types/constants.ts +22 -1
- package/src/types/entities.ts +9 -8
- package/src/types/operations.ts +18 -10
- package/src/types/props.ts +8 -2
- package/src/types/raw-assets.d.ts +5 -0
- package/src/types/views.ts +16 -4
- package/src/ui/__tests__/font-themes.test.ts +42 -30
- package/src/ui/compose/ComposeDialog.tsx +92 -2
- package/src/ui/dash/appearance/NavigationContent.tsx +332 -4
- package/src/ui/dash/appearance/__tests__/NavigationContent.test.tsx +23 -0
- package/src/ui/dash/settings/ConfigEditorContent.tsx +578 -0
- package/src/ui/dash/settings/GeneralContent.tsx +15 -5
- package/src/ui/dash/settings/SettingsRootContent.tsx +21 -1
- package/src/ui/dash/settings/__tests__/ConfigEditorContent.test.tsx +98 -0
- package/src/ui/dash/settings/__tests__/SettingsRootContent.test.tsx +15 -0
- package/src/ui/feed/CuratedThreadPreview.tsx +16 -4
- package/src/ui/feed/LinkCard.tsx +2 -12
- package/src/ui/feed/NoteCard.tsx +10 -20
- package/src/ui/feed/QuoteCard.tsx +2 -12
- package/src/ui/feed/ThreadPreview.tsx +26 -34
- package/src/ui/feed/TimelineFeed.tsx +2 -2
- package/src/ui/feed/__tests__/thread-preview.test.ts +197 -56
- package/src/ui/feed/__tests__/timeline-cards.test.ts +178 -3
- package/src/ui/feed/thread-preview-state.ts +5 -7
- package/src/ui/font-themes.ts +74 -26
- package/src/ui/layouts/BaseLayout.tsx +22 -8
- package/src/ui/layouts/__tests__/BaseLayout.test.tsx +64 -1
- package/src/ui/pages/CollectionPage.tsx +101 -22
- package/src/ui/pages/CollectionsPage.tsx +3 -1
- package/src/ui/pages/PostPage.tsx +39 -12
- package/src/ui/pages/SearchPage.tsx +6 -14
- package/src/ui/pages/__tests__/ArchivePage.test.tsx +7 -0
- package/src/ui/pages/__tests__/PostPage.test.tsx +88 -0
- package/src/ui/shared/CollectionDirectory.tsx +13 -9
- package/src/ui/shared/CollectionsManager.tsx +17 -7
- package/src/ui/shared/DraftPreviewBar.tsx +33 -0
- package/src/ui/shared/HomePageBranding.tsx +2 -2
- package/src/ui/shared/MediaGallery.tsx +1 -0
- package/src/ui/shared/PostFooter.tsx +3 -1
- package/src/ui/shared/__tests__/home-page-branding.test.tsx +1 -1
- package/src/ui/shared/__tests__/media-gallery.test.ts +1 -0
- package/src/ui/shared/__tests__/navigation-labels.test.ts +2 -2
- package/src/ui/shared/__tests__/post-footer.test.ts +15 -0
- package/src/ui/shared/collection-management-labels.ts +33 -2
- package/src/ui/shared/navigation-labels.ts +2 -4
- package/src/ui/shared/post-article-attributes.ts +46 -0
- package/dist/app-DZDlmh7C.js +0 -6
- package/dist/client/_assets/client-Cevfpm8H.css +0 -2
- package/dist/client/_assets/client-auth-v3yvhbgZ.js +0 -4736
- package/src/client/tiptap/wrapping-input-rules.ts +0 -102
|
@@ -14,6 +14,8 @@ import Suggestion, {
|
|
|
14
14
|
import type { Editor, Range } from "@tiptap/core";
|
|
15
15
|
import { Plugin, PluginKey, type EditorState } from "@tiptap/pm/state";
|
|
16
16
|
import { escapeHtml } from "../../lib/html.js";
|
|
17
|
+
import { getConfiguredTableControlLabels } from "./table-controls.js";
|
|
18
|
+
import { openTableSizePicker } from "./table-size-picker.js";
|
|
17
19
|
import { getBestFieldSearchRank, normalizeSearch } from "../search-rank.js";
|
|
18
20
|
import {
|
|
19
21
|
getFixedFloatingContainerRect,
|
|
@@ -165,11 +167,16 @@ const SLASH_COMMANDS: SlashCommandItem[] = [
|
|
|
165
167
|
},
|
|
166
168
|
{
|
|
167
169
|
label: "Table",
|
|
168
|
-
description: "Insert a
|
|
170
|
+
description: "Insert a table.",
|
|
169
171
|
group: "structure",
|
|
170
172
|
keywords: ["grid", "rows", "columns", "spreadsheet"],
|
|
171
173
|
icon: ICONS.table,
|
|
172
174
|
command: (editor, range) => {
|
|
175
|
+
const labels = getConfiguredTableControlLabels(editor);
|
|
176
|
+
if (labels) {
|
|
177
|
+
openTableSizePicker(editor, range, labels);
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
173
180
|
editor
|
|
174
181
|
.chain()
|
|
175
182
|
.focus()
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compose Structural Keymap
|
|
3
|
+
*
|
|
4
|
+
* Keeps Jant's small set of product-specific block-boundary decisions in one
|
|
5
|
+
* place while delegating every unowned case to Tiptap's official keymaps.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Extension, type Editor } from "@tiptap/core";
|
|
9
|
+
import type { Node as ProseMirrorNode, ResolvedPos } from "@tiptap/pm/model";
|
|
10
|
+
|
|
11
|
+
type Direction = "backward" | "forward";
|
|
12
|
+
|
|
13
|
+
interface DirectParagraph {
|
|
14
|
+
kind: "plain" | "quote";
|
|
15
|
+
topIndex: number;
|
|
16
|
+
quoteChildIndex?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function locateDirectParagraph($cursor: ResolvedPos): DirectParagraph | null {
|
|
20
|
+
const { schema } = $cursor.doc.type;
|
|
21
|
+
if ($cursor.parent.type !== schema.nodes.paragraph) return null;
|
|
22
|
+
|
|
23
|
+
if ($cursor.depth === 1) {
|
|
24
|
+
return { kind: "plain", topIndex: $cursor.index(0) };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if ($cursor.depth === 2 && $cursor.node(1).type === schema.nodes.blockquote) {
|
|
28
|
+
return {
|
|
29
|
+
kind: "quote",
|
|
30
|
+
topIndex: $cursor.index(0),
|
|
31
|
+
quoteChildIndex: $cursor.index(1),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function paragraphKindAtQuoteEdge(
|
|
39
|
+
node: ProseMirrorNode,
|
|
40
|
+
direction: Direction,
|
|
41
|
+
): DirectParagraph["kind"] | null {
|
|
42
|
+
if (node.type.name !== "blockquote") return null;
|
|
43
|
+
|
|
44
|
+
const edge = direction === "backward" ? node.lastChild : node.firstChild;
|
|
45
|
+
return edge?.type.name === "paragraph" ? "quote" : null;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function findNeighborParagraphKind(
|
|
49
|
+
$cursor: ResolvedPos,
|
|
50
|
+
current: DirectParagraph,
|
|
51
|
+
direction: Direction,
|
|
52
|
+
): DirectParagraph["kind"] | null {
|
|
53
|
+
const offset = direction === "backward" ? -1 : 1;
|
|
54
|
+
|
|
55
|
+
if (current.kind === "quote") {
|
|
56
|
+
const quote = $cursor.doc.child(current.topIndex);
|
|
57
|
+
const childIndex = current.quoteChildIndex;
|
|
58
|
+
if (childIndex === undefined) return null;
|
|
59
|
+
|
|
60
|
+
const neighborIndex = childIndex + offset;
|
|
61
|
+
if (neighborIndex >= 0 && neighborIndex < quote.childCount) {
|
|
62
|
+
return quote.child(neighborIndex).type.name === "paragraph"
|
|
63
|
+
? "quote"
|
|
64
|
+
: null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const topIndex = current.topIndex + offset;
|
|
69
|
+
if (topIndex < 0 || topIndex >= $cursor.doc.childCount) return null;
|
|
70
|
+
|
|
71
|
+
const topNode = $cursor.doc.child(topIndex);
|
|
72
|
+
if (topNode.type.name === "paragraph") return "plain";
|
|
73
|
+
|
|
74
|
+
return paragraphKindAtQuoteEdge(topNode, direction);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function joinBlockquoteParagraphBoundary(
|
|
78
|
+
editor: Editor,
|
|
79
|
+
direction: Direction,
|
|
80
|
+
): boolean {
|
|
81
|
+
const { selection } = editor.state;
|
|
82
|
+
if (!selection.empty) return false;
|
|
83
|
+
|
|
84
|
+
const { $from } = selection;
|
|
85
|
+
const atBoundary =
|
|
86
|
+
direction === "backward"
|
|
87
|
+
? $from.parentOffset === 0
|
|
88
|
+
: $from.parentOffset === $from.parent.content.size;
|
|
89
|
+
if (!atBoundary) return false;
|
|
90
|
+
|
|
91
|
+
const current = locateDirectParagraph($from);
|
|
92
|
+
if (!current) return false;
|
|
93
|
+
|
|
94
|
+
const neighborKind = findNeighborParagraphKind($from, current, direction);
|
|
95
|
+
if (!neighborKind || (current.kind !== "quote" && neighborKind !== "quote")) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return direction === "backward"
|
|
100
|
+
? editor.commands.joinTextblockBackward()
|
|
101
|
+
: editor.commands.joinTextblockForward();
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function findDirectListItemDepth($cursor: ResolvedPos): number | null {
|
|
105
|
+
const listItemDepth = $cursor.depth - 1;
|
|
106
|
+
if (
|
|
107
|
+
listItemDepth <= 0 ||
|
|
108
|
+
$cursor.node(listItemDepth).type.name !== "listItem"
|
|
109
|
+
) {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const listDepth = listItemDepth - 1;
|
|
114
|
+
const listName = $cursor.node(listDepth).type.name;
|
|
115
|
+
return listName === "bulletList" || listName === "orderedList"
|
|
116
|
+
? listItemDepth
|
|
117
|
+
: null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function joinListItemBackward(editor: Editor): boolean {
|
|
121
|
+
const { selection } = editor.state;
|
|
122
|
+
if (!selection.empty) return false;
|
|
123
|
+
|
|
124
|
+
const { $from } = selection;
|
|
125
|
+
if ($from.parentOffset !== 0 || !$from.parent.isTextblock) return false;
|
|
126
|
+
|
|
127
|
+
const listItemDepth = findDirectListItemDepth($from);
|
|
128
|
+
if (listItemDepth === null) return false;
|
|
129
|
+
|
|
130
|
+
const listItem = $from.node(listItemDepth);
|
|
131
|
+
const childIndex = $from.index(listItemDepth);
|
|
132
|
+
|
|
133
|
+
if (childIndex > 0) {
|
|
134
|
+
const previousChild = listItem.child(childIndex - 1);
|
|
135
|
+
if (previousChild.isTextblock) {
|
|
136
|
+
return editor.commands.joinTextblockBackward();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// A paragraph following a nested structural block has no unambiguous
|
|
140
|
+
// one-key merge target. Consume Backspace instead of letting ListKeymap
|
|
141
|
+
// lift and split the entire list item.
|
|
142
|
+
return true;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const listDepth = listItemDepth - 1;
|
|
146
|
+
const itemIndex = $from.index(listDepth);
|
|
147
|
+
if (itemIndex === 0) {
|
|
148
|
+
// Let the official ListKeymap lift a first/nested-first item.
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (editor.commands.joinItemBackward()) return true;
|
|
153
|
+
|
|
154
|
+
// `joinItemBackward` cannot join when the previous item already owns a
|
|
155
|
+
// nested list. The official textblock join safely removes the current marker
|
|
156
|
+
// while preserving both subtrees in their existing document order.
|
|
157
|
+
if (editor.commands.joinBackward()) return true;
|
|
158
|
+
|
|
159
|
+
// A same-level previous item exists, so never fall through to the official
|
|
160
|
+
// lift behavior, which would split the surrounding list into top-level blocks.
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function handleBackspace(editor: Editor): boolean {
|
|
165
|
+
const { selection } = editor.state;
|
|
166
|
+
if (
|
|
167
|
+
!selection.empty ||
|
|
168
|
+
!selection.$from.parent.isTextblock ||
|
|
169
|
+
selection.$from.parentOffset !== 0
|
|
170
|
+
) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Let the official input-rule undo run before any Jant boundary behavior, so
|
|
175
|
+
// Backspace immediately after `- ` or `> ` reverses that structural change.
|
|
176
|
+
if (editor.commands.undoInputRule()) return true;
|
|
177
|
+
|
|
178
|
+
return (
|
|
179
|
+
joinListItemBackward(editor) ||
|
|
180
|
+
joinBlockquoteParagraphBoundary(editor, "backward")
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export const StructuralKeymap = Extension.create({
|
|
185
|
+
name: "structuralKeymap",
|
|
186
|
+
priority: 1000,
|
|
187
|
+
|
|
188
|
+
addKeyboardShortcuts() {
|
|
189
|
+
return {
|
|
190
|
+
Backspace: ({ editor }) => handleBackspace(editor),
|
|
191
|
+
"Mod-Backspace": ({ editor }) => handleBackspace(editor),
|
|
192
|
+
"Shift-Backspace": ({ editor }) => handleBackspace(editor),
|
|
193
|
+
Delete: ({ editor }) =>
|
|
194
|
+
joinBlockquoteParagraphBoundary(editor, "forward"),
|
|
195
|
+
"Mod-Delete": ({ editor }) =>
|
|
196
|
+
joinBlockquoteParagraphBoundary(editor, "forward"),
|
|
197
|
+
Tab: ({ editor }) => {
|
|
198
|
+
if (!editor.isActive("listItem")) return false;
|
|
199
|
+
|
|
200
|
+
editor.commands.sinkListItem("listItem");
|
|
201
|
+
return true;
|
|
202
|
+
},
|
|
203
|
+
"Shift-Tab": ({ editor }) => {
|
|
204
|
+
if (!editor.isActive("listItem")) return false;
|
|
205
|
+
|
|
206
|
+
editor.commands.liftListItem("listItem");
|
|
207
|
+
return true;
|
|
208
|
+
},
|
|
209
|
+
};
|
|
210
|
+
},
|
|
211
|
+
});
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Code Block Indent Extension
|
|
3
3
|
*
|
|
4
|
-
* Handles Tab / Shift-Tab
|
|
4
|
+
* Handles Tab / Shift-Tab inside code blocks by inserting or removing 2-space
|
|
5
|
+
* indentation. When text is selected across multiple lines, every selected
|
|
6
|
+
* line is indented or outdented.
|
|
5
7
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* 2. **Lists** — sinks or lifts the current list item.
|
|
9
|
-
*
|
|
10
|
-
* Normal paragraphs are left alone so Tab keeps its default focus-navigation
|
|
11
|
-
* behavior for keyboard accessibility.
|
|
8
|
+
* List indentation belongs to StructuralKeymap. Normal paragraphs are left
|
|
9
|
+
* alone so Tab keeps its default focus-navigation behavior for accessibility.
|
|
12
10
|
*/
|
|
13
11
|
|
|
14
12
|
import { Extension } from "@tiptap/core";
|
|
@@ -16,18 +14,12 @@ import { TextSelection } from "@tiptap/pm/state";
|
|
|
16
14
|
|
|
17
15
|
const INDENT = " "; // 2 spaces
|
|
18
16
|
|
|
19
|
-
export const
|
|
20
|
-
name: "
|
|
17
|
+
export const CodeBlockIndent = Extension.create({
|
|
18
|
+
name: "codeBlockIndent",
|
|
21
19
|
|
|
22
20
|
addKeyboardShortcuts() {
|
|
23
21
|
return {
|
|
24
22
|
Tab: ({ editor }) => {
|
|
25
|
-
// ── Lists ──────────────────────────────────────────────────
|
|
26
|
-
if (editor.isActive("listItem")) {
|
|
27
|
-
return editor.commands.sinkListItem("listItem");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// ── Code blocks ────────────────────────────────────────────
|
|
31
23
|
if (editor.isActive("codeBlock")) {
|
|
32
24
|
const { state, dispatch } = editor.view;
|
|
33
25
|
const { selection } = state;
|
|
@@ -88,12 +80,6 @@ export const TabIndent = Extension.create({
|
|
|
88
80
|
},
|
|
89
81
|
|
|
90
82
|
"Shift-Tab": ({ editor }) => {
|
|
91
|
-
// ── Lists ──────────────────────────────────────────────────
|
|
92
|
-
if (editor.isActive("listItem")) {
|
|
93
|
-
return editor.commands.liftListItem("listItem");
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// ── Code blocks ────────────────────────────────────────────
|
|
97
83
|
if (editor.isActive("codeBlock")) {
|
|
98
84
|
const { state, dispatch } = editor.view;
|
|
99
85
|
const { selection } = state;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Localized labels shared by compose SSR and client-side table UI. */
|
|
2
|
+
export interface TableControlLabels {
|
|
3
|
+
toolbarLabel: string;
|
|
4
|
+
addRowAbove: string;
|
|
5
|
+
addRowBelow: string;
|
|
6
|
+
addColumnBefore: string;
|
|
7
|
+
addColumnAfter: string;
|
|
8
|
+
options: string;
|
|
9
|
+
deleteRow: string;
|
|
10
|
+
deleteColumn: string;
|
|
11
|
+
toggleHeaderRow: string;
|
|
12
|
+
deleteTable: string;
|
|
13
|
+
sizePickerLabel: string;
|
|
14
|
+
insertTableSize: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const DEFAULT_TABLE_CONTROL_LABELS: TableControlLabels = {
|
|
18
|
+
toolbarLabel: "Table controls",
|
|
19
|
+
addRowAbove: "Add row above",
|
|
20
|
+
addRowBelow: "Add row below",
|
|
21
|
+
addColumnBefore: "Add column before",
|
|
22
|
+
addColumnAfter: "Add column after",
|
|
23
|
+
options: "Table options",
|
|
24
|
+
deleteRow: "Delete row",
|
|
25
|
+
deleteColumn: "Delete column",
|
|
26
|
+
toggleHeaderRow: "Toggle header row",
|
|
27
|
+
deleteTable: "Delete table",
|
|
28
|
+
sizePickerLabel: "Choose table size",
|
|
29
|
+
insertTableSize: "Insert %rows% by %cols% table",
|
|
30
|
+
};
|