@agent-native/core-corpus 0.201.0-nightly-20261005153421 → 0.201.0

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 (235) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/security/SKILL.md +9 -2
  3. package/corpus/templates/analytics/.agents/skills/session-replay/SKILL.md +14 -4
  4. package/corpus/templates/analytics/.agents/skills/storing-data/SKILL.md +12 -7
  5. package/corpus/templates/analytics/CHANGELOG.md +6 -0
  6. package/corpus/templates/analytics/README.md +2 -2
  7. package/corpus/templates/analytics/changelog/2026-10-02-events-with-a-very-long-name-app-or-page-path-no-longer-caus.md +6 -0
  8. package/corpus/templates/analytics/package.json +1 -0
  9. package/corpus/templates/analytics/server/handlers/first-party-analytics.ts +9 -19
  10. package/corpus/templates/analytics/server/handlers/session-replay.ts +34 -47
  11. package/corpus/templates/analytics/server/lib/first-party-analytics-rollups.ts +9 -6
  12. package/corpus/templates/analytics/server/lib/first-party-analytics.ts +57 -36
  13. package/corpus/templates/analytics/server/lib/indexed-text.ts +53 -0
  14. package/corpus/templates/analytics/server/lib/request-errors.ts +73 -0
  15. package/corpus/templates/analytics/server/lib/session-event-index.ts +6 -16
  16. package/corpus/templates/analytics/server/lib/session-replay.ts +12 -2
  17. package/corpus/templates/analytics/server/plugins/auth.ts +2 -1
  18. package/corpus/templates/analytics/server/plugins/otel.ts +6 -0
  19. package/corpus/templates/assets/.agents/skills/security/SKILL.md +9 -2
  20. package/corpus/templates/assets/.agents/skills/storing-data/SKILL.md +12 -7
  21. package/corpus/templates/assets/CHANGELOG.md +7 -0
  22. package/corpus/templates/assets/README.md +2 -2
  23. package/corpus/templates/assets/package.json +1 -0
  24. package/corpus/templates/assets/server/plugins/auth.ts +2 -1
  25. package/corpus/templates/assets/server/plugins/otel.ts +6 -0
  26. package/corpus/templates/brain/.agents/skills/brain/RUNBOOK.md +2 -1
  27. package/corpus/templates/brain/.agents/skills/brain/SKILL.md +5 -4
  28. package/corpus/templates/brain/.agents/skills/security/SKILL.md +9 -2
  29. package/corpus/templates/brain/.agents/skills/storing-data/SKILL.md +12 -7
  30. package/corpus/templates/brain/CHANGELOG.md +6 -0
  31. package/corpus/templates/brain/README.md +12 -8
  32. package/corpus/templates/brain/changelog/2026-10-05-private-slack-channels-are-searchable-org-wide.md +6 -0
  33. package/corpus/templates/brain/package.json +1 -0
  34. package/corpus/templates/brain/server/lib/audiences.ts +1 -98
  35. package/corpus/templates/brain/server/lib/connectors.ts +2 -166
  36. package/corpus/templates/brain/server/plugins/otel.ts +6 -0
  37. package/corpus/templates/calendar/.agents/skills/security/SKILL.md +9 -2
  38. package/corpus/templates/calendar/.agents/skills/storing-data/SKILL.md +12 -7
  39. package/corpus/templates/calendar/CHANGELOG.md +7 -0
  40. package/corpus/templates/calendar/README.md +2 -2
  41. package/corpus/templates/calendar/package.json +1 -0
  42. package/corpus/templates/calendar/server/plugins/auth.ts +2 -1
  43. package/corpus/templates/calendar/server/plugins/otel.ts +6 -0
  44. package/corpus/templates/chat/.agents/skills/security/SKILL.md +9 -2
  45. package/corpus/templates/chat/.agents/skills/storing-data/SKILL.md +12 -7
  46. package/corpus/templates/chat/README.md +2 -2
  47. package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +9 -0
  48. package/corpus/templates/clips/.agents/skills/security/SKILL.md +9 -2
  49. package/corpus/templates/clips/CHANGELOG.md +24 -0
  50. package/corpus/templates/clips/README.md +2 -2
  51. package/corpus/templates/clips/actions/lib/audio-chunk-list.ts +23 -0
  52. package/corpus/templates/clips/actions/lib/audio-only-transcription.ts +187 -292
  53. package/corpus/templates/clips/actions/lib/chunked-transcription.ts +151 -0
  54. package/corpus/templates/clips/actions/lib/recording-audio-source.ts +191 -0
  55. package/corpus/templates/clips/actions/request-transcript.ts +81 -135
  56. package/corpus/templates/clips/actions/search-recordings.ts +19 -5
  57. package/corpus/templates/clips/app/components/clips-command-menu.tsx +5 -0
  58. package/corpus/templates/clips/app/components/library/library-layout.tsx +3 -1
  59. package/corpus/templates/clips/app/components/library/search-bar.tsx +5 -0
  60. package/corpus/templates/clips/app/hooks/use-library.ts +1 -0
  61. package/corpus/templates/clips/app/lib/local-recording-upload.ts +13 -6
  62. package/corpus/templates/clips/app/lib/recording-section.ts +1 -1
  63. package/corpus/templates/clips/app/routes/_app.r.$recordingId.tsx +7 -5
  64. package/corpus/templates/clips/app/routes/record.tsx +16 -6
  65. package/corpus/templates/clips/changelog/2026-10-02-long-uploads-an-hour-or-more-now-transcribe-reliably-instead.md +6 -0
  66. package/corpus/templates/clips/changelog/2026-10-05-confirming-discard-recording-now-returns-you-to-your-library.md +6 -0
  67. package/corpus/templates/clips/changelog/2026-10-05-discarding-a-recording-now-removes-its-failed-upload-card-fr.md +6 -0
  68. package/corpus/templates/clips/changelog/2026-10-05-discarding-a-recovered-recording-no-longer-warns-that-it-s-o.md +6 -0
  69. package/corpus/templates/clips/changelog/2026-10-05-search-results-identify-recordings-in-trash-and-open-them-wi.md +6 -0
  70. package/corpus/templates/clips/package.json +1 -0
  71. package/corpus/templates/clips/server/lib/builder-cdn.ts +5 -0
  72. package/corpus/templates/clips/server/lib/builder-media-compression.ts +2 -2
  73. package/corpus/templates/clips/server/plugins/auth.ts +2 -1
  74. package/corpus/templates/clips/server/plugins/otel.ts +6 -0
  75. package/corpus/templates/clips/shared/transcript-failure.ts +5 -0
  76. package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +8 -2
  77. package/corpus/templates/content/.agents/skills/security/SKILL.md +9 -2
  78. package/corpus/templates/content/.agents/skills/storing-data/SKILL.md +12 -7
  79. package/corpus/templates/content/CHANGELOG.md +41 -0
  80. package/corpus/templates/content/README.md +2 -2
  81. package/corpus/templates/content/actions/_database-navigation.ts +523 -344
  82. package/corpus/templates/content/actions/_database-row-mutation.ts +44 -10
  83. package/corpus/templates/content/actions/_database-setup-discovery.ts +9 -3
  84. package/corpus/templates/content/actions/_database-utils.ts +299 -271
  85. package/corpus/templates/content/actions/_property-utils.ts +293 -190
  86. package/corpus/templates/content/actions/_relation-values.ts +3 -1
  87. package/corpus/templates/content/actions/get-content-database.ts +1 -0
  88. package/corpus/templates/content/actions/query-content-database-items.ts +32 -5
  89. package/corpus/templates/content/actions/set-document-property.ts +17 -11
  90. package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +21 -6
  91. package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +127 -43
  92. package/corpus/templates/content/app/components/editor/DocumentEditorSkeleton.tsx +159 -50
  93. package/corpus/templates/content/app/components/editor/DocumentToolbar.tsx +12 -28
  94. package/corpus/templates/content/app/components/editor/PageDraftRecovery.tsx +6 -1
  95. package/corpus/templates/content/app/components/editor/TableHoverControls.tsx +139 -70
  96. package/corpus/templates/content/app/components/editor/VisualEditor.tsx +16 -1
  97. package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +180 -75
  98. package/corpus/templates/content/app/components/editor/database/DatabaseViewSkeleton.tsx +76 -0
  99. package/corpus/templates/content/app/components/editor/database/navigation-state.ts +60 -2
  100. package/corpus/templates/content/app/components/editor/database/sidebar.tsx +41 -42
  101. package/corpus/templates/content/app/components/editor/document-editor-layout.ts +18 -0
  102. package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +11 -3
  103. package/corpus/templates/content/app/components/editor/suggestions/draft-session.ts +15 -7
  104. package/corpus/templates/content/app/components/editor/suggestions/model.ts +13 -0
  105. package/corpus/templates/content/app/components/editor/suggestions/read-only-blocks.ts +136 -0
  106. package/corpus/templates/content/app/components/editor/table-view.ts +73 -0
  107. package/corpus/templates/content/app/components/layout/ContentStartupShell.tsx +1 -1
  108. package/corpus/templates/content/app/components/layout/Layout.tsx +5 -1
  109. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +57 -16
  110. package/corpus/templates/content/app/components/sidebar/MovePageDialog.tsx +4 -4
  111. package/corpus/templates/content/app/components/sidebar/SidebarNavigationRow.tsx +34 -10
  112. package/corpus/templates/content/app/global.css +16 -8
  113. package/corpus/templates/content/app/hooks/content-action-refresh.ts +14 -13
  114. package/corpus/templates/content/app/hooks/use-content-database.ts +72 -9
  115. package/corpus/templates/content/app/hooks/use-content-personal-navigation.ts +7 -3
  116. package/corpus/templates/content/app/hooks/use-documents.ts +27 -0
  117. package/corpus/templates/content/app/i18n-data.ts +3 -2
  118. package/corpus/templates/content/app/lib/content-landing.ts +3 -31
  119. package/corpus/templates/content/app/lib/files-navigation.ts +182 -10
  120. package/corpus/templates/content/app/lib/files-root-hint.ts +20 -32
  121. package/corpus/templates/content/app/lib/page-startup-hints.ts +108 -0
  122. package/corpus/templates/content/app/lib/private-link-redirect.ts +25 -0
  123. package/corpus/templates/content/app/lib/sidebar-layout-hint.ts +34 -1
  124. package/corpus/templates/content/app/lib/startup-timing.ts +2 -0
  125. package/corpus/templates/content/app/root.tsx +3 -1
  126. package/corpus/templates/content/app/routes/_app.home.tsx +10 -19
  127. package/corpus/templates/content/app/routes/p.$id.tsx +23 -5
  128. package/corpus/templates/content/changelog/2026-10-02-a-page-link-you-cant-open-now-says-so-instead-of-opening-an.md +6 -0
  129. package/corpus/templates/content/changelog/2026-10-02-after-a-refresh-the-files-sidebar-shows-the-open-page-s-fold.md +6 -0
  130. package/corpus/templates/content/changelog/2026-10-02-large-collections-open-faster.md +6 -0
  131. package/corpus/templates/content/changelog/2026-10-02-pages-stay-inside-the-window-at-every-width-long-inline-code.md +6 -0
  132. package/corpus/templates/content/changelog/2026-10-02-pages-with-open-comments-and-collections-with-sorted-or-filt.md +6 -0
  133. package/corpus/templates/content/changelog/2026-10-02-suggest-edits-works-on-pages-written-by-agents-including-pag.md +6 -0
  134. package/corpus/templates/content/changelog/2026-10-02-while-you-suggest-edits-tables-and-other-blocks-that-suggest.md +6 -0
  135. package/corpus/templates/content/changelog/2026-10-05-collection-view-context-now-survives-quick-page-changes-when.md +6 -0
  136. package/corpus/templates/content/changelog/2026-10-05-collection-views-keep-their-saved-rows-accurate-during-refre.md +6 -0
  137. package/corpus/templates/content/changelog/2026-10-05-exact-saved-view-links-keep-collection-retry-available.md +6 -0
  138. package/corpus/templates/content/changelog/2026-10-05-expanding-a-files-folder-now-shares-one-navigation-read-acro.md +6 -0
  139. package/corpus/templates/content/changelog/2026-10-05-files-navigation-retries-temporary-failures-consistently.md +6 -0
  140. package/corpus/templates/content/changelog/2026-10-05-shared-page-owners-keep-edit-and-manage-controls-in-files-an.md +6 -0
  141. package/corpus/templates/content/changelog/2026-10-05-tagging-an-ai-in-a-comment-works-again-instead-of-failing-ri.md +6 -0
  142. package/corpus/templates/content/changelog/2026-10-05-the-home-loading-shell-keeps-the-layout-of-your-last-opened-.md +6 -0
  143. package/corpus/templates/content/changelog/2026-10-05-typing-and-a-space-or-inserting-a-toggle-or-callout-no-longe.md +6 -0
  144. package/corpus/templates/content/docs/product/capabilities/content.workspace.session-restore.md +4 -1
  145. package/corpus/templates/content/e2e/playwright.config.ts +1 -1
  146. package/corpus/templates/content/package.json +2 -1
  147. package/corpus/templates/content/scripts/seed-perf-database.mjs +600 -0
  148. package/corpus/templates/content/scripts/trace-startup.mjs +25 -3
  149. package/corpus/templates/content/server/db/index.ts +1 -1
  150. package/corpus/templates/content/server/lib/suggested-edits.ts +23 -26
  151. package/corpus/templates/content/server/plugins/auth.ts +2 -1
  152. package/corpus/templates/content/server/plugins/otel.ts +6 -0
  153. package/corpus/templates/content/shared/api.ts +17 -0
  154. package/corpus/templates/content/shared/suggestion-diff.ts +124 -38
  155. package/corpus/templates/content/shared/suggestion-formatting.ts +134 -3
  156. package/corpus/templates/crm/.agents/skills/security/SKILL.md +9 -2
  157. package/corpus/templates/crm/.agents/skills/storing-data/SKILL.md +12 -7
  158. package/corpus/templates/crm/package.json +1 -0
  159. package/corpus/templates/crm/server/plugins/otel.ts +6 -0
  160. package/corpus/templates/design/.agents/skills/security/SKILL.md +9 -2
  161. package/corpus/templates/design/.agents/skills/storing-data/SKILL.md +12 -7
  162. package/corpus/templates/design/CHANGELOG.md +41 -0
  163. package/corpus/templates/design/README.md +2 -2
  164. package/corpus/templates/design/actions/list-designs.ts +11 -4
  165. package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +110 -32
  166. package/corpus/templates/design/app/components/design/multi-screen/cross-screen-drop.ts +28 -0
  167. package/corpus/templates/design/app/components/design/multi-screen/types.ts +1 -0
  168. package/corpus/templates/design/app/components/home/DesignHomeLibrary.tsx +79 -0
  169. package/corpus/templates/design/app/components/layout/Header.tsx +2 -4
  170. package/corpus/templates/design/app/components/ui/tabs.tsx +59 -1
  171. package/corpus/templates/design/app/global.css +1 -34
  172. package/corpus/templates/design/app/i18n/en-US.ts +4 -0
  173. package/corpus/templates/design/app/lib/design-filter.ts +4 -2
  174. package/corpus/templates/design/app/pages/Index.tsx +91 -59
  175. package/corpus/templates/design/app/pages/design-editor/commands/cross-screen-element-drop.ts +58 -17
  176. package/corpus/templates/design/changelog/2026-10-01-filter-designs-by-owner.md +6 -0
  177. package/corpus/templates/design/changelog/2026-10-03-layers-dropped-into-visible-canvas-space-beyond-a-screen-now.md +6 -0
  178. package/corpus/templates/design/changelog/2026-10-03-visible-screen-overflow-no-longer-routes-drops-to-the-canvas.md +6 -0
  179. package/corpus/templates/design/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-designs.md +6 -0
  180. package/corpus/templates/design/package.json +1 -0
  181. package/corpus/templates/design/server/plugins/auth.ts +2 -1
  182. package/corpus/templates/design/server/plugins/otel.ts +6 -0
  183. package/corpus/templates/dispatch/.agents/skills/security/SKILL.md +9 -2
  184. package/corpus/templates/dispatch/.agents/skills/storing-data/SKILL.md +12 -7
  185. package/corpus/templates/dispatch/README.md +2 -2
  186. package/corpus/templates/dispatch/package.json +1 -0
  187. package/corpus/templates/dispatch/server/plugins/otel.ts +6 -0
  188. package/corpus/templates/dispatch/server/plugins/setup-dispatch.ts +2 -1
  189. package/corpus/templates/factory/.agents/skills/security/SKILL.md +9 -2
  190. package/corpus/templates/factory/.agents/skills/storing-data/SKILL.md +12 -7
  191. package/corpus/templates/factory/package.json +1 -0
  192. package/corpus/templates/factory/server/plugins/otel.ts +6 -0
  193. package/corpus/templates/forms/.agents/skills/security/SKILL.md +9 -2
  194. package/corpus/templates/forms/.agents/skills/storing-data/SKILL.md +12 -7
  195. package/corpus/templates/forms/README.md +2 -2
  196. package/corpus/templates/forms/package.json +1 -0
  197. package/corpus/templates/forms/server/plugins/auth.ts +2 -1
  198. package/corpus/templates/forms/server/plugins/otel.ts +6 -0
  199. package/corpus/templates/mail/.agents/skills/security/SKILL.md +9 -2
  200. package/corpus/templates/mail/.agents/skills/storing-data/SKILL.md +12 -7
  201. package/corpus/templates/mail/CHANGELOG.md +6 -0
  202. package/corpus/templates/mail/README.md +2 -2
  203. package/corpus/templates/mail/package.json +1 -0
  204. package/corpus/templates/mail/server/plugins/auth.ts +2 -1
  205. package/corpus/templates/mail/server/plugins/otel.ts +6 -0
  206. package/corpus/templates/plan/.agents/skills/security/SKILL.md +9 -2
  207. package/corpus/templates/plan/.agents/skills/storing-data/SKILL.md +12 -7
  208. package/corpus/templates/plan/CHANGELOG.md +1 -0
  209. package/corpus/templates/plan/README.md +2 -2
  210. package/corpus/templates/plan/package.json +1 -0
  211. package/corpus/templates/plan/server/plugins/auth.ts +2 -1
  212. package/corpus/templates/plan/server/plugins/otel.ts +6 -0
  213. package/corpus/templates/slides/.agents/skills/security/SKILL.md +9 -2
  214. package/corpus/templates/slides/.agents/skills/storing-data/SKILL.md +12 -7
  215. package/corpus/templates/slides/CHANGELOG.md +23 -0
  216. package/corpus/templates/slides/README.md +2 -2
  217. package/corpus/templates/slides/actions/list-decks.ts +11 -4
  218. package/corpus/templates/slides/app/components/deck/DeckFilterMenu.tsx +44 -36
  219. package/corpus/templates/slides/app/components/home/SlidesHomeLibrary.tsx +79 -0
  220. package/corpus/templates/slides/app/components/layout/Header.tsx +2 -15
  221. package/corpus/templates/slides/app/components/ui/tabs.tsx +59 -0
  222. package/corpus/templates/slides/app/global.css +3 -54
  223. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  224. package/corpus/templates/slides/app/lib/deck-filter.ts +5 -2
  225. package/corpus/templates/slides/app/pages/Index.tsx +102 -88
  226. package/corpus/templates/slides/changelog/2026-10-01-filter-decks-by-owner.md +6 -0
  227. package/corpus/templates/slides/changelog/2026-10-02-hide-recent-until-decks-available.md +6 -0
  228. package/corpus/templates/slides/changelog/2026-10-05-the-recent-tab-shows-loading-placeholders-until-your-decks-a.md +6 -0
  229. package/corpus/templates/slides/package.json +1 -0
  230. package/corpus/templates/slides/server/handlers/request-auth-context.ts +8 -0
  231. package/corpus/templates/slides/server/plugins/auth.ts +2 -1
  232. package/corpus/templates/slides/server/plugins/otel.ts +6 -0
  233. package/corpus/templates/tasks/.agents/skills/security/SKILL.md +9 -2
  234. package/corpus/templates/tasks/.agents/skills/storing-data/SKILL.md +12 -7
  235. package/package.json +1 -1
@@ -135,7 +135,6 @@ import {
135
135
  contentNavigationBranchFilter,
136
136
  useContentActionMutation,
137
137
  } from "@/hooks/use-content-action-mutation";
138
- import { useContentDatabasePersonalView } from "@/hooks/use-content-database";
139
138
  import { useCreativeContextLab } from "@/hooks/use-creative-context-lab";
140
139
  import { useLocalStorage } from "@/hooks/use-local-storage";
141
140
  import {
@@ -151,10 +150,7 @@ import {
151
150
  } from "@/hooks/use-notion";
152
151
  import { contentAgentPromptValues } from "@/lib/content-agent-prompt";
153
152
  import { documentQueryFilter } from "@/lib/document-query";
154
- import {
155
- filesNavigationOrder,
156
- filesNavigationPageParams,
157
- } from "@/lib/files-navigation";
153
+ import { filesNavigationPageParams } from "@/lib/files-navigation";
158
154
  import {
159
155
  localSourceAbsolutePath,
160
156
  revealLinkedLocalSourceFile,
@@ -655,27 +651,15 @@ function useBreadcrumbSiblingPage(
655
651
  siblings: ToolbarBreadcrumbSiblings,
656
652
  options: { enabled: boolean; cursor?: string },
657
653
  ) {
658
- const personalView = useContentDatabasePersonalView(
659
- siblings.filesDatabaseId,
660
- { enabled: options.enabled },
661
- );
662
- const order = personalView.data
663
- ? filesNavigationOrder(personalView.data.overrides)
664
- : null;
665
- const page = useActionQuery<ContentDatabaseNavigationPageResponse>(
654
+ return useActionQuery<ContentDatabaseNavigationPageResponse>(
666
655
  "query-content-database-items",
667
- order
668
- ? filesNavigationPageParams({
669
- databaseId: siblings.filesDatabaseId,
670
- parentId: siblings.parentId,
671
- sort: order.order.mode,
672
- viewId: order.activeViewId,
673
- cursor: options.cursor,
674
- })
675
- : undefined,
676
- { enabled: options.enabled && order !== null },
656
+ filesNavigationPageParams({
657
+ databaseId: siblings.filesDatabaseId,
658
+ parentId: siblings.parentId,
659
+ cursor: options.cursor,
660
+ }),
661
+ { enabled: options.enabled },
677
662
  );
678
- return { personalView, page };
679
663
  }
680
664
 
681
665
  // Reads the sidebar's cached page for the branch without fetching, so an item
@@ -684,7 +668,7 @@ function useCachedBreadcrumbPeerCount(
684
668
  siblings: ToolbarBreadcrumbSiblings,
685
669
  documentId: string | undefined,
686
670
  ) {
687
- const { page } = useBreadcrumbSiblingPage(siblings, { enabled: false });
671
+ const page = useBreadcrumbSiblingPage(siblings, { enabled: false });
688
672
  if (!page.data) return null;
689
673
  if (page.data.pagination.hasMore) return Number.POSITIVE_INFINITY;
690
674
  const peers = page.data.items.filter((peer) => peer.sourceKind !== "folder");
@@ -711,16 +695,16 @@ function ToolbarBreadcrumbSiblingPage({
711
695
  }) {
712
696
  const t = useT();
713
697
  const [nextPageVisible, setNextPageVisible] = useState(false);
714
- const { personalView, page } = useBreadcrumbSiblingPage(siblings, {
698
+ const page = useBreadcrumbSiblingPage(siblings, {
715
699
  enabled: true,
716
700
  cursor,
717
701
  });
718
- if (personalView.isError || page.isError) {
702
+ if (page.isError) {
719
703
  return (
720
704
  <DropdownMenuItem
721
705
  onSelect={(event) => {
722
706
  event.preventDefault();
723
- void (personalView.isError ? personalView.refetch() : page.refetch());
707
+ void page.refetch();
724
708
  }}
725
709
  >
726
710
  {t("database.retry")}
@@ -20,7 +20,10 @@ import {
20
20
  useUpdatePreviewDocumentDraft,
21
21
  } from "@/hooks/use-documents";
22
22
  import { isDocumentCreationPending } from "@/lib/optimistic-document";
23
- import { readPageIconRowHint } from "@/lib/page-icon-row-hint";
23
+ import {
24
+ readDocumentShapeHint,
25
+ readPageIconRowHint,
26
+ } from "@/lib/page-startup-hints";
24
27
 
25
28
  import { documentBodyHydrationIsPending } from "./body-hydration";
26
29
  import { saveDocumentWithRebase } from "./document-save-rebase";
@@ -675,6 +678,7 @@ export function PageDraftRecovery({
675
678
  <DocumentEditorSkeleton
676
679
  title={document.title}
677
680
  iconRow={readPageIconRowHint(document.id)}
681
+ shape={readDocumentShapeHint(document)}
678
682
  />
679
683
  );
680
684
  if (!draft) return withNotice(null);
@@ -685,6 +689,7 @@ export function PageDraftRecovery({
685
689
  <DocumentEditorSkeleton
686
690
  title={document.title}
687
691
  iconRow={readPageIconRowHint(document.id)}
692
+ shape={readDocumentShapeHint(document)}
688
693
  />
689
694
  );
690
695
  const savedVersion = conflictDocument ?? document;
@@ -165,7 +165,7 @@ function getCellAtAddress(
165
165
  return getCells(row)[address.columnIndex] ?? null;
166
166
  }
167
167
 
168
- function getSelectionOverlayRect(rects: DOMRect[]) {
168
+ function getSelectionOverlayRect(table: HTMLElement, rects: DOMRect[]) {
169
169
  if (rects.length === 0) return null;
170
170
 
171
171
  const left = Math.min(...rects.map((rect) => rect.left));
@@ -173,12 +173,32 @@ function getSelectionOverlayRect(rects: DOMRect[]) {
173
173
  const top = Math.min(...rects.map((rect) => rect.top));
174
174
  const bottom = Math.max(...rects.map((rect) => rect.bottom));
175
175
 
176
+ return clampToScrollport(
177
+ { height: bottom - top, left, top, width: right - left },
178
+ getTableScrollport(table),
179
+ );
180
+ }
181
+
182
+ // Tables scroll sideways inside `.tableWrapper`, but these controls render
183
+ // beside the editor, outside its clipping, so they clip themselves to it.
184
+ function getTableScrollport(table: HTMLElement) {
185
+ return (table.closest(".tableWrapper") ?? table).getBoundingClientRect();
186
+ }
187
+
188
+ function clampToScrollport(
189
+ rect: SelectionOverlayRect,
190
+ scrollport: DOMRect,
191
+ ): SelectionOverlayRect {
192
+ const clamp = (x: number) =>
193
+ Math.min(Math.max(x, scrollport.left), scrollport.right);
194
+ const left = clamp(rect.left);
195
+
176
196
  return {
177
- height: bottom - top,
197
+ height: rect.height,
178
198
  left,
179
- top,
180
- width: right - left,
181
- } satisfies SelectionOverlayRect;
199
+ top: rect.top,
200
+ width: clamp(rect.left + rect.width) - left,
201
+ };
182
202
  }
183
203
 
184
204
  function getRowSelectionOverlayRect(
@@ -188,6 +208,7 @@ function getRowSelectionOverlayRect(
188
208
  if (!address) return null;
189
209
 
190
210
  return getSelectionOverlayRect(
211
+ table,
191
212
  getCells(getRows(table)[address.rowIndex]).map((cell) =>
192
213
  cell.getBoundingClientRect(),
193
214
  ),
@@ -201,6 +222,7 @@ function getColumnSelectionOverlayRect(
201
222
  if (!address) return null;
202
223
 
203
224
  return getSelectionOverlayRect(
225
+ table,
204
226
  getRows(table)
205
227
  .map((row) => getCells(row)[address.columnIndex])
206
228
  .filter((cell): cell is HTMLElement => Boolean(cell))
@@ -381,6 +403,7 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
381
403
  const [columnMenuOpen, setColumnMenuOpen] = useState(false);
382
404
  const [rowMenuOpen, setRowMenuOpen] = useState(false);
383
405
  const [viewRetry, setViewRetry] = useState(0);
406
+ const [, setGeometryRevision] = useState(0);
384
407
 
385
408
  const holdTableUiSelection = () => {
386
409
  tableUiPointerDownRef.current = true;
@@ -971,7 +994,19 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
971
994
  syncOverlay();
972
995
  };
973
996
 
974
- const handleGeometryChange = () => syncOverlay();
997
+ const handleGeometryChange = () => {
998
+ syncOverlay();
999
+ setGeometryRevision((revision) => revision + 1);
1000
+ };
1001
+ // Page scrolls carry the overlay along with the tables, but a table
1002
+ // scrolled sideways inside its own `.tableWrapper` leaves the overlay behind.
1003
+ const handleScroll = (event: Event) => {
1004
+ if (event.target instanceof Node && view.dom.contains(event.target)) {
1005
+ handleGeometryChange();
1006
+ } else {
1007
+ syncOverlay();
1008
+ }
1009
+ };
975
1010
  const observer = new MutationObserver(syncOverlay);
976
1011
 
977
1012
  syncOverlay();
@@ -982,7 +1017,7 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
982
1017
  document.addEventListener("click", handlePointerDown, true);
983
1018
  document.addEventListener("pointermove", handleHoverPointerMove, true);
984
1019
  window.addEventListener("resize", handleGeometryChange);
985
- window.addEventListener("scroll", handleGeometryChange, true);
1020
+ window.addEventListener("scroll", handleScroll, true);
986
1021
  view.dom.addEventListener("keyup", handleKeyUp);
987
1022
 
988
1023
  return () => {
@@ -992,7 +1027,7 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
992
1027
  document.removeEventListener("click", handlePointerDown, true);
993
1028
  document.removeEventListener("pointermove", handleHoverPointerMove, true);
994
1029
  window.removeEventListener("resize", handleGeometryChange);
995
- window.removeEventListener("scroll", handleGeometryChange, true);
1030
+ window.removeEventListener("scroll", handleScroll, true);
996
1031
  window.removeEventListener("pointermove", handlePointerMove);
997
1032
  window.removeEventListener("pointerup", handlePointerUp);
998
1033
  view.dom.removeEventListener("keyup", handleKeyUp);
@@ -1000,6 +1035,18 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
1000
1035
  };
1001
1036
  }, [editor, viewRetry]);
1002
1037
 
1038
+ // Panels opening beside the page narrow the editor without a window resize.
1039
+ useEffect(() => {
1040
+ const view = getMountedEditorView(editor);
1041
+ if (!view || tables.length === 0) return;
1042
+ const observer = new ResizeObserver(() =>
1043
+ setGeometryRevision((revision) => revision + 1),
1044
+ );
1045
+ observer.observe(view.dom);
1046
+ for (const table of tables) observer.observe(table);
1047
+ return () => observer.disconnect();
1048
+ }, [editor, tables]);
1049
+
1003
1050
  const view = getMountedEditorView(editor);
1004
1051
  if (!view) return null;
1005
1052
 
@@ -1020,6 +1067,13 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
1020
1067
  : null);
1021
1068
  const selectedTableRect =
1022
1069
  selectedTable?.getBoundingClientRect() ?? selectedTableRectRef.current;
1070
+ const selectedScrollport = selectedTable
1071
+ ? getTableScrollport(selectedTable)
1072
+ : null;
1073
+ const visibleSelectedRect =
1074
+ selectedRect && selectedScrollport
1075
+ ? clampToScrollport(selectedRect, selectedScrollport)
1076
+ : null;
1023
1077
  const selectedDimensions = selectedTable
1024
1078
  ? getTableDimensions(selectedTable)
1025
1079
  : { rowCount: 0, columnCount: 0 };
@@ -1050,9 +1104,9 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
1050
1104
  typeof window === "undefined"
1051
1105
  ? Number.POSITIVE_INFINITY
1052
1106
  : window.innerHeight;
1053
- const columnMenuWouldOverflowRight = selectedRect
1054
- ? selectedRect.left +
1055
- selectedRect.width / 2 +
1107
+ const columnMenuWouldOverflowRight = visibleSelectedRect
1108
+ ? visibleSelectedRect.left +
1109
+ visibleSelectedRect.width / 2 +
1056
1110
  COLUMN_OPTIONS_MENU_ALIGN_OFFSET +
1057
1111
  COLUMN_OPTIONS_MENU_WIDTH >
1058
1112
  viewportWidth - MENU_COLLISION_PADDING
@@ -1084,9 +1138,12 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
1084
1138
 
1085
1139
  return (
1086
1140
  <>
1087
- {selectedRect && selectedTable && selectedTableRect ? (
1141
+ {visibleSelectedRect &&
1142
+ selectedScrollport &&
1143
+ selectedTable &&
1144
+ selectedTableRect ? (
1088
1145
  <>
1089
- {selectedColumnOverlayRect ? (
1146
+ {selectedColumnOverlayRect?.width ? (
1090
1147
  <div
1091
1148
  className="pointer-events-none absolute z-20 rounded-[3px] border-2 border-primary/60 bg-primary/10"
1092
1149
  data-testid="table-selected-column"
@@ -1099,7 +1156,7 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
1099
1156
  />
1100
1157
  ) : null}
1101
1158
 
1102
- {selectedRowOverlayRect ? (
1159
+ {selectedRowOverlayRect?.width ? (
1103
1160
  <div
1104
1161
  className="pointer-events-none absolute z-20 rounded-[3px] border-2 border-primary/60 bg-primary/10"
1105
1162
  data-testid="table-selected-row"
@@ -1112,22 +1169,27 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
1112
1169
  />
1113
1170
  ) : null}
1114
1171
 
1115
- <div
1116
- className="pointer-events-none absolute z-30 rounded-[3px] border-2 border-primary/75 bg-primary/10"
1117
- data-testid="table-selected-cell"
1118
- style={{
1119
- left: selectedRect.left - wrapperRect.left,
1120
- top: selectedRect.top - wrapperRect.top,
1121
- width: selectedRect.width,
1122
- height: selectedRect.height,
1123
- }}
1124
- />
1172
+ {visibleSelectedRect.width ? (
1173
+ <div
1174
+ className="pointer-events-none absolute z-30 rounded-[3px] border-2 border-primary/75 bg-primary/10"
1175
+ data-testid="table-selected-cell"
1176
+ style={{
1177
+ left: visibleSelectedRect.left - wrapperRect.left,
1178
+ top: visibleSelectedRect.top - wrapperRect.top,
1179
+ width: visibleSelectedRect.width,
1180
+ height: visibleSelectedRect.height,
1181
+ }}
1182
+ />
1183
+ ) : null}
1125
1184
 
1126
1185
  <DropdownMenu open={columnMenuOpen} onOpenChange={setColumnMenuOpen}>
1127
1186
  <DropdownMenuTrigger asChild>
1128
1187
  <button
1129
1188
  aria-label={t("database.columnOptions")}
1130
- className={lineButtonClass}
1189
+ className={cn(
1190
+ lineButtonClass,
1191
+ !visibleSelectedRect.width && "invisible",
1192
+ )}
1131
1193
  data-testid="table-column-options"
1132
1194
  onClickCapture={(event) => {
1133
1195
  event.preventDefault();
@@ -1146,9 +1208,9 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
1146
1208
  }}
1147
1209
  style={{
1148
1210
  left:
1149
- selectedRect.left -
1211
+ visibleSelectedRect.left -
1150
1212
  wrapperRect.left +
1151
- selectedRect.width / 2,
1213
+ visibleSelectedRect.width / 2,
1152
1214
  top:
1153
1215
  selectedTableRect.top -
1154
1216
  wrapperRect.top -
@@ -1290,13 +1352,13 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
1290
1352
  }}
1291
1353
  style={{
1292
1354
  left:
1293
- selectedTableRect.left -
1355
+ Math.max(selectedTableRect.left, selectedScrollport.left) -
1294
1356
  wrapperRect.left -
1295
1357
  ROW_OPTIONS_HIT_WIDTH / 2,
1296
1358
  top:
1297
- selectedRect.top -
1359
+ visibleSelectedRect.top -
1298
1360
  wrapperRect.top +
1299
- selectedRect.height / 2,
1361
+ visibleSelectedRect.height / 2,
1300
1362
  height: ROW_OPTIONS_HIT_HEIGHT,
1301
1363
  transform: "translateY(-50%)",
1302
1364
  width: ROW_OPTIONS_HIT_WIDTH,
@@ -1416,55 +1478,62 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
1416
1478
 
1417
1479
  const tableId = getTableOverlayId(table);
1418
1480
  const rect = table.getBoundingClientRect();
1419
- const left = rect.left - wrapperRect.left;
1481
+ const scrollportRect = getTableScrollport(table);
1482
+ const visibleLeft = Math.max(rect.left, scrollportRect.left);
1483
+ const visibleRight = Math.min(rect.right, scrollportRect.right);
1484
+ const isTableEndVisible = rect.right <= visibleRight + 1;
1420
1485
  const top = rect.top - wrapperRect.top;
1421
1486
  const right = rect.right - wrapperRect.left;
1422
1487
  const bottom = rect.bottom - wrapperRect.top;
1488
+ const visibleCenter =
1489
+ (visibleLeft + visibleRight) / 2 - wrapperRect.left;
1423
1490
  const isColumnHandleVisible = hoveredEdges.columnTable === table;
1424
1491
  const isRowHandleVisible = hoveredEdges.rowTable === table;
1425
1492
 
1426
1493
  return (
1427
1494
  <div key={tableId}>
1428
- <Tooltip delayDuration={EDGE_HANDLE_TOOLTIP_DELAY}>
1429
- <TooltipTrigger asChild>
1430
- <button
1431
- aria-label={t("database.tableColumnHandle")}
1432
- className={cn(
1433
- handleClass,
1434
- "cursor-col-resize -translate-y-1/2",
1435
- isColumnHandleVisible && "opacity-100",
1436
- )}
1437
- data-table-edge-control
1438
- data-table-edge="column"
1439
- data-table-id={tableId}
1440
- data-testid="table-column-handle"
1441
- onPointerDown={(event) =>
1442
- startHandlePointer("column", table, event)
1443
- }
1444
- style={{
1445
- height: COLUMN_EDGE_HANDLE_HIT_HEIGHT,
1446
- left: right - COLUMN_EDGE_HANDLE_HIT_WIDTH / 2,
1447
- top: top + rect.height / 2,
1448
- width: COLUMN_EDGE_HANDLE_HIT_WIDTH,
1449
- }}
1450
- type="button"
1451
- >
1452
- <span
1453
- className={edgeHandleMarkerClass}
1495
+ {isTableEndVisible ? (
1496
+ <Tooltip delayDuration={EDGE_HANDLE_TOOLTIP_DELAY}>
1497
+ <TooltipTrigger asChild>
1498
+ <button
1499
+ aria-label={t("database.tableColumnHandle")}
1500
+ className={cn(
1501
+ handleClass,
1502
+ "cursor-col-resize -translate-y-1/2",
1503
+ isColumnHandleVisible && "opacity-100",
1504
+ )}
1505
+ data-table-edge-control
1506
+ data-table-edge="column"
1507
+ data-table-id={tableId}
1508
+ data-testid="table-column-handle"
1509
+ onPointerDown={(event) =>
1510
+ startHandlePointer("column", table, event)
1511
+ }
1454
1512
  style={{
1455
- height: EDGE_HANDLE_LENGTH,
1456
- width: EDGE_HANDLE_THICKNESS,
1513
+ height: COLUMN_EDGE_HANDLE_HIT_HEIGHT,
1514
+ left: right - COLUMN_EDGE_HANDLE_HIT_WIDTH / 2,
1515
+ top: top + rect.height / 2,
1516
+ width: COLUMN_EDGE_HANDLE_HIT_WIDTH,
1457
1517
  }}
1458
- />
1459
- </button>
1460
- </TooltipTrigger>
1461
- <TooltipContent>
1462
- <strong>{t("database.click")}</strong>{" "}
1463
- {t("database.toAddAColumn")}{" "}
1464
- <strong>{t("database.drag")}</strong>{" "}
1465
- {t("database.toAddOrRemoveColumns")}
1466
- </TooltipContent>
1467
- </Tooltip>
1518
+ type="button"
1519
+ >
1520
+ <span
1521
+ className={edgeHandleMarkerClass}
1522
+ style={{
1523
+ height: EDGE_HANDLE_LENGTH,
1524
+ width: EDGE_HANDLE_THICKNESS,
1525
+ }}
1526
+ />
1527
+ </button>
1528
+ </TooltipTrigger>
1529
+ <TooltipContent>
1530
+ <strong>{t("database.click")}</strong>{" "}
1531
+ {t("database.toAddAColumn")}{" "}
1532
+ <strong>{t("database.drag")}</strong>{" "}
1533
+ {t("database.toAddOrRemoveColumns")}
1534
+ </TooltipContent>
1535
+ </Tooltip>
1536
+ ) : null}
1468
1537
 
1469
1538
  <Tooltip delayDuration={EDGE_HANDLE_TOOLTIP_DELAY}>
1470
1539
  <TooltipTrigger asChild>
@@ -1484,7 +1553,7 @@ export function TableHoverControls({ editor }: TableHoverControlsProps) {
1484
1553
  }
1485
1554
  style={{
1486
1555
  height: ROW_EDGE_HANDLE_HIT_HEIGHT,
1487
- left: left + rect.width / 2,
1556
+ left: visibleCenter,
1488
1557
  top: bottom - ROW_EDGE_HANDLE_HIT_HEIGHT / 2,
1489
1558
  width: ROW_EDGE_HANDLE_HIT_WIDTH,
1490
1559
  }}
@@ -165,6 +165,8 @@ import {
165
165
  resolveSuggestionPresentationRange,
166
166
  type SuggestionPresentationTransition,
167
167
  } from "./suggestions/presentation-rebase";
168
+ import { SuggestingReadOnlyBlocks } from "./suggestions/read-only-blocks";
169
+ import { ContentTableView } from "./table-view";
168
170
  import { TableHoverControls } from "./TableHoverControls";
169
171
 
170
172
  function compareDocumentBodyRevisions(
@@ -364,7 +366,11 @@ function dispatchLiteralPaste(view: EditorView, slice: Slice): void {
364
366
  .setMeta("paste", true)
365
367
  .setMeta("uiEvent", "paste");
366
368
  const expected = insertion.doc;
369
+ const before = view.state.doc;
367
370
  view.dispatch(insertion);
371
+ // A filter refused the paste (for example into a block that is read-only
372
+ // while suggesting); retrying it as a raw range would insert it anyway.
373
+ if (view.state.doc === before) return;
368
374
 
369
375
  if (!view.state.doc.eq(expected)) {
370
376
  view.dispatch(
@@ -1967,6 +1973,7 @@ interface VisualEditorExtensionOptions {
1967
1973
  onImageComment?: (quotedText: string, offsetTop: number) => void;
1968
1974
  onImageFilePickerRequest?: (request: PendingImagePicker) => void;
1969
1975
  canMutateMedia?: () => boolean;
1976
+ isSuggesting?: () => boolean;
1970
1977
  onJoinTitle?: (text: string) => void;
1971
1978
  onOpenNotionPageLink?: (documentId: string) => void;
1972
1979
  localFilePath?: string | null;
@@ -2566,6 +2573,7 @@ export function createVisualEditorExtensions({
2566
2573
  onImageComment,
2567
2574
  onImageFilePickerRequest,
2568
2575
  canMutateMedia,
2576
+ isSuggesting,
2569
2577
  onJoinTitle,
2570
2578
  onOpenNotionPageLink,
2571
2579
  localFilePath,
@@ -2638,6 +2646,7 @@ export function createVisualEditorExtensions({
2638
2646
  MediaSourceCommit.configure({ onMediaSourceCommitted }),
2639
2647
  CustomTable.configure({
2640
2648
  resizable: true,
2649
+ View: ContentTableView,
2641
2650
  HTMLAttributes: { class: "notion-table" },
2642
2651
  }),
2643
2652
  TableRow,
@@ -2645,6 +2654,9 @@ export function createVisualEditorExtensions({
2645
2654
  NotionTableCell,
2646
2655
  NormalizeTableHeaders,
2647
2656
  NormalizeTableAlignment,
2657
+ ...(isSuggesting
2658
+ ? [SuggestingReadOnlyBlocks.configure({ isSuggesting })]
2659
+ : []),
2648
2660
  ...createNotionEditorExtensions({
2649
2661
  documentId,
2650
2662
  onOpenPageLink: onOpenNotionPageLink,
@@ -3165,6 +3177,7 @@ export function VisualEditor({
3165
3177
  }
3166
3178
  }, [documentId, fileStorageConfigured]);
3167
3179
  const canMutateMedia = useCallback(() => !suggestingRef.current, []);
3180
+ const isSuggesting = useCallback(() => suggestingRef.current, []);
3168
3181
  const isVisualEditorFocused = useCallback((editor: CoreEditor) => {
3169
3182
  if (editor.isFocused) return true;
3170
3183
  const activeElement = editor.view.dom.ownerDocument.activeElement;
@@ -3210,6 +3223,7 @@ export function VisualEditor({
3210
3223
  onImageComment: onComment,
3211
3224
  onImageFilePickerRequest,
3212
3225
  canMutateMedia,
3226
+ isSuggesting,
3213
3227
  onJoinTitle,
3214
3228
  onOpenNotionPageLink,
3215
3229
  localFilePath,
@@ -3252,6 +3266,7 @@ export function VisualEditor({
3252
3266
  onComment,
3253
3267
  onImageFilePickerRequest,
3254
3268
  canMutateMedia,
3269
+ isSuggesting,
3255
3270
  onJoinTitle,
3256
3271
  onOpenNotionPageLink,
3257
3272
  localFilePath,
@@ -4525,7 +4540,7 @@ export function VisualEditor({
4525
4540
  />
4526
4541
  ) : null}
4527
4542
  <LinkHoverPreview editor={editor} editable={editable} />
4528
- {editable ? <TableHoverControls editor={editor} /> : null}
4543
+ {editable && !suggesting ? <TableHoverControls editor={editor} /> : null}
4529
4544
  {editable && isDraggingMedia ? (
4530
4545
  <div className="media-drop-overlay">
4531
4546
  <div className="media-drop-overlay__content">