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,179 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// QuoteDocument — the default business document: a quote, an estimate or
|
|
4
|
+
// an invoice, from data. The quote-builder and proposal blocks print
|
|
5
|
+
// through it; an app can too (renderPdf(<QuoteDocument … />)).
|
|
6
|
+
//
|
|
7
|
+
// The layout is the classic one people trust: who it is from at the top
|
|
8
|
+
// left, what it is and its number at the top right, then who it is for,
|
|
9
|
+
// the dates and the amount in a row of labelled fields, the lines in a
|
|
10
|
+
// table, the sums flush right, and notes, terms and how to pay at the
|
|
11
|
+
// foot. One accent (the theme's primary): the bar along the top edge and
|
|
12
|
+
// the amount due. Everything else is ink and grey on paper.
|
|
13
|
+
import { Image, View } from "@react-pdf/renderer";
|
|
14
|
+
import {
|
|
15
|
+
PdfBadge,
|
|
16
|
+
PdfCallout,
|
|
17
|
+
PdfCol,
|
|
18
|
+
PdfDivider,
|
|
19
|
+
PdfDocument,
|
|
20
|
+
PdfField,
|
|
21
|
+
PdfHeading,
|
|
22
|
+
PdfLabel,
|
|
23
|
+
PdfLines,
|
|
24
|
+
PdfRow,
|
|
25
|
+
PdfStack,
|
|
26
|
+
PdfTable,
|
|
27
|
+
PdfText,
|
|
28
|
+
PdfTotals,
|
|
29
|
+
} from "./primitives";
|
|
30
|
+
import { formatMoney, formatPdfDate, formatQuantity, quoteTotals } from "./money";
|
|
31
|
+
|
|
32
|
+
const WORDS = {
|
|
33
|
+
quote: { title: "Quote", to: "Prepared for", date: "Issued", until: "Valid until", total: "Total" },
|
|
34
|
+
estimate: { title: "Estimate", to: "Prepared for", date: "Issued", until: "Valid until", total: "Estimated total" },
|
|
35
|
+
invoice: { title: "Invoice", to: "Billed to", date: "Issued", until: "Due", total: "Amount due" },
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** A quote, estimate or invoice. See README ## QuoteDocument for every prop. */
|
|
39
|
+
export function QuoteDocument({
|
|
40
|
+
kind = "quote",
|
|
41
|
+
number,
|
|
42
|
+
title,
|
|
43
|
+
issued,
|
|
44
|
+
until,
|
|
45
|
+
from = {},
|
|
46
|
+
to = {},
|
|
47
|
+
items = [],
|
|
48
|
+
currency = "USD",
|
|
49
|
+
locale = "en-US",
|
|
50
|
+
dateLocale = "en-GB",
|
|
51
|
+
taxRate,
|
|
52
|
+
taxLabel,
|
|
53
|
+
discount,
|
|
54
|
+
paid,
|
|
55
|
+
status,
|
|
56
|
+
statusTone = "success",
|
|
57
|
+
notes,
|
|
58
|
+
terms,
|
|
59
|
+
payment,
|
|
60
|
+
reference,
|
|
61
|
+
footer,
|
|
62
|
+
size = "A4",
|
|
63
|
+
}) {
|
|
64
|
+
const w = WORDS[kind] ?? WORDS.quote;
|
|
65
|
+
const sums = quoteTotals({ items, discount, taxRate, paid });
|
|
66
|
+
const money = (n) => formatMoney(n, currency, locale);
|
|
67
|
+
const docTitle = title ?? w.title;
|
|
68
|
+
const fromLines = [from.name, ...(from.lines ?? []), from.email, from.phone, from.taxId ? `Tax ID ${from.taxId}` : null];
|
|
69
|
+
const toLines = [to.name, to.company, ...(to.lines ?? []), to.email];
|
|
70
|
+
const amountLabel = kind === "invoice" && sums.paid > 0 ? "Balance due" : w.total;
|
|
71
|
+
const hasSums = sums.discount > 0 || sums.tax > 0 || sums.paid > 0;
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<PdfDocument
|
|
75
|
+
title={[docTitle, number].filter(Boolean).join(" ")}
|
|
76
|
+
author={from.name}
|
|
77
|
+
subject={to.company ?? to.name}
|
|
78
|
+
size={size}
|
|
79
|
+
footer={footer ?? [from.name, from.email, from.website].filter(Boolean).join(" · ")}
|
|
80
|
+
>
|
|
81
|
+
{/* Top: the sender (logo or name), and what this is. */}
|
|
82
|
+
<PdfRow justify="between" align="start" gap={24}>
|
|
83
|
+
<PdfCol>
|
|
84
|
+
{from.logo ? <Image src={from.logo} style={{ height: 28, objectFit: "contain", objectPosition: "left", marginBottom: 10, alignSelf: "flex-start" }} /> : null}
|
|
85
|
+
<PdfLines lines={fromLines} first={!from.logo} />
|
|
86
|
+
</PdfCol>
|
|
87
|
+
<PdfCol flex={0} style={{ alignItems: "flex-end" }}>
|
|
88
|
+
<PdfHeading level={1} align="right">
|
|
89
|
+
{docTitle}
|
|
90
|
+
</PdfHeading>
|
|
91
|
+
{number ? (
|
|
92
|
+
<PdfText tone="muted" align="right" style={{ marginTop: 4 }}>
|
|
93
|
+
{number}
|
|
94
|
+
</PdfText>
|
|
95
|
+
) : null}
|
|
96
|
+
{status ? (
|
|
97
|
+
<View style={{ marginTop: 8, alignSelf: "flex-end" }}>
|
|
98
|
+
<PdfBadge tone={statusTone}>{status}</PdfBadge>
|
|
99
|
+
</View>
|
|
100
|
+
) : null}
|
|
101
|
+
</PdfCol>
|
|
102
|
+
</PdfRow>
|
|
103
|
+
|
|
104
|
+
<PdfDivider space={24} />
|
|
105
|
+
|
|
106
|
+
{/* Who it is for, the dates, and the one number that matters. */}
|
|
107
|
+
<PdfRow gap={24} align="start">
|
|
108
|
+
<PdfCol flex={1.6}>
|
|
109
|
+
<PdfLabel>{w.to}</PdfLabel>
|
|
110
|
+
<PdfLines lines={toLines} />
|
|
111
|
+
</PdfCol>
|
|
112
|
+
<PdfCol>
|
|
113
|
+
<PdfStack gap={10}>
|
|
114
|
+
{issued ? <PdfField label={w.date}>{formatPdfDate(issued, dateLocale)}</PdfField> : null}
|
|
115
|
+
{until ? <PdfField label={w.until}>{formatPdfDate(until, dateLocale)}</PdfField> : null}
|
|
116
|
+
{reference ? <PdfField label="Reference">{reference}</PdfField> : null}
|
|
117
|
+
</PdfStack>
|
|
118
|
+
</PdfCol>
|
|
119
|
+
<PdfCol style={{ alignItems: "flex-end" }}>
|
|
120
|
+
<PdfLabel align="right">{amountLabel}</PdfLabel>
|
|
121
|
+
<PdfText bold size="xl" tone="accent" align="right">
|
|
122
|
+
{money(sums.due)}
|
|
123
|
+
</PdfText>
|
|
124
|
+
</PdfCol>
|
|
125
|
+
</PdfRow>
|
|
126
|
+
|
|
127
|
+
{/* The lines. */}
|
|
128
|
+
<PdfTable
|
|
129
|
+
style={{ marginTop: 28 }}
|
|
130
|
+
empty="No line items yet."
|
|
131
|
+
columns={[
|
|
132
|
+
{ key: "description", label: "Description", flex: 3 },
|
|
133
|
+
{ key: "quantity", label: "Qty", width: 48, align: "right", render: (r) => [formatQuantity(r.quantity ?? 1, locale), r.unit].filter(Boolean).join(" ") },
|
|
134
|
+
{ key: "unitPrice", label: "Unit price", width: 84, align: "right", render: (r) => money(r.unitPrice) },
|
|
135
|
+
{ key: "amount", label: "Amount", width: 88, align: "right", render: (r, i) => money(sums.lines[i]) },
|
|
136
|
+
]}
|
|
137
|
+
rows={items.map((it, i) => ({ ...it, id: it.id ?? i, detail: [it.detail, it.discountPercent ? `${formatQuantity(it.discountPercent, locale)}% off` : null].filter(Boolean).join(" · ") || undefined }))}
|
|
138
|
+
/>
|
|
139
|
+
|
|
140
|
+
<PdfTotals
|
|
141
|
+
rows={[
|
|
142
|
+
hasSums && { label: "Subtotal", value: money(sums.subtotal) },
|
|
143
|
+
sums.discount > 0 && { label: discount?.label ?? (discount?.percent ? `Discount (${formatQuantity(discount.percent, locale)}%)` : "Discount"), value: `-${money(sums.discount)}` },
|
|
144
|
+
sums.tax > 0 && { label: taxLabel ?? `Tax (${formatQuantity(taxRate, locale)}%)`, value: money(sums.tax) },
|
|
145
|
+
sums.paid > 0 && { label: "Total", value: money(sums.total) },
|
|
146
|
+
sums.paid > 0 && { label: "Paid", value: `-${money(sums.paid)}` },
|
|
147
|
+
{ label: amountLabel, value: money(sums.due), strong: true },
|
|
148
|
+
]}
|
|
149
|
+
/>
|
|
150
|
+
|
|
151
|
+
{/* The foot: notes, terms, how to pay. */}
|
|
152
|
+
{notes || terms || payment ? (
|
|
153
|
+
<PdfStack gap={16} style={{ marginTop: 32 }} wrap={false}>
|
|
154
|
+
{notes ? <PdfCallout title="Notes">{notes}</PdfCallout> : null}
|
|
155
|
+
{terms || payment ? (
|
|
156
|
+
<PdfRow gap={24}>
|
|
157
|
+
{terms ? (
|
|
158
|
+
<PdfCol>
|
|
159
|
+
<PdfHeading level={3} style={{ marginBottom: 3 }}>
|
|
160
|
+
Terms
|
|
161
|
+
</PdfHeading>
|
|
162
|
+
<PdfText tone="muted">{terms}</PdfText>
|
|
163
|
+
</PdfCol>
|
|
164
|
+
) : null}
|
|
165
|
+
{payment ? (
|
|
166
|
+
<PdfCol>
|
|
167
|
+
<PdfHeading level={3} style={{ marginBottom: 3 }}>
|
|
168
|
+
How to pay
|
|
169
|
+
</PdfHeading>
|
|
170
|
+
{Array.isArray(payment) ? <PdfLines lines={payment} first={false} /> : <PdfText tone="muted">{payment}</PdfText>}
|
|
171
|
+
</PdfCol>
|
|
172
|
+
) : null}
|
|
173
|
+
</PdfRow>
|
|
174
|
+
) : null}
|
|
175
|
+
</PdfStack>
|
|
176
|
+
) : null}
|
|
177
|
+
</PdfDocument>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
// The PDF's colours, from the workspace theme.
|
|
2
|
+
//
|
|
3
|
+
// A PDF cannot read a CSS variable: every colour in it is a concrete
|
|
4
|
+
// value written into the file. So the theme is read ONCE, at the moment
|
|
5
|
+
// the PDF is made, from the page's own variables (--color-primary…), and
|
|
6
|
+
// passed into the document as plain values. Change the theme and the next
|
|
7
|
+
// PDF follows; a PDF already made keeps the colours it was made with.
|
|
8
|
+
//
|
|
9
|
+
// Two schemes:
|
|
10
|
+
// paper (the default) — what gets printed, emailed, signed. White paper,
|
|
11
|
+
// near-black ink, grey rules, and the theme's PRIMARY as the one
|
|
12
|
+
// accent. A dark workspace still sends a light invoice. When the
|
|
13
|
+
// theme's primary is too pale to read on white (a mint, a lemon),
|
|
14
|
+
// the text uses a darker shade of it (accentInk, 4.5:1 or more)
|
|
15
|
+
// while bars and fills keep the colour itself.
|
|
16
|
+
// theme — the workspace's own background, text and borders, for a PDF
|
|
17
|
+
// meant to be read on screen in the brand's look.
|
|
18
|
+
//
|
|
19
|
+
// No colour value is written in this file: the paper constants are byte
|
|
20
|
+
// triples turned into strings at run time, and everything else is read
|
|
21
|
+
// from the page. Everything but resolvePdfTheme() is a plain function, so
|
|
22
|
+
// it runs in node and on the server (where the fallback theme is used).
|
|
23
|
+
|
|
24
|
+
/** The slots read from the page. */
|
|
25
|
+
export const PDF_SLOTS = ["background", "foreground", "muted", "muted-foreground", "border", "primary", "primary-foreground", "success", "warning", "destructive", "info"];
|
|
26
|
+
|
|
27
|
+
const clamp = (n, lo = 0, hi = 255) => Math.max(lo, Math.min(hi, n));
|
|
28
|
+
const byte = (n) => clamp(Math.round(n)).toString(16).padStart(2, "0");
|
|
29
|
+
|
|
30
|
+
/** [r, g, b] (0-255) → a "#rrggbb" string. */
|
|
31
|
+
export function toHex([r, g, b]) {
|
|
32
|
+
return "#" + byte(r) + byte(g) + byte(b);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** "#rrggbb" → [r, g, b], or null. */
|
|
36
|
+
export function parseHex(value) {
|
|
37
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(String(value ?? "").trim());
|
|
38
|
+
if (!m) return null;
|
|
39
|
+
const n = parseInt(m[1], 16);
|
|
40
|
+
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** t of colour a over (1 - t) of colour b. */
|
|
44
|
+
export function mix(a, b, t) {
|
|
45
|
+
const x = parseHex(a);
|
|
46
|
+
const y = parseHex(b);
|
|
47
|
+
if (!x || !y) return a ?? b;
|
|
48
|
+
const k = clamp(t, 0, 1);
|
|
49
|
+
return toHex([0, 1, 2].map((i) => x[i] * k + y[i] * (1 - k)));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** WCAG relative luminance of a hex colour (0 black … 1 white). */
|
|
53
|
+
export function luminance(hex) {
|
|
54
|
+
const c = parseHex(hex);
|
|
55
|
+
if (!c) return 0;
|
|
56
|
+
const lin = c.map((v) => {
|
|
57
|
+
const s = v / 255;
|
|
58
|
+
return s <= 0.04045 ? s / 12.92 : ((s + 0.055) / 1.055) ** 2.4;
|
|
59
|
+
});
|
|
60
|
+
return 0.2126 * lin[0] + 0.7152 * lin[1] + 0.0722 * lin[2];
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** WCAG contrast ratio of two hex colours (1 … 21). */
|
|
64
|
+
export function contrast(a, b) {
|
|
65
|
+
const [hi, lo] = [luminance(a), luminance(b)].sort((x, y) => y - x);
|
|
66
|
+
return (hi + 0.05) / (lo + 0.05);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** `colour`, darkened toward `ink` (or lightened, on a dark ground) until
|
|
70
|
+
* it reads on `ground` at `ratio` — the shade used for accent TEXT. */
|
|
71
|
+
export function readableOn(colour, ground, ink, ratio = 4.5) {
|
|
72
|
+
if (!parseHex(colour)) return ink;
|
|
73
|
+
if (contrast(colour, ground) >= ratio) return colour;
|
|
74
|
+
for (let t = 0.9; t >= 0; t -= 0.05) {
|
|
75
|
+
const c = mix(colour, ink, t);
|
|
76
|
+
if (contrast(c, ground) >= ratio) return c;
|
|
77
|
+
}
|
|
78
|
+
return ink;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Black or white, whichever reads better on `fill`. */
|
|
82
|
+
export function inkOn(fill) {
|
|
83
|
+
return luminance(fill) > 0.179 ? PAPER.ink : PAPER.paper;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Print constants: paper, ink, a quiet grey for secondary text (4.5:1 on
|
|
87
|
+
// the paper), a hairline rule and a faint band.
|
|
88
|
+
const PAPER = {
|
|
89
|
+
paper: toHex([255, 255, 255]),
|
|
90
|
+
ink: toHex([23, 23, 27]),
|
|
91
|
+
muted: toHex([107, 107, 118]),
|
|
92
|
+
rule: toHex([226, 226, 231]),
|
|
93
|
+
band: toHex([246, 246, 248]),
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// The fallback accent and tones: used on the server and wherever the page
|
|
97
|
+
// has no theme to read.
|
|
98
|
+
const FALLBACK = {
|
|
99
|
+
primary: toHex([36, 99, 235]),
|
|
100
|
+
success: toHex([21, 112, 58]),
|
|
101
|
+
warning: toHex([154, 74, 6]),
|
|
102
|
+
destructive: toHex([192, 28, 28]),
|
|
103
|
+
info: toHex([29, 78, 216]),
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/** The theme a PDF is drawn with, from slot → hex (as read from the page).
|
|
107
|
+
*
|
|
108
|
+
* paper, ink, muted, rule, band the page, body text, secondary text,
|
|
109
|
+
* hairlines, a faint fill (table head)
|
|
110
|
+
* accent the theme's primary, for bars and fills
|
|
111
|
+
* accentInk the accent as text: 4.5:1 on the paper
|
|
112
|
+
* accentSoft a light tint of it, for a callout
|
|
113
|
+
* onAccent text on an accent fill
|
|
114
|
+
* success, warning, danger, info status tones, readable on the paper
|
|
115
|
+
* font, fontBold the PDF's faces (see registerPdfFont)
|
|
116
|
+
*/
|
|
117
|
+
export function buildPdfTheme(slots = {}, { scheme = "paper", font } = {}) {
|
|
118
|
+
const s = Object.fromEntries(Object.entries(slots).filter(([, v]) => parseHex(v)));
|
|
119
|
+
const own = scheme === "theme" && s.background && s.foreground;
|
|
120
|
+
const paper = own ? s.background : PAPER.paper;
|
|
121
|
+
const ink = own ? s.foreground : PAPER.ink;
|
|
122
|
+
const muted = own ? readableOn(s["muted-foreground"] ?? mix(ink, paper, 0.62), paper, ink, 4.5) : PAPER.muted;
|
|
123
|
+
const rule = own ? (s.border ?? mix(ink, paper, 0.14)) : PAPER.rule;
|
|
124
|
+
const band = own ? (s.muted ?? mix(ink, paper, 0.05)) : PAPER.band;
|
|
125
|
+
const accent = s.primary ?? FALLBACK.primary;
|
|
126
|
+
const tone = (slot) => readableOn(s[slot] ?? FALLBACK[slot], paper, ink, 4.5);
|
|
127
|
+
return {
|
|
128
|
+
scheme: own ? "theme" : "paper",
|
|
129
|
+
paper,
|
|
130
|
+
ink,
|
|
131
|
+
muted,
|
|
132
|
+
rule,
|
|
133
|
+
band,
|
|
134
|
+
accent,
|
|
135
|
+
accentInk: readableOn(accent, paper, ink, 4.5),
|
|
136
|
+
accentSoft: mix(accent, paper, 0.08),
|
|
137
|
+
onAccent: own && s["primary-foreground"] && contrast(s["primary-foreground"], accent) >= 4.5 ? s["primary-foreground"] : inkOn(accent),
|
|
138
|
+
success: tone("success"),
|
|
139
|
+
warning: tone("warning"),
|
|
140
|
+
danger: tone("destructive"),
|
|
141
|
+
info: tone("info"),
|
|
142
|
+
font: font?.family ?? "Helvetica",
|
|
143
|
+
fontBold: font?.bold ?? font?.family ?? "Helvetica-Bold",
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** The theme with nothing read from a page: paper, ink and a blue accent. */
|
|
148
|
+
export const DEFAULT_PDF_THEME = buildPdfTheme({});
|
|
149
|
+
|
|
150
|
+
// ---- the browser half -------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
/** Read the workspace theme from the CSS variables in effect at `root`
|
|
153
|
+
* (default: <body>, so a data-theme or a theme scoped to an ancestor
|
|
154
|
+
* counts) and build the PDF theme. A hidden probe takes
|
|
155
|
+
* `color: var(--color-<slot>)`; the browser resolves var(), color-mix()
|
|
156
|
+
* and oklch() into its computed colour, and a 1×1 canvas turns that into
|
|
157
|
+
* bytes whatever syntax it came back in. On the server it returns the
|
|
158
|
+
* fallback theme. */
|
|
159
|
+
export function resolvePdfTheme(root, options) {
|
|
160
|
+
if (typeof document === "undefined") return buildPdfTheme({}, options);
|
|
161
|
+
const host = root ?? document.body;
|
|
162
|
+
if (!host) return buildPdfTheme({}, options);
|
|
163
|
+
const probe = document.createElement("span");
|
|
164
|
+
probe.setAttribute("aria-hidden", "true");
|
|
165
|
+
probe.style.position = "absolute";
|
|
166
|
+
probe.style.visibility = "hidden";
|
|
167
|
+
probe.style.pointerEvents = "none";
|
|
168
|
+
host.appendChild(probe);
|
|
169
|
+
const canvas = document.createElement("canvas");
|
|
170
|
+
canvas.width = 1;
|
|
171
|
+
canvas.height = 1;
|
|
172
|
+
const ctx = canvas.getContext("2d", { willReadFrequently: true });
|
|
173
|
+
const slots = {};
|
|
174
|
+
try {
|
|
175
|
+
for (const slot of PDF_SLOTS) {
|
|
176
|
+
probe.style.color = "";
|
|
177
|
+
probe.style.color = `var(--color-${slot})`;
|
|
178
|
+
const computed = getComputedStyle(probe).color;
|
|
179
|
+
if (!computed || !ctx) continue;
|
|
180
|
+
ctx.clearRect(0, 0, 1, 1);
|
|
181
|
+
ctx.fillStyle = "transparent";
|
|
182
|
+
ctx.fillStyle = computed;
|
|
183
|
+
ctx.fillRect(0, 0, 1, 1);
|
|
184
|
+
const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data;
|
|
185
|
+
if (a === 0) continue;
|
|
186
|
+
// A translucent token (a tint) is laid on the paper, as it would print.
|
|
187
|
+
slots[slot] = a >= 255 ? toHex([r, g, b]) : mix(toHex([r, g, b]), PAPER.paper, a / 255);
|
|
188
|
+
}
|
|
189
|
+
} finally {
|
|
190
|
+
probe.remove();
|
|
191
|
+
}
|
|
192
|
+
return buildPdfTheme(slots, options);
|
|
193
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# PdfViewer
|
|
2
|
+
|
|
3
|
+
A PDF on screen, in the workspace theme. The pages scroll in one column;
|
|
4
|
+
a rail of thumbnails sits on the left and a page box in the toolbar
|
|
5
|
+
jumps anywhere. Zoom by steps, fit the width, fit the page, or hold
|
|
6
|
+
Ctrl/⌘ and scroll (a trackpad pinch works too) — the line under the
|
|
7
|
+
pointer stays put. ⌘F finds words in the text: every match is marked on
|
|
8
|
+
the page, Enter walks them.
|
|
9
|
+
|
|
10
|
+
People can highlight. Select a sentence and a small bar offers
|
|
11
|
+
**Highlight**, **Add note** and **Copy**. A highlight shows as a marker
|
|
12
|
+
stroke in a theme colour; its note sits in the Highlights list beside
|
|
13
|
+
the pages, where it is edited, recoloured or deleted (with Undo). Every
|
|
14
|
+
change shows at once and saves through your callback; when a save fails,
|
|
15
|
+
the change goes back and a toast says why.
|
|
16
|
+
|
|
17
|
+
A narrow viewer (under 900px wide — a phone, a side column) turns the
|
|
18
|
+
page rail and the Highlights list into sheets. Long files stay fast:
|
|
19
|
+
only the pages near the window are drawn. Password-protected files ask
|
|
20
|
+
for their password. A file that will not open says why and offers Try
|
|
21
|
+
again.
|
|
22
|
+
|
|
23
|
+
It is [React-PDF](https://github.com/wojtekmaj/react-pdf) (MIT) over
|
|
24
|
+
Mozilla's [PDF.js](https://github.com/mozilla/pdf.js) (Apache-2.0)
|
|
25
|
+
underneath: they parse and draw the pages and the selectable text. The
|
|
26
|
+
toolbar, rails, search, highlights and states are ours, in the kit. The
|
|
27
|
+
blocks built on this one (proposal-accept, a contract review screen…)
|
|
28
|
+
import it, never `react-pdf` or `pdfjs-dist`.
|
|
29
|
+
|
|
30
|
+
```jsx
|
|
31
|
+
import { PdfViewer } from "../components/blocks/pdf-viewer"; // a Makersclaw app ("./blocks/pdf-viewer" from components/)
|
|
32
|
+
import { PdfViewer } from "@/components/makersclaw/blocks/pdf-viewer"; // a shadcn project
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
`PdfViewer` is a client component: render it from a `"use client"`
|
|
36
|
+
component. The helpers (`findMatches`, `toPageRects`, `sortHighlights`…)
|
|
37
|
+
are plain functions and work on the server.
|
|
38
|
+
|
|
39
|
+
## The file, and the worker
|
|
40
|
+
|
|
41
|
+
`file` is a URL (same origin, or a server that allows CORS), a `Blob` /
|
|
42
|
+
`File` (an upload, or a PDF made with the `pdf-document` block), or the
|
|
43
|
+
bytes (`ArrayBuffer` / `Uint8Array`, copied — your buffer stays usable).
|
|
44
|
+
|
|
45
|
+
PDF.js parses in a Web Worker. Nothing to set up: the block points
|
|
46
|
+
PDF.js at `new URL("pdfjs-dist/build/pdf.worker.min.mjs", import.meta.url)`,
|
|
47
|
+
which the app's bundler resolves at build time and emits as a hashed
|
|
48
|
+
file under `/_next/static/media/`, with the base path applied. So the
|
|
49
|
+
worker ships with the app, always matches the PDF.js version that calls
|
|
50
|
+
it, and comes from the app's own origin — no file in `public/`, no CDN.
|
|
51
|
+
|
|
52
|
+
## The data
|
|
53
|
+
|
|
54
|
+
A highlight is one row:
|
|
55
|
+
|
|
56
|
+
```js
|
|
57
|
+
{
|
|
58
|
+
id: "hl_81", // yours
|
|
59
|
+
page: 3, // 1-based
|
|
60
|
+
rects: [{ x, y, w, h }], // fractions of the page (0…1), top-left origin — hold at any zoom
|
|
61
|
+
text: "Fees rise by 4% at each annual renewal", // the words highlighted
|
|
62
|
+
note: "Ask for a 3% cap.", // optional
|
|
63
|
+
tone: "warning", // warning (default) · info · success · destructive · primary
|
|
64
|
+
author: "Priya Raman", // optional, shown under the note
|
|
65
|
+
createdAt: "2026-09-21", // optional
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`rects` may be left out: a highlight given only by its `text` (and
|
|
70
|
+
optionally its `page`) is placed where those words first appear, once
|
|
71
|
+
the pages' text has been read. That is how an agent or a server flags a
|
|
72
|
+
clause without knowing any geometry. A quote that is not in the text is
|
|
73
|
+
listed under "Not found in the text". Store the `rects` the viewer sends
|
|
74
|
+
you in `onHighlight` — they are exact; placing by words is close (the
|
|
75
|
+
width inside a line is shared out by characters) and assumes pages that
|
|
76
|
+
are not rotated.
|
|
77
|
+
|
|
78
|
+
Store a highlight as a row in its own table (`document_id`, `page`,
|
|
79
|
+
`rects` jsonb, `text`, `note`, `tone`, `author`, `created_at`).
|
|
80
|
+
|
|
81
|
+
## Props
|
|
82
|
+
|
|
83
|
+
- `file` — the PDF (see above). `null` shows the empty state.
|
|
84
|
+
- `title` — names the viewer for screen readers and shows in the
|
|
85
|
+
toolbar on a wide viewer. Default `"PDF document"` for readers, nothing
|
|
86
|
+
shown.
|
|
87
|
+
- `fileName` — what Download saves as. Default: the title + `.pdf`.
|
|
88
|
+
- `highlights` — the rows above. Default `[]`.
|
|
89
|
+
- `onHighlight(h)` — save a new highlight: `h` is `{ page, rects, text,
|
|
90
|
+
note, tone }`. Return `{ ok: true, id }` (your id replaces the viewer's
|
|
91
|
+
temporary one) or `{ ok: false, error }` (a throw counts as failed): it
|
|
92
|
+
is removed and a toast shows `error`. **Without `onHighlight` the viewer
|
|
93
|
+
is read-only**: no selection bar, and the Highlights list (shown only
|
|
94
|
+
when there are highlights) cannot edit.
|
|
95
|
+
- `onHighlightChange(id, patch)` — `patch` is `{ note }` or `{ tone }`.
|
|
96
|
+
Same return; a failure puts the old value back.
|
|
97
|
+
- `onHighlightDelete(id)` — called 5 seconds after a delete, once the
|
|
98
|
+
Undo in its toast has passed (or at once if the viewer unmounts). Same
|
|
99
|
+
return; a failure puts the highlight back.
|
|
100
|
+
- `initialPage` — the page to open on. Default `1`.
|
|
101
|
+
- `onPageChange(page, pageCount)` — whenever the page at the top of the
|
|
102
|
+
window changes.
|
|
103
|
+
- `defaultZoom` — `"fit"` (width, the default) · `"page"` · a number
|
|
104
|
+
(`1` is 100%).
|
|
105
|
+
- `thumbnails` — the page rail. Default `true`.
|
|
106
|
+
- `search` — find in the text. Default `true`.
|
|
107
|
+
- `download` — the Download button. Default `true`.
|
|
108
|
+
- `notes` — open the Highlights list on a wide viewer at first. Default:
|
|
109
|
+
open when there are highlights.
|
|
110
|
+
- `height` — the viewer's height, any CSS length. Default
|
|
111
|
+
`"min(80vh, 860px)"`; it never goes under 384px.
|
|
112
|
+
- `loading` — `true` shows the skeleton (while you fetch or make the
|
|
113
|
+
file) instead of the empty state.
|
|
114
|
+
- `emptyTitle` · `emptyBody` — the words when `file` is empty. Default
|
|
115
|
+
"No document yet" / "When a PDF is attached, it shows here."
|
|
116
|
+
- `viewerRef` — a ref from `usePdfViewer()`; `ref.current` then has
|
|
117
|
+
`goToPage(n)`, `goToHighlight(id)`, `search(text)`, `setZoom(z)`, and
|
|
118
|
+
`page` / `pageCount`.
|
|
119
|
+
- `className` — added to the frame (a margin, a width). Its border,
|
|
120
|
+
radius and height are the block's; set height through `height`.
|
|
121
|
+
|
|
122
|
+
Keys, while focus is in the viewer: ⌘/Ctrl + F find, Enter / Shift+Enter
|
|
123
|
+
next / previous match, Esc closes find; ⌘/Ctrl + `+` / `-` zoom, `0`
|
|
124
|
+
fits the width; Page Up / Page Down and the arrows scroll; Tab reaches
|
|
125
|
+
every control and each page thumbnail. Notes: ⌘/Ctrl + Enter saves, Esc
|
|
126
|
+
cancels.
|
|
127
|
+
|
|
128
|
+
## Example
|
|
129
|
+
|
|
130
|
+
```jsx
|
|
131
|
+
"use client";
|
|
132
|
+
import { useState } from "react";
|
|
133
|
+
import { PdfViewer } from "../components/blocks/pdf-viewer";
|
|
134
|
+
import { insertRow, updateRow, deleteRow } from "../lib/actions";
|
|
135
|
+
|
|
136
|
+
const source = "public.highlights";
|
|
137
|
+
|
|
138
|
+
export function ContractReview({ doc, rows }) {
|
|
139
|
+
const [highlights, setHighlights] = useState(rows);
|
|
140
|
+
return (
|
|
141
|
+
<PdfViewer
|
|
142
|
+
file={doc.url}
|
|
143
|
+
title={doc.title}
|
|
144
|
+
highlights={highlights}
|
|
145
|
+
onHighlight={async (h) => {
|
|
146
|
+
const r = await insertRow({ source, values: { document_id: doc.id, ...h } });
|
|
147
|
+
if (r.ok) setHighlights((list) => [...list, { ...h, id: r.id }]);
|
|
148
|
+
return r;
|
|
149
|
+
}}
|
|
150
|
+
onHighlightChange={async (id, patch) => {
|
|
151
|
+
const r = await updateRow({ source, id, patch });
|
|
152
|
+
if (r.ok) setHighlights((list) => list.map((x) => (x.id === id ? { ...x, ...patch } : x)));
|
|
153
|
+
return r;
|
|
154
|
+
}}
|
|
155
|
+
onHighlightDelete={async (id) => {
|
|
156
|
+
const r = await deleteRow({ source, id });
|
|
157
|
+
if (r.ok) setHighlights((list) => list.filter((x) => x.id !== id));
|
|
158
|
+
return r;
|
|
159
|
+
}}
|
|
160
|
+
/>
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Preview a PDF you make (the `pdf-document` block):
|
|
166
|
+
|
|
167
|
+
```jsx
|
|
168
|
+
const { blob } = usePdf(() => <QuoteDocument {...quote} />, [quote]);
|
|
169
|
+
<PdfViewer file={blob} loading={!blob} title={`Quote ${quote.number}`} thumbnails={false} />
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## What it will not do
|
|
173
|
+
|
|
174
|
+
- Edit the PDF: fill its forms, sign it, rotate or reorder pages, or
|
|
175
|
+
write highlights into the file. Highlights are rows you store; the PDF
|
|
176
|
+
is untouched. (For signing, the `signature-pad` block.)
|
|
177
|
+
- Search across a line break in one phrase: PDF.js splits text into
|
|
178
|
+
lines, and a match must sit inside one (like most quick finds).
|
|
179
|
+
- Highlight in a scanned PDF (an image with no text layer): there is no
|
|
180
|
+
text to select or find.
|
|
181
|
+
- Keep the old pages up while a NEW file loads: a changed `file` shows
|
|
182
|
+
the skeleton until it has opened.
|
|
183
|
+
- Open a URL on another origin that does not allow CORS: fetch it on
|
|
184
|
+
your server and pass the bytes.
|
|
185
|
+
- Print; the browser's own PDF reader does that from Download.
|
|
186
|
+
|
|
187
|
+
## Credits
|
|
188
|
+
|
|
189
|
+
Built on [React-PDF](https://github.com/wojtekmaj/react-pdf) by Wojciech
|
|
190
|
+
Maj (MIT) and [PDF.js](https://github.com/mozilla/pdf.js) by Mozilla
|
|
191
|
+
(Apache-2.0), used unmodified. See THIRD-PARTY-NOTICES.md.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pdf-viewer",
|
|
3
|
+
"title": "PdfViewer",
|
|
4
|
+
"description": "A PDF on screen, in the workspace theme (react-pdf + pdf.js): pages in one smooth scrolling column (only the pages near the window are drawn, so long files stay fast), a thumbnail rail, a page box, zoom by steps, fit width, fit page and Ctrl/⌘ + wheel or pinch, find in the text with every match marked, and highlights with notes: select text, choose Highlight or Add note, and it saves through onHighlight; notes are edited in a side list, colours are theme tokens, delete has Undo. Opens a URL, a Blob or bytes; password-protected files ask for the password; a narrow viewer turns its rails into sheets. The pdf.js worker ships with the app (no public/ file, no CDN).",
|
|
5
|
+
"useWhen": "A screen shows an existing PDF: a contract or proposal to review, a signed agreement, an uploaded invoice or statement, a report, a generated quote before it is sent; or people mark up a PDF and leave notes on passages. Pair it with pdf-document to preview a PDF you make. Not for making PDFs (pdf-document), for rich text people edit (doc-editor), or for marking up a screenshot (annotate).",
|
|
6
|
+
"tags": ["pdf", "viewer", "document", "reader", "preview", "highlight", "annotate", "notes", "search", "thumbnails", "zoom", "contract", "proposal", "react-pdf", "pdfjs"],
|
|
7
|
+
"exports": ["PdfViewer", "usePdfViewer", "HIGHLIGHT_TONES", "findMatches", "toPageRects", "mergeRects", "sortHighlights", "highlightAt", "fitScale", "ZOOM_STEPS"],
|
|
8
|
+
"files": ["index.js", "pdf-viewer.jsx", "notes.jsx", "helpers.js", "pdfjs.js", "ssr-shim.js", "ssr-shim-end.js"],
|
|
9
|
+
"requires": [],
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"react-pdf": "11.0.0",
|
|
12
|
+
"pdfjs-dist": "6.3.289"
|
|
13
|
+
}
|
|
14
|
+
}
|