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,3 +1,9 @@
1
+ import { titleFieldPath } from '../utils/title-field.js';
2
+ /** The `titleField` an entry type contributes: absent for an unavailable type, which has no schema. */
3
+ const titleFieldFor = (schema) => {
4
+ const titleField = titleFieldPath(schema ?? []);
5
+ return titleField ? { titleField } : {};
6
+ };
1
7
  /**
2
8
  * Build hierarchical editor collections from the flattened schema.
3
9
  * Uses logicalPath as IDs to match API responses.
@@ -18,6 +24,13 @@ export const buildEditorCollections = (flatSchema) => {
18
24
  }
19
25
  childrenByParent.get(key).push(item);
20
26
  }
27
+ // A collection's own `entries` carry no schema on the wire; the entry-type items hold the
28
+ // hydrated one.
29
+ const schemaByEntryType = new Map();
30
+ for (const item of flat) {
31
+ if (item.type === 'entry-type')
32
+ schemaByEntryType.set(`${item.parentPath}\0${item.name}`, item.schema);
33
+ }
21
34
  // Build tree recursively using the grouped map
22
35
  const buildTree = (parentPath) => {
23
36
  const children = childrenByParent.get(parentPath) || [];
@@ -32,6 +45,9 @@ export const buildEditorCollections = (flatSchema) => {
32
45
  format: et.format,
33
46
  default: et.default,
34
47
  maxItems: et.maxItems,
48
+ ...(et.unavailable
49
+ ? { unavailable: et.unavailable }
50
+ : titleFieldFor(schemaByEntryType.get(`${item.logicalPath}\0${et.name}`) ?? et.schema)),
35
51
  }));
36
52
  results.push({
37
53
  path: item.logicalPath,
@@ -17,6 +17,20 @@ type PreviewEntry = {
17
17
  itemType?: string;
18
18
  previewSrc?: string;
19
19
  };
20
+ /**
21
+ * The entry's route on the host site, or `undefined` when it has no page. The first
22
+ * `previewBaseByCollection` key present decides: for a root entry its own path
23
+ * (`<contentRoot>/<slug>`, used as-is), then its collection path, then its collection name (both
24
+ * with the slug appended). The spelling `<parent>/<name>` names both an entry and a same-named
25
+ * sibling collection (a landing entry beside its folder), so below the root it is read only as a
26
+ * collection key, and at the root one key routes both.
27
+ * A `false` value means no page. With no key, the route is the entry's `urlPath`, by the rule
28
+ * `listEntries` publishes it, so a root entry previews at `/<slug>` and only a root index at `/`.
29
+ * Site-relative unless a matching value is absolute.
30
+ */
31
+ export declare const buildPreviewRoute: (entry: PreviewEntry, { previewBaseByCollection, contentRoot }: PreviewContext & {
32
+ contentRoot?: string;
33
+ }) => string | undefined;
20
34
  /**
21
35
  * Builds the preview iframe `src` for an entry: its route under `previewPrefix`, under the
22
36
  * deployment `basePath` (`CanopyClientConfig.basePath`, e.g. `/preview-123`), in the host's
@@ -24,8 +38,8 @@ type PreviewEntry = {
24
38
  * (from `previewBaseByCollection`) skips all three and gets only `?branch=`. An entry's own
25
39
  * `previewSrc` gets only the `basePath`.
26
40
  *
27
- * The result must equal the framed page's own URL: the `<iframe src>` (`PreviewFrame` in
28
- * preview-bridge.tsx) 404s without the prefixes, and a URL the host redirects costs a round trip
41
+ * The result must equal the framed page's own URL: the `<iframe src>` (`PreviewFrame.tsx`)
42
+ * 404s without the prefixes, and a URL the host redirects costs a round trip
29
43
  * on every load. `trailingSlash` defaults to the value `withCanopy` inlines at build time.
30
44
  *
31
45
  * `undefined` means the entry has no page, so the editor frames nothing rather than another page.
@@ -49,13 +63,25 @@ interface BuildEntriesFromListParams {
49
63
  export declare const buildEntriesFromListResponse: ({ response, resolvePreviewSrc, flatSchema, }: BuildEntriesFromListParams) => EditorEntry[];
50
64
  export declare const buildCollectionLabels: (collections?: EditorCollection[]) => Map<string, string>;
51
65
  /**
52
- * Builds breadcrumb segments for an entry based on its collection hierarchy.
53
- *
54
- * @param currentEntry - The entry to build breadcrumbs for (or undefined for root)
55
- * @param collectionLabels - Map of collection IDs to labels
56
- * @returns Array of breadcrumb segment strings, starting with 'All Files'
66
+ * An entry's type as its collection labels it, else its name read as words; undefined when
67
+ * untyped.
68
+ */
69
+ export declare const entryTypeLabel: (collections: EditorCollection[] | undefined, entry: Pick<EditorEntry, "collectionPath" | "entryType">) => string | undefined;
70
+ /** An entry's navigator badge: "Missing" when its file is gone, else its type's label or name. */
71
+ export declare const entryStatusLabel: (collections: EditorCollection[] | undefined, entry: Pick<EditorEntry, "status" | "collectionPath" | "entryType">) => string | undefined;
72
+ /** One crumb before the entry's own: "All content", a collection, or a folder of a nested slug. */
73
+ export interface BreadcrumbSegment {
74
+ label: string;
75
+ /** The collection the crumb opens in the content panel; absent on "All content" and slug folders. */
76
+ collectionPath?: string;
77
+ /** A slug folder, which is not a node of the content tree, so it navigates nowhere. */
78
+ folder?: true;
79
+ }
80
+ /**
81
+ * Builds breadcrumb segments for an entry based on its collection hierarchy, starting with
82
+ * "All content". The first path part is skipped as the content root, which the tree does not show.
57
83
  */
58
- export declare const buildBreadcrumbSegments: (currentEntry: EditorEntry | undefined, collectionLabels: Map<string, string>) => string[];
84
+ export declare const buildBreadcrumbSegments: (currentEntry: EditorEntry | undefined, collectionLabels: Map<string, string>) => BreadcrumbSegment[];
59
85
  /**
60
86
  * Calculates which collection nodes need to be expanded to show the path to a specific entry.
61
87
  * Recursively walks the tree to find the target entry and marks all ancestor collections as expanded.
@@ -1,5 +1,6 @@
1
1
  // Import directly from normalize to avoid pulling in server-only branch.ts
2
2
  import { normalizeFilesystemPath } from '../paths/normalize.js';
3
+ import { humanizeName } from './schema-label.js';
3
4
  import { computeEntryUrl, isIndexSlug } from '../utils/entry-url.js';
4
5
  import { isDataOnlyFormat } from '../utils/format.js';
5
6
  import { isAbsoluteUrl, joinUrlPrefix, matchTrailingSlash, readTrailingSlashEnv, stripTrailingSlashes, } from '../utils/url-prefix.js';
@@ -47,7 +48,7 @@ const previewBaseFor = (bases, key) => bases && key && Object.prototype.hasOwnPr
47
48
  * `listEntries` publishes it, so a root entry previews at `/<slug>` and only a root index at `/`.
48
49
  * Site-relative unless a matching value is absolute.
49
50
  */
50
- const buildPreviewRoute = (entry, { previewBaseByCollection, contentRoot = 'content' }) => {
51
+ export const buildPreviewRoute = (entry, { previewBaseByCollection, contentRoot = 'content' }) => {
51
52
  const collectionPath = normalizeFilesystemPath(entry.collectionPath ?? '');
52
53
  const isRootEntry = collectionPath === normalizeFilesystemPath(contentRoot);
53
54
  const entryRoute = previewBaseFor(previewBaseByCollection, isRootEntry && entry.slug ? `${collectionPath}/${entry.slug}` : undefined);
@@ -73,8 +74,8 @@ const buildPreviewRoute = (entry, { previewBaseByCollection, contentRoot = 'cont
73
74
  * (from `previewBaseByCollection`) skips all three and gets only `?branch=`. An entry's own
74
75
  * `previewSrc` gets only the `basePath`.
75
76
  *
76
- * The result must equal the framed page's own URL: the `<iframe src>` (`PreviewFrame` in
77
- * preview-bridge.tsx) 404s without the prefixes, and a URL the host redirects costs a round trip
77
+ * The result must equal the framed page's own URL: the `<iframe src>` (`PreviewFrame.tsx`)
78
+ * 404s without the prefixes, and a URL the host redirects costs a round trip
78
79
  * on every load. `trailingSlash` defaults to the value `withCanopy` inlines at build time.
79
80
  *
80
81
  * `undefined` means the entry has no page, so the editor frames nothing rather than another page.
@@ -132,12 +133,14 @@ export const buildEntriesFromListResponse = ({ response, resolvePreviewSrc, flat
132
133
  return response.entries.map((entry) => {
133
134
  // Resolve schema from flatSchema using parentPath + name
134
135
  let schema = [];
136
+ let unavailable;
135
137
  if (entry.collectionPath && entry.entryType) {
136
138
  const entryTypeItem = flatSchema.find((item) => item.type === 'entry-type' &&
137
139
  item.parentPath === entry.collectionPath &&
138
140
  item.name === entry.entryType);
139
141
  if (entryTypeItem && entryTypeItem.type === 'entry-type') {
140
142
  schema = entryTypeItem.schema;
143
+ unavailable = entryTypeItem.unavailable;
141
144
  }
142
145
  }
143
146
  return {
@@ -154,6 +157,7 @@ export const buildEntriesFromListResponse = ({ response, resolvePreviewSrc, flat
154
157
  entryType: entry.entryType,
155
158
  type: 'entry',
156
159
  canEdit: entry.canEdit,
160
+ ...(unavailable && { unavailable }),
157
161
  };
158
162
  });
159
163
  };
@@ -173,34 +177,52 @@ export const buildCollectionLabels = (collections) => {
173
177
  return map;
174
178
  };
175
179
  /**
176
- * Builds breadcrumb segments for an entry based on its collection hierarchy.
177
- *
178
- * @param currentEntry - The entry to build breadcrumbs for (or undefined for root)
179
- * @param collectionLabels - Map of collection IDs to labels
180
- * @returns Array of breadcrumb segment strings, starting with 'All Files'
180
+ * An entry's type as its collection labels it, else its name read as words; undefined when
181
+ * untyped.
182
+ */
183
+ export const entryTypeLabel = (collections, entry) => {
184
+ if (!entry.entryType)
185
+ return undefined;
186
+ const find = (nodes) => {
187
+ for (const c of nodes) {
188
+ if (c.path === entry.collectionPath)
189
+ return c;
190
+ const inner = c.children ? find(c.children) : undefined;
191
+ if (inner)
192
+ return inner;
193
+ }
194
+ return undefined;
195
+ };
196
+ const collection = collections ? find(collections) : undefined;
197
+ const type = collection?.entryTypes?.find((t) => t.name === entry.entryType);
198
+ return type?.label ?? humanizeName(entry.entryType);
199
+ };
200
+ /** An entry's navigator badge: "Missing" when its file is gone, else its type's label or name. */
201
+ export const entryStatusLabel = (collections, entry) => {
202
+ if (entry.status === 'missing')
203
+ return 'Missing';
204
+ return entryTypeLabel(collections, entry) ?? (entry.status && humanizeName(entry.status));
205
+ };
206
+ /**
207
+ * Builds breadcrumb segments for an entry based on its collection hierarchy, starting with
208
+ * "All content". The first path part is skipped as the content root, which the tree does not show.
181
209
  */
182
210
  export const buildBreadcrumbSegments = (currentEntry, collectionLabels) => {
211
+ const segments = [{ label: 'All content' }];
183
212
  if (!currentEntry)
184
- return ['All Files'];
185
- const segments = ['All Files'];
186
- // Show collection hierarchy for entries that belong to a collection
213
+ return segments;
187
214
  if (currentEntry.collectionPath) {
188
- // Split the collectionPath into path parts and build cumulative paths
189
- // e.g., "content/documentation/guides" -> ["content/documentation", "content/documentation/guides"]
190
215
  const parts = currentEntry.collectionPath.split('/').filter(Boolean);
191
216
  for (let i = 1; i < parts.length; i++) {
192
217
  const pathUpToHere = parts.slice(0, i + 1).join('/');
193
218
  const label = collectionLabels.get(pathUpToHere);
194
- if (label) {
195
- segments.push(label);
196
- }
219
+ if (label)
220
+ segments.push({ label, collectionPath: pathUpToHere });
197
221
  }
198
222
  }
199
- // Add slug path segments (for nested slugs like "folder/file")
200
223
  const slugSegments = (currentEntry.slug ?? '').split('/').filter(Boolean);
201
- if (slugSegments.length > 1) {
202
- segments.push(...slugSegments.slice(0, -1));
203
- }
224
+ for (const folder of slugSegments.slice(0, -1))
225
+ segments.push({ label: folder, folder: true });
204
226
  return segments;
205
227
  };
206
228
  /**
@@ -0,0 +1,20 @@
1
+ /** Entry search shared by the navigator filter and the quick-open palette. */
2
+ export interface SearchableEntry {
3
+ label: string;
4
+ slug?: string;
5
+ collectionPath?: string;
6
+ collectionName?: string;
7
+ }
8
+ /** Case-insensitive substring match over label and slug; an empty query matches everything. */
9
+ export declare function matchesEntryQuery(entry: Pick<SearchableEntry, 'label' | 'slug'>, query: string): boolean;
10
+ export declare function filterEntries<T extends SearchableEntry>(entries: readonly T[], query: string): T[];
11
+ export interface EntryGroup<T> {
12
+ heading: string;
13
+ entries: T[];
14
+ }
15
+ /**
16
+ * Groups entries by collection, in first-seen order, each under its display heading:
17
+ * `labelFor(collectionPath)`, else the collection name or path, else `Root`. Two collections
18
+ * that share a heading stay separate groups.
19
+ */
20
+ export declare function groupEntriesByCollection<T extends SearchableEntry>(entries: readonly T[], labelFor?: (collectionPath: string) => string | undefined): EntryGroup<T>[];
@@ -0,0 +1,34 @@
1
+ /** Entry search shared by the navigator filter and the quick-open palette. */
2
+ /** Case-insensitive substring match over label and slug; an empty query matches everything. */
3
+ export function matchesEntryQuery(entry, query) {
4
+ const needle = query.trim().toLowerCase();
5
+ if (!needle)
6
+ return true;
7
+ return (entry.label.toLowerCase().includes(needle) ||
8
+ (entry.slug?.toLowerCase().includes(needle) ?? false));
9
+ }
10
+ export function filterEntries(entries, query) {
11
+ return entries.filter((entry) => matchesEntryQuery(entry, query));
12
+ }
13
+ /**
14
+ * Groups entries by collection, in first-seen order, each under its display heading:
15
+ * `labelFor(collectionPath)`, else the collection name or path, else `Root`. Two collections
16
+ * that share a heading stay separate groups.
17
+ */
18
+ export function groupEntriesByCollection(entries, labelFor) {
19
+ const groups = new Map();
20
+ for (const entry of entries) {
21
+ const key = entry.collectionPath ?? entry.collectionName ?? '';
22
+ const group = groups.get(key);
23
+ if (group) {
24
+ group.entries.push(entry);
25
+ continue;
26
+ }
27
+ const heading = (entry.collectionPath ? labelFor?.(entry.collectionPath) : undefined) ??
28
+ entry.collectionName ??
29
+ entry.collectionPath ??
30
+ 'Root';
31
+ groups.set(key, { heading, entries: [entry] });
32
+ }
33
+ return [...groups.values()];
34
+ }
@@ -0,0 +1,12 @@
1
+ import type { FieldConfig } from '../config/index.js';
2
+ /**
3
+ * The human labels along a canopy path, for messages: `blocks[0].title` reads
4
+ * `['Page sections', 'Hero', 'Heading']`. A block is named by its template's label and an
5
+ * object-list item by its title (`listItemHeading`); a segment the schema doesn't know keeps its
6
+ * raw name, so a stale path still reads. A block whose template isn't known (no `value`, or an
7
+ * item that is gone) has its fields looked up in every template. `items: false` leaves the item
8
+ * crumbs out, for a path whose indexes no longer say which item it was.
9
+ */
10
+ export declare const fieldBreadcrumb: (fields: readonly FieldConfig[], value: unknown, path: string, { items }?: {
11
+ items?: boolean;
12
+ }) => string[];
@@ -0,0 +1,85 @@
1
+ import { isPlainRecord } from '../validation/field-traversal.js';
2
+ import { parseCanopyPath } from './canopy-path.js';
3
+ import { listItemHeading } from './fields/list-item-title.js';
4
+ import { schemaLabel } from './schema-label.js';
5
+ /** Labels for an image field's parts, which `ImageField` reports errors on. */
6
+ const IMAGE_PART_LABELS = new Map([
7
+ ['src', 'File'],
8
+ ['alt', 'Alt text'],
9
+ ['crop', 'Crop'],
10
+ ['width', 'Width'],
11
+ ['height', 'Height'],
12
+ ]);
13
+ /** The field named `name` in `fields`, looking inside inline groups, which add no path segment. */
14
+ const findField = (fields, name) => {
15
+ for (const field of fields) {
16
+ if (field.type === 'group' && 'fields' in field) {
17
+ const inner = findField(field.fields, name);
18
+ if (inner)
19
+ return inner;
20
+ }
21
+ else if (field.name === name) {
22
+ return field;
23
+ }
24
+ }
25
+ return undefined;
26
+ };
27
+ /**
28
+ * The human labels along a canopy path, for messages: `blocks[0].title` reads
29
+ * `['Page sections', 'Hero', 'Heading']`. A block is named by its template's label and an
30
+ * object-list item by its title (`listItemHeading`); a segment the schema doesn't know keeps its
31
+ * raw name, so a stale path still reads. A block whose template isn't known (no `value`, or an
32
+ * item that is gone) has its fields looked up in every template. `items: false` leaves the item
33
+ * crumbs out, for a path whose indexes no longer say which item it was.
34
+ */
35
+ export const fieldBreadcrumb = (fields, value, path, { items = true } = {}) => {
36
+ const crumbs = [];
37
+ let scope = fields;
38
+ let current = value;
39
+ let field;
40
+ for (const segment of parseCanopyPath(path)) {
41
+ if (typeof segment === 'number') {
42
+ const item = Array.isArray(current) ? current[segment] : undefined;
43
+ if (field?.type === 'block') {
44
+ const block = isPlainRecord(item) ? item : {};
45
+ const templateName = typeof block.template === 'string' ? block.template : undefined;
46
+ const templates = field.templates;
47
+ const template = templates.find((t) => t.name === templateName);
48
+ if (items)
49
+ crumbs.push(template ? schemaLabel(template) : (templateName ?? `Item ${segment + 1}`));
50
+ scope = template ? template.fields : templates.flatMap((t) => t.fields);
51
+ current = block.value;
52
+ }
53
+ else if (field?.type === 'object') {
54
+ const objectField = field;
55
+ if (items)
56
+ crumbs.push(listItemHeading(item, objectField, segment));
57
+ scope = objectField.fields;
58
+ current = item;
59
+ }
60
+ else {
61
+ if (items)
62
+ crumbs.push(`Item ${segment + 1}`);
63
+ scope = undefined;
64
+ current = item;
65
+ }
66
+ field = undefined;
67
+ continue;
68
+ }
69
+ const imagePart = field?.type === 'image' ? IMAGE_PART_LABELS.get(segment) : undefined;
70
+ if (imagePart) {
71
+ crumbs.push(imagePart);
72
+ field = undefined;
73
+ scope = undefined;
74
+ current = undefined;
75
+ continue;
76
+ }
77
+ const found = scope ? findField(scope, segment) : undefined;
78
+ crumbs.push(found ? schemaLabel(found) : segment);
79
+ current = isPlainRecord(current) ? current[segment] : undefined;
80
+ field = found;
81
+ scope =
82
+ found?.type === 'object' && !found.list ? found.fields : undefined;
83
+ }
84
+ return crumbs;
85
+ };
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Preview field marks, typed against the view's content. Exported from the root `canopycms`,
3
+ * not `canopycms/preview`: that module is `'use client'`, and a server component calling its
4
+ * functions gets a client reference that throws. A public page passes `fieldProps` as
5
+ * `undefined`, never a no-op function, which Next refuses to pass from server to client.
6
+ */
7
+ import type { ResolvedReferenceMeta } from '../entry-schema.js';
8
+ import { type CanopyPathSegment } from './canopy-path.js';
9
+ export type FieldAttrs = {
10
+ 'data-canopy-path'?: string;
11
+ };
12
+ type Digit = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9';
13
+ type IsDigits<S extends string> = S extends `${Digit}${infer Rest}` ? Rest extends '' ? true : IsDigits<Rest> : false;
14
+ /** A template literal's `${number}` hole: a computed path, so untyped. */
15
+ type TemplateHole = {
16
+ readonly templateHole: true;
17
+ };
18
+ type ParseSegment<S extends string> = IsDigits<S> extends true ? number : `${number}` extends S ? TemplateHole : S;
19
+ type ParseBrackets<S extends string> = S extends `${infer Key}[${infer Index}]${infer Rest}` ? [...(Key extends '' ? [] : [ParseSegment<Key>]), ParseSegment<Index>, ...ParseBrackets<Rest>] : S extends '' ? [] : [ParseSegment<S>];
20
+ /** As `parseCanopyPath`: `'blocks.0.title'` → `['blocks', number, 'title']`. */
21
+ type ParsePath<S extends string> = S extends `${infer Head}.${infer Rest}` ? [...ParseBrackets<Head>, ...ParsePath<Rest>] : ParseBrackets<S>;
22
+ type ImageKeys = 'src' | 'alt' | 'width' | 'height' | 'crop';
23
+ /** A value the form edits as one field: a scalar, a reference in any state, an image. */
24
+ type IsLeaf<V> = V extends string | number | boolean | bigint | symbol ? true : V extends {
25
+ unavailable: true;
26
+ } | ResolvedReferenceMeta ? true : V extends {
27
+ src: string;
28
+ alt: string;
29
+ } ? [Exclude<keyof V, ImageKeys>] extends [never] ? true : false : false;
30
+ /**
31
+ * A block item's fields are its template's, under `value`; the form's paths skip `value`. Its
32
+ * `_key` (`ITEM_KEY`, item-keys.ts) is structure, not a field.
33
+ */
34
+ type ListItem<E> = E extends {
35
+ template: string;
36
+ value: infer W;
37
+ } ? [Exclude<keyof E, 'template' | 'value' | '_key'>] extends [never] ? W : E : E;
38
+ type NextSegment<V> = unknown extends V ? CanopyPathSegment : V extends unknown ? IsLeaf<V> extends true ? never : V extends readonly unknown[] ? number : V extends object ? Exclude<keyof V & string, '_key'> : never : never;
39
+ type Child<V, S> = unknown extends V ? unknown : V extends unknown ? V extends readonly (infer E)[] ? S extends number ? Defined<ListItem<Defined<E>>> : never : IsLeaf<V> extends true ? never : S extends keyof V ? Defined<V[S]> : never : never;
40
+ type ValueAt<V, P> = P extends readonly [infer Head, ...infer Rest] ? ValueAt<Child<V, Head>, Rest> : V;
41
+ type IsFieldPath<V, P> = P extends readonly [infer Head, ...infer Rest] ? Head extends NextSegment<V> ? IsFieldPath<Child<V, Head>, Rest> : false : true;
42
+ /** The path with the allowed segments at its first wrong one, for the compile error. */
43
+ type ExpectedSegments<V, P> = P extends readonly [infer Head, ...infer Rest] ? Head extends NextSegment<V> ? readonly [Head, ...ExpectedSegments<Child<V, Head>, Rest>] : readonly [NextSegment<V>, ...CanopyPathSegment[]] : readonly [];
44
+ type SegmentsArg<V, P extends readonly unknown[]> = unknown extends V ? P : number extends P['length'] ? ComputedPathError : IsFieldPath<V, P> extends true ? P : ExpectedSegments<V, P>;
45
+ type Spell<P> = P extends readonly [infer Head, ...infer Rest] ? `${Head extends number ? `[${Head}]` : `.${Head & string}`}${Spell<Rest>}` : '';
46
+ type TrimDot<S extends string> = S extends `.${infer Rest}` ? Rest : S;
47
+ /** The paths one step past `P`'s last valid prefix, for the compile error. */
48
+ type Completions<V, P, Done extends readonly CanopyPathSegment[] = []> = P extends readonly [
49
+ infer Head,
50
+ ...infer Rest
51
+ ] ? Head extends NextSegment<V> ? Completions<Child<V, Head>, Rest, [...Done, Head]> : [NextSegment<V>] extends [never] ? TrimDot<Spell<Done>> : TrimDot<Spell<[...Done, NextSegment<V>]>> : never;
52
+ type ComputedPathError = 'a computed path is untyped: pass segments as a literal, e.g. ["list", i, "field"]';
53
+ type StringArg<V, S extends string> = unknown extends V ? S : string extends S ? ComputedPathError : TemplateHole extends ParsePath<S>[number] ? ComputedPathError : IsFieldPath<V, ParsePath<S>> extends true ? S : Completions<V, ParsePath<S>>;
54
+ /** `NonNullable<unknown>` is `{}`, which would make untyped content typed. */
55
+ type Defined<T> = unknown extends T ? unknown : NonNullable<T>;
56
+ declare const fieldPropsContent: unique symbol;
57
+ /**
58
+ * Marks the element rendering a field: `<h1 {...fieldProps('title')}>`. A path is a string
59
+ * literal or literal segments (`['blocks', i, 'title']`, for anything computed), checked against `T`
60
+ * the way the form names fields: a block's fields follow its index (no `.value`), and nothing
61
+ * is below a reference or image. Any template's fields compile after a block's index; the
62
+ * editor warns about the rest. `FieldProps` alone (`T = unknown`) takes any path.
63
+ */
64
+ export type FieldProps<T = unknown> = FieldPropsCall<Defined<T>> & {
65
+ /** Bivariant, so any typed `FieldProps` still assigns to plain `FieldProps`. */
66
+ readonly [fieldPropsContent]?: {
67
+ bivariant(content: T): void;
68
+ }['bivariant'];
69
+ };
70
+ interface FieldPropsCall<V> {
71
+ <const S extends string>(path: StringArg<V, S>): FieldAttrs;
72
+ <const P extends readonly CanopyPathSegment[]>(path: SegmentsArg<V, P>): FieldAttrs;
73
+ }
74
+ /** An empty path marks nothing. @internal `useCanopyPreview` is its only caller. */
75
+ export declare const createFieldProps: <T>() => FieldProps<T>;
76
+ /** `fieldProps(path)`, or nothing on a public page; `[]` marks the field a caller scoped to. */
77
+ export declare function fieldAttrs<T, const S extends string>(fieldProps: FieldProps<T> | undefined, path: StringArg<Defined<T>, S>): FieldAttrs;
78
+ export declare function fieldAttrs<T, const P extends readonly CanopyPathSegment[]>(fieldProps: FieldProps<T> | undefined, path: SegmentsArg<Defined<T>, P>): FieldAttrs;
79
+ /**
80
+ * `fieldProps` for a component rendering part of the entry, which marks paths relative to it
81
+ * while its caller names the part: `scopeFieldProps(fieldProps, ['sections', i])`. `undefined`
82
+ * in, `undefined` out, so a public page never builds a function.
83
+ */
84
+ export declare function scopeFieldProps<T, const S extends string>(fieldProps: FieldProps<T> | undefined, prefix: StringArg<Defined<T>, S>): FieldProps<ValueAt<Defined<T>, ParsePath<S>>> | undefined;
85
+ export declare function scopeFieldProps<T, const P extends readonly CanopyPathSegment[]>(fieldProps: FieldProps<T> | undefined, prefix: SegmentsArg<Defined<T>, P>): FieldProps<ValueAt<Defined<T>, P>> | undefined;
86
+ export {};
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Preview field marks, typed against the view's content. Exported from the root `canopycms`,
3
+ * not `canopycms/preview`: that module is `'use client'`, and a server component calling its
4
+ * functions gets a client reference that throws. A public page passes `fieldProps` as
5
+ * `undefined`, never a no-op function, which Next refuses to pass from server to client.
6
+ */
7
+ import { normalizeCanopyPath } from './canopy-path.js';
8
+ const markField = (path) => {
9
+ const normalized = normalizeCanopyPath(path);
10
+ return normalized ? { 'data-canopy-path': normalized } : {};
11
+ };
12
+ /** An empty path marks nothing. @internal `useCanopyPreview` is its only caller. */
13
+ export const createFieldProps = () => markField;
14
+ export function fieldAttrs(fieldProps, path) {
15
+ return fieldProps ? fieldProps(path) : {};
16
+ }
17
+ export function scopeFieldProps(fieldProps, prefix) {
18
+ if (!fieldProps)
19
+ return undefined;
20
+ const base = normalizeCanopyPath(prefix);
21
+ return (path) => {
22
+ const relative = normalizeCanopyPath(path);
23
+ if (!relative)
24
+ return fieldProps(base);
25
+ return fieldProps(relative.startsWith('[') ? `${base}${relative}` : `${base}.${relative}`);
26
+ };
27
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The form element for a path, as given or as `canopy-path.ts` spells it (`blocks.2.title` is
3
+ * `blocks[2].title`), else for its nearest ancestor that has one: a list item (`tags[1]`) has no
4
+ * field of its own. Compares values, not a selector: the path is untrusted.
5
+ */
6
+ export declare const findFieldTarget: (path: string, root?: ParentNode) => {
7
+ element: HTMLElement;
8
+ path: string;
9
+ } | undefined;
10
+ /** Dispatched from a form element to open every collapsed list row holding it (`ItemList`). */
11
+ export declare const REVEAL_FIELD_EVENT = "canopy:reveal-field";
12
+ /**
13
+ * Asks every collapsed row holding `element` to open. True when one was closed: its content shows
14
+ * once React re-renders, so act on the element through `whenRevealed`. @internal Exported for
15
+ * tests; callers use `whenRevealed`.
16
+ */
17
+ export declare const revealField: (element: HTMLElement) => boolean;
18
+ /**
19
+ * Runs `then` once `element` is shown: at once, or a few frames on when a row had to open. It asks
20
+ * again each frame, since a row mounted in the same commit as the element may not listen yet.
21
+ */
22
+ export declare const whenRevealed: (element: HTMLElement, then: () => void) => void;
23
+ /**
24
+ * Scrolls a field's element into view and focuses what a person would type into: the element
25
+ * itself when it is an input, else its first focusable input, else its first other focusable
26
+ * control that is not a comment control, else the element when it takes programmatic focus.
27
+ * An input out of the tab order or not rendered, such as a dropzone's file input, is never chosen.
28
+ * Collapsed list rows holding the element open first.
29
+ */
30
+ export declare const focusFieldTarget: (element: HTMLElement) => void;
@@ -0,0 +1,77 @@
1
+ import { formatCanopyPath, parseCanopyPath } from './canopy-path.js';
2
+ /**
3
+ * The form element for a path, as given or as `canopy-path.ts` spells it (`blocks.2.title` is
4
+ * `blocks[2].title`), else for its nearest ancestor that has one: a list item (`tags[1]`) has no
5
+ * field of its own. Compares values, not a selector: the path is untrusted.
6
+ */
7
+ export const findFieldTarget = (path, root = document) => {
8
+ const byField = new Map();
9
+ for (const element of root.querySelectorAll('[data-canopy-field]')) {
10
+ const field = element.getAttribute('data-canopy-field');
11
+ if (field && !byField.has(field))
12
+ byField.set(field, element);
13
+ }
14
+ const exact = byField.get(path);
15
+ if (exact)
16
+ return { element: exact, path };
17
+ const segments = parseCanopyPath(path);
18
+ for (let length = segments.length; length > 0; length--) {
19
+ const candidate = formatCanopyPath(segments.slice(0, length));
20
+ const element = byField.get(candidate);
21
+ if (element)
22
+ return { element, path: candidate };
23
+ }
24
+ return undefined;
25
+ };
26
+ /** Dispatched from a form element to open every collapsed list row holding it (`ItemList`). */
27
+ export const REVEAL_FIELD_EVENT = 'canopy:reveal-field';
28
+ /**
29
+ * Asks every collapsed row holding `element` to open. True when one was closed: its content shows
30
+ * once React re-renders, so act on the element through `whenRevealed`. @internal Exported for
31
+ * tests; callers use `whenRevealed`.
32
+ */
33
+ export const revealField = (element) => !element.dispatchEvent(new CustomEvent(REVEAL_FIELD_EVENT, { bubbles: true, cancelable: true }));
34
+ const MAX_REVEAL_FRAMES = 10;
35
+ /**
36
+ * Runs `then` once `element` is shown: at once, or a few frames on when a row had to open. It asks
37
+ * again each frame, since a row mounted in the same commit as the element may not listen yet.
38
+ */
39
+ export const whenRevealed = (element, then) => {
40
+ const shown = () => typeof element.checkVisibility !== 'function' || element.checkVisibility();
41
+ if (!revealField(element) && shown()) {
42
+ then();
43
+ return;
44
+ }
45
+ let frames = 0;
46
+ const check = () => {
47
+ frames += 1;
48
+ if (shown() || frames >= MAX_REVEAL_FRAMES) {
49
+ then();
50
+ return;
51
+ }
52
+ revealField(element);
53
+ requestAnimationFrame(check);
54
+ };
55
+ requestAnimationFrame(check);
56
+ };
57
+ const EDITABLE = 'input:not([type="hidden"]), textarea, select, [contenteditable="true"]';
58
+ const FOCUSABLE = 'button, [href], [tabindex]';
59
+ /** Takes keyboard focus as it stands: enabled, in the tab order, and rendered. */
60
+ const canTakeFocus = (el) => !el.matches(':disabled, [tabindex="-1"]') &&
61
+ (typeof el.checkVisibility !== 'function' || el.checkVisibility({ visibilityProperty: true }));
62
+ /**
63
+ * Scrolls a field's element into view and focuses what a person would type into: the element
64
+ * itself when it is an input, else its first focusable input, else its first other focusable
65
+ * control that is not a comment control, else the element when it takes programmatic focus.
66
+ * An input out of the tab order or not rendered, such as a dropzone's file input, is never chosen.
67
+ * Collapsed list rows holding the element open first.
68
+ */
69
+ export const focusFieldTarget = (element) => whenRevealed(element, () => focusShownField(element));
70
+ const focusShownField = (element) => {
71
+ element.scrollIntoView({ behavior: 'smooth', block: 'center' });
72
+ const inputs = [element, ...element.querySelectorAll(EDITABLE)].filter((el) => el.matches(EDITABLE) && canTakeFocus(el));
73
+ // The element itself counts: a date field's target is its picker's trigger button.
74
+ const controls = [element, ...element.querySelectorAll(FOCUSABLE)].filter((el) => el.matches(FOCUSABLE) && canTakeFocus(el) && !el.closest('[data-comment-control]'));
75
+ const focusable = inputs[0] ?? controls[0] ?? (element.hasAttribute('tabindex') ? element : undefined);
76
+ focusable?.focus({ preventScroll: true });
77
+ };
@@ -1,12 +1,16 @@
1
1
  import React from 'react';
2
2
  import type { BlockConfig, FieldConfig } from '../../config/index.js';
3
+ import { ITEM_KEY } from '../../item-keys.js';
3
4
  export interface BlockInstance {
4
5
  template: string;
5
6
  value: Record<string, unknown>;
7
+ /** The block's key (`item-keys.ts`). */
8
+ [ITEM_KEY]?: string;
6
9
  }
7
10
  type RenderField = (field: FieldConfig, value: unknown, onChange: (v: unknown) => void, path: Array<string | number>) => React.ReactNode;
8
11
  export interface BlockFieldProps {
9
12
  label?: string;
13
+ required?: boolean;
10
14
  description?: string;
11
15
  templates: BlockConfig[];
12
16
  value: BlockInstance[];
@@ -14,6 +18,14 @@ export interface BlockFieldProps {
14
18
  renderField: RenderField;
15
19
  path: Array<string | number>;
16
20
  dataCanopyField?: string;
21
+ /** No add, remove, reorder or drag; rows still collapse. */
22
+ readOnly?: boolean;
23
+ /** Names the entry being edited; another entry starts with the default rows open. */
24
+ resetKey?: string;
25
+ /** True when a field inside block `index` has a validation error. */
26
+ hasErrors?: (index: number) => boolean;
27
+ /** Told of each block Remove takes out, so the caller can offer Undo. */
28
+ onRemoved?: (index: number, block: BlockInstance) => void;
17
29
  }
18
30
  export declare const BlockField: React.FC<BlockFieldProps>;
19
31
  export {};