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,215 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useRef, useState } from 'react';
4
+ import { CANOPY_PREVIEW_ERROR, CANOPY_PREVIEW_HIGHLIGHT, CANOPY_PREVIEW_MARKS, CANOPY_PREVIEW_MESSAGE, CANOPY_PREVIEW_READY, isOpaqueOrigin, MARK_REPORT_LIMITS, resolveMessageOrigin, } from './preview-bridge.js';
5
+ /**
6
+ * How long after the iframe's `load` the preview has to send its ready message before the frame
7
+ * says live updates are off. Ready can also arrive before `load`, which waits for images too.
8
+ */
9
+ const READY_TIMEOUT_MS = 5000;
10
+ const LIVE_UPDATES_OFF_HELP = "The preview didn't connect, so your edits won't show in it until it reconnects. Retry reloads the preview; your edits are kept.";
11
+ const visuallyHidden = {
12
+ position: 'absolute',
13
+ width: 1,
14
+ height: 1,
15
+ padding: 0,
16
+ margin: -1,
17
+ overflow: 'hidden',
18
+ clip: 'rect(0, 0, 0, 0)',
19
+ whiteSpace: 'nowrap',
20
+ border: 0,
21
+ };
22
+ const isMarkPaths = (paths) => Array.isArray(paths) &&
23
+ paths.length <= MARK_REPORT_LIMITS.paths &&
24
+ paths.every((path) => typeof path === 'string' && path.length <= MARK_REPORT_LIMITS.pathLength);
25
+ const sendDraftUpdate = (iframe, message, targetOrigin) => {
26
+ if (!iframe?.contentWindow)
27
+ return;
28
+ const target = targetOrigin ?? resolveMessageOrigin(iframe.src);
29
+ if (isOpaqueOrigin(target))
30
+ return;
31
+ iframe.contentWindow.postMessage(message, target);
32
+ };
33
+ /**
34
+ * Lightweight iframe wrapper to keep the preview in sync with form state.
35
+ * It posts the latest draft data to the iframe after load and when data changes. A progress bar
36
+ * runs until the preview's ready message arrives; when none does, a "Live updates off" chip offers
37
+ * to reload the preview.
38
+ */
39
+ export const PreviewFrame = ({ src, path, data, isLoading, className, style, highlightEnabled, onPreviewError, onMarks, assetBase, iframeStyle, onReload, }) => {
40
+ const iframeRef = useRef(null);
41
+ // Pin the preview origin from the src prop: outbound messages target it (never '*'),
42
+ // and inbound messages must come from it. An iframe that navigates cross-origin
43
+ // silently stops participating in the bridge.
44
+ const previewOrigin = resolveMessageOrigin(src);
45
+ // Only the ready message clears the progress bar: `onLoad` can post the draft before the
46
+ // preview's listener exists, so only the re-post that ready triggers is sure to land.
47
+ const [handshake, setHandshake] = useState('waiting');
48
+ const [loaded, setLoaded] = useState(false);
49
+ // Retry and a new src each mount a fresh iframe rather than navigating the old one, so a late
50
+ // ready from the page it replaces fails the source check, and a late load has no handler.
51
+ const [retries, setRetries] = useState(0);
52
+ // A new src is a new page, with a handshake of its own.
53
+ const [prevSrc, setPrevSrc] = useState(src);
54
+ if (src !== prevSrc) {
55
+ setPrevSrc(src);
56
+ setHandshake('waiting');
57
+ setLoaded(false);
58
+ }
59
+ useEffect(() => {
60
+ if (!loaded || handshake !== 'waiting')
61
+ return;
62
+ // Functional, so a ready batched into the same render as this callback still wins.
63
+ const timer = setTimeout(() => setHandshake((current) => (current === 'waiting' ? 'missing' : current)), READY_TIMEOUT_MS);
64
+ return () => clearTimeout(timer);
65
+ }, [loaded, handshake]);
66
+ const retry = () => {
67
+ setHandshake('waiting');
68
+ setLoaded(false);
69
+ setRetries((count) => count + 1);
70
+ };
71
+ const hasDraft = data !== undefined;
72
+ const syncPending = hasDraft && handshake === 'waiting';
73
+ const liveUpdatesOff = hasDraft && handshake === 'missing';
74
+ // Inject the progress bar keyframe animation once per page.
75
+ useEffect(() => {
76
+ const styleId = 'canopycms-preview-sync-style';
77
+ if (!document.getElementById(styleId)) {
78
+ const el = document.createElement('style');
79
+ el.id = styleId;
80
+ el.textContent = `@keyframes canopy-preview-sync { 0% { transform: translateX(-100%); } 100% { transform: translateX(250%); } }`;
81
+ document.head.appendChild(el);
82
+ }
83
+ }, []);
84
+ const post = () => {
85
+ if (data === undefined)
86
+ return;
87
+ const sameOrigin = previewOrigin === window.location.origin;
88
+ sendDraftUpdate(iframeRef.current, {
89
+ type: CANOPY_PREVIEW_MESSAGE,
90
+ path,
91
+ data,
92
+ isLoading,
93
+ ...(assetBase !== undefined && sameOrigin ? { assetBase } : {}),
94
+ }, previewOrigin);
95
+ };
96
+ const postHighlight = () => {
97
+ if (!iframeRef.current?.contentWindow)
98
+ return;
99
+ if (isOpaqueOrigin(previewOrigin))
100
+ return;
101
+ const msg = {
102
+ type: CANOPY_PREVIEW_HIGHLIGHT,
103
+ enabled: Boolean(highlightEnabled),
104
+ };
105
+ iframeRef.current.contentWindow.postMessage(msg, previewOrigin);
106
+ };
107
+ // Keep refs pointing at the latest closures so the message handler below never goes stale.
108
+ const postRef = useRef(post);
109
+ const postHighlightRef = useRef(postHighlight);
110
+ const onPreviewErrorRef = useRef(onPreviewError);
111
+ const onMarksRef = useRef(onMarks);
112
+ useEffect(() => {
113
+ postRef.current = post;
114
+ postHighlightRef.current = postHighlight;
115
+ onPreviewErrorRef.current = onPreviewError;
116
+ onMarksRef.current = onMarks;
117
+ });
118
+ useEffect(() => {
119
+ post();
120
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- post is tracked via ref
121
+ }, [data, isLoading]);
122
+ useEffect(() => {
123
+ postHighlight();
124
+ // eslint-disable-next-line react-hooks/exhaustive-deps -- postHighlight is tracked via ref
125
+ }, [highlightEnabled]);
126
+ // When the preview page's React effects have run and its message listener is ready,
127
+ // it sends CANOPY_PREVIEW_READY. We respond with the current data so the preview
128
+ // receives the draft even if it wasn't ready when onLoad fired.
129
+ useEffect(() => {
130
+ const handleMessage = (event) => {
131
+ if (!iframeRef.current || event.source !== iframeRef.current.contentWindow)
132
+ return;
133
+ // Source check alone is insufficient if the iframe navigated cross-origin.
134
+ if (isOpaqueOrigin(previewOrigin) || event.origin !== previewOrigin)
135
+ return;
136
+ const type = event.data?.type;
137
+ if (type === CANOPY_PREVIEW_READY) {
138
+ postRef.current();
139
+ postHighlightRef.current();
140
+ setHandshake('ready');
141
+ }
142
+ else if (type === CANOPY_PREVIEW_ERROR) {
143
+ const msg = event.data;
144
+ // Shape-check the payload: an adopter passing an Error object (instead of
145
+ // err.message) must not crash the editor when rendered as a React child.
146
+ if (msg.message != null && typeof msg.message !== 'string')
147
+ return;
148
+ const fieldPath = typeof msg.fieldPath === 'string' ? msg.fieldPath : undefined;
149
+ onPreviewErrorRef.current?.(msg.message == null
150
+ ? null
151
+ : { message: msg.message, ...(fieldPath ? { fieldPath } : {}) });
152
+ }
153
+ else if (type === CANOPY_PREVIEW_MARKS) {
154
+ const { count, paths } = event.data;
155
+ if (typeof count === 'number' && Number.isInteger(count) && count >= 0) {
156
+ onMarksRef.current?.({ count, ...(isMarkPaths(paths) ? { paths } : {}) });
157
+ }
158
+ }
159
+ };
160
+ window.addEventListener('message', handleMessage);
161
+ return () => window.removeEventListener('message', handleMessage);
162
+ }, [previewOrigin]);
163
+ return (_jsxs("div", { className: className, style: { position: 'relative', overflow: 'hidden', ...style }, children: [syncPending && (_jsx("div", { role: "progressbar", "aria-label": "Connecting to the preview", style: {
164
+ position: 'absolute',
165
+ top: 0,
166
+ left: 0,
167
+ right: 0,
168
+ height: 3,
169
+ zIndex: 1,
170
+ overflow: 'hidden',
171
+ }, children: _jsx("div", { style: {
172
+ position: 'absolute',
173
+ top: 0,
174
+ left: 0,
175
+ height: '100%',
176
+ width: '40%',
177
+ background: 'var(--mantine-color-blue-filled, #228be6)',
178
+ borderRadius: '0 2px 2px 0',
179
+ animation: 'canopy-preview-sync 1.5s ease-in-out infinite',
180
+ } }) })), _jsx("div", { role: "status", style: { position: 'absolute', top: 8, right: 8, zIndex: 1 }, children: liveUpdatesOff && (_jsxs("div", { style: {
181
+ display: 'flex',
182
+ alignItems: 'center',
183
+ gap: 6,
184
+ padding: '2px 4px 2px 10px',
185
+ borderRadius: 999,
186
+ border: '1px solid var(--mantine-color-default-border)',
187
+ background: 'var(--mantine-color-body)',
188
+ boxShadow: 'var(--mantine-shadow-xs, 0 1px 3px rgba(0, 0, 0, 0.1))',
189
+ color: 'var(--mantine-color-dimmed)',
190
+ fontFamily: 'var(--mantine-font-family, inherit)',
191
+ fontSize: 12,
192
+ lineHeight: '20px',
193
+ }, children: [_jsx("span", { title: LIVE_UPDATES_OFF_HELP, children: "Live updates off" }), _jsx("span", { style: visuallyHidden, children: LIVE_UPDATES_OFF_HELP }), _jsx("button", { type: "button", onClick: onReload ?? retry, title: "Reload the preview", style: {
194
+ border: 'none',
195
+ borderRadius: 999,
196
+ padding: '0 8px',
197
+ background: 'transparent',
198
+ color: 'var(--mantine-color-blue-filled, #228be6)',
199
+ font: 'inherit',
200
+ fontWeight: 600,
201
+ cursor: 'pointer',
202
+ }, children: "Retry" })] })) }), _jsx("iframe", { ref: iframeRef, src: src, title: "Live preview", style: {
203
+ display: 'block',
204
+ position: 'absolute',
205
+ inset: 0,
206
+ width: '100%',
207
+ height: '100%',
208
+ border: 'none',
209
+ ...iframeStyle,
210
+ }, onLoad: () => {
211
+ post();
212
+ postHighlight();
213
+ setLoaded(true);
214
+ } }, `${retries}:${src}`)] }));
215
+ };
@@ -0,0 +1,47 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { PreviewWidth } from './hooks/useEditorLayout.js';
3
+ import { type PreviewMarks } from './PreviewFrame.js';
4
+ import type { InexactMark } from './preview-marks.js';
5
+ import type { PaneArrangement } from './shell/PaneLayout.js';
6
+ import { type PreviewMount } from './preview-path.js';
7
+ export interface PreviewPaneProps {
8
+ src: string;
9
+ /** The page's path for the bridge and the toolbar; defaults to `src`. */
10
+ path?: string;
11
+ /** Where the preview routes are mounted; the toolbar's path leaves out the `previewPrefix`. */
12
+ mount?: PreviewMount;
13
+ data?: unknown;
14
+ isLoading?: unknown;
15
+ highlightEnabled?: boolean;
16
+ assetBase?: string;
17
+ onPreviewError?: (error: {
18
+ message: string;
19
+ fieldPath?: string;
20
+ } | null) => void;
21
+ onMarks?: (marks: PreviewMarks) => void;
22
+ previewWidth: PreviewWidth;
23
+ onPreviewWidthChange: (width: PreviewWidth) => void;
24
+ /** Shown between the toolbar and the preview, such as a preview error. */
25
+ notice?: ReactNode;
26
+ /** With `onHighlightToggle`, the toolbar shows the highlight toggle. */
27
+ onHighlightToggle?: () => void;
28
+ /** The page marked nothing while highlighting; see `usePreviewMarks`. */
29
+ marksNothing?: boolean;
30
+ /** Marks naming no field of the entry, counted in the toolbar only with `showMarkDiagnostics`. */
31
+ inexactMarks?: readonly InexactMark[];
32
+ /** Admins only: diagnostics of the site's markup are no editor's to act on. */
33
+ showMarkDiagnostics?: boolean;
34
+ /** Shapes the size readout shown while the divider is dragged. */
35
+ layout?: PaneArrangement;
36
+ /** With `onMaximizedChange`, the toolbar offers Maximize, and Esc restores. */
37
+ maximized?: boolean;
38
+ onMaximizedChange?: (maximized: boolean) => void;
39
+ /** A drag of the preview/form divider is under way: the preview shows its size over itself. */
40
+ resizing?: boolean;
41
+ }
42
+ /**
43
+ * The preview region: a toolbar (path, width, reload, saved version) over a `PreviewFrame`. A
44
+ * fixed width renders the iframe at that CSS width, so the site's own breakpoints apply, scaled
45
+ * down to fit a narrower pane.
46
+ */
47
+ export declare const PreviewPane: ({ src, path, mount, previewWidth, onPreviewWidthChange, notice, onHighlightToggle, marksNothing, inexactMarks, showMarkDiagnostics, layout, maximized, onMaximizedChange, resizing, ...frameProps }: PreviewPaneProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,147 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useLayoutEffect, useRef, useState } from 'react';
4
+ import { ActionIcon, Box, Group, Select, Text, Tooltip, UnstyledButton, VisuallyHidden, } from '@mantine/core';
5
+ import { useClipboard, useElementSize, useWindowEvent } from '@mantine/hooks';
6
+ import { IconCheck, IconExternalLink, IconRefresh } from '@tabler/icons-react';
7
+ import { PreviewFrame } from './PreviewFrame.js';
8
+ import { HighlightToggle, MaximizeToggle, UnmappedMarksChip } from './PreviewToolbarTools.js';
9
+ import { displayPreviewPath } from './preview-path.js';
10
+ import { computePreviewViewport, formatPreviewWidthReadout, PREVIEW_DEVICE_WIDTHS, } from './preview-scale.js';
11
+ const WIDTH_OPTIONS = [
12
+ { value: 'fit', label: 'Fit', detail: 'Pane width' },
13
+ { value: 'desktop', label: 'Desktop', detail: `${PREVIEW_DEVICE_WIDTHS.desktop} px` },
14
+ { value: 'tablet', label: 'Tablet', detail: `${PREVIEW_DEVICE_WIDTHS.tablet} px` },
15
+ { value: 'mobile', label: 'Mobile', detail: `${PREVIEW_DEVICE_WIDTHS.mobile} px` },
16
+ ];
17
+ const isPreviewWidth = (value) => WIDTH_OPTIONS.some((option) => option.value === value);
18
+ const TEXT_INPUT_TYPES = new Set(['text', 'search', 'email', 'url', 'tel', 'password', 'number']);
19
+ const hasTextToClear = (element) => ((element instanceof HTMLInputElement && TEXT_INPUT_TYPES.has(element.type)) ||
20
+ element instanceof HTMLTextAreaElement) &&
21
+ !element.readOnly &&
22
+ element.value !== '';
23
+ const RELOAD_LABEL = 'Reload preview';
24
+ const OPEN_SAVED_LABEL = 'Open saved version in a new tab';
25
+ /**
26
+ * The preview region: a toolbar (path, width, reload, saved version) over a `PreviewFrame`. A
27
+ * fixed width renders the iframe at that CSS width, so the site's own breakpoints apply, scaled
28
+ * down to fit a narrower pane.
29
+ */
30
+ export const PreviewPane = ({ src, path = src, mount, previewWidth, onPreviewWidthChange, notice, onHighlightToggle, marksNothing, inexactMarks = [], showMarkDiagnostics = false, layout, maximized = false, onMaximizedChange, resizing = false, ...frameProps }) => {
31
+ const { ref: viewportRef, width, height } = useElementSize();
32
+ const rootRef = useRef(null);
33
+ const maximizeRef = useRef(null);
34
+ const restoreRef = useRef(null);
35
+ // Maximize and Restore swap places, so focus follows to the other. Restoring by other means,
36
+ // such as a preview click that focuses a form field, leaves focus where that put it.
37
+ const wasMaximized = useRef(maximized);
38
+ useLayoutEffect(() => {
39
+ if (maximized && !wasMaximized.current)
40
+ restoreRef.current?.focus();
41
+ if (!maximized && wasMaximized.current && document.activeElement === document.body) {
42
+ maximizeRef.current?.focus();
43
+ }
44
+ wasMaximized.current = maximized;
45
+ }, [maximized]);
46
+ // Escape from the editor's shell, or with focus nowhere, restores: a drawer or modal outside it
47
+ // closes on its own Escape, an open popup marks its owner, and a text field with text keeps it.
48
+ // Captured, because an open tooltip's dismiss stops the key on the document. A key inside the
49
+ // preview frame never reaches this window.
50
+ useWindowEvent('keydown', (event) => {
51
+ if (!maximized || event.key !== 'Escape' || event.defaultPrevented)
52
+ return;
53
+ const target = event.target;
54
+ if (!(target instanceof HTMLElement))
55
+ return;
56
+ const inEditor = rootRef.current?.closest('[data-canopy-shell]')?.contains(target);
57
+ if (target !== document.body && !(inEditor ?? rootRef.current?.contains(target)))
58
+ return;
59
+ if (target.isContentEditable || hasTextToClear(target))
60
+ return;
61
+ if (target.closest('[data-mantine-stop-propagation="true"], [aria-haspopup][aria-expanded="true"]'))
62
+ return;
63
+ event.preventDefault();
64
+ onMaximizedChange?.(false);
65
+ }, { capture: true });
66
+ const clipboard = useClipboard({ timeout: 2000 });
67
+ const reloadButtonRef = useRef(null);
68
+ // A dismissed notice takes its focused Close button with it; the toolbar takes the focus back.
69
+ // Focus anywhere else, such as a form field while a draft starts compiling, stays put.
70
+ const hadNotice = useRef(false);
71
+ useEffect(() => {
72
+ if (hadNotice.current && !notice && document.activeElement === document.body) {
73
+ reloadButtonRef.current?.focus();
74
+ }
75
+ hadNotice.current = Boolean(notice);
76
+ }, [notice]);
77
+ // Reloading remounts the frame for a fresh handshake. It drops a reported error too: a page
78
+ // that reports draft errors reports it again once the reloaded page renders the draft.
79
+ const [reloads, setReloads] = useState(0);
80
+ const reload = () => {
81
+ setReloads((count) => count + 1);
82
+ frameProps.onPreviewError?.(null);
83
+ };
84
+ const shownPath = displayPreviewPath(path, mount);
85
+ const viewport = computePreviewViewport(previewWidth, width, height);
86
+ const iframeStyle = previewWidth === 'fit'
87
+ ? undefined
88
+ : {
89
+ inset: 'auto',
90
+ top: 0,
91
+ left: viewport.offsetX,
92
+ width: viewport.frameWidth,
93
+ height: viewport.frameHeight,
94
+ transform: `scale(${viewport.scale})`,
95
+ transformOrigin: '0 0',
96
+ background: 'var(--mantine-color-body)',
97
+ boxShadow: '0 0 0 1px var(--mantine-color-default-border)',
98
+ };
99
+ const copyStatus = clipboard.copied
100
+ ? 'Path copied'
101
+ : clipboard.error
102
+ ? "Couldn't copy the path"
103
+ : '';
104
+ const copyLabel = `Copy path ${shownPath}`;
105
+ return (_jsxs(Box, { ref: rootRef, style: {
106
+ display: 'flex',
107
+ flexDirection: 'column',
108
+ width: '100%',
109
+ height: '100%',
110
+ border: '1px solid var(--mantine-color-default-border)',
111
+ }, children: [_jsxs(Group, { role: "group", "aria-label": "Preview toolbar", "data-testid": "preview-toolbar", gap: 6, px: 6, style: {
112
+ // Wraps to a second row, rather than clipping, in a pane too narrow for one.
113
+ minHeight: 32,
114
+ rowGap: 2,
115
+ paddingBlock: 2,
116
+ flex: '0 0 auto',
117
+ borderBottom: '1px solid var(--mantine-color-default-border)',
118
+ background: 'var(--mantine-color-body)',
119
+ }, children: [_jsx(Tooltip, { label: copyStatus || copyLabel, multiline: true, maw: 360, style: { overflowWrap: 'anywhere' }, children: _jsx(UnstyledButton, { onClick: () => clipboard.copy(shownPath), "aria-label": copyLabel, style: { flex: '1 1 80px', minWidth: 0, borderRadius: 4, padding: '2px 4px' }, children: _jsx(Text, { component: "span", size: "xs", ff: "monospace", truncate: "end", display: "block", children: shownPath }) }) }), _jsx(VisuallyHidden, { role: "status", children: copyStatus }), _jsx(Select, { "aria-label": "Preview width", data: WIDTH_OPTIONS, value: previewWidth, onChange: (value) => {
120
+ if (isPreviewWidth(value))
121
+ onPreviewWidthChange(value);
122
+ }, allowDeselect: false, size: "xs", w: 96, style: { flexShrink: 0 }, styles: { input: { height: 24, minHeight: 24 } }, comboboxProps: { width: 170, position: 'bottom-end' }, renderOption: ({ option, checked }) => (_jsxs(Group, { gap: 6, wrap: "nowrap", w: "100%", children: [_jsx(IconCheck, { "aria-hidden": true, size: 14, style: { visibility: checked ? 'visible' : 'hidden' } }), _jsx("span", { style: { flex: 1 }, children: option.label }), _jsx(Text, { component: "span", size: "xs", children: WIDTH_OPTIONS.find((o) => o.value === option.value)?.detail })] })) }), width > 0 && (_jsx(Text, { size: "xs", c: "dimmed", "data-testid": "preview-width-readout", style: { flexShrink: 0, whiteSpace: 'nowrap', fontVariantNumeric: 'tabular-nums' }, children: formatPreviewWidthReadout(viewport) })), (onHighlightToggle || (showMarkDiagnostics && inexactMarks.length > 0)) && (_jsxs(Group, { gap: 6, wrap: "nowrap", children: [onHighlightToggle && (_jsx(HighlightToggle, { enabled: Boolean(frameProps.highlightEnabled), onToggle: onHighlightToggle, marksNothing: marksNothing })), showMarkDiagnostics && _jsx(UnmappedMarksChip, { marks: inexactMarks })] })), _jsxs(Group, { gap: 6, wrap: "nowrap", children: [onMaximizedChange && (_jsx(MaximizeToggle, { maximized: maximized, onChange: onMaximizedChange, maximizeRef: maximizeRef, restoreRef: restoreRef })), _jsx(Tooltip, { label: RELOAD_LABEL, children: _jsx(ActionIcon, { ref: reloadButtonRef, variant: "subtle", size: "md", "aria-label": RELOAD_LABEL, onClick: reload, children: _jsx(IconRefresh, { size: 16 }) }) }), _jsx(Tooltip, { label: OPEN_SAVED_LABEL, children: _jsx(ActionIcon, { component: "a", href: src, target: "_blank", rel: "noopener noreferrer", variant: "subtle", size: "md", "aria-label": OPEN_SAVED_LABEL, children: _jsx(IconExternalLink, { size: 16 }) }) })] })] }), notice, _jsxs(Box, { ref: viewportRef, pos: "relative", style: { flex: '1 1 auto', minHeight: 0 }, children: [_jsx(PreviewFrame, { src: src, path: path, ...frameProps, onReload: () => {
123
+ // Retry goes with the frame it sits in; the toolbar's reload offers the same action.
124
+ reload();
125
+ reloadButtonRef.current?.focus();
126
+ }, iframeStyle: iframeStyle, style: {
127
+ position: 'absolute',
128
+ inset: 0,
129
+ background: previewWidth === 'fit' ? undefined : 'var(--canopy-surface-muted)',
130
+ } }, reloads), resizing && width > 0 && (_jsx(Box, { "aria-hidden": true, "data-testid": "preview-resize-readout", style: {
131
+ position: 'absolute',
132
+ top: '50%',
133
+ left: '50%',
134
+ transform: 'translate(-50%, -50%)',
135
+ padding: '6px 12px',
136
+ borderRadius: 6,
137
+ background: 'var(--mantine-color-body)',
138
+ color: 'var(--mantine-color-text)',
139
+ boxShadow: 'var(--mantine-shadow-md)',
140
+ fontSize: 'var(--mantine-font-size-lg)',
141
+ fontWeight: 600,
142
+ fontVariantNumeric: 'tabular-nums',
143
+ pointerEvents: 'none',
144
+ }, children: layout === 'stacked'
145
+ ? `${Math.round(width)} × ${Math.round(height)} px`
146
+ : `${Math.round(width)} px` }))] })] }));
147
+ };
@@ -0,0 +1,22 @@
1
+ import type { Ref } from 'react';
2
+ import type { InexactMark } from './preview-marks.js';
3
+ export interface HighlightToggleProps {
4
+ enabled: boolean;
5
+ onToggle: () => void;
6
+ /** The page reported marking nothing while highlighting. */
7
+ marksNothing?: boolean;
8
+ }
9
+ /** Turns preview highlights on and off; says so when the page marks nothing to highlight. */
10
+ export declare function HighlightToggle({ enabled, onToggle, marksNothing }: HighlightToggleProps): import("react/jsx-runtime").JSX.Element;
11
+ /** The admin's count of preview marks that name no field of the entry; see `findInexactMarks`. */
12
+ export declare function UnmappedMarksChip({ marks }: {
13
+ marks: readonly InexactMark[];
14
+ }): import("react/jsx-runtime").JSX.Element | null;
15
+ export interface MaximizeToggleProps {
16
+ maximized: boolean;
17
+ onChange: (maximized: boolean) => void;
18
+ maximizeRef?: Ref<HTMLButtonElement>;
19
+ restoreRef?: Ref<HTMLButtonElement>;
20
+ }
21
+ /** An icon to maximize; once maximized, a labelled Restore, which Esc also does. */
22
+ export declare function MaximizeToggle({ maximized, onChange, maximizeRef, restoreRef, }: MaximizeToggleProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,73 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useId, useRef, useState } from 'react';
4
+ import { ActionIcon, Button, Group, Popover, Stack, Text, Tooltip, UnstyledButton, VisuallyHidden, } from '@mantine/core';
5
+ import { IconArrowsMaximize, IconArrowsMinimize, IconMarquee } from '@tabler/icons-react';
6
+ const HIGHLIGHT_LABEL = 'Highlight fields in the preview';
7
+ const NOTHING_MARKED_NOTE = "This page marks no editable elements, so nothing can be highlighted or clicked to focus. The site's developer can mark them with fieldProps.";
8
+ /** Turns preview highlights on and off; says so when the page marks nothing to highlight. */
9
+ export function HighlightToggle({ enabled, onToggle, marksNothing = false }) {
10
+ const noteId = useId();
11
+ const showNote = enabled && marksNothing;
12
+ return (_jsxs(Group, { gap: 4, wrap: "nowrap", children: [_jsx(Tooltip, { label: HIGHLIGHT_LABEL, children: _jsx(ActionIcon, { variant: enabled ? 'filled' : 'subtle', color: enabled ? 'brand' : 'gray', size: "md", "aria-pressed": enabled, "aria-label": HIGHLIGHT_LABEL, "aria-describedby": showNote ? noteId : undefined, "data-testid": "toggle-highlights-button", onClick: onToggle, children: _jsx(IconMarquee, { size: 16 }) }) }), showNote && (_jsx(Tooltip, { label: NOTHING_MARKED_NOTE, multiline: true, w: 260, children: _jsxs(Text, { size: "xs", c: "dimmed", style: { whiteSpace: 'nowrap' }, children: ["Nothing to highlight", _jsx(VisuallyHidden, { id: noteId, children: NOTHING_MARKED_NOTE })] }) }))] }));
13
+ }
14
+ const LISTED = 3;
15
+ // Module-level, so React never re-calls it on a re-render and pulls focus back while closing.
16
+ const focusOnMount = (node) => node?.focus();
17
+ const markList = (marks) => marks
18
+ .slice(0, LISTED)
19
+ .map((mark) => mark.path || '""')
20
+ .join(', ');
21
+ /** The admin's count of preview marks that name no field of the entry; see `findInexactMarks`. */
22
+ export function UnmappedMarksChip({ marks }) {
23
+ const [opened, setOpened] = useState(false);
24
+ const chipRef = useRef(null);
25
+ // Focus moves to Close as the dropdown mounts. Close and Escape hand it back to the chip; focus
26
+ // leaving otherwise, Tab included, just closes it, so there is no focus trap.
27
+ // Closed when the marks run out, so their return never reopens it and takes focus.
28
+ if (marks.length === 0) {
29
+ if (opened)
30
+ setOpened(false);
31
+ return null;
32
+ }
33
+ const one = marks.length === 1;
34
+ const closeToChip = () => {
35
+ setOpened(false);
36
+ chipRef.current?.focus();
37
+ };
38
+ return (_jsxs(Popover, { opened: opened, onChange: setOpened, closeOnEscape: false, width: 300, position: "bottom-end", withArrow: true, shadow: "md", children: [_jsx(Popover.Target, { children: _jsxs(UnstyledButton, { ref: chipRef, "data-testid": "preview-unmapped-chip",
39
+ // A controlled Popover's target toggles nothing itself.
40
+ // Pressed while open, it keeps focus in the dropdown, whose blur would close it first
41
+ // and let this click reopen it.
42
+ onMouseDown: (event) => {
43
+ if (opened)
44
+ event.preventDefault();
45
+ }, onClick: () => (opened ? closeToChip() : setOpened(true)), style: {
46
+ flexShrink: 0,
47
+ borderRadius: 999,
48
+ minHeight: 24,
49
+ padding: '0 8px',
50
+ fontSize: 'var(--mantine-font-size-xs)',
51
+ fontWeight: 600,
52
+ whiteSpace: 'nowrap',
53
+ color: 'var(--mantine-color-text)',
54
+ background: 'var(--canopy-count-bg-orange)',
55
+ }, children: [marks.length, " unmapped", _jsxs(VisuallyHidden, { children: [" preview ", one ? 'mark' : 'marks'] })] }) }), _jsx(Popover.Dropdown, { onKeyDown: (event) => {
56
+ if (event.key === 'Escape')
57
+ closeToChip();
58
+ }, onBlur: (event) => {
59
+ // Not when the window itself loses focus, such as to the browser's console.
60
+ if (document.hasFocus() && !event.currentTarget.contains(event.relatedTarget)) {
61
+ setOpened(false);
62
+ }
63
+ }, children: _jsxs(Stack, { gap: 6, children: [_jsx(Text, { size: "sm", fw: 600, children: "Unmapped preview marks" }), _jsxs(Text, { size: "sm", children: [one
64
+ ? "One element on this page carries a field mark that doesn't match a field of this entry: "
65
+ : `${marks.length} elements on this page carry field marks that don't match a field of this entry: `, _jsx(Text, { component: "span", ff: "monospace", size: "xs", style: { overflowWrap: 'anywhere' }, children: markList(marks) }), marks.length > LISTED ? `, and ${marks.length - LISTED} more` : '', ".", ' ', one
66
+ ? "It's outlined, and clicking it focuses its nearest field, if it has one."
67
+ : "They're outlined, and clicking one focuses its nearest field, if it has one."] }), _jsxs(Text, { size: "sm", children: ["The browser console names the nearest field of ", one ? 'it' : 'each', ", for the site's developer to correct in its fieldProps."] }), _jsx(Group, { justify: "flex-end", children: _jsx(Button, { ref: focusOnMount, size: "compact-sm", variant: "default", onClick: closeToChip, children: "Close" }) })] }) })] }));
68
+ }
69
+ const MAXIMIZE_LABEL = 'Maximize preview';
70
+ /** An icon to maximize; once maximized, a labelled Restore, which Esc also does. */
71
+ export function MaximizeToggle({ maximized, onChange, maximizeRef, restoreRef, }) {
72
+ return maximized ? (_jsx(Tooltip, { label: "Show the form again \u00B7 Esc", children: _jsx(Button, { ref: restoreRef, size: "compact-sm", variant: "default", leftSection: _jsx(IconArrowsMinimize, { size: 14 }), "aria-keyshortcuts": "Escape", "data-testid": "preview-restore-button", onClick: () => onChange(false), children: "Restore" }) })) : (_jsx(Tooltip, { label: MAXIMIZE_LABEL, children: _jsx(ActionIcon, { ref: maximizeRef, variant: "subtle", size: "md", "aria-label": MAXIMIZE_LABEL, "data-testid": "preview-maximize-button", onClick: () => onChange(true), children: _jsx(IconArrowsMaximize, { size: 16 }) }) }));
73
+ }
@@ -1,5 +1,6 @@
1
1
  export interface SystemHealthPanelProps {
2
2
  opened: boolean;
3
3
  onClose: () => void;
4
+ returnFocusTo?: () => HTMLElement | null;
4
5
  }
5
- export declare function SystemHealthPanel({ opened, onClose }: SystemHealthPanelProps): import("react/jsx-runtime").JSX.Element;
6
+ export declare function SystemHealthPanel({ opened, onClose, returnFocusTo }: SystemHealthPanelProps): import("react/jsx-runtime").JSX.Element;