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
@@ -0,0 +1,160 @@
1
+ 'use client';
2
+ function isListLike(node) {
3
+ return (typeof node === 'object' &&
4
+ node !== null &&
5
+ 'getListType' in node &&
6
+ 'getStart' in node &&
7
+ 'setStart' in node &&
8
+ typeof node.setStart === 'function');
9
+ }
10
+ function isListItem(node) {
11
+ return node.type === 'listItem';
12
+ }
13
+ function isLinkLike(node) {
14
+ return (node.getType() === 'link' || node.getType() === 'autolink') && 'getURL' in node;
15
+ }
16
+ const FORMAT_CONTAINER_TYPES = ['emphasis', 'strong', 'delete'];
17
+ function isFormatContainer(node) {
18
+ return FORMAT_CONTAINER_TYPES.includes(node.type);
19
+ }
20
+ /** `nodes` with every container of a type in `types` replaced by its children, at any depth. */
21
+ function withoutContainers(nodes, types) {
22
+ return nodes.flatMap((node) => {
23
+ if (!isFormatContainer(node))
24
+ return [node];
25
+ const children = withoutContainers(node.children, types);
26
+ return types.has(node.type) ? children : [{ ...node, children }];
27
+ });
28
+ }
29
+ /** Creates the plugin from MDXEditor's exports; call once per load of MDXEditor. */
30
+ export function createMarkdownFidelityPlugin(mdx) {
31
+ const { IS_BOLD, IS_CODE, IS_ITALIC, IS_STRIKETHROUGH, addExportVisitor$, addImportVisitor$, lexical: { $isElementNode, $isTextNode }, realmPlugin, } = mdx;
32
+ const FORMATS = [
33
+ { format: IS_ITALIC, type: 'emphasis' },
34
+ { format: IS_BOLD, type: 'strong' },
35
+ { format: IS_STRIKETHROUGH, type: 'delete' },
36
+ ];
37
+ /** The formats every text node in `node` carries, or 0 for one with no text. */
38
+ const sharedFormat = (node) => {
39
+ const texts = $isElementNode(node) ? node.getChildren().filter($isTextNode) : [];
40
+ return texts.length === 0 ? 0 : texts.reduce((all, text) => all & text.getFormat(), ~0);
41
+ };
42
+ // MDXEditor imports a list without its `start`, and exports one without it.
43
+ const listStartImportVisitor = {
44
+ priority: 100,
45
+ testNode: (node) => node.type === 'list' &&
46
+ 'ordered' in node &&
47
+ node.ordered === true &&
48
+ typeof node.start === 'number' &&
49
+ node.start !== 1,
50
+ visitNode({ mdastNode, lexicalParent, actions }) {
51
+ actions.nextVisitor();
52
+ // MDXEditor appends the list, or for a nested one, a list item holding it after the parent.
53
+ // Under an insert, `lexicalParent` is an import point that is no element node.
54
+ const holder = lexicalParent.getType() === 'listitem' && $isElementNode(lexicalParent)
55
+ ? lexicalParent.getNextSibling()
56
+ : lexicalParent;
57
+ const list = $isElementNode(holder)
58
+ ? lexicalParent === holder
59
+ ? holder.getLastChild()
60
+ : holder.getFirstChild()
61
+ : null;
62
+ if (isListLike(list) && typeof mdastNode.start === 'number')
63
+ list.setStart(mdastNode.start);
64
+ },
65
+ };
66
+ const listStartExportVisitor = {
67
+ priority: 100,
68
+ testLexicalNode: (node) => isListLike(node) && node.getListType() === 'number' && node.getStart() !== 1,
69
+ visitLexicalNode({ lexicalNode, mdastParent, actions }) {
70
+ actions.nextVisitor();
71
+ const list = mdastParent.children.at(-1);
72
+ if (list?.type === 'list' && isListLike(lexicalNode))
73
+ list.start = lexicalNode.getStart();
74
+ // Only a list starting at 1 can interrupt a paragraph, so one right after a paragraph in a
75
+ // list item needs the blank line a loose item writes, or it reads back as that paragraph.
76
+ if (isListItem(mdastParent) && mdastParent.children.at(-2)?.type === 'paragraph') {
77
+ mdastParent.spread = true;
78
+ }
79
+ },
80
+ };
81
+ /**
82
+ * A link inside a bold, italic or struck-through span is written inside that span, carrying it
83
+ * on as MDXEditor's text visitor carries a format across text nodes, so
84
+ * `**Read the [guide](/g) first.**` keeps its shape; MDXEditor's own visitor writes the link
85
+ * beside the span, bolding its text. A link the span ends at is written that way still, since
86
+ * lexical keeps no record of which was written: `**[guide](/g)**` saves as `[**guide**](/g)`.
87
+ *
88
+ * An auto-link holding code-formatted text is written as its text: lexical's auto-link matchers
89
+ * see text, not formats, so a URL inside a code span becomes a link markdown never meant.
90
+ */
91
+ const linkExportVisitor = {
92
+ priority: 100,
93
+ testLexicalNode: (node) => isLinkLike(node),
94
+ visitLexicalNode({ lexicalNode, mdastParent, actions }) {
95
+ if (!isLinkLike(lexicalNode))
96
+ return;
97
+ if (lexicalNode.getType() === 'autolink' &&
98
+ $isElementNode(lexicalNode) &&
99
+ lexicalNode
100
+ .getChildren()
101
+ .some((child) => $isTextNode(child) && (child.getFormat() & IS_CODE) !== 0)) {
102
+ actions.visitChildren(lexicalNode, mdastParent);
103
+ return;
104
+ }
105
+ const format = sharedFormat(lexicalNode);
106
+ const next = lexicalNode.getNextSibling();
107
+ const carried = new Set();
108
+ let parent = mdastParent;
109
+ for (;;) {
110
+ const last = parent.children.at(-1);
111
+ const container = FORMATS.find(({ format: bit, type }) => format & bit && !carried.has(type) && last?.type === type);
112
+ if (container === undefined || last === undefined || !('children' in last))
113
+ break;
114
+ carried.add(container.type);
115
+ parent = last;
116
+ }
117
+ for (const { format: bit, type } of FORMATS) {
118
+ if (!(format & bit) || carried.has(type))
119
+ continue;
120
+ if (!$isTextNode(next) || !(next.getFormat() & bit))
121
+ continue;
122
+ const opened = actions.appendToParent(parent, { type, children: [] });
123
+ if (!('children' in opened))
124
+ break;
125
+ carried.add(type);
126
+ parent = opened;
127
+ }
128
+ const link = {
129
+ type: 'link',
130
+ url: lexicalNode.getURL(),
131
+ title: lexicalNode.getTitle(),
132
+ children: [],
133
+ };
134
+ actions.appendToParent(parent, link);
135
+ actions.visitChildren(lexicalNode, link);
136
+ if (carried.size > 0)
137
+ link.children = withoutContainers(link.children, carried);
138
+ },
139
+ };
140
+ // Markdown has no way to write two code spans side by side, and an auto-link written as its
141
+ // text leaves the code either side of it as separate spans.
142
+ const inlineCodeJoinVisitor = {
143
+ shouldJoin: (prev, current) => prev.type === 'inlineCode' && current.type === 'inlineCode',
144
+ join(prev, current) {
145
+ if (prev.type === 'inlineCode' && current.type === 'inlineCode')
146
+ prev.value += current.value;
147
+ return prev;
148
+ },
149
+ };
150
+ return realmPlugin({
151
+ init(realm) {
152
+ realm.pub(addImportVisitor$, listStartImportVisitor);
153
+ realm.pub(addExportVisitor$, [
154
+ listStartExportVisitor,
155
+ linkExportVisitor,
156
+ inlineCodeJoinVisitor,
157
+ ]);
158
+ },
159
+ });
160
+ }
@@ -1 +1,5 @@
1
- export declare function mdxJsxPlugins(): import("@mdxeditor/editor").RealmPlugin[];
1
+ import type * as MdxEditor from '@mdxeditor/editor';
2
+ type MdxEditorModule = typeof MdxEditor;
3
+ /** Creates the JSX plugins from MDXEditor's exports; call once per load of MDXEditor. */
4
+ export declare function createMdxJsxPlugins(mdx: MdxEditorModule): () => MdxEditor.RealmPlugin[];
5
+ export {};
@@ -1,6 +1,5 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { NestedLexicalEditor, UnrecognizedMarkdownConstructError, addImportVisitor$, importVisitors$, isMdastHTMLNode, isMdastJsxNode, jsxPlugin, realmPlugin, } from '@mdxeditor/editor';
4
3
  function childrenOf(node) {
5
4
  return 'children' in node && Array.isArray(node.children) ? node.children : [];
6
5
  }
@@ -13,26 +12,6 @@ function describeAttribute(attribute) {
13
12
  return `${attribute.name}="${attribute.value}"`;
14
13
  return `${attribute.name}={…}`;
15
14
  }
16
- /**
17
- * Shows an element's tag and attributes read-only (they are edited as source)
18
- * and edits its children, inline or block per the parsed node: one `*`
19
- * descriptor serves both, and a block editor rejects inline children.
20
- */
21
- const CatchAllJsxEditor = ({ mdastNode }) => {
22
- const inline = mdastNode.type === 'mdxJsxTextElement';
23
- const tag = [mdastNode.name ?? '', ...mdastNode.attributes.map(describeAttribute)]
24
- .join(' ')
25
- .trim();
26
- const Wrapper = inline ? 'span' : 'div';
27
- return (_jsxs(Wrapper, { className: inline ? 'canopy-mdx-jsx canopy-mdx-jsx-inline' : 'canopy-mdx-jsx', children: [_jsx("span", { className: "canopy-mdx-jsx-tag", "data-testid": "mdx-jsx-tag", title: tag, children: `<${tag}>` }), mdastNode.children.length > 0 ? (_jsx(NestedLexicalEditor, { block: !inline, getContent: (node) => node.children, getUpdatedMdastNode: (node, children) => ({ ...node, children }) })) : null] }));
28
- };
29
- const catchAllJsxDescriptor = {
30
- name: '*',
31
- kind: 'flow',
32
- props: [],
33
- hasChildren: true,
34
- Editor: CatchAllJsxEditor,
35
- };
36
15
  const isStringAttribute = (attribute, name) => attribute.type === 'mdxJsxAttribute' &&
37
16
  attribute.name === name &&
38
17
  typeof attribute.value === 'string';
@@ -70,68 +49,177 @@ function roundTripsImage(node) {
70
49
  }
71
50
  // Why MDXEditor cannot round-trip this JSX element, or null if it can. A
72
51
  // fragment has no name, which MDXEditor's HTML handling throws on.
73
- function unsupportedJsx(node) {
74
- if (!isMdastJsxNode(node))
52
+ function unsupportedJsx(mdx, node) {
53
+ if (!mdx.isMdastJsxNode(node))
75
54
  return null;
76
55
  if (node.name === null)
77
56
  return 'fragments (<>…</>)';
78
57
  // `img` is the image plugin's, not in MDXEditor's HTML tag list.
79
58
  if (node.name === 'img')
80
59
  return roundTripsImage(node) ? null : 'this <img>';
81
- if (isMdastHTMLNode(node) && breaksSpanCollapse(node)) {
60
+ if (mdx.isMdastHTMLNode(node) && breaksSpanCollapse(node)) {
82
61
  return `<${node.name}> wrapping a <span>, with an {expression} class or style`;
83
62
  }
84
63
  return null;
85
64
  }
65
+ // Blocks that run into the block before them in a list item, by that block's type.
66
+ const RUNS_INTO = {
67
+ paragraph: ['thematicBreak'],
68
+ blockquote: ['paragraph', 'blockquote', 'table'],
69
+ table: ['paragraph', 'table'],
70
+ };
71
+ const BLOCK_NAMES = {
72
+ paragraph: 'paragraph',
73
+ blockquote: 'quote',
74
+ table: 'table',
75
+ thematicBreak: 'horizontal rule',
76
+ };
77
+ /**
78
+ * Why MDXEditor would change what this list item says, or null. Its import moves a nested list into
79
+ * a new item after its own, so what follows the list comes out before it; its export writes an item
80
+ * tight, so `---` underlines a paragraph and a line continues a quote or table (`RUNS_INTO`).
81
+ */
82
+ function rearrangedBlocks(node) {
83
+ if (node.type !== 'listItem')
84
+ return null;
85
+ for (let i = 1; i < node.children.length; i++) {
86
+ const before = node.children[i - 1].type;
87
+ const after = node.children[i].type;
88
+ if (before === 'list')
89
+ return 'a list item with content after its nested list';
90
+ if (RUNS_INTO[before]?.includes(after)) {
91
+ return `a list item with a ${BLOCK_NAMES[before] ?? before} followed by a ${BLOCK_NAMES[after] ?? after}`;
92
+ }
93
+ }
94
+ return null;
95
+ }
96
+ const isLexicalParent = (node) => 'getChildren' in node && typeof node.getChildren === 'function';
97
+ const hasBlockChild = (node) => isLexicalParent(node) && node.getChildren().some((child) => !child.isInline());
98
+ // Writes `node`'s children into `target`: a run of inline children as one paragraph, a block as itself.
99
+ function writeBlocks(node, target, actions) {
100
+ let paragraph = null;
101
+ for (const child of isLexicalParent(node) ? node.getChildren() : []) {
102
+ if (!child.isInline()) {
103
+ paragraph = null;
104
+ actions.visit(child, target);
105
+ continue;
106
+ }
107
+ if (paragraph === null) {
108
+ const created = { type: 'paragraph', children: [] };
109
+ actions.appendToParent(target, created);
110
+ paragraph = created;
111
+ }
112
+ actions.visit(child, paragraph);
113
+ }
114
+ }
115
+ // MDXEditor 4 exports each child of a quote as a block, so inline children the toolbar's Quote,
116
+ // the `> ` shortcut or a merge put in a quote would come out one paragraph each.
117
+ const quoteExportVisitor = {
118
+ priority: 100,
119
+ testLexicalNode: (node) => node.getType() === 'quote',
120
+ visitLexicalNode({ lexicalNode, mdastParent, actions }) {
121
+ const quote = { type: 'blockquote', children: [] };
122
+ actions.appendToParent(mdastParent, quote);
123
+ writeBlocks(lexicalNode, quote, actions);
124
+ },
125
+ };
126
+ // Backspace at the start of a quote moves its paragraphs and lists into one paragraph, which
127
+ // MDXEditor would export as one run of text; they are written as the blocks they show.
128
+ const paragraphOfBlocksExportVisitor = {
129
+ priority: 100,
130
+ testLexicalNode: (node) => node.getType() === 'paragraph' && hasBlockChild(node),
131
+ visitLexicalNode({ lexicalNode, mdastParent, actions }) {
132
+ writeBlocks(lexicalNode, mdastParent, actions);
133
+ },
134
+ };
86
135
  /** Typed `string` because the mdast node union this package resolves omits the ESM node. */
87
136
  const ESM_NODE_TYPE = 'mdxjsEsm';
88
- /** Node types the table visitor imports itself, so they have no visitor of their own. */
137
+ /** Node types inside a table, imported by its cell editors rather than by visitors. */
89
138
  const CONSUMED_BY_PARENT_VISITOR = new Set(['tableRow', 'tableCell']);
90
- /**
91
- * Reports through `onError`, at import, what MDXEditor would otherwise lose
92
- * silently: `import`/`export` lines (its visitor for them is a no-op), elements
93
- * `unsupportedJsx` rejects, and content with no visitor inside a JSX element or
94
- * table, whose children nested editors import later, only logging a failure and
95
- * writing partial children back on edit. It throws an error class MDXEditor's
96
- * import reports; any other error would crash the editor.
97
- */
98
- const roundTripGuardPlugin = realmPlugin({
99
- init(realm) {
100
- const guard = {
101
- priority: 100,
102
- testNode: (node) => node.type === ESM_NODE_TYPE || node.type === 'table' || isMdastJsxNode(node),
103
- visitNode({ mdastNode, descriptors, actions }) {
104
- if (mdastNode.type === ESM_NODE_TYPE) {
105
- throw new UnrecognizedMarkdownConstructError('import/export statements cannot be edited in the rich-text editor');
106
- }
107
- const reject = (node) => {
108
- const reason = unsupportedJsx(node);
109
- if (reason !== null) {
110
- throw new UnrecognizedMarkdownConstructError(`${reason} cannot be edited in the rich-text editor`);
139
+ /** Creates the JSX plugins from MDXEditor's exports; call once per load of MDXEditor. */
140
+ export function createMdxJsxPlugins(mdx) {
141
+ const { NestedLexicalEditor, UnrecognizedMarkdownConstructError, addExportVisitor$, addImportVisitor$, importVisitors$, isMdastJsxNode, jsxPlugin, realmPlugin, } = mdx;
142
+ /**
143
+ * Shows an element's tag and attributes read-only (they are edited as source)
144
+ * and edits its children, inline or block per the parsed node: one `*`
145
+ * descriptor serves both, and a block editor rejects inline children.
146
+ */
147
+ const CatchAllJsxEditor = ({ mdastNode }) => {
148
+ const inline = mdastNode.type === 'mdxJsxTextElement';
149
+ const tag = [mdastNode.name ?? '', ...mdastNode.attributes.map(describeAttribute)]
150
+ .join(' ')
151
+ .trim();
152
+ const Wrapper = inline ? 'span' : 'div';
153
+ return (_jsxs(Wrapper, { className: inline ? 'canopy-mdx-jsx canopy-mdx-jsx-inline' : 'canopy-mdx-jsx', children: [_jsx("span", { className: "canopy-mdx-jsx-tag", "data-testid": "mdx-jsx-tag", title: tag, children: `<${tag}>` }), mdastNode.children.length > 0 ? (_jsx(NestedLexicalEditor, { block: !inline, getContent: (node) => node.children, getUpdatedMdastNode: (node, children) => ({ ...node, children }) })) : null] }));
154
+ };
155
+ const catchAllJsxDescriptor = {
156
+ name: '*',
157
+ kind: 'flow',
158
+ props: [],
159
+ hasChildren: true,
160
+ Editor: CatchAllJsxEditor,
161
+ };
162
+ /**
163
+ * Reports through `onError`, at import, what MDXEditor would otherwise lose or
164
+ * break on without reporting it: `import`/`export` lines (its visitor for them
165
+ * is a no-op), what `unsupportedJsx` and `rearrangedBlocks` reject, and content
166
+ * with no visitor inside a JSX element or table, whose children nested editors
167
+ * import later, only logging a failure and writing partial children back on
168
+ * edit. It throws an error class MDXEditor's import reports; any other error
169
+ * crashes the editor.
170
+ */
171
+ const roundTripGuardPlugin = realmPlugin({
172
+ init(realm) {
173
+ const guard = {
174
+ priority: 100,
175
+ testNode: (node) => node.type === ESM_NODE_TYPE ||
176
+ node.type === 'table' ||
177
+ node.type === 'listItem' ||
178
+ isMdastJsxNode(node),
179
+ visitNode({ mdastNode, descriptors, actions }) {
180
+ if (mdastNode.type === ESM_NODE_TYPE) {
181
+ throw new UnrecognizedMarkdownConstructError('import/export statements cannot be edited in the rich-text editor');
111
182
  }
112
- };
113
- reject(mdastNode);
114
- const visitors = realm.getValue(importVisitors$).filter((visitor) => visitor !== guard);
115
- const hasVisitor = (node) => visitors.some((visitor) => typeof visitor.testNode === 'string'
116
- ? visitor.testNode === node.type
117
- : visitor.testNode(node, descriptors));
118
- const check = (node) => {
119
- for (const child of childrenOf(node)) {
120
- reject(child);
121
- if (!CONSUMED_BY_PARENT_VISITOR.has(child.type) && !hasVisitor(child)) {
122
- const where = isMdastJsxNode(mdastNode) ? `<${mdastNode.name ?? ''}>` : 'A table';
123
- throw new UnrecognizedMarkdownConstructError(`${where} contains ${child.type} content the rich-text editor cannot edit`);
183
+ const reject = (node) => {
184
+ const reason = unsupportedJsx(mdx, node) ?? rearrangedBlocks(node);
185
+ if (reason !== null) {
186
+ throw new UnrecognizedMarkdownConstructError(`${reason} cannot be edited in the rich-text editor`);
124
187
  }
125
- check(child);
188
+ };
189
+ reject(mdastNode);
190
+ if (mdastNode.type === 'listItem') {
191
+ actions.nextVisitor();
192
+ return;
126
193
  }
127
- };
128
- check(mdastNode);
129
- actions.nextVisitor();
130
- },
131
- };
132
- realm.pub(addImportVisitor$, guard);
133
- },
134
- });
135
- export function mdxJsxPlugins() {
136
- return [jsxPlugin({ jsxComponentDescriptors: [catchAllJsxDescriptor] }), roundTripGuardPlugin()];
194
+ const visitors = realm.getValue(importVisitors$).filter((visitor) => visitor !== guard);
195
+ const hasVisitor = (node) => visitors.some((visitor) => typeof visitor.testNode === 'string'
196
+ ? visitor.testNode === node.type
197
+ : visitor.testNode(node, descriptors));
198
+ const check = (node) => {
199
+ for (const child of childrenOf(node)) {
200
+ reject(child);
201
+ if (!CONSUMED_BY_PARENT_VISITOR.has(child.type) && !hasVisitor(child)) {
202
+ const where = isMdastJsxNode(mdastNode) ? `<${mdastNode.name ?? ''}>` : 'A table';
203
+ throw new UnrecognizedMarkdownConstructError(`${where} contains ${child.type} content the rich-text editor cannot edit`);
204
+ }
205
+ check(child);
206
+ }
207
+ };
208
+ check(mdastNode);
209
+ actions.nextVisitor();
210
+ },
211
+ };
212
+ realm.pub(addImportVisitor$, guard);
213
+ },
214
+ });
215
+ const blockExportPlugin = realmPlugin({
216
+ init(realm) {
217
+ realm.pub(addExportVisitor$, [quoteExportVisitor, paragraphOfBlocksExportVisitor]);
218
+ },
219
+ });
220
+ return () => [
221
+ jsxPlugin({ jsxComponentDescriptors: [catchAllJsxDescriptor] }),
222
+ roundTripGuardPlugin(),
223
+ blockExportPlugin(),
224
+ ];
137
225
  }
@@ -0,0 +1,5 @@
1
+ export declare function rememberRichTextFailure(markdown: string, reason: string): void;
2
+ export declare function recallRichTextFailure(markdown: string): string | undefined;
3
+ export declare function forgetRichTextFailure(markdown: string): void;
4
+ /** @internal Exported for tests. */
5
+ export declare function resetRichTextFailures(): void;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Markdown the rich-text editor failed to open this page session, keyed by text so the same text
3
+ * shown again opens straight to source, with the reason to show. Memory only: a reload tries
4
+ * rich text again.
5
+ */
6
+ const failures = new Map();
7
+ const MAX_REMEMBERED = 20;
8
+ export function rememberRichTextFailure(markdown, reason) {
9
+ failures.delete(markdown);
10
+ failures.set(markdown, reason);
11
+ if (failures.size > MAX_REMEMBERED) {
12
+ const oldest = failures.keys().next();
13
+ if (!oldest.done)
14
+ failures.delete(oldest.value);
15
+ }
16
+ }
17
+ export function recallRichTextFailure(markdown) {
18
+ return failures.get(markdown);
19
+ }
20
+ export function forgetRichTextFailure(markdown) {
21
+ failures.delete(markdown);
22
+ }
23
+ /** @internal Exported for tests. */
24
+ export function resetRichTextFailures() {
25
+ failures.clear();
26
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @internal Exported for tests. Hides each separator that starts or ends a wrapped row; it keeps
3
+ * its space, so hiding never moves the wrap. One not laid out (zero height) is left alone.
4
+ */
5
+ export declare const hideSeparatorsAtWrap: (toolbar: HTMLElement) => void;
6
+ /** Reruns `hideSeparatorsAtWrap` on `selector` in `root` as either resizes; returns cleanup. */
7
+ export declare const watchToolbarWrap: (root: HTMLElement, selector: string) => (() => void);
@@ -0,0 +1,35 @@
1
+ /**
2
+ * @internal Exported for tests. Hides each separator that starts or ends a wrapped row; it keeps
3
+ * its space, so hiding never moves the wrap. One not laid out (zero height) is left alone.
4
+ */
5
+ export const hideSeparatorsAtWrap = (toolbar) => {
6
+ for (const separator of toolbar.querySelectorAll('[role="separator"]')) {
7
+ const own = separator.getBoundingClientRect();
8
+ if (own.height === 0)
9
+ continue;
10
+ const previous = separator.previousElementSibling?.getBoundingClientRect();
11
+ const next = separator.nextElementSibling?.getBoundingClientRect();
12
+ const atRowEdge = !previous || !next || previous.bottom <= own.top || next.top >= own.bottom;
13
+ separator.style.visibility = atRowEdge ? 'hidden' : '';
14
+ }
15
+ };
16
+ /** Reruns `hideSeparatorsAtWrap` on `selector` in `root` as either resizes; returns cleanup. */
17
+ export const watchToolbarWrap = (root, selector) => {
18
+ if (typeof ResizeObserver !== 'function')
19
+ return () => { };
20
+ let watched = null;
21
+ const observer = new ResizeObserver(() => {
22
+ const toolbar = root.querySelector(selector);
23
+ if (!toolbar)
24
+ return;
25
+ if (toolbar !== watched) {
26
+ if (watched)
27
+ observer.unobserve(watched);
28
+ watched = toolbar;
29
+ observer.observe(toolbar);
30
+ }
31
+ hideSeparatorsAtWrap(toolbar);
32
+ });
33
+ observer.observe(root);
34
+ return () => observer.disconnect();
35
+ };
@@ -0,0 +1,13 @@
1
+ import type { FieldConfig } from '../config/index.js';
2
+ import type { OutlineNode } from './FormHeader.js';
3
+ /**
4
+ * The form's outline: each top-level field in form order, holding the rows of a list or block
5
+ * field. An inline group holds its fields and has no path, since it is not a field. A type in
6
+ * `customTypes` has a custom renderer, so it holds no rows.
7
+ */
8
+ export declare function buildFormOutline(fields: readonly FieldConfig[], value: Record<string, unknown>, customTypes?: ReadonlySet<string>): OutlineNode[];
9
+ /**
10
+ * True when some field, at any depth, is a block field or a list of objects that the form draws
11
+ * itself: a type in `customTypes` has a custom renderer.
12
+ */
13
+ export declare function hasCollapsibleList(fields: readonly FieldConfig[], customTypes?: ReadonlySet<string>): boolean;
@@ -0,0 +1,70 @@
1
+ import { isPlainRecord } from '../validation/field-traversal.js';
2
+ import { formatCanopyPath } from './canopy-path.js';
3
+ import { listItemSecondary, listItemSummary } from './fields/list-item-title.js';
4
+ import { schemaLabel } from './schema-label.js';
5
+ /**
6
+ * The form's outline: each top-level field in form order, holding the rows of a list or block
7
+ * field. An inline group holds its fields and has no path, since it is not a field. A type in
8
+ * `customTypes` has a custom renderer, so it holds no rows.
9
+ */
10
+ export function buildFormOutline(fields, value, customTypes = new Set()) {
11
+ const rowsOf = (field) => {
12
+ const current = value[field.name];
13
+ // A custom renderer draws its own rows, which carry no row paths.
14
+ if (!Array.isArray(current) || customTypes.has(field.type))
15
+ return undefined;
16
+ if (field.type === 'block') {
17
+ const { templates } = field;
18
+ return current.map((block, idx) => {
19
+ const name = isPlainRecord(block) && typeof block.template === 'string' ? block.template : '';
20
+ const template = templates.find((t) => t.name === name);
21
+ return {
22
+ label: template ? schemaLabel(template) : name || 'Unknown block',
23
+ secondary: template && isPlainRecord(block)
24
+ ? listItemSecondary(block.value, template.fields)
25
+ : undefined,
26
+ path: formatCanopyPath([field.name, idx]),
27
+ };
28
+ });
29
+ }
30
+ if (field.type === 'object' && field.list) {
31
+ return current.map((item, idx) => {
32
+ const { title, secondary } = listItemSummary(item, field, idx);
33
+ return { label: title, secondary, path: formatCanopyPath([field.name, idx]) };
34
+ });
35
+ }
36
+ return undefined;
37
+ };
38
+ const nodeOf = (field) => {
39
+ if (field.type === 'group') {
40
+ const group = field;
41
+ return { label: schemaLabel(group), children: group.fields.map(nodeOf) };
42
+ }
43
+ return {
44
+ label: schemaLabel(field),
45
+ path: formatCanopyPath([field.name]),
46
+ children: rowsOf(field),
47
+ };
48
+ };
49
+ return fields.map(nodeOf);
50
+ }
51
+ /**
52
+ * True when some field, at any depth, is a block field or a list of objects that the form draws
53
+ * itself: a type in `customTypes` has a custom renderer.
54
+ */
55
+ export function hasCollapsibleList(fields, customTypes = new Set()) {
56
+ return fields.some((field) => {
57
+ if (customTypes.has(field.type))
58
+ return false;
59
+ if (field.type === 'block')
60
+ return true;
61
+ if (field.type === 'group') {
62
+ return hasCollapsibleList(field.fields, customTypes);
63
+ }
64
+ if (field.type === 'object') {
65
+ const objectField = field;
66
+ return objectField.list === true || hasCollapsibleList(objectField.fields, customTypes);
67
+ }
68
+ return false;
69
+ });
70
+ }
@@ -1,12 +1,15 @@
1
1
  import React from 'react';
2
2
  import type { InternalGroup, UserSearchResult, CanopyGroupId, CanopyUserId } from './types.js';
3
+ export declare const memberCountLabel: (count: number) => string;
3
4
  export interface GroupCardProps {
4
5
  group: InternalGroup;
6
+ /** The group is new or edited and its change is staged, not saved. */
7
+ isUnsaved: boolean;
5
8
  onEdit: (group: InternalGroup) => void;
6
9
  onDelete: (groupId: CanopyGroupId) => void;
7
10
  onAddMember: (groupId: CanopyGroupId, userId: CanopyUserId) => void;
8
11
  onRemoveMember: (groupId: CanopyGroupId, userId: CanopyUserId) => void;
9
- onGetUserMetadata?: (userId: string) => Promise<UserSearchResult | null>;
12
+ onGetUserMetadata: (userId: string) => Promise<UserSearchResult | null>;
10
13
  showUserSearch: boolean;
11
14
  searchQuery: string;
12
15
  searchResults: UserSearchResult[];
@@ -1,8 +1,17 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { ActionIcon, Badge, Group, Paper, Text, Tooltip } from '@mantine/core';
3
+ import { useId } from 'react';
4
+ import { ActionIcon, Badge, Group, Paper, Text, Tooltip, VisuallyHidden } from '@mantine/core';
4
5
  import { IconEdit, IconTrash } from '@tabler/icons-react';
5
6
  import { MemberList } from './MemberList.js';
6
- export const GroupCard = ({ group, onEdit, onDelete, onAddMember, onRemoveMember, onGetUserMetadata, showUserSearch, searchQuery, searchResults, isSearching, searchError, onSearchQueryChange, onShowSearch, onHideSearch, canSearch, }) => {
7
- return (_jsxs(Paper, { withBorder: true, p: "sm", mb: "xs", children: [_jsxs(Group, { justify: "space-between", mb: "sm", children: [_jsxs("div", { style: { flex: 1 }, children: [_jsxs(Group, { gap: "xs", children: [_jsx(Text, { size: "sm", fw: 500, children: group.name }), _jsxs(Badge, { size: "sm", variant: "light", children: [group.members?.length || 0, " members"] })] }), _jsxs(Text, { size: "xs", c: "dimmed", mt: 4, children: ["ID: ", group.id] }), group.description && (_jsx(Text, { size: "xs", c: "dimmed", mt: 4, children: group.description }))] }), _jsxs(Group, { gap: "xs", children: [_jsx(Tooltip, { label: "Edit group", children: _jsx(ActionIcon, { size: "sm", variant: "subtle", onClick: () => onEdit(group), children: _jsx(IconEdit, { size: 16 }) }) }), _jsx(Tooltip, { label: "Delete group", children: _jsx(ActionIcon, { size: "sm", variant: "subtle", color: "red", onClick: () => onDelete(group.id), children: _jsx(IconTrash, { size: 16 }) }) })] })] }), _jsx(MemberList, { groupId: group.id, members: group.members || [], onRemoveMember: onRemoveMember, onAddMember: onAddMember, onGetUserMetadata: onGetUserMetadata, showUserSearch: showUserSearch, searchQuery: searchQuery, searchResults: searchResults, isSearching: isSearching, searchError: searchError, onSearchQueryChange: onSearchQueryChange, onShowSearch: onShowSearch, onHideSearch: onHideSearch, canSearch: canSearch })] }));
7
+ import { isReservedGroup } from '../../authorization/helpers.js';
8
+ export const memberCountLabel = (count) => `${count} ${count === 1 ? 'member' : 'members'}`;
9
+ const reservedDeleteReason = (name) => `"${name}" is a built-in group, so it can't be deleted.`;
10
+ export const GroupCard = ({ group, isUnsaved, onEdit, onDelete, onAddMember, onRemoveMember, onGetUserMetadata, showUserSearch, searchQuery, searchResults, isSearching, searchError, onSearchQueryChange, onShowSearch, onHideSearch, canSearch, }) => {
11
+ const reserved = isReservedGroup(group.id);
12
+ const reservedReasonId = useId();
13
+ return (_jsxs(Paper, { withBorder: true, p: "sm", mb: "xs", children: [_jsxs(Group, { justify: "space-between", mb: "sm", children: [_jsxs("div", { style: { flex: 1 }, children: [_jsxs(Group, { gap: "xs", children: [_jsx(Text, { size: "sm", fw: 500, children: group.name }), _jsx(Badge, { size: "sm", variant: "light", children: memberCountLabel(group.members?.length ?? 0) }), isUnsaved && (_jsx(Badge, { size: "sm", variant: "light", color: "orange", children: "Unsaved" }))] }), _jsxs(Text, { size: "xs", c: "dimmed", mt: 4, children: ["ID: ", group.id] }), group.description && (_jsx(Text, { size: "xs", c: "dimmed", mt: 4, children: group.description }))] }), _jsxs(Group, { gap: "xs", children: [_jsx(Tooltip, { label: `Edit group "${group.name}"`, children: _jsx(ActionIcon, { variant: "subtle", "aria-label": `Edit group "${group.name}"`, onClick: () => onEdit(group), children: _jsx(IconEdit, { size: 16 }) }) }), _jsx(Tooltip, { label: reserved ? reservedDeleteReason(group.name) : `Delete group "${group.name}"`, events: { hover: true, focus: true, touch: true }, children: _jsx(ActionIcon, { variant: "subtle", color: "red", "aria-label": `Delete group "${group.name}"`, "aria-describedby": reserved ? reservedReasonId : undefined, "data-disabled": reserved ? true : undefined, "aria-disabled": reserved ? true : undefined, onClick: () => {
14
+ if (!reserved)
15
+ onDelete(group.id);
16
+ }, children: _jsx(IconTrash, { size: 16 }) }) }), reserved && (_jsx(VisuallyHidden, { id: reservedReasonId, children: reservedDeleteReason(group.name) }))] })] }), _jsx(MemberList, { groupId: group.id, members: group.members || [], onRemoveMember: onRemoveMember, onAddMember: onAddMember, onGetUserMetadata: onGetUserMetadata, showUserSearch: showUserSearch, searchQuery: searchQuery, searchResults: searchResults, isSearching: isSearching, searchError: searchError, onSearchQueryChange: onSearchQueryChange, onShowSearch: onShowSearch, onHideSearch: onHideSearch, canSearch: canSearch })] }));
8
17
  };