@cosmicdrift/kumiko-bundled-features 0.362.0 → 0.364.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 (468) hide show
  1. package/dist/admin-shell/feature.d.ts +3 -0
  2. package/dist/admin-shell/feature.js +6 -1
  3. package/dist/agent-tools/agent-manifest.js +2 -1
  4. package/dist/agent-tools/filter-ops.d.ts +1 -1
  5. package/dist/agent-tools/filter-ops.js +1 -3
  6. package/dist/agent-tools/tool-dispatch.js +2 -1
  7. package/dist/audit/handlers/list.query.js +9 -5
  8. package/dist/auth-email-password/bootstrap.d.ts +8 -5
  9. package/dist/auth-email-password/bootstrap.js +12 -4
  10. package/dist/auth-email-password/email-rate-limits.d.ts +4 -0
  11. package/dist/auth-email-password/email-rate-limits.js +13 -0
  12. package/dist/auth-email-password/email-templates.d.ts +4 -26
  13. package/dist/auth-email-password/email-templates.js +9 -101
  14. package/dist/auth-email-password/feature.js +24 -6
  15. package/dist/auth-email-password/handlers/change-password.write.d.ts +1 -1
  16. package/dist/auth-email-password/handlers/change-password.write.js +6 -2
  17. package/dist/auth-email-password/handlers/confirm-account-unlock.write.d.ts +1 -1
  18. package/dist/auth-email-password/handlers/invite-accept-with-login.write.d.ts +1 -1
  19. package/dist/auth-email-password/handlers/invite-accept.write.d.ts +1 -1
  20. package/dist/auth-email-password/handlers/invite-create.write.d.ts +2 -2
  21. package/dist/auth-email-password/handlers/invite-create.write.js +4 -4
  22. package/dist/auth-email-password/handlers/invite-signup-complete.write.d.ts +1 -1
  23. package/dist/auth-email-password/handlers/login.write.d.ts +1 -1
  24. package/dist/auth-email-password/handlers/logout.write.d.ts +1 -1
  25. package/dist/auth-email-password/handlers/logout.write.js +6 -2
  26. package/dist/auth-email-password/handlers/request-account-unlock.write.d.ts +1 -1
  27. package/dist/auth-email-password/handlers/request-account-unlock.write.js +2 -4
  28. package/dist/auth-email-password/handlers/request-email-verification.write.d.ts +1 -1
  29. package/dist/auth-email-password/handlers/request-email-verification.write.js +2 -4
  30. package/dist/auth-email-password/handlers/request-password-reset.write.d.ts +1 -1
  31. package/dist/auth-email-password/handlers/request-password-reset.write.js +2 -4
  32. package/dist/auth-email-password/handlers/reset-password.write.d.ts +1 -1
  33. package/dist/auth-email-password/handlers/signup-confirm.write.d.ts +1 -1
  34. package/dist/auth-email-password/handlers/signup-confirm.write.js +3 -4
  35. package/dist/auth-email-password/handlers/signup-request.write.d.ts +1 -1
  36. package/dist/auth-email-password/handlers/signup-request.write.js +2 -1
  37. package/dist/auth-email-password/handlers/switch-tenant-mfa-gate.write.d.ts +1 -1
  38. package/dist/auth-email-password/handlers/token-request-handler.d.ts +2 -3
  39. package/dist/auth-email-password/handlers/token-request-handler.js +2 -2
  40. package/dist/auth-email-password/handlers/verify-email.write.d.ts +1 -1
  41. package/dist/auth-email-password/index.d.ts +2 -2
  42. package/dist/auth-email-password/index.js +1 -1
  43. package/dist/auth-email-password/magic-link-mail.d.ts +3 -2
  44. package/dist/auth-email-password/magic-link-mail.js +19 -14
  45. package/dist/auth-email-password/mail-notifications.d.ts +32 -0
  46. package/dist/auth-email-password/mail-notifications.js +116 -0
  47. package/dist/auth-email-password/signup-activation.d.ts +1 -1
  48. package/dist/auth-email-password/signup-activation.js +2 -3
  49. package/dist/auth-email-password/web/auth-gate.js +16 -4
  50. package/dist/auth-foundation/types.js +2 -8
  51. package/dist/auth-mfa/feature.js +4 -4
  52. package/dist/auth-mfa/handlers/disable.write.d.ts +1 -1
  53. package/dist/auth-mfa/handlers/enable-confirm-preauth.write.d.ts +1 -1
  54. package/dist/auth-mfa/handlers/enable-confirm.write.d.ts +1 -1
  55. package/dist/auth-mfa/handlers/enable-start-preauth.write.d.ts +1 -1
  56. package/dist/auth-mfa/handlers/enable-start.write.d.ts +1 -1
  57. package/dist/auth-mfa/handlers/regenerate-recovery.write.d.ts +1 -1
  58. package/dist/auth-mfa/handlers/verify.write.d.ts +1 -1
  59. package/dist/auth-mfa/hmac-token-codec.js +4 -4
  60. package/dist/auth-mfa/mfa-challenge-token.js +3 -3
  61. package/dist/auth-mfa/mfa-preauth-setup-token.js +3 -3
  62. package/dist/auth-mfa/mfa-setup-token.js +8 -8
  63. package/dist/billing-foundation/constants.d.ts +3 -3
  64. package/dist/billing-foundation/constants.js +5 -4
  65. package/dist/billing-foundation/consumer-protection/confirmation-mail.d.ts +32 -14
  66. package/dist/billing-foundation/consumer-protection/confirmation-mail.js +74 -32
  67. package/dist/billing-foundation/consumer-protection/consent-gate.d.ts +3 -0
  68. package/dist/billing-foundation/consumer-protection/consent-gate.js +21 -2
  69. package/dist/billing-foundation/consumer-protection/issue-confirmation.js +3 -3
  70. package/dist/billing-foundation/consumer-protection/mail-notifications.d.ts +8 -0
  71. package/dist/billing-foundation/consumer-protection/mail-notifications.js +95 -0
  72. package/dist/billing-foundation/consumer-protection/register-consent.js +2 -0
  73. package/dist/billing-foundation/consumer-protection/register-termination.js +11 -1
  74. package/dist/billing-foundation/consumer-protection/termination-mail.d.ts +25 -13
  75. package/dist/billing-foundation/consumer-protection/termination-mail.js +11 -23
  76. package/dist/billing-foundation/consumer-protection/termination-notify.js +2 -2
  77. package/dist/billing-foundation/consumer-protection/termination-pages.js +1 -3
  78. package/dist/billing-foundation/consumer-protection/termination-receipt-limit.d.ts +6 -0
  79. package/dist/billing-foundation/consumer-protection/termination-receipt-limit.js +34 -0
  80. package/dist/billing-foundation/consumer-protection/termination-record.d.ts +2 -0
  81. package/dist/billing-foundation/consumer-protection/termination-record.js +7 -1
  82. package/dist/billing-foundation/consumer-protection/termination-request.js +31 -21
  83. package/dist/billing-foundation/consumer-protection/termination-texts.d.ts +1 -1
  84. package/dist/billing-foundation/consumer-protection/termination-texts.js +6 -0
  85. package/dist/billing-foundation/consumer-protection/withdrawal-period.d.ts +10 -0
  86. package/dist/billing-foundation/consumer-protection/withdrawal-period.js +26 -0
  87. package/dist/billing-foundation/handlers/create-checkout-session.write.js +11 -5
  88. package/dist/billing-foundation/handlers/process-event.write.js +12 -8
  89. package/dist/billing-foundation/handlers/process-payment-event.write.js +1 -1
  90. package/dist/billing-foundation/i18n.js +3 -0
  91. package/dist/billing-foundation/subscription-tier-sync.d.ts +7 -1
  92. package/dist/billing-foundation/subscription-tier-sync.js +16 -9
  93. package/dist/billing-foundation/types.d.ts +7 -2
  94. package/dist/cap-counter/calendar-cap-usage-reservation.js +2 -0
  95. package/dist/cap-counter/enforce-cap.d.ts +18 -1
  96. package/dist/cap-counter/enforce-cap.js +49 -6
  97. package/dist/cap-counter/index.d.ts +1 -1
  98. package/dist/cap-counter/index.js +1 -1
  99. package/dist/cap-counter/with-cap-enforcement.d.ts +2 -0
  100. package/dist/cap-overview/handlers/tenant-caps-list.query.js +2 -1
  101. package/dist/cap-overview/web/cap-usage-cell.js +5 -4
  102. package/dist/channel-email/email-channel.d.ts +2 -2
  103. package/dist/channel-email/email-channel.js +101 -26
  104. package/dist/channel-email/feature.js +3 -3
  105. package/dist/channel-email/index.d.ts +1 -1
  106. package/dist/channel-email/index.js +1 -1
  107. package/dist/channel-email/pii-guard.js +10 -0
  108. package/dist/channel-email/smtp-transport.js +13 -0
  109. package/dist/channel-email/types.d.ts +8 -0
  110. package/dist/channel-in-app/handlers/mark-all-read.write.d.ts +1 -1
  111. package/dist/channel-in-app/handlers/mark-read.write.d.ts +1 -1
  112. package/dist/compliance-profiles/handlers/set-profile.write.d.ts +1 -1
  113. package/dist/config/handlers/reset.write.d.ts +1 -1
  114. package/dist/config/handlers/set.write.d.ts +1 -1
  115. package/dist/config/handlers/set.write.js +3 -4
  116. package/dist/config/resolver.d.ts +1 -0
  117. package/dist/config/resolver.js +11 -14
  118. package/dist/config/write-helpers.d.ts +2 -0
  119. package/dist/config/write-helpers.js +19 -0
  120. package/dist/crypto-shredding/handlers/forget-subject.write.d.ts +1 -1
  121. package/dist/crypto-shredding/handlers/forget-subject.write.js +29 -19
  122. package/dist/custom-fields/handlers/update-tenant-field.write.js +0 -1
  123. package/dist/custom-fields/lib/value-schema.js +10 -11
  124. package/dist/custom-fields/wire-user-data-rights.js +7 -6
  125. package/dist/data-retention/index.d.ts +1 -0
  126. package/dist/data-retention/index.js +1 -0
  127. package/dist/data-retention/run-retention-cleanup.js +6 -6
  128. package/dist/delivery/attachment-ref.d.ts +41 -0
  129. package/dist/delivery/attachment-ref.js +78 -0
  130. package/dist/delivery/channel-context.d.ts +8 -4
  131. package/dist/delivery/channel-context.js +94 -2
  132. package/dist/delivery/constants.d.ts +1 -0
  133. package/dist/delivery/constants.js +1 -0
  134. package/dist/delivery/delivery-service.d.ts +4 -1
  135. package/dist/delivery/delivery-service.js +38 -32
  136. package/dist/delivery/feature.js +1 -1
  137. package/dist/delivery/handlers/resubscribe-address.write.d.ts +1 -1
  138. package/dist/delivery/handlers/resubscribe-user.write.d.ts +1 -1
  139. package/dist/delivery/handlers/set-preference.write.d.ts +1 -1
  140. package/dist/delivery/handlers/unsubscribe-address.write.d.ts +1 -1
  141. package/dist/delivery/handlers/unsubscribe-user.write.d.ts +1 -1
  142. package/dist/delivery/index.d.ts +5 -2
  143. package/dist/delivery/index.js +4 -1
  144. package/dist/delivery/jobs.js +66 -14
  145. package/dist/delivery/notify-factory.js +4 -1
  146. package/dist/delivery/testing.d.ts +4 -1
  147. package/dist/delivery/types.d.ts +26 -14
  148. package/dist/delivery/unsubscribe.js +4 -1
  149. package/dist/derivatives-sharp/render.js +1 -18
  150. package/dist/document-ingest-foundation/pages.js +4 -4
  151. package/dist/feature-toggles/handlers/set.write.d.ts +1 -1
  152. package/dist/feature-toggles/toggle-sync-signal.js +4 -4
  153. package/dist/file-derivatives/handlers/public-variant.query.js +1 -1
  154. package/dist/file-foundation/index.d.ts +1 -0
  155. package/dist/file-foundation/index.js +1 -0
  156. package/dist/file-foundation/read-file-ref-content.d.ts +27 -0
  157. package/dist/file-foundation/read-file-ref-content.js +51 -0
  158. package/dist/files-tenant-data/hooks.js +4 -0
  159. package/dist/folders/web/folder-manager.js +3 -2
  160. package/dist/form-draft/db/queries/cleanup.js +4 -4
  161. package/dist/form-draft/db/queries/draft-count.js +2 -2
  162. package/dist/form-draft/db/queries/owned-file-refs.js +2 -2
  163. package/dist/form-draft/handlers/discard.write.d.ts +1 -1
  164. package/dist/form-draft/handlers/save.write.d.ts +1 -1
  165. package/dist/form-draft/release-file-refs.js +3 -2
  166. package/dist/inbound-mail-foundation/handlers/connect-account.write.js +1 -1
  167. package/dist/inbound-mail-foundation/handlers/ingest-message.write.js +6 -6
  168. package/dist/inbound-mail-foundation/handlers/scope-visibility.d.ts +1 -1
  169. package/dist/inbound-mail-foundation/oauth-access-token.js +8 -3
  170. package/dist/inbound-mail-foundation/oauth-state.js +7 -7
  171. package/dist/inbound-mail-foundation/types.js +4 -4
  172. package/dist/inbound-mail-foundation/watch-supervisor.js +24 -13
  173. package/dist/inbound-provider-imap/imap-client.js +4 -3
  174. package/dist/jobs/db/queries/stale-run-sweep.d.ts +1 -1
  175. package/dist/jobs/db/queries/stale-run-sweep.js +12 -5
  176. package/dist/jobs/feature.js +5 -3
  177. package/dist/jobs/handlers/list.query.js +3 -1
  178. package/dist/jobs/handlers/retry.write.d.ts +1 -1
  179. package/dist/jobs/handlers/stale-run-sweep.job.d.ts +1 -1
  180. package/dist/jobs/handlers/stale-run-sweep.job.js +2 -2
  181. package/dist/jobs/handlers/trigger.write.d.ts +1 -1
  182. package/dist/jobs/job-run-logger.js +32 -10
  183. package/dist/jobs/tenant-job-run-table.js +3 -2
  184. package/dist/ledger/entity.js +3 -1
  185. package/dist/ledger/recurring.js +1 -3
  186. package/dist/managed-pages/branding.d.ts +2 -0
  187. package/dist/managed-pages/branding.js +24 -2
  188. package/dist/managed-pages/feature.js +1 -0
  189. package/dist/managed-pages/handlers/set.write.d.ts +1 -1
  190. package/dist/managed-pages/i18n.js +1 -0
  191. package/dist/managed-pages/screens/branding-screen.js +8 -1
  192. package/dist/page-render/branding.d.ts +1 -0
  193. package/dist/page-render/branding.js +1 -0
  194. package/dist/page-render/markdown.js +1 -1
  195. package/dist/personal-access-tokens/feature.js +1 -1
  196. package/dist/personal-access-tokens/handlers/create.write.d.ts +1 -1
  197. package/dist/personal-access-tokens/handlers/list.query.js +2 -1
  198. package/dist/personal-access-tokens/handlers/revoke.write.d.ts +1 -1
  199. package/dist/personal-access-tokens/revoke-for-user.js +2 -1
  200. package/dist/renderer-foundation/api.d.ts +13 -13
  201. package/dist/renderer-foundation/api.js +1 -1
  202. package/dist/renderer-foundation/constants.js +2 -4
  203. package/dist/renderer-foundation/feature.js +7 -7
  204. package/dist/renderer-foundation/index.d.ts +2 -1
  205. package/dist/renderer-foundation/index.js +1 -0
  206. package/dist/renderer-foundation/types.d.ts +94 -32
  207. package/dist/renderer-pdf/feature.js +7 -1
  208. package/dist/renderer-pdf/render-table-pdf.d.ts +27 -33
  209. package/dist/renderer-pdf/render-table-pdf.js +95 -34
  210. package/dist/secrets/feature.js +4 -3
  211. package/dist/secrets/handlers/delete.write.d.ts +1 -1
  212. package/dist/secrets/handlers/set.write.d.ts +1 -1
  213. package/dist/secrets/secrets-context.js +15 -3
  214. package/dist/sessions/db/queries/cleanup.js +2 -2
  215. package/dist/sessions/feature.js +1 -1
  216. package/dist/sessions/handlers/list.query.js +2 -1
  217. package/dist/sessions/handlers/revoke-all-for-user.write.d.ts +1 -1
  218. package/dist/sessions/handlers/revoke-all-others.write.d.ts +1 -1
  219. package/dist/sessions/handlers/revoke.write.d.ts +1 -1
  220. package/dist/shared/attachment-file-name.d.ts +3 -0
  221. package/dist/shared/attachment-file-name.js +35 -0
  222. package/dist/shared/chunked-entity-migration.d.ts +1 -0
  223. package/dist/shared/chunked-entity-migration.js +1 -1
  224. package/dist/shared/index.d.ts +3 -0
  225. package/dist/shared/index.js +3 -0
  226. package/dist/shared/is-tenant-db.js +1 -1
  227. package/dist/shared/mail-template-body.d.ts +7 -0
  228. package/dist/shared/mail-template-body.js +27 -0
  229. package/dist/shared/sharp-input-limits.d.ts +6 -0
  230. package/dist/shared/sharp-input-limits.js +22 -0
  231. package/dist/shared/signup-handover.js +2 -2
  232. package/dist/subscription-stripe/plugin-methods.js +18 -8
  233. package/dist/subscription-stripe/verify-webhook.d.ts +1 -1
  234. package/dist/tags/handlers/assign-tag.write.js +3 -1
  235. package/dist/tags/web/tag-chip.js +2 -0
  236. package/dist/template-resolver/api.d.ts +30 -2
  237. package/dist/template-resolver/api.js +42 -6
  238. package/dist/template-resolver/compile-document-body.d.ts +12 -0
  239. package/dist/template-resolver/compile-document-body.js +205 -0
  240. package/dist/template-resolver/constants.d.ts +13 -4
  241. package/dist/template-resolver/constants.js +32 -10
  242. package/dist/template-resolver/document-sanitizer.d.ts +32 -0
  243. package/dist/template-resolver/document-sanitizer.js +201 -0
  244. package/dist/template-resolver/document-schema.d.ts +21 -0
  245. package/dist/template-resolver/document-schema.js +316 -0
  246. package/dist/template-resolver/feature.d.ts +20 -0
  247. package/dist/template-resolver/feature.js +53 -6
  248. package/dist/template-resolver/handlers/bundle-import.d.ts +20 -0
  249. package/dist/template-resolver/handlers/bundle-import.js +147 -0
  250. package/dist/template-resolver/handlers/collection-set.write.d.ts +1 -1
  251. package/dist/template-resolver/handlers/collection-set.write.js +25 -2
  252. package/dist/template-resolver/handlers/copy-locale.write.d.ts +19 -0
  253. package/dist/template-resolver/handlers/copy-locale.write.js +134 -0
  254. package/dist/template-resolver/handlers/diff-to-system.query.d.ts +22 -0
  255. package/dist/template-resolver/handlers/diff-to-system.query.js +30 -0
  256. package/dist/template-resolver/handlers/discard-draft.write.d.ts +13 -0
  257. package/dist/template-resolver/handlers/discard-draft.write.js +37 -0
  258. package/dist/template-resolver/handlers/export-bundle.query.d.ts +35 -0
  259. package/dist/template-resolver/handlers/export-bundle.query.js +118 -0
  260. package/dist/template-resolver/handlers/find-by-id.query.d.ts +2 -0
  261. package/dist/template-resolver/handlers/find-by-id.query.js +9 -6
  262. package/dist/template-resolver/handlers/import-bundle-system.write.d.ts +39 -0
  263. package/dist/template-resolver/handlers/import-bundle-system.write.js +36 -0
  264. package/dist/template-resolver/handlers/import-bundle.write.d.ts +40 -0
  265. package/dist/template-resolver/handlers/import-bundle.write.js +19 -0
  266. package/dist/template-resolver/handlers/layout-source.query.d.ts +31 -0
  267. package/dist/template-resolver/handlers/layout-source.query.js +87 -0
  268. package/dist/template-resolver/handlers/list.query.d.ts +4 -1
  269. package/dist/template-resolver/handlers/list.query.js +9 -8
  270. package/dist/template-resolver/handlers/override-diff.d.ts +20 -0
  271. package/dist/template-resolver/handlers/override-diff.js +41 -0
  272. package/dist/template-resolver/handlers/overview.query.d.ts +65 -0
  273. package/dist/template-resolver/handlers/overview.query.js +205 -0
  274. package/dist/template-resolver/handlers/preview.query.d.ts +12 -0
  275. package/dist/template-resolver/handlers/preview.query.js +24 -0
  276. package/dist/template-resolver/handlers/reset-to-system.write.d.ts +8 -0
  277. package/dist/template-resolver/handlers/reset-to-system.write.js +50 -0
  278. package/dist/template-resolver/handlers/resource-link-pdf.write.d.ts +8 -0
  279. package/dist/template-resolver/handlers/resource-link-pdf.write.js +32 -0
  280. package/dist/template-resolver/handlers/resource-remove.write.d.ts +9 -0
  281. package/dist/template-resolver/handlers/resource-remove.write.js +44 -0
  282. package/dist/template-resolver/handlers/resource-shared.d.ts +9 -0
  283. package/dist/template-resolver/handlers/resource-shared.js +14 -0
  284. package/dist/template-resolver/handlers/resource-upload.write.d.ts +13 -0
  285. package/dist/template-resolver/handlers/resource-upload.write.js +98 -0
  286. package/dist/template-resolver/handlers/send-test.write.d.ts +13 -0
  287. package/dist/template-resolver/handlers/send-test.write.js +108 -0
  288. package/dist/template-resolver/handlers/set.write.d.ts +5 -2
  289. package/dist/template-resolver/handlers/set.write.js +25 -3
  290. package/dist/template-resolver/handlers/shared.d.ts +9 -5
  291. package/dist/template-resolver/handlers/shared.js +6 -2
  292. package/dist/template-resolver/handlers/template-gates.d.ts +36 -0
  293. package/dist/template-resolver/handlers/template-gates.js +142 -0
  294. package/dist/template-resolver/handlers/template-write.d.ts +45 -0
  295. package/dist/template-resolver/handlers/template-write.js +141 -0
  296. package/dist/template-resolver/handlers/tenant-overrides.query.d.ts +49 -0
  297. package/dist/template-resolver/handlers/tenant-overrides.query.js +112 -0
  298. package/dist/template-resolver/handlers/toggle-status.write.d.ts +27 -2
  299. package/dist/template-resolver/handlers/toggle-status.write.js +47 -15
  300. package/dist/template-resolver/handlers/upsert-system.write.d.ts +5 -8
  301. package/dist/template-resolver/handlers/upsert-system.write.js +14 -59
  302. package/dist/template-resolver/handlers/upsert-tenant.write.d.ts +5 -8
  303. package/dist/template-resolver/handlers/upsert-tenant.write.js +11 -62
  304. package/dist/template-resolver/handlers/usage.query.d.ts +17 -0
  305. package/dist/template-resolver/handlers/usage.query.js +24 -0
  306. package/dist/template-resolver/handlers/validate.query.d.ts +74 -0
  307. package/dist/template-resolver/handlers/validate.query.js +80 -0
  308. package/dist/template-resolver/index.d.ts +19 -1
  309. package/dist/template-resolver/index.js +17 -1
  310. package/dist/template-resolver/layout-appearance.d.ts +10 -0
  311. package/dist/template-resolver/layout-appearance.js +26 -0
  312. package/dist/template-resolver/layout-regions.d.ts +23 -0
  313. package/dist/template-resolver/layout-regions.js +125 -0
  314. package/dist/template-resolver/linked-resources.d.ts +17 -0
  315. package/dist/template-resolver/linked-resources.js +75 -0
  316. package/dist/template-resolver/pdf-constants.d.ts +7 -0
  317. package/dist/template-resolver/pdf-constants.js +8 -0
  318. package/dist/template-resolver/preview-display-html.d.ts +7 -0
  319. package/dist/template-resolver/preview-display-html.js +27 -0
  320. package/dist/template-resolver/print-document.d.ts +1 -0
  321. package/dist/template-resolver/print-document.js +55 -0
  322. package/dist/template-resolver/qualified-names.d.ts +34 -0
  323. package/dist/template-resolver/qualified-names.js +34 -0
  324. package/dist/template-resolver/record-mapping.d.ts +2 -0
  325. package/dist/template-resolver/record-mapping.js +21 -0
  326. package/dist/template-resolver/resource-image.d.ts +15 -0
  327. package/dist/template-resolver/resource-image.js +34 -0
  328. package/dist/template-resolver/seeding.d.ts +14 -1
  329. package/dist/template-resolver/seeding.js +125 -18
  330. package/dist/template-resolver/store-template-resource.d.ts +64 -0
  331. package/dist/template-resolver/store-template-resource.js +264 -0
  332. package/dist/template-resolver/table.d.ts +150 -8
  333. package/dist/template-resolver/table.js +20 -2
  334. package/dist/template-resolver/template-bundle.d.ts +36 -0
  335. package/dist/template-resolver/template-bundle.js +60 -0
  336. package/dist/template-resolver/template-diff.d.ts +7 -0
  337. package/dist/template-resolver/template-diff.js +68 -0
  338. package/dist/template-resolver/template-draft.d.ts +51 -0
  339. package/dist/template-resolver/template-draft.js +72 -0
  340. package/dist/template-resolver/template-meta.d.ts +85 -0
  341. package/dist/template-resolver/template-meta.js +145 -0
  342. package/dist/template-resolver/template-preview.d.ts +103 -0
  343. package/dist/template-resolver/template-preview.js +418 -0
  344. package/dist/template-resolver/template-resources.d.ts +19 -0
  345. package/dist/template-resolver/template-resources.js +73 -0
  346. package/dist/template-resolver/template-usage.d.ts +16 -0
  347. package/dist/template-resolver/template-usage.js +35 -0
  348. package/dist/template-resolver/template-validation.d.ts +22 -0
  349. package/dist/template-resolver/template-validation.js +173 -0
  350. package/dist/template-resolver/testing.js +5 -5
  351. package/dist/template-resolver/user-content-table.d.ts +14 -8
  352. package/dist/template-resolver/web/client-plugin.d.ts +1 -0
  353. package/dist/template-resolver/web/client-plugin.js +12 -7
  354. package/dist/template-resolver/web/document-editor-extensions.d.ts +18 -0
  355. package/dist/template-resolver/web/document-editor-extensions.js +145 -0
  356. package/dist/template-resolver/web/document-editor.d.ts +4 -0
  357. package/dist/template-resolver/web/document-editor.js +17 -0
  358. package/dist/template-resolver/web/document-tiptap-editor.d.ts +3 -0
  359. package/dist/template-resolver/web/document-tiptap-editor.js +492 -0
  360. package/dist/template-resolver/web/document-toolbar-blocks.d.ts +41 -0
  361. package/dist/template-resolver/web/document-toolbar-blocks.js +19 -0
  362. package/dist/template-resolver/web/editor-handle.d.ts +3 -0
  363. package/dist/template-resolver/web/editor-handle.js +24 -0
  364. package/dist/template-resolver/web/i18n.js +91 -0
  365. package/dist/template-resolver/web/index.d.ts +5 -0
  366. package/dist/template-resolver/web/index.js +5 -0
  367. package/dist/template-resolver/web/placeholder-line-editor-lazy.d.ts +4 -0
  368. package/dist/template-resolver/web/placeholder-line-editor-lazy.js +16 -0
  369. package/dist/template-resolver/web/placeholder-line-editor.d.ts +17 -0
  370. package/dist/template-resolver/web/placeholder-line-editor.js +94 -0
  371. package/dist/template-resolver/web/placeholder-text.d.ts +4 -0
  372. package/dist/template-resolver/web/placeholder-text.js +34 -0
  373. package/dist/template-resolver/web/use-stable-by-key.d.ts +1 -0
  374. package/dist/template-resolver/web/use-stable-by-key.js +13 -0
  375. package/dist/tenant/handlers/add-member.write.d.ts +1 -1
  376. package/dist/tenant/handlers/cancel-invitation.write.d.ts +1 -1
  377. package/dist/tenant/handlers/create.write.d.ts +1 -1
  378. package/dist/tenant/handlers/remove-member.write.d.ts +1 -1
  379. package/dist/tenant/handlers/team-list.query.js +3 -2
  380. package/dist/tenant/handlers/toggle-enabled.write.d.ts +2 -2
  381. package/dist/tenant/handlers/update-member-roles.write.d.ts +1 -1
  382. package/dist/tenant/handlers/update.write.d.ts +1 -1
  383. package/dist/tenant/seeding.js +31 -6
  384. package/dist/tenant-handover/handlers/claim.write.d.ts +1 -1
  385. package/dist/tenant-lifecycle/handlers/cancel-destruction.write.d.ts +2 -2
  386. package/dist/tenant-lifecycle/handlers/cancel-destruction.write.js +2 -1
  387. package/dist/tenant-lifecycle/handlers/request-destruction.write.d.ts +1 -1
  388. package/dist/tier-engine/feature.js +9 -3
  389. package/dist/tier-engine/handlers/set-tenant-tier.write.d.ts +1 -1
  390. package/dist/user/db/queries/stream-tenant-backfill.js +4 -4
  391. package/dist/user/handlers/create.write.d.ts +1 -1
  392. package/dist/user/handlers/detail.query.js +2 -1
  393. package/dist/user/handlers/update.write.d.ts +1 -1
  394. package/dist/user/resolve-display-names.js +5 -9
  395. package/dist/user/seeding.js +20 -1
  396. package/dist/user-data-rights/db/queries/forget-cleanup.d.ts +2 -2
  397. package/dist/user-data-rights/email-templates.d.ts +1 -29
  398. package/dist/user-data-rights/email-templates.js +5 -106
  399. package/dist/user-data-rights/feature.js +53 -35
  400. package/dist/user-data-rights/handlers/cancel-deletion.write.d.ts +2 -2
  401. package/dist/user-data-rights/handlers/cancel-deletion.write.js +2 -1
  402. package/dist/user-data-rights/handlers/confirm-deletion-by-token.write.d.ts +1 -1
  403. package/dist/user-data-rights/handlers/lift-restriction.write.d.ts +1 -1
  404. package/dist/user-data-rights/handlers/request-deletion-by-email.write.d.ts +1 -1
  405. package/dist/user-data-rights/handlers/request-deletion.write.d.ts +1 -1
  406. package/dist/user-data-rights/handlers/request-deletion.write.js +5 -7
  407. package/dist/user-data-rights/handlers/request-export.write.d.ts +1 -1
  408. package/dist/user-data-rights/handlers/restrict-account.write.d.ts +1 -1
  409. package/dist/user-data-rights/handlers/run-forget-cleanup.write.d.ts +1 -1
  410. package/dist/user-data-rights/lib/default-mailers.d.ts +15 -7
  411. package/dist/user-data-rights/lib/default-mailers.js +100 -48
  412. package/dist/user-data-rights/lib/update-user-lifecycle.js +1 -1
  413. package/dist/user-data-rights/mail-notifications.d.ts +13 -0
  414. package/dist/user-data-rights/mail-notifications.js +118 -0
  415. package/dist/user-data-rights/web/privacy-center-screen.js +2 -1
  416. package/dist/user-profile/handlers/change-email.write.d.ts +1 -1
  417. package/dist/user-profile/web/profile-screen.js +2 -1
  418. package/dist/waitlist/feature.js +10 -0
  419. package/dist/waitlist/handlers/invite.write.d.ts +1 -1
  420. package/dist/waitlist/handlers/reject.write.d.ts +1 -1
  421. package/dist/waitlist/handlers/submit.write.d.ts +1 -1
  422. package/dist/waitlist/handlers/submit.write.js +3 -4
  423. package/dist/waitlist/mail.d.ts +19 -6
  424. package/dist/waitlist/mail.js +50 -14
  425. package/dist/waitlist/options.js +1 -1
  426. package/dist/workflow-runner/event-trigger.js +2 -2
  427. package/dist/workflow-runner/handlers/resume-run.write.js +7 -2
  428. package/package.json +37 -17
  429. package/src/admin-shell/changes.json +6 -0
  430. package/src/audit/changes.json +6 -0
  431. package/src/auth-email-password/changes.json +51 -0
  432. package/src/billing-foundation/changes.json +43 -0
  433. package/src/cap-counter/changes.json +6 -0
  434. package/src/channel-email/changes.json +19 -0
  435. package/src/config/changes.json +6 -0
  436. package/src/crypto-shredding/changes.json +6 -0
  437. package/src/custom-fields/changes.json +6 -0
  438. package/src/data-retention/changes.json +6 -0
  439. package/src/delivery/changes.json +66 -0
  440. package/src/file-foundation/changes.json +6 -0
  441. package/src/files-tenant-data/changes.json +6 -0
  442. package/src/inbound-mail-foundation/changes.json +6 -0
  443. package/src/jobs/changes.json +19 -0
  444. package/src/ledger/changes.json +7 -0
  445. package/src/managed-pages/changes.json +6 -0
  446. package/src/renderer-foundation/changes.json +39 -0
  447. package/src/renderer-pdf/changes.json +12 -0
  448. package/src/secrets/changes.json +6 -0
  449. package/src/shared/changes.json +6 -0
  450. package/src/subscription-stripe/changes.json +6 -0
  451. package/src/template-resolver/changes.json +186 -0
  452. package/src/tier-engine/changes.json +6 -0
  453. package/src/user/changes.json +6 -0
  454. package/src/user-data-rights/changes.json +13 -0
  455. package/src/user-profile/changes.json +1 -1
  456. package/src/waitlist/changes.json +7 -0
  457. package/src/workflow-runner/changes.json +6 -0
  458. package/dist/renderer-simple/feature.d.ts +0 -10
  459. package/dist/renderer-simple/feature.js +0 -42
  460. package/dist/renderer-simple/index.d.ts +0 -3
  461. package/dist/renderer-simple/index.js +0 -2
  462. package/dist/renderer-simple/mail-blocks.d.ts +0 -21
  463. package/dist/renderer-simple/mail-blocks.js +0 -107
  464. package/dist/renderer-simple/resolve-variables.d.ts +0 -7
  465. package/dist/renderer-simple/resolve-variables.js +0 -47
  466. package/dist/renderer-simple/simple-renderer.d.ts +0 -24
  467. package/dist/renderer-simple/simple-renderer.js +0 -200
  468. package/src/renderer-simple/changes.json +0 -27
@@ -0,0 +1,492 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // @runtime client
3
+ //
4
+ // tiptap-backed implementation behind DocumentContentEditor's lazy() boundary —
5
+ // never import this file statically, tiptap must only load when a "document"
6
+ // collection is rendered. Variables are inserted as `variable` nodes only,
7
+ // never as `{{name}}` text, so the sanitizer's schema keeps them.
8
+ import { TextareaContentEditor, usePrimitives, useTranslation, VariableChips, } from "@cosmicdrift/kumiko-renderer";
9
+ import { cn } from "@cosmicdrift/kumiko-renderer-web";
10
+ import { isOneOf } from "@cosmicdrift/kumiko-types/type-guards";
11
+ import { EditorContent, useEditor, useEditorState } from "@tiptap/react";
12
+ import { BubbleMenu } from "@tiptap/react/menus";
13
+ import { AlignCenter, AlignJustify, AlignLeft, AlignRight, Bold as BoldIcon, Braces, ChevronDown, Image as ImageIcon, Italic as ItalicIcon, Link as LinkIcon, List, ListOrdered, Minus, MousePointerClick, Repeat, Scissors, Table as TableIcon, Underline as UnderlineIcon, } from "lucide-react";
14
+ import { Fragment, useEffect, useMemo, useState } from "react";
15
+ import { createPortal } from "react-dom";
16
+ import { DOCUMENT_TEXT_ALIGNMENTS, isAllowedDocumentLinkHref, isDocumentPlaceholderHref, isDocumentReferenceName, isDocumentResourceKey, } from "../document-schema.js";
17
+ import { createDocumentEditorExtensions, DOCUMENT_BLOCK_ATTRIBUTE, } from "./document-editor-extensions.js";
18
+ import { MAIL_DOCUMENT_BLOCKS, } from "./document-toolbar-blocks.js";
19
+ import { createEditorHandle } from "./editor-handle.js";
20
+ import { useStableByKey } from "./use-stable-by-key.js";
21
+ const NO_LABELS = {};
22
+ const NO_NAMES = [];
23
+ const NO_PREVIEWS = {};
24
+ function previewsKey(previews) {
25
+ return Object.entries(previews)
26
+ .map(([key, { src, caption }]) => `${key}|${src.length}|${src.slice(-24)}|${caption ?? ""}`)
27
+ .join("\n");
28
+ }
29
+ // Blocks that stay in the canvas toolbar; the rest moves into the overflow menu.
30
+ const CANVAS_INLINE_BLOCKS = ["image", "table"];
31
+ const BLOCK_PANEL = {
32
+ image: "image",
33
+ button: "button",
34
+ repeat: "repeat",
35
+ align: "align",
36
+ };
37
+ const ALIGNMENT_ICONS = {
38
+ left: _jsx(AlignLeft, { size: 16 }),
39
+ center: _jsx(AlignCenter, { size: 16 }),
40
+ right: _jsx(AlignRight, { size: 16 }),
41
+ justify: _jsx(AlignJustify, { size: 16 }),
42
+ };
43
+ const ALIGNMENT_LABEL_KEYS = {
44
+ left: "template-resolver.documentEditor.alignLeft",
45
+ center: "template-resolver.documentEditor.alignCenter",
46
+ right: "template-resolver.documentEditor.alignRight",
47
+ justify: "template-resolver.documentEditor.alignJustify",
48
+ };
49
+ // print-document moves the leading rows flagged repeatHeader into thead, so the
50
+ // toggle reads and writes the table's first row.
51
+ function findRepeatTable(editor) {
52
+ const { $from } = editor.state.selection;
53
+ for (let depth = $from.depth; depth > 0; depth--) {
54
+ const node = $from.node(depth);
55
+ if (node.type.name !== "table")
56
+ continue;
57
+ const lists = [];
58
+ node.forEach((row) => {
59
+ const each = row.attrs["each"];
60
+ if (typeof each === "string" && each !== "" && !lists.includes(each))
61
+ lists.push(each);
62
+ });
63
+ if (lists.length === 0)
64
+ return null;
65
+ return {
66
+ lists,
67
+ headerRepeats: node.firstChild?.attrs["repeatHeader"] === true,
68
+ firstRowPos: $from.start(depth),
69
+ };
70
+ }
71
+ return null;
72
+ }
73
+ function toggleRepeatHeader(editor) {
74
+ const found = findRepeatTable(editor);
75
+ if (found === null)
76
+ return;
77
+ editor
78
+ .chain()
79
+ .focus()
80
+ .command(({ tr }) => {
81
+ const row = tr.doc.nodeAt(found.firstRowPos);
82
+ if (row === null)
83
+ return false;
84
+ tr.setNodeMarkup(found.firstRowPos, undefined, {
85
+ ...row.attrs,
86
+ repeatHeader: !found.headerRepeats,
87
+ });
88
+ return true;
89
+ })
90
+ .run();
91
+ }
92
+ const PARAGRAPH_STYLES = ["paragraph", "1", "2", "3"];
93
+ const HEADING_LEVELS = { "1": 1, "2": 2, "3": 3 };
94
+ const PLACEHOLDER_HREF = /^\{\{([^{}]+)\}\}$/;
95
+ function buttonTargetLabel(href, labels) {
96
+ const name = PLACEHOLDER_HREF.exec(href)?.[1];
97
+ if (name === undefined)
98
+ return href;
99
+ return Object.hasOwn(labels, name) ? (labels[name] ?? name) : name;
100
+ }
101
+ // The bubble menu registers its plugin once per mount, so a rebuilt editor needs a fresh mount.
102
+ const editorMountKeys = new WeakMap();
103
+ let lastMountKey = 0;
104
+ function mountKeyOf(editor) {
105
+ const known = editorMountKeys.get(editor);
106
+ if (known !== undefined)
107
+ return known;
108
+ lastMountKey += 1;
109
+ const created = lastMountKey;
110
+ editorMountKeys.set(editor, created);
111
+ return created;
112
+ }
113
+ // Board .hb: a small bar that straddles the block's top frame line on the right; above a table it sits fully
114
+ // outside so the header row stays readable.
115
+ const BUBBLE_BAR_CLASS = "flex w-max items-center gap-1 rounded border border-input bg-popover p-px text-xs [&_button]:h-5 [&_button]:px-1.5 [&_button]:text-[10px]";
116
+ function bubbleOffset(editor) {
117
+ return ({ rects }) => ({
118
+ mainAxis: findRepeatTable(editor) !== null ? 2 : -rects.floating.height / 2,
119
+ crossAxis: -8,
120
+ });
121
+ }
122
+ const BUBBLE_MENU_PLUGIN_KEY = "documentBlockOptions";
123
+ // The options bar belongs to the block frame, not to the caret inside it.
124
+ function selectedBlockReference(editor) {
125
+ const { node } = editor.view.domAtPos(editor.state.selection.from);
126
+ const start = node instanceof Element ? node : node.parentElement;
127
+ const block = start?.closest(`[${DOCUMENT_BLOCK_ATTRIBUTE}], table`);
128
+ if (block === null || block === undefined)
129
+ return null;
130
+ return {
131
+ getBoundingClientRect: () => block.getBoundingClientRect(),
132
+ getClientRects: () => [block.getBoundingClientRect()],
133
+ contextElement: block,
134
+ };
135
+ }
136
+ // The bubble is first measured before React has filled it, so it sits at the wrong place until a second pass.
137
+ function repositionBubble(editor) {
138
+ if (editor.isDestroyed)
139
+ return;
140
+ editor.view.dispatch(editor.state.tr.setMeta(BUBBLE_MENU_PLUGIN_KEY, "updatePosition"));
141
+ }
142
+ function isParagraphStyle(value) {
143
+ return isOneOf(PARAGRAPH_STYLES, value);
144
+ }
145
+ function emptyParagraph() {
146
+ return { type: "paragraph" };
147
+ }
148
+ function repeatTableContent(listName) {
149
+ const headerRow = {
150
+ type: "tableRow",
151
+ content: [
152
+ { type: "tableHeader", content: [emptyParagraph()] },
153
+ { type: "tableHeader", content: [emptyParagraph()] },
154
+ ],
155
+ };
156
+ const repeatRow = {
157
+ type: "tableRow",
158
+ attrs: { each: listName },
159
+ content: [
160
+ { type: "tableCell", content: [emptyParagraph()] },
161
+ { type: "tableCell", content: [emptyParagraph()] },
162
+ ],
163
+ };
164
+ return { type: "table", content: [headerRow, repeatRow] };
165
+ }
166
+ function Separator({ compact = false }) {
167
+ return (_jsx("span", { "aria-hidden": "true", className: cn("h-5 w-px bg-border", compact ? "mx-0.5" : "mx-2") }));
168
+ }
169
+ function PanelActions({ onInsert, onRemoveLink, onCancel, }) {
170
+ const { Button } = usePrimitives();
171
+ const t = useTranslation();
172
+ return (_jsxs("div", { className: "flex gap-2", children: [onInsert && (_jsx(Button, { type: "button", size: "sm", onClick: onInsert, children: t("template-resolver.documentEditor.insert") })), onRemoveLink && (_jsx(Button, { type: "button", size: "sm", variant: "danger-ghost", onClick: onRemoveLink, children: t("template-resolver.documentEditor.removeLink") })), _jsx(Button, { type: "button", size: "sm", variant: "secondary", onClick: onCancel, children: t("template-resolver.documentEditor.cancel") })] }));
173
+ }
174
+ function NameSelect({ id, label, names, value, onChange }) {
175
+ const { Field, Input } = usePrimitives();
176
+ return (_jsx(Field, { id: id, label: label, children: _jsx(Input, { kind: "select", id: id, name: id, value: value, onChange: onChange, display: "dropdown", options: names.map((name) => ({ value: name, label: name })) }) }));
177
+ }
178
+ function InsertPanel({ editor, editorId, kind, variables, onClose }) {
179
+ const { Button, Field, Input } = usePrimitives();
180
+ const t = useTranslation();
181
+ const [href, setHref] = useState(() => {
182
+ const current = editor.getAttributes("link")["href"];
183
+ return typeof current === "string" ? current : "";
184
+ });
185
+ const [resource, setResource] = useState("");
186
+ const [alt, setAlt] = useState("");
187
+ const [buttonText, setButtonText] = useState(() => t("template-resolver.documentEditor.buttonDefaultText"));
188
+ const [chosenName, setChosenName] = useState("");
189
+ const [error, setError] = useState(null);
190
+ const referenceNames = variables.filter(isDocumentReferenceName);
191
+ const buttonTargets = referenceNames.filter((name) => isDocumentPlaceholderHref(`{{${name}}}`));
192
+ const selectable = kind === "button" ? buttonTargets : referenceNames;
193
+ const selectedName = selectable.includes(chosenName) ? chosenName : (selectable[0] ?? "");
194
+ const insertAndClose = (content) => {
195
+ editor.chain().focus().insertContent(content).run();
196
+ onClose();
197
+ };
198
+ const submitLink = () => {
199
+ if (!isAllowedDocumentLinkHref(href)) {
200
+ setError(t("template-resolver.documentEditor.invalidLink"));
201
+ return;
202
+ }
203
+ const chain = editor.chain().focus();
204
+ if (!editor.state.selection.empty)
205
+ chain.setLink({ href }).run();
206
+ else if (editor.isActive("link"))
207
+ chain.extendMarkRange("link").setLink({ href }).run();
208
+ else if (isDocumentPlaceholderHref(href))
209
+ // Placeholders are never inserted as {{name}} text; the link shows the variable's value.
210
+ chain
211
+ .insertContent({
212
+ type: "variable",
213
+ attrs: { name: href.slice(2, -2) },
214
+ marks: [{ type: "link", attrs: { href } }],
215
+ })
216
+ .run();
217
+ else
218
+ chain
219
+ .insertContent({ type: "text", text: href, marks: [{ type: "link", attrs: { href } }] })
220
+ .run();
221
+ onClose();
222
+ };
223
+ const submitImage = () => {
224
+ if (!isDocumentResourceKey(resource)) {
225
+ setError(t("template-resolver.documentEditor.invalidResourceKey"));
226
+ return;
227
+ }
228
+ if (/[<>]/.test(alt)) {
229
+ setError(t("template-resolver.documentEditor.invalidImageAlt"));
230
+ return;
231
+ }
232
+ insertAndClose({ type: "resource", attrs: { resource, alt: alt || null } });
233
+ };
234
+ const needsVariables = kind === "button" || kind === "repeat" || kind === "placeholder";
235
+ const noVariables = needsVariables && selectable.length === 0;
236
+ const idPrefix = `${editorId}-panel`;
237
+ return (_jsxs("div", { className: "flex flex-col gap-2 border-b border-input bg-muted/40 p-2", children: [noVariables && (_jsx("p", { className: "text-sm text-muted-foreground", children: t("template-resolver.documentEditor.noVariables") })), kind === "link" && (_jsx(Field, { id: `${idPrefix}-href`, label: t("template-resolver.documentEditor.linkHref"), children: _jsx(Input, { kind: "text", id: `${idPrefix}-href`, name: "href", value: href, onChange: setHref, placeholder: t("template-resolver.documentEditor.linkHrefPlaceholder") }) })), kind === "placeholder" && !noVariables && (_jsx("div", { className: "flex flex-wrap gap-1", children: _jsx(VariableChips, { variables: selectable, onInsert: (name) => insertAndClose({ type: "variable", attrs: { name } }) }) })), kind === "align" && (_jsx("div", { className: "flex flex-wrap gap-1", children: DOCUMENT_TEXT_ALIGNMENTS.map((alignment) => (_jsxs(Button, { type: "button", variant: "secondary", size: "sm", onClick: () => {
238
+ editor
239
+ .chain()
240
+ .focus()
241
+ .updateAttributes("paragraph", { textAlign: alignment })
242
+ .updateAttributes("heading", { textAlign: alignment })
243
+ .run();
244
+ onClose();
245
+ }, children: [ALIGNMENT_ICONS[alignment], t(ALIGNMENT_LABEL_KEYS[alignment])] }, alignment))) })), kind === "image" && (_jsxs(_Fragment, { children: [_jsx(Field, { id: `${idPrefix}-resource`, label: t("template-resolver.documentEditor.resourceKey"), children: _jsx(Input, { kind: "text", id: `${idPrefix}-resource`, name: "resource", value: resource, onChange: setResource }) }), _jsx(Field, { id: `${idPrefix}-alt`, label: t("template-resolver.documentEditor.imageAlt"), children: _jsx(Input, { kind: "text", id: `${idPrefix}-alt`, name: "alt", value: alt, onChange: setAlt }) })] })), kind === "button" && !noVariables && (_jsxs(_Fragment, { children: [_jsx(NameSelect, { id: `${idPrefix}-target`, label: t("template-resolver.documentEditor.buttonTarget"), names: selectable, value: selectedName, onChange: setChosenName }), _jsx(Field, { id: `${idPrefix}-text`, label: t("template-resolver.documentEditor.buttonText"), children: _jsx(Input, { kind: "text", id: `${idPrefix}-text`, name: "text", value: buttonText, onChange: setButtonText }) })] })), kind === "repeat" && !noVariables && (_jsx(NameSelect, { id: `${idPrefix}-list`, label: t("template-resolver.documentEditor.repeatList"), names: selectable, value: selectedName, onChange: setChosenName })), error !== null && (_jsx("p", { role: "alert", className: "text-sm text-destructive", children: error })), _jsx("div", { className: "flex flex-wrap gap-2", children: _jsx(PanelActions, { onCancel: onClose, ...(kind === "link" && { onInsert: submitLink }), ...(kind === "link" &&
246
+ editor.isActive("link") && {
247
+ onRemoveLink: () => {
248
+ editor.chain().focus().extendMarkRange("link").unsetLink().run();
249
+ onClose();
250
+ },
251
+ }), ...(kind === "image" && { onInsert: submitImage }), ...(kind === "button" &&
252
+ !noVariables && {
253
+ onInsert: () => insertAndClose({
254
+ type: "button",
255
+ attrs: { href: `{{${selectedName}}}` },
256
+ content: buttonText ? [{ type: "text", text: buttonText }] : [],
257
+ }),
258
+ }), ...(kind === "repeat" &&
259
+ !noVariables && { onInsert: () => insertAndClose(repeatTableContent(selectedName)) }) }) })] }));
260
+ }
261
+ export default function DocumentTiptapEditor({ id, value, onChange, variables, readOnly, blocks = MAIL_DOCUMENT_BLOCKS, variableLabels = NO_LABELS, systemVariables = NO_NAMES, resourcePreviews = NO_PREVIEWS, chrome = "default", toolbar = "full", renderPaper, toolbarHost, onEditorReady, }) {
262
+ const t = useTranslation();
263
+ const { ActionOverflowMenu, Button, Field, Input } = usePrimitives();
264
+ const [openPanel, setOpenPanel] = useState(null);
265
+ const [canvasScroller, setCanvasScroller] = useState(null);
266
+ const [showHtml, setShowHtml] = useState(false);
267
+ const canvas = chrome === "canvas";
268
+ const compact = toolbar === "compact" && !canvas;
269
+ const hosted = toolbarHost !== undefined;
270
+ const placeholderLabel = t("template-resolver.documentEditor.placeholder");
271
+ const imageLabel = t("template-resolver.documentEditor.image");
272
+ const imageBlockLabel = t("template-resolver.documentEditor.imageBlock");
273
+ const pageBreakLabel = t("template-resolver.documentEditor.pageBreak");
274
+ const buttonLabel = t("template-resolver.documentEditor.button");
275
+ const stableLabels = useStableByKey(variableLabels, JSON.stringify(variableLabels));
276
+ const stableSystem = useStableByKey(systemVariables, systemVariables.join("\n"));
277
+ const stablePreviews = useStableByKey(resourcePreviews, previewsKey(resourcePreviews));
278
+ const extensions = useMemo(() => createDocumentEditorExtensions({
279
+ placeholder: placeholderLabel,
280
+ image: imageLabel,
281
+ pageBreak: pageBreakLabel,
282
+ button: buttonLabel,
283
+ imageBlock: imageBlockLabel,
284
+ variableLabels: stableLabels,
285
+ systemVariables: stableSystem,
286
+ resourcePreviews: stablePreviews,
287
+ blockLabels: canvas,
288
+ }), [
289
+ placeholderLabel,
290
+ imageLabel,
291
+ imageBlockLabel,
292
+ pageBreakLabel,
293
+ buttonLabel,
294
+ stableLabels,
295
+ stableSystem,
296
+ stablePreviews,
297
+ canvas,
298
+ ]);
299
+ // The node views are built from labels and previews, so a changed set
300
+ // rebuilds the editor; its content is re-read from `value`.
301
+ const editor = useEditor({
302
+ extensions,
303
+ content: value,
304
+ editable: !readOnly,
305
+ // Suspense (DocumentContentEditor's lazy boundary) speculatively mounts
306
+ // this component before committing it; immediate render would create an
307
+ // editor instance during that throwaway pass.
308
+ immediatelyRender: false,
309
+ editorProps: { attributes: { id } },
310
+ onCreate: ({ editor: created }) => onEditorReady?.(createEditorHandle(created)),
311
+ onUpdate: ({ editor: e }) => onChange(e.getHTML()),
312
+ }, [extensions]);
313
+ // @tiptap/react v3 does not re-render on selection-only transactions, so
314
+ // active states must come from a subscription.
315
+ const activeState = useEditorState({
316
+ editor,
317
+ selector: ({ editor: e }) => e === null
318
+ ? null
319
+ : {
320
+ blockStyle: e.isActive("heading", { level: 1 })
321
+ ? "1"
322
+ : e.isActive("heading", { level: 2 })
323
+ ? "2"
324
+ : e.isActive("heading", { level: 3 })
325
+ ? "3"
326
+ : "paragraph",
327
+ bold: e.isActive("bold"),
328
+ italic: e.isActive("italic"),
329
+ underline: e.isActive("underline"),
330
+ selectedBlock: e.isActive("resource")
331
+ ? {
332
+ type: "resource",
333
+ detail: String(e.getAttributes("resource")["resource"]),
334
+ }
335
+ : e.isActive("button")
336
+ ? { type: "button", detail: String(e.getAttributes("button")["href"]) }
337
+ : null,
338
+ html: showHtml ? e.getHTML() : "",
339
+ bulletList: e.isActive("bulletList"),
340
+ orderedList: e.isActive("orderedList"),
341
+ link: e.isActive("link"),
342
+ repeatTable: findRepeatTable(e),
343
+ },
344
+ });
345
+ // The entry loads asynchronously, so `value` arrives after useEditor read
346
+ // its initial content; the guard keeps in-flight typing from being clobbered.
347
+ // kumiko-lint-ignore no-raw-hooks DOM integration: syncs the controlled value into the imperative tiptap editor
348
+ useEffect(() => {
349
+ if (editor && value !== editor.getHTML()) {
350
+ editor.commands.setContent(value, { emitUpdate: false });
351
+ }
352
+ }, [value, editor]);
353
+ // kumiko-lint-ignore no-raw-hooks DOM integration: tiptap exposes editability only imperatively via setEditable
354
+ useEffect(() => {
355
+ editor?.setEditable(!readOnly);
356
+ }, [readOnly, editor]);
357
+ if (!editor)
358
+ return (_jsx(TextareaContentEditor, { id: id, value: value, onChange: onChange, variables: variables, readOnly: readOnly }));
359
+ const togglePanel = (kind) => setOpenPanel((current) => (current === kind ? null : kind));
360
+ const setBlockStyle = (style) => {
361
+ if (!isParagraphStyle(style))
362
+ return;
363
+ const chain = editor.chain().focus();
364
+ if (style === "paragraph")
365
+ chain.setParagraph().run();
366
+ else
367
+ chain.setHeading({ level: HEADING_LEVELS[style] }).run();
368
+ };
369
+ const runBlock = (block) => {
370
+ const panel = BLOCK_PANEL[block];
371
+ if (panel) {
372
+ togglePanel(panel);
373
+ return;
374
+ }
375
+ const chain = editor.chain().focus();
376
+ if (block === "table")
377
+ chain.insertTable({ rows: 3, cols: 2, withHeaderRow: true }).run();
378
+ else if (block === "divider")
379
+ chain.insertContent({ type: "divider" }).run();
380
+ else if (block === "pageBreak")
381
+ chain.insertContent({ type: "pageBreak" }).run();
382
+ };
383
+ const blockButtons = {
384
+ image: { label: imageLabel, icon: _jsx(ImageIcon, { size: 16 }) },
385
+ table: { label: t("template-resolver.documentEditor.table"), icon: _jsx(TableIcon, { size: 16 }) },
386
+ button: {
387
+ label: t("template-resolver.documentEditor.button"),
388
+ icon: _jsx(MousePointerClick, { size: 16 }),
389
+ },
390
+ divider: { label: t("template-resolver.documentEditor.divider"), icon: _jsx(Minus, { size: 16 }) },
391
+ repeat: { label: t("template-resolver.documentEditor.repeat"), icon: _jsx(Repeat, { size: 16 }) },
392
+ pageBreak: { label: pageBreakLabel, icon: _jsx(Scissors, { size: 16 }) },
393
+ align: { label: t("template-resolver.documentEditor.align"), icon: _jsx(AlignLeft, { size: 16 }) },
394
+ };
395
+ const repeatTable = activeState?.repeatTable ?? null;
396
+ const repeatListLabel = repeatTable !== null && repeatTable.lists.length === 1
397
+ ? (variableLabels[repeatTable.lists[0] ?? ""] ?? repeatTable.lists[0])
398
+ : undefined;
399
+ const repeatBarLabel = repeatListLabel === undefined
400
+ ? t("template-resolver.documentEditor.repeat")
401
+ : t("template-resolver.documentEditor.repeatBarList", { list: repeatListLabel });
402
+ const paragraphStyleLabel = t("template-resolver.documentEditor.paragraphStyle");
403
+ const styleOptions = [
404
+ { value: "paragraph", label: t("template-resolver.documentEditor.paragraph") },
405
+ { value: "1", label: t("kumiko.contentEditor.heading1") },
406
+ { value: "2", label: t("kumiko.contentEditor.heading2") },
407
+ { value: "3", label: t("template-resolver.documentEditor.heading3") },
408
+ ];
409
+ // Canvas chrome is one flat row: unframed ghost buttons, glyph plus text for the longer names.
410
+ const iconButton = (label, icon, isActive, onClick, text) => canvas ? (_jsxs(Button, { type: "button", variant: "ghost", size: "sm", pressed: isActive, disabled: readOnly, onClick: onClick, ariaLabel: label, title: label, children: [icon, text] })) : (_jsx(Button, { type: "button", variant: isActive ? "primary" : "secondary", size: "icon", pressed: isActive, disabled: readOnly, onClick: onClick, ariaLabel: label, title: label, children: icon }));
411
+ const markContent = (letter, icon, className) => canvas ? _jsx("span", { className: className, children: letter }) : icon;
412
+ const selectedBlock = activeState?.selectedBlock ?? null;
413
+ const flatVariant = canvas ? "ghost" : "secondary";
414
+ const labelledButton = (spec) => {
415
+ const shared = {
416
+ type: "button",
417
+ variant: flatVariant,
418
+ disabled: readOnly,
419
+ onClick: spec.onClick,
420
+ ...(spec.expanded !== undefined && { expanded: spec.expanded }),
421
+ };
422
+ return compact ? (_jsx(Button, { ...shared, size: "icon", ariaLabel: spec.label, title: spec.label, children: spec.icon }, spec.key)) : (_jsxs(Button, { ...shared, size: "sm", children: [spec.showIcon && spec.icon, spec.label, spec.trailingIcon] }, spec.key));
423
+ };
424
+ const editorContent = (_jsx(EditorContent, { editor: editor, className: cn(!canvas && "min-h-40 px-3 py-2 text-base outline-none md:text-sm", canvas && "text-sm", "[&_.ProseMirror-focused_.ProseMirror-selectednode]:ring-2 [&_.ProseMirror-focused_.ProseMirror-selectednode]:ring-primary", hosted
425
+ ? "[&_.ProseMirror]:outline-none"
426
+ : "[&_.ProseMirror]:min-h-40 [&_.ProseMirror]:outline-none", "[&_ul]:list-disc [&_ol]:list-decimal [&_ul]:pl-6 [&_ol]:pl-6", "[&_h1]:text-xl [&_h1]:font-bold [&_h2]:text-lg [&_h2]:font-bold [&_h3]:text-base [&_h3]:font-bold", "[&_a]:underline [&_a]:text-primary", "[&_strong]:font-bold [&_em]:italic [&_u]:underline", canvas
427
+ ? "[&_table]:mb-2 [&_table]:mt-6 [&_.ProseMirror>:first-child_table]:mt-0 [&_.ProseMirror>table:first-child]:mt-0 [&_td:last-child>p[data-size=small][data-align=right]]:whitespace-nowrap"
428
+ : "[&_table]:my-2", "[&_table]:w-full [&_table]:border-collapse", "[&_td]:border-b [&_td]:border-border [&_td]:px-2 [&_td]:py-1.5 [&_td>p]:m-0 [&_th>p]:m-0", "[&_th]:border-b [&_th]:border-border [&_th]:px-2 [&_th]:py-1.5 [&_th]:text-left [&_th]:text-xs [&_th]:font-medium [&_th]:text-muted-foreground", "[&_tr[data-each]>td]:bg-muted/50", "[&_[data-align=left]]:text-left [&_[data-align=center]]:text-center [&_[data-align=right]]:text-right [&_[data-align=justify]]:text-justify", "[&_p[data-size=small]]:text-xs [&_p[data-size=small]]:text-muted-foreground", "[&_a[data-button]]:inline-block [&_a[data-button]]:rounded-full [&_a[data-button]]:bg-primary [&_a[data-button]]:px-4 [&_a[data-button]]:py-1.5 [&_a[data-button]]:text-primary-foreground [&_a[data-button]]:no-underline", "[&_hr]:my-3 [&_hr]:border-input", "[&_.is-editor-empty]:before:pointer-events-none [&_.is-editor-empty]:before:float-left [&_.is-editor-empty]:before:h-0 [&_.is-editor-empty]:before:text-muted-foreground [&_.is-editor-empty]:before:content-[attr(data-placeholder)]") }));
429
+ // The canvas toolbar never scrolls sideways: the rarer blocks and the HTML view sit in the menu.
430
+ const menuBlocks = canvas && ActionOverflowMenu !== undefined
431
+ ? blocks.filter((block) => !CANVAS_INLINE_BLOCKS.includes(block))
432
+ : [];
433
+ const inlineBlocks = blocks.filter((block) => !menuBlocks.includes(block));
434
+ const overflowItems = [
435
+ ...menuBlocks.map((block) => ({
436
+ id: block,
437
+ label: blockButtons[block].label,
438
+ disabled: readOnly,
439
+ onSelect: () => runBlock(block),
440
+ })),
441
+ ...(canvas && !hosted
442
+ ? [
443
+ {
444
+ id: "html",
445
+ label: t("template-resolver.documentEditor.showHtml"),
446
+ onSelect: () => setShowHtml((current) => !current),
447
+ },
448
+ ]
449
+ : []),
450
+ ];
451
+ const toolbarBar = (_jsxs("div", { className: cn("flex items-center border-b border-input", canvas
452
+ ? "min-h-9 flex-nowrap gap-0 overflow-hidden bg-background px-1.5 [&>*]:shrink-0 [&_button]:h-7 [&_button]:gap-1 [&_button]:px-1 [&_button]:text-xs"
453
+ : "flex-wrap gap-1 p-1"), children: [_jsx("div", {
454
+ // kumiko-lint-ignore raw-classname the toolbar paragraph select sits flush in the editor toolbar; ComboboxInput has no flat trigger variant
455
+ className: cn(!canvas && (compact ? "w-24" : "w-40"), canvas &&
456
+ "w-auto shrink-0 [&_button[aria-haspopup=listbox]]:border-transparent [&_button[aria-haspopup=listbox]]:bg-transparent [&_button[aria-haspopup=listbox]]:shadow-none"), children: _jsx(Field, { id: `${id}-paragraph-style`, label: paragraphStyleLabel, hideLabel: true, children: _jsx(Input, { kind: "select", id: `${id}-paragraph-style`, name: "paragraph-style", value: activeState?.blockStyle ?? "paragraph", onChange: setBlockStyle, options: styleOptions, display: "dropdown", disabled: readOnly }) }) }), _jsx(Separator, { compact: compact || canvas }), iconButton(t("kumiko.contentEditor.bold"), markContent("B", _jsx(BoldIcon, { size: 16 }), "font-bold"), activeState?.bold ?? false, () => editor.chain().focus().toggleBold().run()), iconButton(t("kumiko.contentEditor.italic"), markContent("I", _jsx(ItalicIcon, { size: 16 }), "italic"), activeState?.italic ?? false, () => editor.chain().focus().toggleItalic().run()), iconButton(t("template-resolver.documentEditor.underline"), markContent("U", _jsx(UnderlineIcon, { size: 16 }), "underline"), activeState?.underline ?? false, () => editor.chain().focus().toggleUnderline().run()), _jsx(Separator, { compact: compact || canvas }), iconButton(t("kumiko.contentEditor.bulletList"), _jsx(List, { size: 16 }), activeState?.bulletList ?? false, () => editor.chain().focus().toggleBulletList().run(), canvas ? undefined : t("template-resolver.documentEditor.list")), iconButton(t("kumiko.contentEditor.orderedList"), _jsx(ListOrdered, { size: 16 }), activeState?.orderedList ?? false, () => editor.chain().focus().toggleOrderedList().run()), iconButton(t("template-resolver.documentEditor.link"), _jsx(LinkIcon, { size: 16 }), activeState?.link ?? false, () => togglePanel("link")), _jsx(Separator, { compact: compact || canvas }), labelledButton({
457
+ label: t("template-resolver.documentEditor.insertPlaceholder"),
458
+ icon: _jsx(Braces, { size: 16 }),
459
+ showIcon: true,
460
+ trailingIcon: canvas ? _jsx(ChevronDown, { size: 12 }) : undefined,
461
+ expanded: openPanel === "placeholder",
462
+ onClick: () => togglePanel("placeholder"),
463
+ }), inlineBlocks.length > 0 && _jsx(Separator, { compact: compact || canvas }), inlineBlocks.map((block) => canvas ? (_jsx(Fragment, { children: iconButton(blockButtons[block].label, blockButtons[block].icon, false, () => runBlock(block)) }, block)) : (labelledButton({
464
+ key: block,
465
+ label: blockButtons[block].label,
466
+ icon: blockButtons[block].icon,
467
+ showIcon: true,
468
+ onClick: () => runBlock(block),
469
+ }))), overflowItems.length > 0 && ActionOverflowMenu !== undefined && (_jsx("span", { className: "ml-auto shrink-0", children: _jsx(ActionOverflowMenu, { items: overflowItems, label: t("template-resolver.documentEditor.more"), testId: `${id}-toolbar-more` }) }))] }));
470
+ const bubbleMenu = (_jsx(BubbleMenu, { pluginKey: BUBBLE_MENU_PLUGIN_KEY, editor: editor, options: {
471
+ strategy: "fixed",
472
+ placement: "top-end",
473
+ offset: bubbleOffset(editor),
474
+ scrollTarget: canvasScroller ?? window,
475
+ onShow: () => requestAnimationFrame(() => repositionBubble(editor)),
476
+ }, getReferencedVirtualElement: () => selectedBlockReference(editor), shouldShow: ({ editor: e, element }) =>
477
+ // A leading image is selected by default; the bubble belongs to a deliberate selection.
478
+ (e.isFocused || element.contains(document.activeElement)) &&
479
+ (e.isActive("resource") || e.isActive("button") || findRepeatTable(e) !== null), children: selectedBlock !== null ? (_jsxs("div", { className: BUBBLE_BAR_CLASS, "data-testid": "document-block-options", children: [_jsxs("span", { className: "px-1.5 text-[10px] text-muted-foreground", children: [selectedBlock.type === "resource"
480
+ ? t("template-resolver.documentEditor.resourceKey")
481
+ : t("template-resolver.documentEditor.buttonTarget"), ": ", selectedBlock.type === "button" ? (_jsx("strong", { children: buttonTargetLabel(selectedBlock.detail, variableLabels) })) : (_jsx("code", { children: selectedBlock.detail }))] }), _jsx(Button, { type: "button", size: "sm", variant: "danger-ghost", onClick: () => {
482
+ editor.chain().focus().deleteNode(selectedBlock.type).run();
483
+ }, children: t("template-resolver.documentEditor.removeBlock") })] })) : (repeatTable !== null && (_jsxs("div", { "data-testid": "document-repeat-bar", className: BUBBLE_BAR_CLASS, children: [_jsx("span", { className: "px-1.5 text-[10px] uppercase tracking-wide text-muted-foreground", children: repeatBarLabel }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", pressed: repeatTable.headerRepeats, onClick: () => toggleRepeatHeader(editor), children: t("template-resolver.documentEditor.repeatHeader") })] }))) }, mountKeyOf(editor)));
484
+ const insertPanel = openPanel !== null && !readOnly && (_jsx(InsertPanel, { editor: editor, editorId: id, kind: openPanel, variables: variables, onClose: () => setOpenPanel(null) }, openPanel));
485
+ if (hosted) {
486
+ return (_jsxs(_Fragment, { children: [toolbarHost !== null &&
487
+ createPortal(_jsxs(_Fragment, { children: [toolbarBar, insertPanel] }), toolbarHost), !readOnly && bubbleMenu, editorContent] }));
488
+ }
489
+ return (_jsxs("div", { className: cn(canvas ? "flex min-h-0 flex-1 flex-col" : "rounded-md border border-input bg-transparent"), children: [!hosted && toolbarBar, canvas && !readOnly && bubbleMenu, canvas && !hosted && showHtml && (_jsx("section", { "aria-label": t("template-resolver.documentEditor.htmlSource"), children: _jsx("pre", { className: "h-40 overflow-auto whitespace-pre-wrap break-all border-b border-input bg-muted p-2 font-mono text-xs", children: activeState?.html ?? "" }) })), !hosted && insertPanel, repeatTable !== null && !readOnly && !canvas && (_jsxs("div", { "data-testid": "document-repeat-bar", className: "flex flex-wrap items-center gap-3 border-b border-input bg-muted/40 px-2 py-1 text-xs", children: [_jsx("span", { className: "font-medium", children: repeatListLabel === undefined
490
+ ? t("template-resolver.documentEditor.repeat")
491
+ : t("template-resolver.documentEditor.repeatBarList", { list: repeatListLabel }) }), _jsx(Button, { type: "button", variant: "secondary", size: "sm", pressed: repeatTable.headerRepeats, onClick: () => toggleRepeatHeader(editor), children: t("template-resolver.documentEditor.repeatHeader") })] })), _jsx("div", { ref: setCanvasScroller, className: cn(canvas && "min-h-0 flex-1 overflow-auto bg-muted px-8 py-6"), children: canvas && renderPaper !== undefined ? renderPaper(editorContent) : editorContent })] }));
492
+ }
@@ -0,0 +1,41 @@
1
+ import type { ContentEditorProps } from "@cosmicdrift/kumiko-renderer";
2
+ import type { ReactNode } from "react";
3
+ export type DocumentToolbarBlock = "image" | "table" | "button" | "divider" | "repeat" | "pageBreak" | "align";
4
+ /** Imperative access for an outside panel (placeholder list, resource list). */
5
+ export type DocumentEditorHandle = {
6
+ readonly insertPlaceholder: (name: string) => void;
7
+ readonly insertResource: (key: string, alt?: string) => void;
8
+ readonly focus: () => void;
9
+ };
10
+ export type DocumentResourcePreview = {
11
+ /** Shown as the image source in the editor only; never written to the document. */
12
+ readonly src: string;
13
+ readonly caption?: string;
14
+ };
15
+ /** "default" keeps the compact bordered editor; "canvas" renders a flat text
16
+ * toolbar and a paper-like page with block labels. */
17
+ export type DocumentEditorChrome = "default" | "canvas";
18
+ export type DocumentEditorProps = ContentEditorProps & {
19
+ readonly blocks?: readonly DocumentToolbarBlock[];
20
+ /** Display label per variable name, as inserted (list item fields use the
21
+ * dotted form, e.g. "lines.description"). A chip shows label and name. */
22
+ readonly variableLabels?: Readonly<Record<string, string>>;
23
+ /** Variable names rendered as system chips (a different tint). */
24
+ readonly systemVariables?: readonly string[];
25
+ /** Image previews by resource key; resources without one show a key placeholder. */
26
+ readonly resourcePreviews?: Readonly<Record<string, DocumentResourcePreview>>;
27
+ readonly chrome?: DocumentEditorChrome;
28
+ /** "compact" renders the placeholder and block buttons icon-only with a tooltip, for narrow columns. Default "full". */
29
+ readonly toolbar?: "full" | "compact";
30
+ /** Canvas only: wraps the editable area in a caller-owned page (letterhead, margins) instead of the default mail paper. */
31
+ readonly renderPaper?: (editable: ReactNode) => ReactNode;
32
+ /** Canvas only: renders the toolbar (and its insert panel) into this element instead of above the editor;
33
+ * null renders none. Lets several region editors share one toolbar that follows the focused one. */
34
+ readonly toolbarHost?: HTMLElement | null;
35
+ /** Called with the handle once the editor exists and with null when it is destroyed. */
36
+ readonly onEditorReady?: (handle: DocumentEditorHandle) => void;
37
+ };
38
+ export declare const MAIL_DOCUMENT_BLOCKS: readonly ["image", "table", "button", "divider", "repeat"];
39
+ export declare const PDF_DOCUMENT_BLOCKS: readonly ["align", "image", "table", "divider", "repeat", "pageBreak"];
40
+ /** Block set for a template-resource kind; every kind except "document-pdf" gets the mail set. */
41
+ export declare function documentBlocksForKind(kind: string | undefined): readonly DocumentToolbarBlock[];
@@ -0,0 +1,19 @@
1
+ export const MAIL_DOCUMENT_BLOCKS = [
2
+ "image",
3
+ "table",
4
+ "button",
5
+ "divider",
6
+ "repeat",
7
+ ];
8
+ export const PDF_DOCUMENT_BLOCKS = [
9
+ "align",
10
+ "image",
11
+ "table",
12
+ "divider",
13
+ "repeat",
14
+ "pageBreak",
15
+ ];
16
+ /** Block set for a template-resource kind; every kind except "document-pdf" gets the mail set. */
17
+ export function documentBlocksForKind(kind) {
18
+ return kind === "document-pdf" ? PDF_DOCUMENT_BLOCKS : MAIL_DOCUMENT_BLOCKS;
19
+ }
@@ -0,0 +1,3 @@
1
+ import type { Editor } from "@tiptap/core";
2
+ import type { DocumentEditorHandle } from "./document-toolbar-blocks.js";
3
+ export declare function createEditorHandle(editor: Editor): DocumentEditorHandle;
@@ -0,0 +1,24 @@
1
+ import { isDocumentReferenceName, isDocumentResourceKey } from "../document-schema.js";
2
+ export function createEditorHandle(editor) {
3
+ return {
4
+ insertPlaceholder: (name) => {
5
+ // skip: an invalid variable name is not insertable
6
+ if (!isDocumentReferenceName(name))
7
+ return;
8
+ editor.chain().focus().insertContent({ type: "variable", attrs: { name } }).run();
9
+ },
10
+ insertResource: (key, alt) => {
11
+ // skip: an invalid resource key is not insertable
12
+ if (!isDocumentResourceKey(key))
13
+ return;
14
+ editor
15
+ .chain()
16
+ .focus()
17
+ .insertContent({ type: "resource", attrs: { resource: key, alt: alt ?? null } })
18
+ .run();
19
+ },
20
+ focus: () => {
21
+ editor.commands.focus();
22
+ },
23
+ };
24
+ }