canopycms 0.0.68-int.98 → 0.1.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 (688) hide show
  1. package/CHANGELOG.md +2131 -0
  2. package/README.md +47 -63
  3. package/dist/ai/generate.d.ts +5 -0
  4. package/dist/ai/generate.js +244 -115
  5. package/dist/ai/index.d.ts +1 -1
  6. package/dist/ai/json-to-markdown.d.ts +21 -1
  7. package/dist/ai/json-to-markdown.js +120 -57
  8. package/dist/ai/references.d.ts +72 -0
  9. package/dist/ai/references.js +223 -0
  10. package/dist/ai/resolve-branch.js +9 -2
  11. package/dist/ai/to-plain-text.d.ts +17 -8
  12. package/dist/ai/to-plain-text.js +18 -15
  13. package/dist/ai/types.d.ts +84 -3
  14. package/dist/api/admin-branch-health.d.ts +24 -1
  15. package/dist/api/admin-branch-health.js +52 -20
  16. package/dist/api/admin.d.ts +23 -5
  17. package/dist/api/admin.js +36 -1
  18. package/dist/api/assets.js +88 -78
  19. package/dist/api/branch-create-window.d.ts +12 -0
  20. package/dist/api/branch-create-window.js +13 -0
  21. package/dist/api/branch-merge.d.ts +1 -1
  22. package/dist/api/branch-merge.js +1 -1
  23. package/dist/api/branch-review.d.ts +3 -3
  24. package/dist/api/branch-review.js +16 -7
  25. package/dist/api/branch-status.d.ts +16 -6
  26. package/dist/api/branch-status.js +57 -12
  27. package/dist/api/branch-withdraw.d.ts +2 -2
  28. package/dist/api/branch-withdraw.js +8 -3
  29. package/dist/api/branch.d.ts +25 -12
  30. package/dist/api/branch.js +164 -103
  31. package/dist/api/client.d.ts +78 -58
  32. package/dist/api/client.js +150 -117
  33. package/dist/api/comments.d.ts +12 -3
  34. package/dist/api/comments.js +118 -9
  35. package/dist/api/content.d.ts +9 -9
  36. package/dist/api/content.js +131 -22
  37. package/dist/api/entries-constants.d.ts +14 -3
  38. package/dist/api/entries-constants.js +14 -3
  39. package/dist/api/entries.d.ts +40 -2
  40. package/dist/api/entries.js +102 -6
  41. package/dist/api/github-sync.d.ts +19 -0
  42. package/dist/api/github-sync.js +50 -3
  43. package/dist/api/groups.d.ts +4 -4
  44. package/dist/api/groups.js +2 -1
  45. package/dist/api/guards.js +23 -3
  46. package/dist/api/index.d.ts +3 -1
  47. package/dist/api/index.js +1 -0
  48. package/dist/api/permissions.d.ts +21 -2
  49. package/dist/api/permissions.js +50 -3
  50. package/dist/api/request-deadline.d.ts +59 -0
  51. package/dist/api/request-deadline.js +73 -0
  52. package/dist/api/resolve-references.js +8 -7
  53. package/dist/api/route-builder.d.ts +14 -0
  54. package/dist/api/route-builder.js +14 -1
  55. package/dist/api/schema.d.ts +11 -9
  56. package/dist/api/schema.js +2 -0
  57. package/dist/api/settings-helpers.d.ts +5 -1
  58. package/dist/api/settings-helpers.js +10 -2
  59. package/dist/api/types.d.ts +18 -0
  60. package/dist/api/users-constants.d.ts +6 -0
  61. package/dist/api/users-constants.js +6 -0
  62. package/dist/assets/asset-url.d.ts +28 -16
  63. package/dist/assets/asset-url.js +51 -25
  64. package/dist/assets/finalize.js +3 -0
  65. package/dist/assets/index.d.ts +1 -1
  66. package/dist/assets/materialize.d.ts +153 -0
  67. package/dist/assets/materialize.js +402 -0
  68. package/dist/assets/store-local.d.ts +19 -5
  69. package/dist/assets/store-local.js +69 -10
  70. package/dist/assets/store-s3.d.ts +38 -7
  71. package/dist/assets/store-s3.js +128 -22
  72. package/dist/assets/transform-directives.d.ts +52 -13
  73. package/dist/assets/transform-directives.js +87 -27
  74. package/dist/assets/transform.d.ts +3 -3
  75. package/dist/assets/transform.js +13 -8
  76. package/dist/assets/types.d.ts +31 -4
  77. package/dist/auth/cache.d.ts +1 -1
  78. package/dist/auth/cache.js +1 -1
  79. package/dist/auth/caching-auth-plugin.d.ts +2 -0
  80. package/dist/auth/caching-auth-plugin.js +12 -2
  81. package/dist/auth/file-based-auth-cache.d.ts +8 -0
  82. package/dist/auth/file-based-auth-cache.js +18 -8
  83. package/dist/auth/person-name.d.ts +5 -0
  84. package/dist/auth/person-name.js +8 -0
  85. package/dist/auth/plugin.d.ts +10 -1
  86. package/dist/auth/types.d.ts +2 -0
  87. package/dist/auth/user-metadata-lookup.d.ts +21 -0
  88. package/dist/auth/user-metadata-lookup.js +116 -0
  89. package/dist/authorization/branch.d.ts +1 -1
  90. package/dist/authorization/branch.js +12 -13
  91. package/dist/authorization/groups/schema.d.ts +4 -4
  92. package/dist/authorization/helpers.d.ts +8 -0
  93. package/dist/authorization/helpers.js +8 -0
  94. package/dist/authorization/index.d.ts +1 -1
  95. package/dist/authorization/index.js +1 -1
  96. package/dist/authorization/protected-branch.d.ts +5 -4
  97. package/dist/authorization/protected-branch.js +7 -5
  98. package/dist/branch-health.d.ts +35 -8
  99. package/dist/branch-health.js +54 -18
  100. package/dist/branch-metadata-error.d.ts +27 -0
  101. package/dist/branch-metadata-error.js +23 -0
  102. package/dist/branch-metadata-file.d.ts +205 -24
  103. package/dist/branch-metadata-file.js +126 -25
  104. package/dist/branch-metadata.d.ts +45 -6
  105. package/dist/branch-metadata.js +142 -50
  106. package/dist/branch-provisioning.d.ts +167 -0
  107. package/dist/branch-provisioning.js +501 -0
  108. package/dist/branch-registry.d.ts +8 -0
  109. package/dist/branch-registry.js +61 -9
  110. package/dist/branch-schema-cache.d.ts +29 -12
  111. package/dist/branch-schema-cache.js +64 -21
  112. package/dist/branch-sparse.d.ts +23 -0
  113. package/dist/branch-sparse.js +118 -0
  114. package/dist/branch-workspace.d.ts +42 -3
  115. package/dist/branch-workspace.js +239 -100
  116. package/dist/build/asset-refs.d.ts +94 -0
  117. package/dist/build/asset-refs.js +267 -0
  118. package/dist/build/generate-ai-content.js +5 -0
  119. package/dist/build/inline-flight.d.ts +37 -0
  120. package/dist/build/inline-flight.js +142 -0
  121. package/dist/cli/asset-refs.d.ts +52 -0
  122. package/dist/cli/asset-refs.js +194 -0
  123. package/dist/cli/cli.d.ts +15 -1
  124. package/dist/cli/cli.js +8543 -3193
  125. package/dist/cli/configured-asset-store.d.ts +12 -0
  126. package/dist/cli/configured-asset-store.js +46 -0
  127. package/dist/cli/generate-ai-content.js +4244 -1072
  128. package/dist/cli/init.js +217 -126
  129. package/dist/cli/project-detect.d.ts +2 -0
  130. package/dist/cli/project-detect.js +2 -0
  131. package/dist/cli/template-files/Dockerfile.cms.template +13 -5
  132. package/dist/cli/template-files/cms-stack.ts.template +16 -13
  133. package/dist/client.d.ts +1 -2
  134. package/dist/client.js +1 -2
  135. package/dist/comment-store.d.ts +25 -0
  136. package/dist/comment-store.js +43 -8
  137. package/dist/config/flatten.js +2 -0
  138. package/dist/config/helpers.js +2 -2
  139. package/dist/config/index.d.ts +1 -1
  140. package/dist/config/schemas/config.d.ts +12 -29
  141. package/dist/config/schemas/config.js +9 -12
  142. package/dist/config/schemas/field.d.ts +3 -0
  143. package/dist/config/schemas/field.js +58 -4
  144. package/dist/config/schemas/media.d.ts +4 -13
  145. package/dist/config/schemas/media.js +5 -8
  146. package/dist/config/schemas/url.d.ts +2 -20
  147. package/dist/config/schemas/url.js +2 -25
  148. package/dist/config/types.d.ts +116 -22
  149. package/dist/config/types.js +3 -9
  150. package/dist/config/validation.d.ts +25 -4
  151. package/dist/config/validation.js +116 -3
  152. package/dist/content-id-index.js +2 -2
  153. package/dist/content-index-generation.d.ts +1 -1
  154. package/dist/content-index-generation.js +1 -1
  155. package/dist/content-listing.d.ts +10 -1
  156. package/dist/content-listing.js +22 -5
  157. package/dist/content-reader.d.ts +9 -0
  158. package/dist/content-reader.js +16 -11
  159. package/dist/content-store.d.ts +75 -12
  160. package/dist/content-store.js +249 -86
  161. package/dist/content-tree.js +2 -2
  162. package/dist/context.js +5 -2
  163. package/dist/dangling-reference-log.d.ts +17 -0
  164. package/dist/dangling-reference-log.js +29 -0
  165. package/dist/dev-content-watcher.d.ts +1 -1
  166. package/dist/dev-content-watcher.js +1 -1
  167. package/dist/editor/BranchManager.d.ts +23 -7
  168. package/dist/editor/BranchManager.js +119 -54
  169. package/dist/editor/CanopyEditor.d.ts +1 -1
  170. package/dist/editor/CanopyEditor.js +1 -2
  171. package/dist/editor/CommentsPanel.d.ts +14 -0
  172. package/dist/editor/CommentsPanel.js +68 -43
  173. package/dist/editor/Editor.d.ts +11 -5
  174. package/dist/editor/Editor.js +891 -218
  175. package/dist/editor/EditorAuthGate.d.ts +7 -1
  176. package/dist/editor/EditorAuthGate.js +41 -9
  177. package/dist/editor/EntryNavigator.d.ts +22 -0
  178. package/dist/editor/EntryNavigator.js +353 -105
  179. package/dist/editor/FormHeader.d.ts +25 -0
  180. package/dist/editor/FormHeader.js +82 -0
  181. package/dist/editor/FormRenderer.d.ts +27 -3
  182. package/dist/editor/FormRenderer.js +171 -76
  183. package/dist/editor/PreviewFrame.d.ts +40 -0
  184. package/dist/editor/PreviewFrame.js +215 -0
  185. package/dist/editor/PreviewPane.d.ts +47 -0
  186. package/dist/editor/PreviewPane.js +147 -0
  187. package/dist/editor/PreviewToolbarTools.d.ts +22 -0
  188. package/dist/editor/PreviewToolbarTools.js +73 -0
  189. package/dist/editor/admin/SystemHealthPanel.d.ts +2 -1
  190. package/dist/editor/admin/SystemHealthPanel.js +163 -33
  191. package/dist/editor/admin/useSystemHealth.d.ts +18 -0
  192. package/dist/editor/admin/useSystemHealth.js +70 -1
  193. package/dist/editor/branch-status.d.ts +17 -0
  194. package/dist/editor/branch-status.js +29 -0
  195. package/dist/editor/canopy-path.d.ts +9 -6
  196. package/dist/editor/canopy-path.js +8 -11
  197. package/dist/editor/client-reference-resolver.d.ts +43 -16
  198. package/dist/editor/client-reference-resolver.js +155 -64
  199. package/dist/editor/comments/BranchComments.d.ts +1 -1
  200. package/dist/editor/comments/BranchComments.js +2 -2
  201. package/dist/editor/comments/CloseRefusedNotice.d.ts +4 -0
  202. package/dist/editor/comments/CloseRefusedNotice.js +7 -0
  203. package/dist/editor/comments/CommentThreadsPopover.d.ts +47 -0
  204. package/dist/editor/comments/CommentThreadsPopover.js +274 -0
  205. package/dist/editor/comments/CommentWriteAlert.d.ts +11 -0
  206. package/dist/editor/comments/CommentWriteAlert.js +13 -0
  207. package/dist/editor/comments/EntryComments.d.ts +10 -4
  208. package/dist/editor/comments/EntryComments.js +14 -17
  209. package/dist/editor/comments/FieldWrapper.d.ts +18 -4
  210. package/dist/editor/comments/FieldWrapper.js +62 -28
  211. package/dist/editor/comments/InlineCommentThread.d.ts +9 -2
  212. package/dist/editor/comments/InlineCommentThread.js +11 -47
  213. package/dist/editor/comments/ThreadCarousel.d.ts +1 -1
  214. package/dist/editor/comments/ThreadCarousel.js +18 -21
  215. package/dist/editor/comments/ThreadReplyControls.d.ts +28 -0
  216. package/dist/editor/comments/ThreadReplyControls.js +92 -0
  217. package/dist/editor/comments/field-comment-context.d.ts +14 -0
  218. package/dist/editor/comments/field-comment-context.js +14 -0
  219. package/dist/editor/comments/form-comments.d.ts +48 -0
  220. package/dist/editor/comments/form-comments.js +178 -0
  221. package/dist/editor/comments/item-anchor-copy.d.ts +6 -0
  222. package/dist/editor/comments/item-anchor-copy.js +6 -0
  223. package/dist/editor/comments/move-focus-if-unmoved.d.ts +6 -0
  224. package/dist/editor/comments/move-focus-if-unmoved.js +11 -0
  225. package/dist/editor/comments/popover-placement.d.ts +18 -0
  226. package/dist/editor/comments/popover-placement.js +58 -0
  227. package/dist/editor/comments/use-tracked-writes.d.ts +16 -0
  228. package/dist/editor/comments/use-tracked-writes.js +53 -0
  229. package/dist/editor/components/BranchAccessList.d.ts +15 -0
  230. package/dist/editor/components/BranchAccessList.js +52 -0
  231. package/dist/editor/components/BranchLockBanner.d.ts +22 -0
  232. package/dist/editor/components/BranchLockBanner.js +39 -0
  233. package/dist/editor/components/BranchPill.d.ts +32 -0
  234. package/dist/editor/components/BranchPill.js +33 -0
  235. package/dist/editor/components/BranchesDrawer.d.ts +11 -0
  236. package/dist/editor/components/BranchesDrawer.js +5 -0
  237. package/dist/editor/components/ConfirmDeleteModal.d.ts +6 -1
  238. package/dist/editor/components/ConfirmDeleteModal.js +3 -2
  239. package/dist/editor/components/DestructiveMenuItem.d.ts +7 -0
  240. package/dist/editor/components/DestructiveMenuItem.js +8 -0
  241. package/dist/editor/components/EditorCrashScreen.d.ts +17 -0
  242. package/dist/editor/components/EditorCrashScreen.js +22 -0
  243. package/dist/editor/components/EditorErrorBoundary.d.ts +38 -0
  244. package/dist/editor/components/EditorErrorBoundary.js +40 -0
  245. package/dist/editor/components/EditorHeader.d.ts +56 -106
  246. package/dist/editor/components/EditorHeader.js +130 -131
  247. package/dist/editor/components/EditorRail.d.ts +49 -0
  248. package/dist/editor/components/EditorRail.js +65 -0
  249. package/dist/editor/components/EntryBreadcrumb.d.ts +33 -0
  250. package/dist/editor/components/EntryBreadcrumb.js +56 -0
  251. package/dist/editor/components/EntryCreateModal.d.ts +12 -7
  252. package/dist/editor/components/EntryCreateModal.js +51 -57
  253. package/dist/editor/components/NoEditPermissionNotice.d.ts +6 -5
  254. package/dist/editor/components/NoEditPermissionNotice.js +5 -4
  255. package/dist/editor/components/QuickOpenPalette.d.ts +22 -0
  256. package/dist/editor/components/QuickOpenPalette.js +66 -0
  257. package/dist/editor/components/ReadOnlyDraftNotice.d.ts +11 -0
  258. package/dist/editor/components/ReadOnlyDraftNotice.js +12 -0
  259. package/dist/editor/components/ReasonedMenuItem.d.ts +15 -0
  260. package/dist/editor/components/ReasonedMenuItem.js +15 -0
  261. package/dist/editor/components/ReferencedByList.d.ts +11 -0
  262. package/dist/editor/components/ReferencedByList.js +28 -0
  263. package/dist/editor/components/RelativeTime.d.ts +10 -0
  264. package/dist/editor/components/RelativeTime.js +10 -0
  265. package/dist/editor/components/RenameEntryModal.d.ts +9 -1
  266. package/dist/editor/components/RenameEntryModal.js +19 -31
  267. package/dist/editor/components/RetryToastMessage.d.ts +9 -0
  268. package/dist/editor/components/RetryToastMessage.js +6 -0
  269. package/dist/editor/components/SaveAllResult.d.ts +25 -0
  270. package/dist/editor/components/SaveAllResult.js +86 -0
  271. package/dist/editor/components/SaveSplitButton.d.ts +30 -0
  272. package/dist/editor/components/SaveSplitButton.js +108 -0
  273. package/dist/editor/components/StagedChangesDrawer.d.ts +39 -0
  274. package/dist/editor/components/StagedChangesDrawer.js +92 -0
  275. package/dist/editor/components/UnavailableEntryNotice.d.ts +6 -0
  276. package/dist/editor/components/UnavailableEntryNotice.js +9 -0
  277. package/dist/editor/components/UnavailableTypeMessage.d.ts +6 -0
  278. package/dist/editor/components/UnavailableTypeMessage.js +9 -0
  279. package/dist/editor/components/UndoToastMessage.d.ts +18 -0
  280. package/dist/editor/components/UndoToastMessage.js +10 -0
  281. package/dist/editor/components/UserBadge.d.ts +2 -5
  282. package/dist/editor/components/UserBadge.js +62 -33
  283. package/dist/editor/components/ValidationSummary.d.ts +14 -0
  284. package/dist/editor/components/ValidationSummary.js +24 -0
  285. package/dist/editor/components/index.d.ts +2 -2
  286. package/dist/editor/components/index.js +2 -2
  287. package/dist/editor/context/ApiClientContext.d.ts +8 -2
  288. package/dist/editor/context/ApiClientContext.js +19 -8
  289. package/dist/editor/context/AssetContext.d.ts +13 -35
  290. package/dist/editor/context/AssetContext.js +12 -31
  291. package/dist/editor/context/EditorStateContext.d.ts +4 -4
  292. package/dist/editor/context/EditorStateContext.js +4 -4
  293. package/dist/editor/context/SWRProvider.d.ts +3 -3
  294. package/dist/editor/context/SiteMdxAllowContext.d.ts +4 -0
  295. package/dist/editor/context/SiteMdxAllowContext.js +7 -0
  296. package/dist/editor/context/index.d.ts +2 -1
  297. package/dist/editor/context/index.js +2 -1
  298. package/dist/editor/contrast.d.ts +19 -0
  299. package/dist/editor/contrast.js +41 -0
  300. package/dist/editor/copy.d.ts +18 -0
  301. package/dist/editor/copy.js +18 -0
  302. package/dist/editor/editor-config.js +16 -0
  303. package/dist/editor/editor-utils.d.ts +34 -8
  304. package/dist/editor/editor-utils.js +42 -20
  305. package/dist/editor/entry-search.d.ts +20 -0
  306. package/dist/editor/entry-search.js +34 -0
  307. package/dist/editor/field-breadcrumb.d.ts +12 -0
  308. package/dist/editor/field-breadcrumb.js +85 -0
  309. package/dist/editor/field-props.d.ts +86 -0
  310. package/dist/editor/field-props.js +27 -0
  311. package/dist/editor/field-target.d.ts +30 -0
  312. package/dist/editor/field-target.js +77 -0
  313. package/dist/editor/fields/BlockField.d.ts +12 -0
  314. package/dist/editor/fields/BlockField.js +89 -73
  315. package/dist/editor/fields/CodeField.d.ts +2 -0
  316. package/dist/editor/fields/CodeField.js +6 -2
  317. package/dist/editor/fields/DateTimeField.d.ts +4 -29
  318. package/dist/editor/fields/DateTimeField.js +79 -41
  319. package/dist/editor/fields/ExpandAllButton.d.ts +6 -0
  320. package/dist/editor/fields/ExpandAllButton.js +4 -0
  321. package/dist/editor/fields/FieldCrashFallback.d.ts +17 -0
  322. package/dist/editor/fields/FieldCrashFallback.js +30 -0
  323. package/dist/editor/fields/FieldLabel.d.ts +37 -0
  324. package/dist/editor/fields/FieldLabel.js +19 -0
  325. package/dist/editor/fields/ImageField.d.ts +4 -0
  326. package/dist/editor/fields/ImageField.js +29 -14
  327. package/dist/editor/fields/InlineGroupField.js +4 -3
  328. package/dist/editor/fields/ItemList.d.ts +42 -0
  329. package/dist/editor/fields/ItemList.js +130 -0
  330. package/dist/editor/fields/MarkdownField.d.ts +32 -0
  331. package/dist/editor/fields/MarkdownField.js +223 -46
  332. package/dist/editor/fields/MdxImageDialog.js +1 -1
  333. package/dist/editor/fields/NumberField.d.ts +2 -0
  334. package/dist/editor/fields/NumberField.js +8 -5
  335. package/dist/editor/fields/NumberListField.d.ts +2 -0
  336. package/dist/editor/fields/NumberListField.js +19 -16
  337. package/dist/editor/fields/ObjectField.d.ts +2 -7
  338. package/dist/editor/fields/ObjectField.js +15 -5
  339. package/dist/editor/fields/ObjectListField.d.ts +29 -0
  340. package/dist/editor/fields/ObjectListField.js +57 -0
  341. package/dist/editor/fields/ReferenceField.d.ts +2 -0
  342. package/dist/editor/fields/ReferenceField.js +34 -9
  343. package/dist/editor/fields/SelectField.d.ts +2 -0
  344. package/dist/editor/fields/SelectField.js +11 -2
  345. package/dist/editor/fields/StringListField.d.ts +4 -1
  346. package/dist/editor/fields/StringListField.js +22 -8
  347. package/dist/editor/fields/TextField.d.ts +2 -0
  348. package/dist/editor/fields/TextField.js +6 -2
  349. package/dist/editor/fields/ToggleField.d.ts +2 -0
  350. package/dist/editor/fields/ToggleField.js +8 -3
  351. package/dist/editor/fields/entry-link/InsertEntryLink.d.ts +1 -1
  352. package/dist/editor/fields/entry-link/InsertEntryLink.js +1 -1
  353. package/dist/editor/fields/form-expansion.d.ts +9 -0
  354. package/dist/editor/fields/form-expansion.js +2 -0
  355. package/dist/editor/fields/item-expansion.d.ts +15 -0
  356. package/dist/editor/fields/item-expansion.js +60 -0
  357. package/dist/editor/fields/list-item-keys.d.ts +8 -0
  358. package/dist/editor/fields/list-item-keys.js +50 -0
  359. package/dist/editor/fields/list-item-title.d.ts +20 -0
  360. package/dist/editor/fields/list-item-title.js +85 -0
  361. package/dist/editor/fields/markdown-export-options.d.ts +2 -0
  362. package/dist/editor/fields/markdown-export-options.js +8 -0
  363. package/dist/editor/fields/markdown-fidelity-visitors.d.ts +11 -0
  364. package/dist/editor/fields/markdown-fidelity-visitors.js +160 -0
  365. package/dist/editor/fields/mdx-jsx-support.d.ts +5 -1
  366. package/dist/editor/fields/mdx-jsx-support.js +157 -69
  367. package/dist/editor/fields/rich-text-failures.d.ts +5 -0
  368. package/dist/editor/fields/rich-text-failures.js +26 -0
  369. package/dist/editor/fields/toolbar-wrap.d.ts +7 -0
  370. package/dist/editor/fields/toolbar-wrap.js +35 -0
  371. package/dist/editor/form-outline.d.ts +13 -0
  372. package/dist/editor/form-outline.js +70 -0
  373. package/dist/editor/group-manager/GroupCard.d.ts +4 -1
  374. package/dist/editor/group-manager/GroupCard.js +12 -3
  375. package/dist/editor/group-manager/GroupForm.js +1 -1
  376. package/dist/editor/group-manager/InternalGroupsTab.d.ts +2 -1
  377. package/dist/editor/group-manager/InternalGroupsTab.js +4 -4
  378. package/dist/editor/group-manager/MemberList.d.ts +2 -1
  379. package/dist/editor/group-manager/MemberList.js +15 -4
  380. package/dist/editor/group-manager/hooks/useGroupState.d.ts +5 -0
  381. package/dist/editor/group-manager/hooks/useGroupState.js +30 -7
  382. package/dist/editor/group-manager/index.js +34 -5
  383. package/dist/editor/group-manager/types.d.ts +5 -2
  384. package/dist/editor/hooks/create-branch-request.d.ts +20 -0
  385. package/dist/editor/hooks/create-branch-request.js +54 -0
  386. package/dist/editor/hooks/save-all.d.ts +68 -0
  387. package/dist/editor/hooks/save-all.js +61 -0
  388. package/dist/editor/hooks/useBranchActions.d.ts +11 -1
  389. package/dist/editor/hooks/useBranchActions.js +42 -19
  390. package/dist/editor/hooks/useBranchManager.d.ts +21 -0
  391. package/dist/editor/hooks/useBranchManager.js +321 -125
  392. package/dist/editor/hooks/useBranchesData.d.ts +8 -4
  393. package/dist/editor/hooks/useBranchesData.js +9 -5
  394. package/dist/editor/hooks/useCommentSystem.d.ts +14 -2
  395. package/dist/editor/hooks/useCommentSystem.js +79 -55
  396. package/dist/editor/hooks/useCommentsData.d.ts +11 -7
  397. package/dist/editor/hooks/useCommentsData.js +20 -19
  398. package/dist/editor/hooks/useDraftManager.d.ts +77 -3
  399. package/dist/editor/hooks/useDraftManager.js +887 -94
  400. package/dist/editor/hooks/useEditorLayout.d.ts +53 -7
  401. package/dist/editor/hooks/useEditorLayout.js +98 -20
  402. package/dist/editor/hooks/useEntriesData.d.ts +2 -1
  403. package/dist/editor/hooks/useEntriesData.js +18 -4
  404. package/dist/editor/hooks/useEntryManager.d.ts +41 -2
  405. package/dist/editor/hooks/useEntryManager.js +227 -41
  406. package/dist/editor/hooks/useGroupManager.js +13 -16
  407. package/dist/editor/hooks/usePermissionManager.js +14 -6
  408. package/dist/editor/hooks/usePreviewMarks.d.ts +21 -0
  409. package/dist/editor/hooks/usePreviewMarks.js +33 -0
  410. package/dist/editor/hooks/useReferenceResolution.d.ts +10 -3
  411. package/dist/editor/hooks/useReferenceResolution.js +34 -177
  412. package/dist/editor/hooks/useSchemaManager.d.ts +25 -6
  413. package/dist/editor/hooks/useSchemaManager.js +97 -39
  414. package/dist/editor/hooks/useUserMetadata.d.ts +14 -4
  415. package/dist/editor/hooks/useUserMetadata.js +76 -47
  416. package/dist/editor/hooks/user-metadata-batcher.d.ts +8 -0
  417. package/dist/editor/hooks/user-metadata-batcher.js +33 -0
  418. package/dist/editor/media/AssetCard.d.ts +6 -7
  419. package/dist/editor/media/AssetCard.js +24 -31
  420. package/dist/editor/media/AssetListRow.d.ts +16 -0
  421. package/dist/editor/media/AssetListRow.js +41 -0
  422. package/dist/editor/media/CropStep.js +6 -1
  423. package/dist/editor/media/MediaLibrary.d.ts +4 -3
  424. package/dist/editor/media/MediaLibrary.js +11 -4
  425. package/dist/editor/media/MediaLibraryBody.d.ts +3 -3
  426. package/dist/editor/media/MediaLibraryBody.js +195 -80
  427. package/dist/editor/media/MediaLibrarySkeleton.d.ts +6 -0
  428. package/dist/editor/media/MediaLibrarySkeleton.js +14 -0
  429. package/dist/editor/media/crop-math.d.ts +3 -4
  430. package/dist/editor/media/crop-math.js +11 -22
  431. package/dist/editor/media/editor-image-src.d.ts +8 -0
  432. package/dist/editor/media/editor-image-src.js +10 -0
  433. package/dist/editor/media/format-bytes.d.ts +2 -0
  434. package/dist/editor/media/format-bytes.js +23 -0
  435. package/dist/editor/media/media-library-prefs.d.ts +23 -0
  436. package/dist/editor/media/media-library-prefs.js +49 -0
  437. package/dist/editor/media/media-library-view.d.ts +34 -0
  438. package/dist/editor/media/media-library-view.js +40 -0
  439. package/dist/editor/media/useAssetLibrary.d.ts +30 -0
  440. package/dist/editor/media/useAssetLibrary.js +126 -0
  441. package/dist/editor/media/useStableAssetOrder.d.ts +11 -0
  442. package/dist/editor/media/useStableAssetOrder.js +37 -0
  443. package/dist/editor/media/useThumbnailFailure.d.ts +6 -0
  444. package/dist/editor/media/useThumbnailFailure.js +16 -0
  445. package/dist/editor/permission-manager/GroupSelector.js +2 -2
  446. package/dist/editor/permission-manager/PermissionEditor.d.ts +1 -1
  447. package/dist/editor/permission-manager/PermissionEditor.js +15 -4
  448. package/dist/editor/permission-manager/PermissionLevelBadge.js +1 -1
  449. package/dist/editor/permission-manager/PermissionTree.d.ts +1 -1
  450. package/dist/editor/permission-manager/UserSelector.d.ts +1 -1
  451. package/dist/editor/permission-manager/UserSelector.js +3 -3
  452. package/dist/editor/permission-manager/index.js +12 -3
  453. package/dist/editor/permission-manager/types.d.ts +5 -2
  454. package/dist/editor/platform.d.ts +3 -0
  455. package/dist/editor/platform.js +9 -0
  456. package/dist/editor/preview-asset-base.d.ts +9 -0
  457. package/dist/editor/preview-asset-base.js +17 -0
  458. package/dist/editor/preview-bridge.d.ts +51 -27
  459. package/dist/editor/preview-bridge.js +103 -144
  460. package/dist/editor/preview-marks.d.ts +15 -0
  461. package/dist/editor/preview-marks.js +74 -0
  462. package/dist/editor/preview-path.d.ts +12 -0
  463. package/dist/editor/preview-path.js +45 -1
  464. package/dist/editor/preview-scale.d.ts +27 -0
  465. package/dist/editor/preview-scale.js +34 -0
  466. package/dist/editor/raw-asset-base.d.ts +5 -0
  467. package/dist/editor/raw-asset-base.js +14 -0
  468. package/dist/editor/relative-time.d.ts +4 -4
  469. package/dist/editor/relative-time.js +16 -8
  470. package/dist/editor/schema-editor/CollectionEditor.d.ts +20 -3
  471. package/dist/editor/schema-editor/CollectionEditor.js +361 -62
  472. package/dist/editor/schema-editor/EntryTypeEditor.d.ts +5 -1
  473. package/dist/editor/schema-editor/EntryTypeEditor.js +11 -6
  474. package/dist/editor/schema-editor/collection-draft.d.ts +22 -0
  475. package/dist/editor/schema-editor/collection-draft.js +40 -0
  476. package/dist/editor/schema-editor/index.d.ts +1 -1
  477. package/dist/editor/schema-label.d.ts +10 -0
  478. package/dist/editor/schema-label.js +17 -0
  479. package/dist/editor/settings-conflict.d.ts +5 -0
  480. package/dist/editor/settings-conflict.js +8 -0
  481. package/dist/editor/shell/ActivityRail.d.ts +37 -0
  482. package/dist/editor/shell/ActivityRail.js +91 -0
  483. package/dist/editor/shell/EditorShell.d.ts +17 -0
  484. package/dist/editor/shell/EditorShell.js +31 -0
  485. package/dist/editor/shell/PaneLayout.d.ts +28 -0
  486. package/dist/editor/shell/PaneLayout.js +116 -0
  487. package/dist/editor/shell/SidePanelHost.d.ts +35 -0
  488. package/dist/editor/shell/SidePanelHost.js +184 -0
  489. package/dist/editor/shell/TopBar.d.ts +12 -0
  490. package/dist/editor/shell/TopBar.js +14 -0
  491. package/dist/editor/shell/host-chrome.d.ts +16 -0
  492. package/dist/editor/shell/host-chrome.js +69 -0
  493. package/dist/editor/slug.d.ts +16 -0
  494. package/dist/editor/slug.js +43 -0
  495. package/dist/editor/theme.d.ts +2 -1
  496. package/dist/editor/theme.js +314 -13
  497. package/dist/editor/unanswered.d.ts +17 -0
  498. package/dist/editor/unanswered.js +26 -0
  499. package/dist/editor/unavailable-entry-type.d.ts +20 -0
  500. package/dist/editor/unavailable-entry-type.js +28 -0
  501. package/dist/editor/undo-removal.d.ts +57 -0
  502. package/dist/editor/undo-removal.js +163 -0
  503. package/dist/editor/user-display.d.ts +4 -0
  504. package/dist/editor/user-display.js +5 -0
  505. package/dist/editor/utils/confirm-modal.d.ts +8 -0
  506. package/dist/editor/utils/confirm-modal.js +12 -0
  507. package/dist/editor/utils/editor-errors.d.ts +19 -0
  508. package/dist/editor/utils/editor-errors.js +32 -0
  509. package/dist/editor/utils/focus-return.d.ts +56 -0
  510. package/dist/editor/utils/focus-return.js +106 -0
  511. package/dist/entry-link-resolver.d.ts +11 -1
  512. package/dist/entry-link-resolver.js +65 -5
  513. package/dist/entry-schema-registry.d.ts +3 -3
  514. package/dist/entry-schema-registry.js +7 -4
  515. package/dist/entry-schema.d.ts +49 -3
  516. package/dist/entry-schema.js +18 -0
  517. package/dist/git-manager.d.ts +172 -10
  518. package/dist/git-manager.js +449 -107
  519. package/dist/github-service.d.ts +39 -2
  520. package/dist/github-service.js +101 -7
  521. package/dist/http/handler.js +74 -9
  522. package/dist/http/types.d.ts +2 -0
  523. package/dist/http/worker-not-ready.d.ts +9 -4
  524. package/dist/http/worker-not-ready.js +59 -6
  525. package/dist/index.d.ts +2 -0
  526. package/dist/index.js +3 -0
  527. package/dist/item-keys.d.ts +46 -0
  528. package/dist/item-keys.js +235 -0
  529. package/dist/operating-mode/editor-mode-check.d.ts +15 -0
  530. package/dist/operating-mode/editor-mode-check.js +24 -0
  531. package/dist/operating-mode/mode-env.d.ts +13 -14
  532. package/dist/operating-mode/mode-env.js +13 -14
  533. package/dist/operating-mode/types.d.ts +2 -2
  534. package/dist/paths/branch.d.ts +0 -1
  535. package/dist/paths/branch.js +1 -8
  536. package/dist/paths/index.d.ts +1 -1
  537. package/dist/paths/index.js +1 -1
  538. package/dist/paths/validation.js +0 -2
  539. package/dist/preview.d.ts +8 -0
  540. package/dist/preview.js +7 -0
  541. package/dist/reference-resolver.js +1 -0
  542. package/dist/resolve-canopy-user.d.ts +1 -1
  543. package/dist/resolve-canopy-user.js +1 -1
  544. package/dist/schema/meta-loader.d.ts +18 -8
  545. package/dist/schema/meta-loader.js +42 -9
  546. package/dist/schema/registry-fingerprint.d.ts +14 -0
  547. package/dist/schema/registry-fingerprint.js +63 -0
  548. package/dist/schema/resolver.d.ts +7 -4
  549. package/dist/schema/resolver.js +7 -6
  550. package/dist/schema/schema-store.d.ts +7 -10
  551. package/dist/schema/schema-store.js +13 -11
  552. package/dist/schema/schema-unavailable-error.d.ts +11 -0
  553. package/dist/schema/schema-unavailable-error.js +15 -0
  554. package/dist/schema/types.d.ts +22 -0
  555. package/dist/schema-registry-record.d.ts +35 -0
  556. package/dist/schema-registry-record.js +134 -0
  557. package/dist/server.d.ts +79 -9
  558. package/dist/server.js +62 -8
  559. package/dist/services.d.ts +33 -5
  560. package/dist/services.js +155 -37
  561. package/dist/settings-workspace.d.ts +23 -3
  562. package/dist/settings-workspace.js +159 -45
  563. package/dist/stamp-on-publish.d.ts +36 -0
  564. package/dist/stamp-on-publish.js +71 -0
  565. package/dist/static/index.d.ts +58 -5
  566. package/dist/static/index.js +133 -3
  567. package/dist/static/seo.d.ts +5 -5
  568. package/dist/static/seo.js +5 -5
  569. package/dist/submission-attribution.d.ts +8 -0
  570. package/dist/submission-attribution.js +22 -0
  571. package/dist/system-users.d.ts +12 -0
  572. package/dist/system-users.js +12 -0
  573. package/dist/task-queue/cms-task-queue.d.ts +1 -1
  574. package/dist/task-queue/cms-task-queue.js +1 -1
  575. package/dist/task-queue/index.d.ts +1 -1
  576. package/dist/task-queue/index.js +1 -1
  577. package/dist/task-queue/task-queue.d.ts +6 -0
  578. package/dist/task-queue/task-queue.js +29 -0
  579. package/dist/task-queue/worker-status.d.ts +35 -9
  580. package/dist/task-queue/worker-status.js +84 -17
  581. package/dist/types.d.ts +90 -9
  582. package/dist/url-collision.js +3 -3
  583. package/dist/url-exclusivity-fixtures.d.ts +8 -1
  584. package/dist/url-exclusivity-fixtures.js +11 -1
  585. package/dist/user.js +2 -1
  586. package/dist/utils/atomic-write.js +2 -1
  587. package/dist/utils/base-branch.d.ts +13 -0
  588. package/dist/utils/base-branch.js +23 -0
  589. package/dist/utils/content-serialize.d.ts +15 -7
  590. package/dist/utils/content-serialize.js +353 -51
  591. package/dist/utils/content-write-lock.d.ts +6 -1
  592. package/dist/utils/content-write-lock.js +21 -6
  593. package/dist/utils/debug.d.ts +1 -1
  594. package/dist/utils/debug.js +5 -3
  595. package/dist/utils/error.js +13 -2
  596. package/dist/utils/escape-text.d.ts +7 -0
  597. package/dist/utils/escape-text.js +27 -0
  598. package/dist/utils/fs.d.ts +12 -4
  599. package/dist/utils/fs.js +18 -5
  600. package/dist/utils/git.d.ts +21 -1
  601. package/dist/utils/git.js +63 -8
  602. package/dist/utils/json-source-splice.d.ts +14 -0
  603. package/dist/utils/json-source-splice.js +120 -0
  604. package/dist/utils/markdown-body-splice.d.ts +39 -0
  605. package/dist/utils/markdown-body-splice.js +421 -0
  606. package/dist/utils/occ-json-write.js +18 -12
  607. package/dist/utils/provision-log.d.ts +25 -0
  608. package/dist/utils/provision-log.js +49 -0
  609. package/dist/utils/provisioning-lock.d.ts +32 -1
  610. package/dist/utils/provisioning-lock.js +78 -32
  611. package/dist/utils/sanitize-href.d.ts +9 -23
  612. package/dist/utils/sanitize-href.js +14 -28
  613. package/dist/utils/title-field.d.ts +10 -0
  614. package/dist/utils/title-field.js +47 -0
  615. package/dist/utils/yaml-source-splice.d.ts +58 -0
  616. package/dist/utils/yaml-source-splice.js +515 -0
  617. package/dist/validation/block-structural-keys.d.ts +1 -1
  618. package/dist/validation/block-structural-keys.js +1 -1
  619. package/dist/validation/deletion-checker.d.ts +21 -29
  620. package/dist/validation/deletion-checker.js +41 -117
  621. package/dist/validation/entry-validator.d.ts +6 -10
  622. package/dist/validation/entry-validator.js +19 -26
  623. package/dist/validation/field-traversal.d.ts +22 -0
  624. package/dist/validation/field-traversal.js +39 -8
  625. package/dist/validation/markdown-safety.d.ts +68 -0
  626. package/dist/validation/markdown-safety.js +596 -0
  627. package/dist/validation/mdx-allowlist.d.ts +55 -0
  628. package/dist/validation/mdx-allowlist.js +183 -0
  629. package/dist/validation/reference-validator.d.ts +2 -0
  630. package/dist/validation/reference-validator.js +3 -0
  631. package/dist/version.d.ts +1 -1
  632. package/dist/version.js +1 -1
  633. package/dist/worker/branch-policy.d.ts +124 -0
  634. package/dist/worker/branch-policy.js +243 -0
  635. package/dist/worker/bundle-header.d.ts +117 -0
  636. package/dist/worker/bundle-header.js +253 -0
  637. package/dist/worker/cms-worker.d.ts +236 -142
  638. package/dist/worker/cms-worker.js +772 -285
  639. package/dist/worker/gateway-egress.d.ts +43 -0
  640. package/dist/worker/gateway-egress.js +209 -0
  641. package/dist/worker/gateway-instance.d.ts +42 -0
  642. package/dist/worker/gateway-instance.js +129 -0
  643. package/dist/worker/git-process.d.ts +81 -0
  644. package/dist/worker/git-process.js +234 -0
  645. package/dist/worker/git-sync.d.ts +34 -17
  646. package/dist/worker/git-sync.js +394 -131
  647. package/dist/worker/github-auth.d.ts +9 -9
  648. package/dist/worker/github-auth.js +13 -15
  649. package/dist/worker/github-gateway-http.d.ts +62 -0
  650. package/dist/worker/github-gateway-http.js +977 -0
  651. package/dist/worker/github-gateway-wire.d.ts +590 -0
  652. package/dist/worker/github-gateway-wire.js +488 -0
  653. package/dist/worker/github-gateway.d.ts +238 -0
  654. package/dist/worker/github-gateway.js +726 -0
  655. package/dist/worker/github-mirror-upkeep.d.ts +75 -0
  656. package/dist/worker/github-mirror-upkeep.js +266 -0
  657. package/dist/worker/github-mirror.d.ts +364 -0
  658. package/dist/worker/github-mirror.js +1030 -0
  659. package/dist/worker/github-transfer.d.ts +56 -0
  660. package/dist/worker/github-transfer.js +444 -0
  661. package/dist/worker/history-rewrite.d.ts +4 -5
  662. package/dist/worker/history-rewrite.js +12 -17
  663. package/dist/worker/provisioned-workspace.d.ts +5 -5
  664. package/dist/worker/provisioned-workspace.js +5 -5
  665. package/dist/worker/rebase.d.ts +1 -1
  666. package/dist/worker/rebase.js +58 -54
  667. package/dist/worker/remote-git-maintenance.d.ts +3 -0
  668. package/dist/worker/remote-git-maintenance.js +12 -0
  669. package/dist/worker/schema-gate.d.ts +49 -0
  670. package/dist/worker/schema-gate.js +226 -0
  671. package/dist/worker/self-checks.d.ts +107 -0
  672. package/dist/worker/self-checks.js +358 -0
  673. package/dist/worker/shared-repo-git.d.ts +96 -0
  674. package/dist/worker/shared-repo-git.js +459 -0
  675. package/dist/worker/sparse-cone.d.ts +20 -0
  676. package/dist/worker/sparse-cone.js +136 -0
  677. package/dist/worker/stale-mirror.d.ts +82 -0
  678. package/dist/worker/stale-mirror.js +130 -0
  679. package/dist/worker/task-runner.d.ts +5 -3
  680. package/dist/worker/task-runner.js +287 -186
  681. package/dist/worker/worker-context.d.ts +36 -37
  682. package/package.json +35 -7
  683. package/dist/editor/EditorPanes.d.ts +0 -10
  684. package/dist/editor/EditorPanes.js +0 -98
  685. package/dist/editor/components/EditorFooter.d.ts +0 -11
  686. package/dist/editor/components/EditorFooter.js +0 -9
  687. package/dist/editor/components/EditorSidebar.d.ts +0 -67
  688. package/dist/editor/components/EditorSidebar.js +0 -22
@@ -1,10 +1,127 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { useMemo, useRef, useEffect } from 'react';
4
- import { ActionIcon, Badge, Box, Group, Loader, Menu, ScrollArea, Stack, Text, Tooltip, Tree, useTree, rem, } from '@mantine/core';
5
- import { IconArrowDown, IconArrowUp, IconDots, IconEdit, IconFolderPlus, IconPlus, IconTrash, } from '@tabler/icons-react';
3
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
4
+ import { ActionIcon, Badge, Box, Button, CloseButton, Group, Highlight, Loader, Menu, ScrollArea, Stack, Text, TextInput, Tooltip, Tree, useTree, rem, } from '@mantine/core';
5
+ import { IconArrowDown, IconAlertTriangle, IconArrowUp, IconDots, IconEdit, IconFolderPlus, IconLock, IconPlus, IconSearch, IconTrash, } from '@tabler/icons-react';
6
6
  import { calculatePathToEntry } from './editor-utils.js';
7
- export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onTreeControllerReady, expandedStateRef, onExpandedStateChange, onDeleteEntry: onDeleteEntryProp, onRenameEntry: onRenameEntryProp, onReorderEntry: onReorderEntryProp, hiddenRootPath, loading, readOnly = false, }) => {
7
+ import { matchesEntryQuery } from './entry-search.js';
8
+ import { DestructiveMenuItem } from './components/DestructiveMenuItem.js';
9
+ import { ReasonedMenuItem } from './components/ReasonedMenuItem.js';
10
+ import { UnavailableTypeMessage } from './components/UnavailableTypeMessage.js';
11
+ const UnavailableTypeRow = ({ schemaRefs }) => (_jsxs(Group, { gap: 6, wrap: "nowrap", align: "flex-start", mt: 4, "data-testid": "unavailable-type-message", children: [_jsx(Box, { c: "orange", style: { display: 'flex', flexShrink: 0, paddingTop: 2 }, children: _jsx(IconAlertTriangle, { size: 14, "aria-hidden": true }) }), _jsx(Text, { size: "xs", c: "orange", children: _jsx(UnavailableTypeMessage, { schemaRefs: schemaRefs }) })] }));
12
+ /** Where path rules refuse new entries, one line says so in place of the "…" menus they hide. */
13
+ const AddRefusedRow = () => (_jsx(Text, { size: "xs", c: "dimmed", mt: 4, "data-testid": "add-refused-message", children: "You can't add entries here." }));
14
+ const lastSegment = (path) => path.split('/').filter(Boolean).pop() ?? path;
15
+ /** A collection's node value; a single-entry collection's node is its entry. */
16
+ const collectionNodeValue = (nodes, path) => {
17
+ for (const node of nodes) {
18
+ if (node.value === `collection:${path}` || node.nodeProps?.collectionPath === path) {
19
+ return node.value;
20
+ }
21
+ const inner = node.children && collectionNodeValue(node.children, path);
22
+ if (inner)
23
+ return inner;
24
+ }
25
+ return undefined;
26
+ };
27
+ /** The collection values below `nodes` that have children, as an all-expanded state. */
28
+ const expandedStateFor = (nodes, acc = {}) => {
29
+ for (const node of nodes) {
30
+ if (node.children?.length) {
31
+ acc[node.value] = true;
32
+ expandedStateFor(node.children, acc);
33
+ }
34
+ }
35
+ return acc;
36
+ };
37
+ /**
38
+ * The nodes of `nodes` that match `query`. An entry matches on label or slug; a collection whose
39
+ * label matches keeps its whole subtree, and any other collection survives only with its matching
40
+ * descendants. Nodes keep the position data (`childIndex`, `totalChildrenCount`) of the full tree.
41
+ */
42
+ const filterTree = (nodes, query) => {
43
+ const kept = [];
44
+ for (const node of nodes) {
45
+ const label = String(node.label ?? '');
46
+ if (node.nodeProps?.isEntry) {
47
+ if (matchesEntryQuery({ label, slug: node.nodeProps.slug }, query)) {
48
+ kept.push(node);
49
+ }
50
+ }
51
+ else if (matchesEntryQuery({ label }, query)) {
52
+ kept.push(node);
53
+ }
54
+ else {
55
+ const children = filterTree(node.children ?? [], query);
56
+ if (children.length > 0)
57
+ kept.push({ ...node, children });
58
+ }
59
+ }
60
+ return kept;
61
+ };
62
+ /** The first entry in tree order that matches `query`, else the first entry of any kind. */
63
+ const firstEntryPath = (nodes, query) => {
64
+ const entries = [];
65
+ const walk = (list) => {
66
+ for (const node of list) {
67
+ if (node.nodeProps?.isEntry)
68
+ entries.push(node);
69
+ else
70
+ walk(node.children ?? []);
71
+ }
72
+ };
73
+ walk(nodes);
74
+ const match = entries.find((node) => matchesEntryQuery({ label: String(node.label ?? ''), slug: node.nodeProps?.slug }, query));
75
+ return (match ?? entries[0])?.value;
76
+ };
77
+ /**
78
+ * A row's title, truncated with an ellipsis. Its full text shows in a tooltip, and only while the
79
+ * text is cut: the width is measured when the pointer or focus enters the row, not on every render.
80
+ */
81
+ const TruncatedLabel = ({ label, highlight, fw, }) => {
82
+ const elementRef = useRef(null);
83
+ const [truncated, setTruncated] = useState(false);
84
+ const setElement = useCallback((node) => {
85
+ elementRef.current = node;
86
+ }, []);
87
+ useEffect(() => {
88
+ const row = elementRef.current?.closest('[data-nav-row]');
89
+ if (!row)
90
+ return;
91
+ // Read at measure time: the label swaps between Text and Highlight as a filter starts and stops.
92
+ const measure = () => {
93
+ const element = elementRef.current;
94
+ setTruncated(!!element && element.scrollWidth > element.clientWidth);
95
+ };
96
+ row.addEventListener('mouseenter', measure);
97
+ row.addEventListener('focusin', measure);
98
+ return () => {
99
+ row.removeEventListener('mouseenter', measure);
100
+ row.removeEventListener('focusin', measure);
101
+ };
102
+ }, []);
103
+ return (_jsx(Tooltip, { label: label, openDelay: 400, withinPortal: true, disabled: !truncated, children: highlight ? (_jsx(Highlight, { ref: setElement, highlight: highlight, size: "sm", fw: fw, truncate: "end", style: { minWidth: 0 }, children: label })) : (_jsx(Text, { ref: setElement, size: "sm", fw: fw, truncate: "end", style: { minWidth: 0 }, children: label })) }));
104
+ };
105
+ /** The keys Mantine's tree acts on, matched as it matches them, by `code`. */
106
+ const TREE_KEYS = new Set(['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight', 'Space']);
107
+ /**
108
+ * A row menu's dropdown is portaled, but React still bubbles its key events to the row, where the
109
+ * tree's arrow keys would take focus out of the open menu. Only those keys stop: React's
110
+ * stopPropagation stops the native event too, and every other key must still reach the document,
111
+ * where the Mod+P shortcut and the focus traps' Tab handling listen.
112
+ */
113
+ const stopTreeKeys = (event) => {
114
+ if (TREE_KEYS.has(event.nativeEvent.code))
115
+ event.stopPropagation();
116
+ };
117
+ const UnsavedDot = ({ label }) => (_jsx(Tooltip, { label: label, withinPortal: true, children: _jsx(Box, { component: "span", role: "img", "aria-label": label, "data-testid": "unsaved-dot", style: {
118
+ flexShrink: 0,
119
+ width: 8,
120
+ height: 8,
121
+ borderRadius: '50%',
122
+ backgroundColor: 'var(--mantine-color-brand-6)',
123
+ } }) }));
124
+ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onTreeControllerReady, expandedStateRef, onExpandedStateChange, onDeleteEntry: onDeleteEntryProp, onRenameEntry: onRenameEntryProp, onReorderEntry: onReorderEntryProp, hiddenRootPath, loading, readOnly = false, dirtyPaths, revealCollection, onRevealed, }) => {
8
125
  // Shadow the entry-mutation callbacks with undefined when readOnly, so every
9
126
  // downstream reference (hasEntryMenu, canReorder, the menu items themselves)
10
127
  // sees them as absent rather than threading a readOnly check through each
@@ -16,7 +133,32 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
16
133
  const hasScrolledRef = useRef(false);
17
134
  // Track expanded state synchronously to avoid race conditions on unmount
18
135
  const localExpandedStateRef = useRef(expandedStateRef?.current ?? {});
136
+ const [query, setQuery] = useState('');
137
+ const filterInputRef = useRef(null);
138
+ const filtering = query.trim() !== '';
139
+ // Read from the tree's expand/collapse callbacks, which fire from state updaters.
140
+ const filteringRef = useRef(false);
141
+ useEffect(() => {
142
+ filteringRef.current = filtering;
143
+ }, [filtering]);
19
144
  const treeData = useMemo(() => {
145
+ const entryNode = (entry, parent, childIndex, totalChildren) => ({
146
+ value: entry.path,
147
+ label: entry.label,
148
+ nodeProps: {
149
+ status: entry.status,
150
+ isEntry: true,
151
+ entryPath: entry.path,
152
+ slug: entry.slug ?? lastSegment(entry.path),
153
+ contentId: entry.contentId,
154
+ conflictNotice: entry.conflictNotice,
155
+ unavailable: entry.unavailable,
156
+ itemReadOnly: entry.readOnly,
157
+ parentCollectionPath: parent.path,
158
+ childIndex,
159
+ totalChildrenCount: totalChildren,
160
+ },
161
+ });
20
162
  if (collections?.length) {
21
163
  const toTree = (col) => {
22
164
  if (col.type === 'entry') {
@@ -28,6 +170,9 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
28
170
  status: entry?.status,
29
171
  isEntry: true,
30
172
  entryPath: entry?.path,
173
+ collectionPath: col.path,
174
+ slug: entry ? (entry.slug ?? lastSegment(entry.path)) : undefined,
175
+ itemReadOnly: entry?.readOnly,
31
176
  },
32
177
  children: [],
33
178
  };
@@ -38,51 +183,39 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
38
183
  const order = col.order ?? [];
39
184
  const entryNodesByContentId = new Map();
40
185
  entries.forEach((entry) => {
41
- const node = {
42
- value: entry.path,
43
- label: entry.label,
44
- nodeProps: {
45
- status: entry.status,
46
- isEntry: true,
47
- entryPath: entry.path,
48
- contentId: entry.contentId,
49
- conflictNotice: entry.conflictNotice,
50
- parentCollectionPath: col.path,
51
- childIndex: 0, // Will be set below
52
- totalChildrenCount: totalChildren,
53
- },
54
- };
55
186
  if (entry.contentId) {
56
- entryNodesByContentId.set(entry.contentId, node);
187
+ entryNodesByContentId.set(entry.contentId, entryNode(entry, col, 0, totalChildren));
57
188
  }
58
189
  });
59
- const childNodesByContentId = new Map();
60
- childCollections.forEach((child) => {
190
+ const withPosition = (child, childIndex) => {
61
191
  const childTree = toTree(child);
62
- const node = {
192
+ return {
63
193
  ...childTree,
64
194
  nodeProps: {
65
195
  ...childTree.nodeProps,
66
196
  contentId: child.contentId,
67
197
  parentCollectionPath: col.path,
68
- childIndex: 0, // Will be set below
198
+ childIndex,
69
199
  totalChildrenCount: totalChildren,
70
200
  },
71
201
  };
202
+ };
203
+ const childNodesByContentId = new Map();
204
+ childCollections.forEach((child) => {
72
205
  if (child.contentId) {
73
- childNodesByContentId.set(child.contentId, node);
206
+ childNodesByContentId.set(child.contentId, withPosition(child, 0));
74
207
  }
75
208
  });
76
209
  const allChildren = [];
77
210
  const usedContentIds = new Set();
78
211
  for (const contentId of order) {
79
- const entryNode = entryNodesByContentId.get(contentId);
80
- if (entryNode) {
81
- entryNode.nodeProps = {
82
- ...entryNode.nodeProps,
212
+ const orderedEntry = entryNodesByContentId.get(contentId);
213
+ if (orderedEntry) {
214
+ orderedEntry.nodeProps = {
215
+ ...orderedEntry.nodeProps,
83
216
  childIndex: allChildren.length,
84
217
  };
85
- allChildren.push(entryNode);
218
+ allChildren.push(orderedEntry);
86
219
  usedContentIds.add(contentId);
87
220
  continue;
88
221
  }
@@ -100,38 +233,13 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
100
233
  .filter((e) => !e.contentId || !usedContentIds.has(e.contentId))
101
234
  .sort((a, b) => (a.label ?? '').localeCompare(b.label ?? ''));
102
235
  for (const entry of unorderedEntries) {
103
- const node = {
104
- value: entry.path,
105
- label: entry.label,
106
- nodeProps: {
107
- status: entry.status,
108
- isEntry: true,
109
- entryPath: entry.path,
110
- contentId: entry.contentId,
111
- conflictNotice: entry.conflictNotice,
112
- parentCollectionPath: col.path,
113
- childIndex: allChildren.length,
114
- totalChildrenCount: totalChildren,
115
- },
116
- };
117
- allChildren.push(node);
236
+ allChildren.push(entryNode(entry, col, allChildren.length, totalChildren));
118
237
  }
119
238
  const unorderedChildren = childCollections
120
239
  .filter((c) => !c.contentId || !usedContentIds.has(c.contentId))
121
240
  .sort((a, b) => (a.label ?? '').localeCompare(b.label ?? ''));
122
241
  for (const child of unorderedChildren) {
123
- const childTree = toTree(child);
124
- const node = {
125
- ...childTree,
126
- nodeProps: {
127
- ...childTree.nodeProps,
128
- contentId: child.contentId,
129
- parentCollectionPath: col.path,
130
- childIndex: allChildren.length,
131
- totalChildrenCount: totalChildren,
132
- },
133
- };
134
- allChildren.push(node);
242
+ allChildren.push(withPosition(child, allChildren.length));
135
243
  }
136
244
  // Collections should always have children array (even if empty) to show chevron
137
245
  // This matches standard file tree UI behavior where folders always show expand/collapse
@@ -143,6 +251,8 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
143
251
  type: col.type,
144
252
  collectionPath: col.path,
145
253
  conflictNotice: col.conflictNotice,
254
+ unavailableSchemaRefs: col.unavailableSchemaRefs,
255
+ addRefused: col.addRefused,
146
256
  onAdd: col.onAdd,
147
257
  onEdit: col.onEdit,
148
258
  onAddSubCollection: col.onAddSubCollection,
@@ -163,12 +273,56 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
163
273
  return flatItems.map((item) => ({
164
274
  value: item.path,
165
275
  label: item.label,
166
- nodeProps: { status: item.status, isEntry: true, entryPath: item.path },
276
+ nodeProps: {
277
+ status: item.status,
278
+ isEntry: true,
279
+ entryPath: item.path,
280
+ slug: item.slug ?? lastSegment(item.path),
281
+ itemReadOnly: item.readOnly,
282
+ },
167
283
  }));
168
284
  }, [collections, items, hiddenRootPath]);
285
+ // Filtered from the finished tree, so each node keeps its position in the whole collection and
286
+ // Move up / Move down stay correct while a filter is on.
287
+ const filteredTree = useMemo(() => (filtering ? filterTree(treeData, query) : treeData), [filtering, treeData, query]);
288
+ // Collections that hold an entry with unsaved changes, found over the whole tree so a filter
289
+ // never hides the reason for a dot.
290
+ const dirtyCollections = useMemo(() => {
291
+ const dirty = new Set();
292
+ if (!dirtyPaths?.size)
293
+ return dirty;
294
+ const walk = (nodes) => {
295
+ let any = false;
296
+ for (const node of nodes) {
297
+ if (node.nodeProps?.isEntry) {
298
+ if (dirtyPaths.has(node.value))
299
+ any = true;
300
+ }
301
+ else if (walk(node.children ?? [])) {
302
+ dirty.add(node.value);
303
+ any = true;
304
+ }
305
+ }
306
+ return any;
307
+ };
308
+ walk(treeData);
309
+ return dirty;
310
+ }, [treeData, dirtyPaths]);
311
+ // The hidden root's own row never renders, so its message is shown once above the tree.
312
+ const hiddenRootAddRefused = !readOnly &&
313
+ !!hiddenRootPath &&
314
+ collections?.length === 1 &&
315
+ collections[0].path === hiddenRootPath &&
316
+ !!collections[0].addRefused;
317
+ const hiddenRootUnavailableRefs = hiddenRootPath && collections?.length === 1 && collections[0].path === hiddenRootPath
318
+ ? collections[0].unavailableSchemaRefs
319
+ : undefined;
169
320
  const tree = useTree({
170
321
  initialExpandedState: expandedStateRef?.current ?? {},
322
+ // A filter expands and collapses nodes only for as long as it is on, so none of it is saved.
171
323
  onNodeExpand: (value) => {
324
+ if (filteringRef.current)
325
+ return;
172
326
  localExpandedStateRef.current = {
173
327
  ...localExpandedStateRef.current,
174
328
  [value]: true,
@@ -176,6 +330,8 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
176
330
  onExpandedStateChange?.(localExpandedStateRef.current);
177
331
  },
178
332
  onNodeCollapse: (value) => {
333
+ if (filteringRef.current)
334
+ return;
179
335
  localExpandedStateRef.current = {
180
336
  ...localExpandedStateRef.current,
181
337
  [value]: false,
@@ -194,8 +350,26 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
194
350
  };
195
351
  // eslint-disable-next-line react-hooks/exhaustive-deps
196
352
  }, []);
353
+ // The expanded state from before the filter started, put back exactly when it clears. The tree
354
+ // drops the state of nodes it no longer renders, so it cannot be recovered from the tree itself.
355
+ const expandedBeforeFilterRef = useRef(null);
197
356
  useEffect(() => {
198
- if (!selectedPath || !treeData)
357
+ if (filtering) {
358
+ expandedBeforeFilterRef.current ??= tree.expandedState;
359
+ tree.setExpandedState(expandedStateFor(filteredTree));
360
+ }
361
+ else if (expandedBeforeFilterRef.current) {
362
+ // Plus the ancestors of an entry picked while filtering, so it stays in view.
363
+ tree.setExpandedState({
364
+ ...expandedBeforeFilterRef.current,
365
+ ...calculatePathToEntry(selectedPath, treeData),
366
+ });
367
+ expandedBeforeFilterRef.current = null;
368
+ }
369
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- runs when the filter or the filtered tree changes; `tree` is a fresh object each render
370
+ }, [filtering, filteredTree]);
371
+ useEffect(() => {
372
+ if (!selectedPath || !treeData || filtering)
199
373
  return;
200
374
  const savedState = expandedStateRef?.current ?? {};
201
375
  const pathToEntry = calculatePathToEntry(selectedPath, treeData);
@@ -228,7 +402,65 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
228
402
  useEffect(() => {
229
403
  hasScrolledRef.current = false;
230
404
  }, []);
231
- const Chevron = ({ expanded, visible }) => (_jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", style: { opacity: visible ? 0.9 : 0 }, children: expanded ? (_jsx("path", { d: "M7.41 8.59 12 13.17 16.59 8.59 18 10l-6 6-6-6z" })) : (_jsx("path", { d: "M10 6 8.59 7.41 13.17 12 8.59 16.59 10 18l6-6z" })) }));
405
+ const treeBoxRef = useRef(null);
406
+ const servedRevealRef = useRef();
407
+ // Runs again as the filter clears and the expansion lands, then focuses the row a frame later.
408
+ useEffect(() => {
409
+ if (!revealCollection || !treeData || servedRevealRef.current === revealCollection.seq)
410
+ return;
411
+ const served = () => {
412
+ servedRevealRef.current = revealCollection.seq;
413
+ onRevealed?.();
414
+ };
415
+ if (query) {
416
+ setQuery('');
417
+ return;
418
+ }
419
+ const value = collectionNodeValue(treeData, revealCollection.path);
420
+ if (!value) {
421
+ served();
422
+ return;
423
+ }
424
+ const wanted = { ...calculatePathToEntry(value, treeData), [value]: true };
425
+ if (Object.keys(wanted).some((key) => !tree.expandedState[key])) {
426
+ const next = { ...tree.expandedState, ...wanted };
427
+ tree.setExpandedState(next);
428
+ localExpandedStateRef.current = next;
429
+ onExpandedStateChange?.(next);
430
+ return;
431
+ }
432
+ const frame = requestAnimationFrame(() => {
433
+ const row = Array.from(treeBoxRef.current?.querySelectorAll('[role="treeitem"]') ?? []).find((item) => item.dataset.value === value);
434
+ row?.scrollIntoView({ block: 'nearest' });
435
+ row?.focus();
436
+ served();
437
+ });
438
+ return () => cancelAnimationFrame(frame);
439
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- `tree` and the callbacks are fresh each render
440
+ }, [revealCollection, treeData, query, tree.expandedState]);
441
+ const clearFilter = () => {
442
+ setQuery('');
443
+ filterInputRef.current?.focus();
444
+ };
445
+ const handleFilterKeyDown = (event) => {
446
+ // Enter and Escape during IME composition commit or cancel the composition, nothing more.
447
+ if (event.nativeEvent.isComposing)
448
+ return;
449
+ if (event.key === 'Escape' && query) {
450
+ // Clears the filter and nothing else: the surrounding drawer stays open.
451
+ event.preventDefault();
452
+ event.stopPropagation();
453
+ setQuery('');
454
+ }
455
+ else if (event.key === 'Enter' && filtering) {
456
+ const path = firstEntryPath(filteredTree, query);
457
+ if (path) {
458
+ event.preventDefault();
459
+ onSelect(path);
460
+ }
461
+ }
462
+ };
463
+ const Chevron = ({ expanded, visible }) => (_jsx("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "currentColor", "aria-hidden": "true", style: { flexShrink: 0, opacity: visible ? 0.9 : 0 }, children: expanded ? (_jsx("path", { d: "M7.41 8.59 12 13.17 16.59 8.59 18 10l-6 6-6-6z" })) : (_jsx("path", { d: "M10 6 8.59 7.41 13.17 12 8.59 16.59 10 18l6-6z" })) }));
232
464
  const renderNode = ({ node, elementProps, hasChildren, expanded, level, }) => {
233
465
  const status = node.nodeProps?.status;
234
466
  // Collection-level mutation callbacks are nulled when readOnly, same as
@@ -248,8 +480,13 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
248
480
  const isCollection = node.nodeProps?.isCollection;
249
481
  const isEntry = node.nodeProps?.isEntry;
250
482
  const conflictNotice = node.nodeProps?.conflictNotice;
483
+ const unavailableSchemaRefs = node.nodeProps?.unavailableSchemaRefs;
484
+ // A read-only navigator already says so once, in the branch banner.
485
+ const addRefused = !readOnly && !!node.nodeProps?.addRefused;
251
486
  const isLeaf = !hasChildren || isEntry;
252
487
  const selected = node.value === selectedPath;
488
+ const label = String(node.label ?? '');
489
+ const testIdSuffix = label.toLowerCase().replace(/\s+/g, '-');
253
490
  // For collections, always show chevron (even if empty) to match standard tree UI
254
491
  // Mantine only provides hasChildren=true if children.length > 0, but we want
255
492
  // collections to always be expandable
@@ -259,10 +496,21 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
259
496
  const canMoveDown = canReorder && typeof totalChildrenCount === 'number' && childIndex < totalChildrenCount - 1;
260
497
  // Collections show menu for add/edit/delete actions OR for reordering (subcollections)
261
498
  const hasCollectionMenu = isCollection && (onAdd || onEdit || onAddSubCollection || onDelete || canReorder);
262
- const hasEntryMenu = isEntry && entryPath && (onDeleteEntry || onRenameEntry || onReorderEntry);
263
- return (_jsx(Box, { ...elementProps, ref: selected ? selectedNodeRef : undefined, "data-testid": `entry-nav-item-${String(node.label ?? '')
264
- .toLowerCase()
265
- .replace(/\s+/g, '-')}`, onClick: (event) => {
499
+ // An unavailable entry cannot be written, so its menu (rename, delete, reorder) is not offered.
500
+ const entryUnavailable = node.nodeProps?.unavailable;
501
+ // The same holds for an entry this user may not edit. A read-only navigator already says so
502
+ // once, in the branch banner, so only a lone read-only entry gets its own lock.
503
+ const entryLocked = !readOnly && !!node.nodeProps?.itemReadOnly;
504
+ const hasEntryMenu = isEntry &&
505
+ entryPath &&
506
+ !entryUnavailable &&
507
+ !entryLocked &&
508
+ (onDeleteEntry || onRenameEntry || onReorderEntry);
509
+ const showEntryDirtyDot = isEntry && !!entryPath && !!dirtyPaths?.has(entryPath);
510
+ const showCollectionDirtyDot = !isEntry && dirtyCollections.has(node.value);
511
+ const adminItems = onAddSubCollection || onEdit || onDelete;
512
+ const hasCollectionContentItems = onAdd || canReorder;
513
+ return (_jsxs(Box, { ...elementProps, ref: selected ? selectedNodeRef : undefined, "data-nav-row": true, "data-testid": `entry-nav-item-${testIdSuffix}`, onClick: (event) => {
266
514
  elementProps.onClick(event);
267
515
  if (isLeaf && isEntry) {
268
516
  onSelect(node.value);
@@ -274,49 +522,49 @@ export const EntryNavigator = ({ items, collections, selectedPath, onSelect, onT
274
522
  paddingInline: 10,
275
523
  paddingBlock: 6,
276
524
  paddingLeft: `calc(${rem(8)} + ${rem(level * 12)})`,
277
- backgroundColor: selected ? 'var(--mantine-color-brand-0)' : undefined,
278
- border: selected ? '1px solid var(--mantine-color-brand-3)' : '1px solid transparent',
525
+ backgroundColor: selected ? 'var(--mantine-primary-color-light)' : undefined,
526
+ color: selected ? 'var(--mantine-primary-color-light-color)' : undefined,
527
+ border: selected
528
+ ? '1px solid var(--mantine-primary-color-light-color)'
529
+ : '1px solid transparent',
279
530
  transition: 'background-color 120ms ease, border-color 120ms ease',
280
- }, children: _jsxs(Group, { gap: "xs", justify: "space-between", wrap: "nowrap", children: [_jsxs(Group, { gap: 6, wrap: "nowrap", children: [_jsx(Box, { w: 18, h: 18, style: {
281
- display: 'flex',
282
- alignItems: 'center',
283
- justifyContent: 'center',
284
- }, children: _jsx(Chevron, { expanded: expanded, visible: showChevron }) }), _jsx(Text, { size: "sm", fw: selected ? 600 : 500, truncate: "end", children: node.label }), status && (_jsx(Badge, { size: "xs", variant: "light", color: "gray", children: status })), conflictNotice && (_jsx(Tooltip, { label: "This content was updated on the base branch \u2014 a reviewer will reconcile", withArrow: true, children: _jsx(Badge, { size: "xs", variant: "light", color: "orange", "data-testid": "conflict-badge", children: "conflict" }) }))] }), _jsxs(Group, { gap: 4, wrap: "nowrap", children: [hasCollectionMenu && (_jsxs(Menu, { shadow: "md", width: 200, withinPortal: true, position: "bottom-end", children: [_jsx(Menu.Target, { children: _jsx(ActionIcon, { size: "xs", variant: "subtle", color: "gray", onClick: (event) => event.stopPropagation(), "aria-label": "Collection actions", "data-testid": `collection-menu-${String(node.label ?? '')
285
- .toLowerCase()
286
- .replace(/\s+/g, '-')}`, children: _jsx(IconDots, { size: 14 }) }) }), _jsxs(Menu.Dropdown, { children: [canReorder && (_jsxs(_Fragment, { children: [_jsx(Menu.Item, { leftSection: _jsx(IconArrowUp, { size: 14 }), disabled: !canMoveUp, onClick: (event) => {
287
- event.stopPropagation();
288
- onReorderEntry?.(parentCollectionPath, contentId, 'up');
289
- }, children: "Move Up" }), _jsx(Menu.Item, { leftSection: _jsx(IconArrowDown, { size: 14 }), disabled: !canMoveDown, onClick: (event) => {
290
- event.stopPropagation();
291
- onReorderEntry?.(parentCollectionPath, contentId, 'down');
292
- }, children: "Move Down" }), (onAdd || onAddSubCollection || onEdit || onDelete) && _jsx(Menu.Divider, {})] })), onAdd && (_jsx(Menu.Item, { leftSection: _jsx(IconPlus, { size: 14 }), onClick: (event) => {
293
- event.stopPropagation();
294
- onAdd();
295
- }, "data-testid": "add-entry-menu-item", children: "Add Entry" })), onAddSubCollection && (_jsx(Menu.Item, { leftSection: _jsx(IconFolderPlus, { size: 14 }), onClick: (event) => {
296
- event.stopPropagation();
297
- onAddSubCollection();
298
- }, children: "Add Sub-Collection" })), (onAdd || onAddSubCollection) && (onEdit || onDelete) && _jsx(Menu.Divider, {}), onEdit && (_jsx(Menu.Item, { leftSection: _jsx(IconEdit, { size: 14 }), onClick: (event) => {
299
- event.stopPropagation();
300
- onEdit();
301
- }, children: "Edit Collection" })), onDelete && (_jsx(Menu.Item, { leftSection: _jsx(IconTrash, { size: 14 }), color: "red", onClick: (event) => {
302
- event.stopPropagation();
303
- onDelete();
304
- }, children: "Delete Collection" }))] })] })), hasEntryMenu && (_jsxs(Menu, { shadow: "md", width: 150, withinPortal: true, position: "bottom-end", children: [_jsx(Menu.Target, { children: _jsx(ActionIcon, { size: "xs", variant: "subtle", color: "gray", onClick: (event) => event.stopPropagation(), "aria-label": "Entry actions", "data-testid": `entry-menu-${String(node.label ?? '')
305
- .toLowerCase()
306
- .replace(/\s+/g, '-')}`, children: _jsx(IconDots, { size: 14 }) }) }), _jsxs(Menu.Dropdown, { children: [onReorderEntry && contentId && parentCollectionPath && (_jsxs(_Fragment, { children: [_jsx(Menu.Item, { leftSection: _jsx(IconArrowUp, { size: 14 }), disabled: !canMoveUp, onClick: (event) => {
307
- event.stopPropagation();
308
- onReorderEntry(parentCollectionPath, contentId, 'up');
309
- }, children: "Move Up" }), _jsx(Menu.Item, { leftSection: _jsx(IconArrowDown, { size: 14 }), disabled: !canMoveDown, onClick: (event) => {
310
- event.stopPropagation();
311
- onReorderEntry(parentCollectionPath, contentId, 'down');
312
- }, children: "Move Down" }), (onRenameEntry || onDeleteEntry) && _jsx(Menu.Divider, {})] })), onRenameEntry && (_jsx(Menu.Item, { leftSection: _jsx(IconEdit, { size: 14 }), onClick: (event) => {
313
- event.stopPropagation();
314
- onRenameEntry(entryPath);
315
- }, "data-testid": "rename-entry-menu-item", children: "Rename Entry" })), onDeleteEntry && (_jsx(Menu.Item, { leftSection: _jsx(IconTrash, { size: 14 }), color: "red", onClick: (event) => {
316
- event.stopPropagation();
317
- onDeleteEntry(entryPath);
318
- }, "data-testid": "delete-entry-menu-item", children: "Delete Entry" }))] })] }))] })] }) }));
531
+ }, children: [_jsxs(Group, { gap: "xs", justify: "space-between", wrap: "nowrap", style: { width: '100%' }, children: [_jsxs(Group, { gap: 6, wrap: "nowrap", style: { flex: 1, minWidth: 0 }, children: [_jsx(Box, { w: 18, h: 18, style: {
532
+ display: 'flex',
533
+ flexShrink: 0,
534
+ alignItems: 'center',
535
+ justifyContent: 'center',
536
+ }, children: _jsx(Chevron, { expanded: expanded, visible: showChevron }) }), _jsx(TruncatedLabel, { label: label, highlight: filtering ? query.trim() : '', fw: selected ? 600 : 500 }), showEntryDirtyDot && _jsx(UnsavedDot, { label: "Unsaved changes" }), showCollectionDirtyDot && _jsx(UnsavedDot, { label: "Contains unsaved changes" }), status && (_jsx(Badge, { size: "xs", variant: "light", color: "gray", style: { flexShrink: 0, maxWidth: 96 }, children: status })), conflictNotice && (_jsx(Tooltip, { label: "This content was updated on the base branch \u2014 a reviewer will reconcile", withArrow: true, children: _jsx(Badge, { size: "xs", variant: "light", color: "orange", "data-testid": "conflict-badge", style: { flexShrink: 0 }, children: "Conflict" }) })), entryLocked && (_jsx(Tooltip, { label: "You can't edit this entry", withinPortal: true, children: _jsx(Box, { component: "span", role: "img", "aria-label": "You can't edit this entry", "data-testid": "entry-lock", c: "dimmed", style: { display: 'inline-flex', flexShrink: 0 }, children: _jsx(IconLock, { size: 14, "aria-hidden": true }) }) }))] }), _jsxs(Group, { gap: 4, wrap: "nowrap", style: { flexShrink: 0 }, children: [hasCollectionMenu && (_jsxs(Menu, { shadow: "md", width: 200, withinPortal: true, position: "bottom-end", children: [_jsx(Menu.Target, { children: _jsx(ActionIcon, { size: "xs", variant: "subtle", color: "gray", onClick: (event) => event.stopPropagation(), "aria-label": "Collection actions", "data-testid": `collection-menu-${testIdSuffix}`, children: _jsx(IconDots, { size: 14 }) }) }), _jsxs(Menu.Dropdown, { onKeyDown: stopTreeKeys, children: [onAdd && (_jsx(Menu.Item, { leftSection: _jsx(IconPlus, { size: 14 }), onClick: (event) => {
537
+ event.stopPropagation();
538
+ onAdd();
539
+ }, "data-testid": "add-entry-menu-item", children: "Add entry\u2026" })), canReorder && (_jsxs(_Fragment, { children: [_jsx(ReasonedMenuItem, { leftSection: _jsx(IconArrowUp, { size: 14 }), blockedReason: canMoveUp ? undefined : 'Already first', onClick: (event) => {
540
+ event.stopPropagation();
541
+ onReorderEntry?.(parentCollectionPath, contentId, 'up');
542
+ }, children: "Move up" }), _jsx(ReasonedMenuItem, { leftSection: _jsx(IconArrowDown, { size: 14 }), blockedReason: canMoveDown ? undefined : 'Already last', onClick: (event) => {
543
+ event.stopPropagation();
544
+ onReorderEntry?.(parentCollectionPath, contentId, 'down');
545
+ }, children: "Move down" })] })), adminItems && (_jsxs(_Fragment, { children: [hasCollectionContentItems && _jsx(Menu.Divider, {}), _jsx(Menu.Label, { children: "Admin" })] })), onAddSubCollection && (_jsx(Menu.Item, { leftSection: _jsx(IconFolderPlus, { size: 14 }), onClick: (event) => {
546
+ event.stopPropagation();
547
+ onAddSubCollection();
548
+ }, children: "Add sub-collection\u2026" })), onEdit && (_jsx(Menu.Item, { leftSection: _jsx(IconEdit, { size: 14 }), onClick: (event) => {
549
+ event.stopPropagation();
550
+ onEdit();
551
+ }, children: "Edit collection\u2026" })), onDelete && (_jsx(DestructiveMenuItem, { leftSection: _jsx(IconTrash, { size: 14 }), onClick: (event) => {
552
+ event.stopPropagation();
553
+ onDelete();
554
+ }, children: "Delete collection" }))] })] })), hasEntryMenu && (_jsxs(Menu, { shadow: "md", width: 180, withinPortal: true, position: "bottom-end", children: [_jsx(Menu.Target, { children: _jsx(ActionIcon, { size: "xs", variant: "subtle", color: "gray", onClick: (event) => event.stopPropagation(), "aria-label": "Entry actions", "data-testid": `entry-menu-${testIdSuffix}`, children: _jsx(IconDots, { size: 14 }) }) }), _jsxs(Menu.Dropdown, { onKeyDown: stopTreeKeys, children: [onRenameEntry && (_jsx(Menu.Item, { leftSection: _jsx(IconEdit, { size: 14 }), onClick: (event) => {
555
+ event.stopPropagation();
556
+ onRenameEntry(entryPath);
557
+ }, "data-testid": "rename-entry-menu-item", children: "Rename\u2026" })), onReorderEntry && contentId && parentCollectionPath && (_jsxs(_Fragment, { children: [_jsx(ReasonedMenuItem, { leftSection: _jsx(IconArrowUp, { size: 14 }), blockedReason: canMoveUp ? undefined : 'Already first', onClick: (event) => {
558
+ event.stopPropagation();
559
+ onReorderEntry(parentCollectionPath, contentId, 'up');
560
+ }, children: "Move up" }), _jsx(ReasonedMenuItem, { leftSection: _jsx(IconArrowDown, { size: 14 }), blockedReason: canMoveDown ? undefined : 'Already last', onClick: (event) => {
561
+ event.stopPropagation();
562
+ onReorderEntry(parentCollectionPath, contentId, 'down');
563
+ }, children: "Move down" })] })), onDeleteEntry && (_jsxs(_Fragment, { children: [(onRenameEntry || (onReorderEntry && contentId && parentCollectionPath)) && (_jsx(Menu.Divider, {})), _jsx(DestructiveMenuItem, { leftSection: _jsx(IconTrash, { size: 14 }), onClick: (event) => {
564
+ event.stopPropagation();
565
+ onDeleteEntry(entryPath);
566
+ }, "data-testid": "delete-entry-menu-item", children: "Delete entry" })] }))] })] }))] })] }), isCollection && unavailableSchemaRefs && unavailableSchemaRefs.length > 0 && (_jsx(UnavailableTypeRow, { schemaRefs: unavailableSchemaRefs })), isCollection && addRefused && _jsx(AddRefusedRow, {})] }));
319
567
  };
320
- return (_jsx(Stack, { h: "100%", style: { display: 'flex', flexDirection: 'column' }, gap: 0, "data-testid": "entry-navigator", children: _jsx(ScrollArea, { type: "auto", offsetScrollbars: true, style: { flex: 1 }, children: treeData.length === 0 ? (loading ? (_jsxs(Group, { gap: "xs", py: "sm", children: [_jsx(Loader, { size: "xs" }), _jsx(Text, { size: "xs", c: "dimmed", children: "Loading content\u2026" })] })) : (_jsx(Text, { size: "xs", c: "dimmed", py: "sm", children: "No content" }))) : (_jsx(Box, { py: "sm", children: _jsx(Tree, { data: treeData, tree: tree, renderNode: renderNode, selectOnClick: false, levelOffset: "sm" }) })) }) }));
568
+ return (_jsxs(Stack, { h: "100%", style: { display: 'flex', flexDirection: 'column' }, gap: 0, "data-testid": "entry-navigator", children: [treeData.length > 0 && (_jsx(TextInput, { ref: filterInputRef, size: "sm", py: 4, "aria-label": "Filter entries", spellCheck: false, "data-autofocus": true, placeholder: "Filter by title or slug", value: query, onChange: (event) => setQuery(event.currentTarget.value), onKeyDown: handleFilterKeyDown, leftSection: _jsx(IconSearch, { size: 14, "aria-hidden": true }), rightSection: query ? _jsx(CloseButton, { size: "sm", "aria-label": "Clear filter", onClick: clearFilter }) : null, "data-mantine-stop-propagation": query ? 'true' : undefined, "data-testid": "entry-nav-filter" })), _jsxs(ScrollArea, { type: "auto", scrollbars: "y", offsetScrollbars: true, style: { flex: 1 }, children: [hiddenRootUnavailableRefs && hiddenRootUnavailableRefs.length > 0 && (_jsx(Box, { pt: "sm", children: _jsx(UnavailableTypeRow, { schemaRefs: hiddenRootUnavailableRefs }) })), hiddenRootAddRefused && (_jsx(Box, { pt: "sm", children: _jsx(AddRefusedRow, {}) })), treeData.length === 0 ? (loading ? (_jsxs(Group, { gap: "xs", py: "sm", children: [_jsx(Loader, { size: "xs" }), _jsx(Text, { size: "xs", c: "dimmed", children: "Loading content\u2026" })] })) : (_jsx(Text, { size: "xs", c: "dimmed", py: "sm", children: "No content" }))) : filteredTree.length === 0 ? (_jsxs(Stack, { gap: 4, py: "sm", align: "flex-start", "data-testid": "entry-nav-filter-empty", children: [_jsxs(Text, { size: "sm", c: "dimmed", children: ["No entries match \u201C", query, "\u201D."] }), _jsx(Button, { size: "compact-sm", variant: "subtle", onClick: clearFilter, children: "Clear filter" })] })) : (_jsx(Box, { py: "sm", ref: treeBoxRef, children: _jsx(Tree, { data: filteredTree, tree: tree, renderNode: renderNode, selectOnClick: false, levelOffset: "sm" }) }))] })] }));
321
569
  };
322
570
  export default EntryNavigator;
@@ -0,0 +1,25 @@
1
+ import React from 'react';
2
+ /** A field in the outline, holding its rows, or an inline group holding its fields. */
3
+ export interface OutlineNode {
4
+ label: string;
5
+ /** The canopy path to focus; absent for an inline group, which is not a field. */
6
+ path?: string;
7
+ /** A row's second value, shown dimmed beside its label. */
8
+ secondary?: string;
9
+ children?: OutlineNode[];
10
+ }
11
+ export interface FormHeaderProps {
12
+ title: string;
13
+ /** The entry type's label, shown as a badge. */
14
+ typeLabel?: string;
15
+ outline: OutlineNode[];
16
+ /** Scrolls to and focuses the field at `path`. */
17
+ onSelect: (path: string) => void;
18
+ /** Set when the form has a list or block field, so expanding and collapsing has a target. */
19
+ onExpandAll?: (expanded: boolean) => void;
20
+ }
21
+ /**
22
+ * The form's sticky header: which entry this is, an outline of its fields to jump to, and
23
+ * Expand all / Collapse all for every list and block field in it.
24
+ */
25
+ export declare const FormHeader: React.FC<FormHeaderProps>;