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,574 @@
|
|
|
1
|
+
import { Children } from "react";
|
|
2
|
+
import { cx } from "./cx";
|
|
3
|
+
import { Icon } from "./icon";
|
|
4
|
+
|
|
5
|
+
// Numbers at a glance: a Stat, the strip of them, the signed change beside
|
|
6
|
+
// one, a status dot, a legend of dots, a meter against a limit.
|
|
7
|
+
// Server-safe (no hooks), so a server surface can use them directly.
|
|
8
|
+
// Every number is tabular (data-nums), so a column of them lines up and a
|
|
9
|
+
// ticking value does not shake. Colour is the signal: tones are named, as
|
|
10
|
+
// Badge does it, and status tones are for status only — never decoration.
|
|
11
|
+
// A dot can take a categorical `hue` (1..5, the chart colours) instead, for
|
|
12
|
+
// KINDS of things: a platform, a content type. Tone is status, hue is
|
|
13
|
+
// category; a tone given with a hue wins.
|
|
14
|
+
// Blocks use these and never draw their own.
|
|
15
|
+
|
|
16
|
+
// The text colour of a value in each tone.
|
|
17
|
+
const TEXT_TONES = {
|
|
18
|
+
neutral: "text-foreground",
|
|
19
|
+
muted: "text-muted-foreground",
|
|
20
|
+
primary: "text-primary",
|
|
21
|
+
success: "text-success",
|
|
22
|
+
warning: "text-warning",
|
|
23
|
+
danger: "text-destructive",
|
|
24
|
+
info: "text-info",
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
// The fill of a dot or a bar in each tone. neutral is a quiet grey for a
|
|
28
|
+
// dot; a Meter's neutral bar is bg-primary, the same as Progress, and its
|
|
29
|
+
// muted bar is the grey.
|
|
30
|
+
const FILL_TONES = {
|
|
31
|
+
neutral: "bg-muted-foreground",
|
|
32
|
+
muted: "bg-muted-foreground",
|
|
33
|
+
primary: "bg-primary",
|
|
34
|
+
success: "bg-success",
|
|
35
|
+
warning: "bg-warning",
|
|
36
|
+
danger: "bg-destructive",
|
|
37
|
+
info: "bg-info",
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
// The fill of a dot in each categorical hue (--color-chart-N).
|
|
41
|
+
const HUE_FILLS = { 1: "bg-chart-1", 2: "bg-chart-2", 3: "bg-chart-3", 4: "bg-chart-4", 5: "bg-chart-5" };
|
|
42
|
+
|
|
43
|
+
const EN = "en-US"; // one locale on the server and the client: no hydration drift
|
|
44
|
+
const formatNumber = (n) => (typeof n === "number" ? n.toLocaleString(EN, { maximumFractionDigits: 2 }) : String(n ?? ""));
|
|
45
|
+
|
|
46
|
+
/* ------------------------------------------------------------------------
|
|
47
|
+
Delta
|
|
48
|
+
------------------------------------------------------------------------ */
|
|
49
|
+
|
|
50
|
+
const DELTA_SIZES = { sm: { text: "text-xs", icon: 12 }, md: { text: "text-sm", icon: 14 } };
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* A signed change: an arrow, the value with its sign, an optional suffix —
|
|
54
|
+
* "↑ +12.4%". Up is good (success) and down is bad (danger) unless
|
|
55
|
+
* `invert`, for "lower is better" (latency, churn, cost). Zero is neutral,
|
|
56
|
+
* with a flat dash and no sign.
|
|
57
|
+
*
|
|
58
|
+
* value the change, a number; its sign sets the arrow and the tone
|
|
59
|
+
* display what to show for the size of it instead of the number
|
|
60
|
+
* ("$35K"); the sign is still added. Default the number, to at
|
|
61
|
+
* most one decimal
|
|
62
|
+
* suffix after the number: "%", " pts", "ms"
|
|
63
|
+
* invert lower is better: down turns success, up turns danger
|
|
64
|
+
* label a muted line after it: "vs last week"
|
|
65
|
+
* size sm (text-xs) · md (text-sm)
|
|
66
|
+
* variant text (bare) · badge (a tinted pill, for a table cell or a tile corner)
|
|
67
|
+
* arrow default true; false for the bare "+$35K" of a dense row
|
|
68
|
+
* hideValue the arrow and its tone alone (a trend in a tight cell);
|
|
69
|
+
* the value is still what a screen reader hears. Always draws
|
|
70
|
+
* the arrow, whatever `arrow` says
|
|
71
|
+
*/
|
|
72
|
+
export function Delta({ value, display, suffix = "", invert = false, label, size = "sm", variant = "text", arrow = true, hideValue = false, className }) {
|
|
73
|
+
const n = typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
74
|
+
const sign = n > 0 ? 1 : n < 0 ? -1 : 0;
|
|
75
|
+
const good = invert ? sign < 0 : sign > 0;
|
|
76
|
+
const tone = sign === 0 ? "neutral" : good ? "success" : "danger";
|
|
77
|
+
const s = DELTA_SIZES[size] ?? DELTA_SIZES.sm;
|
|
78
|
+
const amount = display ?? Math.abs(n).toLocaleString(EN, { maximumFractionDigits: 1 });
|
|
79
|
+
const signed = `${sign > 0 ? "+" : sign < 0 ? "−" : ""}${amount}${suffix}`;
|
|
80
|
+
const look =
|
|
81
|
+
variant === "badge"
|
|
82
|
+
? {
|
|
83
|
+
neutral: "bg-muted text-muted-foreground",
|
|
84
|
+
success: "bg-success/15 text-success",
|
|
85
|
+
danger: "bg-destructive/15 text-destructive",
|
|
86
|
+
}[tone]
|
|
87
|
+
: { neutral: "text-muted-foreground", success: "text-success", danger: "text-destructive" }[tone];
|
|
88
|
+
return (
|
|
89
|
+
<span className={cx("inline-flex items-baseline gap-1.5", s.text, className)}>
|
|
90
|
+
<span
|
|
91
|
+
data-nums
|
|
92
|
+
className={cx(
|
|
93
|
+
"inline-flex items-center gap-0.5 whitespace-nowrap font-medium",
|
|
94
|
+
variant === "badge" && "rounded-sm px-1.5 py-0.5",
|
|
95
|
+
look,
|
|
96
|
+
)}
|
|
97
|
+
>
|
|
98
|
+
{arrow || hideValue ? <Icon name={sign > 0 ? "arrow-up" : sign < 0 ? "arrow-down" : "minus"} size={s.icon} className="self-center" /> : null}
|
|
99
|
+
{/* The sign is a real minus (U+2212) on screen; a reader hears the word. */}
|
|
100
|
+
{hideValue ? null : <span aria-hidden="true">{signed}</span>}
|
|
101
|
+
<span className="sr-only">{sign > 0 ? `up ${amount}${suffix}` : sign < 0 ? `down ${amount}${suffix}` : `no change`}</span>
|
|
102
|
+
</span>
|
|
103
|
+
{label ? <span className="text-muted-foreground">{label}</span> : null}
|
|
104
|
+
</span>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* ------------------------------------------------------------------------
|
|
109
|
+
StatusDot and Legend
|
|
110
|
+
------------------------------------------------------------------------ */
|
|
111
|
+
|
|
112
|
+
const DOT_SIZES = { sm: "size-1.5", md: "size-2" };
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* A small round dot in a tone: a row's state, a service's health, a
|
|
116
|
+
* legend key. The dot alone says nothing to a screen reader — the meaning
|
|
117
|
+
* is in `label` (shown), or in `label` + `hideLabel` (read, not shown), or
|
|
118
|
+
* in the text beside it.
|
|
119
|
+
*
|
|
120
|
+
* tone neutral · primary · success · warning · danger · info
|
|
121
|
+
* hue 1..5 — a categorical colour instead (a kind of thing, not
|
|
122
|
+
* a state); ignored when a tone is given
|
|
123
|
+
* size sm (6px, in a dense row) · md (8px)
|
|
124
|
+
* pulse a ring that breathes out, for something live right now
|
|
125
|
+
* (deploying, recording); still under prefers-reduced-motion
|
|
126
|
+
* label the words after it: "Healthy", "3 alerts"
|
|
127
|
+
* hideLabel keep the label for readers only
|
|
128
|
+
*/
|
|
129
|
+
export function StatusDot({ tone, hue, size = "md", pulse = false, label, hideLabel = false, className }) {
|
|
130
|
+
const fill = tone == null && HUE_FILLS[hue] ? HUE_FILLS[hue] : FILL_TONES[tone ?? "neutral"] ?? FILL_TONES.neutral;
|
|
131
|
+
const dot = (
|
|
132
|
+
<span aria-hidden="true" className={cx("relative inline-flex shrink-0", DOT_SIZES[size] ?? DOT_SIZES.md)}>
|
|
133
|
+
{pulse ? <span className={cx("absolute inset-0 rounded-full opacity-60 animate-ping motion-reduce:hidden", fill)} /> : null}
|
|
134
|
+
<span className={cx("relative inline-flex size-full rounded-full", fill)} />
|
|
135
|
+
</span>
|
|
136
|
+
);
|
|
137
|
+
if (!label) return <span className={cx("inline-flex items-center", className)}>{dot}</span>;
|
|
138
|
+
return (
|
|
139
|
+
<span className={cx("inline-flex items-center gap-1.5 text-sm text-muted-foreground", className)}>
|
|
140
|
+
{dot}
|
|
141
|
+
<span className={hideLabel ? "sr-only" : "min-w-0 truncate"}>{label}</span>
|
|
142
|
+
</span>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* A row of dot · count · label, wrapping when it runs out of room — "● 2
|
|
148
|
+
* overdue · ● 3 urgent". The key under a chart, the summary in a card
|
|
149
|
+
* header. A list, so a reader hears how many kinds there are.
|
|
150
|
+
*
|
|
151
|
+
* items [{ tone, label, count }] — count optional; an item with count 0
|
|
152
|
+
* is still drawn (say it, or leave it out of items). `hue` (1..5)
|
|
153
|
+
* in place of `tone` for a key of categories
|
|
154
|
+
* size sm (text-xs, 6px dots) · md (text-sm, 8px dots)
|
|
155
|
+
* label the list's name for readers: "Tasks by state"
|
|
156
|
+
*/
|
|
157
|
+
export function Legend({ items = [], size = "md", label, className }) {
|
|
158
|
+
if (!items.length) return null;
|
|
159
|
+
return (
|
|
160
|
+
<ul
|
|
161
|
+
aria-label={label}
|
|
162
|
+
className={cx("flex flex-wrap items-center gap-x-3 gap-y-1", size === "sm" ? "text-xs" : "text-sm", className)}
|
|
163
|
+
>
|
|
164
|
+
{items.map((it, i) => (
|
|
165
|
+
<li key={it.key ?? `${it.label}-${i}`} className="inline-flex items-center gap-1.5 text-muted-foreground">
|
|
166
|
+
<StatusDot tone={it.tone} hue={it.hue} size={size === "sm" ? "sm" : "md"} />
|
|
167
|
+
{it.count != null ? (
|
|
168
|
+
<span data-nums className="font-medium text-foreground">
|
|
169
|
+
{formatNumber(it.count)}
|
|
170
|
+
</span>
|
|
171
|
+
) : null}
|
|
172
|
+
<span>{it.label}</span>
|
|
173
|
+
</li>
|
|
174
|
+
))}
|
|
175
|
+
</ul>
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/* ------------------------------------------------------------------------
|
|
180
|
+
Stat and StatGroup
|
|
181
|
+
------------------------------------------------------------------------ */
|
|
182
|
+
|
|
183
|
+
const STAT_SIZES = {
|
|
184
|
+
sm: { label: "text-xs", value: "text-lg font-semibold leading-tight", unit: "text-xs", icon: 14, delta: "sm" },
|
|
185
|
+
md: { label: "text-sm", value: "text-2xl font-semibold leading-tight tracking-tight", unit: "text-sm", icon: 16, delta: "sm" },
|
|
186
|
+
lg: { label: "text-sm", value: "font-display text-4xl font-semibold leading-none tracking-tight", unit: "text-base", icon: 18, delta: "md" },
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* One number with its name: "Hit rate 94.8%". The value is the loudest
|
|
191
|
+
* thing on it; everything else is muted.
|
|
192
|
+
*
|
|
193
|
+
* label what it counts: "Monthly revenue"
|
|
194
|
+
* value already formatted — "$1.37M", "42", "2.4/4" (a string or a
|
|
195
|
+
* number; a number gets thousands separators)
|
|
196
|
+
* unit after the value, smaller and muted: "ms", "%", "/ 10.3 TB"
|
|
197
|
+
* caption a muted line under it: "Unit + integration tests"
|
|
198
|
+
* tone colours the value, for a threshold state (a miss rate over
|
|
199
|
+
* budget is danger). neutral (default) · primary · success ·
|
|
200
|
+
* warning · danger · info
|
|
201
|
+
* dot a tone for a StatusDot before the label (the state of the
|
|
202
|
+
* thing, when the value itself stays neutral)
|
|
203
|
+
* icon an Icon name, muted, at the end of the label row
|
|
204
|
+
* delta the change beside the value: a number (a percent: 12.4 →
|
|
205
|
+
* "↑ +12.4%") or Delta's props ({ value, display, suffix, label })
|
|
206
|
+
* invert lower is better, passed to the Delta
|
|
207
|
+
* size sm (a dense strip) · md · lg (the one number a card is about)
|
|
208
|
+
* align start · end (a stat pinned to the right of a header)
|
|
209
|
+
*/
|
|
210
|
+
export function Stat({ label, value, unit, caption, tone = "neutral", dot, icon, delta, invert, size = "md", align = "start", className }) {
|
|
211
|
+
const s = STAT_SIZES[size] ?? STAT_SIZES.md;
|
|
212
|
+
const d = delta == null ? null : typeof delta === "number" ? { value: delta, suffix: "%" } : delta;
|
|
213
|
+
return (
|
|
214
|
+
<div className={cx("min-w-0", align === "end" && "text-right", className)}>
|
|
215
|
+
{label || icon || dot ? (
|
|
216
|
+
<div className={cx("flex items-center gap-1.5 text-muted-foreground", s.label, align === "end" && "justify-end")}>
|
|
217
|
+
{dot ? <StatusDot tone={dot} size="sm" /> : null}
|
|
218
|
+
{label ? <span className="min-w-0 truncate">{label}</span> : null}
|
|
219
|
+
{icon ? <Icon name={icon} size={s.icon} className={cx("shrink-0", align !== "end" && "ml-auto")} /> : null}
|
|
220
|
+
</div>
|
|
221
|
+
) : null}
|
|
222
|
+
<div className={cx("mt-1 flex flex-wrap items-baseline gap-x-2 gap-y-0.5", align === "end" && "justify-end")}>
|
|
223
|
+
<span className="inline-flex min-w-0 items-baseline gap-1">
|
|
224
|
+
<span data-nums className={cx(s.value, TEXT_TONES[tone] ?? TEXT_TONES.neutral)}>
|
|
225
|
+
{formatNumber(value)}
|
|
226
|
+
</span>
|
|
227
|
+
{unit ? (
|
|
228
|
+
<span data-nums className={cx("text-muted-foreground", s.unit)}>
|
|
229
|
+
{unit}
|
|
230
|
+
</span>
|
|
231
|
+
) : null}
|
|
232
|
+
</span>
|
|
233
|
+
{d ? <Delta invert={invert} size={s.delta} {...d} /> : null}
|
|
234
|
+
</div>
|
|
235
|
+
{caption ? <p className="mt-1 text-xs text-muted-foreground">{caption}</p> : null}
|
|
236
|
+
</div>
|
|
237
|
+
);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Literal class names, so Tailwind sees every one.
|
|
241
|
+
const COLS = { 1: "sm:grid-cols-1", 2: "sm:grid-cols-2", 3: "sm:grid-cols-3", 4: "sm:grid-cols-4" };
|
|
242
|
+
const SPAN_SM = { 1: "sm:col-span-1", 2: "sm:col-span-2", 3: "sm:col-span-3", 4: "sm:col-span-4" };
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* The strip of 2 to 4 Stats across the top of a card or a page. Two
|
|
246
|
+
* columns on a phone, all of them from sm up; a last cell that would
|
|
247
|
+
* leave a hole stretches to fill its row.
|
|
248
|
+
*
|
|
249
|
+
* variant card (default: bordered, a rule between every cell) ·
|
|
250
|
+
* divided (no box, a vertical rule between cells — for a strip
|
|
251
|
+
* already inside a Card) · bare (spacing only)
|
|
252
|
+
* columns from sm up; default the number of Stats (at most 4). Six
|
|
253
|
+
* stats in columns={3} make two rows
|
|
254
|
+
* label the strip's name for readers: "Cache summary"
|
|
255
|
+
* children the Stats
|
|
256
|
+
*
|
|
257
|
+
* Edge to edge inside a Card: variant="card" with className="rounded-none
|
|
258
|
+
* border-x-0" and the Card's padding taken off (-mx-4).
|
|
259
|
+
*/
|
|
260
|
+
export function StatGroup({ variant = "card", columns, label, className, children }) {
|
|
261
|
+
const kids = Children.toArray(children).filter(Boolean);
|
|
262
|
+
const n = kids.length;
|
|
263
|
+
if (!n) return null;
|
|
264
|
+
const cols = Math.min(4, Math.max(1, columns ?? Math.min(n, 4)));
|
|
265
|
+
const phoneCols = Math.min(2, n);
|
|
266
|
+
const card = variant === "card";
|
|
267
|
+
const divided = variant === "divided";
|
|
268
|
+
return (
|
|
269
|
+
<div
|
|
270
|
+
role={label ? "group" : undefined}
|
|
271
|
+
aria-label={label}
|
|
272
|
+
className={cx(
|
|
273
|
+
"grid",
|
|
274
|
+
phoneCols === 1 ? "grid-cols-1" : "grid-cols-2",
|
|
275
|
+
COLS[cols],
|
|
276
|
+
card && "gap-px overflow-hidden rounded-lg border border-border bg-border",
|
|
277
|
+
divided && "gap-y-4",
|
|
278
|
+
variant === "bare" && "gap-4",
|
|
279
|
+
className,
|
|
280
|
+
)}
|
|
281
|
+
>
|
|
282
|
+
{kids.map((kid, i) => {
|
|
283
|
+
const last = i === n - 1;
|
|
284
|
+
// A last cell alone on its row spans what is left of it.
|
|
285
|
+
const phoneSpan = last && n % phoneCols !== 0 ? "col-span-2" : "";
|
|
286
|
+
const remSm = n % cols;
|
|
287
|
+
const smSpan = last ? SPAN_SM[remSm ? cols - remSm + 1 : 1] : phoneSpan ? "sm:col-span-1" : "";
|
|
288
|
+
// Divided: a rule on every cell that does not start a row.
|
|
289
|
+
const rulePhone = i % phoneCols !== 0;
|
|
290
|
+
const ruleSm = i % cols !== 0;
|
|
291
|
+
const rule = divided
|
|
292
|
+
? cx(
|
|
293
|
+
"pr-4",
|
|
294
|
+
rulePhone && "border-l border-border pl-4",
|
|
295
|
+
rulePhone && !ruleSm && "sm:border-l-0 sm:pl-0",
|
|
296
|
+
!rulePhone && ruleSm && "sm:border-l sm:border-border sm:pl-4",
|
|
297
|
+
)
|
|
298
|
+
: "";
|
|
299
|
+
return (
|
|
300
|
+
<div key={kid.key ?? i} className={cx("min-w-0", card && "bg-card p-4", rule, phoneSpan, smSpan)}>
|
|
301
|
+
{kid}
|
|
302
|
+
</div>
|
|
303
|
+
);
|
|
304
|
+
})}
|
|
305
|
+
</div>
|
|
306
|
+
);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* ------------------------------------------------------------------------
|
|
310
|
+
Meter
|
|
311
|
+
------------------------------------------------------------------------ */
|
|
312
|
+
|
|
313
|
+
const METER_SIZES = { thin: { track: "h-1", mark: "h-3" }, md: { track: "h-2", mark: "h-4" } };
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* A quantity against a limit: storage used of a plan, spend of a budget,
|
|
317
|
+
* bandwidth of a cap. Drawn like Progress, but it is a role=meter, not a
|
|
318
|
+
* progressbar — Progress is how far a job has got, which only moves
|
|
319
|
+
* forward and ends; a Meter is how full something is, which can fall and
|
|
320
|
+
* can go OVER. Over the limit the bar stays full, turns danger, and a
|
|
321
|
+
* reader hears "over by …".
|
|
322
|
+
*
|
|
323
|
+
* value the amount used, a number in the unit of `max`
|
|
324
|
+
* max the limit; default 100
|
|
325
|
+
* label the meter's name, shown above it and read to a screen reader
|
|
326
|
+
* unit after the numbers: "GB", "credits"
|
|
327
|
+
* format (n) → string for every number shown; default thousands
|
|
328
|
+
* separators ("$" + n / 1000 + "K" for money)
|
|
329
|
+
* valueText the right side of the header; default "used / limit unit";
|
|
330
|
+
* null hides it (a row that shows its own numbers)
|
|
331
|
+
* valueTone the colour of that text: muted (default) · neutral ·
|
|
332
|
+
* primary · success · warning · danger · info · "bar" (the
|
|
333
|
+
* bar's own tone). Over the limit it is danger regardless
|
|
334
|
+
* target a mark on the bar at this amount (a goal, a budget line),
|
|
335
|
+
* named in the footer and to a reader
|
|
336
|
+
* targetMark default true; false keeps the target in the footer and for
|
|
337
|
+
* a reader but draws no tick on the bar
|
|
338
|
+
* direction against `target`, when no `tone` is given: higher (a goal —
|
|
339
|
+
* success once reached, warning below it) · lower (a budget —
|
|
340
|
+
* success at or under it, warning past it). Higher also keeps
|
|
341
|
+
* a bar over the limit out of danger: past a quota is good
|
|
342
|
+
* thresholds [{ at, tone }] — `at` is a percent of max; the bar takes the
|
|
343
|
+
* tone of the highest one reached: [{ at: 80, tone: "warning" },
|
|
344
|
+
* { at: 95, tone: "danger" }]
|
|
345
|
+
* tone the bar below every threshold: neutral (bg-primary, like
|
|
346
|
+
* Progress) · muted (grey, a plain share that signals
|
|
347
|
+
* nothing) · success · warning · danger · info
|
|
348
|
+
* caption a muted line under the bar, left of the target
|
|
349
|
+
* size thin (4px, a list row) · md (8px); a ring: sm (40px, a
|
|
350
|
+
* list row or a stat tile) · md (64px) · lg (96px)
|
|
351
|
+
* shape bar (default) · ring — a circular gauge, the percent in its
|
|
352
|
+
* middle, the label, value text, caption and target beside
|
|
353
|
+
* it. Tone, thresholds, target (a tick across the ring),
|
|
354
|
+
* direction, over-the-limit and what a reader hears are the
|
|
355
|
+
* bar's
|
|
356
|
+
* center a ring's middle instead of the percent: a string or a node
|
|
357
|
+
* ("4.2 GB", an Icon); null leaves it empty
|
|
358
|
+
*/
|
|
359
|
+
export function Meter({
|
|
360
|
+
value,
|
|
361
|
+
max = 100,
|
|
362
|
+
label,
|
|
363
|
+
unit,
|
|
364
|
+
format = formatNumber,
|
|
365
|
+
valueText,
|
|
366
|
+
valueTone = "muted",
|
|
367
|
+
target,
|
|
368
|
+
targetMark = true,
|
|
369
|
+
direction,
|
|
370
|
+
thresholds,
|
|
371
|
+
tone,
|
|
372
|
+
caption,
|
|
373
|
+
size = "md",
|
|
374
|
+
shape = "bar",
|
|
375
|
+
center,
|
|
376
|
+
className,
|
|
377
|
+
...rest
|
|
378
|
+
}) {
|
|
379
|
+
const v = typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
380
|
+
const limit = max > 0 ? max : 100;
|
|
381
|
+
const pct = (v / limit) * 100;
|
|
382
|
+
const over = v > limit;
|
|
383
|
+
const overBad = over && direction !== "higher";
|
|
384
|
+
const u = unit ? ` ${unit}` : "";
|
|
385
|
+
const hasTarget = typeof target === "number" && Number.isFinite(target);
|
|
386
|
+
|
|
387
|
+
// No tone given: the direction judges the value against the target.
|
|
388
|
+
const met = direction === "higher" ? v >= target : v <= target;
|
|
389
|
+
let barTone = tone ?? (hasTarget && (direction === "higher" || direction === "lower") ? (met ? "success" : "warning") : "neutral");
|
|
390
|
+
for (const t of [...(thresholds ?? [])].sort((a, b) => a.at - b.at)) if (pct >= t.at) barTone = t.tone;
|
|
391
|
+
if (overBad) barTone = "danger";
|
|
392
|
+
const fill = barTone === "neutral" ? "bg-primary" : FILL_TONES[barTone] ?? "bg-primary";
|
|
393
|
+
const valueClass = overBad
|
|
394
|
+
? "font-medium text-destructive"
|
|
395
|
+
: valueTone === "bar"
|
|
396
|
+
? cx("font-medium", barTone === "neutral" ? "text-primary" : TEXT_TONES[barTone] ?? "text-primary")
|
|
397
|
+
: valueTone === "muted"
|
|
398
|
+
? "text-muted-foreground"
|
|
399
|
+
: cx("font-medium", TEXT_TONES[valueTone] ?? "text-muted-foreground");
|
|
400
|
+
|
|
401
|
+
const targetPct = hasTarget ? Math.min(100, Math.max(0, (target / limit) * 100)) : 0;
|
|
402
|
+
const shown = valueText === undefined ? `${format(v)} / ${format(limit)}${u}` : valueText;
|
|
403
|
+
const said = [
|
|
404
|
+
`${format(v)} of ${format(limit)}${u}`,
|
|
405
|
+
over ? `over by ${format(v - limit)}${u}` : `${Math.round(pct)}%`,
|
|
406
|
+
hasTarget ? `target ${format(target)}${u}` : null,
|
|
407
|
+
]
|
|
408
|
+
.filter(Boolean)
|
|
409
|
+
.join(", ");
|
|
410
|
+
const meterProps = {
|
|
411
|
+
role: "meter",
|
|
412
|
+
"aria-label": label,
|
|
413
|
+
"aria-valuemin": 0,
|
|
414
|
+
"aria-valuemax": limit,
|
|
415
|
+
"aria-valuenow": Math.min(v, limit),
|
|
416
|
+
"aria-valuetext": said,
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
if (shape === "ring") {
|
|
420
|
+
return (
|
|
421
|
+
<MeterRing
|
|
422
|
+
{...{ pct, over, overBad, barTone, valueTone, valueClass, label, shown, caption, hasTarget, targetMark, targetPct, center, size, className, meterProps, rest }}
|
|
423
|
+
targetText={hasTarget ? `Target ${format(target)}${u}` : null}
|
|
424
|
+
/>
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const s = METER_SIZES[size] ?? METER_SIZES.md;
|
|
429
|
+
const footer = caption || (hasTarget && size === "md");
|
|
430
|
+
|
|
431
|
+
return (
|
|
432
|
+
<div className={cx("grid gap-1.5", className)}>
|
|
433
|
+
{label || shown ? (
|
|
434
|
+
<div aria-hidden="true" className="flex items-baseline justify-between gap-3 text-sm">
|
|
435
|
+
<span className="min-w-0 truncate font-medium text-foreground">{label}</span>
|
|
436
|
+
{shown ? (
|
|
437
|
+
<span data-nums className={cx("shrink-0 text-xs", valueClass)}>
|
|
438
|
+
{shown}
|
|
439
|
+
</span>
|
|
440
|
+
) : null}
|
|
441
|
+
</div>
|
|
442
|
+
) : null}
|
|
443
|
+
<div className="relative">
|
|
444
|
+
<div
|
|
445
|
+
role="meter"
|
|
446
|
+
aria-label={label}
|
|
447
|
+
aria-valuemin={0}
|
|
448
|
+
aria-valuemax={limit}
|
|
449
|
+
aria-valuenow={Math.min(v, limit)}
|
|
450
|
+
aria-valuetext={said}
|
|
451
|
+
className={cx("relative w-full overflow-hidden rounded-full bg-accent", s.track)}
|
|
452
|
+
{...rest}
|
|
453
|
+
>
|
|
454
|
+
<div
|
|
455
|
+
className={cx("h-full rounded-full transition-[width] duration-300 ease-out motion-reduce:transition-none", fill)}
|
|
456
|
+
style={{ width: `${Math.min(100, Math.max(0, pct))}%` }}
|
|
457
|
+
/>
|
|
458
|
+
</div>
|
|
459
|
+
{hasTarget && targetMark ? (
|
|
460
|
+
<span
|
|
461
|
+
aria-hidden="true"
|
|
462
|
+
className={cx("absolute top-1/2 w-0.5 -translate-x-1/2 -translate-y-1/2 rounded-full bg-foreground", s.mark)}
|
|
463
|
+
style={{ left: `${targetPct}%` }}
|
|
464
|
+
/>
|
|
465
|
+
) : null}
|
|
466
|
+
</div>
|
|
467
|
+
{footer ? (
|
|
468
|
+
<div aria-hidden={caption ? undefined : "true"} className="flex items-baseline justify-between gap-3 text-xs text-muted-foreground">
|
|
469
|
+
<span className="min-w-0">{caption}</span>
|
|
470
|
+
{hasTarget ? (
|
|
471
|
+
<span data-nums className="shrink-0">
|
|
472
|
+
Target {format(target)}
|
|
473
|
+
{u}
|
|
474
|
+
</span>
|
|
475
|
+
) : null}
|
|
476
|
+
</div>
|
|
477
|
+
) : null}
|
|
478
|
+
</div>
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// The ring's stroke in each tone (neutral is bg-primary's stroke, as the bar).
|
|
483
|
+
const STROKE_TONES = {
|
|
484
|
+
neutral: "stroke-primary",
|
|
485
|
+
muted: "stroke-muted-foreground",
|
|
486
|
+
primary: "stroke-primary",
|
|
487
|
+
success: "stroke-success",
|
|
488
|
+
warning: "stroke-warning",
|
|
489
|
+
danger: "stroke-destructive",
|
|
490
|
+
info: "stroke-info",
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
// px is the ring's box, w its stroke; text the middle's type.
|
|
494
|
+
const RING_SIZES = {
|
|
495
|
+
sm: { px: 40, w: 4, text: "text-2xs font-semibold", side: "text-sm", gap: "gap-2.5" },
|
|
496
|
+
md: { px: 64, w: 6, text: "text-sm font-semibold", side: "text-sm", gap: "gap-3" },
|
|
497
|
+
lg: { px: 96, w: 8, text: "text-xl font-semibold tracking-tight", side: "text-base", gap: "gap-4" },
|
|
498
|
+
};
|
|
499
|
+
RING_SIZES.thin = RING_SIZES.sm;
|
|
500
|
+
|
|
501
|
+
// Meter shape="ring": the same numbers, drawn as an arc from twelve o'clock.
|
|
502
|
+
function MeterRing({ pct, overBad, barTone, valueTone, valueClass, label, shown, caption, hasTarget, targetMark, targetPct, targetText, center, size, className, meterProps, rest }) {
|
|
503
|
+
const g = RING_SIZES[size] ?? RING_SIZES.md;
|
|
504
|
+
const c = g.px / 2;
|
|
505
|
+
const r = c - g.w / 2;
|
|
506
|
+
const len = 2 * Math.PI * r;
|
|
507
|
+
const frac = Math.min(1, Math.max(0, pct / 100));
|
|
508
|
+
const stroke = STROKE_TONES[barTone] ?? "stroke-primary";
|
|
509
|
+
const middleClass = overBad
|
|
510
|
+
? "text-destructive"
|
|
511
|
+
: valueTone === "bar"
|
|
512
|
+
? barTone === "neutral"
|
|
513
|
+
? "text-primary"
|
|
514
|
+
: TEXT_TONES[barTone] ?? "text-primary"
|
|
515
|
+
: valueTone === "muted"
|
|
516
|
+
? "text-foreground"
|
|
517
|
+
: TEXT_TONES[valueTone] ?? "text-foreground";
|
|
518
|
+
const middle = center === undefined ? `${Math.round(pct)}%` : center;
|
|
519
|
+
// The target tick: a short radial line across the ring, at its angle.
|
|
520
|
+
const a = (targetPct / 100) * 2 * Math.PI - Math.PI / 2;
|
|
521
|
+
const tick = (d) => [c + Math.cos(a) * d, c + Math.sin(a) * d];
|
|
522
|
+
const [x1, y1] = tick(r - g.w / 2 - 1.5);
|
|
523
|
+
const [x2, y2] = tick(r + g.w / 2 + 1.5);
|
|
524
|
+
const side = label || shown || caption || (hasTarget && size !== "sm");
|
|
525
|
+
|
|
526
|
+
return (
|
|
527
|
+
<div className={cx("flex min-w-0 items-center", g.gap, className)}>
|
|
528
|
+
<div {...meterProps} className="relative shrink-0" style={{ width: g.px, height: g.px }} {...rest}>
|
|
529
|
+
<svg aria-hidden="true" width={g.px} height={g.px} viewBox={`0 0 ${g.px} ${g.px}`} className="block overflow-visible">
|
|
530
|
+
{/* raw: an SVG gauge — the kit has no smaller part to draw an arc. */}
|
|
531
|
+
<circle cx={c} cy={c} r={r} fill="none" strokeWidth={g.w} className="stroke-accent" />
|
|
532
|
+
{frac > 0 ? (
|
|
533
|
+
<circle
|
|
534
|
+
cx={c}
|
|
535
|
+
cy={c}
|
|
536
|
+
r={r}
|
|
537
|
+
fill="none"
|
|
538
|
+
strokeWidth={g.w}
|
|
539
|
+
strokeLinecap="round"
|
|
540
|
+
strokeDasharray={`${len * frac} ${len}`}
|
|
541
|
+
transform={`rotate(-90 ${c} ${c})`}
|
|
542
|
+
className={cx("transition-[stroke-dasharray] duration-300 ease-out motion-reduce:transition-none", stroke)}
|
|
543
|
+
/>
|
|
544
|
+
) : null}
|
|
545
|
+
{hasTarget && targetMark ? (
|
|
546
|
+
<line x1={x1} y1={y1} x2={x2} y2={y2} strokeWidth={2} strokeLinecap="round" className="stroke-foreground" />
|
|
547
|
+
) : null}
|
|
548
|
+
</svg>
|
|
549
|
+
{middle !== null && middle !== false ? (
|
|
550
|
+
<span aria-hidden="true" data-nums className={cx("absolute inset-0 flex items-center justify-center leading-none", g.text, middleClass)}>
|
|
551
|
+
{middle}
|
|
552
|
+
</span>
|
|
553
|
+
) : null}
|
|
554
|
+
</div>
|
|
555
|
+
{side ? (
|
|
556
|
+
<div className={cx("grid min-w-0 gap-0.5", g.side)}>
|
|
557
|
+
{label ? <span aria-hidden="true" className="min-w-0 truncate font-medium text-foreground">{label}</span> : null}
|
|
558
|
+
{shown ? (
|
|
559
|
+
<span data-nums aria-hidden="true" className={cx("text-xs", valueClass)}>
|
|
560
|
+
{shown}
|
|
561
|
+
</span>
|
|
562
|
+
) : null}
|
|
563
|
+
{caption || (hasTarget && size !== "sm") ? (
|
|
564
|
+
<span className="text-xs text-muted-foreground">
|
|
565
|
+
{caption}
|
|
566
|
+
{caption && hasTarget && size !== "sm" ? " · " : null}
|
|
567
|
+
{hasTarget && size !== "sm" ? <span aria-hidden="true" data-nums>{targetText}</span> : null}
|
|
568
|
+
</span>
|
|
569
|
+
) : null}
|
|
570
|
+
</div>
|
|
571
|
+
) : null}
|
|
572
|
+
</div>
|
|
573
|
+
);
|
|
574
|
+
}
|