makersclaw 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +180 -0
- package/package.json +3 -2
- package/r/annotate.json +62 -0
- package/r/approval-request.json +52 -0
- package/r/audio-player.json +74 -0
- package/r/auth-form.json +55 -0
- package/r/board.json +10 -6
- package/r/calendar-view.json +105 -0
- package/r/cart.json +62 -0
- package/r/chart.json +83 -0
- package/r/chat.json +95 -0
- package/r/code-editor.json +94 -0
- package/r/comment-box.json +64 -0
- package/r/contact-section.json +53 -0
- package/r/core.json +205 -8
- package/r/csv-import.json +63 -0
- package/r/data-table.json +69 -0
- package/r/diagram.json +74 -0
- package/r/doc-editor.json +82 -0
- package/r/doc-page.json +61 -0
- package/r/email-render.json +73 -0
- package/r/faq.json +50 -0
- package/r/file-upload.json +54 -0
- package/r/flow-canvas.json +93 -0
- package/r/footer.json +52 -0
- package/r/gantt.json +70 -0
- package/r/job-panel.json +12 -7
- package/r/json-editor.json +66 -0
- package/r/map.json +89 -0
- package/r/menubar.json +52 -0
- package/r/mind-map.json +67 -0
- package/r/navigation-menu.json +52 -0
- package/r/order-detail.json +54 -0
- package/r/org-chart.json +66 -0
- package/r/page-builder.json +105 -0
- package/r/payment-methods.json +51 -0
- package/r/pdf-document.json +79 -0
- package/r/pdf-viewer.json +88 -0
- package/r/product-detail.json +76 -0
- package/r/product-grid.json +65 -0
- package/r/record-form.json +67 -0
- package/r/record-notes.json +55 -0
- package/r/registry.json +3411 -29
- package/r/search-dialog.json +51 -0
- package/r/settings-list.json +66 -0
- package/r/setup-checklist.json +51 -0
- package/r/share-dialog.json +52 -0
- package/r/sidebar.json +69 -0
- package/r/signature-pad.json +72 -0
- package/r/sketch-canvas.json +99 -0
- package/r/spreadsheet.json +90 -0
- package/r/stat-cards.json +66 -0
- package/r/task-list.json +63 -0
- package/r/task-model.json +98 -0
- package/r/testimonials.json +52 -0
- package/r/transaction-list.json +53 -0
- package/r/whiteboard.json +66 -0
- package/registry/blocks/annotate/README.md +179 -0
- package/registry/blocks/annotate/annotate-data.js +250 -0
- package/registry/blocks/annotate/annotate.jsx +646 -0
- package/registry/blocks/annotate/block.json +10 -0
- package/registry/blocks/annotate/demo.jsx +135 -0
- package/registry/blocks/annotate/index.js +15 -0
- package/registry/blocks/approval-request/README.md +116 -0
- package/registry/blocks/approval-request/approval-request.jsx +386 -0
- package/registry/blocks/approval-request/block.json +10 -0
- package/registry/blocks/approval-request/demo.jsx +127 -0
- package/registry/blocks/approval-request/index.js +4 -0
- package/registry/blocks/audio-player/README.md +167 -0
- package/registry/blocks/audio-player/audio-player.jsx +623 -0
- package/registry/blocks/audio-player/block.json +14 -0
- package/registry/blocks/audio-player/colors.js +109 -0
- package/registry/blocks/audio-player/demo.jsx +209 -0
- package/registry/blocks/audio-player/index.js +6 -0
- package/registry/blocks/audio-player/time.js +67 -0
- package/registry/blocks/audio-player/wavesurfer.js +9 -0
- package/registry/blocks/auth-form/README.md +126 -0
- package/registry/blocks/auth-form/auth-form.jsx +568 -0
- package/registry/blocks/auth-form/block.json +10 -0
- package/registry/blocks/auth-form/demo.jsx +131 -0
- package/registry/blocks/auth-form/index.js +3 -0
- package/registry/blocks/board/README.md +55 -5
- package/registry/blocks/board/block.json +2 -2
- package/registry/blocks/board/board.jsx +230 -86
- package/registry/blocks/board/demo.jsx +103 -24
- package/registry/blocks/calendar-view/README.md +180 -0
- package/registry/blocks/calendar-view/agenda.jsx +147 -0
- package/registry/blocks/calendar-view/block.json +76 -0
- package/registry/blocks/calendar-view/calendar-model.js +442 -0
- package/registry/blocks/calendar-view/calendar.jsx +627 -0
- package/registry/blocks/calendar-view/demo.jsx +195 -0
- package/registry/blocks/calendar-view/draft.jsx +49 -0
- package/registry/blocks/calendar-view/index.js +39 -0
- package/registry/blocks/calendar-view/month.jsx +346 -0
- package/registry/blocks/calendar-view/paint.js +69 -0
- package/registry/blocks/calendar-view/time-grid.jsx +527 -0
- package/registry/blocks/calendar-view/tray.jsx +87 -0
- package/registry/blocks/cart/README.md +146 -0
- package/registry/blocks/cart/block.json +10 -0
- package/registry/blocks/cart/cart.jsx +597 -0
- package/registry/blocks/cart/demo.jsx +98 -0
- package/registry/blocks/cart/index.js +4 -0
- package/registry/blocks/cart/money.js +28 -0
- package/registry/blocks/chart/README.md +316 -0
- package/registry/blocks/chart/block.json +10 -0
- package/registry/blocks/chart/cartesian.jsx +642 -0
- package/registry/blocks/chart/core.jsx +262 -0
- package/registry/blocks/chart/demo.jsx +357 -0
- package/registry/blocks/chart/heatmap.jsx +336 -0
- package/registry/blocks/chart/index.js +8 -0
- package/registry/blocks/chart/pie.jsx +245 -0
- package/registry/blocks/chart/sparkline.jsx +88 -0
- package/registry/blocks/chat/README.md +273 -0
- package/registry/blocks/chat/attachment.jsx +95 -0
- package/registry/blocks/chat/block.json +10 -0
- package/registry/blocks/chat/chat.jsx +132 -0
- package/registry/blocks/chat/composer.jsx +364 -0
- package/registry/blocks/chat/demo.jsx +578 -0
- package/registry/blocks/chat/header.jsx +34 -0
- package/registry/blocks/chat/index.js +9 -0
- package/registry/blocks/chat/message.jsx +450 -0
- package/registry/blocks/chat/scroller.jsx +247 -0
- package/registry/blocks/chat/text.jsx +104 -0
- package/registry/blocks/code-editor/README.md +210 -0
- package/registry/blocks/code-editor/block.json +22 -0
- package/registry/blocks/code-editor/code-editor.jsx +534 -0
- package/registry/blocks/code-editor/codemirror.js +38 -0
- package/registry/blocks/code-editor/demo.jsx +205 -0
- package/registry/blocks/code-editor/index.js +8 -0
- package/registry/blocks/code-editor/json.js +317 -0
- package/registry/blocks/code-editor/sql.js +136 -0
- package/registry/blocks/code-editor/text.js +101 -0
- package/registry/blocks/code-editor/theme.js +186 -0
- package/registry/blocks/comment-box/README.md +123 -0
- package/registry/blocks/comment-box/block.json +10 -0
- package/registry/blocks/comment-box/comment-body.jsx +217 -0
- package/registry/blocks/comment-box/comment-box.jsx +198 -0
- package/registry/blocks/comment-box/comment-time.jsx +77 -0
- package/registry/blocks/comment-box/demo.jsx +141 -0
- package/registry/blocks/comment-box/index.js +8 -0
- package/registry/blocks/contact-section/README.md +152 -0
- package/registry/blocks/contact-section/block.json +11 -0
- package/registry/blocks/contact-section/contact-section.jsx +509 -0
- package/registry/blocks/contact-section/demo.jsx +93 -0
- package/registry/blocks/contact-section/index.js +4 -0
- package/registry/blocks/csv-import/README.md +133 -0
- package/registry/blocks/csv-import/block.json +13 -0
- package/registry/blocks/csv-import/csv-import.jsx +479 -0
- package/registry/blocks/csv-import/demo.jsx +106 -0
- package/registry/blocks/csv-import/import.js +200 -0
- package/registry/blocks/csv-import/index.js +7 -0
- package/registry/blocks/data-table/README.md +386 -0
- package/registry/blocks/data-table/block.json +10 -0
- package/registry/blocks/data-table/data-table.jsx +1164 -0
- package/registry/blocks/data-table/demo.jsx +588 -0
- package/registry/blocks/data-table/index.js +5 -0
- package/registry/blocks/data-table/model.js +169 -0
- package/registry/blocks/diagram/README.md +108 -0
- package/registry/blocks/diagram/block.json +13 -0
- package/registry/blocks/diagram/demo.jsx +113 -0
- package/registry/blocks/diagram/diagram.jsx +481 -0
- package/registry/blocks/diagram/index.js +7 -0
- package/registry/blocks/diagram/mermaid.js +52 -0
- package/registry/blocks/diagram/palette.js +313 -0
- package/registry/blocks/diagram/source.js +98 -0
- package/registry/blocks/doc-editor/README.md +215 -0
- package/registry/blocks/doc-editor/block.json +15 -0
- package/registry/blocks/doc-editor/demo.jsx +225 -0
- package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
- package/registry/blocks/doc-editor/doc.js +309 -0
- package/registry/blocks/doc-editor/index.js +7 -0
- package/registry/blocks/doc-editor/schema.jsx +56 -0
- package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
- package/registry/blocks/doc-editor/theme.js +82 -0
- package/registry/blocks/doc-page/README.md +119 -0
- package/registry/blocks/doc-page/autosave.js +104 -0
- package/registry/blocks/doc-page/block.json +10 -0
- package/registry/blocks/doc-page/demo.jsx +137 -0
- package/registry/blocks/doc-page/doc-page.jsx +276 -0
- package/registry/blocks/doc-page/index.js +4 -0
- package/registry/blocks/email-render/README.md +151 -0
- package/registry/blocks/email-render/block.json +14 -0
- package/registry/blocks/email-render/demo.jsx +153 -0
- package/registry/blocks/email-render/doc-email.jsx +210 -0
- package/registry/blocks/email-render/email.jsx +221 -0
- package/registry/blocks/email-render/index.js +10 -0
- package/registry/blocks/email-render/render.js +50 -0
- package/registry/blocks/email-render/theme.js +215 -0
- package/registry/blocks/faq/README.md +101 -0
- package/registry/blocks/faq/block.json +11 -0
- package/registry/blocks/faq/demo.jsx +89 -0
- package/registry/blocks/faq/faq.jsx +220 -0
- package/registry/blocks/faq/index.js +4 -0
- package/registry/blocks/file-upload/README.md +138 -0
- package/registry/blocks/file-upload/block.json +10 -0
- package/registry/blocks/file-upload/demo.jsx +204 -0
- package/registry/blocks/file-upload/file-upload.jsx +635 -0
- package/registry/blocks/file-upload/index.js +4 -0
- package/registry/blocks/flow-canvas/README.md +420 -0
- package/registry/blocks/flow-canvas/block.json +13 -0
- package/registry/blocks/flow-canvas/board.js +819 -0
- package/registry/blocks/flow-canvas/chrome.jsx +649 -0
- package/registry/blocks/flow-canvas/context.jsx +35 -0
- package/registry/blocks/flow-canvas/demo.jsx +249 -0
- package/registry/blocks/flow-canvas/edges.jsx +107 -0
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
- package/registry/blocks/flow-canvas/index.js +41 -0
- package/registry/blocks/flow-canvas/nodes.jsx +392 -0
- package/registry/blocks/flow-canvas/theme.js +174 -0
- package/registry/blocks/footer/README.md +133 -0
- package/registry/blocks/footer/block.json +11 -0
- package/registry/blocks/footer/demo.jsx +119 -0
- package/registry/blocks/footer/footer.jsx +406 -0
- package/registry/blocks/footer/index.js +4 -0
- package/registry/blocks/gantt/README.md +220 -0
- package/registry/blocks/gantt/block.json +10 -0
- package/registry/blocks/gantt/demo.jsx +148 -0
- package/registry/blocks/gantt/gantt.jsx +923 -0
- package/registry/blocks/gantt/index.js +7 -0
- package/registry/blocks/gantt/rows.jsx +468 -0
- package/registry/blocks/gantt/schedule.js +278 -0
- package/registry/blocks/job-panel/README.md +80 -0
- package/registry/blocks/job-panel/block.json +3 -3
- package/registry/blocks/job-panel/demo.jsx +230 -3
- package/registry/blocks/job-panel/job-panel.jsx +169 -3
- package/registry/blocks/json-editor/README.md +133 -0
- package/registry/blocks/json-editor/block.json +10 -0
- package/registry/blocks/json-editor/demo.jsx +92 -0
- package/registry/blocks/json-editor/index.js +7 -0
- package/registry/blocks/json-editor/json-editor.jsx +305 -0
- package/registry/blocks/json-editor/json-tree.jsx +393 -0
- package/registry/blocks/json-editor/tree.js +225 -0
- package/registry/blocks/map/README.md +221 -0
- package/registry/blocks/map/block.json +14 -0
- package/registry/blocks/map/demo.jsx +201 -0
- package/registry/blocks/map/geo.js +198 -0
- package/registry/blocks/map/index.js +8 -0
- package/registry/blocks/map/list.jsx +128 -0
- package/registry/blocks/map/map-view.jsx +715 -0
- package/registry/blocks/map/maplibre.js +30 -0
- package/registry/blocks/map/marks.jsx +146 -0
- package/registry/blocks/map/theme.js +142 -0
- package/registry/blocks/menubar/README.md +109 -0
- package/registry/blocks/menubar/block.json +10 -0
- package/registry/blocks/menubar/demo.jsx +128 -0
- package/registry/blocks/menubar/index.js +4 -0
- package/registry/blocks/menubar/menubar.jsx +199 -0
- package/registry/blocks/mind-map/README.md +206 -0
- package/registry/blocks/mind-map/block.json +10 -0
- package/registry/blocks/mind-map/demo.jsx +103 -0
- package/registry/blocks/mind-map/index.js +31 -0
- package/registry/blocks/mind-map/mind-map.jsx +1125 -0
- package/registry/blocks/mind-map/topic.jsx +143 -0
- package/registry/blocks/mind-map/tree.js +645 -0
- package/registry/blocks/navigation-menu/README.md +124 -0
- package/registry/blocks/navigation-menu/block.json +10 -0
- package/registry/blocks/navigation-menu/demo.jsx +84 -0
- package/registry/blocks/navigation-menu/index.js +4 -0
- package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
- package/registry/blocks/order-detail/README.md +109 -0
- package/registry/blocks/order-detail/block.json +10 -0
- package/registry/blocks/order-detail/demo.jsx +88 -0
- package/registry/blocks/order-detail/index.js +4 -0
- package/registry/blocks/order-detail/order-detail.jsx +354 -0
- package/registry/blocks/org-chart/README.md +145 -0
- package/registry/blocks/org-chart/block.json +10 -0
- package/registry/blocks/org-chart/demo.jsx +94 -0
- package/registry/blocks/org-chart/index.js +7 -0
- package/registry/blocks/org-chart/org-chart.jsx +631 -0
- package/registry/blocks/org-chart/org.js +245 -0
- package/registry/blocks/org-chart/person.jsx +96 -0
- package/registry/blocks/page-builder/README.md +257 -0
- package/registry/blocks/page-builder/block.json +14 -0
- package/registry/blocks/page-builder/demo.jsx +145 -0
- package/registry/blocks/page-builder/grapes.js +18 -0
- package/registry/blocks/page-builder/index.js +11 -0
- package/registry/blocks/page-builder/page-builder.jsx +704 -0
- package/registry/blocks/page-builder/page-view.jsx +33 -0
- package/registry/blocks/page-builder/page.js +118 -0
- package/registry/blocks/page-builder/panels.jsx +588 -0
- package/registry/blocks/page-builder/sections.js +209 -0
- package/registry/blocks/page-builder/theme.js +87 -0
- package/registry/blocks/page-builder/thumbs.jsx +189 -0
- package/registry/blocks/page-builder/tokens.js +329 -0
- package/registry/blocks/payment-methods/README.md +104 -0
- package/registry/blocks/payment-methods/block.json +10 -0
- package/registry/blocks/payment-methods/demo.jsx +71 -0
- package/registry/blocks/payment-methods/index.js +4 -0
- package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
- package/registry/blocks/pdf-document/README.md +213 -0
- package/registry/blocks/pdf-document/block.json +13 -0
- package/registry/blocks/pdf-document/demo.jsx +136 -0
- package/registry/blocks/pdf-document/index.js +33 -0
- package/registry/blocks/pdf-document/money.js +83 -0
- package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
- package/registry/blocks/pdf-document/primitives.jsx +271 -0
- package/registry/blocks/pdf-document/quote.jsx +179 -0
- package/registry/blocks/pdf-document/theme.js +193 -0
- package/registry/blocks/pdf-viewer/README.md +191 -0
- package/registry/blocks/pdf-viewer/block.json +14 -0
- package/registry/blocks/pdf-viewer/demo.jsx +252 -0
- package/registry/blocks/pdf-viewer/helpers.js +270 -0
- package/registry/blocks/pdf-viewer/index.js +8 -0
- package/registry/blocks/pdf-viewer/notes.jsx +195 -0
- package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
- package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
- package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
- package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
- package/registry/blocks/product-detail/README.md +217 -0
- package/registry/blocks/product-detail/block.json +10 -0
- package/registry/blocks/product-detail/demo.jsx +233 -0
- package/registry/blocks/product-detail/index.js +7 -0
- package/registry/blocks/product-detail/price.jsx +115 -0
- package/registry/blocks/product-detail/product-detail.jsx +348 -0
- package/registry/blocks/product-detail/product-media.jsx +102 -0
- package/registry/blocks/product-detail/product-options.jsx +144 -0
- package/registry/blocks/product-grid/README.md +162 -0
- package/registry/blocks/product-grid/block.json +10 -0
- package/registry/blocks/product-grid/demo.jsx +255 -0
- package/registry/blocks/product-grid/index.js +5 -0
- package/registry/blocks/product-grid/product-card.jsx +232 -0
- package/registry/blocks/product-grid/product-grid.jsx +235 -0
- package/registry/blocks/record-form/README.md +196 -0
- package/registry/blocks/record-form/block.json +10 -0
- package/registry/blocks/record-form/demo.jsx +525 -0
- package/registry/blocks/record-form/index.js +4 -0
- package/registry/blocks/record-form/record-fields.jsx +457 -0
- package/registry/blocks/record-form/record-form.jsx +415 -0
- package/registry/blocks/record-form/rules.js +81 -0
- package/registry/blocks/record-notes/README.md +139 -0
- package/registry/blocks/record-notes/block.json +10 -0
- package/registry/blocks/record-notes/demo.jsx +179 -0
- package/registry/blocks/record-notes/index.js +4 -0
- package/registry/blocks/record-notes/record-notes.jsx +266 -0
- package/registry/blocks/search-dialog/README.md +108 -0
- package/registry/blocks/search-dialog/block.json +10 -0
- package/registry/blocks/search-dialog/demo.jsx +116 -0
- package/registry/blocks/search-dialog/index.js +3 -0
- package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
- package/registry/blocks/settings-list/README.md +171 -0
- package/registry/blocks/settings-list/block.json +10 -0
- package/registry/blocks/settings-list/demo.jsx +333 -0
- package/registry/blocks/settings-list/index.js +4 -0
- package/registry/blocks/settings-list/row-state.jsx +93 -0
- package/registry/blocks/settings-list/settings-list.jsx +349 -0
- package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
- package/registry/blocks/setup-checklist/README.md +142 -0
- package/registry/blocks/setup-checklist/block.json +10 -0
- package/registry/blocks/setup-checklist/demo.jsx +159 -0
- package/registry/blocks/setup-checklist/index.js +4 -0
- package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
- package/registry/blocks/share-dialog/README.md +113 -0
- package/registry/blocks/share-dialog/block.json +10 -0
- package/registry/blocks/share-dialog/demo.jsx +140 -0
- package/registry/blocks/share-dialog/index.js +3 -0
- package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
- package/registry/blocks/sidebar/README.md +190 -0
- package/registry/blocks/sidebar/block.json +43 -0
- package/registry/blocks/sidebar/demo.jsx +577 -0
- package/registry/blocks/sidebar/index.js +4 -0
- package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
- package/registry/blocks/sidebar/sidebar.jsx +864 -0
- package/registry/blocks/signature-pad/README.md +137 -0
- package/registry/blocks/signature-pad/block.json +13 -0
- package/registry/blocks/signature-pad/colors.js +115 -0
- package/registry/blocks/signature-pad/demo.jsx +94 -0
- package/registry/blocks/signature-pad/index.js +6 -0
- package/registry/blocks/signature-pad/pad.js +7 -0
- package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
- package/registry/blocks/signature-pad/signature.js +68 -0
- package/registry/blocks/sketch-canvas/README.md +280 -0
- package/registry/blocks/sketch-canvas/block.json +13 -0
- package/registry/blocks/sketch-canvas/demo.jsx +159 -0
- package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
- package/registry/blocks/sketch-canvas/index.js +9 -0
- package/registry/blocks/sketch-canvas/palette.js +226 -0
- package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
- package/registry/blocks/sketch-canvas/sketch.js +179 -0
- package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
- package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
- package/registry/blocks/sketch-canvas/stamps.js +104 -0
- package/registry/blocks/sketch-canvas/theme.js +131 -0
- package/registry/blocks/spreadsheet/README.md +307 -0
- package/registry/blocks/spreadsheet/block.json +13 -0
- package/registry/blocks/spreadsheet/cells.jsx +455 -0
- package/registry/blocks/spreadsheet/chrome.jsx +325 -0
- package/registry/blocks/spreadsheet/demo.jsx +177 -0
- package/registry/blocks/spreadsheet/grid.js +387 -0
- package/registry/blocks/spreadsheet/index.js +34 -0
- package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
- package/registry/blocks/spreadsheet/types.js +473 -0
- package/registry/blocks/stat-cards/README.md +173 -0
- package/registry/blocks/stat-cards/block.json +10 -0
- package/registry/blocks/stat-cards/demo.jsx +257 -0
- package/registry/blocks/stat-cards/index.js +4 -0
- package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
- package/registry/blocks/stat-cards/usage.jsx +243 -0
- package/registry/blocks/task-list/README.md +176 -0
- package/registry/blocks/task-list/block.json +10 -0
- package/registry/blocks/task-list/demo.jsx +134 -0
- package/registry/blocks/task-list/index.js +5 -0
- package/registry/blocks/task-list/task-list.jsx +907 -0
- package/registry/blocks/task-model/README.md +455 -0
- package/registry/blocks/task-model/block.json +167 -0
- package/registry/blocks/task-model/changes.js +89 -0
- package/registry/blocks/task-model/dates.js +371 -0
- package/registry/blocks/task-model/demo.jsx +215 -0
- package/registry/blocks/task-model/dnd.jsx +240 -0
- package/registry/blocks/task-model/index.js +97 -0
- package/registry/blocks/task-model/model.js +919 -0
- package/registry/blocks/task-model/parts.jsx +449 -0
- package/registry/blocks/task-model/toolbar.jsx +271 -0
- package/registry/blocks/testimonials/README.md +139 -0
- package/registry/blocks/testimonials/block.json +11 -0
- package/registry/blocks/testimonials/demo.jsx +137 -0
- package/registry/blocks/testimonials/index.js +4 -0
- package/registry/blocks/testimonials/testimonials.jsx +430 -0
- package/registry/blocks/transaction-list/README.md +126 -0
- package/registry/blocks/transaction-list/block.json +10 -0
- package/registry/blocks/transaction-list/demo.jsx +79 -0
- package/registry/blocks/transaction-list/index.js +4 -0
- package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
- package/registry/blocks/whiteboard/README.md +179 -0
- package/registry/blocks/whiteboard/block.json +10 -0
- package/registry/blocks/whiteboard/demo.jsx +169 -0
- package/registry/blocks/whiteboard/index.js +6 -0
- package/registry/blocks/whiteboard/templates.js +150 -0
- package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
- package/src/cli.mjs +19 -6
- package/src/install.mjs +18 -0
- package/src/registry.mjs +38 -4
- package/src/shadcn.mjs +14 -1
- package/templates/next/files/README.md +145 -11
- package/templates/next/files/app/globals.css +55 -4
- package/templates/next/files/check/run.mjs +3 -3
- package/templates/next/files/components/ui/avatar.jsx +141 -0
- package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
- package/templates/next/files/components/ui/button-group.jsx +70 -0
- package/templates/next/files/components/ui/button.jsx +132 -12
- package/templates/next/files/components/ui/calendar.jsx +609 -0
- package/templates/next/files/components/ui/carousel.jsx +281 -0
- package/templates/next/files/components/ui/collapsible.jsx +208 -0
- package/templates/next/files/components/ui/combobox.jsx +608 -0
- package/templates/next/files/components/ui/command.jsx +577 -0
- package/templates/next/files/components/ui/context-menu.jsx +191 -0
- package/templates/next/files/components/ui/date-picker.jsx +360 -0
- package/templates/next/files/components/ui/distribution.jsx +117 -0
- package/templates/next/files/components/ui/feedback.jsx +143 -0
- package/templates/next/files/components/ui/field.jsx +115 -3
- package/templates/next/files/components/ui/file-input.jsx +234 -0
- package/templates/next/files/components/ui/icon.jsx +130 -8
- package/templates/next/files/components/ui/image.jsx +143 -0
- package/templates/next/files/components/ui/index.js +47 -2
- package/templates/next/files/components/ui/input-group.jsx +213 -0
- package/templates/next/files/components/ui/input-otp.jsx +170 -0
- package/templates/next/files/components/ui/item.jsx +206 -0
- package/templates/next/files/components/ui/menu.jsx +454 -82
- package/templates/next/files/components/ui/notice.jsx +126 -14
- package/templates/next/files/components/ui/pagination.jsx +156 -0
- package/templates/next/files/components/ui/popover.jsx +284 -0
- package/templates/next/files/components/ui/radio.jsx +193 -0
- package/templates/next/files/components/ui/rating.jsx +131 -0
- package/templates/next/files/components/ui/resizable.jsx +338 -0
- package/templates/next/files/components/ui/scroll-area.jsx +123 -0
- package/templates/next/files/components/ui/separator.jsx +119 -0
- package/templates/next/files/components/ui/sheet.jsx +96 -11
- package/templates/next/files/components/ui/slider.jsx +174 -0
- package/templates/next/files/components/ui/stat.jsx +574 -0
- package/templates/next/files/components/ui/steps.jsx +338 -0
- package/templates/next/files/components/ui/swatch.jsx +33 -0
- package/templates/next/files/components/ui/table.jsx +130 -0
- package/templates/next/files/components/ui/toast.jsx +440 -0
- package/templates/next/files/components/ui/toggle.jsx +195 -0
- package/templates/next/files/components/ui/tooltip.jsx +270 -0
- package/templates/next/template.json +264 -8
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef } from "react";
|
|
4
|
+
import { cx } from "./cx";
|
|
5
|
+
import { MenuPanel } from "./menu";
|
|
6
|
+
import { panelClass, usePopoverPosition } from "./popover";
|
|
7
|
+
|
|
8
|
+
// ContextMenu — the menu a right-click opens on a region: a row, a card,
|
|
9
|
+
// a canvas. The same `items` as Menu (actions, groups, checkboxes,
|
|
10
|
+
// radios, shortcuts, submenus) and the same keys, opened at the pointer
|
|
11
|
+
// and flipped to stay on screen. It opens on:
|
|
12
|
+
//
|
|
13
|
+
// a right-click (or Ctrl-click on a Mac) at the pointer
|
|
14
|
+
// a long press on touch under the finger
|
|
15
|
+
// Shift+F10 or the Menu key on a focused thing under that thing
|
|
16
|
+
//
|
|
17
|
+
// <ContextMenu label="Actions for Acme" items={[{ label: "Edit", onSelect }]}>
|
|
18
|
+
// <Row … />
|
|
19
|
+
// </ContextMenu>
|
|
20
|
+
//
|
|
21
|
+
// items as Menu's (./menu); none (or []) leaves the browser's own
|
|
22
|
+
// right-click menu alone
|
|
23
|
+
// label what a reader calls the menu (default "Actions")
|
|
24
|
+
// disabled true: the region behaves as if there were no menu
|
|
25
|
+
// className the region's (a <div> around children)
|
|
26
|
+
//
|
|
27
|
+
// The one rule: a context menu is a shortcut, never the only door. Every
|
|
28
|
+
// action in it is also somewhere a tap or a Tab can reach — a Menu on the
|
|
29
|
+
// row, a button in its page — because nobody discovers a right-click.
|
|
30
|
+
// Focus goes to the first item when it opens and back to what had it
|
|
31
|
+
// when it closes.
|
|
32
|
+
//
|
|
33
|
+
// The panel is a manual popover with its own light dismiss: an auto one
|
|
34
|
+
// would be closed by the very release of the button (or the finger) that
|
|
35
|
+
// opened it, since a right-click opens on press on a Mac.
|
|
36
|
+
|
|
37
|
+
const LONG_PRESS = 550; // ms; just past the OS's own, which wins where it fires
|
|
38
|
+
|
|
39
|
+
// A Menu open inside the region (a row's ⋯) keeps its own keys and clicks.
|
|
40
|
+
const inMenu = (e) => Boolean(e.target.closest?.('[role="menu"]'));
|
|
41
|
+
|
|
42
|
+
export function ContextMenu({ items, label = "Actions", disabled = false, className, children }) {
|
|
43
|
+
const pop = useRef(null);
|
|
44
|
+
const point = useRef(null);
|
|
45
|
+
const back = useRef(null);
|
|
46
|
+
const press = useRef({ timer: 0, x: 0, y: 0, at: 0 });
|
|
47
|
+
const opened = useRef(0);
|
|
48
|
+
const unwatch = useRef(null);
|
|
49
|
+
usePopoverPosition(point, pop, { side: "bottom", align: "start", offset: 2 });
|
|
50
|
+
const live = (items ?? []).filter(Boolean);
|
|
51
|
+
useEffect(() => () => unwatch.current?.(), []);
|
|
52
|
+
|
|
53
|
+
if (live.length === 0 || disabled) return <div className={className}>{children}</div>;
|
|
54
|
+
|
|
55
|
+
function hide() {
|
|
56
|
+
if (pop.current?.matches(":popover-open")) pop.current.hidePopover();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Light dismiss: a press anywhere outside the panel (and its submenus,
|
|
60
|
+
// which sit inside it) closes it; so does Escape wherever focus is.
|
|
61
|
+
function watch() {
|
|
62
|
+
if (unwatch.current) return;
|
|
63
|
+
const down = (e) => {
|
|
64
|
+
if (!pop.current?.contains(e.target)) hide();
|
|
65
|
+
};
|
|
66
|
+
const key = (e) => {
|
|
67
|
+
if (e.key === "Escape" && !pop.current?.contains(e.target)) {
|
|
68
|
+
hide();
|
|
69
|
+
restore();
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
document.addEventListener("pointerdown", down, true);
|
|
73
|
+
document.addEventListener("keydown", key);
|
|
74
|
+
window.addEventListener("blur", hide);
|
|
75
|
+
unwatch.current = () => {
|
|
76
|
+
document.removeEventListener("pointerdown", down, true);
|
|
77
|
+
document.removeEventListener("keydown", key);
|
|
78
|
+
window.removeEventListener("blur", hide);
|
|
79
|
+
unwatch.current = null;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// `other` marks an open by a long press or a key, after which the
|
|
84
|
+
// browser's own contextmenu event (Android, Windows) is a duplicate.
|
|
85
|
+
function openAt(x, y, other = false) {
|
|
86
|
+
const p = pop.current;
|
|
87
|
+
const s = point.current;
|
|
88
|
+
if (!p || !s) return;
|
|
89
|
+
// The point is a fixed, empty box the panel is anchored to. Set it, then
|
|
90
|
+
// correct for a transformed ancestor that moves what "fixed" means;
|
|
91
|
+
// its width flips 0/1px so a measured placement sees a change.
|
|
92
|
+
s.style.left = `${x}px`;
|
|
93
|
+
s.style.top = `${y}px`;
|
|
94
|
+
const r = s.getBoundingClientRect();
|
|
95
|
+
s.style.left = `${2 * x - r.left}px`;
|
|
96
|
+
s.style.top = `${2 * y - r.top}px`;
|
|
97
|
+
s.style.width = s.style.width === "1px" ? "0px" : "1px";
|
|
98
|
+
if (!p.matches(":popover-open")) {
|
|
99
|
+
if (!back.current || !back.current.isConnected || p.contains(back.current)) back.current = document.activeElement;
|
|
100
|
+
} else p.hidePopover();
|
|
101
|
+
p.showPopover();
|
|
102
|
+
watch();
|
|
103
|
+
if (other) opened.current = Date.now();
|
|
104
|
+
p.querySelector('[role^="menuitem"]:not([disabled])')?.focus({ preventScroll: true });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function restore() {
|
|
108
|
+
const to = back.current;
|
|
109
|
+
back.current = null;
|
|
110
|
+
if (to && to !== document.body && to.isConnected) to.focus({ preventScroll: true });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function cancelPress() {
|
|
114
|
+
clearTimeout(press.current.timer);
|
|
115
|
+
press.current.timer = 0;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return (
|
|
119
|
+
<>
|
|
120
|
+
<div
|
|
121
|
+
className={cx("[-webkit-touch-callout:none]", className)}
|
|
122
|
+
onContextMenu={(e) => {
|
|
123
|
+
if (inMenu(e)) return;
|
|
124
|
+
e.preventDefault();
|
|
125
|
+
cancelPress();
|
|
126
|
+
// A long press or Shift+F10 opened it just now.
|
|
127
|
+
if (Date.now() - opened.current < 800) return;
|
|
128
|
+
openAt(e.clientX, e.clientY);
|
|
129
|
+
}}
|
|
130
|
+
onKeyDown={(e) => {
|
|
131
|
+
if ((e.key !== "ContextMenu" && !(e.shiftKey && e.key === "F10")) || inMenu(e)) return;
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
const r = e.target.getBoundingClientRect();
|
|
134
|
+
openAt(r.left + Math.min(16, r.width / 2), r.bottom, true);
|
|
135
|
+
}}
|
|
136
|
+
onPointerDown={(e) => {
|
|
137
|
+
if (e.pointerType === "mouse" || inMenu(e)) return;
|
|
138
|
+
cancelPress();
|
|
139
|
+
const { clientX: x, clientY: y } = e;
|
|
140
|
+
press.current = {
|
|
141
|
+
x,
|
|
142
|
+
y,
|
|
143
|
+
at: 0,
|
|
144
|
+
timer: setTimeout(() => {
|
|
145
|
+
press.current.timer = 0;
|
|
146
|
+
press.current.at = Date.now();
|
|
147
|
+
openAt(x, y, true);
|
|
148
|
+
}, LONG_PRESS),
|
|
149
|
+
};
|
|
150
|
+
}}
|
|
151
|
+
onPointerMove={(e) => {
|
|
152
|
+
const p = press.current;
|
|
153
|
+
if (p.timer && Math.hypot(e.clientX - p.x, e.clientY - p.y) > 10) cancelPress();
|
|
154
|
+
}}
|
|
155
|
+
onPointerUp={cancelPress}
|
|
156
|
+
onPointerCancel={cancelPress}
|
|
157
|
+
onClickCapture={(e) => {
|
|
158
|
+
// The finger lifting after a long press is not a tap on what is under it.
|
|
159
|
+
if (Date.now() - press.current.at < 800) {
|
|
160
|
+
e.preventDefault();
|
|
161
|
+
e.stopPropagation();
|
|
162
|
+
}
|
|
163
|
+
}}
|
|
164
|
+
>
|
|
165
|
+
<span ref={point} aria-hidden="true" className="pointer-events-none fixed top-0 left-0 h-0 w-0" />
|
|
166
|
+
{children}
|
|
167
|
+
</div>
|
|
168
|
+
<MenuPanel
|
|
169
|
+
items={live}
|
|
170
|
+
label={label}
|
|
171
|
+
panelRef={pop}
|
|
172
|
+
popover="manual"
|
|
173
|
+
onToggle={(e) => {
|
|
174
|
+
// A submenu's toggle bubbles here; a close already followed by an
|
|
175
|
+
// open (a right-click elsewhere) is not a close.
|
|
176
|
+
if (e.target !== e.currentTarget || e.newState !== "closed" || pop.current?.matches(":popover-open")) return;
|
|
177
|
+
unwatch.current?.();
|
|
178
|
+
const a = document.activeElement;
|
|
179
|
+
if (!a || a === document.body || pop.current?.contains(a)) restore();
|
|
180
|
+
else back.current = null;
|
|
181
|
+
}}
|
|
182
|
+
onExit={() => {
|
|
183
|
+
hide();
|
|
184
|
+
restore();
|
|
185
|
+
}}
|
|
186
|
+
onClose={hide}
|
|
187
|
+
className={panelClass("auto", "min-w-44 max-h-[calc(100vh-1rem)] overflow-y-auto p-1")}
|
|
188
|
+
/>
|
|
189
|
+
</>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useState, useSyncExternalStore } from "react";
|
|
4
|
+
import { cx } from "./cx";
|
|
5
|
+
import { Icon } from "./icon";
|
|
6
|
+
import { Button, IconButton } from "./button";
|
|
7
|
+
import { Input } from "./field";
|
|
8
|
+
import { Popover } from "./popover";
|
|
9
|
+
import {
|
|
10
|
+
Calendar,
|
|
11
|
+
addDays,
|
|
12
|
+
addMonths,
|
|
13
|
+
endOfMonth,
|
|
14
|
+
formatDate,
|
|
15
|
+
parseDate,
|
|
16
|
+
plainSpaces,
|
|
17
|
+
startOfMonth,
|
|
18
|
+
useLocale,
|
|
19
|
+
useToday,
|
|
20
|
+
} from "./calendar";
|
|
21
|
+
|
|
22
|
+
// DatePicker — a field that reads like an input and opens a Calendar in a
|
|
23
|
+
// Popover: a due date, a report's span. The trigger shows the day in the
|
|
24
|
+
// reader's words ("Mar 12, 2026"); the value stays a "YYYY-MM-DD" string
|
|
25
|
+
// (calendar.jsx says why). Put it in <Field id> with the same `id`: the
|
|
26
|
+
// label points at the trigger.
|
|
27
|
+
//
|
|
28
|
+
// mode single (value "2026-03-12" | null) · range (value
|
|
29
|
+
// { from, to } | null)
|
|
30
|
+
// value, onChange(value) — controlled; or `defaultValue`
|
|
31
|
+
// placeholder "Pick a date" · "Pick a range"
|
|
32
|
+
// presets true (the defaults for the mode: Today, Tomorrow, In a
|
|
33
|
+
// week… · Today, Last 7 days, This month…) or your own
|
|
34
|
+
// [{ label, value }] — `value` a date, a { from, to }, or
|
|
35
|
+
// (today) → one. A list beside the calendar; a row above
|
|
36
|
+
// it on a phone
|
|
37
|
+
// clearable an × in the field once it holds a date (true)
|
|
38
|
+
// format Intl.DateTimeFormat options for the field ({ dateStyle:
|
|
39
|
+
// "medium" }); a range is written with formatRange
|
|
40
|
+
// disabled true: the whole field; a function (date) → true: those days
|
|
41
|
+
// min, max, numberOfMonths (range: 2 from 640px; always 1 on a phone),
|
|
42
|
+
// captionLayout, showWeekNumbers, weekStartsOn, locale, today — as
|
|
43
|
+
// Calendar
|
|
44
|
+
// name a hidden input for a form; a range submits two under it
|
|
45
|
+
// invalid the red edge — pair it with <Field error>
|
|
46
|
+
// size md (44px) · sm (36px)
|
|
47
|
+
// label what a screen reader calls the panel ("Choose a date")
|
|
48
|
+
// defaultOpen open on first render (a demo; a form never needs it)
|
|
49
|
+
//
|
|
50
|
+
// It closes when a day, a finished range or a preset is picked; the focus
|
|
51
|
+
// lands on the chosen day when it opens and back on the field when it
|
|
52
|
+
// closes.
|
|
53
|
+
//
|
|
54
|
+
// DateInput below is the typed way in: the browser's own date field
|
|
55
|
+
// (segments in the reader's order, digits only, never a free-text parse)
|
|
56
|
+
// with this Calendar one button away. Typing a date into a text box and
|
|
57
|
+
// parsing it is not robust across locales ("03/04" is two different
|
|
58
|
+
// days), which is why there is no text DateInput.
|
|
59
|
+
|
|
60
|
+
const FIELD =
|
|
61
|
+
"flex w-full items-center gap-2 rounded-md border border-input bg-background px-3 text-left text-sm text-foreground " +
|
|
62
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 " +
|
|
63
|
+
"aria-[invalid=true]:border-destructive";
|
|
64
|
+
const HEIGHT = { md: "min-h-11", sm: "min-h-9" };
|
|
65
|
+
// Presets: on a phone a scrolling row exactly as wide as the calendar (w-0
|
|
66
|
+
// plus a min width of its box: it never widens the panel); a column beside
|
|
67
|
+
// the calendar from 640px.
|
|
68
|
+
const PRESETS =
|
|
69
|
+
"-mx-3 flex w-0 min-w-[calc(100%+1.5rem)] gap-1 overflow-x-auto px-3 pb-1 " +
|
|
70
|
+
"sm:m-0 sm:w-36 sm:min-w-0 sm:flex-col sm:overflow-visible sm:border-r sm:border-border sm:p-0 sm:pr-3";
|
|
71
|
+
|
|
72
|
+
function useWide() {
|
|
73
|
+
return useSyncExternalStore(
|
|
74
|
+
(cb) => {
|
|
75
|
+
const q = window.matchMedia("(min-width: 640px)");
|
|
76
|
+
q.addEventListener("change", cb);
|
|
77
|
+
return () => q.removeEventListener("change", cb);
|
|
78
|
+
},
|
|
79
|
+
() => window.matchMedia("(min-width: 640px)").matches,
|
|
80
|
+
() => false,
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** The default presets. Each value is (today) → a date or a { from, to }. */
|
|
85
|
+
export const DATE_PRESETS = {
|
|
86
|
+
single: [
|
|
87
|
+
{ label: "Today", value: (t) => t },
|
|
88
|
+
{ label: "Tomorrow", value: (t) => addDays(t, 1) },
|
|
89
|
+
{ label: "In a week", value: (t) => addDays(t, 7) },
|
|
90
|
+
{ label: "In a month", value: (t) => addMonths(t, 1) },
|
|
91
|
+
],
|
|
92
|
+
range: [
|
|
93
|
+
{ label: "Today", value: (t) => ({ from: t, to: t }) },
|
|
94
|
+
{ label: "Last 7 days", value: (t) => ({ from: addDays(t, -6), to: t }) },
|
|
95
|
+
{ label: "Last 30 days", value: (t) => ({ from: addDays(t, -29), to: t }) },
|
|
96
|
+
{ label: "This month", value: (t) => ({ from: startOfMonth(t), to: endOfMonth(t) }) },
|
|
97
|
+
{ label: "Last month", value: (t) => ({ from: startOfMonth(addMonths(t, -1)), to: endOfMonth(addMonths(t, -1)) }) },
|
|
98
|
+
{ label: "This year", value: (t) => ({ from: `${t.slice(0, 4)}-01-01`, to: `${t.slice(0, 4)}-12-31` }) },
|
|
99
|
+
],
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const same = (a, b) => (a && b && typeof a === "object" ? a.from === b.from && a.to === b.to : a === b);
|
|
103
|
+
|
|
104
|
+
/** The value in words: a day, or a span through formatRange. */
|
|
105
|
+
function words(mode, value, format, locale) {
|
|
106
|
+
if (mode !== "range") return value ? formatDate(value, format, locale) : "";
|
|
107
|
+
const { from, to } = value ?? {};
|
|
108
|
+
if (!from) return "";
|
|
109
|
+
if (!to) return `${formatDate(from, format, locale)} – …`;
|
|
110
|
+
const f = new Intl.DateTimeFormat(locale, { ...format, timeZone: "UTC" });
|
|
111
|
+
return plainSpaces(f.formatRange ? f.formatRange(parseDate(from), parseDate(to)) : `${f.format(parseDate(from))} – ${f.format(parseDate(to))}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function DatePicker({
|
|
115
|
+
id,
|
|
116
|
+
mode = "single",
|
|
117
|
+
value: valueProp,
|
|
118
|
+
defaultValue = null,
|
|
119
|
+
onChange,
|
|
120
|
+
placeholder,
|
|
121
|
+
presets = false,
|
|
122
|
+
clearable = true,
|
|
123
|
+
format = { dateStyle: "medium" },
|
|
124
|
+
disabled,
|
|
125
|
+
min,
|
|
126
|
+
max,
|
|
127
|
+
numberOfMonths,
|
|
128
|
+
captionLayout,
|
|
129
|
+
showWeekNumbers,
|
|
130
|
+
weekStartsOn,
|
|
131
|
+
locale: localeProp,
|
|
132
|
+
today: todayProp,
|
|
133
|
+
name,
|
|
134
|
+
invalid,
|
|
135
|
+
size = "md",
|
|
136
|
+
align = "start",
|
|
137
|
+
label,
|
|
138
|
+
defaultOpen = false,
|
|
139
|
+
className,
|
|
140
|
+
}) {
|
|
141
|
+
const locale = useLocale(localeProp);
|
|
142
|
+
const today = useToday(todayProp);
|
|
143
|
+
const wide = useWide();
|
|
144
|
+
const [own, setOwn] = useState(defaultValue);
|
|
145
|
+
const value = valueProp !== undefined ? valueProp : own;
|
|
146
|
+
const [open, setOpen] = useState(defaultOpen);
|
|
147
|
+
const [month, setMonth] = useState(null);
|
|
148
|
+
const range = mode === "range";
|
|
149
|
+
const off = disabled === true;
|
|
150
|
+
|
|
151
|
+
const first = range ? value?.from : value;
|
|
152
|
+
const text = words(mode, value, format, locale);
|
|
153
|
+
const list = presets === true ? DATE_PRESETS[range ? "range" : "single"] : Array.isArray(presets) ? presets : [];
|
|
154
|
+
const shown = list.map((p) => ({ label: p.label, value: typeof p.value === "function" ? (today ? p.value(today) : null) : p.value }));
|
|
155
|
+
|
|
156
|
+
function set(v) {
|
|
157
|
+
if (valueProp === undefined) setOwn(v);
|
|
158
|
+
onChange?.(v);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Each opening starts on the chosen day's month (or today's).
|
|
162
|
+
function onOpenChange(next) {
|
|
163
|
+
if (next) setMonth(startOfMonth(first) ?? startOfMonth(today));
|
|
164
|
+
setOpen(next);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function choose(v) {
|
|
168
|
+
set(v);
|
|
169
|
+
if (!range || (v?.from && v?.to)) setOpen(false);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const months = wide ? numberOfMonths ?? (range ? 2 : 1) : 1;
|
|
173
|
+
const showClear = clearable && !off && (range ? !!value?.from : !!value);
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
<div className={cx("relative w-full", className)}>
|
|
177
|
+
<Popover
|
|
178
|
+
open={open}
|
|
179
|
+
onOpenChange={onOpenChange}
|
|
180
|
+
align={align}
|
|
181
|
+
width="auto"
|
|
182
|
+
className="p-3"
|
|
183
|
+
label={label ?? (range ? "Choose a date range" : "Choose a date")}
|
|
184
|
+
trigger={(props) => (
|
|
185
|
+
<button
|
|
186
|
+
{...props}
|
|
187
|
+
id={id}
|
|
188
|
+
type="button"
|
|
189
|
+
disabled={off}
|
|
190
|
+
aria-invalid={invalid ? true : undefined}
|
|
191
|
+
className={cx(FIELD, HEIGHT[size] ?? HEIGHT.md, showClear && "pr-11")}
|
|
192
|
+
>
|
|
193
|
+
<Icon name="calendar" className="shrink-0 text-muted-foreground" />
|
|
194
|
+
<span className={cx("min-w-0 flex-1 truncate", !text && "text-muted-foreground")}>
|
|
195
|
+
{text || placeholder || (range ? "Pick a range" : "Pick a date")}
|
|
196
|
+
</span>
|
|
197
|
+
</button>
|
|
198
|
+
)}
|
|
199
|
+
>
|
|
200
|
+
<div className="flex flex-col gap-3 sm:flex-row">
|
|
201
|
+
{shown.length ? (
|
|
202
|
+
<div
|
|
203
|
+
role="group"
|
|
204
|
+
aria-label="Presets"
|
|
205
|
+
className={PRESETS}
|
|
206
|
+
>
|
|
207
|
+
{shown.map((p) => {
|
|
208
|
+
const on = !!p.value && same(p.value, value);
|
|
209
|
+
return (
|
|
210
|
+
<Button
|
|
211
|
+
key={p.label}
|
|
212
|
+
size={wide ? "sm" : "md"}
|
|
213
|
+
variant={on ? "secondary" : "quiet"}
|
|
214
|
+
aria-pressed={on}
|
|
215
|
+
disabled={!p.value}
|
|
216
|
+
className="shrink-0 justify-start"
|
|
217
|
+
onClick={() => {
|
|
218
|
+
choose(p.value);
|
|
219
|
+
setMonth(startOfMonth(range ? p.value.from : p.value));
|
|
220
|
+
}}
|
|
221
|
+
>
|
|
222
|
+
{p.label}
|
|
223
|
+
</Button>
|
|
224
|
+
);
|
|
225
|
+
})}
|
|
226
|
+
</div>
|
|
227
|
+
) : null}
|
|
228
|
+
<Calendar
|
|
229
|
+
mode={range ? "range" : "single"}
|
|
230
|
+
value={value}
|
|
231
|
+
onChange={choose}
|
|
232
|
+
month={month ?? undefined}
|
|
233
|
+
onMonthChange={(m) => setMonth(`${m}-01`)}
|
|
234
|
+
numberOfMonths={months}
|
|
235
|
+
min={min}
|
|
236
|
+
max={max}
|
|
237
|
+
disabled={typeof disabled === "function" ? disabled : undefined}
|
|
238
|
+
captionLayout={captionLayout}
|
|
239
|
+
showWeekNumbers={showWeekNumbers}
|
|
240
|
+
weekStartsOn={weekStartsOn}
|
|
241
|
+
locale={locale}
|
|
242
|
+
today={today ?? undefined}
|
|
243
|
+
autoFocus={open}
|
|
244
|
+
label={label ?? (range ? "Choose a date range" : "Choose a date")}
|
|
245
|
+
/>
|
|
246
|
+
</div>
|
|
247
|
+
</Popover>
|
|
248
|
+
{showClear ? (
|
|
249
|
+
<IconButton
|
|
250
|
+
icon="x"
|
|
251
|
+
label="Clear date"
|
|
252
|
+
size="sm"
|
|
253
|
+
onClick={() => set(null)}
|
|
254
|
+
className={cx("absolute right-1", size === "sm" ? "top-0" : "top-1")}
|
|
255
|
+
/>
|
|
256
|
+
) : null}
|
|
257
|
+
{name && !range ? <input type="hidden" name={name} value={value ?? ""} /> : null}
|
|
258
|
+
{name && range ? (
|
|
259
|
+
<>
|
|
260
|
+
<input type="hidden" name={name} value={value?.from ?? ""} />
|
|
261
|
+
<input type="hidden" name={name} value={value?.to ?? ""} />
|
|
262
|
+
</>
|
|
263
|
+
) : null}
|
|
264
|
+
</div>
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* A date typed or picked. The browser's own date field — segments in the
|
|
270
|
+
* reader's order, digits only, the value a "YYYY-MM-DD" string or "" while
|
|
271
|
+
* incomplete — with its built-in picker swapped for a button that opens
|
|
272
|
+
* this Calendar. onChange(date | null). Chrome and Safari hide their own
|
|
273
|
+
* picker icon; Firefox keeps its own beside ours.
|
|
274
|
+
*
|
|
275
|
+
* value, onChange(date | null), defaultValue, min, max, disabled
|
|
276
|
+
* (true, or a function for the Calendar's days), name, invalid, size,
|
|
277
|
+
* locale (the Calendar's; the field itself follows the browser), today
|
|
278
|
+
*/
|
|
279
|
+
export function DateInput({
|
|
280
|
+
id,
|
|
281
|
+
value: valueProp,
|
|
282
|
+
defaultValue = null,
|
|
283
|
+
onChange,
|
|
284
|
+
min,
|
|
285
|
+
max,
|
|
286
|
+
disabled,
|
|
287
|
+
name,
|
|
288
|
+
invalid,
|
|
289
|
+
size = "md",
|
|
290
|
+
locale,
|
|
291
|
+
today,
|
|
292
|
+
weekStartsOn,
|
|
293
|
+
className,
|
|
294
|
+
...rest
|
|
295
|
+
}) {
|
|
296
|
+
const [own, setOwn] = useState(defaultValue);
|
|
297
|
+
const value = valueProp !== undefined ? valueProp : own;
|
|
298
|
+
const [open, setOpen] = useState(false);
|
|
299
|
+
const [month, setMonth] = useState(null);
|
|
300
|
+
const off = disabled === true;
|
|
301
|
+
const out = !!value && ((min && value < min) || (max && value > max));
|
|
302
|
+
|
|
303
|
+
function set(v) {
|
|
304
|
+
if (valueProp === undefined) setOwn(v);
|
|
305
|
+
onChange?.(v);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return (
|
|
309
|
+
<div className={cx("relative w-full", className)}>
|
|
310
|
+
<Input
|
|
311
|
+
id={id}
|
|
312
|
+
type="date"
|
|
313
|
+
name={name}
|
|
314
|
+
value={value ?? ""}
|
|
315
|
+
min={min}
|
|
316
|
+
max={max}
|
|
317
|
+
disabled={off}
|
|
318
|
+
invalid={invalid || out}
|
|
319
|
+
onChange={(e) => set(e.target.value || null)}
|
|
320
|
+
className={cx(
|
|
321
|
+
"pr-12 [&::-webkit-calendar-picker-indicator]:hidden tabular-nums",
|
|
322
|
+
size === "sm" && "min-h-9",
|
|
323
|
+
)}
|
|
324
|
+
{...rest}
|
|
325
|
+
/>
|
|
326
|
+
<span className={cx("absolute right-1", size === "sm" ? "top-0" : "top-1")}>
|
|
327
|
+
<Popover
|
|
328
|
+
open={open}
|
|
329
|
+
onOpenChange={(next) => {
|
|
330
|
+
if (next) setMonth(startOfMonth(value) ?? null);
|
|
331
|
+
setOpen(next);
|
|
332
|
+
}}
|
|
333
|
+
align="end"
|
|
334
|
+
width="auto"
|
|
335
|
+
className="p-3"
|
|
336
|
+
label="Choose a date"
|
|
337
|
+
trigger={(props) => <IconButton {...props} icon="calendar" label="Open calendar" size="sm" disabled={off} />}
|
|
338
|
+
>
|
|
339
|
+
<Calendar
|
|
340
|
+
value={value}
|
|
341
|
+
onChange={(v) => {
|
|
342
|
+
set(v);
|
|
343
|
+
setOpen(false);
|
|
344
|
+
}}
|
|
345
|
+
month={month ?? undefined}
|
|
346
|
+
onMonthChange={(m) => setMonth(`${m}-01`)}
|
|
347
|
+
min={min}
|
|
348
|
+
max={max}
|
|
349
|
+
disabled={typeof disabled === "function" ? disabled : undefined}
|
|
350
|
+
locale={locale}
|
|
351
|
+
today={today}
|
|
352
|
+
weekStartsOn={weekStartsOn}
|
|
353
|
+
autoFocus={open}
|
|
354
|
+
label="Choose a date"
|
|
355
|
+
/>
|
|
356
|
+
</Popover>
|
|
357
|
+
</span>
|
|
358
|
+
</div>
|
|
359
|
+
);
|
|
360
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { cx } from "./cx";
|
|
2
|
+
|
|
3
|
+
// Parts of one whole as a single stacked bar: traffic by device, tickets
|
|
4
|
+
// by channel, spend by category. Server-safe (no hooks). Meter is one
|
|
5
|
+
// amount against a limit; this is N shares of a total, which always fill
|
|
6
|
+
// the bar — unless a `total` above their sum leaves a rest of track.
|
|
7
|
+
//
|
|
8
|
+
// Colour: each segment takes a categorical hue by default (segment i gets
|
|
9
|
+
// hue i+1, round 1..5, from --color-chart-N) — the parts are KINDS of a
|
|
10
|
+
// thing. A segment's status `tone` overrides it, for sentiment (positive ·
|
|
11
|
+
// neutral · negative feedback). Tone is status, hue is category.
|
|
12
|
+
|
|
13
|
+
// Literal class names, so Tailwind sees every one.
|
|
14
|
+
const HUE_FILLS = { 1: "bg-chart-1", 2: "bg-chart-2", 3: "bg-chart-3", 4: "bg-chart-4", 5: "bg-chart-5" };
|
|
15
|
+
const TONE_FILLS = {
|
|
16
|
+
neutral: "bg-muted-foreground",
|
|
17
|
+
success: "bg-success",
|
|
18
|
+
warning: "bg-warning",
|
|
19
|
+
danger: "bg-destructive",
|
|
20
|
+
info: "bg-info",
|
|
21
|
+
};
|
|
22
|
+
const SIZES = { thin: "h-1.5", md: "h-2.5" };
|
|
23
|
+
|
|
24
|
+
const EN = "en-US";
|
|
25
|
+
function shareText(pct) {
|
|
26
|
+
if (pct > 0 && pct < 1) return "<1%";
|
|
27
|
+
return `${Math.round(pct).toLocaleString(EN)}%`;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* segments [{ label, value, tone?, hue? }] — value is a number in any
|
|
32
|
+
* unit; the bar shows each one's share of their total. A zero
|
|
33
|
+
* (or negative, or missing) value is skipped
|
|
34
|
+
* size thin (6px, a list row) · md (10px)
|
|
35
|
+
* legend a row under the bar: dot, label, share %
|
|
36
|
+
* label the bar's name, read to a screen reader with every
|
|
37
|
+
* segment's label and share: "Traffic by device: Desktop 62%, …"
|
|
38
|
+
* total the whole the shares are of, in the segments' unit: 100 GB of
|
|
39
|
+
* storage, a $1,000 budget. When the segments sum to less, the
|
|
40
|
+
* rest is drawn as unfilled track at the end and every share is
|
|
41
|
+
* of `total`. Left out (or not above the sum), the segments fill
|
|
42
|
+
* the bar, as before
|
|
43
|
+
* restLabel names that rest — "Free", "Remaining" — in the legend (a
|
|
44
|
+
* hollow dot) and to a screen reader; left out, the rest is
|
|
45
|
+
* track only
|
|
46
|
+
* formatValue (value) → string — the legend shows each value in it
|
|
47
|
+
* ("$450") instead of the share; a reader hears both
|
|
48
|
+
* formatLegend ({ label, value, pct, share, rest }) → the words after a
|
|
49
|
+
* legend label, whole ("$450 · 52%"); wins over formatValue.
|
|
50
|
+
* `rest` is true for the restLabel entry
|
|
51
|
+
*
|
|
52
|
+
* tone success · warning · danger · info · neutral — sentiment,
|
|
53
|
+
* overrides the hue
|
|
54
|
+
* hue 1..5 — pin a category's colour (so "Email" is the same hue
|
|
55
|
+
* in every chart); default the segment's place in the list
|
|
56
|
+
*
|
|
57
|
+
* An empty total (no positive values) draws the empty track and reads as
|
|
58
|
+
* "no data". Thin gaps separate the segments; the ends are round.
|
|
59
|
+
*/
|
|
60
|
+
export function Distribution({ segments = [], size = "md", legend = false, label, total: whole, restLabel, formatValue, formatLegend, className }) {
|
|
61
|
+
const parts = segments
|
|
62
|
+
.map((s, i) => ({ ...s, i }))
|
|
63
|
+
.filter((s) => typeof s.value === "number" && Number.isFinite(s.value) && s.value > 0);
|
|
64
|
+
const sum = parts.reduce((n, s) => n + s.value, 0);
|
|
65
|
+
// A `total` above the sum leaves a rest: unfilled track, optionally named.
|
|
66
|
+
const rest = typeof whole === "number" && Number.isFinite(whole) && whole > sum ? whole - sum : 0;
|
|
67
|
+
const total = sum + rest;
|
|
68
|
+
const shown = parts.map((s) => {
|
|
69
|
+
const fill = TONE_FILLS[s.tone] ?? HUE_FILLS[s.hue] ?? HUE_FILLS[(s.i % 5) + 1];
|
|
70
|
+
const pct = total > 0 ? (s.value / total) * 100 : 0;
|
|
71
|
+
return { key: s.key ?? `${s.label}-${s.i}`, label: s.label, value: s.value, fill, pct, share: shareText(pct) };
|
|
72
|
+
});
|
|
73
|
+
const restPct = total > 0 ? (rest / total) * 100 : 0;
|
|
74
|
+
const restPart = rest > 0 ? { key: "__rest", label: restLabel, value: rest, pct: restPct, share: shareText(restPct), rest: true } : null;
|
|
75
|
+
const named = [...shown, ...(restPart && restLabel ? [restPart] : [])];
|
|
76
|
+
const words = (s) => (formatValue ? `${s.label} ${formatValue(s.value)}, ${s.share}` : `${s.label} ${s.share}`);
|
|
77
|
+
const said = shown.length
|
|
78
|
+
? `${label ? `${label}: ` : ""}${named.map(words).join(", ")}`
|
|
79
|
+
: `${label ? `${label}: ` : ""}no data`;
|
|
80
|
+
const legendText = (s) =>
|
|
81
|
+
formatLegend ? formatLegend({ label: s.label, value: s.value, pct: s.pct, share: s.share, rest: Boolean(s.rest) }) : formatValue ? formatValue(s.value) : s.share;
|
|
82
|
+
const track = SIZES[size] ?? SIZES.md;
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<div className={cx("grid gap-2", className)}>
|
|
86
|
+
<div role="img" aria-label={said} className={cx("flex w-full gap-0.5 overflow-hidden rounded-full", track, !shown.length && "bg-accent")}>
|
|
87
|
+
{shown.map((s) => (
|
|
88
|
+
<span
|
|
89
|
+
key={s.key}
|
|
90
|
+
className={cx("h-full min-w-0.5 transition-[flex-grow] duration-300 ease-out motion-reduce:transition-none", s.fill)}
|
|
91
|
+
style={{ flexGrow: s.value, flexShrink: 1, flexBasis: 0 }}
|
|
92
|
+
/>
|
|
93
|
+
))}
|
|
94
|
+
{restPart ? <span className="h-full min-w-0.5 bg-accent" style={{ flexGrow: rest, flexShrink: 1, flexBasis: 0 }} /> : null}
|
|
95
|
+
</div>
|
|
96
|
+
{legend && shown.length ? (
|
|
97
|
+
<ul aria-hidden="true" className={cx("flex flex-wrap items-center gap-x-3 gap-y-1", size === "thin" ? "text-xs" : "text-sm")}>
|
|
98
|
+
{named.map((s) => (
|
|
99
|
+
<li key={s.key} className="inline-flex min-w-0 items-center gap-1.5 text-muted-foreground">
|
|
100
|
+
<span
|
|
101
|
+
className={cx(
|
|
102
|
+
"shrink-0 rounded-full",
|
|
103
|
+
size === "thin" ? "size-1.5" : "size-2",
|
|
104
|
+
s.rest ? "border border-muted-foreground bg-accent" : s.fill,
|
|
105
|
+
)}
|
|
106
|
+
/>
|
|
107
|
+
<span className="min-w-0 truncate">{s.label}</span>
|
|
108
|
+
<span data-nums className="font-medium text-foreground">
|
|
109
|
+
{legendText(s)}
|
|
110
|
+
</span>
|
|
111
|
+
</li>
|
|
112
|
+
))}
|
|
113
|
+
</ul>
|
|
114
|
+
) : null}
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
}
|