makersclaw 0.2.0 → 0.3.1
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.
- package/THIRD-PARTY-NOTICES.md +180 -0
- package/package.json +3 -2
- package/r/annotate.json +62 -0
- package/r/approval-request.json +52 -0
- package/r/audio-player.json +74 -0
- package/r/auth-form.json +55 -0
- package/r/board.json +10 -6
- package/r/calendar-view.json +105 -0
- package/r/cart.json +62 -0
- package/r/chart.json +83 -0
- package/r/chat.json +95 -0
- package/r/code-editor.json +94 -0
- package/r/comment-box.json +64 -0
- package/r/contact-section.json +53 -0
- package/r/core.json +205 -8
- package/r/csv-import.json +63 -0
- package/r/data-table.json +69 -0
- package/r/diagram.json +74 -0
- package/r/doc-editor.json +82 -0
- package/r/doc-page.json +61 -0
- package/r/email-render.json +73 -0
- package/r/faq.json +50 -0
- package/r/file-upload.json +54 -0
- package/r/flow-canvas.json +93 -0
- package/r/footer.json +52 -0
- package/r/gantt.json +70 -0
- package/r/job-panel.json +12 -7
- package/r/json-editor.json +66 -0
- package/r/map.json +89 -0
- package/r/menubar.json +52 -0
- package/r/mind-map.json +67 -0
- package/r/navigation-menu.json +52 -0
- package/r/order-detail.json +54 -0
- package/r/org-chart.json +66 -0
- package/r/page-builder.json +105 -0
- package/r/payment-methods.json +51 -0
- package/r/pdf-document.json +79 -0
- package/r/pdf-viewer.json +88 -0
- package/r/product-detail.json +76 -0
- package/r/product-grid.json +65 -0
- package/r/record-form.json +67 -0
- package/r/record-notes.json +55 -0
- package/r/registry.json +3411 -29
- package/r/search-dialog.json +51 -0
- package/r/settings-list.json +66 -0
- package/r/setup-checklist.json +51 -0
- package/r/share-dialog.json +52 -0
- package/r/sidebar.json +69 -0
- package/r/signature-pad.json +72 -0
- package/r/sketch-canvas.json +99 -0
- package/r/spreadsheet.json +90 -0
- package/r/stat-cards.json +66 -0
- package/r/task-list.json +63 -0
- package/r/task-model.json +98 -0
- package/r/testimonials.json +52 -0
- package/r/transaction-list.json +53 -0
- package/r/whiteboard.json +66 -0
- package/registry/blocks/annotate/README.md +179 -0
- package/registry/blocks/annotate/annotate-data.js +250 -0
- package/registry/blocks/annotate/annotate.jsx +646 -0
- package/registry/blocks/annotate/block.json +10 -0
- package/registry/blocks/annotate/demo.jsx +135 -0
- package/registry/blocks/annotate/index.js +15 -0
- package/registry/blocks/approval-request/README.md +116 -0
- package/registry/blocks/approval-request/approval-request.jsx +386 -0
- package/registry/blocks/approval-request/block.json +10 -0
- package/registry/blocks/approval-request/demo.jsx +127 -0
- package/registry/blocks/approval-request/index.js +4 -0
- package/registry/blocks/audio-player/README.md +167 -0
- package/registry/blocks/audio-player/audio-player.jsx +623 -0
- package/registry/blocks/audio-player/block.json +14 -0
- package/registry/blocks/audio-player/colors.js +109 -0
- package/registry/blocks/audio-player/demo.jsx +209 -0
- package/registry/blocks/audio-player/index.js +6 -0
- package/registry/blocks/audio-player/time.js +67 -0
- package/registry/blocks/audio-player/wavesurfer.js +9 -0
- package/registry/blocks/auth-form/README.md +126 -0
- package/registry/blocks/auth-form/auth-form.jsx +568 -0
- package/registry/blocks/auth-form/block.json +10 -0
- package/registry/blocks/auth-form/demo.jsx +131 -0
- package/registry/blocks/auth-form/index.js +3 -0
- package/registry/blocks/board/README.md +55 -5
- package/registry/blocks/board/block.json +2 -2
- package/registry/blocks/board/board.jsx +230 -86
- package/registry/blocks/board/demo.jsx +103 -24
- package/registry/blocks/calendar-view/README.md +180 -0
- package/registry/blocks/calendar-view/agenda.jsx +147 -0
- package/registry/blocks/calendar-view/block.json +76 -0
- package/registry/blocks/calendar-view/calendar-model.js +442 -0
- package/registry/blocks/calendar-view/calendar.jsx +627 -0
- package/registry/blocks/calendar-view/demo.jsx +195 -0
- package/registry/blocks/calendar-view/draft.jsx +49 -0
- package/registry/blocks/calendar-view/index.js +39 -0
- package/registry/blocks/calendar-view/month.jsx +346 -0
- package/registry/blocks/calendar-view/paint.js +69 -0
- package/registry/blocks/calendar-view/time-grid.jsx +527 -0
- package/registry/blocks/calendar-view/tray.jsx +87 -0
- package/registry/blocks/cart/README.md +146 -0
- package/registry/blocks/cart/block.json +10 -0
- package/registry/blocks/cart/cart.jsx +597 -0
- package/registry/blocks/cart/demo.jsx +98 -0
- package/registry/blocks/cart/index.js +4 -0
- package/registry/blocks/cart/money.js +28 -0
- package/registry/blocks/chart/README.md +316 -0
- package/registry/blocks/chart/block.json +10 -0
- package/registry/blocks/chart/cartesian.jsx +642 -0
- package/registry/blocks/chart/core.jsx +262 -0
- package/registry/blocks/chart/demo.jsx +357 -0
- package/registry/blocks/chart/heatmap.jsx +336 -0
- package/registry/blocks/chart/index.js +8 -0
- package/registry/blocks/chart/pie.jsx +245 -0
- package/registry/blocks/chart/sparkline.jsx +88 -0
- package/registry/blocks/chat/README.md +273 -0
- package/registry/blocks/chat/attachment.jsx +95 -0
- package/registry/blocks/chat/block.json +10 -0
- package/registry/blocks/chat/chat.jsx +132 -0
- package/registry/blocks/chat/composer.jsx +364 -0
- package/registry/blocks/chat/demo.jsx +578 -0
- package/registry/blocks/chat/header.jsx +34 -0
- package/registry/blocks/chat/index.js +9 -0
- package/registry/blocks/chat/message.jsx +450 -0
- package/registry/blocks/chat/scroller.jsx +247 -0
- package/registry/blocks/chat/text.jsx +104 -0
- package/registry/blocks/code-editor/README.md +210 -0
- package/registry/blocks/code-editor/block.json +22 -0
- package/registry/blocks/code-editor/code-editor.jsx +534 -0
- package/registry/blocks/code-editor/codemirror.js +38 -0
- package/registry/blocks/code-editor/demo.jsx +205 -0
- package/registry/blocks/code-editor/index.js +8 -0
- package/registry/blocks/code-editor/json.js +317 -0
- package/registry/blocks/code-editor/sql.js +136 -0
- package/registry/blocks/code-editor/text.js +101 -0
- package/registry/blocks/code-editor/theme.js +186 -0
- package/registry/blocks/comment-box/README.md +123 -0
- package/registry/blocks/comment-box/block.json +10 -0
- package/registry/blocks/comment-box/comment-body.jsx +217 -0
- package/registry/blocks/comment-box/comment-box.jsx +198 -0
- package/registry/blocks/comment-box/comment-time.jsx +77 -0
- package/registry/blocks/comment-box/demo.jsx +141 -0
- package/registry/blocks/comment-box/index.js +8 -0
- package/registry/blocks/contact-section/README.md +152 -0
- package/registry/blocks/contact-section/block.json +11 -0
- package/registry/blocks/contact-section/contact-section.jsx +509 -0
- package/registry/blocks/contact-section/demo.jsx +93 -0
- package/registry/blocks/contact-section/index.js +4 -0
- package/registry/blocks/csv-import/README.md +133 -0
- package/registry/blocks/csv-import/block.json +13 -0
- package/registry/blocks/csv-import/csv-import.jsx +479 -0
- package/registry/blocks/csv-import/demo.jsx +106 -0
- package/registry/blocks/csv-import/import.js +200 -0
- package/registry/blocks/csv-import/index.js +7 -0
- package/registry/blocks/data-table/README.md +386 -0
- package/registry/blocks/data-table/block.json +10 -0
- package/registry/blocks/data-table/data-table.jsx +1164 -0
- package/registry/blocks/data-table/demo.jsx +588 -0
- package/registry/blocks/data-table/index.js +5 -0
- package/registry/blocks/data-table/model.js +169 -0
- package/registry/blocks/diagram/README.md +108 -0
- package/registry/blocks/diagram/block.json +13 -0
- package/registry/blocks/diagram/demo.jsx +113 -0
- package/registry/blocks/diagram/diagram.jsx +481 -0
- package/registry/blocks/diagram/index.js +7 -0
- package/registry/blocks/diagram/mermaid.js +52 -0
- package/registry/blocks/diagram/palette.js +313 -0
- package/registry/blocks/diagram/source.js +98 -0
- package/registry/blocks/doc-editor/README.md +215 -0
- package/registry/blocks/doc-editor/block.json +15 -0
- package/registry/blocks/doc-editor/demo.jsx +225 -0
- package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
- package/registry/blocks/doc-editor/doc.js +309 -0
- package/registry/blocks/doc-editor/index.js +7 -0
- package/registry/blocks/doc-editor/schema.jsx +56 -0
- package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
- package/registry/blocks/doc-editor/theme.js +82 -0
- package/registry/blocks/doc-page/README.md +119 -0
- package/registry/blocks/doc-page/autosave.js +104 -0
- package/registry/blocks/doc-page/block.json +10 -0
- package/registry/blocks/doc-page/demo.jsx +137 -0
- package/registry/blocks/doc-page/doc-page.jsx +276 -0
- package/registry/blocks/doc-page/index.js +4 -0
- package/registry/blocks/email-render/README.md +151 -0
- package/registry/blocks/email-render/block.json +14 -0
- package/registry/blocks/email-render/demo.jsx +153 -0
- package/registry/blocks/email-render/doc-email.jsx +210 -0
- package/registry/blocks/email-render/email.jsx +221 -0
- package/registry/blocks/email-render/index.js +10 -0
- package/registry/blocks/email-render/render.js +50 -0
- package/registry/blocks/email-render/theme.js +215 -0
- package/registry/blocks/faq/README.md +101 -0
- package/registry/blocks/faq/block.json +11 -0
- package/registry/blocks/faq/demo.jsx +89 -0
- package/registry/blocks/faq/faq.jsx +220 -0
- package/registry/blocks/faq/index.js +4 -0
- package/registry/blocks/file-upload/README.md +138 -0
- package/registry/blocks/file-upload/block.json +10 -0
- package/registry/blocks/file-upload/demo.jsx +204 -0
- package/registry/blocks/file-upload/file-upload.jsx +635 -0
- package/registry/blocks/file-upload/index.js +4 -0
- package/registry/blocks/flow-canvas/README.md +420 -0
- package/registry/blocks/flow-canvas/block.json +13 -0
- package/registry/blocks/flow-canvas/board.js +819 -0
- package/registry/blocks/flow-canvas/chrome.jsx +649 -0
- package/registry/blocks/flow-canvas/context.jsx +35 -0
- package/registry/blocks/flow-canvas/demo.jsx +249 -0
- package/registry/blocks/flow-canvas/edges.jsx +107 -0
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
- package/registry/blocks/flow-canvas/index.js +41 -0
- package/registry/blocks/flow-canvas/nodes.jsx +392 -0
- package/registry/blocks/flow-canvas/theme.js +174 -0
- package/registry/blocks/footer/README.md +133 -0
- package/registry/blocks/footer/block.json +11 -0
- package/registry/blocks/footer/demo.jsx +119 -0
- package/registry/blocks/footer/footer.jsx +406 -0
- package/registry/blocks/footer/index.js +4 -0
- package/registry/blocks/gantt/README.md +220 -0
- package/registry/blocks/gantt/block.json +10 -0
- package/registry/blocks/gantt/demo.jsx +148 -0
- package/registry/blocks/gantt/gantt.jsx +923 -0
- package/registry/blocks/gantt/index.js +7 -0
- package/registry/blocks/gantt/rows.jsx +468 -0
- package/registry/blocks/gantt/schedule.js +278 -0
- package/registry/blocks/job-panel/README.md +80 -0
- package/registry/blocks/job-panel/block.json +3 -3
- package/registry/blocks/job-panel/demo.jsx +230 -3
- package/registry/blocks/job-panel/job-panel.jsx +169 -3
- package/registry/blocks/json-editor/README.md +133 -0
- package/registry/blocks/json-editor/block.json +10 -0
- package/registry/blocks/json-editor/demo.jsx +92 -0
- package/registry/blocks/json-editor/index.js +7 -0
- package/registry/blocks/json-editor/json-editor.jsx +305 -0
- package/registry/blocks/json-editor/json-tree.jsx +393 -0
- package/registry/blocks/json-editor/tree.js +225 -0
- package/registry/blocks/map/README.md +221 -0
- package/registry/blocks/map/block.json +14 -0
- package/registry/blocks/map/demo.jsx +201 -0
- package/registry/blocks/map/geo.js +198 -0
- package/registry/blocks/map/index.js +8 -0
- package/registry/blocks/map/list.jsx +128 -0
- package/registry/blocks/map/map-view.jsx +715 -0
- package/registry/blocks/map/maplibre.js +30 -0
- package/registry/blocks/map/marks.jsx +146 -0
- package/registry/blocks/map/theme.js +142 -0
- package/registry/blocks/menubar/README.md +109 -0
- package/registry/blocks/menubar/block.json +10 -0
- package/registry/blocks/menubar/demo.jsx +128 -0
- package/registry/blocks/menubar/index.js +4 -0
- package/registry/blocks/menubar/menubar.jsx +199 -0
- package/registry/blocks/mind-map/README.md +206 -0
- package/registry/blocks/mind-map/block.json +10 -0
- package/registry/blocks/mind-map/demo.jsx +103 -0
- package/registry/blocks/mind-map/index.js +31 -0
- package/registry/blocks/mind-map/mind-map.jsx +1125 -0
- package/registry/blocks/mind-map/topic.jsx +143 -0
- package/registry/blocks/mind-map/tree.js +645 -0
- package/registry/blocks/navigation-menu/README.md +124 -0
- package/registry/blocks/navigation-menu/block.json +10 -0
- package/registry/blocks/navigation-menu/demo.jsx +84 -0
- package/registry/blocks/navigation-menu/index.js +4 -0
- package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
- package/registry/blocks/order-detail/README.md +109 -0
- package/registry/blocks/order-detail/block.json +10 -0
- package/registry/blocks/order-detail/demo.jsx +88 -0
- package/registry/blocks/order-detail/index.js +4 -0
- package/registry/blocks/order-detail/order-detail.jsx +354 -0
- package/registry/blocks/org-chart/README.md +145 -0
- package/registry/blocks/org-chart/block.json +10 -0
- package/registry/blocks/org-chart/demo.jsx +94 -0
- package/registry/blocks/org-chart/index.js +7 -0
- package/registry/blocks/org-chart/org-chart.jsx +631 -0
- package/registry/blocks/org-chart/org.js +245 -0
- package/registry/blocks/org-chart/person.jsx +96 -0
- package/registry/blocks/page-builder/README.md +257 -0
- package/registry/blocks/page-builder/block.json +14 -0
- package/registry/blocks/page-builder/demo.jsx +145 -0
- package/registry/blocks/page-builder/grapes.js +18 -0
- package/registry/blocks/page-builder/index.js +11 -0
- package/registry/blocks/page-builder/page-builder.jsx +704 -0
- package/registry/blocks/page-builder/page-view.jsx +33 -0
- package/registry/blocks/page-builder/page.js +118 -0
- package/registry/blocks/page-builder/panels.jsx +588 -0
- package/registry/blocks/page-builder/sections.js +209 -0
- package/registry/blocks/page-builder/theme.js +87 -0
- package/registry/blocks/page-builder/thumbs.jsx +189 -0
- package/registry/blocks/page-builder/tokens.js +329 -0
- package/registry/blocks/payment-methods/README.md +104 -0
- package/registry/blocks/payment-methods/block.json +10 -0
- package/registry/blocks/payment-methods/demo.jsx +71 -0
- package/registry/blocks/payment-methods/index.js +4 -0
- package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
- package/registry/blocks/pdf-document/README.md +213 -0
- package/registry/blocks/pdf-document/block.json +13 -0
- package/registry/blocks/pdf-document/demo.jsx +136 -0
- package/registry/blocks/pdf-document/index.js +33 -0
- package/registry/blocks/pdf-document/money.js +83 -0
- package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
- package/registry/blocks/pdf-document/primitives.jsx +271 -0
- package/registry/blocks/pdf-document/quote.jsx +179 -0
- package/registry/blocks/pdf-document/theme.js +193 -0
- package/registry/blocks/pdf-viewer/README.md +191 -0
- package/registry/blocks/pdf-viewer/block.json +14 -0
- package/registry/blocks/pdf-viewer/demo.jsx +252 -0
- package/registry/blocks/pdf-viewer/helpers.js +270 -0
- package/registry/blocks/pdf-viewer/index.js +8 -0
- package/registry/blocks/pdf-viewer/notes.jsx +195 -0
- package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
- package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
- package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
- package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
- package/registry/blocks/product-detail/README.md +217 -0
- package/registry/blocks/product-detail/block.json +10 -0
- package/registry/blocks/product-detail/demo.jsx +233 -0
- package/registry/blocks/product-detail/index.js +7 -0
- package/registry/blocks/product-detail/price.jsx +115 -0
- package/registry/blocks/product-detail/product-detail.jsx +348 -0
- package/registry/blocks/product-detail/product-media.jsx +102 -0
- package/registry/blocks/product-detail/product-options.jsx +144 -0
- package/registry/blocks/product-grid/README.md +162 -0
- package/registry/blocks/product-grid/block.json +10 -0
- package/registry/blocks/product-grid/demo.jsx +255 -0
- package/registry/blocks/product-grid/index.js +5 -0
- package/registry/blocks/product-grid/product-card.jsx +232 -0
- package/registry/blocks/product-grid/product-grid.jsx +235 -0
- package/registry/blocks/record-form/README.md +196 -0
- package/registry/blocks/record-form/block.json +10 -0
- package/registry/blocks/record-form/demo.jsx +525 -0
- package/registry/blocks/record-form/index.js +4 -0
- package/registry/blocks/record-form/record-fields.jsx +457 -0
- package/registry/blocks/record-form/record-form.jsx +415 -0
- package/registry/blocks/record-form/rules.js +81 -0
- package/registry/blocks/record-notes/README.md +139 -0
- package/registry/blocks/record-notes/block.json +10 -0
- package/registry/blocks/record-notes/demo.jsx +179 -0
- package/registry/blocks/record-notes/index.js +4 -0
- package/registry/blocks/record-notes/record-notes.jsx +266 -0
- package/registry/blocks/search-dialog/README.md +108 -0
- package/registry/blocks/search-dialog/block.json +10 -0
- package/registry/blocks/search-dialog/demo.jsx +116 -0
- package/registry/blocks/search-dialog/index.js +3 -0
- package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
- package/registry/blocks/settings-list/README.md +171 -0
- package/registry/blocks/settings-list/block.json +10 -0
- package/registry/blocks/settings-list/demo.jsx +333 -0
- package/registry/blocks/settings-list/index.js +4 -0
- package/registry/blocks/settings-list/row-state.jsx +93 -0
- package/registry/blocks/settings-list/settings-list.jsx +349 -0
- package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
- package/registry/blocks/setup-checklist/README.md +142 -0
- package/registry/blocks/setup-checklist/block.json +10 -0
- package/registry/blocks/setup-checklist/demo.jsx +159 -0
- package/registry/blocks/setup-checklist/index.js +4 -0
- package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
- package/registry/blocks/share-dialog/README.md +113 -0
- package/registry/blocks/share-dialog/block.json +10 -0
- package/registry/blocks/share-dialog/demo.jsx +140 -0
- package/registry/blocks/share-dialog/index.js +3 -0
- package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
- package/registry/blocks/sidebar/README.md +190 -0
- package/registry/blocks/sidebar/block.json +43 -0
- package/registry/blocks/sidebar/demo.jsx +577 -0
- package/registry/blocks/sidebar/index.js +4 -0
- package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
- package/registry/blocks/sidebar/sidebar.jsx +864 -0
- package/registry/blocks/signature-pad/README.md +137 -0
- package/registry/blocks/signature-pad/block.json +13 -0
- package/registry/blocks/signature-pad/colors.js +115 -0
- package/registry/blocks/signature-pad/demo.jsx +94 -0
- package/registry/blocks/signature-pad/index.js +6 -0
- package/registry/blocks/signature-pad/pad.js +7 -0
- package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
- package/registry/blocks/signature-pad/signature.js +68 -0
- package/registry/blocks/sketch-canvas/README.md +280 -0
- package/registry/blocks/sketch-canvas/block.json +13 -0
- package/registry/blocks/sketch-canvas/demo.jsx +159 -0
- package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
- package/registry/blocks/sketch-canvas/index.js +9 -0
- package/registry/blocks/sketch-canvas/palette.js +226 -0
- package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
- package/registry/blocks/sketch-canvas/sketch.js +179 -0
- package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
- package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
- package/registry/blocks/sketch-canvas/stamps.js +104 -0
- package/registry/blocks/sketch-canvas/theme.js +131 -0
- package/registry/blocks/spreadsheet/README.md +307 -0
- package/registry/blocks/spreadsheet/block.json +13 -0
- package/registry/blocks/spreadsheet/cells.jsx +455 -0
- package/registry/blocks/spreadsheet/chrome.jsx +325 -0
- package/registry/blocks/spreadsheet/demo.jsx +177 -0
- package/registry/blocks/spreadsheet/grid.js +387 -0
- package/registry/blocks/spreadsheet/index.js +34 -0
- package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
- package/registry/blocks/spreadsheet/types.js +473 -0
- package/registry/blocks/stat-cards/README.md +173 -0
- package/registry/blocks/stat-cards/block.json +10 -0
- package/registry/blocks/stat-cards/demo.jsx +257 -0
- package/registry/blocks/stat-cards/index.js +4 -0
- package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
- package/registry/blocks/stat-cards/usage.jsx +243 -0
- package/registry/blocks/task-list/README.md +176 -0
- package/registry/blocks/task-list/block.json +10 -0
- package/registry/blocks/task-list/demo.jsx +134 -0
- package/registry/blocks/task-list/index.js +5 -0
- package/registry/blocks/task-list/task-list.jsx +907 -0
- package/registry/blocks/task-model/README.md +455 -0
- package/registry/blocks/task-model/block.json +167 -0
- package/registry/blocks/task-model/changes.js +89 -0
- package/registry/blocks/task-model/dates.js +371 -0
- package/registry/blocks/task-model/demo.jsx +215 -0
- package/registry/blocks/task-model/dnd.jsx +240 -0
- package/registry/blocks/task-model/index.js +97 -0
- package/registry/blocks/task-model/model.js +919 -0
- package/registry/blocks/task-model/parts.jsx +449 -0
- package/registry/blocks/task-model/toolbar.jsx +271 -0
- package/registry/blocks/testimonials/README.md +139 -0
- package/registry/blocks/testimonials/block.json +11 -0
- package/registry/blocks/testimonials/demo.jsx +137 -0
- package/registry/blocks/testimonials/index.js +4 -0
- package/registry/blocks/testimonials/testimonials.jsx +430 -0
- package/registry/blocks/transaction-list/README.md +126 -0
- package/registry/blocks/transaction-list/block.json +10 -0
- package/registry/blocks/transaction-list/demo.jsx +79 -0
- package/registry/blocks/transaction-list/index.js +4 -0
- package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
- package/registry/blocks/whiteboard/README.md +179 -0
- package/registry/blocks/whiteboard/block.json +10 -0
- package/registry/blocks/whiteboard/demo.jsx +169 -0
- package/registry/blocks/whiteboard/index.js +6 -0
- package/registry/blocks/whiteboard/templates.js +150 -0
- package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
- package/src/cli.mjs +19 -6
- package/src/install.mjs +18 -0
- package/src/registry.mjs +38 -4
- package/src/shadcn.mjs +14 -1
- package/templates/next/files/README.md +145 -11
- package/templates/next/files/app/globals.css +55 -4
- package/templates/next/files/check/run.mjs +3 -3
- package/templates/next/files/components/ui/avatar.jsx +141 -0
- package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
- package/templates/next/files/components/ui/button-group.jsx +70 -0
- package/templates/next/files/components/ui/button.jsx +132 -12
- package/templates/next/files/components/ui/calendar.jsx +609 -0
- package/templates/next/files/components/ui/carousel.jsx +281 -0
- package/templates/next/files/components/ui/collapsible.jsx +208 -0
- package/templates/next/files/components/ui/combobox.jsx +608 -0
- package/templates/next/files/components/ui/command.jsx +577 -0
- package/templates/next/files/components/ui/context-menu.jsx +191 -0
- package/templates/next/files/components/ui/date-picker.jsx +360 -0
- package/templates/next/files/components/ui/distribution.jsx +117 -0
- package/templates/next/files/components/ui/feedback.jsx +143 -0
- package/templates/next/files/components/ui/field.jsx +115 -3
- package/templates/next/files/components/ui/file-input.jsx +234 -0
- package/templates/next/files/components/ui/icon.jsx +130 -8
- package/templates/next/files/components/ui/image.jsx +143 -0
- package/templates/next/files/components/ui/index.js +47 -2
- package/templates/next/files/components/ui/input-group.jsx +213 -0
- package/templates/next/files/components/ui/input-otp.jsx +170 -0
- package/templates/next/files/components/ui/item.jsx +206 -0
- package/templates/next/files/components/ui/menu.jsx +454 -82
- package/templates/next/files/components/ui/notice.jsx +126 -14
- package/templates/next/files/components/ui/pagination.jsx +156 -0
- package/templates/next/files/components/ui/popover.jsx +284 -0
- package/templates/next/files/components/ui/radio.jsx +193 -0
- package/templates/next/files/components/ui/rating.jsx +131 -0
- package/templates/next/files/components/ui/resizable.jsx +338 -0
- package/templates/next/files/components/ui/scroll-area.jsx +123 -0
- package/templates/next/files/components/ui/separator.jsx +119 -0
- package/templates/next/files/components/ui/sheet.jsx +96 -11
- package/templates/next/files/components/ui/slider.jsx +174 -0
- package/templates/next/files/components/ui/stat.jsx +574 -0
- package/templates/next/files/components/ui/steps.jsx +338 -0
- package/templates/next/files/components/ui/swatch.jsx +33 -0
- package/templates/next/files/components/ui/table.jsx +130 -0
- package/templates/next/files/components/ui/toast.jsx +440 -0
- package/templates/next/files/components/ui/toggle.jsx +195 -0
- package/templates/next/files/components/ui/tooltip.jsx +270 -0
- package/templates/next/template.json +264 -8
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
# EmailRender
|
|
2
|
+
|
|
3
|
+
Email HTML from React, in the workspace theme. A layout with the 600px
|
|
4
|
+
column every client draws well and the preview line inboxes show after
|
|
5
|
+
the subject; a brand line for the top; a footer with the sender's address
|
|
6
|
+
and the unsubscribe link; buttons, headings and text; and `DocEmail`,
|
|
7
|
+
which draws a `doc-editor` document as email markup. `renderEmail` turns
|
|
8
|
+
the tree into `{ html, text }`: the HTML for the send and the plain-text
|
|
9
|
+
part beside it.
|
|
10
|
+
|
|
11
|
+
It is [react-email](https://react.email) (MIT) underneath:
|
|
12
|
+
`@react-email/components` for the parts and `@react-email/render` for the
|
|
13
|
+
HTML. The blocks built on this one (`newsletter-builder` first) import it,
|
|
14
|
+
never `@react-email/*` directly.
|
|
15
|
+
|
|
16
|
+
```jsx
|
|
17
|
+
import { EmailLayout, EmailCard, DocEmail, renderEmail, resolveEmailTheme } from "../components/blocks/email-render"; // a Makersclaw app ("./blocks/email-render" from components/)
|
|
18
|
+
import { EmailLayout, EmailCard, DocEmail, renderEmail, resolveEmailTheme } from "@/components/makersclaw/blocks/email-render"; // a shadcn project
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Everything here is server-safe (no hooks, no context), except
|
|
22
|
+
`resolveEmailTheme`, which reads the page. `makersclaw add email-render`
|
|
23
|
+
adds `@react-email/components` and `@react-email/render` (pinned, exact)
|
|
24
|
+
to package.json: run `npm install` after.
|
|
25
|
+
|
|
26
|
+
## Email cannot read the theme
|
|
27
|
+
|
|
28
|
+
**An email never sees the app's stylesheet, and most clients ignore CSS
|
|
29
|
+
variables. So an email carries concrete colours, copied from the theme
|
|
30
|
+
when it is rendered.**
|
|
31
|
+
|
|
32
|
+
- In the browser, `resolveEmailTheme(root)` reads every token where
|
|
33
|
+
`root` sits (its light or dark scheme, any `[data-theme]` scope) and
|
|
34
|
+
returns plain hex values, the theme's typefaces with web-safe
|
|
35
|
+
fallbacks, and its corner radius. A colour with transparency is laid
|
|
36
|
+
over the background first: email has none to rely on.
|
|
37
|
+
- On the server there is no page to read. Pass the theme the browser
|
|
38
|
+
resolved (it is plain JSON; send it along with the email), or use
|
|
39
|
+
`EMAIL_FALLBACK`, a neutral light theme of greys.
|
|
40
|
+
- The source of truth stays the theme. Re-render to pick up a change.
|
|
41
|
+
|
|
42
|
+
The theme object:
|
|
43
|
+
|
|
44
|
+
```js
|
|
45
|
+
{
|
|
46
|
+
colors: { background: "…", foreground: "…", card: "…", "card-foreground": "…",
|
|
47
|
+
primary: "…", "primary-foreground": "…", muted: "…", "muted-foreground": "…",
|
|
48
|
+
border: "…", accent: "…", … }, // every name in EMAIL_TOKENS, as hex
|
|
49
|
+
font: "\"Schibsted Grotesk\", -apple-system, … sans-serif",
|
|
50
|
+
fontDisplay: "…", fontMono: "…",
|
|
51
|
+
radius: "8px",
|
|
52
|
+
scheme: "light" | "dark", // from the background; sets the color-scheme meta
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Props
|
|
57
|
+
|
|
58
|
+
Every part takes `theme` (above). Leave it out and the part uses
|
|
59
|
+
`EMAIL_FALLBACK`.
|
|
60
|
+
|
|
61
|
+
- `EmailLayout` — the whole email. `preview` (the preheader: the line an
|
|
62
|
+
inbox shows after the subject, up to ~110 characters), `title`, `lang`
|
|
63
|
+
(`"en"`), `children`.
|
|
64
|
+
- `EmailCard` — a raised panel in the column: card colour, hairline,
|
|
65
|
+
the theme's corner. `padding` (px, `32`).
|
|
66
|
+
- `EmailHeader` — the brand line. `name`, `logoUrl`, `logoAlt`,
|
|
67
|
+
`logoHeight` (`28`), `href`, `tagline`, `band` (`"none"` ·
|
|
68
|
+
`"primary"` · `"muted"` · `"card"`: a filled strip, the words in the
|
|
69
|
+
matching foreground), `align` (`"left"` · `"center"`).
|
|
70
|
+
- `EmailFooter` — the small print. `note` (why the reader gets this),
|
|
71
|
+
`address` (the sender's postal address; the law in most places wants
|
|
72
|
+
it), `unsubscribeUrl` (what your sender fills in, e.g.
|
|
73
|
+
`"{{unsubscribe_url}}"`), `unsubscribeLabel` (`"Unsubscribe"`), `links`
|
|
74
|
+
(`[{ label, href }]`), `align` (`"center"`).
|
|
75
|
+
- `EmailButton` — a padded link that works in every client. `href`,
|
|
76
|
+
`tone` (`"primary"` · `"secondary"` · `"foreground"`), `align`.
|
|
77
|
+
- `EmailHeading` (`level` 1–3, `align`), `EmailText` (`muted`, `size`
|
|
78
|
+
`"md"` · `"sm"`, `align`), `EmailDivider`.
|
|
79
|
+
- `DocEmail` — a `doc-editor` document as email markup. `doc` (the
|
|
80
|
+
BlockNote JSON), `fields` (merge fields: `{ key: value }` or
|
|
81
|
+
`(key, props) => value`; a key with no value stays `{key}`). Headings,
|
|
82
|
+
paragraphs, nested lists, checklists, quotes, code, tables, images with
|
|
83
|
+
captions, dividers; bold, italic, underline, strike, inline code and
|
|
84
|
+
links. A mention reads `@Label`. Text colours are dropped.
|
|
85
|
+
|
|
86
|
+
The functions:
|
|
87
|
+
|
|
88
|
+
- `await renderEmail(element, { pretty? })` → `{ ok: true, html, text }`
|
|
89
|
+
or `{ ok: false, error }` (in words, never a throw). `html` is a whole
|
|
90
|
+
`<!DOCTYPE html>` document with inline styles; `text` is its plain-text
|
|
91
|
+
part (headings in their own case, tables as rows).
|
|
92
|
+
- `resolveEmailTheme(root?)` — browser only; on the server it returns
|
|
93
|
+
`EMAIL_FALLBACK`.
|
|
94
|
+
- `emailColor(theme, token)` — a token name to its hex.
|
|
95
|
+
- `emailThemeKey(theme)` — a fingerprint: equal keys, nothing to
|
|
96
|
+
re-render.
|
|
97
|
+
- `emailPlainText(html)`, `fieldText(props, fields)`, `emailFontStack`,
|
|
98
|
+
`luminance`, `toHex`, `EMAIL_TOKENS`, `EMAIL_WIDTH` (600).
|
|
99
|
+
|
|
100
|
+
## Example
|
|
101
|
+
|
|
102
|
+
A preview in the browser:
|
|
103
|
+
|
|
104
|
+
```jsx
|
|
105
|
+
"use client";
|
|
106
|
+
import { useEffect, useRef, useState } from "react";
|
|
107
|
+
import { DocEmail, EmailButton, EmailCard, EmailFooter, EmailHeader, EmailLayout, renderEmail, resolveEmailTheme } from "./blocks/email-render";
|
|
108
|
+
|
|
109
|
+
export function InvitePreview({ doc, team }) {
|
|
110
|
+
const box = useRef(null);
|
|
111
|
+
const [html, setHtml] = useState("");
|
|
112
|
+
useEffect(() => {
|
|
113
|
+
const theme = resolveEmailTheme(box.current);
|
|
114
|
+
renderEmail(
|
|
115
|
+
<EmailLayout theme={theme} preview={`${team.name} invited you to plan with them.`}>
|
|
116
|
+
<EmailHeader theme={theme} name={team.name} />
|
|
117
|
+
<EmailCard theme={theme}>
|
|
118
|
+
<DocEmail doc={doc} theme={theme} fields={{ first_name: "Ana" }} />
|
|
119
|
+
<EmailButton theme={theme} href={team.inviteUrl}>Accept the invite</EmailButton>
|
|
120
|
+
</EmailCard>
|
|
121
|
+
<EmailFooter theme={theme} address={team.address} />
|
|
122
|
+
</EmailLayout>,
|
|
123
|
+
).then((r) => r.ok && setHtml(r.html));
|
|
124
|
+
}, [doc, team]);
|
|
125
|
+
return <div ref={box}><iframe title="Invite email" srcDoc={html} sandbox="" className="h-[600px] w-full rounded-md border border-border" /></div>;
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The same tree on the server, for the send (a server action):
|
|
130
|
+
|
|
131
|
+
```js
|
|
132
|
+
const { ok, html, text, error } = await renderEmail(<Newsletter theme={savedTheme} … />);
|
|
133
|
+
if (ok) await sender.send({ to, subject, html, text });
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## What it will not do
|
|
137
|
+
|
|
138
|
+
- Send email. It makes the HTML; your sender (Resend, Postmark, SES, the
|
|
139
|
+
app's server) sends it.
|
|
140
|
+
- Follow a later theme change inside an email already sent: the colours
|
|
141
|
+
are a copy made at render time.
|
|
142
|
+
- Dark-mode variants inside one email. It is drawn in the scheme it was
|
|
143
|
+
resolved in, and says so in its `color-scheme` meta.
|
|
144
|
+
- Tailwind classes in email. Styles are inline, which is what clients
|
|
145
|
+
keep.
|
|
146
|
+
|
|
147
|
+
## Credits
|
|
148
|
+
|
|
149
|
+
react-email (https://github.com/resend/react-email), MIT, © Resend —
|
|
150
|
+
installed from npm as dependencies, not copied here. See
|
|
151
|
+
THIRD-PARTY-NOTICES.md.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "email-render",
|
|
3
|
+
"title": "EmailRender",
|
|
4
|
+
"description": "Email HTML from React (react-email) in the workspace theme: a layout with the 600px column and the inbox preview line, a header brand line, a footer with the address and unsubscribe link, buttons, headings and text, and DocEmail, which draws a doc-editor document as email markup (lists, quotes, code, tables, images, merge fields). Email cannot read CSS variables, so resolveEmailTheme reads the tokens where the editor sits and hands the email plain hex values; renderEmail returns { html, text }, in the browser for a preview and on the server for a send.",
|
|
5
|
+
"useWhen": "Code that must produce an email's HTML: a newsletter, a transactional email (receipt, invite, reset), a digest, a notification, a test send from an editor. newsletter-builder is built on it. Not for writing the email (doc-editor or email-composer), sending it (your sender or the app's server) or a web page (page-builder).",
|
|
6
|
+
"tags": ["email", "html email", "react-email", "newsletter", "transactional email", "render", "template", "inbox", "preheader", "unsubscribe", "merge field", "plain text"],
|
|
7
|
+
"exports": ["EmailLayout", "EmailCard", "EmailHeader", "EmailFooter", "EmailButton", "EmailHeading", "EmailText", "EmailDivider", "EMAIL_WIDTH", "DocEmail", "fieldText", "renderEmail", "emailPlainText", "EMAIL_TOKENS", "EMAIL_FALLBACK", "resolveEmailTheme", "emailColor", "emailFontStack", "emailThemeKey", "luminance", "toHex"],
|
|
8
|
+
"files": ["index.js", "email.jsx", "doc-email.jsx", "render.js", "theme.js"],
|
|
9
|
+
"requires": [],
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@react-email/components": "1.0.12",
|
|
12
|
+
"@react-email/render": "2.1.0"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// EmailRender — the gallery's and the smoke test's surface. Not installed
|
|
4
|
+
// into apps. A short product update, drawn with the email parts and a
|
|
5
|
+
// doc, rendered to real email HTML in the workspace theme (switch the
|
|
6
|
+
// theme: the email follows), shown in a frame at desktop or phone width,
|
|
7
|
+
// with its plain-text part and a copy button.
|
|
8
|
+
import { useEffect, useRef, useState } from "react";
|
|
9
|
+
import { Badge, Button, Card, Skeleton, TabPanel, Tabs, ToggleGroup, toast } from "../components/ui";
|
|
10
|
+
import {
|
|
11
|
+
DocEmail,
|
|
12
|
+
EmailButton,
|
|
13
|
+
EmailCard,
|
|
14
|
+
EmailFooter,
|
|
15
|
+
EmailHeader,
|
|
16
|
+
EmailLayout,
|
|
17
|
+
renderEmail,
|
|
18
|
+
resolveEmailTheme,
|
|
19
|
+
emailThemeKey,
|
|
20
|
+
} from "../components/blocks/email-render";
|
|
21
|
+
|
|
22
|
+
const UPDATE_DOC = [
|
|
23
|
+
{ type: "heading", props: { level: 1 }, content: "Shared calendars are here" },
|
|
24
|
+
{
|
|
25
|
+
type: "paragraph",
|
|
26
|
+
content: [
|
|
27
|
+
{ type: "text", text: "Hi ", styles: {} },
|
|
28
|
+
{ type: "field", props: { key: "first_name", label: "First name" } },
|
|
29
|
+
{ type: "text", text: ", your team can now see one week, together. ", styles: {} },
|
|
30
|
+
{ type: "text", text: "No more asking who is out on Friday.", styles: { bold: true } },
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
{ type: "bulletListItem", content: "Everyone's time off, in one view" },
|
|
34
|
+
{ type: "bulletListItem", content: "Drag a task onto a day to plan it" },
|
|
35
|
+
{ type: "bulletListItem", content: "Subscribe from Google or Apple Calendar" },
|
|
36
|
+
{ type: "quote", content: "We cancelled our Monday planning call the week this shipped. — Dana, ops lead at Brightline" },
|
|
37
|
+
];
|
|
38
|
+
|
|
39
|
+
export default function EmailRenderDemo() {
|
|
40
|
+
const doc = UPDATE_DOC;
|
|
41
|
+
const box = useRef(null);
|
|
42
|
+
const [theme, setTheme] = useState(null);
|
|
43
|
+
const [out, setOut] = useState(null);
|
|
44
|
+
const [width, setWidth] = useState("desktop");
|
|
45
|
+
const [tab, setTab] = useState("email");
|
|
46
|
+
|
|
47
|
+
// Read the theme where the demo sits, again when it changes.
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
const read = () => setTheme((prev) => {
|
|
50
|
+
const next = resolveEmailTheme(box.current);
|
|
51
|
+
return prev && emailThemeKey(prev) === emailThemeKey(next) ? prev : next;
|
|
52
|
+
});
|
|
53
|
+
read();
|
|
54
|
+
const watch = new MutationObserver(read);
|
|
55
|
+
watch.observe(document.documentElement, { attributes: true, attributeFilter: ["class", "style", "data-theme"] });
|
|
56
|
+
return () => watch.disconnect();
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
if (!theme) return;
|
|
61
|
+
let live = true;
|
|
62
|
+
renderEmail(
|
|
63
|
+
<EmailLayout theme={theme} preview="Your whole team's week, in one place — and three other things we shipped." title="Shared calendars are here">
|
|
64
|
+
<EmailHeader theme={theme} name="Tidewater" href="https://tidewater.example" />
|
|
65
|
+
<EmailCard theme={theme}>
|
|
66
|
+
<DocEmail doc={doc} theme={theme} fields={{ first_name: "Ana" }} />
|
|
67
|
+
<EmailButton theme={theme} href="https://tidewater.example/calendar">Open your calendar</EmailButton>
|
|
68
|
+
</EmailCard>
|
|
69
|
+
<EmailFooter
|
|
70
|
+
theme={theme}
|
|
71
|
+
note="You get this because you have a Tidewater account."
|
|
72
|
+
address="Tidewater Labs, 14 Harbour Row, Bristol BS1 5TY"
|
|
73
|
+
unsubscribeUrl="https://tidewater.example/unsubscribe"
|
|
74
|
+
/>
|
|
75
|
+
</EmailLayout>,
|
|
76
|
+
).then((r) => live && setOut(r));
|
|
77
|
+
return () => {
|
|
78
|
+
live = false;
|
|
79
|
+
};
|
|
80
|
+
}, [theme, doc]);
|
|
81
|
+
|
|
82
|
+
return (
|
|
83
|
+
<div ref={box} className="grid gap-4">
|
|
84
|
+
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
85
|
+
<Tabs
|
|
86
|
+
aria-label="What to show"
|
|
87
|
+
tabs={[
|
|
88
|
+
{ key: "email", label: "Email" },
|
|
89
|
+
{ key: "text", label: "Plain text" },
|
|
90
|
+
]}
|
|
91
|
+
value={tab}
|
|
92
|
+
onChange={setTab}
|
|
93
|
+
/>
|
|
94
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
95
|
+
{out?.ok ? <Badge variant="soft">{`${Math.round(out.html.length / 102.4) / 10} KB of HTML`}</Badge> : null}
|
|
96
|
+
<ToggleGroup
|
|
97
|
+
size="sm"
|
|
98
|
+
type="single"
|
|
99
|
+
value={width}
|
|
100
|
+
onChange={setWidth}
|
|
101
|
+
items={[
|
|
102
|
+
{ value: "desktop", label: "Desktop", icon: "monitor", iconOnly: true },
|
|
103
|
+
{ value: "mobile", label: "Phone", icon: "smartphone", iconOnly: true },
|
|
104
|
+
]}
|
|
105
|
+
/>
|
|
106
|
+
<Button
|
|
107
|
+
size="sm"
|
|
108
|
+
variant="secondary"
|
|
109
|
+
icon="copy"
|
|
110
|
+
disabled={!out?.ok}
|
|
111
|
+
onClick={async () => {
|
|
112
|
+
try {
|
|
113
|
+
await navigator.clipboard.writeText(out.html);
|
|
114
|
+
toast.success("Email HTML copied");
|
|
115
|
+
} catch {
|
|
116
|
+
toast.error("Could not copy", { description: "Your browser blocked the clipboard." });
|
|
117
|
+
}
|
|
118
|
+
}}
|
|
119
|
+
>
|
|
120
|
+
Copy HTML
|
|
121
|
+
</Button>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
<TabPanel tab="email" value={tab}>
|
|
125
|
+
<Card padding="none">
|
|
126
|
+
<div className="flex justify-center bg-muted p-4">
|
|
127
|
+
{out?.ok ? (
|
|
128
|
+
<iframe
|
|
129
|
+
title="Email preview"
|
|
130
|
+
srcDoc={out.html}
|
|
131
|
+
sandbox=""
|
|
132
|
+
className="h-[640px] rounded-md border border-border bg-background transition-[width] duration-150 motion-reduce:transition-none"
|
|
133
|
+
style={{ width: width === "mobile" ? 375 : "100%", maxWidth: "100%" }}
|
|
134
|
+
/>
|
|
135
|
+
) : out ? (
|
|
136
|
+
<p className="p-6 text-sm text-destructive">{out.error}</p>
|
|
137
|
+
) : (
|
|
138
|
+
<div className="grid w-full max-w-xl gap-3 py-8" aria-busy="true">
|
|
139
|
+
<Skeleton className="h-5 w-32" />
|
|
140
|
+
<Skeleton shape="block" className="h-64 w-full" />
|
|
141
|
+
</div>
|
|
142
|
+
)}
|
|
143
|
+
</div>
|
|
144
|
+
</Card>
|
|
145
|
+
</TabPanel>
|
|
146
|
+
<TabPanel tab="text" value={tab}>
|
|
147
|
+
<Card>
|
|
148
|
+
<pre className="max-h-[520px] overflow-auto whitespace-pre-wrap font-mono text-sm text-muted-foreground">{out?.ok ? out.text : "Rendering…"}</pre>
|
|
149
|
+
</Card>
|
|
150
|
+
</TabPanel>
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
// DocEmail — a doc-editor document (BlockNote JSON) drawn as email markup.
|
|
2
|
+
//
|
|
3
|
+
// The doc is plain JSON, so this walks it directly; it does not import the
|
|
4
|
+
// editor (a server send never loads BlockNote). What email can show, it
|
|
5
|
+
// shows: headings, paragraphs, lists (nested), checklists, quotes, code,
|
|
6
|
+
// tables, images, dividers; bold, italic, underline, strike, inline code,
|
|
7
|
+
// links. A mention is @Label; a merge field is its value, or what
|
|
8
|
+
// `fields` makes of its key (a tag your sender fills in, "{{first_name}}").
|
|
9
|
+
// Text and highlight colours are dropped: an email wears the theme.
|
|
10
|
+
import { Img, Link, Section, Text } from "@react-email/components";
|
|
11
|
+
import { EMAIL_FALLBACK, emailColor } from "./theme";
|
|
12
|
+
|
|
13
|
+
const blocksOf = (doc) => (Array.isArray(doc) ? doc : []);
|
|
14
|
+
const inlineOf = (content) => (typeof content === "string" ? [{ type: "text", text: content, styles: {} }] : Array.isArray(content) ? content : []);
|
|
15
|
+
|
|
16
|
+
/** A merge field's words: `fields` is { key: value } or (key, props) → value.
|
|
17
|
+
* Nothing given leaves "{key}", as docToText does. */
|
|
18
|
+
export function fieldText(props, fields) {
|
|
19
|
+
const key = props?.key ?? "";
|
|
20
|
+
const v = typeof fields === "function" ? fields(key, props) : fields && typeof fields === "object" ? fields[key] : undefined;
|
|
21
|
+
return v === undefined || v === null || v === "" ? `{${key}}` : String(v);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function Inline({ content, t, fields, linkColor }) {
|
|
25
|
+
return inlineOf(content).map((c, i) => {
|
|
26
|
+
if (!c) return null;
|
|
27
|
+
if (c.type === "link") {
|
|
28
|
+
return (
|
|
29
|
+
<Link key={i} href={c.href ?? "#"} style={{ color: linkColor, textDecoration: "underline" }}>
|
|
30
|
+
<Inline content={c.content} t={t} fields={fields} linkColor={linkColor} />
|
|
31
|
+
</Link>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
if (c.type === "mention") return <span key={i}>{`@${c.props?.label ?? c.props?.id ?? ""}`}</span>;
|
|
35
|
+
if (c.type === "field") return <span key={i}>{fieldText(c.props, fields)}</span>;
|
|
36
|
+
if (c.type !== "text") return Array.isArray(c.content) ? <Inline key={i} content={c.content} t={t} fields={fields} linkColor={linkColor} /> : null;
|
|
37
|
+
const s = c.styles ?? {};
|
|
38
|
+
let node = c.text ?? "";
|
|
39
|
+
if (s.code) {
|
|
40
|
+
node = (
|
|
41
|
+
<code style={{ fontFamily: t.fontMono, fontSize: "0.9em", backgroundColor: emailColor(t, "muted"), borderRadius: "4px", padding: "1px 4px" }}>{node}</code>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
if (s.bold) node = <strong>{node}</strong>;
|
|
45
|
+
if (s.italic) node = <em>{node}</em>;
|
|
46
|
+
if (s.underline) node = <u>{node}</u>;
|
|
47
|
+
if (s.strike) node = <s>{node}</s>;
|
|
48
|
+
return <span key={i}>{node}</span>;
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const HEAD = {
|
|
53
|
+
1: { fontSize: "28px", lineHeight: "34px", margin: "8px 0 16px" },
|
|
54
|
+
2: { fontSize: "22px", lineHeight: "28px", margin: "28px 0 12px" },
|
|
55
|
+
3: { fontSize: "18px", lineHeight: "24px", margin: "24px 0 8px" },
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const LIST = new Set(["bulletListItem", "numberedListItem", "checkListItem", "toggleListItem"]);
|
|
59
|
+
|
|
60
|
+
/** Consecutive list items of one kind become one list. */
|
|
61
|
+
function runs(blocks) {
|
|
62
|
+
const out = [];
|
|
63
|
+
for (const b of blocksOf(blocks)) {
|
|
64
|
+
if (!b || typeof b !== "object") continue;
|
|
65
|
+
const kind = LIST.has(b.type) ? (b.type === "numberedListItem" ? "ol" : b.type === "checkListItem" ? "check" : "ul") : null;
|
|
66
|
+
const last = out[out.length - 1];
|
|
67
|
+
if (kind && last?.kind === kind) last.items.push(b);
|
|
68
|
+
else out.push(kind ? { kind, items: [b] } : { kind: null, block: b });
|
|
69
|
+
}
|
|
70
|
+
return out;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function Blocks({ blocks, t, fields, depth = 0 }) {
|
|
74
|
+
const text = emailColor(t, "card-foreground");
|
|
75
|
+
const muted = emailColor(t, "muted-foreground");
|
|
76
|
+
const link = emailColor(t, "primary");
|
|
77
|
+
const para = { margin: "0 0 16px", fontSize: "16px", lineHeight: "26px", color: text };
|
|
78
|
+
return runs(blocks).map((run, i) => {
|
|
79
|
+
if (run.kind === "ul" || run.kind === "ol") {
|
|
80
|
+
const Tag = run.kind;
|
|
81
|
+
return (
|
|
82
|
+
<Tag key={i} style={{ margin: depth ? "4px 0 4px" : "0 0 16px", paddingLeft: "24px", color: text }}>
|
|
83
|
+
{run.items.map((b, j) => (
|
|
84
|
+
<li key={b.id ?? j} style={{ margin: "0 0 6px", fontSize: "16px", lineHeight: "26px" }}>
|
|
85
|
+
<Inline content={b.content} t={t} fields={fields} linkColor={link} />
|
|
86
|
+
{b.children?.length ? <Blocks blocks={b.children} t={t} fields={fields} depth={depth + 1} /> : null}
|
|
87
|
+
</li>
|
|
88
|
+
))}
|
|
89
|
+
</Tag>
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (run.kind === "check") {
|
|
93
|
+
return (
|
|
94
|
+
<Section key={i} style={{ margin: "0 0 16px" }}>
|
|
95
|
+
{run.items.map((b, j) => (
|
|
96
|
+
<Text key={b.id ?? j} style={{ ...para, margin: "0 0 6px", paddingLeft: `${depth * 24}px` }}>
|
|
97
|
+
<span style={{ color: b.props?.checked ? link : muted }}>{b.props?.checked ? "☑\u00a0 " : "☐\u00a0 "}</span>
|
|
98
|
+
<span style={b.props?.checked ? { color: muted, textDecoration: "line-through" } : undefined}>
|
|
99
|
+
<Inline content={b.content} t={t} fields={fields} linkColor={link} />
|
|
100
|
+
</span>
|
|
101
|
+
</Text>
|
|
102
|
+
))}
|
|
103
|
+
</Section>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
const b = run.block;
|
|
107
|
+
const kids = b.children?.length ? <Blocks blocks={b.children} t={t} fields={fields} depth={depth + 1} /> : null;
|
|
108
|
+
switch (b.type) {
|
|
109
|
+
case "heading": {
|
|
110
|
+
const level = Math.min(3, Math.max(1, Number(b.props?.level) || 2));
|
|
111
|
+
const Tag = `h${level}`;
|
|
112
|
+
return (
|
|
113
|
+
<div key={i}>
|
|
114
|
+
<Tag style={{ ...HEAD[level], fontFamily: t.fontDisplay, fontWeight: 700, letterSpacing: "-0.015em", color: text }}>
|
|
115
|
+
<Inline content={b.content} t={t} fields={fields} linkColor={link} />
|
|
116
|
+
</Tag>
|
|
117
|
+
{kids}
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
case "quote":
|
|
122
|
+
return (
|
|
123
|
+
<Section key={i} style={{ margin: "0 0 16px", borderLeft: `3px solid ${link}`, padding: "2px 0 2px 16px" }}>
|
|
124
|
+
<Text style={{ ...para, margin: 0, fontSize: "17px", lineHeight: "28px", fontStyle: "italic" }}>
|
|
125
|
+
<Inline content={b.content} t={t} fields={fields} linkColor={link} />
|
|
126
|
+
</Text>
|
|
127
|
+
{kids}
|
|
128
|
+
</Section>
|
|
129
|
+
);
|
|
130
|
+
case "codeBlock":
|
|
131
|
+
return (
|
|
132
|
+
<pre
|
|
133
|
+
key={i}
|
|
134
|
+
style={{
|
|
135
|
+
margin: "0 0 16px",
|
|
136
|
+
padding: "14px 16px",
|
|
137
|
+
backgroundColor: emailColor(t, "muted"),
|
|
138
|
+
color: emailColor(t, "foreground"),
|
|
139
|
+
border: `1px solid ${emailColor(t, "border")}`,
|
|
140
|
+
borderRadius: t.radius,
|
|
141
|
+
fontFamily: t.fontMono,
|
|
142
|
+
fontSize: "13px",
|
|
143
|
+
lineHeight: "20px",
|
|
144
|
+
whiteSpace: "pre-wrap",
|
|
145
|
+
wordBreak: "break-word",
|
|
146
|
+
}}
|
|
147
|
+
>
|
|
148
|
+
{inlineOf(b.content)
|
|
149
|
+
.map((c) => c?.text ?? "")
|
|
150
|
+
.join("")}
|
|
151
|
+
</pre>
|
|
152
|
+
);
|
|
153
|
+
case "divider":
|
|
154
|
+
return <hr key={i} style={{ border: 0, borderTop: `1px solid ${emailColor(t, "border")}`, margin: "28px 0" }} />;
|
|
155
|
+
case "image":
|
|
156
|
+
if (!b.props?.url) return null;
|
|
157
|
+
return (
|
|
158
|
+
<Section key={i} style={{ margin: "0 0 20px" }}>
|
|
159
|
+
<Img src={b.props.url} alt={b.props?.caption || b.props?.name || ""} width="100%" style={{ display: "block", width: "100%", maxWidth: "100%", height: "auto", borderRadius: t.radius, border: 0 }} />
|
|
160
|
+
{b.props?.caption ? <Text style={{ margin: "8px 0 0", fontSize: "13px", lineHeight: "18px", color: muted, textAlign: "center" }}>{b.props.caption}</Text> : null}
|
|
161
|
+
</Section>
|
|
162
|
+
);
|
|
163
|
+
case "table": {
|
|
164
|
+
const rows = b.content?.rows ?? [];
|
|
165
|
+
if (!rows.length) return null;
|
|
166
|
+
const cell = { padding: "8px 10px", borderBottom: `1px solid ${emailColor(t, "border")}`, fontSize: "14px", lineHeight: "20px", color: text, textAlign: "left", verticalAlign: "top" };
|
|
167
|
+
return (
|
|
168
|
+
<table key={i} role="presentation" cellPadding="0" cellSpacing="0" width="100%" style={{ margin: "0 0 20px", borderCollapse: "collapse", width: "100%" }}>
|
|
169
|
+
<tbody>
|
|
170
|
+
{rows.map((r, ri) => (
|
|
171
|
+
<tr key={ri}>
|
|
172
|
+
{(r.cells ?? []).map((c, ci) => {
|
|
173
|
+
const Cell = ri === 0 ? "th" : "td";
|
|
174
|
+
return (
|
|
175
|
+
<Cell key={ci} style={{ ...cell, fontWeight: ri === 0 ? 600 : 400 }}>
|
|
176
|
+
<Inline content={c?.content ?? c} t={t} fields={fields} linkColor={link} />
|
|
177
|
+
</Cell>
|
|
178
|
+
);
|
|
179
|
+
})}
|
|
180
|
+
</tr>
|
|
181
|
+
))}
|
|
182
|
+
</tbody>
|
|
183
|
+
</table>
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
default: {
|
|
187
|
+
const empty = !inlineOf(b.content).some((c) => c && (c.type !== "text" || (c.text ?? "") !== ""));
|
|
188
|
+
return (
|
|
189
|
+
<div key={i}>
|
|
190
|
+
<Text style={empty ? { ...para, margin: "0 0 8px", lineHeight: "8px" } : para}>{empty ? " " : <Inline content={b.content} t={t} fields={fields} linkColor={link} />}</Text>
|
|
191
|
+
{kids}
|
|
192
|
+
</div>
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* A doc as email markup, inside whatever frame you give it (EmailCard).
|
|
201
|
+
* doc the doc-editor document (BlockNote JSON)
|
|
202
|
+
* theme resolveEmailTheme(root) or EMAIL_FALLBACK
|
|
203
|
+
* fields merge fields: { key: value } or (key, props) → value; a key
|
|
204
|
+
* with no value stays "{key}"
|
|
205
|
+
*/
|
|
206
|
+
export function DocEmail({ doc, theme, fields }) {
|
|
207
|
+
const t = theme ?? EMAIL_FALLBACK;
|
|
208
|
+
return <Blocks blocks={doc} t={t} fields={fields} />;
|
|
209
|
+
}
|
|
210
|
+
|