makersclaw 0.1.0 → 0.3.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.
- package/LICENSE +21 -0
- package/README.md +41 -1
- package/THIRD-PARTY-NOTICES.md +180 -0
- package/package.json +15 -8
- 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 +55 -0
- 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 +341 -0
- 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 +56 -0
- 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 +3612 -0
- 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 +64 -13
- package/registry/blocks/board/block.json +2 -2
- package/registry/blocks/board/board.jsx +237 -94
- 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 +86 -2
- 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/install.mjs +18 -0
- package/src/shadcn.mjs +171 -0
- 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/parts/fixture.jsx +1 -1
- package/templates/next/files/components/parts/sample.js +15 -0
- 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/files/lib/sample.js +4 -12
- package/templates/next/template.json +264 -8
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// The PdfDocument block — `makersclaw add pdf-document`. Fixed: compose it
|
|
2
|
+
// through its props (README.md beside this file). Themed PDF primitives,
|
|
3
|
+
// a ready invoice/quote layout, and renderPdf(doc) → Blob. The blocks that
|
|
4
|
+
// print (quote-builder, proposal-accept…) import this one, never
|
|
5
|
+
// @react-pdf/renderer directly. The sums and formatters in money.js and
|
|
6
|
+
// the theme maths in theme.js run anywhere, the server included.
|
|
7
|
+
export { renderPdf, usePdf, PdfDownloadButton, downloadBlob, registerPdfFont } from "./pdf-document";
|
|
8
|
+
export {
|
|
9
|
+
PdfDocument,
|
|
10
|
+
PdfStack,
|
|
11
|
+
PdfRow,
|
|
12
|
+
PdfCol,
|
|
13
|
+
PdfText,
|
|
14
|
+
PdfHeading,
|
|
15
|
+
PdfLabel,
|
|
16
|
+
PdfField,
|
|
17
|
+
PdfDivider,
|
|
18
|
+
PdfCallout,
|
|
19
|
+
PdfBadge,
|
|
20
|
+
PdfTable,
|
|
21
|
+
PdfTotals,
|
|
22
|
+
PdfLines,
|
|
23
|
+
PdfView,
|
|
24
|
+
PdfRawText,
|
|
25
|
+
PdfImage,
|
|
26
|
+
PdfLink,
|
|
27
|
+
PdfThemeProvider,
|
|
28
|
+
usePdfTheme,
|
|
29
|
+
PDF_TYPE,
|
|
30
|
+
} from "./primitives";
|
|
31
|
+
export { QuoteDocument } from "./quote";
|
|
32
|
+
export { quoteTotals, lineAmount, round2, formatMoney, formatQuantity, formatPdfDate } from "./money";
|
|
33
|
+
export { resolvePdfTheme, buildPdfTheme, DEFAULT_PDF_THEME } from "./theme";
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// Quote and invoice sums — plain functions, so a server action, a test or
|
|
2
|
+
// the quote builder's live preview all get the same numbers the PDF prints.
|
|
3
|
+
//
|
|
4
|
+
// Amounts are in the currency's major unit (dollars, not cents) and every
|
|
5
|
+
// sum is rounded to the cent line by line, the way an accountant writes
|
|
6
|
+
// it: each line's amount is rounded, then added.
|
|
7
|
+
|
|
8
|
+
/** Round to 2 decimals without the 1.005 → 1.00 float trap. */
|
|
9
|
+
export const round2 = (n) => Math.round((Number(n) + Number.EPSILON) * 100) / 100;
|
|
10
|
+
|
|
11
|
+
const num = (v) => {
|
|
12
|
+
const n = typeof v === "string" ? Number(v.replace(/[, ]/g, "")) : Number(v);
|
|
13
|
+
return Number.isFinite(n) ? n : 0;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/** One line's amount: quantity × unit price, less its own discount (%). */
|
|
17
|
+
export function lineAmount(item) {
|
|
18
|
+
const gross = num(item?.quantity ?? 1) * num(item?.unitPrice);
|
|
19
|
+
const off = item?.discountPercent ? (gross * num(item.discountPercent)) / 100 : 0;
|
|
20
|
+
return round2(gross - off);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** The sums of a quote or invoice.
|
|
24
|
+
*
|
|
25
|
+
* items [{ description, quantity, unitPrice, discountPercent?,
|
|
26
|
+
* taxable? (default true) }]
|
|
27
|
+
* discount { percent } or { amount } off the subtotal (optional)
|
|
28
|
+
* taxRate percent, on the taxable lines after the discount (optional)
|
|
29
|
+
* paid what has already been paid (an invoice's deposit)
|
|
30
|
+
*
|
|
31
|
+
* → { lines: [amount…], subtotal, discount, tax, total, paid, due } */
|
|
32
|
+
export function quoteTotals({ items = [], discount, taxRate, paid } = {}) {
|
|
33
|
+
const lines = items.map(lineAmount);
|
|
34
|
+
const subtotal = round2(lines.reduce((s, a) => s + a, 0));
|
|
35
|
+
const taxableBase = round2(lines.reduce((s, a, i) => (items[i]?.taxable === false ? s : s + a), 0));
|
|
36
|
+
let off = 0;
|
|
37
|
+
if (discount?.percent) off = round2((subtotal * num(discount.percent)) / 100);
|
|
38
|
+
else if (discount?.amount) off = round2(Math.min(num(discount.amount), subtotal));
|
|
39
|
+
// The discount is shared across lines in proportion, so tax falls on
|
|
40
|
+
// what is actually charged for the taxable ones.
|
|
41
|
+
const share = subtotal > 0 ? taxableBase / subtotal : 0;
|
|
42
|
+
const tax = taxRate ? round2(((taxableBase - off * share) * num(taxRate)) / 100) : 0;
|
|
43
|
+
const total = round2(subtotal - off + tax);
|
|
44
|
+
const already = round2(num(paid));
|
|
45
|
+
return { lines, subtotal, discount: off, tax, total, paid: already, due: round2(total - already) };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Characters the PDF's built-in faces (WinAnsi) cannot draw, which Intl
|
|
49
|
+
// puts in some locales' numbers: narrow and no-break spaces, the Unicode
|
|
50
|
+
// minus. Swapped for their plain forms.
|
|
51
|
+
const PLAIN = [
|
|
52
|
+
[/[ ]/g, " "],
|
|
53
|
+
[/−/g, "-"],
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
/** 1234.5 → "$1,234.50" in `currency` and `locale`, drawable by the PDF's
|
|
57
|
+
* built-in fonts. A bad currency code falls back to the plain number. */
|
|
58
|
+
export function formatMoney(amount, currency = "USD", locale = "en-US") {
|
|
59
|
+
let out;
|
|
60
|
+
try {
|
|
61
|
+
out = new Intl.NumberFormat(locale, { style: "currency", currency, minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(num(amount));
|
|
62
|
+
} catch {
|
|
63
|
+
out = `${num(amount).toFixed(2)} ${currency ?? ""}`.trim();
|
|
64
|
+
}
|
|
65
|
+
for (const [re, to] of PLAIN) out = out.replace(re, to);
|
|
66
|
+
return out;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** A quantity as people write it: 3, 1.5, 0.25 — no trailing zeros. */
|
|
70
|
+
export function formatQuantity(q, locale = "en-US") {
|
|
71
|
+
const out = new Intl.NumberFormat(locale, { maximumFractionDigits: 3 }).format(num(q));
|
|
72
|
+
return PLAIN.reduce((s, [re, to]) => s.replace(re, to), out);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/** "2026-09-23" (or a Date) → "23 Sep 2026" in `locale`; "" when empty.
|
|
76
|
+
* A bare date string is read as that calendar day, not as UTC midnight. */
|
|
77
|
+
export function formatPdfDate(value, locale = "en-GB") {
|
|
78
|
+
if (!value) return "";
|
|
79
|
+
const d = value instanceof Date ? value : /^\d{4}-\d{2}-\d{2}$/.test(String(value)) ? new Date(`${value}T12:00:00`) : new Date(value);
|
|
80
|
+
if (Number.isNaN(d.getTime())) return String(value);
|
|
81
|
+
const out = new Intl.DateTimeFormat(locale, { day: "numeric", month: "short", year: "numeric" }).format(d);
|
|
82
|
+
return PLAIN.reduce((s, [re, to]) => s.replace(re, to), out);
|
|
83
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// Making the PDF: renderPdf turns a document (the primitives, or
|
|
4
|
+
// QuoteDocument) into a Blob in the workspace's theme; usePdf keeps one
|
|
5
|
+
// fresh while its data changes (a live preview); PdfDownloadButton is the
|
|
6
|
+
// "Download PDF" a screen puts beside it.
|
|
7
|
+
//
|
|
8
|
+
// The theme is read from the page at the moment of rendering (./theme.js):
|
|
9
|
+
// a PDF cannot read CSS variables, so its colours are written in as values.
|
|
10
|
+
// @react-pdf/renderer lays the document out in JS (no browser print, no
|
|
11
|
+
// server), in the browser or in node alike.
|
|
12
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
13
|
+
import { Font, pdf } from "@react-pdf/renderer";
|
|
14
|
+
import { Button, toast } from "../../ui";
|
|
15
|
+
import { PdfThemeProvider } from "./primitives";
|
|
16
|
+
import { buildPdfTheme, resolvePdfTheme } from "./theme";
|
|
17
|
+
|
|
18
|
+
let hyphenationOff = false;
|
|
19
|
+
|
|
20
|
+
/** Render a PDF document to a Blob.
|
|
21
|
+
*
|
|
22
|
+
* doc a <PdfDocument>…</PdfDocument> or <QuoteDocument … /> element
|
|
23
|
+
* options theme a theme from resolvePdfTheme/buildPdfTheme (default:
|
|
24
|
+
* read from the page now; the fallback on the server)
|
|
25
|
+
* root the element whose theme to read (default <body>)
|
|
26
|
+
* scheme "paper" (default: white paper, the theme's accent)
|
|
27
|
+
* or "theme" (the workspace's own background and ink)
|
|
28
|
+
*
|
|
29
|
+
* Resolves to a Blob of type application/pdf; rejects when the document
|
|
30
|
+
* cannot be laid out (a broken image URL, a font that will not load). */
|
|
31
|
+
export async function renderPdf(doc, { theme, root, scheme = "paper" } = {}) {
|
|
32
|
+
if (!hyphenationOff) {
|
|
33
|
+
// Whole words only: a business document never splits "invoice" as
|
|
34
|
+
// "in-voice" at a line end.
|
|
35
|
+
Font.registerHyphenationCallback((word) => [word]);
|
|
36
|
+
hyphenationOff = true;
|
|
37
|
+
}
|
|
38
|
+
const t = theme ?? (typeof document === "undefined" ? buildPdfTheme({}, { scheme }) : resolvePdfTheme(root, { scheme }));
|
|
39
|
+
return pdf(<PdfThemeProvider theme={t}>{doc}</PdfThemeProvider>).toBlob();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Use a brand face in PDFs: registerPdfFont({ family: "Inter", regular:
|
|
43
|
+
* url, bold: url }) — TTF or WOFF files the browser can fetch — then pass
|
|
44
|
+
* `font: { family: "Inter", bold: "Inter-Bold" }` to buildPdfTheme, or
|
|
45
|
+
* let renderPdf's theme carry it. Without one, PDFs use Helvetica, which
|
|
46
|
+
* every reader has built in (it draws Latin text; for other scripts or
|
|
47
|
+
* symbols like ₹, register a font that has them). */
|
|
48
|
+
export function registerPdfFont({ family, regular, bold }) {
|
|
49
|
+
if (!family || !regular) return null;
|
|
50
|
+
Font.register({ family, src: regular });
|
|
51
|
+
if (bold) Font.register({ family: `${family}-Bold`, src: bold });
|
|
52
|
+
return { family, bold: bold ? `${family}-Bold` : family };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Keep a PDF of `build()` up to date: a live preview.
|
|
56
|
+
*
|
|
57
|
+
* const { url, blob, loading, error, refresh } = usePdf(() => <QuoteDocument {...q} />, [q]);
|
|
58
|
+
*
|
|
59
|
+
* Re-renders `delay` ms (default 400) after the deps settle, so typing in
|
|
60
|
+
* a form does not lay out a PDF per key. `url` is an object URL for the
|
|
61
|
+
* current Blob (revoked when it is replaced); `error` is the last
|
|
62
|
+
* failure, cleared by the next success. `options` go to renderPdf. */
|
|
63
|
+
export function usePdf(build, deps = [], { delay = 400, enabled = true, ...options } = {}) {
|
|
64
|
+
const [state, setState] = useState({ blob: null, url: null, loading: enabled, error: null });
|
|
65
|
+
const buildRef = useRef(build);
|
|
66
|
+
buildRef.current = build;
|
|
67
|
+
const optsRef = useRef(options);
|
|
68
|
+
optsRef.current = options;
|
|
69
|
+
const urlRef = useRef(null);
|
|
70
|
+
const run = useRef(0);
|
|
71
|
+
const [tick, setTick] = useState(0);
|
|
72
|
+
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
if (!enabled) return undefined;
|
|
75
|
+
const id = ++run.current;
|
|
76
|
+
setState((s) => ({ ...s, loading: true }));
|
|
77
|
+
const timer = setTimeout(async () => {
|
|
78
|
+
try {
|
|
79
|
+
const blob = await renderPdf(buildRef.current(), optsRef.current);
|
|
80
|
+
if (id !== run.current) return;
|
|
81
|
+
const url = URL.createObjectURL(blob);
|
|
82
|
+
if (urlRef.current) URL.revokeObjectURL(urlRef.current);
|
|
83
|
+
urlRef.current = url;
|
|
84
|
+
setState({ blob, url, loading: false, error: null });
|
|
85
|
+
} catch (error) {
|
|
86
|
+
if (id !== run.current) return;
|
|
87
|
+
setState((s) => ({ ...s, loading: false, error }));
|
|
88
|
+
}
|
|
89
|
+
}, delay);
|
|
90
|
+
return () => clearTimeout(timer);
|
|
91
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
92
|
+
}, [enabled, delay, tick, ...deps]);
|
|
93
|
+
|
|
94
|
+
useEffect(
|
|
95
|
+
() => () => {
|
|
96
|
+
run.current++;
|
|
97
|
+
if (urlRef.current) URL.revokeObjectURL(urlRef.current);
|
|
98
|
+
},
|
|
99
|
+
[],
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
const refresh = useCallback(() => setTick((n) => n + 1), []);
|
|
103
|
+
return { ...state, refresh };
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Save a Blob as a file, the way a download link would. */
|
|
107
|
+
export function downloadBlob(blob, fileName = "document.pdf") {
|
|
108
|
+
if (typeof document === "undefined" || !blob) return;
|
|
109
|
+
const url = URL.createObjectURL(blob);
|
|
110
|
+
// raw: an <a download> is how a browser saves a Blob; it is never shown.
|
|
111
|
+
const a = document.createElement("a");
|
|
112
|
+
a.href = url;
|
|
113
|
+
a.download = fileName;
|
|
114
|
+
a.rel = "noopener";
|
|
115
|
+
document.body.appendChild(a);
|
|
116
|
+
a.click();
|
|
117
|
+
a.remove();
|
|
118
|
+
setTimeout(() => URL.revokeObjectURL(url), 1000);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** A "Download PDF" button: renders `document` (an element, or a function
|
|
122
|
+
* returning one) when pressed, then saves it as `fileName`. Busy while it
|
|
123
|
+
* renders; a failure says so in a toast and the button is ready again.
|
|
124
|
+
* Other props (variant, size, icon, label, disabled) are the kit
|
|
125
|
+
* Button's; `options` go to renderPdf. */
|
|
126
|
+
export function PdfDownloadButton({ document: doc, fileName = "document.pdf", label = "Download PDF", icon = "download", variant = "secondary", size = "md", options, disabled, className }) {
|
|
127
|
+
const [busy, setBusy] = useState(false);
|
|
128
|
+
const onClick = async () => {
|
|
129
|
+
setBusy(true);
|
|
130
|
+
try {
|
|
131
|
+
const blob = await renderPdf(typeof doc === "function" ? doc() : doc, options);
|
|
132
|
+
downloadBlob(blob, fileName);
|
|
133
|
+
} catch (e) {
|
|
134
|
+
toast.error("Couldn't make the PDF", { description: e?.message ? `${e.message}. Try again in a moment.` : "Try again in a moment." });
|
|
135
|
+
} finally {
|
|
136
|
+
setBusy(false);
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
return (
|
|
140
|
+
<Button variant={variant} size={size} icon={icon} loading={busy} disabled={disabled || !doc} onClick={onClick} className={className}>
|
|
141
|
+
{label}
|
|
142
|
+
</Button>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// The PDF primitives: a small set of parts that draw a clean business
|
|
4
|
+
// document in the workspace's theme. They render INSIDE a PDF (the
|
|
5
|
+
// @react-pdf/renderer tree), never into the page: compose them into a
|
|
6
|
+
// document and pass it to renderPdf (./pdf-document) or PdfDownloadButton.
|
|
7
|
+
//
|
|
8
|
+
// Every colour comes from the theme in context (./theme.js — resolved from
|
|
9
|
+
// the workspace's CSS variables when the PDF is made); a part takes a
|
|
10
|
+
// `tone` name, never a colour. Type is one family (Helvetica, built into
|
|
11
|
+
// every PDF reader, unless a brand font is registered) at a few fixed
|
|
12
|
+
// sizes, on a 4pt rhythm.
|
|
13
|
+
import { createContext, useContext } from "react";
|
|
14
|
+
import { Document, Image, Link, Page, Text, View } from "@react-pdf/renderer";
|
|
15
|
+
import { DEFAULT_PDF_THEME } from "./theme";
|
|
16
|
+
|
|
17
|
+
const ThemeContext = createContext(DEFAULT_PDF_THEME);
|
|
18
|
+
|
|
19
|
+
/** Wraps a PDF tree in a theme; renderPdf does this for you. */
|
|
20
|
+
export function PdfThemeProvider({ theme, children }) {
|
|
21
|
+
return <ThemeContext.Provider value={theme ?? DEFAULT_PDF_THEME}>{children}</ThemeContext.Provider>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/** The theme the PDF is being drawn with (./theme.js buildPdfTheme). */
|
|
25
|
+
export function usePdfTheme() {
|
|
26
|
+
return useContext(ThemeContext);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** The type scale, in points. Body is 9.5pt: a business document is read
|
|
30
|
+
* at arm's length, and this is the size a good invoice uses. */
|
|
31
|
+
export const PDF_TYPE = { xs: 7.5, sm: 8.5, md: 9.5, lg: 12, xl: 16, xxl: 24 };
|
|
32
|
+
|
|
33
|
+
const TONE = (t, tone) =>
|
|
34
|
+
({ default: t.ink, muted: t.muted, accent: t.accentInk, success: t.success, warning: t.warning, danger: t.danger, info: t.info, onAccent: t.onAccent })[tone] ?? t.ink;
|
|
35
|
+
|
|
36
|
+
// Body leading, set on each text (a leading on the page is measured wrong
|
|
37
|
+
// by the layout and lines overlap).
|
|
38
|
+
const LEADING = 1.4; // always with an explicit fontSize: the leading is read against it
|
|
39
|
+
|
|
40
|
+
const MARGINS = { compact: 36, normal: 48, roomy: 64 };
|
|
41
|
+
|
|
42
|
+
/** The document: one flowing page (it breaks onto more by itself), the
|
|
43
|
+
* brand's accent bar along the top edge, and a footer with the page
|
|
44
|
+
* count on every page.
|
|
45
|
+
*
|
|
46
|
+
* title, author, subject the PDF's properties (a reader shows title)
|
|
47
|
+
* size "A4" (default) · "LETTER" · "LEGAL" · [width, height] pt
|
|
48
|
+
* landscape false
|
|
49
|
+
* margin compact (36pt) · normal (48pt, default) · roomy (64pt)
|
|
50
|
+
* accentBar true: a 4pt bar of the accent along the top of each page
|
|
51
|
+
* footer a line at the foot of each page (left); the page count
|
|
52
|
+
* sits at the right. null: no footer at all. */
|
|
53
|
+
export function PdfDocument({ title, author, subject, size = "A4", landscape = false, margin = "normal", accentBar = true, footer, children }) {
|
|
54
|
+
const t = usePdfTheme();
|
|
55
|
+
const m = MARGINS[margin] ?? MARGINS.normal;
|
|
56
|
+
return (
|
|
57
|
+
<Document title={title} author={author} subject={subject} creator={author} producer={author}>
|
|
58
|
+
<Page
|
|
59
|
+
size={size}
|
|
60
|
+
orientation={landscape ? "landscape" : "portrait"}
|
|
61
|
+
style={{ paddingTop: m, paddingBottom: m + (footer === null ? 0 : 20), paddingHorizontal: m, backgroundColor: t.paper, color: t.ink, fontFamily: t.font, fontSize: PDF_TYPE.md }}
|
|
62
|
+
>
|
|
63
|
+
{accentBar ? <View fixed style={{ position: "absolute", top: 0, left: 0, right: 0, height: 4, backgroundColor: t.accent }} /> : null}
|
|
64
|
+
{children}
|
|
65
|
+
{footer === null ? null : (
|
|
66
|
+
<View fixed style={{ position: "absolute", bottom: m - 16, left: m, right: m, flexDirection: "row", justifyContent: "space-between", fontSize: PDF_TYPE.xs, color: t.muted }}>
|
|
67
|
+
<Text>{footer ?? ""}</Text>
|
|
68
|
+
<Text render={({ pageNumber, totalPages }) => (totalPages > 1 ? `Page ${pageNumber} of ${totalPages}` : "")} />
|
|
69
|
+
</View>
|
|
70
|
+
)}
|
|
71
|
+
</Page>
|
|
72
|
+
</Document>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** A column with a gap between its children (pt). */
|
|
77
|
+
export function PdfStack({ gap = 8, style, children, wrap, break: pageBreak }) {
|
|
78
|
+
return (
|
|
79
|
+
<View wrap={wrap} break={pageBreak} style={[{ flexDirection: "column", gap }, style ?? {}]}>
|
|
80
|
+
{children}
|
|
81
|
+
</View>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** A row. `justify` start · between · end; `align` start · center · end ·
|
|
86
|
+
* baseline. Children share the width by their own `flex` (see PdfCol). */
|
|
87
|
+
export function PdfRow({ gap = 16, justify = "start", align = "start", style, children, wrap }) {
|
|
88
|
+
const J = { start: "flex-start", between: "space-between", end: "flex-end", center: "center" };
|
|
89
|
+
const A = { start: "flex-start", center: "center", end: "flex-end", baseline: "baseline", stretch: "stretch" };
|
|
90
|
+
return (
|
|
91
|
+
<View wrap={wrap} style={[{ flexDirection: "row", gap, justifyContent: J[justify] ?? J.start, alignItems: A[align] ?? A.start }, style ?? {}]}>
|
|
92
|
+
{children}
|
|
93
|
+
</View>
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** One column of a PdfRow: `flex` its share (default 1), or `width` pt. */
|
|
98
|
+
export function PdfCol({ flex = 1, width, style, children }) {
|
|
99
|
+
const size = width ? { width } : flex === 0 ? { flexGrow: 0, flexShrink: 0 } : { flexGrow: flex, flexShrink: 1, flexBasis: 0, minWidth: 0 };
|
|
100
|
+
return <View style={[size, style ?? {}]}>{children}</View>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** Text. size xs · sm · md (default) · lg · xl · xxl; tone default · muted
|
|
104
|
+
* · accent · success · warning · danger · info; bold; align. */
|
|
105
|
+
export function PdfText({ size = "md", tone = "default", bold = false, align, style, children, ...rest }) {
|
|
106
|
+
const t = usePdfTheme();
|
|
107
|
+
return (
|
|
108
|
+
<Text
|
|
109
|
+
{...rest}
|
|
110
|
+
style={[{ fontSize: PDF_TYPE[size] ?? PDF_TYPE.md, lineHeight: LEADING, color: TONE(t, tone), fontFamily: bold ? t.fontBold : t.font, textAlign: align }, style ?? {}]}
|
|
111
|
+
>
|
|
112
|
+
{children}
|
|
113
|
+
</Text>
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** A heading: level 1 (24pt, the document's name) · 2 (12pt, a section)
|
|
118
|
+
* · 3 (9.5pt bold, a group inside one). Tight leading, never all caps. */
|
|
119
|
+
export function PdfHeading({ level = 2, tone = "default", align, style, children }) {
|
|
120
|
+
const t = usePdfTheme();
|
|
121
|
+
const L = {
|
|
122
|
+
1: { fontSize: PDF_TYPE.xxl, lineHeight: 1.15, letterSpacing: -0.4 },
|
|
123
|
+
2: { fontSize: PDF_TYPE.lg, lineHeight: 1.3 },
|
|
124
|
+
3: { fontSize: PDF_TYPE.md, lineHeight: 1.4 },
|
|
125
|
+
};
|
|
126
|
+
return <Text style={[{ fontFamily: t.fontBold, color: TONE(t, tone), textAlign: align }, L[level] ?? L[2], style ?? {}]}>{children}</Text>;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/** The small muted line above a value: "Billed to", "Due". */
|
|
130
|
+
export function PdfLabel({ align, style, children }) {
|
|
131
|
+
const t = usePdfTheme();
|
|
132
|
+
return <Text style={[{ fontSize: PDF_TYPE.sm, color: t.muted, marginBottom: 3, textAlign: align }, style ?? {}]}>{children}</Text>;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** A label over a value, the unit of a document's header. */
|
|
136
|
+
export function PdfField({ label, align, strong = false, tone, children }) {
|
|
137
|
+
return (
|
|
138
|
+
<View>
|
|
139
|
+
<PdfLabel align={align}>{label}</PdfLabel>
|
|
140
|
+
<PdfText bold={strong} tone={tone} align={align} size={strong ? "lg" : "md"}>
|
|
141
|
+
{children}
|
|
142
|
+
</PdfText>
|
|
143
|
+
</View>
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** A hairline rule. `space` is the room above and below it (pt). */
|
|
148
|
+
export function PdfDivider({ space = 16, strong = false }) {
|
|
149
|
+
const t = usePdfTheme();
|
|
150
|
+
return <View style={{ height: strong ? 1 : 0.75, backgroundColor: strong ? t.ink : t.rule, marginVertical: space }} />;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** A soft box: a note, a callout, payment details. tone accent (default,
|
|
154
|
+
* the accent's tint with a bar at its edge) · neutral (the faint band). */
|
|
155
|
+
export function PdfCallout({ tone = "accent", title, style, children }) {
|
|
156
|
+
const t = usePdfTheme();
|
|
157
|
+
const accent = tone === "accent";
|
|
158
|
+
return (
|
|
159
|
+
<View
|
|
160
|
+
wrap={false}
|
|
161
|
+
style={[
|
|
162
|
+
{ backgroundColor: accent ? t.accentSoft : t.band, borderLeftWidth: accent ? 2 : 0, borderLeftColor: t.accent, paddingVertical: 10, paddingHorizontal: 12, borderRadius: 3 },
|
|
163
|
+
style ?? {},
|
|
164
|
+
]}
|
|
165
|
+
>
|
|
166
|
+
{title ? <PdfHeading level={3} style={{ marginBottom: 3 }}>{title}</PdfHeading> : null}
|
|
167
|
+
{typeof children === "string" ? <PdfText>{children}</PdfText> : children}
|
|
168
|
+
</View>
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** A small pill: "Paid", "Accepted". tone accent · success · warning ·
|
|
173
|
+
* danger · neutral. An outline, so it prints well in black and white. */
|
|
174
|
+
export function PdfBadge({ tone = "accent", children }) {
|
|
175
|
+
const t = usePdfTheme();
|
|
176
|
+
const c = { accent: t.accentInk, success: t.success, warning: t.warning, danger: t.danger, neutral: t.muted }[tone] ?? t.accentInk;
|
|
177
|
+
return (
|
|
178
|
+
<View style={{ alignSelf: "flex-start", borderWidth: 1, borderColor: c, borderRadius: 3, paddingHorizontal: 6, paddingVertical: 2 }}>
|
|
179
|
+
<Text style={{ fontSize: PDF_TYPE.sm, fontFamily: t.fontBold, color: c }}>{children}</Text>
|
|
180
|
+
</View>
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/** A table: a quiet header on the faint band, hairlines between rows, the
|
|
185
|
+
* header repeated on every page it runs onto, a row never split.
|
|
186
|
+
*
|
|
187
|
+
* columns [{ key, label, flex? (default 1) | width? (pt), align?:
|
|
188
|
+
* "left" | "right" | "center", render?(row) → string | node }]
|
|
189
|
+
* rows [{ … }]; a row's `detail` (string) prints as a muted second
|
|
190
|
+
* line under the FIRST column
|
|
191
|
+
* empty what to print when there are no rows */
|
|
192
|
+
export function PdfTable({ columns = [], rows = [], empty = "Nothing here.", style }) {
|
|
193
|
+
const t = usePdfTheme();
|
|
194
|
+
const cell = (c) => [c.width ? { width: c.width } : { flex: c.flex ?? 1, minWidth: 0 }, { paddingHorizontal: 6, textAlign: c.align ?? "left" }];
|
|
195
|
+
return (
|
|
196
|
+
<View style={style}>
|
|
197
|
+
<View fixed style={{ flexDirection: "row", backgroundColor: t.band, borderRadius: 3, paddingVertical: 6 }}>
|
|
198
|
+
{columns.map((c) => (
|
|
199
|
+
<Text key={c.key} style={[...cell(c), { fontSize: PDF_TYPE.sm, color: t.muted }]}>
|
|
200
|
+
{c.label}
|
|
201
|
+
</Text>
|
|
202
|
+
))}
|
|
203
|
+
</View>
|
|
204
|
+
{rows.length === 0 ? (
|
|
205
|
+
<Text style={{ paddingVertical: 12, paddingHorizontal: 6, color: t.muted }}>{empty}</Text>
|
|
206
|
+
) : (
|
|
207
|
+
rows.map((row, i) => (
|
|
208
|
+
<View key={row.id ?? i} wrap={false} style={{ flexDirection: "row", paddingVertical: 8, borderBottomWidth: 0.75, borderBottomColor: t.rule }}>
|
|
209
|
+
{columns.map((c, j) => {
|
|
210
|
+
const value = c.render ? c.render(row, i) : row[c.key];
|
|
211
|
+
return (
|
|
212
|
+
<View key={c.key} style={cell(c)}>
|
|
213
|
+
{typeof value === "string" || typeof value === "number" ? (
|
|
214
|
+
<Text style={{ textAlign: c.align ?? "left", fontFamily: j === 0 ? t.fontBold : t.font }}>{String(value)}</Text>
|
|
215
|
+
) : (
|
|
216
|
+
value ?? null
|
|
217
|
+
)}
|
|
218
|
+
{j === 0 && row.detail ? <Text style={{ color: t.muted, fontSize: PDF_TYPE.sm, lineHeight: LEADING, marginTop: 2 }}>{row.detail}</Text> : null}
|
|
219
|
+
</View>
|
|
220
|
+
);
|
|
221
|
+
})}
|
|
222
|
+
</View>
|
|
223
|
+
))
|
|
224
|
+
)}
|
|
225
|
+
</View>
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/** The sums under a table, flush right: label and value per line, the
|
|
230
|
+
* last `strong` line set larger over a rule.
|
|
231
|
+
*
|
|
232
|
+
* rows [{ label, value, strong?, tone? }]
|
|
233
|
+
* width the block's width (pt, default 220) */
|
|
234
|
+
export function PdfTotals({ rows = [], width = 220 }) {
|
|
235
|
+
const t = usePdfTheme();
|
|
236
|
+
return (
|
|
237
|
+
<View wrap={false} style={{ alignSelf: "flex-end", width, marginTop: 12 }}>
|
|
238
|
+
{rows.filter(Boolean).map((r, i) => (
|
|
239
|
+
<View
|
|
240
|
+
key={r.label ?? i}
|
|
241
|
+
style={[
|
|
242
|
+
{ flexDirection: "row", justifyContent: "space-between", paddingVertical: 3, paddingHorizontal: 6 },
|
|
243
|
+
r.strong ? { borderTopWidth: 1, borderTopColor: t.ink, marginTop: 6, paddingTop: 8 } : {},
|
|
244
|
+
]}
|
|
245
|
+
>
|
|
246
|
+
<Text style={{ color: r.strong ? t.ink : t.muted, fontFamily: r.strong ? t.fontBold : t.font, fontSize: r.strong ? PDF_TYPE.lg : PDF_TYPE.md }}>{r.label}</Text>
|
|
247
|
+
<Text style={{ color: TONE(t, r.tone ?? "default"), fontFamily: r.strong ? t.fontBold : t.font, fontSize: r.strong ? PDF_TYPE.lg : PDF_TYPE.md }}>{r.value}</Text>
|
|
248
|
+
</View>
|
|
249
|
+
))}
|
|
250
|
+
</View>
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Lines of plain text (an address): each on its own line, muted after
|
|
255
|
+
* the first unless `muted` is false. Empty lines are dropped. */
|
|
256
|
+
export function PdfLines({ lines = [], first = true, muted = true, align }) {
|
|
257
|
+
const t = usePdfTheme();
|
|
258
|
+
return (
|
|
259
|
+
<View>
|
|
260
|
+
{lines.filter(Boolean).map((line, i) => (
|
|
261
|
+
<Text key={i} style={{ fontSize: PDF_TYPE.md, lineHeight: LEADING, textAlign: align, color: muted && !(first && i === 0) ? t.muted : t.ink, fontFamily: first && i === 0 ? t.fontBold : t.font }}>
|
|
262
|
+
{line}
|
|
263
|
+
</Text>
|
|
264
|
+
))}
|
|
265
|
+
</View>
|
|
266
|
+
);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// The rest of @react-pdf/renderer's parts, under our names, so a block
|
|
270
|
+
// built on this one never imports the library itself.
|
|
271
|
+
export { View as PdfView, Text as PdfRawText, Image as PdfImage, Link as PdfLink };
|