makersclaw 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +41 -1
- package/THIRD-PARTY-NOTICES.md +180 -0
- package/package.json +15 -8
- package/r/annotate.json +62 -0
- package/r/approval-request.json +52 -0
- package/r/audio-player.json +74 -0
- package/r/auth-form.json +55 -0
- package/r/board.json +55 -0
- package/r/calendar-view.json +105 -0
- package/r/cart.json +62 -0
- package/r/chart.json +83 -0
- package/r/chat.json +95 -0
- package/r/code-editor.json +94 -0
- package/r/comment-box.json +64 -0
- package/r/contact-section.json +53 -0
- package/r/core.json +341 -0
- package/r/csv-import.json +63 -0
- package/r/data-table.json +69 -0
- package/r/diagram.json +74 -0
- package/r/doc-editor.json +82 -0
- package/r/doc-page.json +61 -0
- package/r/email-render.json +73 -0
- package/r/faq.json +50 -0
- package/r/file-upload.json +54 -0
- package/r/flow-canvas.json +93 -0
- package/r/footer.json +52 -0
- package/r/gantt.json +70 -0
- package/r/job-panel.json +56 -0
- package/r/json-editor.json +66 -0
- package/r/map.json +89 -0
- package/r/menubar.json +52 -0
- package/r/mind-map.json +67 -0
- package/r/navigation-menu.json +52 -0
- package/r/order-detail.json +54 -0
- package/r/org-chart.json +66 -0
- package/r/page-builder.json +105 -0
- package/r/payment-methods.json +51 -0
- package/r/pdf-document.json +79 -0
- package/r/pdf-viewer.json +88 -0
- package/r/product-detail.json +76 -0
- package/r/product-grid.json +65 -0
- package/r/record-form.json +67 -0
- package/r/record-notes.json +55 -0
- package/r/registry.json +3612 -0
- package/r/search-dialog.json +51 -0
- package/r/settings-list.json +66 -0
- package/r/setup-checklist.json +51 -0
- package/r/share-dialog.json +52 -0
- package/r/sidebar.json +69 -0
- package/r/signature-pad.json +72 -0
- package/r/sketch-canvas.json +99 -0
- package/r/spreadsheet.json +90 -0
- package/r/stat-cards.json +66 -0
- package/r/task-list.json +63 -0
- package/r/task-model.json +98 -0
- package/r/testimonials.json +52 -0
- package/r/transaction-list.json +53 -0
- package/r/whiteboard.json +66 -0
- package/registry/blocks/annotate/README.md +179 -0
- package/registry/blocks/annotate/annotate-data.js +250 -0
- package/registry/blocks/annotate/annotate.jsx +646 -0
- package/registry/blocks/annotate/block.json +10 -0
- package/registry/blocks/annotate/demo.jsx +135 -0
- package/registry/blocks/annotate/index.js +15 -0
- package/registry/blocks/approval-request/README.md +116 -0
- package/registry/blocks/approval-request/approval-request.jsx +386 -0
- package/registry/blocks/approval-request/block.json +10 -0
- package/registry/blocks/approval-request/demo.jsx +127 -0
- package/registry/blocks/approval-request/index.js +4 -0
- package/registry/blocks/audio-player/README.md +167 -0
- package/registry/blocks/audio-player/audio-player.jsx +623 -0
- package/registry/blocks/audio-player/block.json +14 -0
- package/registry/blocks/audio-player/colors.js +109 -0
- package/registry/blocks/audio-player/demo.jsx +209 -0
- package/registry/blocks/audio-player/index.js +6 -0
- package/registry/blocks/audio-player/time.js +67 -0
- package/registry/blocks/audio-player/wavesurfer.js +9 -0
- package/registry/blocks/auth-form/README.md +126 -0
- package/registry/blocks/auth-form/auth-form.jsx +568 -0
- package/registry/blocks/auth-form/block.json +10 -0
- package/registry/blocks/auth-form/demo.jsx +131 -0
- package/registry/blocks/auth-form/index.js +3 -0
- package/registry/blocks/board/README.md +64 -13
- package/registry/blocks/board/block.json +2 -2
- package/registry/blocks/board/board.jsx +237 -94
- package/registry/blocks/board/demo.jsx +103 -24
- package/registry/blocks/calendar-view/README.md +180 -0
- package/registry/blocks/calendar-view/agenda.jsx +147 -0
- package/registry/blocks/calendar-view/block.json +76 -0
- package/registry/blocks/calendar-view/calendar-model.js +442 -0
- package/registry/blocks/calendar-view/calendar.jsx +627 -0
- package/registry/blocks/calendar-view/demo.jsx +195 -0
- package/registry/blocks/calendar-view/draft.jsx +49 -0
- package/registry/blocks/calendar-view/index.js +39 -0
- package/registry/blocks/calendar-view/month.jsx +346 -0
- package/registry/blocks/calendar-view/paint.js +69 -0
- package/registry/blocks/calendar-view/time-grid.jsx +527 -0
- package/registry/blocks/calendar-view/tray.jsx +87 -0
- package/registry/blocks/cart/README.md +146 -0
- package/registry/blocks/cart/block.json +10 -0
- package/registry/blocks/cart/cart.jsx +597 -0
- package/registry/blocks/cart/demo.jsx +98 -0
- package/registry/blocks/cart/index.js +4 -0
- package/registry/blocks/cart/money.js +28 -0
- package/registry/blocks/chart/README.md +316 -0
- package/registry/blocks/chart/block.json +10 -0
- package/registry/blocks/chart/cartesian.jsx +642 -0
- package/registry/blocks/chart/core.jsx +262 -0
- package/registry/blocks/chart/demo.jsx +357 -0
- package/registry/blocks/chart/heatmap.jsx +336 -0
- package/registry/blocks/chart/index.js +8 -0
- package/registry/blocks/chart/pie.jsx +245 -0
- package/registry/blocks/chart/sparkline.jsx +88 -0
- package/registry/blocks/chat/README.md +273 -0
- package/registry/blocks/chat/attachment.jsx +95 -0
- package/registry/blocks/chat/block.json +10 -0
- package/registry/blocks/chat/chat.jsx +132 -0
- package/registry/blocks/chat/composer.jsx +364 -0
- package/registry/blocks/chat/demo.jsx +578 -0
- package/registry/blocks/chat/header.jsx +34 -0
- package/registry/blocks/chat/index.js +9 -0
- package/registry/blocks/chat/message.jsx +450 -0
- package/registry/blocks/chat/scroller.jsx +247 -0
- package/registry/blocks/chat/text.jsx +104 -0
- package/registry/blocks/code-editor/README.md +210 -0
- package/registry/blocks/code-editor/block.json +22 -0
- package/registry/blocks/code-editor/code-editor.jsx +534 -0
- package/registry/blocks/code-editor/codemirror.js +38 -0
- package/registry/blocks/code-editor/demo.jsx +205 -0
- package/registry/blocks/code-editor/index.js +8 -0
- package/registry/blocks/code-editor/json.js +317 -0
- package/registry/blocks/code-editor/sql.js +136 -0
- package/registry/blocks/code-editor/text.js +101 -0
- package/registry/blocks/code-editor/theme.js +186 -0
- package/registry/blocks/comment-box/README.md +123 -0
- package/registry/blocks/comment-box/block.json +10 -0
- package/registry/blocks/comment-box/comment-body.jsx +217 -0
- package/registry/blocks/comment-box/comment-box.jsx +198 -0
- package/registry/blocks/comment-box/comment-time.jsx +77 -0
- package/registry/blocks/comment-box/demo.jsx +141 -0
- package/registry/blocks/comment-box/index.js +8 -0
- package/registry/blocks/contact-section/README.md +152 -0
- package/registry/blocks/contact-section/block.json +11 -0
- package/registry/blocks/contact-section/contact-section.jsx +509 -0
- package/registry/blocks/contact-section/demo.jsx +93 -0
- package/registry/blocks/contact-section/index.js +4 -0
- package/registry/blocks/csv-import/README.md +133 -0
- package/registry/blocks/csv-import/block.json +13 -0
- package/registry/blocks/csv-import/csv-import.jsx +479 -0
- package/registry/blocks/csv-import/demo.jsx +106 -0
- package/registry/blocks/csv-import/import.js +200 -0
- package/registry/blocks/csv-import/index.js +7 -0
- package/registry/blocks/data-table/README.md +386 -0
- package/registry/blocks/data-table/block.json +10 -0
- package/registry/blocks/data-table/data-table.jsx +1164 -0
- package/registry/blocks/data-table/demo.jsx +588 -0
- package/registry/blocks/data-table/index.js +5 -0
- package/registry/blocks/data-table/model.js +169 -0
- package/registry/blocks/diagram/README.md +108 -0
- package/registry/blocks/diagram/block.json +13 -0
- package/registry/blocks/diagram/demo.jsx +113 -0
- package/registry/blocks/diagram/diagram.jsx +481 -0
- package/registry/blocks/diagram/index.js +7 -0
- package/registry/blocks/diagram/mermaid.js +52 -0
- package/registry/blocks/diagram/palette.js +313 -0
- package/registry/blocks/diagram/source.js +98 -0
- package/registry/blocks/doc-editor/README.md +215 -0
- package/registry/blocks/doc-editor/block.json +15 -0
- package/registry/blocks/doc-editor/demo.jsx +225 -0
- package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
- package/registry/blocks/doc-editor/doc.js +309 -0
- package/registry/blocks/doc-editor/index.js +7 -0
- package/registry/blocks/doc-editor/schema.jsx +56 -0
- package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
- package/registry/blocks/doc-editor/theme.js +82 -0
- package/registry/blocks/doc-page/README.md +119 -0
- package/registry/blocks/doc-page/autosave.js +104 -0
- package/registry/blocks/doc-page/block.json +10 -0
- package/registry/blocks/doc-page/demo.jsx +137 -0
- package/registry/blocks/doc-page/doc-page.jsx +276 -0
- package/registry/blocks/doc-page/index.js +4 -0
- package/registry/blocks/email-render/README.md +151 -0
- package/registry/blocks/email-render/block.json +14 -0
- package/registry/blocks/email-render/demo.jsx +153 -0
- package/registry/blocks/email-render/doc-email.jsx +210 -0
- package/registry/blocks/email-render/email.jsx +221 -0
- package/registry/blocks/email-render/index.js +10 -0
- package/registry/blocks/email-render/render.js +50 -0
- package/registry/blocks/email-render/theme.js +215 -0
- package/registry/blocks/faq/README.md +101 -0
- package/registry/blocks/faq/block.json +11 -0
- package/registry/blocks/faq/demo.jsx +89 -0
- package/registry/blocks/faq/faq.jsx +220 -0
- package/registry/blocks/faq/index.js +4 -0
- package/registry/blocks/file-upload/README.md +138 -0
- package/registry/blocks/file-upload/block.json +10 -0
- package/registry/blocks/file-upload/demo.jsx +204 -0
- package/registry/blocks/file-upload/file-upload.jsx +635 -0
- package/registry/blocks/file-upload/index.js +4 -0
- package/registry/blocks/flow-canvas/README.md +420 -0
- package/registry/blocks/flow-canvas/block.json +13 -0
- package/registry/blocks/flow-canvas/board.js +819 -0
- package/registry/blocks/flow-canvas/chrome.jsx +649 -0
- package/registry/blocks/flow-canvas/context.jsx +35 -0
- package/registry/blocks/flow-canvas/demo.jsx +249 -0
- package/registry/blocks/flow-canvas/edges.jsx +107 -0
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
- package/registry/blocks/flow-canvas/index.js +41 -0
- package/registry/blocks/flow-canvas/nodes.jsx +392 -0
- package/registry/blocks/flow-canvas/theme.js +174 -0
- package/registry/blocks/footer/README.md +133 -0
- package/registry/blocks/footer/block.json +11 -0
- package/registry/blocks/footer/demo.jsx +119 -0
- package/registry/blocks/footer/footer.jsx +406 -0
- package/registry/blocks/footer/index.js +4 -0
- package/registry/blocks/gantt/README.md +220 -0
- package/registry/blocks/gantt/block.json +10 -0
- package/registry/blocks/gantt/demo.jsx +148 -0
- package/registry/blocks/gantt/gantt.jsx +923 -0
- package/registry/blocks/gantt/index.js +7 -0
- package/registry/blocks/gantt/rows.jsx +468 -0
- package/registry/blocks/gantt/schedule.js +278 -0
- package/registry/blocks/job-panel/README.md +86 -2
- package/registry/blocks/job-panel/block.json +3 -3
- package/registry/blocks/job-panel/demo.jsx +230 -3
- package/registry/blocks/job-panel/job-panel.jsx +169 -3
- package/registry/blocks/json-editor/README.md +133 -0
- package/registry/blocks/json-editor/block.json +10 -0
- package/registry/blocks/json-editor/demo.jsx +92 -0
- package/registry/blocks/json-editor/index.js +7 -0
- package/registry/blocks/json-editor/json-editor.jsx +305 -0
- package/registry/blocks/json-editor/json-tree.jsx +393 -0
- package/registry/blocks/json-editor/tree.js +225 -0
- package/registry/blocks/map/README.md +221 -0
- package/registry/blocks/map/block.json +14 -0
- package/registry/blocks/map/demo.jsx +201 -0
- package/registry/blocks/map/geo.js +198 -0
- package/registry/blocks/map/index.js +8 -0
- package/registry/blocks/map/list.jsx +128 -0
- package/registry/blocks/map/map-view.jsx +715 -0
- package/registry/blocks/map/maplibre.js +30 -0
- package/registry/blocks/map/marks.jsx +146 -0
- package/registry/blocks/map/theme.js +142 -0
- package/registry/blocks/menubar/README.md +109 -0
- package/registry/blocks/menubar/block.json +10 -0
- package/registry/blocks/menubar/demo.jsx +128 -0
- package/registry/blocks/menubar/index.js +4 -0
- package/registry/blocks/menubar/menubar.jsx +199 -0
- package/registry/blocks/mind-map/README.md +206 -0
- package/registry/blocks/mind-map/block.json +10 -0
- package/registry/blocks/mind-map/demo.jsx +103 -0
- package/registry/blocks/mind-map/index.js +31 -0
- package/registry/blocks/mind-map/mind-map.jsx +1125 -0
- package/registry/blocks/mind-map/topic.jsx +143 -0
- package/registry/blocks/mind-map/tree.js +645 -0
- package/registry/blocks/navigation-menu/README.md +124 -0
- package/registry/blocks/navigation-menu/block.json +10 -0
- package/registry/blocks/navigation-menu/demo.jsx +84 -0
- package/registry/blocks/navigation-menu/index.js +4 -0
- package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
- package/registry/blocks/order-detail/README.md +109 -0
- package/registry/blocks/order-detail/block.json +10 -0
- package/registry/blocks/order-detail/demo.jsx +88 -0
- package/registry/blocks/order-detail/index.js +4 -0
- package/registry/blocks/order-detail/order-detail.jsx +354 -0
- package/registry/blocks/org-chart/README.md +145 -0
- package/registry/blocks/org-chart/block.json +10 -0
- package/registry/blocks/org-chart/demo.jsx +94 -0
- package/registry/blocks/org-chart/index.js +7 -0
- package/registry/blocks/org-chart/org-chart.jsx +631 -0
- package/registry/blocks/org-chart/org.js +245 -0
- package/registry/blocks/org-chart/person.jsx +96 -0
- package/registry/blocks/page-builder/README.md +257 -0
- package/registry/blocks/page-builder/block.json +14 -0
- package/registry/blocks/page-builder/demo.jsx +145 -0
- package/registry/blocks/page-builder/grapes.js +18 -0
- package/registry/blocks/page-builder/index.js +11 -0
- package/registry/blocks/page-builder/page-builder.jsx +704 -0
- package/registry/blocks/page-builder/page-view.jsx +33 -0
- package/registry/blocks/page-builder/page.js +118 -0
- package/registry/blocks/page-builder/panels.jsx +588 -0
- package/registry/blocks/page-builder/sections.js +209 -0
- package/registry/blocks/page-builder/theme.js +87 -0
- package/registry/blocks/page-builder/thumbs.jsx +189 -0
- package/registry/blocks/page-builder/tokens.js +329 -0
- package/registry/blocks/payment-methods/README.md +104 -0
- package/registry/blocks/payment-methods/block.json +10 -0
- package/registry/blocks/payment-methods/demo.jsx +71 -0
- package/registry/blocks/payment-methods/index.js +4 -0
- package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
- package/registry/blocks/pdf-document/README.md +213 -0
- package/registry/blocks/pdf-document/block.json +13 -0
- package/registry/blocks/pdf-document/demo.jsx +136 -0
- package/registry/blocks/pdf-document/index.js +33 -0
- package/registry/blocks/pdf-document/money.js +83 -0
- package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
- package/registry/blocks/pdf-document/primitives.jsx +271 -0
- package/registry/blocks/pdf-document/quote.jsx +179 -0
- package/registry/blocks/pdf-document/theme.js +193 -0
- package/registry/blocks/pdf-viewer/README.md +191 -0
- package/registry/blocks/pdf-viewer/block.json +14 -0
- package/registry/blocks/pdf-viewer/demo.jsx +252 -0
- package/registry/blocks/pdf-viewer/helpers.js +270 -0
- package/registry/blocks/pdf-viewer/index.js +8 -0
- package/registry/blocks/pdf-viewer/notes.jsx +195 -0
- package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
- package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
- package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
- package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
- package/registry/blocks/product-detail/README.md +217 -0
- package/registry/blocks/product-detail/block.json +10 -0
- package/registry/blocks/product-detail/demo.jsx +233 -0
- package/registry/blocks/product-detail/index.js +7 -0
- package/registry/blocks/product-detail/price.jsx +115 -0
- package/registry/blocks/product-detail/product-detail.jsx +348 -0
- package/registry/blocks/product-detail/product-media.jsx +102 -0
- package/registry/blocks/product-detail/product-options.jsx +144 -0
- package/registry/blocks/product-grid/README.md +162 -0
- package/registry/blocks/product-grid/block.json +10 -0
- package/registry/blocks/product-grid/demo.jsx +255 -0
- package/registry/blocks/product-grid/index.js +5 -0
- package/registry/blocks/product-grid/product-card.jsx +232 -0
- package/registry/blocks/product-grid/product-grid.jsx +235 -0
- package/registry/blocks/record-form/README.md +196 -0
- package/registry/blocks/record-form/block.json +10 -0
- package/registry/blocks/record-form/demo.jsx +525 -0
- package/registry/blocks/record-form/index.js +4 -0
- package/registry/blocks/record-form/record-fields.jsx +457 -0
- package/registry/blocks/record-form/record-form.jsx +415 -0
- package/registry/blocks/record-form/rules.js +81 -0
- package/registry/blocks/record-notes/README.md +139 -0
- package/registry/blocks/record-notes/block.json +10 -0
- package/registry/blocks/record-notes/demo.jsx +179 -0
- package/registry/blocks/record-notes/index.js +4 -0
- package/registry/blocks/record-notes/record-notes.jsx +266 -0
- package/registry/blocks/search-dialog/README.md +108 -0
- package/registry/blocks/search-dialog/block.json +10 -0
- package/registry/blocks/search-dialog/demo.jsx +116 -0
- package/registry/blocks/search-dialog/index.js +3 -0
- package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
- package/registry/blocks/settings-list/README.md +171 -0
- package/registry/blocks/settings-list/block.json +10 -0
- package/registry/blocks/settings-list/demo.jsx +333 -0
- package/registry/blocks/settings-list/index.js +4 -0
- package/registry/blocks/settings-list/row-state.jsx +93 -0
- package/registry/blocks/settings-list/settings-list.jsx +349 -0
- package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
- package/registry/blocks/setup-checklist/README.md +142 -0
- package/registry/blocks/setup-checklist/block.json +10 -0
- package/registry/blocks/setup-checklist/demo.jsx +159 -0
- package/registry/blocks/setup-checklist/index.js +4 -0
- package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
- package/registry/blocks/share-dialog/README.md +113 -0
- package/registry/blocks/share-dialog/block.json +10 -0
- package/registry/blocks/share-dialog/demo.jsx +140 -0
- package/registry/blocks/share-dialog/index.js +3 -0
- package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
- package/registry/blocks/sidebar/README.md +190 -0
- package/registry/blocks/sidebar/block.json +43 -0
- package/registry/blocks/sidebar/demo.jsx +577 -0
- package/registry/blocks/sidebar/index.js +4 -0
- package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
- package/registry/blocks/sidebar/sidebar.jsx +864 -0
- package/registry/blocks/signature-pad/README.md +137 -0
- package/registry/blocks/signature-pad/block.json +13 -0
- package/registry/blocks/signature-pad/colors.js +115 -0
- package/registry/blocks/signature-pad/demo.jsx +94 -0
- package/registry/blocks/signature-pad/index.js +6 -0
- package/registry/blocks/signature-pad/pad.js +7 -0
- package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
- package/registry/blocks/signature-pad/signature.js +68 -0
- package/registry/blocks/sketch-canvas/README.md +280 -0
- package/registry/blocks/sketch-canvas/block.json +13 -0
- package/registry/blocks/sketch-canvas/demo.jsx +159 -0
- package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
- package/registry/blocks/sketch-canvas/index.js +9 -0
- package/registry/blocks/sketch-canvas/palette.js +226 -0
- package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
- package/registry/blocks/sketch-canvas/sketch.js +179 -0
- package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
- package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
- package/registry/blocks/sketch-canvas/stamps.js +104 -0
- package/registry/blocks/sketch-canvas/theme.js +131 -0
- package/registry/blocks/spreadsheet/README.md +307 -0
- package/registry/blocks/spreadsheet/block.json +13 -0
- package/registry/blocks/spreadsheet/cells.jsx +455 -0
- package/registry/blocks/spreadsheet/chrome.jsx +325 -0
- package/registry/blocks/spreadsheet/demo.jsx +177 -0
- package/registry/blocks/spreadsheet/grid.js +387 -0
- package/registry/blocks/spreadsheet/index.js +34 -0
- package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
- package/registry/blocks/spreadsheet/types.js +473 -0
- package/registry/blocks/stat-cards/README.md +173 -0
- package/registry/blocks/stat-cards/block.json +10 -0
- package/registry/blocks/stat-cards/demo.jsx +257 -0
- package/registry/blocks/stat-cards/index.js +4 -0
- package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
- package/registry/blocks/stat-cards/usage.jsx +243 -0
- package/registry/blocks/task-list/README.md +176 -0
- package/registry/blocks/task-list/block.json +10 -0
- package/registry/blocks/task-list/demo.jsx +134 -0
- package/registry/blocks/task-list/index.js +5 -0
- package/registry/blocks/task-list/task-list.jsx +907 -0
- package/registry/blocks/task-model/README.md +455 -0
- package/registry/blocks/task-model/block.json +167 -0
- package/registry/blocks/task-model/changes.js +89 -0
- package/registry/blocks/task-model/dates.js +371 -0
- package/registry/blocks/task-model/demo.jsx +215 -0
- package/registry/blocks/task-model/dnd.jsx +240 -0
- package/registry/blocks/task-model/index.js +97 -0
- package/registry/blocks/task-model/model.js +919 -0
- package/registry/blocks/task-model/parts.jsx +449 -0
- package/registry/blocks/task-model/toolbar.jsx +271 -0
- package/registry/blocks/testimonials/README.md +139 -0
- package/registry/blocks/testimonials/block.json +11 -0
- package/registry/blocks/testimonials/demo.jsx +137 -0
- package/registry/blocks/testimonials/index.js +4 -0
- package/registry/blocks/testimonials/testimonials.jsx +430 -0
- package/registry/blocks/transaction-list/README.md +126 -0
- package/registry/blocks/transaction-list/block.json +10 -0
- package/registry/blocks/transaction-list/demo.jsx +79 -0
- package/registry/blocks/transaction-list/index.js +4 -0
- package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
- package/registry/blocks/whiteboard/README.md +179 -0
- package/registry/blocks/whiteboard/block.json +10 -0
- package/registry/blocks/whiteboard/demo.jsx +169 -0
- package/registry/blocks/whiteboard/index.js +6 -0
- package/registry/blocks/whiteboard/templates.js +150 -0
- package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
- package/src/install.mjs +18 -0
- package/src/shadcn.mjs +171 -0
- package/templates/next/files/README.md +145 -11
- package/templates/next/files/app/globals.css +55 -4
- package/templates/next/files/check/run.mjs +3 -3
- package/templates/next/files/components/parts/fixture.jsx +1 -1
- package/templates/next/files/components/parts/sample.js +15 -0
- package/templates/next/files/components/ui/avatar.jsx +141 -0
- package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
- package/templates/next/files/components/ui/button-group.jsx +70 -0
- package/templates/next/files/components/ui/button.jsx +132 -12
- package/templates/next/files/components/ui/calendar.jsx +609 -0
- package/templates/next/files/components/ui/carousel.jsx +281 -0
- package/templates/next/files/components/ui/collapsible.jsx +208 -0
- package/templates/next/files/components/ui/combobox.jsx +608 -0
- package/templates/next/files/components/ui/command.jsx +577 -0
- package/templates/next/files/components/ui/context-menu.jsx +191 -0
- package/templates/next/files/components/ui/date-picker.jsx +360 -0
- package/templates/next/files/components/ui/distribution.jsx +117 -0
- package/templates/next/files/components/ui/feedback.jsx +143 -0
- package/templates/next/files/components/ui/field.jsx +115 -3
- package/templates/next/files/components/ui/file-input.jsx +234 -0
- package/templates/next/files/components/ui/icon.jsx +130 -8
- package/templates/next/files/components/ui/image.jsx +143 -0
- package/templates/next/files/components/ui/index.js +47 -2
- package/templates/next/files/components/ui/input-group.jsx +213 -0
- package/templates/next/files/components/ui/input-otp.jsx +170 -0
- package/templates/next/files/components/ui/item.jsx +206 -0
- package/templates/next/files/components/ui/menu.jsx +454 -82
- package/templates/next/files/components/ui/notice.jsx +126 -14
- package/templates/next/files/components/ui/pagination.jsx +156 -0
- package/templates/next/files/components/ui/popover.jsx +284 -0
- package/templates/next/files/components/ui/radio.jsx +193 -0
- package/templates/next/files/components/ui/rating.jsx +131 -0
- package/templates/next/files/components/ui/resizable.jsx +338 -0
- package/templates/next/files/components/ui/scroll-area.jsx +123 -0
- package/templates/next/files/components/ui/separator.jsx +119 -0
- package/templates/next/files/components/ui/sheet.jsx +96 -11
- package/templates/next/files/components/ui/slider.jsx +174 -0
- package/templates/next/files/components/ui/stat.jsx +574 -0
- package/templates/next/files/components/ui/steps.jsx +338 -0
- package/templates/next/files/components/ui/swatch.jsx +33 -0
- package/templates/next/files/components/ui/table.jsx +130 -0
- package/templates/next/files/components/ui/toast.jsx +440 -0
- package/templates/next/files/components/ui/toggle.jsx +195 -0
- package/templates/next/files/components/ui/tooltip.jsx +270 -0
- package/templates/next/files/lib/sample.js +4 -12
- package/templates/next/template.json +264 -8
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// The panels around the grid: filter, sort, fields, add a field, the
|
|
4
|
+
// keyboard sheet. Each edits one part of the view and hands it back.
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { Avatar, Button, Combobox, Field, Icon, IconButton, Input, KbdGroup, Select, Switch, cx } from "../../ui";
|
|
7
|
+
import { COLUMN_TYPES, parseNumberText, typeOf } from "./types";
|
|
8
|
+
|
|
9
|
+
let seq = 0;
|
|
10
|
+
export const uid = (p) => `${p}-${Date.now().toString(36)}${(seq++).toString(36)}`;
|
|
11
|
+
|
|
12
|
+
/** What "ascending" and "descending" mean for a type, in words. */
|
|
13
|
+
export function sortWords(type) {
|
|
14
|
+
switch (type.name) {
|
|
15
|
+
case "number":
|
|
16
|
+
case "currency":
|
|
17
|
+
case "rating":
|
|
18
|
+
return { asc: "1 → 9", desc: "9 → 1" };
|
|
19
|
+
case "date":
|
|
20
|
+
return { asc: "Oldest first", desc: "Newest first" };
|
|
21
|
+
case "checkbox":
|
|
22
|
+
return { asc: "Checked first", desc: "Unchecked first" };
|
|
23
|
+
case "select":
|
|
24
|
+
case "multi-select":
|
|
25
|
+
return { asc: "First → last", desc: "Last → first" };
|
|
26
|
+
default:
|
|
27
|
+
return { asc: "A → Z", desc: "Z → A" };
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// ── filter ──────────────────────────────────────────────────────────────
|
|
32
|
+
|
|
33
|
+
function NumberValue({ value, onChange }) {
|
|
34
|
+
const [text, setText] = useState(value == null || value === "" ? "" : String(value));
|
|
35
|
+
const n = parseNumberText(text);
|
|
36
|
+
return (
|
|
37
|
+
<Input
|
|
38
|
+
inputMode="decimal"
|
|
39
|
+
placeholder="Number"
|
|
40
|
+
aria-label="Value"
|
|
41
|
+
value={text}
|
|
42
|
+
invalid={text !== "" && Number.isNaN(n)}
|
|
43
|
+
onChange={(e) => {
|
|
44
|
+
setText(e.target.value);
|
|
45
|
+
const next = parseNumberText(e.target.value);
|
|
46
|
+
onChange(next === null ? "" : Number.isNaN(next) ? "" : next);
|
|
47
|
+
}}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function FilterValue({ op, column, value, onChange, ctx }) {
|
|
53
|
+
switch (op?.arg) {
|
|
54
|
+
case "text":
|
|
55
|
+
return <Input placeholder="Text" aria-label="Value" value={value ?? ""} onChange={(e) => onChange(e.target.value)} />;
|
|
56
|
+
case "number":
|
|
57
|
+
return <NumberValue key={column.key + op.id} value={value} onChange={onChange} />;
|
|
58
|
+
case "date":
|
|
59
|
+
return <Input type="date" aria-label="Value" value={value ?? ""} onChange={(e) => onChange(e.target.value)} />;
|
|
60
|
+
case "options":
|
|
61
|
+
return (
|
|
62
|
+
<Combobox
|
|
63
|
+
multiple
|
|
64
|
+
label="Values"
|
|
65
|
+
placeholder="Pick options"
|
|
66
|
+
options={(column.options ?? []).map((o) => ({ value: o.value, label: o.label }))}
|
|
67
|
+
value={Array.isArray(value) ? value : []}
|
|
68
|
+
onValueChange={(v) => onChange(v)}
|
|
69
|
+
/>
|
|
70
|
+
);
|
|
71
|
+
case "person":
|
|
72
|
+
return (
|
|
73
|
+
<Combobox
|
|
74
|
+
multiple
|
|
75
|
+
label="People"
|
|
76
|
+
placeholder="Pick people"
|
|
77
|
+
options={(ctx.people ?? []).map((p) => ({ value: p.id, label: p.name, icon: <Avatar name={p.name} src={p.src} size="xs" /> }))}
|
|
78
|
+
value={Array.isArray(value) ? value : []}
|
|
79
|
+
onValueChange={(v) => onChange(v)}
|
|
80
|
+
/>
|
|
81
|
+
);
|
|
82
|
+
default:
|
|
83
|
+
return <span aria-hidden="true" />;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function FilterPanel({ columns, filters, onChange, ctx, custom }) {
|
|
88
|
+
const byKey = new Map(columns.map((c) => [c.key, c]));
|
|
89
|
+
function set(id, patch) {
|
|
90
|
+
onChange(filters.map((f) => (f.id === id ? { ...f, ...patch } : f)));
|
|
91
|
+
}
|
|
92
|
+
function add() {
|
|
93
|
+
const col = columns[0];
|
|
94
|
+
if (!col) return;
|
|
95
|
+
onChange([...filters, { id: uid("f"), key: col.key, op: typeOf(col, custom).allFilters[0].id, value: "" }]);
|
|
96
|
+
}
|
|
97
|
+
return (
|
|
98
|
+
<div className="grid w-[38rem] max-w-full gap-3">
|
|
99
|
+
<p className="text-sm font-medium">Filter rows</p>
|
|
100
|
+
{filters.length === 0 ? (
|
|
101
|
+
<p className="text-sm text-muted-foreground">Nothing filtered. Add a condition to show only the rows you need.</p>
|
|
102
|
+
) : (
|
|
103
|
+
<ul className="grid gap-2">
|
|
104
|
+
{filters.map((f, i) => {
|
|
105
|
+
const col = byKey.get(f.key) ?? columns[0];
|
|
106
|
+
const t = typeOf(col, custom);
|
|
107
|
+
const op = t.allFilters.find((o) => o.id === f.op) ?? t.allFilters[0];
|
|
108
|
+
return (
|
|
109
|
+
<li
|
|
110
|
+
key={f.id}
|
|
111
|
+
className="grid gap-2 max-sm:rounded-md max-sm:border max-sm:border-border max-sm:p-2 sm:grid-cols-[3rem_minmax(0,1fr)_minmax(0,9rem)_minmax(0,1fr)_auto] sm:items-center"
|
|
112
|
+
>
|
|
113
|
+
<div className="flex items-center justify-between sm:contents">
|
|
114
|
+
<span className="text-xs text-muted-foreground">{i === 0 ? "Where" : "and"}</span>
|
|
115
|
+
<IconButton icon="x" size="sm" label="Remove this condition" className="sm:hidden" onClick={() => onChange(filters.filter((x) => x.id !== f.id))} />
|
|
116
|
+
</div>
|
|
117
|
+
<Select
|
|
118
|
+
aria-label="Field"
|
|
119
|
+
value={col.key}
|
|
120
|
+
options={columns.map((c) => ({ value: c.key, label: c.name }))}
|
|
121
|
+
onChange={(e) => {
|
|
122
|
+
const next = byKey.get(e.target.value);
|
|
123
|
+
set(f.id, { key: next.key, op: typeOf(next, custom).allFilters[0].id, value: "" });
|
|
124
|
+
}}
|
|
125
|
+
/>
|
|
126
|
+
<Select
|
|
127
|
+
aria-label="Condition"
|
|
128
|
+
value={op.id}
|
|
129
|
+
options={t.allFilters.map((o) => ({ value: o.id, label: o.label }))}
|
|
130
|
+
onChange={(e) => set(f.id, { op: e.target.value, value: t.allFilters.find((o) => o.id === e.target.value)?.arg === op.arg ? f.value : "" })}
|
|
131
|
+
/>
|
|
132
|
+
<div className="min-w-0">
|
|
133
|
+
<FilterValue key={f.key + op.arg} op={op} column={col} value={f.value} ctx={ctx} onChange={(value) => set(f.id, { value })} />
|
|
134
|
+
</div>
|
|
135
|
+
<IconButton icon="x" size="sm" label="Remove this condition" className="max-sm:hidden" onClick={() => onChange(filters.filter((x) => x.id !== f.id))} />
|
|
136
|
+
</li>
|
|
137
|
+
);
|
|
138
|
+
})}
|
|
139
|
+
</ul>
|
|
140
|
+
)}
|
|
141
|
+
<div className="flex items-center justify-between gap-2">
|
|
142
|
+
<Button variant="quiet" size="sm" icon="plus" onClick={add} disabled={!columns.length}>
|
|
143
|
+
Add condition
|
|
144
|
+
</Button>
|
|
145
|
+
{filters.length ? (
|
|
146
|
+
<Button variant="quiet" size="sm" onClick={() => onChange([])}>
|
|
147
|
+
Clear all
|
|
148
|
+
</Button>
|
|
149
|
+
) : null}
|
|
150
|
+
</div>
|
|
151
|
+
</div>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ── sort ────────────────────────────────────────────────────────────────
|
|
156
|
+
|
|
157
|
+
export function SortPanel({ columns, sort, onChange, custom }) {
|
|
158
|
+
const used = new Set(sort.map((s) => s.key));
|
|
159
|
+
const free = columns.filter((c) => !used.has(c.key));
|
|
160
|
+
return (
|
|
161
|
+
<div className="grid w-[26rem] max-w-full gap-3">
|
|
162
|
+
<p className="text-sm font-medium">Sort rows</p>
|
|
163
|
+
{sort.length === 0 ? (
|
|
164
|
+
<p className="text-sm text-muted-foreground">Rows show in the order they were added. Pick a field to sort by.</p>
|
|
165
|
+
) : (
|
|
166
|
+
<ol className="grid gap-2">
|
|
167
|
+
{sort.map((s, i) => {
|
|
168
|
+
const col = columns.find((c) => c.key === s.key);
|
|
169
|
+
if (!col) return null;
|
|
170
|
+
const words = sortWords(typeOf(col, custom));
|
|
171
|
+
return (
|
|
172
|
+
<li key={s.key} className="grid grid-cols-[3rem_minmax(0,1fr)_minmax(0,9rem)_auto] items-center gap-2">
|
|
173
|
+
<span className="text-xs text-muted-foreground">{i === 0 ? "Sort by" : "then"}</span>
|
|
174
|
+
<Select
|
|
175
|
+
aria-label="Field"
|
|
176
|
+
value={s.key}
|
|
177
|
+
options={[col, ...free].map((c) => ({ value: c.key, label: c.name }))}
|
|
178
|
+
onChange={(e) => onChange(sort.map((x, j) => (j === i ? { ...x, key: e.target.value } : x)))}
|
|
179
|
+
/>
|
|
180
|
+
<Select
|
|
181
|
+
aria-label="Direction"
|
|
182
|
+
value={s.dir}
|
|
183
|
+
options={[
|
|
184
|
+
{ value: "asc", label: words.asc },
|
|
185
|
+
{ value: "desc", label: words.desc },
|
|
186
|
+
]}
|
|
187
|
+
onChange={(e) => onChange(sort.map((x, j) => (j === i ? { ...x, dir: e.target.value } : x)))}
|
|
188
|
+
/>
|
|
189
|
+
<IconButton icon="x" size="sm" label="Remove this sort" onClick={() => onChange(sort.filter((_, j) => j !== i))} />
|
|
190
|
+
</li>
|
|
191
|
+
);
|
|
192
|
+
})}
|
|
193
|
+
</ol>
|
|
194
|
+
)}
|
|
195
|
+
<div className="flex items-center justify-between gap-2">
|
|
196
|
+
<Button variant="quiet" size="sm" icon="plus" disabled={!free.length} onClick={() => onChange([...sort, { key: free[0].key, dir: "asc" }])}>
|
|
197
|
+
{sort.length ? "Add another sort" : "Add a sort"}
|
|
198
|
+
</Button>
|
|
199
|
+
{sort.length ? (
|
|
200
|
+
<Button variant="quiet" size="sm" onClick={() => onChange([])}>
|
|
201
|
+
Clear
|
|
202
|
+
</Button>
|
|
203
|
+
) : null}
|
|
204
|
+
</div>
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ── fields (show / hide) ────────────────────────────────────────────────
|
|
210
|
+
|
|
211
|
+
export function FieldsPanel({ columns, hidden, onChange, custom }) {
|
|
212
|
+
const off = new Set(hidden);
|
|
213
|
+
const [q, setQ] = useState("");
|
|
214
|
+
const shown = columns.filter((c) => c.name.toLowerCase().includes(q.trim().toLowerCase()));
|
|
215
|
+
const visibleCount = columns.filter((c) => !off.has(c.key)).length;
|
|
216
|
+
return (
|
|
217
|
+
<div className="grid w-72 max-w-full gap-2">
|
|
218
|
+
{columns.length > 8 ? <Input placeholder="Find a field" aria-label="Find a field" value={q} onChange={(e) => setQ(e.target.value)} /> : null}
|
|
219
|
+
<ul className="grid max-h-80 overflow-y-auto">
|
|
220
|
+
{shown.map((c) => {
|
|
221
|
+
const t = typeOf(c, custom);
|
|
222
|
+
const on = !off.has(c.key);
|
|
223
|
+
return (
|
|
224
|
+
<li key={c.key} className="flex items-center gap-2">
|
|
225
|
+
<Icon name={t.icon} size={14} className="shrink-0 text-muted-foreground" />
|
|
226
|
+
<Switch
|
|
227
|
+
id={`field-${c.key}`}
|
|
228
|
+
checked={on}
|
|
229
|
+
disabled={on && visibleCount <= 1}
|
|
230
|
+
onChange={() => onChange(on ? [...hidden, c.key] : hidden.filter((k) => k !== c.key))}
|
|
231
|
+
label={c.name}
|
|
232
|
+
className="min-w-0 flex-1 flex-row-reverse justify-between"
|
|
233
|
+
/>
|
|
234
|
+
</li>
|
|
235
|
+
);
|
|
236
|
+
})}
|
|
237
|
+
</ul>
|
|
238
|
+
<div className="flex items-center justify-between gap-2 border-t border-border pt-2">
|
|
239
|
+
<Button variant="quiet" size="sm" onClick={() => onChange(columns.slice(1).map((c) => c.key))} disabled={visibleCount <= 1}>
|
|
240
|
+
Hide all
|
|
241
|
+
</Button>
|
|
242
|
+
<Button variant="quiet" size="sm" onClick={() => onChange([])} disabled={!hidden.length}>
|
|
243
|
+
Show all
|
|
244
|
+
</Button>
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// ── add a field ─────────────────────────────────────────────────────────
|
|
251
|
+
|
|
252
|
+
export const TYPE_ORDER = ["text", "number", "currency", "date", "select", "multi-select", "person", "checkbox", "url", "rating"];
|
|
253
|
+
|
|
254
|
+
export function AddFieldPanel({ onAdd, names, custom }) {
|
|
255
|
+
const [name, setName] = useState("");
|
|
256
|
+
const [type, setType] = useState("text");
|
|
257
|
+
const kinds = [...TYPE_ORDER, ...Object.keys(custom ?? {}).filter((k) => !TYPE_ORDER.includes(k))];
|
|
258
|
+
const clash = names.some((n) => n.toLowerCase() === name.trim().toLowerCase());
|
|
259
|
+
function submit(e) {
|
|
260
|
+
e.preventDefault();
|
|
261
|
+
if (!name.trim() || clash) return;
|
|
262
|
+
onAdd({ name: name.trim(), type });
|
|
263
|
+
setName("");
|
|
264
|
+
setType("text");
|
|
265
|
+
}
|
|
266
|
+
return (
|
|
267
|
+
<form className="grid w-80 max-w-full gap-3" onSubmit={submit}>
|
|
268
|
+
<Field id="new-field-name" label="Field name" error={clash ? "A field already has that name" : undefined}>
|
|
269
|
+
<Input id="new-field-name" placeholder="Renewal date" value={name} onChange={(e) => setName(e.target.value)} autoComplete="off" />
|
|
270
|
+
</Field>
|
|
271
|
+
<div className="grid gap-1.5">
|
|
272
|
+
<p className="text-sm font-medium" id="new-field-type">
|
|
273
|
+
Type
|
|
274
|
+
</p>
|
|
275
|
+
<div role="radiogroup" aria-labelledby="new-field-type" className="grid grid-cols-2 gap-1">
|
|
276
|
+
{kinds.map((k) => {
|
|
277
|
+
const t = typeOf({ type: k }, custom);
|
|
278
|
+
const on = type === k;
|
|
279
|
+
return (
|
|
280
|
+
<Button key={k} variant={on ? "secondary" : "quiet"} size="sm" align="start" icon={t.icon} role="radio" aria-checked={on} onClick={() => setType(k)} className={cx("font-normal", on && "ring-1 ring-primary")}>
|
|
281
|
+
{t.label}
|
|
282
|
+
</Button>
|
|
283
|
+
);
|
|
284
|
+
})}
|
|
285
|
+
</div>
|
|
286
|
+
</div>
|
|
287
|
+
<Button type="submit" variant="primary" size="sm" disabled={!name.trim() || clash}>
|
|
288
|
+
Add field
|
|
289
|
+
</Button>
|
|
290
|
+
</form>
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ── keys ────────────────────────────────────────────────────────────────
|
|
295
|
+
|
|
296
|
+
const KEYS = [
|
|
297
|
+
[["↑", "↓", "←", "→"], "Move"],
|
|
298
|
+
[["⇧", "↑"], "Select more"],
|
|
299
|
+
[["↵"], "Edit (or start typing)"],
|
|
300
|
+
[["Esc"], "Cancel an edit"],
|
|
301
|
+
[["⌫"], "Clear cells"],
|
|
302
|
+
[["⌘", "C"], "Copy · ⌘V paste"],
|
|
303
|
+
[["⌘", "D"], "Fill down"],
|
|
304
|
+
[["⌘", "Z"], "Undo · ⇧⌘Z redo"],
|
|
305
|
+
[["Space"], "Tick a box · open a row"],
|
|
306
|
+
[["⇧", "Space"], "Select the row"],
|
|
307
|
+
];
|
|
308
|
+
|
|
309
|
+
export function ShortcutsPanel() {
|
|
310
|
+
return (
|
|
311
|
+
<div className="grid w-72 gap-2">
|
|
312
|
+
<p className="text-sm font-medium">Keyboard</p>
|
|
313
|
+
<ul className="grid gap-1.5">
|
|
314
|
+
{KEYS.map(([keys, what]) => (
|
|
315
|
+
<li key={what} className="flex items-center justify-between gap-3 text-sm">
|
|
316
|
+
<span className="text-muted-foreground">{what}</span>
|
|
317
|
+
<KbdGroup keys={keys} />
|
|
318
|
+
</li>
|
|
319
|
+
))}
|
|
320
|
+
</ul>
|
|
321
|
+
</div>
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export { COLUMN_TYPES };
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// The Spreadsheet over a sales pipeline in memory — the gallery's and the
|
|
4
|
+
// smoke test's surface. Not installed into apps: `makersclaw add
|
|
5
|
+
// spreadsheet` lays index.js and the block's files only.
|
|
6
|
+
import { useMemo, useState } from "react";
|
|
7
|
+
import { Card, Sheet, Switch, ToggleGroup } from "../components/ui";
|
|
8
|
+
import { Spreadsheet } from "../components/blocks/spreadsheet";
|
|
9
|
+
|
|
10
|
+
const TEAM = [
|
|
11
|
+
{ id: "u-maya", name: "Maya Okafor", email: "maya@northpeak.io" },
|
|
12
|
+
{ id: "u-leon", name: "Leon Brandt", email: "leon@northpeak.io" },
|
|
13
|
+
{ id: "u-priya", name: "Priya Raman", email: "priya@northpeak.io" },
|
|
14
|
+
{ id: "u-tomas", name: "Tomás Ferreira", email: "tomas@northpeak.io" },
|
|
15
|
+
{ id: "u-hana", name: "Hana Sato", email: "hana@northpeak.io" },
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const STAGES = [
|
|
19
|
+
{ value: "lead", label: "Lead", hue: 5 },
|
|
20
|
+
{ value: "qualified", label: "Qualified", hue: 2 },
|
|
21
|
+
{ value: "proposal", label: "Proposal", hue: 3 },
|
|
22
|
+
{ value: "negotiation", label: "Negotiation", hue: 4 },
|
|
23
|
+
{ value: "won", label: "Won", hue: 1 },
|
|
24
|
+
{ value: "lost", label: "Lost", hue: 5 },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
const SEGMENTS = [
|
|
28
|
+
{ value: "saas", label: "SaaS", hue: 1 },
|
|
29
|
+
{ value: "fintech", label: "Fintech", hue: 2 },
|
|
30
|
+
{ value: "health", label: "Health", hue: 3 },
|
|
31
|
+
{ value: "retail", label: "Retail", hue: 4 },
|
|
32
|
+
{ value: "enterprise", label: "Enterprise", hue: 5 },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
const PIPELINE_COLUMNS = [
|
|
36
|
+
{ key: "company", name: "Company", type: "text", width: 200, required: true },
|
|
37
|
+
{ key: "stage", name: "Stage", type: "select", options: STAGES },
|
|
38
|
+
{ key: "value", name: "Deal value", type: "currency", currency: "USD", precision: 0 },
|
|
39
|
+
{ key: "owner", name: "Owner", type: "person" },
|
|
40
|
+
{ key: "close", name: "Close date", type: "date" },
|
|
41
|
+
{ key: "segments", name: "Segments", type: "multi-select", options: SEGMENTS },
|
|
42
|
+
{ key: "seats", name: "Seats", type: "number", width: 96 },
|
|
43
|
+
{ key: "fit", name: "Fit", type: "rating", max: 5, width: 120 },
|
|
44
|
+
{ key: "contacted", name: "Contacted", type: "checkbox" },
|
|
45
|
+
{ key: "website", name: "Website", type: "url" },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const FIRST = ["North", "Blue", "Silver", "Bright", "Iron", "Maple", "Harbor", "Summit", "Cedar", "Atlas", "Nova", "Pine", "River", "Stone", "Lumen", "Orbit", "Vista", "Juniper"];
|
|
49
|
+
const SECOND = ["Labs", "Health", "Logistics", "Foods", "Studio", "Capital", "Robotics", "Media", "Dental", "Freight", "Analytics", "Apparel", "Energy", "Legal", "Clinics", "Software"];
|
|
50
|
+
|
|
51
|
+
// The same rows every render: a small seeded generator, so the gallery
|
|
52
|
+
// render does not change between runs.
|
|
53
|
+
function makeDeals(n) {
|
|
54
|
+
let seed = 11;
|
|
55
|
+
const rnd = () => {
|
|
56
|
+
seed = (seed * 16807) % 2147483647;
|
|
57
|
+
return seed / 2147483647;
|
|
58
|
+
};
|
|
59
|
+
const pick = (list) => list[Math.floor(rnd() * list.length)];
|
|
60
|
+
return Array.from({ length: n }, (_, i) => {
|
|
61
|
+
const company = `${pick(FIRST)} ${pick(SECOND)}${i >= FIRST.length * 4 ? ` ${Math.floor(i / 97) + 2}` : ""}`;
|
|
62
|
+
const slug = company.toLowerCase().replace(/[^a-z0-9]+/g, "");
|
|
63
|
+
const stage = pick(STAGES).value;
|
|
64
|
+
const d = new Date(Date.UTC(2026, 8, 1) + Math.floor(rnd() * 150) * 86400000).toISOString().slice(0, 10);
|
|
65
|
+
const segs = SEGMENTS.filter(() => rnd() < 0.28).map((s) => s.value);
|
|
66
|
+
return {
|
|
67
|
+
id: `deal-${1000 + i}`,
|
|
68
|
+
company,
|
|
69
|
+
stage,
|
|
70
|
+
value: Math.round(2 + rnd() * 120) * 500,
|
|
71
|
+
owner: pick(TEAM).id,
|
|
72
|
+
close: rnd() < 0.08 ? null : d,
|
|
73
|
+
segments: segs,
|
|
74
|
+
seats: Math.round(5 + rnd() * 400),
|
|
75
|
+
fit: Math.floor(rnd() * 6),
|
|
76
|
+
contacted: rnd() < 0.55,
|
|
77
|
+
website: rnd() < 0.1 ? "" : `https://${slug}.com`,
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const MANY = makeDeals(10000);
|
|
83
|
+
let made = 0;
|
|
84
|
+
const FEW = makeDeals(60);
|
|
85
|
+
|
|
86
|
+
export default function SpreadsheetDemo() {
|
|
87
|
+
const [size, setSize] = useState("many");
|
|
88
|
+
const [failing, setFailing] = useState(false);
|
|
89
|
+
const [data, setData] = useState({ many: MANY, few: FEW, empty: [] });
|
|
90
|
+
const [columns, setColumns] = useState(PIPELINE_COLUMNS);
|
|
91
|
+
const [open, setOpen] = useState(null);
|
|
92
|
+
const rows = size === "loading" ? [] : data[size];
|
|
93
|
+
|
|
94
|
+
const save = (fn) => async (...args) => {
|
|
95
|
+
await new Promise((r) => setTimeout(r, 250));
|
|
96
|
+
if (failing) return { ok: false, error: "The server said no (the demo's “Saves fail” switch is on)." };
|
|
97
|
+
fn(...args);
|
|
98
|
+
return { ok: true };
|
|
99
|
+
};
|
|
100
|
+
const onChange = save((changes) =>
|
|
101
|
+
setData((d) => {
|
|
102
|
+
const by = new Map();
|
|
103
|
+
for (const c of changes) by.set(c.rowId, { ...(by.get(c.rowId) ?? {}), [c.key]: c.value });
|
|
104
|
+
return { ...d, [size]: d[size].map((r) => (by.has(r.id) ? { ...r, ...by.get(r.id) } : r)) };
|
|
105
|
+
}),
|
|
106
|
+
);
|
|
107
|
+
const onAddRows = save((added, { index }) =>
|
|
108
|
+
setData((d) => {
|
|
109
|
+
const list = d[size];
|
|
110
|
+
const at = index ?? list.length;
|
|
111
|
+
return { ...d, [size]: [...list.slice(0, at), ...added, ...list.slice(at)] };
|
|
112
|
+
}),
|
|
113
|
+
);
|
|
114
|
+
const onDeleteRows = save((ids) => setData((d) => ({ ...d, [size]: d[size].filter((r) => !ids.includes(r.id)) })));
|
|
115
|
+
const onColumnsChange = save((next) => setColumns(next));
|
|
116
|
+
|
|
117
|
+
const openRow = useMemo(() => (open ? rows.find((r) => r.id === open) : null), [open, rows]);
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<div className="grid gap-4">
|
|
121
|
+
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
122
|
+
<div>
|
|
123
|
+
<h2 className="text-lg font-semibold">Pipeline</h2>
|
|
124
|
+
<p className="text-sm text-muted-foreground">Click a cell and type. Drag the corner to fill, paste from Sheets, right-click for more.</p>
|
|
125
|
+
</div>
|
|
126
|
+
<div className="flex flex-wrap items-center gap-3">
|
|
127
|
+
<ToggleGroup
|
|
128
|
+
size="sm"
|
|
129
|
+
aria-label="Rows"
|
|
130
|
+
value={size}
|
|
131
|
+
onChange={setSize}
|
|
132
|
+
items={[
|
|
133
|
+
{ value: "many", label: "10,000 rows" },
|
|
134
|
+
{ value: "few", label: "60 rows" },
|
|
135
|
+
{ value: "empty", label: "Empty" },
|
|
136
|
+
{ value: "loading", label: "Loading" },
|
|
137
|
+
]}
|
|
138
|
+
/>
|
|
139
|
+
<Switch id="sheet-fail" label="Saves fail" checked={failing} onChange={(e) => setFailing(e.target.checked)} />
|
|
140
|
+
</div>
|
|
141
|
+
</div>
|
|
142
|
+
<Spreadsheet
|
|
143
|
+
key={size}
|
|
144
|
+
label="Pipeline"
|
|
145
|
+
noun="deal"
|
|
146
|
+
rows={rows}
|
|
147
|
+
columns={columns}
|
|
148
|
+
people={TEAM}
|
|
149
|
+
loading={size === "loading"}
|
|
150
|
+
today="2026-09-23"
|
|
151
|
+
locale="en-US"
|
|
152
|
+
defaultView={{ frozen: 1, widths: {}, sort: [], filters: [] }}
|
|
153
|
+
onChange={onChange}
|
|
154
|
+
onAddRows={onAddRows}
|
|
155
|
+
onDeleteRows={onDeleteRows}
|
|
156
|
+
onColumnsChange={onColumnsChange}
|
|
157
|
+
onExpandRow={(row) => setOpen(row.id)}
|
|
158
|
+
createRow={() => ({ id: `deal-new-${++made}`, stage: "lead", contacted: false, segments: [] })}
|
|
159
|
+
height={560}
|
|
160
|
+
/>
|
|
161
|
+
<Sheet open={Boolean(openRow)} onClose={() => setOpen(null)} title={openRow?.company || "Untitled deal"} description="The row, opened: base-view draws a record here.">
|
|
162
|
+
{openRow ? (
|
|
163
|
+
<Card padding="sm">
|
|
164
|
+
<dl className="grid grid-cols-[8rem_1fr] gap-x-3 gap-y-2 text-sm">
|
|
165
|
+
{columns.map((c) => (
|
|
166
|
+
<div key={c.key} className="contents">
|
|
167
|
+
<dt className="text-muted-foreground">{c.name}</dt>
|
|
168
|
+
<dd className="truncate">{Array.isArray(openRow[c.key]) ? openRow[c.key].join(", ") : String(openRow[c.key] ?? "—")}</dd>
|
|
169
|
+
</div>
|
|
170
|
+
))}
|
|
171
|
+
</dl>
|
|
172
|
+
</Card>
|
|
173
|
+
) : null}
|
|
174
|
+
</Sheet>
|
|
175
|
+
</div>
|
|
176
|
+
);
|
|
177
|
+
}
|