makersclaw 0.2.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/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/install.mjs +18 -0
- package/src/shadcn.mjs +8 -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/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,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "file-upload",
|
|
4
|
+
"type": "registry:block",
|
|
5
|
+
"title": "FileUpload",
|
|
6
|
+
"description": "Files chosen or dropped, each uploaded through your async onUpload(file, { onProgress, signal }) with a progress bar, cancel while it runs, a retry when it fails and a remove once done. Variants: a list of file cards, one file at a time, Uploading/Finished sections, image thumbnails (one or two columns), and a profile picture.",
|
|
7
|
+
"registryDependencies": [
|
|
8
|
+
"https://cdn.jsdelivr.net/npm/makersclaw@0.3.0/r/core.json"
|
|
9
|
+
],
|
|
10
|
+
"dependencies": [],
|
|
11
|
+
"files": [
|
|
12
|
+
{
|
|
13
|
+
"path": "registry/blocks/file-upload/index.js",
|
|
14
|
+
"type": "registry:component",
|
|
15
|
+
"target": "@components/makersclaw/blocks/file-upload/index.js",
|
|
16
|
+
"content": "// The FileUpload block — `makersclaw add file-upload`. Fixed: compose it\n// through its props (README.md beside this file); an upload it cannot be\n// is your own component in components/, built on the kit's FileInput.\nexport { FileUpload, formatSize, fileIcon } from \"./file-upload\";\n"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "registry/blocks/file-upload/file-upload.jsx",
|
|
20
|
+
"type": "registry:component",
|
|
21
|
+
"target": "@components/makersclaw/blocks/file-upload/file-upload.jsx",
|
|
22
|
+
"content": "\"use client\";\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { Avatar, Button, FileDrop, FileInput, IconButton, Image, Item, ItemGroup, Kicker, Notice, Progress, Spinner, cx } from \"../../ui\";\n\n// FileUpload — files chosen or dropped, each one uploaded through the\n// caller's `onUpload(file, { onProgress, signal })`, shown with its bar,\n// a retry when it fails, a cancel while it runs and a remove once done.\n// The picker is the kit's (FileDrop, or FileInput with picker=\"button\");\n// the upload itself is the caller's: storage is the app's, not the block's.\n\n/* ------------------------------------------------------------------------\n Helpers\n ------------------------------------------------------------------------ */\n\nconst EXT_TYPES = {\n png: \"image/png\", jpg: \"image/jpeg\", jpeg: \"image/jpeg\", gif: \"image/gif\", webp: \"image/webp\", svg: \"image/svg+xml\", avif: \"image/avif\",\n csv: \"text/csv\", xls: \"application/vnd.ms-excel\", xlsx: \"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\",\n pdf: \"application/pdf\", doc: \"application/msword\", docx: \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\",\n txt: \"text/plain\", md: \"text/markdown\", zip: \"application/zip\", mp4: \"video/mp4\", mov: \"video/quicktime\", mp3: \"audio/mpeg\",\n};\n\n/** The glyph for a file, from its type (or, failing that, its extension). */\nexport function fileIcon(type, name) {\n const t = type || EXT_TYPES[String(name ?? \"\").split(\".\").pop()?.toLowerCase()] || \"\";\n if (t.startsWith(\"image/\")) return \"image\";\n if (t.startsWith(\"video/\") || t.startsWith(\"audio/\")) return \"play\";\n if (/zip|tar|gzip|compressed|rar|7z/.test(t)) return \"archive\";\n if (/csv|excel|spreadsheet/.test(t)) return \"grid\";\n return \"file\";\n}\n\nfunction isImage(type, name) {\n return fileIcon(type, name) === \"image\";\n}\n\n/** 3_250_000 → \"3.1 MB\"; 900 → \"900 B\". */\nexport function formatSize(bytes) {\n const n = Number(bytes);\n if (!Number.isFinite(n) || n < 0) return \"\";\n if (n < 1024) return `${n} B`;\n const units = [\"KB\", \"MB\", \"GB\", \"TB\"];\n let v = n / 1024;\n let i = 0;\n for (; v >= 1024 && i < units.length - 1; i++) v /= 1024;\n return `${v < 10 ? v.toFixed(1).replace(/\\.0$/, \"\") : Math.round(v)} ${units[i]}`;\n}\n\n/** \"image/*,.pdf\" + 10 MB → \"Images, PDF · up to 10 MB\". */\nfunction acceptHint(accept, maxSize) {\n const parts = [];\n if (accept) {\n const kinds = accept\n .split(\",\")\n .map((a) => a.trim())\n .filter(Boolean)\n .map((a) => (a.endsWith(\"/*\") ? `${a.slice(0, -2)}s` : a.startsWith(\".\") ? a.slice(1).toUpperCase() : a.split(\"/\").pop().replace(/\\+.*$/, \"\").toUpperCase()))\n .map((k) => k.charAt(0).toUpperCase() + k.slice(1));\n parts.push([...new Set(kinds)].join(\", \"));\n }\n if (maxSize) parts.push(`up to ${formatSize(maxSize)}`);\n return parts.join(\" · \") || undefined;\n}\n\nconst clamp = (n) => Math.min(100, Math.max(0, Math.round(Number(n) || 0)));\n\n// What the caller hears about a file: never the File, never our state.\nfunction publicFile(item) {\n const { id, name, size, type, url, meta } = item;\n return { ...(meta ?? {}), id, name, size, type, url };\n}\n\n/* ------------------------------------------------------------------------\n The upload queue\n ------------------------------------------------------------------------ */\n\nfunction useUploads({ defaultFiles, onUpload, onRemove, onChange, autoUpload, thumbs }) {\n // A default entry with a `file` (a File handed over from a paste or a\n // drop elsewhere on the page) starts uploading on mount; the rest are\n // files already uploaded.\n const [items, setItems] = useState(() =>\n (defaultFiles ?? []).map((f, i) =>\n f.file\n ? { id: f.id ?? `file-${i}`, name: f.file.name, size: f.file.size, type: f.file.type, file: f.file, status: autoUpload ? \"uploading\" : \"queued\", progress: null }\n : { id: f.id ?? `file-${i}`, name: f.name, size: f.size, type: f.type, url: f.url, status: \"done\", progress: 100 },\n ),\n );\n const seq = useRef(0);\n const controllers = useRef(new Map());\n const previews = useRef(new Set());\n const first = useRef(true);\n const itemsRef = useRef(items);\n itemsRef.current = items;\n\n // Abort what still runs and free the previews when the block leaves.\n useEffect(() => {\n const ctl = controllers.current;\n const urls = previews.current;\n // Cleared too, so a remount (React's dev double effect) starts afresh.\n return () => {\n for (const c of ctl.values()) c.abort();\n for (const u of urls) URL.revokeObjectURL(u);\n ctl.clear();\n urls.clear();\n };\n }, []);\n\n // onChange hears the uploaded list when it changes — not every tick of\n // a bar.\n const doneSig = items\n .filter((i) => i.status === \"done\")\n .map((i) => `${i.id}\\u0000${i.url ?? \"\"}`)\n .join(\"\\u0001\");\n useEffect(() => {\n if (first.current) {\n first.current = false;\n return;\n }\n onChange?.(itemsRef.current.filter((i) => i.status === \"done\").map(publicFile));\n // onChange is the caller's; the uploaded list is what changed.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [doneSig]);\n\n const patch = (id, next) => setItems((all) => all.map((i) => (i.id === id ? { ...i, ...next } : i)));\n\n // Handed-over files: their previews, then their uploads.\n useEffect(() => {\n for (const it of itemsRef.current) {\n if (!it.file) continue;\n if (thumbs && !it.preview && isImage(it.type, it.name) && URL.createObjectURL) {\n const preview = URL.createObjectURL(it.file);\n previews.current.add(preview);\n patch(it.id, { preview });\n }\n if (it.status === \"uploading\" && !controllers.current.has(it.id)) start(it);\n }\n // Mount only: later files arrive through add().\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n function forget(item) {\n controllers.current.get(item.id)?.abort();\n controllers.current.delete(item.id);\n if (item.preview) {\n URL.revokeObjectURL(item.preview);\n previews.current.delete(item.preview);\n }\n }\n\n async function start(item) {\n if (!item.file) return;\n if (!onUpload) {\n // No uploader: the block is only a picker; the file counts as added.\n patch(item.id, { status: \"done\", progress: 100, url: item.preview });\n return;\n }\n controllers.current.get(item.id)?.abort();\n const ctl = new AbortController();\n controllers.current.set(item.id, ctl);\n patch(item.id, { status: \"uploading\", progress: null, error: null });\n let res;\n try {\n res = await onUpload(item.file, {\n signal: ctl.signal,\n onProgress: (p) => {\n if (!ctl.signal.aborted) patch(item.id, { progress: clamp(p) });\n },\n });\n } catch (e) {\n res = { ok: false, error: e?.message };\n }\n if (ctl.signal.aborted) return;\n controllers.current.delete(item.id);\n if (res?.ok) {\n const { ok, error, url, ...meta } = res;\n patch(item.id, { status: \"done\", progress: 100, url: url ?? item.url, meta });\n } else {\n patch(item.id, { status: \"failed\", error: res?.error || \"The upload failed.\" });\n }\n }\n\n function add(files, { replace = false } = {}) {\n const fresh = files.map((file) => {\n seq.current += 1;\n let preview;\n if (thumbs && isImage(file.type, file.name) && typeof URL !== \"undefined\" && URL.createObjectURL) {\n preview = URL.createObjectURL(file);\n previews.current.add(preview);\n }\n return {\n id: `upload-${seq.current}`,\n name: file.name,\n size: file.size,\n type: file.type,\n file,\n preview,\n status: autoUpload ? \"uploading\" : \"queued\",\n progress: null,\n };\n });\n if (replace) for (const old of itemsRef.current) forget(old);\n setItems((all) => (replace ? fresh : [...all, ...fresh]));\n if (autoUpload) for (const it of fresh) start(it);\n }\n\n function cancel(item) {\n forget(item);\n setItems((all) => all.filter((i) => i.id !== item.id));\n }\n\n async function remove(item) {\n if (item.status !== \"done\" || !onRemove) return cancel(item);\n patch(item.id, { removing: true, error: null });\n let res;\n try {\n res = await onRemove(publicFile(item));\n } catch (e) {\n res = { ok: false, error: e?.message };\n }\n if (res?.ok) cancel(item);\n else patch(item.id, { removing: false, error: res?.error || \"It could not be removed.\" });\n }\n\n function uploadQueued() {\n for (const it of itemsRef.current) if (it.status === \"queued\") start(it);\n }\n\n function clear() {\n for (const it of itemsRef.current) if (it.status === \"queued\") forget(it);\n setItems((all) => all.filter((i) => i.status !== \"queued\"));\n }\n\n return { items, add, start, cancel, remove, uploadQueued, clear };\n}\n\n/* ------------------------------------------------------------------------\n One file's row\n ------------------------------------------------------------------------ */\n\nfunction statusText(item) {\n const size = formatSize(item.size);\n const word = {\n queued: \"Ready to upload\",\n uploading: \"Uploading…\",\n done: \"Uploaded\",\n failed: \"Not uploaded\",\n }[item.status];\n return [size, word].filter(Boolean).join(\" · \");\n}\n\nfunction FileRow({ item, look, thumb, onRetry, onCancel, onRemove, disabled }) {\n const failed = item.status === \"failed\";\n const running = item.status === \"uploading\";\n const src = item.preview ?? (isImage(item.type, item.name) ? item.url : undefined);\n const media =\n thumb && src && !failed ? (\n <Image src={src} alt=\"\" ratio=\"photo\" className=\"w-16 shrink-0\" />\n ) : undefined;\n\n const actions = (\n <>\n {failed && item.file ? (\n <IconButton icon=\"refresh\" label={`Retry ${item.name}`} size=\"sm\" onClick={() => onRetry(item)} disabled={disabled} />\n ) : null}\n {running ? (\n <IconButton icon=\"x\" label={`Cancel ${item.name}`} size=\"sm\" onClick={() => onCancel(item)} />\n ) : (\n <IconButton\n icon={item.status === \"done\" ? \"trash\" : \"x\"}\n label={`Remove ${item.name}`}\n size=\"sm\"\n loading={item.removing}\n onClick={() => onRemove(item)}\n disabled={disabled}\n />\n )}\n </>\n );\n\n return (\n <Item\n variant={look}\n icon={media ? undefined : failed ? \"warning\" : fileIcon(item.type, item.name)}\n media={media}\n title={item.name}\n description={statusText(item)}\n actions={actions}\n aria-busy={running || undefined}\n >\n {running ? (\n <div className=\"flex items-center gap-3\">\n <Progress value={item.progress ?? undefined} aria-label={`Uploading ${item.name}`} className=\"min-w-0 flex-1\" />\n <span data-nums className=\"w-9 shrink-0 text-right text-xs text-muted-foreground\">\n {item.progress == null ? \"\" : `${item.progress}%`}\n </span>\n </div>\n ) : null}\n {item.error ? (\n <p role=\"alert\" className=\"text-xs text-destructive\">\n {item.error}\n </p>\n ) : null}\n </Item>\n );\n}\n\n/* ------------------------------------------------------------------------\n The picture of one person or thing (variant=\"avatar\")\n ------------------------------------------------------------------------ */\n\nfunction AvatarUpload({ value, name, onUpload, onRemove, onChange, accept, maxSize, label, hint, uploadLabel, disabled, className }) {\n const [src, setSrc] = useState(value ?? null);\n const [state, setState] = useState({ busy: false, progress: null, error: null, removing: false });\n const last = useRef(null);\n const ctl = useRef(null);\n const blob = useRef(null);\n\n useEffect(\n () => () => {\n ctl.current?.abort();\n if (blob.current) URL.revokeObjectURL(blob.current);\n },\n [],\n );\n\n function show(next) {\n if (blob.current && blob.current !== next) {\n URL.revokeObjectURL(blob.current);\n blob.current = null;\n }\n setSrc(next);\n onChange?.(next);\n }\n\n async function upload(file) {\n if (maxSize && file.size > maxSize) {\n setState({ busy: false, progress: null, error: `${file.name} is over ${formatSize(maxSize)}.`, removing: false });\n return;\n }\n if (!onUpload) return;\n last.current = file;\n ctl.current?.abort();\n const c = new AbortController();\n ctl.current = c;\n setState({ busy: true, progress: null, error: null, removing: false });\n let res;\n try {\n res = await onUpload(file, {\n signal: c.signal,\n onProgress: (p) => {\n if (!c.signal.aborted) setState((s) => ({ ...s, progress: clamp(p) }));\n },\n });\n } catch (e) {\n res = { ok: false, error: e?.message };\n }\n if (c.signal.aborted) return;\n if (res?.ok) {\n let url = res.url;\n if (!url && typeof URL !== \"undefined\" && URL.createObjectURL) {\n url = URL.createObjectURL(file);\n blob.current = url;\n }\n show(url ?? null);\n setState({ busy: false, progress: null, error: null, removing: false });\n } else {\n setState({ busy: false, progress: null, error: res?.error || \"The picture was not uploaded.\", removing: false });\n }\n }\n\n async function remove() {\n setState((s) => ({ ...s, removing: true, error: null }));\n let res = { ok: true };\n if (onRemove) {\n try {\n res = await onRemove();\n } catch (e) {\n res = { ok: false, error: e?.message };\n }\n }\n if (res?.ok) {\n show(null);\n setState({ busy: false, progress: null, error: null, removing: false });\n } else setState((s) => ({ ...s, removing: false, error: res?.error || \"The picture was not removed.\" }));\n }\n\n return (\n <div className={cx(\"grid gap-3\", className)} aria-busy={state.busy || undefined}>\n <div className=\"flex flex-wrap items-center gap-4\">\n <Avatar name={name} src={src ?? undefined} size=\"lg\" label={name ? `${name}'s picture` : \"Picture\"} />\n <div className=\"grid min-w-0 flex-1 gap-0.5\">\n <p className=\"text-sm font-medium text-foreground\">{label}</p>\n {hint ?? acceptHint(accept, maxSize) ? <p className=\"text-xs text-muted-foreground\">{hint ?? acceptHint(accept, maxSize)}</p> : null}\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <FileInput\n accept={accept}\n onFiles={(files) => upload(files[0])}\n onReject={(files) => setState((s) => ({ ...s, error: `${files[0]?.name ?? \"That file\"} is not a picture this accepts.` }))}\n disabled={disabled || state.removing}\n loading={state.busy}\n variant=\"secondary\"\n size=\"sm\"\n >\n {uploadLabel}\n </FileInput>\n {src ? (\n <Button variant=\"danger\" size=\"sm\" icon=\"trash\" onClick={remove} loading={state.removing} disabled={disabled || state.busy}>\n Remove\n </Button>\n ) : null}\n </div>\n </div>\n {state.busy ? <Progress value={state.progress ?? undefined} aria-label=\"Uploading the picture\" /> : null}\n {state.error ? (\n <Notice\n tone=\"danger\"\n action={\n last.current && !state.busy ? (\n <Button size=\"sm\" variant=\"secondary\" icon=\"refresh\" onClick={() => upload(last.current)}>\n Retry\n </Button>\n ) : null\n }\n onDismiss={() => setState((s) => ({ ...s, error: null }))}\n >\n {state.error}\n </Notice>\n ) : null}\n </div>\n );\n}\n\n/* ------------------------------------------------------------------------\n FileUpload\n ------------------------------------------------------------------------ */\n\nconst LOOK = { list: \"outline\", single: \"muted\", sections: \"plain\", preview: \"outline\" };\n\nexport function FileUpload({\n onUpload,\n onRemove,\n onChange,\n variant = \"list\",\n defaultFiles,\n accept,\n multiple,\n maxSize,\n maxFiles,\n autoUpload = true,\n picker = \"drop\",\n label,\n hint,\n buttonLabel = \"Add files\",\n uploadLabel,\n columns = 1,\n disabled = false,\n value,\n name,\n className,\n \"aria-label\": ariaLabel,\n}) {\n if (variant === \"avatar\") {\n return (\n <AvatarUpload\n value={value}\n name={name}\n onUpload={onUpload}\n onRemove={onRemove}\n onChange={onChange}\n accept={accept ?? \"image/png,image/jpeg,image/webp\"}\n maxSize={maxSize}\n label={label ?? \"Profile picture\"}\n hint={hint}\n uploadLabel={uploadLabel ?? \"Upload picture\"}\n disabled={disabled}\n className={className}\n />\n );\n }\n return (\n <FileList\n {...{ onUpload, onRemove, onChange, variant, defaultFiles, accept, maxSize, maxFiles, autoUpload, picker, hint, buttonLabel, columns, disabled, className, ariaLabel }}\n multiple={variant === \"single\" ? false : multiple ?? true}\n label={label ?? (variant === \"single\" ? \"Drop a file here or browse\" : \"Drop files here or browse\")}\n uploadLabel={uploadLabel}\n />\n );\n}\n\nfunction FileList({\n onUpload,\n onRemove,\n onChange,\n variant,\n defaultFiles,\n accept,\n multiple,\n maxSize,\n maxFiles,\n autoUpload,\n picker,\n label,\n hint,\n buttonLabel,\n uploadLabel,\n columns,\n disabled,\n className,\n ariaLabel,\n}) {\n const single = variant === \"single\";\n const thumbs = variant === \"preview\";\n const q = useUploads({ defaultFiles, onUpload, onRemove, onChange, autoUpload, thumbs });\n const [rejected, setRejected] = useState([]);\n const look = LOOK[variant] ?? LOOK.list;\n const full = !single && maxFiles && q.items.length >= maxFiles;\n\n function take(files) {\n const no = [];\n let ok = files.filter((f) => {\n if (maxSize && f.size > maxSize) {\n no.push({ name: f.name, reason: `over ${formatSize(maxSize)}` });\n return false;\n }\n return true;\n });\n if (!single && maxFiles) {\n const room = Math.max(0, maxFiles - q.items.length);\n for (const f of ok.slice(room)) no.push({ name: f.name, reason: `only ${maxFiles} ${maxFiles === 1 ? \"file\" : \"files\"} in all` });\n ok = ok.slice(0, room);\n }\n setRejected(no);\n if (ok.length) q.add(ok, { replace: single });\n }\n\n function refuse(files) {\n setRejected(files.map((f) => ({ name: f.name, reason: \"not a type this accepts\" })));\n }\n\n const shownHint = hint ?? acceptHint(accept, maxSize);\n const door =\n picker === \"button\" ? (\n <div className=\"flex flex-wrap items-center gap-x-3 gap-y-1\">\n <FileInput accept={accept} multiple={multiple} onFiles={take} onReject={refuse} disabled={disabled || full} size=\"sm\">\n {buttonLabel}\n </FileInput>\n {shownHint ? <span className=\"text-xs text-muted-foreground\">{shownHint}</span> : null}\n </div>\n ) : (\n <FileDrop\n accept={accept}\n multiple={multiple}\n onFiles={take}\n onReject={refuse}\n disabled={disabled || full}\n label={full ? `That is ${maxFiles} — remove one to add another` : label}\n hint={shownHint}\n size={variant === \"sections\" ? \"sm\" : \"md\"}\n invalid={rejected.length > 0}\n aria-label={ariaLabel}\n />\n );\n\n const row = (item) => (\n <FileRow key={item.id} item={item} look={look} thumb={thumbs} onRetry={q.start} onCancel={q.cancel} onRemove={q.remove} disabled={disabled} />\n );\n\n const queued = q.items.filter((i) => i.status === \"queued\");\n const running = q.items.filter((i) => i.status === \"uploading\" || i.status === \"failed\");\n const done = q.items.filter((i) => i.status === \"done\");\n\n let list = null;\n if (q.items.length && variant === \"sections\") {\n list = (\n <div className=\"grid gap-4\">\n {[\n { key: \"queued\", label: \"Ready\", rows: queued },\n { key: \"running\", label: \"Uploading\", rows: running, busy: running.some((i) => i.status === \"uploading\") },\n { key: \"done\", label: \"Finished\", rows: done },\n ]\n .filter((s) => s.rows.length)\n .map((s) => (\n <section key={s.key} aria-label={s.label} className=\"grid gap-1\">\n <div className=\"flex items-center gap-2\">\n {s.busy ? <Spinner size=\"sm\" label={null} className=\"text-muted-foreground\" /> : null}\n <Kicker>\n {s.label} · {s.rows.length}\n </Kicker>\n </div>\n <ItemGroup aria-label={s.label}>{s.rows.map(row)}</ItemGroup>\n </section>\n ))}\n </div>\n );\n } else if (q.items.length) {\n list = (\n <ul role=\"list\" aria-label=\"Files\" className={cx(\"grid gap-2\", columns === 2 && \"sm:grid-cols-2\")}>\n {q.items.map((item) => (\n <li key={item.id} className=\"min-w-0\">\n {row(item)}\n </li>\n ))}\n </ul>\n );\n }\n\n return (\n <div className={cx(\"grid min-w-0 gap-3\", className)}>\n {door}\n {rejected.length ? (\n <Notice tone=\"danger\" title={rejected.length === 1 ? \"One file was not added\" : `${rejected.length} files were not added`} onDismiss={() => setRejected([])}>\n <ul className=\"grid gap-0.5\">\n {rejected.map((r, i) => (\n <li key={i} className=\"break-all\">\n {r.name} — {r.reason}\n </li>\n ))}\n </ul>\n </Notice>\n ) : null}\n {list}\n {!autoUpload && queued.length ? (\n <div className=\"flex flex-wrap justify-end gap-2\">\n <Button variant=\"quiet\" size=\"sm\" onClick={q.clear}>\n Clear\n </Button>\n <Button variant=\"primary\" size=\"sm\" icon=\"upload\" onClick={q.uploadQueued} disabled={disabled}>\n {uploadLabel ?? `Upload ${queued.length} ${queued.length === 1 ? \"file\" : \"files\"}`}\n </Button>\n </div>\n ) : null}\n </div>\n );\n}\n"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"path": "registry/blocks/file-upload/README.md",
|
|
26
|
+
"type": "registry:file",
|
|
27
|
+
"target": "@components/makersclaw/blocks/file-upload/README.md",
|
|
28
|
+
"content": "# FileUpload\n\nFiles chosen or dropped, each one uploaded through your `onUpload` as\nsoon as it lands. Every file shows its bar while it runs (with Cancel),\nthe reason and a Retry when it fails, and a Remove once it is up. Files\nthe picker refuses (wrong type, too big, too many) are named in a notice.\nThe upload itself is yours: the block never fetches.\n\n```jsx\nimport { FileUpload } from \"../components/blocks/file-upload\"; // a Makersclaw app (\"./blocks/file-upload\" from components/)\nimport { FileUpload } from \"@/components/makersclaw/blocks/file-upload\"; // a shadcn project\n```\n\nA client component. The picker is the kit's `FileDrop` (or `FileInput`\nwith `picker=\"button\"`), so the browser's own file dialog opens and the\nkeyboard works: Tab to the zone, Enter or Space.\n\n## The data\n\nWhat the block tells you about a file (in `onChange` and `onRemove`):\n`{ id, name, size, type, url?, ...whatever your onUpload returned }`.\nNever the `File` and never the block's own state.\n\n## Props\n\n- `onUpload(file, { onProgress, signal })` — upload one `File`. Call\n `onProgress(percent)` (0–100) as it goes; without it the bar sweeps.\n Watch `signal` (an AbortSignal): it aborts when the person cancels or\n replaces the file, and pass it to `fetch`. Return `{ ok: true, url?,\n ...anything }` or `{ ok: false, error }`; a throw counts as failed and\n its message is shown. Without `onUpload` the block is a picker only:\n files count as added at once.\n- `variant` — how the files show, default `\"list\"`:\n - `list` — the drop zone, then a card per file (name, size, state).\n - `single` — one file at a time in a filled panel; a new pick replaces\n it (and aborts its upload). An import, a contract.\n - `sections` — a one-row drop zone, then the files grouped under\n \"Ready\", \"Uploading\" (failed ones stay here with Retry) and\n \"Finished\".\n - `preview` — cards with the picture itself for images. `columns={2}`\n lays them two across from 640px.\n - `avatar` — one picture of a person or a company: the current one (or\n the initials), Upload picture, Remove. Takes `value` (the current\n URL) and `name`; `onChange(url | null)`.\n- `onRemove(file)` — delete an uploaded file from storage; return\n `{ ok }` like `onUpload`. The row shows a spinner, and on failure stays\n with the reason. Without it Remove only drops the row. Removing a file\n that is still queued, uploading or failed never calls it.\n- `onChange(files)` — the uploaded files, every time that list changes.\n Save their ids or URLs with the record here.\n- `defaultFiles` — what shows at first: files already uploaded\n (`[{ id, name, size, type, url? }]`). An entry that is `{ id?, file }`\n (a `File` you got from a paste or a drop elsewhere on the page) starts\n uploading on mount.\n- `accept` — as the input's: `\"image/*\"`, `\".csv,.xlsx\"`. The picker\n greys out the rest; a drop of the rest is refused and named.\n- `multiple` — default `true` (`false` for `single` and `avatar`).\n- `maxSize` — bytes, per file. Bigger files are refused and named.\n- `maxFiles` — how many in all; the zone says so when it is full.\n- `autoUpload` — default `true`. `false` holds new files as \"Ready to\n upload\" with Clear and an \"Upload N files\" button, for a form that\n sends its attachments on submit.\n- `picker` — `\"drop\"` (default: the drop zone) · `\"button\"` (a\n `FileInput` button and the hint beside it, for a tight form row).\n- `label` — the zone's line (default \"Drop files here or browse\"); in\n `avatar`, the name beside the picture (\"Profile picture\").\n- `hint` — the muted line: default built from `accept` and `maxSize`\n (\"Images · up to 4 MB\").\n- `buttonLabel` — `picker=\"button\"`'s text, default \"Add files\".\n- `uploadLabel` — the queue's submit text, or `avatar`'s button text.\n- `columns` — `1` (default) or `2`, for `list` and `preview`.\n- `disabled` — no picking, no retry, no remove.\n- `aria-label` — the drop zone's name when `label` is not enough.\n- `className` — layout around it. Never colour.\n\n`formatSize(bytes)` (\"3.1 MB\") and `fileIcon(type, name)` (the kit icon\nfor a file) are exported too, for your own file rows.\n\n## Example\n\n```jsx\n// components/DealFiles.jsx — client\n\"use client\";\nimport { FileUpload } from \"./blocks/file-upload\";\n\n// Your storage route answers a PUT with { id, url }. XMLHttpRequest, not\n// fetch, because only it reports upload progress.\nfunction put(file, { onProgress, signal }) {\n return new Promise((resolve) => {\n const xhr = new XMLHttpRequest();\n xhr.open(\"PUT\", `/api/files?name=${encodeURIComponent(file.name)}`);\n xhr.upload.onprogress = (e) => e.lengthComputable && onProgress((e.loaded / e.total) * 100);\n xhr.onload = () =>\n xhr.status < 300 ? resolve({ ok: true, ...JSON.parse(xhr.responseText) }) : resolve({ ok: false, error: `Upload failed (${xhr.status}).` });\n xhr.onerror = () => resolve({ ok: false, error: \"The connection dropped. Try again.\" });\n signal.addEventListener(\"abort\", () => xhr.abort());\n xhr.send(file);\n });\n}\n\nexport default function DealFiles({ deal, onSaveFiles }) {\n return (\n <FileUpload\n defaultFiles={deal.files}\n onUpload={put}\n onRemove={(f) => fetch(`/api/files/${f.id}`, { method: \"DELETE\" }).then((r) => ({ ok: r.ok }))}\n onChange={(files) => onSaveFiles(files.map((f) => ({ id: f.id, name: f.name, size: f.size, url: f.url })))}\n maxSize={50 * 1024 * 1024}\n />\n );\n}\n```\n\nOne spreadsheet to import, and a profile picture:\n\n```jsx\n<FileUpload variant=\"single\" accept=\".csv,.xlsx\" maxSize={10 * 1024 * 1024} onUpload={put} onChange={([f]) => setImport(f ?? null)} />\n\n<FileUpload variant=\"avatar\" name={me.name} value={me.avatarUrl} onUpload={put} onChange={(url) => saveProfile({ avatar_url: url })} />\n```\n\n## What it will not do\n\n- Store anything: `onUpload` is yours (a storage bucket, a signed URL).\n- Crop or resize a picture, or read a spreadsheet's rows: do that in\n `onUpload` or after `onChange`.\n- Reorder files, or keep a list you control from outside: `defaultFiles`\n is where it starts; remount it (a `key`) to start again.\n- Show a chat message's attachments: that is the chat block's composer.\n\nA file picker it cannot be is your own component in `components/`,\nbuilt on the kit's `FileInput` or `FileDrop` — not an edit to this\nblock. Its files are fixed: `npm run check` refuses a change, and\n`makersclaw add file-upload` restores them.\n\n## Credits\n\nPorted from blocks.so (https://blocks.so, file-upload 01, 03–06, MIT) and Creative Tim UI (https://github.com/creativetimofficial/ui, modals-05 and account-avatar-upload-01, MIT), rewritten on the Makersclaw kit.\n"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"categories": [
|
|
32
|
+
"file",
|
|
33
|
+
"upload",
|
|
34
|
+
"dropzone",
|
|
35
|
+
"drag",
|
|
36
|
+
"drop",
|
|
37
|
+
"attachment",
|
|
38
|
+
"progress",
|
|
39
|
+
"image",
|
|
40
|
+
"photo",
|
|
41
|
+
"avatar",
|
|
42
|
+
"profile picture",
|
|
43
|
+
"csv",
|
|
44
|
+
"import",
|
|
45
|
+
"retry"
|
|
46
|
+
],
|
|
47
|
+
"docs": "Installed to components/makersclaw/blocks/file-upload. Import: import { FileUpload, formatSize, fileIcon } from \"@/components/makersclaw/blocks/file-upload\". Props and an example: components/makersclaw/blocks/file-upload/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
|
|
48
|
+
"meta": {
|
|
49
|
+
"makersclaw": {
|
|
50
|
+
"version": "0.3.0",
|
|
51
|
+
"useWhen": "A form or page takes files the app stores: attachments on a record, a CSV to import, product photos, a logo, a profile picture. Not for showing files already stored with no way to add (a table or list), and not for a chat message's attachments (the chat block's composer has those)."
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|