@agent-native/core 0.101.7 → 0.101.11
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +28 -0
- package/corpus/core/docs/content/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/ar-SA/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/de-DE/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/es-ES/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/fr-FR/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/hi-IN/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/ja-JP/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/ko-KR/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/pt-BR/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/zh-CN/deployment.mdx +9 -7
- package/corpus/core/docs/content/locales/zh-TW/deployment.mdx +9 -7
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/client.ts +23 -1
- package/corpus/core/src/a2a/handlers.ts +65 -1
- package/corpus/core/src/a2a/server.ts +124 -0
- package/corpus/core/src/a2a/task-store.ts +253 -0
- package/corpus/core/src/a2a/types.ts +26 -0
- package/corpus/core/src/agent/production-agent.ts +5 -2
- package/corpus/core/src/client/review/ReviewCommentComposer.tsx +9 -1
- package/corpus/core/src/client/review/ReviewThreadPanel.tsx +17 -2
- package/corpus/core/src/client/settings/SettingsPanel.tsx +41 -21
- package/corpus/core/src/client/settings/useBuilderStatus.ts +28 -9
- package/corpus/core/src/client/setup-connections/BuilderConnectCard.tsx +2 -7
- package/corpus/core/src/mcp/builtin-tools.ts +25 -1
- package/corpus/core/src/scripts/call-agent.ts +22 -3
- package/corpus/core/src/server/agent-chat-plugin.ts +86 -1
- package/corpus/core/src/server/auth.ts +25 -1
- package/corpus/core/src/server/builder-browser.ts +353 -1
- package/corpus/core/src/server/core-routes-plugin.ts +601 -223
- package/corpus/core/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
- package/corpus/templates/calendar/app/components/calendar/DayView.tsx +80 -1
- package/corpus/templates/calendar/app/components/calendar/EventCard.tsx +28 -3
- package/corpus/templates/calendar/app/components/calendar/EventDetailPanel.tsx +5 -1
- package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +30 -3
- package/corpus/templates/calendar/app/components/calendar/OutOfOfficeEvent.tsx +196 -0
- package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +115 -1
- package/corpus/templates/calendar/app/lib/out-of-office.ts +45 -0
- package/corpus/templates/calendar/changelog/2026-07-14-out-of-office-blocks-now-sit-behind-meetings-and-event-stack.md +6 -0
- package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +23 -0
- package/corpus/templates/content/AGENTS.md +3 -2
- package/corpus/templates/content/actions/_builder-cms-intent-lookup.ts +87 -0
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +173 -25
- package/corpus/templates/content/actions/_builder-cms-source-adapter.ts +1 -0
- package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +427 -18
- package/corpus/templates/content/actions/_builder-cms-write-client.ts +17 -73
- package/corpus/templates/content/actions/_builder-cms-write-settings.ts +27 -7
- package/corpus/templates/content/actions/_builder-source-execution-claim.ts +124 -0
- package/corpus/templates/content/actions/_builder-source-execution-preservation.ts +21 -0
- package/corpus/templates/content/actions/_builder-source-timings.ts +57 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +1041 -154
- package/corpus/templates/content/actions/_database-utils.ts +89 -12
- package/corpus/templates/content/actions/_preview-document-draft.ts +31 -0
- package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +309 -0
- package/corpus/templates/content/actions/execute-builder-source-batch.ts +120 -49
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +608 -264
- package/corpus/templates/content/actions/get-preview-document-draft.ts +26 -0
- package/corpus/templates/content/actions/materialize-builder-required-fields.ts +550 -0
- package/corpus/templates/content/actions/prepare-builder-source-execution.ts +112 -65
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +463 -170
- package/corpus/templates/content/actions/preview-builder-source-review.ts +99 -0
- package/corpus/templates/content/actions/set-content-database-source-write-mode.ts +2 -2
- package/corpus/templates/content/actions/update-preview-document-draft.ts +153 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +27 -15
- package/corpus/templates/content/app/components/editor/MathRenderer.tsx +43 -0
- package/corpus/templates/content/app/components/editor/SlashCommandMenu.tsx +260 -4
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +57 -5
- package/corpus/templates/content/app/components/editor/body-hydration.ts +27 -0
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +2353 -576
- package/corpus/templates/content/app/components/editor/database/settings.tsx +13 -10
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +358 -75
- package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +78 -0
- package/corpus/templates/content/app/components/editor/previewDocumentSaveController.ts +124 -29
- package/corpus/templates/content/app/components/editor/previewDocumentSaveRegistry.ts +2 -0
- package/corpus/templates/content/app/global.css +71 -1
- package/corpus/templates/content/app/hooks/use-content-database.ts +68 -0
- package/corpus/templates/content/app/hooks/use-documents.ts +53 -4
- package/corpus/templates/content/app/i18n/zh-TW.ts +38 -0
- package/corpus/templates/content/app/i18n-data.ts +450 -0
- package/corpus/templates/content/app/root.tsx +2 -0
- package/corpus/templates/content/changelog/2026-07-10-builder-backed-preview-edits-are-preserved-when-article-bodi.md +6 -0
- package/corpus/templates/content/changelog/2026-07-10-builder-cms-sources-can-now-be-enabled-for-guarded-staged-or.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-builder-connection-setup-is-now-available-directly-from-conn.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-builder-reviews-now-hide-already-applied-writes-detect-nativ.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-required-builder-publishing-fields-can-now-be-added-directly.md +6 -0
- package/corpus/templates/content/changelog/2026-07-13-you-can-now-cancel-a-prepared-builder-update-safely-before-i.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-account-connection-now-remains-available-when-branch.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-backed-articles-now-preserve-fifth-and-sixth-level-h.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-sources-now-review-and-publish-rich-article-updates-.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-builder-writes-now-stop-retries-when-reconciliation-is-needed.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-file-and-media-links-now-validate-before-saving.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-latex-equations-render-in-documents-public-pages-and-exports.md +6 -0
- package/corpus/templates/content/package.json +1 -0
- package/corpus/templates/content/parity/matrix.md +27 -25
- package/corpus/templates/content/parity/matrix.ts +50 -2
- package/corpus/templates/content/server/db/schema.ts +47 -0
- package/corpus/templates/content/server/plugins/auth.ts +1 -0
- package/corpus/templates/content/server/plugins/db.ts +53 -0
- package/corpus/templates/content/shared/api.ts +70 -1
- package/corpus/templates/content/shared/builder-mdx.ts +705 -15
- package/corpus/templates/content/shared/document-export.ts +296 -25
- package/corpus/templates/content/shared/inline-math.ts +128 -0
- package/corpus/templates/content/shared/math-rendering.ts +50 -0
- package/corpus/templates/content/shared/nfm.ts +20 -17
- package/corpus/templates/content/vite.config.ts +0 -1
- package/corpus/templates/design/app/components/design/ReadOnlyDesignBanner.tsx +52 -7
- package/corpus/templates/design/app/components/design/ReviewCommentsPanel.tsx +36 -4
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +4 -1
- package/corpus/templates/design/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/design/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/design/app/i18n/en-US.ts +1 -0
- package/corpus/templates/design/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/design/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/design/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/design/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/design/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/design/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/design/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/design/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +8 -0
- package/corpus/templates/design/app/pages/design-editor/tool-state.ts +11 -0
- package/corpus/templates/design/changelog/2026-07-14-reviewers-can-now-pin-comments-from-the-canvas-toolbar-targe.md +6 -0
- package/corpus/templates/design/changelog/2026-07-15-viewer-comment-controls-now-sit-inside-the-read-only-notice-.md +6 -0
- package/corpus/templates/design/shared/review-anchor.ts +48 -0
- package/corpus/templates/mail/.agents/skills/email-drafts/SKILL.md +17 -0
- package/corpus/templates/mail/AGENTS.md +21 -19
- package/corpus/templates/mail/actions/create-attachment-upload.ts +49 -0
- package/corpus/templates/mail/changelog/2026-07-14-connected-agents-can-now-securely-upload-local-files-for-mai.md +6 -0
- package/corpus/templates/mail/server/handlers/media.ts +84 -61
- package/corpus/templates/mail/server/lib/attachment-upload-ticket.ts +234 -0
- package/corpus/templates/mail/server/lib/mail-connector-catalog.ts +8 -4
- package/corpus/templates/mail/server/lib/media-upload.ts +114 -0
- package/corpus/templates/mail/server/plugins/auth.ts +9 -1
- package/corpus/templates/mail/server/routes/api/media/attachment-upload/[uploadId].put.ts +1 -0
- package/corpus/templates/plan/server/plan-mdx.ts +53 -7
- package/dist/a2a/client.d.ts +5 -1
- package/dist/a2a/client.d.ts.map +1 -1
- package/dist/a2a/client.js +18 -1
- package/dist/a2a/client.js.map +1 -1
- package/dist/a2a/handlers.d.ts.map +1 -1
- package/dist/a2a/handlers.js +57 -8
- package/dist/a2a/handlers.js.map +1 -1
- package/dist/a2a/server.d.ts.map +1 -1
- package/dist/a2a/server.js +87 -1
- package/dist/a2a/server.js.map +1 -1
- package/dist/a2a/task-store.d.ts +27 -0
- package/dist/a2a/task-store.d.ts.map +1 -1
- package/dist/a2a/task-store.js +216 -0
- package/dist/a2a/task-store.js.map +1 -1
- package/dist/a2a/types.d.ts +24 -0
- package/dist/a2a/types.d.ts.map +1 -1
- package/dist/a2a/types.js.map +1 -1
- package/dist/agent/production-agent.d.ts +1 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +5 -2
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/client/review/ReviewCommentComposer.d.ts +2 -1
- package/dist/client/review/ReviewCommentComposer.d.ts.map +1 -1
- package/dist/client/review/ReviewCommentComposer.js +3 -3
- package/dist/client/review/ReviewCommentComposer.js.map +1 -1
- package/dist/client/review/ReviewThreadPanel.d.ts +9 -1
- package/dist/client/review/ReviewThreadPanel.d.ts.map +1 -1
- package/dist/client/review/ReviewThreadPanel.js +6 -4
- package/dist/client/review/ReviewThreadPanel.js.map +1 -1
- package/dist/client/settings/SettingsPanel.d.ts +3 -0
- package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
- package/dist/client/settings/SettingsPanel.js +11 -4
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts +8 -4
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +19 -6
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/client/setup-connections/BuilderConnectCard.d.ts.map +1 -1
- package/dist/client/setup-connections/BuilderConnectCard.js +2 -5
- package/dist/client/setup-connections/BuilderConnectCard.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +22 -3
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/scripts/call-agent.d.ts +1 -1
- package/dist/scripts/call-agent.d.ts.map +1 -1
- package/dist/scripts/call-agent.js +19 -1
- package/dist/scripts/call-agent.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +71 -2
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.d.ts +1 -0
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +19 -2
- package/dist/server/auth.js.map +1 -1
- package/dist/server/builder-browser.d.ts +78 -0
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +246 -1
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts +41 -0
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +260 -14
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
- package/docs/content/deployment.mdx +9 -7
- package/docs/content/locales/ar-SA/deployment.mdx +9 -7
- package/docs/content/locales/de-DE/deployment.mdx +9 -7
- package/docs/content/locales/es-ES/deployment.mdx +9 -7
- package/docs/content/locales/fr-FR/deployment.mdx +9 -7
- package/docs/content/locales/hi-IN/deployment.mdx +9 -7
- package/docs/content/locales/ja-JP/deployment.mdx +9 -7
- package/docs/content/locales/ko-KR/deployment.mdx +9 -7
- package/docs/content/locales/pt-BR/deployment.mdx +9 -7
- package/docs/content/locales/zh-CN/deployment.mdx +9 -7
- package/docs/content/locales/zh-TW/deployment.mdx +9 -7
- package/package.json +2 -2
- package/src/templates/workspace-core/.agents/skills/a2a-protocol/SKILL.md +25 -0
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { useSendToAgentChat, useT } from "@agent-native/core/client";
|
|
2
2
|
import type { CreateInlineDatabaseResponse } from "@shared/api";
|
|
3
|
+
import { renderMathToHtml } from "@shared/math-rendering";
|
|
3
4
|
import { collapseExactRepeatedNfm, docToNfm } from "@shared/nfm";
|
|
4
5
|
import { serializeRegistryBlockToMdx } from "@shared/nfm-registry";
|
|
5
6
|
import {
|
|
7
|
+
IconCheck,
|
|
6
8
|
IconTypography,
|
|
7
9
|
IconH1,
|
|
8
10
|
IconH2,
|
|
@@ -23,6 +25,8 @@ import {
|
|
|
23
25
|
IconFileText,
|
|
24
26
|
IconDatabase,
|
|
25
27
|
IconVideo,
|
|
28
|
+
IconMathFunction,
|
|
29
|
+
IconSquareRoot2,
|
|
26
30
|
} from "@tabler/icons-react";
|
|
27
31
|
import { Editor } from "@tiptap/react";
|
|
28
32
|
import { useState, useEffect, useCallback, useRef, useMemo } from "react";
|
|
@@ -30,6 +34,7 @@ import { useNavigate } from "react-router";
|
|
|
30
34
|
import { toast } from "sonner";
|
|
31
35
|
|
|
32
36
|
import { contentBlockRegistry } from "@/blocks/contentBlockRegistry";
|
|
37
|
+
import { Button } from "@/components/ui/button";
|
|
33
38
|
import {
|
|
34
39
|
Popover,
|
|
35
40
|
PopoverContent,
|
|
@@ -42,6 +47,7 @@ import { localContentComponents } from "@/local-components";
|
|
|
42
47
|
|
|
43
48
|
import { focusMostRecentEmptyToggleSummary } from "./extensions/NotionExtensions";
|
|
44
49
|
import { buildLocalComponentSlashItems } from "./localComponentSlashItems";
|
|
50
|
+
import { MathRenderer } from "./MathRenderer";
|
|
45
51
|
import { buildRegistrySlashItems } from "./registrySlashItems";
|
|
46
52
|
|
|
47
53
|
interface SlashCommandMenuProps {
|
|
@@ -64,6 +70,13 @@ interface EditorMenuPosition {
|
|
|
64
70
|
left: number;
|
|
65
71
|
}
|
|
66
72
|
|
|
73
|
+
interface EquationDraft {
|
|
74
|
+
displayMode: boolean;
|
|
75
|
+
insertionRange: { from: number; to: number };
|
|
76
|
+
slashRange: { from: number; to: number };
|
|
77
|
+
position: EditorMenuPosition;
|
|
78
|
+
}
|
|
79
|
+
|
|
67
80
|
interface CommandItem {
|
|
68
81
|
title: string;
|
|
69
82
|
description: string;
|
|
@@ -178,6 +191,47 @@ export function insertInlineDatabaseBlock(
|
|
|
178
191
|
: chain.insertContent(content).run();
|
|
179
192
|
}
|
|
180
193
|
|
|
194
|
+
export function equationNodeContent(latex: string, displayMode: boolean) {
|
|
195
|
+
return displayMode
|
|
196
|
+
? {
|
|
197
|
+
type: "notionBlockAtom",
|
|
198
|
+
attrs: { tagName: "equation", attrsJson: "{}", label: latex },
|
|
199
|
+
}
|
|
200
|
+
: {
|
|
201
|
+
type: "notionInlineAtom",
|
|
202
|
+
attrs: { tagName: "math", attrsJson: "{}", label: latex },
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export function insertEquation(
|
|
207
|
+
editor: Editor,
|
|
208
|
+
latex: string,
|
|
209
|
+
displayMode: boolean,
|
|
210
|
+
range: { from: number; to: number },
|
|
211
|
+
) {
|
|
212
|
+
const content = equationNodeContent(latex, displayMode);
|
|
213
|
+
return editor
|
|
214
|
+
.chain()
|
|
215
|
+
.focus()
|
|
216
|
+
.insertContentAt(
|
|
217
|
+
range,
|
|
218
|
+
displayMode ? [content, { type: "paragraph" }] : content,
|
|
219
|
+
)
|
|
220
|
+
.run();
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function getEquationInsertionRange(
|
|
224
|
+
editor: Editor,
|
|
225
|
+
slashRange: { from: number; to: number },
|
|
226
|
+
displayMode: boolean,
|
|
227
|
+
) {
|
|
228
|
+
if (!displayMode) return slashRange;
|
|
229
|
+
const resolved = editor.state.doc.resolve(slashRange.from);
|
|
230
|
+
return resolved.parent.isTextblock
|
|
231
|
+
? { from: resolved.before(), to: resolved.after() }
|
|
232
|
+
: slashRange;
|
|
233
|
+
}
|
|
234
|
+
|
|
181
235
|
const commands: CommandTemplate[] = [
|
|
182
236
|
{
|
|
183
237
|
titleKey: "editor.slash.text",
|
|
@@ -460,6 +514,16 @@ export function SlashCommandMenu({
|
|
|
460
514
|
);
|
|
461
515
|
const generateTextareaRef = useRef<HTMLTextAreaElement>(null);
|
|
462
516
|
|
|
517
|
+
const [equationDraft, setEquationDraft] = useState<EquationDraft | null>(
|
|
518
|
+
null,
|
|
519
|
+
);
|
|
520
|
+
const [equationLatex, setEquationLatex] = useState("");
|
|
521
|
+
const equationInputRef = useRef<HTMLTextAreaElement>(null);
|
|
522
|
+
const equationResult = useMemo(
|
|
523
|
+
() => renderMathToHtml(equationLatex, equationDraft?.displayMode ?? false),
|
|
524
|
+
[equationDraft?.displayMode, equationLatex],
|
|
525
|
+
);
|
|
526
|
+
|
|
463
527
|
const submitGeneratePrompt = useCallback(
|
|
464
528
|
(prompt: string) => {
|
|
465
529
|
const trimmed = prompt.trim();
|
|
@@ -684,6 +748,80 @@ export function SlashCommandMenu({
|
|
|
684
748
|
},
|
|
685
749
|
};
|
|
686
750
|
|
|
751
|
+
const openEquationComposer = useCallback(
|
|
752
|
+
(displayMode: boolean, slashRange: { from: number; to: number } | null) => {
|
|
753
|
+
const menuPosition = position ?? getSelectionMenuPosition();
|
|
754
|
+
if (!slashRange || !menuPosition) return false;
|
|
755
|
+
setEquationLatex("");
|
|
756
|
+
setEquationDraft({
|
|
757
|
+
displayMode,
|
|
758
|
+
slashRange,
|
|
759
|
+
insertionRange: getEquationInsertionRange(
|
|
760
|
+
editor,
|
|
761
|
+
slashRange,
|
|
762
|
+
displayMode,
|
|
763
|
+
),
|
|
764
|
+
position: menuPosition,
|
|
765
|
+
});
|
|
766
|
+
setTimeout(() => equationInputRef.current?.focus(), 0);
|
|
767
|
+
return true;
|
|
768
|
+
},
|
|
769
|
+
[editor, getSelectionMenuPosition, position],
|
|
770
|
+
);
|
|
771
|
+
|
|
772
|
+
const cancelEquation = useCallback(() => {
|
|
773
|
+
const draft = equationDraft;
|
|
774
|
+
setEquationDraft(null);
|
|
775
|
+
setEquationLatex("");
|
|
776
|
+
if (draft) {
|
|
777
|
+
editor.chain().focus().deleteRange(draft.slashRange).run();
|
|
778
|
+
}
|
|
779
|
+
}, [editor, equationDraft]);
|
|
780
|
+
|
|
781
|
+
const submitEquation = useCallback(() => {
|
|
782
|
+
if (!equationDraft || !equationResult.ok) return;
|
|
783
|
+
const latex = equationLatex.trim();
|
|
784
|
+
const { displayMode, insertionRange } = equationDraft;
|
|
785
|
+
setEquationDraft(null);
|
|
786
|
+
setEquationLatex("");
|
|
787
|
+
const inserted = insertEquation(editor, latex, displayMode, insertionRange);
|
|
788
|
+
if (!inserted) {
|
|
789
|
+
toast.error(t("editor.slash.equationInsertFailed"));
|
|
790
|
+
return;
|
|
791
|
+
}
|
|
792
|
+
void onDraftCommitted?.();
|
|
793
|
+
}, [
|
|
794
|
+
editor,
|
|
795
|
+
equationDraft,
|
|
796
|
+
equationLatex,
|
|
797
|
+
equationResult.ok,
|
|
798
|
+
onDraftCommitted,
|
|
799
|
+
t,
|
|
800
|
+
]);
|
|
801
|
+
|
|
802
|
+
const equationCommands: CommandItem[] = isTurnInto
|
|
803
|
+
? []
|
|
804
|
+
: [
|
|
805
|
+
{
|
|
806
|
+
title: t("editor.slash.blockEquation"),
|
|
807
|
+
description: t("editor.slash.blockEquationDescription"),
|
|
808
|
+
searchText: "latex katex math formula",
|
|
809
|
+
icon: IconMathFunction,
|
|
810
|
+
preserveSlashRange: true,
|
|
811
|
+
action: (_editor, { slashRange }) =>
|
|
812
|
+
openEquationComposer(true, slashRange),
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
title: t("editor.slash.inlineEquation"),
|
|
816
|
+
description: t("editor.slash.inlineEquationDescription"),
|
|
817
|
+
searchText: "latex katex math formula",
|
|
818
|
+
icon: IconSquareRoot2,
|
|
819
|
+
preserveSlashRange: true,
|
|
820
|
+
action: (_editor, { slashRange }) =>
|
|
821
|
+
openEquationComposer(false, slashRange),
|
|
822
|
+
},
|
|
823
|
+
];
|
|
824
|
+
|
|
687
825
|
// Registry-derived block items (the shared dev-doc / OpenAPI / structured
|
|
688
826
|
// library). Filtered to Notion-compatible specs when the document is linked to
|
|
689
827
|
// a Notion page. "Turn into" only converts the current text block, so these
|
|
@@ -713,9 +851,10 @@ export function SlashCommandMenu({
|
|
|
713
851
|
title: t(cmd.titleKey),
|
|
714
852
|
description: t(cmd.descriptionKey),
|
|
715
853
|
});
|
|
716
|
-
const blockCommands =
|
|
717
|
-
localizeCommand,
|
|
718
|
-
|
|
854
|
+
const blockCommands = [
|
|
855
|
+
...(isTurnInto ? turnIntoCommands : commands).map(localizeCommand),
|
|
856
|
+
...equationCommands,
|
|
857
|
+
];
|
|
719
858
|
const pageCommands = isTurnInto ? [] : [pageCommand, databaseCommand];
|
|
720
859
|
const mediaCommands = isTurnInto
|
|
721
860
|
? []
|
|
@@ -1042,7 +1181,7 @@ export function SlashCommandMenu({
|
|
|
1042
1181
|
align="start"
|
|
1043
1182
|
side="bottom"
|
|
1044
1183
|
className="w-[calc(100vw-2rem)] max-w-80 rounded-xl p-0"
|
|
1045
|
-
onOpenAutoFocus={(e) => {
|
|
1184
|
+
onOpenAutoFocus={(e: Event) => {
|
|
1046
1185
|
e.preventDefault();
|
|
1047
1186
|
generateTextareaRef.current?.focus();
|
|
1048
1187
|
}}
|
|
@@ -1086,6 +1225,123 @@ export function SlashCommandMenu({
|
|
|
1086
1225
|
</PopoverContent>
|
|
1087
1226
|
</Popover>
|
|
1088
1227
|
)}
|
|
1228
|
+
|
|
1229
|
+
{equationDraft && (
|
|
1230
|
+
<Popover
|
|
1231
|
+
open
|
|
1232
|
+
onOpenChange={(open: boolean) => {
|
|
1233
|
+
if (!open) cancelEquation();
|
|
1234
|
+
}}
|
|
1235
|
+
>
|
|
1236
|
+
<PopoverTrigger asChild>
|
|
1237
|
+
<span
|
|
1238
|
+
className="pointer-events-none absolute size-0"
|
|
1239
|
+
style={{
|
|
1240
|
+
top: equationDraft.position.top,
|
|
1241
|
+
left: Math.min(equationDraft.position.left, 16),
|
|
1242
|
+
}}
|
|
1243
|
+
/>
|
|
1244
|
+
</PopoverTrigger>
|
|
1245
|
+
<PopoverContent
|
|
1246
|
+
align="start"
|
|
1247
|
+
side="bottom"
|
|
1248
|
+
className="w-[calc(100vw-2rem)] max-w-md rounded-xl p-0"
|
|
1249
|
+
onOpenAutoFocus={(event: Event) => {
|
|
1250
|
+
event.preventDefault();
|
|
1251
|
+
equationInputRef.current?.focus();
|
|
1252
|
+
}}
|
|
1253
|
+
>
|
|
1254
|
+
<div className="p-4">
|
|
1255
|
+
<div className="flex items-center gap-2 text-sm font-semibold">
|
|
1256
|
+
{equationDraft.displayMode ? (
|
|
1257
|
+
<IconMathFunction
|
|
1258
|
+
className="text-muted-foreground"
|
|
1259
|
+
size={16}
|
|
1260
|
+
/>
|
|
1261
|
+
) : (
|
|
1262
|
+
<IconSquareRoot2
|
|
1263
|
+
className="text-muted-foreground"
|
|
1264
|
+
size={16}
|
|
1265
|
+
/>
|
|
1266
|
+
)}
|
|
1267
|
+
{equationDraft.displayMode
|
|
1268
|
+
? t("editor.slash.blockEquation")
|
|
1269
|
+
: t("editor.slash.inlineEquation")}
|
|
1270
|
+
</div>
|
|
1271
|
+
<textarea
|
|
1272
|
+
ref={equationInputRef}
|
|
1273
|
+
value={equationLatex}
|
|
1274
|
+
onChange={(event) => setEquationLatex(event.target.value)}
|
|
1275
|
+
onKeyDown={(event) => {
|
|
1276
|
+
if (
|
|
1277
|
+
event.key === "Enter" &&
|
|
1278
|
+
(event.metaKey || event.ctrlKey) &&
|
|
1279
|
+
equationResult.ok
|
|
1280
|
+
) {
|
|
1281
|
+
event.preventDefault();
|
|
1282
|
+
submitEquation();
|
|
1283
|
+
}
|
|
1284
|
+
if (event.key === "Escape") {
|
|
1285
|
+
event.preventDefault();
|
|
1286
|
+
cancelEquation();
|
|
1287
|
+
}
|
|
1288
|
+
}}
|
|
1289
|
+
rows={equationDraft.displayMode ? 3 : 2}
|
|
1290
|
+
placeholder={t("editor.slash.equationPlaceholder")}
|
|
1291
|
+
aria-label={t("editor.slash.equationInputLabel")}
|
|
1292
|
+
aria-invalid={equationLatex.length > 0 && !equationResult.ok}
|
|
1293
|
+
aria-describedby="equation-preview-status"
|
|
1294
|
+
className="mt-3 w-full resize-y rounded-lg border border-input bg-background px-3 py-2 font-mono text-sm outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
1295
|
+
/>
|
|
1296
|
+
<div className="mt-3 min-h-20 rounded-lg border border-border bg-muted/30 p-3">
|
|
1297
|
+
<div className="mb-2 text-[11px] font-medium uppercase tracking-wide text-muted-foreground">
|
|
1298
|
+
{t("editor.slash.equationPreview")}
|
|
1299
|
+
</div>
|
|
1300
|
+
<div className="flex min-h-9 items-center justify-center overflow-x-auto text-foreground">
|
|
1301
|
+
{equationResult.ok ? (
|
|
1302
|
+
<MathRenderer
|
|
1303
|
+
latex={equationLatex}
|
|
1304
|
+
displayMode={equationDraft.displayMode}
|
|
1305
|
+
/>
|
|
1306
|
+
) : (
|
|
1307
|
+
<span className="text-sm text-muted-foreground">
|
|
1308
|
+
{equationLatex
|
|
1309
|
+
? t("editor.slash.equationNeedsRepair")
|
|
1310
|
+
: t("editor.slash.equationPreviewEmpty")}
|
|
1311
|
+
</span>
|
|
1312
|
+
)}
|
|
1313
|
+
</div>
|
|
1314
|
+
</div>
|
|
1315
|
+
<p
|
|
1316
|
+
id="equation-preview-status"
|
|
1317
|
+
className={cn(
|
|
1318
|
+
"mt-2 min-h-5 text-xs",
|
|
1319
|
+
equationLatex && !equationResult.ok
|
|
1320
|
+
? "text-destructive"
|
|
1321
|
+
: "text-muted-foreground",
|
|
1322
|
+
)}
|
|
1323
|
+
>
|
|
1324
|
+
{equationLatex && !equationResult.ok
|
|
1325
|
+
? equationResult.error
|
|
1326
|
+
: t("editor.slash.equationSubmitHint")}
|
|
1327
|
+
</p>
|
|
1328
|
+
</div>
|
|
1329
|
+
<div className="flex items-center justify-end gap-2 border-t border-border px-4 py-3">
|
|
1330
|
+
<Button variant="ghost" size="sm" onClick={cancelEquation}>
|
|
1331
|
+
{t("editor.slash.cancelEquation")}
|
|
1332
|
+
</Button>
|
|
1333
|
+
<Button
|
|
1334
|
+
size="sm"
|
|
1335
|
+
onClick={submitEquation}
|
|
1336
|
+
disabled={!equationResult.ok}
|
|
1337
|
+
>
|
|
1338
|
+
<IconCheck />
|
|
1339
|
+
{t("editor.slash.insertEquation")}
|
|
1340
|
+
</Button>
|
|
1341
|
+
</div>
|
|
1342
|
+
</PopoverContent>
|
|
1343
|
+
</Popover>
|
|
1344
|
+
)}
|
|
1089
1345
|
</>
|
|
1090
1346
|
);
|
|
1091
1347
|
}
|
|
@@ -924,6 +924,28 @@ export function shouldPersistLocalFileEditorUpdate({
|
|
|
924
924
|
return Boolean(transactionUiEvent);
|
|
925
925
|
}
|
|
926
926
|
|
|
927
|
+
function isEffectivelyEmptyEditorContent(value: string): boolean {
|
|
928
|
+
const normalized = value.trim();
|
|
929
|
+
return normalized === "" || normalized === "<empty-block/>";
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
export function shouldPersistEffectivelyEmptyEditorUpdate({
|
|
933
|
+
nextContent,
|
|
934
|
+
userInitiated,
|
|
935
|
+
}: {
|
|
936
|
+
nextContent: string;
|
|
937
|
+
userInitiated: boolean;
|
|
938
|
+
}): boolean {
|
|
939
|
+
if (!isEffectivelyEmptyEditorContent(nextContent)) return true;
|
|
940
|
+
// Empty editor state is never worth persisting without a user gesture. This
|
|
941
|
+
// also covers the preview remount window where `content` can briefly be an
|
|
942
|
+
// empty list snapshot even though its retained save controller still has a
|
|
943
|
+
// rich confirmed baseline. Comparing only to this render's prop would let
|
|
944
|
+
// that mount-time filler mark the retained controller dirty and its
|
|
945
|
+
// flush-on-release path would then overwrite SQL.
|
|
946
|
+
return userInitiated;
|
|
947
|
+
}
|
|
948
|
+
|
|
927
949
|
function isActiveSlashCommandDraft(editor: CoreEditor): boolean {
|
|
928
950
|
const { state } = editor;
|
|
929
951
|
if (!state.selection.empty) return false;
|
|
@@ -1086,7 +1108,9 @@ function getVisualEditorPlaceholder({
|
|
|
1086
1108
|
if (level === 1) return "Heading 1";
|
|
1087
1109
|
if (level === 2) return "Heading 2";
|
|
1088
1110
|
if (level === 3) return "Heading 3";
|
|
1089
|
-
return "Heading 4";
|
|
1111
|
+
if (level === 4) return "Heading 4";
|
|
1112
|
+
if (level === 5) return "Heading 5";
|
|
1113
|
+
return "Heading 6";
|
|
1090
1114
|
}
|
|
1091
1115
|
|
|
1092
1116
|
if (
|
|
@@ -1300,6 +1324,7 @@ export function createVisualEditorExtensions({
|
|
|
1300
1324
|
starterKit: {
|
|
1301
1325
|
blockquote: false,
|
|
1302
1326
|
paragraph: false,
|
|
1327
|
+
heading: { levels: [1, 2, 3, 4, 5, 6] },
|
|
1303
1328
|
horizontalRule: {},
|
|
1304
1329
|
dropcursor: { color: false, width: 3, class: "notion-dropcursor" },
|
|
1305
1330
|
},
|
|
@@ -1742,7 +1767,11 @@ export function VisualEditor({
|
|
|
1742
1767
|
const persistEditorContent = useCallback(
|
|
1743
1768
|
(
|
|
1744
1769
|
editorToPersist: CoreEditor,
|
|
1745
|
-
options?: {
|
|
1770
|
+
options?: {
|
|
1771
|
+
markdown?: string;
|
|
1772
|
+
immediate?: boolean;
|
|
1773
|
+
userInitiated?: boolean;
|
|
1774
|
+
},
|
|
1746
1775
|
) => {
|
|
1747
1776
|
const guards = guardsRef.current;
|
|
1748
1777
|
if (!guards) return false;
|
|
@@ -1750,6 +1779,20 @@ export function VisualEditor({
|
|
|
1750
1779
|
const normalized =
|
|
1751
1780
|
options?.markdown ?? docToNfm(editorToPersist.getJSON() as any);
|
|
1752
1781
|
if (localFileMode && normalized === content) return true;
|
|
1782
|
+
// TipTap/Yjs can emit a local-looking empty-paragraph transaction while
|
|
1783
|
+
// an editor is mounting or reconciling. Content serializes that filler
|
|
1784
|
+
// as `<empty-block/>`, so the generic whitespace-only collab guard does
|
|
1785
|
+
// not catch it. Never let that lifecycle normalization clear a saved
|
|
1786
|
+
// body. A real Select All/Delete (or Cut) records user intent through
|
|
1787
|
+
// the DOM handlers below and is still allowed to persist normally.
|
|
1788
|
+
if (
|
|
1789
|
+
!shouldPersistEffectivelyEmptyEditorUpdate({
|
|
1790
|
+
nextContent: normalized,
|
|
1791
|
+
userInitiated: options?.userInitiated === true,
|
|
1792
|
+
})
|
|
1793
|
+
) {
|
|
1794
|
+
return true;
|
|
1795
|
+
}
|
|
1753
1796
|
if (options?.immediate && onSaveContentRef.current) {
|
|
1754
1797
|
return onSaveContentRef.current(normalized);
|
|
1755
1798
|
}
|
|
@@ -1923,7 +1966,12 @@ export function VisualEditor({
|
|
|
1923
1966
|
return;
|
|
1924
1967
|
}
|
|
1925
1968
|
if (isActiveSlashCommandDraft(editor)) return;
|
|
1926
|
-
persistEditorContent(editor
|
|
1969
|
+
persistEditorContent(editor, {
|
|
1970
|
+
userInitiated:
|
|
1971
|
+
transaction.getMeta(LOCAL_FILE_USER_EDIT_META) === true ||
|
|
1972
|
+
Date.now() - lastUserEditIntentAtRef.current < 2000 ||
|
|
1973
|
+
Boolean(transaction.getMeta("uiEvent")),
|
|
1974
|
+
});
|
|
1927
1975
|
},
|
|
1928
1976
|
});
|
|
1929
1977
|
|
|
@@ -2239,10 +2287,14 @@ export function VisualEditor({
|
|
|
2239
2287
|
documentId={documentId}
|
|
2240
2288
|
notionPageId={notionPageId}
|
|
2241
2289
|
onDraftCommitted={() => {
|
|
2242
|
-
void persistEditorContent(editor);
|
|
2290
|
+
void persistEditorContent(editor, { userInitiated: true });
|
|
2243
2291
|
}}
|
|
2244
2292
|
onDraftPersisted={(markdown) =>
|
|
2245
|
-
persistEditorContent(editor, {
|
|
2293
|
+
persistEditorContent(editor, {
|
|
2294
|
+
markdown,
|
|
2295
|
+
immediate: true,
|
|
2296
|
+
userInitiated: true,
|
|
2297
|
+
})
|
|
2246
2298
|
}
|
|
2247
2299
|
/>
|
|
2248
2300
|
) : null}
|
|
@@ -89,6 +89,33 @@ export function previewBodyHydrationIsPending(args: {
|
|
|
89
89
|
);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* A draft that began from an empty source snapshot must not automatically
|
|
94
|
+
* replace a non-empty Builder body that arrived while hydration was running.
|
|
95
|
+
* Keep the draft dirty/recoverable and let the user decide which body to keep.
|
|
96
|
+
*/
|
|
97
|
+
export function previewDraftConflictsWithHydratedBody(args: {
|
|
98
|
+
loadedContent: string | null | undefined;
|
|
99
|
+
loadedUpdatedAt: string | null | undefined;
|
|
100
|
+
loadedContentWasEmpty: boolean | undefined;
|
|
101
|
+
pendingContent: string | null | undefined;
|
|
102
|
+
hydratedContent: string | null | undefined;
|
|
103
|
+
hydratedUpdatedAt: string | null | undefined;
|
|
104
|
+
}) {
|
|
105
|
+
const sourceChangedSinceDraftLoaded =
|
|
106
|
+
(!!args.loadedUpdatedAt &&
|
|
107
|
+
!!args.hydratedUpdatedAt &&
|
|
108
|
+
args.loadedUpdatedAt !== args.hydratedUpdatedAt) ||
|
|
109
|
+
args.loadedContent !== args.hydratedContent;
|
|
110
|
+
return (
|
|
111
|
+
!isEffectivelyEmptyDocumentContent(args.pendingContent) &&
|
|
112
|
+
args.pendingContent !== args.hydratedContent &&
|
|
113
|
+
sourceChangedSinceDraftLoaded &&
|
|
114
|
+
(args.loadedContentWasEmpty === true ||
|
|
115
|
+
args.loadedContent !== args.hydratedContent)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
92
119
|
export function previewBodyHydrationIsTerminalError(args: {
|
|
93
120
|
item: Pick<ContentDatabaseItem, "bodyHydration" | "document">;
|
|
94
121
|
document: Pick<Document, "databaseMembership"> | null | undefined;
|