makersclaw 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +180 -0
- package/package.json +3 -2
- package/r/annotate.json +62 -0
- package/r/approval-request.json +52 -0
- package/r/audio-player.json +74 -0
- package/r/auth-form.json +55 -0
- package/r/board.json +10 -6
- package/r/calendar-view.json +105 -0
- package/r/cart.json +62 -0
- package/r/chart.json +83 -0
- package/r/chat.json +95 -0
- package/r/code-editor.json +94 -0
- package/r/comment-box.json +64 -0
- package/r/contact-section.json +53 -0
- package/r/core.json +205 -8
- package/r/csv-import.json +63 -0
- package/r/data-table.json +69 -0
- package/r/diagram.json +74 -0
- package/r/doc-editor.json +82 -0
- package/r/doc-page.json +61 -0
- package/r/email-render.json +73 -0
- package/r/faq.json +50 -0
- package/r/file-upload.json +54 -0
- package/r/flow-canvas.json +93 -0
- package/r/footer.json +52 -0
- package/r/gantt.json +70 -0
- package/r/job-panel.json +12 -7
- package/r/json-editor.json +66 -0
- package/r/map.json +89 -0
- package/r/menubar.json +52 -0
- package/r/mind-map.json +67 -0
- package/r/navigation-menu.json +52 -0
- package/r/order-detail.json +54 -0
- package/r/org-chart.json +66 -0
- package/r/page-builder.json +105 -0
- package/r/payment-methods.json +51 -0
- package/r/pdf-document.json +79 -0
- package/r/pdf-viewer.json +88 -0
- package/r/product-detail.json +76 -0
- package/r/product-grid.json +65 -0
- package/r/record-form.json +67 -0
- package/r/record-notes.json +55 -0
- package/r/registry.json +3411 -29
- package/r/search-dialog.json +51 -0
- package/r/settings-list.json +66 -0
- package/r/setup-checklist.json +51 -0
- package/r/share-dialog.json +52 -0
- package/r/sidebar.json +69 -0
- package/r/signature-pad.json +72 -0
- package/r/sketch-canvas.json +99 -0
- package/r/spreadsheet.json +90 -0
- package/r/stat-cards.json +66 -0
- package/r/task-list.json +63 -0
- package/r/task-model.json +98 -0
- package/r/testimonials.json +52 -0
- package/r/transaction-list.json +53 -0
- package/r/whiteboard.json +66 -0
- package/registry/blocks/annotate/README.md +179 -0
- package/registry/blocks/annotate/annotate-data.js +250 -0
- package/registry/blocks/annotate/annotate.jsx +646 -0
- package/registry/blocks/annotate/block.json +10 -0
- package/registry/blocks/annotate/demo.jsx +135 -0
- package/registry/blocks/annotate/index.js +15 -0
- package/registry/blocks/approval-request/README.md +116 -0
- package/registry/blocks/approval-request/approval-request.jsx +386 -0
- package/registry/blocks/approval-request/block.json +10 -0
- package/registry/blocks/approval-request/demo.jsx +127 -0
- package/registry/blocks/approval-request/index.js +4 -0
- package/registry/blocks/audio-player/README.md +167 -0
- package/registry/blocks/audio-player/audio-player.jsx +623 -0
- package/registry/blocks/audio-player/block.json +14 -0
- package/registry/blocks/audio-player/colors.js +109 -0
- package/registry/blocks/audio-player/demo.jsx +209 -0
- package/registry/blocks/audio-player/index.js +6 -0
- package/registry/blocks/audio-player/time.js +67 -0
- package/registry/blocks/audio-player/wavesurfer.js +9 -0
- package/registry/blocks/auth-form/README.md +126 -0
- package/registry/blocks/auth-form/auth-form.jsx +568 -0
- package/registry/blocks/auth-form/block.json +10 -0
- package/registry/blocks/auth-form/demo.jsx +131 -0
- package/registry/blocks/auth-form/index.js +3 -0
- package/registry/blocks/board/README.md +55 -5
- package/registry/blocks/board/block.json +2 -2
- package/registry/blocks/board/board.jsx +230 -86
- package/registry/blocks/board/demo.jsx +103 -24
- package/registry/blocks/calendar-view/README.md +180 -0
- package/registry/blocks/calendar-view/agenda.jsx +147 -0
- package/registry/blocks/calendar-view/block.json +76 -0
- package/registry/blocks/calendar-view/calendar-model.js +442 -0
- package/registry/blocks/calendar-view/calendar.jsx +627 -0
- package/registry/blocks/calendar-view/demo.jsx +195 -0
- package/registry/blocks/calendar-view/draft.jsx +49 -0
- package/registry/blocks/calendar-view/index.js +39 -0
- package/registry/blocks/calendar-view/month.jsx +346 -0
- package/registry/blocks/calendar-view/paint.js +69 -0
- package/registry/blocks/calendar-view/time-grid.jsx +527 -0
- package/registry/blocks/calendar-view/tray.jsx +87 -0
- package/registry/blocks/cart/README.md +146 -0
- package/registry/blocks/cart/block.json +10 -0
- package/registry/blocks/cart/cart.jsx +597 -0
- package/registry/blocks/cart/demo.jsx +98 -0
- package/registry/blocks/cart/index.js +4 -0
- package/registry/blocks/cart/money.js +28 -0
- package/registry/blocks/chart/README.md +316 -0
- package/registry/blocks/chart/block.json +10 -0
- package/registry/blocks/chart/cartesian.jsx +642 -0
- package/registry/blocks/chart/core.jsx +262 -0
- package/registry/blocks/chart/demo.jsx +357 -0
- package/registry/blocks/chart/heatmap.jsx +336 -0
- package/registry/blocks/chart/index.js +8 -0
- package/registry/blocks/chart/pie.jsx +245 -0
- package/registry/blocks/chart/sparkline.jsx +88 -0
- package/registry/blocks/chat/README.md +273 -0
- package/registry/blocks/chat/attachment.jsx +95 -0
- package/registry/blocks/chat/block.json +10 -0
- package/registry/blocks/chat/chat.jsx +132 -0
- package/registry/blocks/chat/composer.jsx +364 -0
- package/registry/blocks/chat/demo.jsx +578 -0
- package/registry/blocks/chat/header.jsx +34 -0
- package/registry/blocks/chat/index.js +9 -0
- package/registry/blocks/chat/message.jsx +450 -0
- package/registry/blocks/chat/scroller.jsx +247 -0
- package/registry/blocks/chat/text.jsx +104 -0
- package/registry/blocks/code-editor/README.md +210 -0
- package/registry/blocks/code-editor/block.json +22 -0
- package/registry/blocks/code-editor/code-editor.jsx +534 -0
- package/registry/blocks/code-editor/codemirror.js +38 -0
- package/registry/blocks/code-editor/demo.jsx +205 -0
- package/registry/blocks/code-editor/index.js +8 -0
- package/registry/blocks/code-editor/json.js +317 -0
- package/registry/blocks/code-editor/sql.js +136 -0
- package/registry/blocks/code-editor/text.js +101 -0
- package/registry/blocks/code-editor/theme.js +186 -0
- package/registry/blocks/comment-box/README.md +123 -0
- package/registry/blocks/comment-box/block.json +10 -0
- package/registry/blocks/comment-box/comment-body.jsx +217 -0
- package/registry/blocks/comment-box/comment-box.jsx +198 -0
- package/registry/blocks/comment-box/comment-time.jsx +77 -0
- package/registry/blocks/comment-box/demo.jsx +141 -0
- package/registry/blocks/comment-box/index.js +8 -0
- package/registry/blocks/contact-section/README.md +152 -0
- package/registry/blocks/contact-section/block.json +11 -0
- package/registry/blocks/contact-section/contact-section.jsx +509 -0
- package/registry/blocks/contact-section/demo.jsx +93 -0
- package/registry/blocks/contact-section/index.js +4 -0
- package/registry/blocks/csv-import/README.md +133 -0
- package/registry/blocks/csv-import/block.json +13 -0
- package/registry/blocks/csv-import/csv-import.jsx +479 -0
- package/registry/blocks/csv-import/demo.jsx +106 -0
- package/registry/blocks/csv-import/import.js +200 -0
- package/registry/blocks/csv-import/index.js +7 -0
- package/registry/blocks/data-table/README.md +386 -0
- package/registry/blocks/data-table/block.json +10 -0
- package/registry/blocks/data-table/data-table.jsx +1164 -0
- package/registry/blocks/data-table/demo.jsx +588 -0
- package/registry/blocks/data-table/index.js +5 -0
- package/registry/blocks/data-table/model.js +169 -0
- package/registry/blocks/diagram/README.md +108 -0
- package/registry/blocks/diagram/block.json +13 -0
- package/registry/blocks/diagram/demo.jsx +113 -0
- package/registry/blocks/diagram/diagram.jsx +481 -0
- package/registry/blocks/diagram/index.js +7 -0
- package/registry/blocks/diagram/mermaid.js +52 -0
- package/registry/blocks/diagram/palette.js +313 -0
- package/registry/blocks/diagram/source.js +98 -0
- package/registry/blocks/doc-editor/README.md +215 -0
- package/registry/blocks/doc-editor/block.json +15 -0
- package/registry/blocks/doc-editor/demo.jsx +225 -0
- package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
- package/registry/blocks/doc-editor/doc.js +309 -0
- package/registry/blocks/doc-editor/index.js +7 -0
- package/registry/blocks/doc-editor/schema.jsx +56 -0
- package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
- package/registry/blocks/doc-editor/theme.js +82 -0
- package/registry/blocks/doc-page/README.md +119 -0
- package/registry/blocks/doc-page/autosave.js +104 -0
- package/registry/blocks/doc-page/block.json +10 -0
- package/registry/blocks/doc-page/demo.jsx +137 -0
- package/registry/blocks/doc-page/doc-page.jsx +276 -0
- package/registry/blocks/doc-page/index.js +4 -0
- package/registry/blocks/email-render/README.md +151 -0
- package/registry/blocks/email-render/block.json +14 -0
- package/registry/blocks/email-render/demo.jsx +153 -0
- package/registry/blocks/email-render/doc-email.jsx +210 -0
- package/registry/blocks/email-render/email.jsx +221 -0
- package/registry/blocks/email-render/index.js +10 -0
- package/registry/blocks/email-render/render.js +50 -0
- package/registry/blocks/email-render/theme.js +215 -0
- package/registry/blocks/faq/README.md +101 -0
- package/registry/blocks/faq/block.json +11 -0
- package/registry/blocks/faq/demo.jsx +89 -0
- package/registry/blocks/faq/faq.jsx +220 -0
- package/registry/blocks/faq/index.js +4 -0
- package/registry/blocks/file-upload/README.md +138 -0
- package/registry/blocks/file-upload/block.json +10 -0
- package/registry/blocks/file-upload/demo.jsx +204 -0
- package/registry/blocks/file-upload/file-upload.jsx +635 -0
- package/registry/blocks/file-upload/index.js +4 -0
- package/registry/blocks/flow-canvas/README.md +420 -0
- package/registry/blocks/flow-canvas/block.json +13 -0
- package/registry/blocks/flow-canvas/board.js +819 -0
- package/registry/blocks/flow-canvas/chrome.jsx +649 -0
- package/registry/blocks/flow-canvas/context.jsx +35 -0
- package/registry/blocks/flow-canvas/demo.jsx +249 -0
- package/registry/blocks/flow-canvas/edges.jsx +107 -0
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
- package/registry/blocks/flow-canvas/index.js +41 -0
- package/registry/blocks/flow-canvas/nodes.jsx +392 -0
- package/registry/blocks/flow-canvas/theme.js +174 -0
- package/registry/blocks/footer/README.md +133 -0
- package/registry/blocks/footer/block.json +11 -0
- package/registry/blocks/footer/demo.jsx +119 -0
- package/registry/blocks/footer/footer.jsx +406 -0
- package/registry/blocks/footer/index.js +4 -0
- package/registry/blocks/gantt/README.md +220 -0
- package/registry/blocks/gantt/block.json +10 -0
- package/registry/blocks/gantt/demo.jsx +148 -0
- package/registry/blocks/gantt/gantt.jsx +923 -0
- package/registry/blocks/gantt/index.js +7 -0
- package/registry/blocks/gantt/rows.jsx +468 -0
- package/registry/blocks/gantt/schedule.js +278 -0
- package/registry/blocks/job-panel/README.md +80 -0
- package/registry/blocks/job-panel/block.json +3 -3
- package/registry/blocks/job-panel/demo.jsx +230 -3
- package/registry/blocks/job-panel/job-panel.jsx +169 -3
- package/registry/blocks/json-editor/README.md +133 -0
- package/registry/blocks/json-editor/block.json +10 -0
- package/registry/blocks/json-editor/demo.jsx +92 -0
- package/registry/blocks/json-editor/index.js +7 -0
- package/registry/blocks/json-editor/json-editor.jsx +305 -0
- package/registry/blocks/json-editor/json-tree.jsx +393 -0
- package/registry/blocks/json-editor/tree.js +225 -0
- package/registry/blocks/map/README.md +221 -0
- package/registry/blocks/map/block.json +14 -0
- package/registry/blocks/map/demo.jsx +201 -0
- package/registry/blocks/map/geo.js +198 -0
- package/registry/blocks/map/index.js +8 -0
- package/registry/blocks/map/list.jsx +128 -0
- package/registry/blocks/map/map-view.jsx +715 -0
- package/registry/blocks/map/maplibre.js +30 -0
- package/registry/blocks/map/marks.jsx +146 -0
- package/registry/blocks/map/theme.js +142 -0
- package/registry/blocks/menubar/README.md +109 -0
- package/registry/blocks/menubar/block.json +10 -0
- package/registry/blocks/menubar/demo.jsx +128 -0
- package/registry/blocks/menubar/index.js +4 -0
- package/registry/blocks/menubar/menubar.jsx +199 -0
- package/registry/blocks/mind-map/README.md +206 -0
- package/registry/blocks/mind-map/block.json +10 -0
- package/registry/blocks/mind-map/demo.jsx +103 -0
- package/registry/blocks/mind-map/index.js +31 -0
- package/registry/blocks/mind-map/mind-map.jsx +1125 -0
- package/registry/blocks/mind-map/topic.jsx +143 -0
- package/registry/blocks/mind-map/tree.js +645 -0
- package/registry/blocks/navigation-menu/README.md +124 -0
- package/registry/blocks/navigation-menu/block.json +10 -0
- package/registry/blocks/navigation-menu/demo.jsx +84 -0
- package/registry/blocks/navigation-menu/index.js +4 -0
- package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
- package/registry/blocks/order-detail/README.md +109 -0
- package/registry/blocks/order-detail/block.json +10 -0
- package/registry/blocks/order-detail/demo.jsx +88 -0
- package/registry/blocks/order-detail/index.js +4 -0
- package/registry/blocks/order-detail/order-detail.jsx +354 -0
- package/registry/blocks/org-chart/README.md +145 -0
- package/registry/blocks/org-chart/block.json +10 -0
- package/registry/blocks/org-chart/demo.jsx +94 -0
- package/registry/blocks/org-chart/index.js +7 -0
- package/registry/blocks/org-chart/org-chart.jsx +631 -0
- package/registry/blocks/org-chart/org.js +245 -0
- package/registry/blocks/org-chart/person.jsx +96 -0
- package/registry/blocks/page-builder/README.md +257 -0
- package/registry/blocks/page-builder/block.json +14 -0
- package/registry/blocks/page-builder/demo.jsx +145 -0
- package/registry/blocks/page-builder/grapes.js +18 -0
- package/registry/blocks/page-builder/index.js +11 -0
- package/registry/blocks/page-builder/page-builder.jsx +704 -0
- package/registry/blocks/page-builder/page-view.jsx +33 -0
- package/registry/blocks/page-builder/page.js +118 -0
- package/registry/blocks/page-builder/panels.jsx +588 -0
- package/registry/blocks/page-builder/sections.js +209 -0
- package/registry/blocks/page-builder/theme.js +87 -0
- package/registry/blocks/page-builder/thumbs.jsx +189 -0
- package/registry/blocks/page-builder/tokens.js +329 -0
- package/registry/blocks/payment-methods/README.md +104 -0
- package/registry/blocks/payment-methods/block.json +10 -0
- package/registry/blocks/payment-methods/demo.jsx +71 -0
- package/registry/blocks/payment-methods/index.js +4 -0
- package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
- package/registry/blocks/pdf-document/README.md +213 -0
- package/registry/blocks/pdf-document/block.json +13 -0
- package/registry/blocks/pdf-document/demo.jsx +136 -0
- package/registry/blocks/pdf-document/index.js +33 -0
- package/registry/blocks/pdf-document/money.js +83 -0
- package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
- package/registry/blocks/pdf-document/primitives.jsx +271 -0
- package/registry/blocks/pdf-document/quote.jsx +179 -0
- package/registry/blocks/pdf-document/theme.js +193 -0
- package/registry/blocks/pdf-viewer/README.md +191 -0
- package/registry/blocks/pdf-viewer/block.json +14 -0
- package/registry/blocks/pdf-viewer/demo.jsx +252 -0
- package/registry/blocks/pdf-viewer/helpers.js +270 -0
- package/registry/blocks/pdf-viewer/index.js +8 -0
- package/registry/blocks/pdf-viewer/notes.jsx +195 -0
- package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
- package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
- package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
- package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
- package/registry/blocks/product-detail/README.md +217 -0
- package/registry/blocks/product-detail/block.json +10 -0
- package/registry/blocks/product-detail/demo.jsx +233 -0
- package/registry/blocks/product-detail/index.js +7 -0
- package/registry/blocks/product-detail/price.jsx +115 -0
- package/registry/blocks/product-detail/product-detail.jsx +348 -0
- package/registry/blocks/product-detail/product-media.jsx +102 -0
- package/registry/blocks/product-detail/product-options.jsx +144 -0
- package/registry/blocks/product-grid/README.md +162 -0
- package/registry/blocks/product-grid/block.json +10 -0
- package/registry/blocks/product-grid/demo.jsx +255 -0
- package/registry/blocks/product-grid/index.js +5 -0
- package/registry/blocks/product-grid/product-card.jsx +232 -0
- package/registry/blocks/product-grid/product-grid.jsx +235 -0
- package/registry/blocks/record-form/README.md +196 -0
- package/registry/blocks/record-form/block.json +10 -0
- package/registry/blocks/record-form/demo.jsx +525 -0
- package/registry/blocks/record-form/index.js +4 -0
- package/registry/blocks/record-form/record-fields.jsx +457 -0
- package/registry/blocks/record-form/record-form.jsx +415 -0
- package/registry/blocks/record-form/rules.js +81 -0
- package/registry/blocks/record-notes/README.md +139 -0
- package/registry/blocks/record-notes/block.json +10 -0
- package/registry/blocks/record-notes/demo.jsx +179 -0
- package/registry/blocks/record-notes/index.js +4 -0
- package/registry/blocks/record-notes/record-notes.jsx +266 -0
- package/registry/blocks/search-dialog/README.md +108 -0
- package/registry/blocks/search-dialog/block.json +10 -0
- package/registry/blocks/search-dialog/demo.jsx +116 -0
- package/registry/blocks/search-dialog/index.js +3 -0
- package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
- package/registry/blocks/settings-list/README.md +171 -0
- package/registry/blocks/settings-list/block.json +10 -0
- package/registry/blocks/settings-list/demo.jsx +333 -0
- package/registry/blocks/settings-list/index.js +4 -0
- package/registry/blocks/settings-list/row-state.jsx +93 -0
- package/registry/blocks/settings-list/settings-list.jsx +349 -0
- package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
- package/registry/blocks/setup-checklist/README.md +142 -0
- package/registry/blocks/setup-checklist/block.json +10 -0
- package/registry/blocks/setup-checklist/demo.jsx +159 -0
- package/registry/blocks/setup-checklist/index.js +4 -0
- package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
- package/registry/blocks/share-dialog/README.md +113 -0
- package/registry/blocks/share-dialog/block.json +10 -0
- package/registry/blocks/share-dialog/demo.jsx +140 -0
- package/registry/blocks/share-dialog/index.js +3 -0
- package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
- package/registry/blocks/sidebar/README.md +190 -0
- package/registry/blocks/sidebar/block.json +43 -0
- package/registry/blocks/sidebar/demo.jsx +577 -0
- package/registry/blocks/sidebar/index.js +4 -0
- package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
- package/registry/blocks/sidebar/sidebar.jsx +864 -0
- package/registry/blocks/signature-pad/README.md +137 -0
- package/registry/blocks/signature-pad/block.json +13 -0
- package/registry/blocks/signature-pad/colors.js +115 -0
- package/registry/blocks/signature-pad/demo.jsx +94 -0
- package/registry/blocks/signature-pad/index.js +6 -0
- package/registry/blocks/signature-pad/pad.js +7 -0
- package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
- package/registry/blocks/signature-pad/signature.js +68 -0
- package/registry/blocks/sketch-canvas/README.md +280 -0
- package/registry/blocks/sketch-canvas/block.json +13 -0
- package/registry/blocks/sketch-canvas/demo.jsx +159 -0
- package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
- package/registry/blocks/sketch-canvas/index.js +9 -0
- package/registry/blocks/sketch-canvas/palette.js +226 -0
- package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
- package/registry/blocks/sketch-canvas/sketch.js +179 -0
- package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
- package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
- package/registry/blocks/sketch-canvas/stamps.js +104 -0
- package/registry/blocks/sketch-canvas/theme.js +131 -0
- package/registry/blocks/spreadsheet/README.md +307 -0
- package/registry/blocks/spreadsheet/block.json +13 -0
- package/registry/blocks/spreadsheet/cells.jsx +455 -0
- package/registry/blocks/spreadsheet/chrome.jsx +325 -0
- package/registry/blocks/spreadsheet/demo.jsx +177 -0
- package/registry/blocks/spreadsheet/grid.js +387 -0
- package/registry/blocks/spreadsheet/index.js +34 -0
- package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
- package/registry/blocks/spreadsheet/types.js +473 -0
- package/registry/blocks/stat-cards/README.md +173 -0
- package/registry/blocks/stat-cards/block.json +10 -0
- package/registry/blocks/stat-cards/demo.jsx +257 -0
- package/registry/blocks/stat-cards/index.js +4 -0
- package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
- package/registry/blocks/stat-cards/usage.jsx +243 -0
- package/registry/blocks/task-list/README.md +176 -0
- package/registry/blocks/task-list/block.json +10 -0
- package/registry/blocks/task-list/demo.jsx +134 -0
- package/registry/blocks/task-list/index.js +5 -0
- package/registry/blocks/task-list/task-list.jsx +907 -0
- package/registry/blocks/task-model/README.md +455 -0
- package/registry/blocks/task-model/block.json +167 -0
- package/registry/blocks/task-model/changes.js +89 -0
- package/registry/blocks/task-model/dates.js +371 -0
- package/registry/blocks/task-model/demo.jsx +215 -0
- package/registry/blocks/task-model/dnd.jsx +240 -0
- package/registry/blocks/task-model/index.js +97 -0
- package/registry/blocks/task-model/model.js +919 -0
- package/registry/blocks/task-model/parts.jsx +449 -0
- package/registry/blocks/task-model/toolbar.jsx +271 -0
- package/registry/blocks/testimonials/README.md +139 -0
- package/registry/blocks/testimonials/block.json +11 -0
- package/registry/blocks/testimonials/demo.jsx +137 -0
- package/registry/blocks/testimonials/index.js +4 -0
- package/registry/blocks/testimonials/testimonials.jsx +430 -0
- package/registry/blocks/transaction-list/README.md +126 -0
- package/registry/blocks/transaction-list/block.json +10 -0
- package/registry/blocks/transaction-list/demo.jsx +79 -0
- package/registry/blocks/transaction-list/index.js +4 -0
- package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
- package/registry/blocks/whiteboard/README.md +179 -0
- package/registry/blocks/whiteboard/block.json +10 -0
- package/registry/blocks/whiteboard/demo.jsx +169 -0
- package/registry/blocks/whiteboard/index.js +6 -0
- package/registry/blocks/whiteboard/templates.js +150 -0
- package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
- package/src/install.mjs +18 -0
- package/src/shadcn.mjs +8 -0
- package/templates/next/files/README.md +145 -11
- package/templates/next/files/app/globals.css +55 -4
- package/templates/next/files/check/run.mjs +3 -3
- package/templates/next/files/components/ui/avatar.jsx +141 -0
- package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
- package/templates/next/files/components/ui/button-group.jsx +70 -0
- package/templates/next/files/components/ui/button.jsx +132 -12
- package/templates/next/files/components/ui/calendar.jsx +609 -0
- package/templates/next/files/components/ui/carousel.jsx +281 -0
- package/templates/next/files/components/ui/collapsible.jsx +208 -0
- package/templates/next/files/components/ui/combobox.jsx +608 -0
- package/templates/next/files/components/ui/command.jsx +577 -0
- package/templates/next/files/components/ui/context-menu.jsx +191 -0
- package/templates/next/files/components/ui/date-picker.jsx +360 -0
- package/templates/next/files/components/ui/distribution.jsx +117 -0
- package/templates/next/files/components/ui/feedback.jsx +143 -0
- package/templates/next/files/components/ui/field.jsx +115 -3
- package/templates/next/files/components/ui/file-input.jsx +234 -0
- package/templates/next/files/components/ui/icon.jsx +130 -8
- package/templates/next/files/components/ui/image.jsx +143 -0
- package/templates/next/files/components/ui/index.js +47 -2
- package/templates/next/files/components/ui/input-group.jsx +213 -0
- package/templates/next/files/components/ui/input-otp.jsx +170 -0
- package/templates/next/files/components/ui/item.jsx +206 -0
- package/templates/next/files/components/ui/menu.jsx +454 -82
- package/templates/next/files/components/ui/notice.jsx +126 -14
- package/templates/next/files/components/ui/pagination.jsx +156 -0
- package/templates/next/files/components/ui/popover.jsx +284 -0
- package/templates/next/files/components/ui/radio.jsx +193 -0
- package/templates/next/files/components/ui/rating.jsx +131 -0
- package/templates/next/files/components/ui/resizable.jsx +338 -0
- package/templates/next/files/components/ui/scroll-area.jsx +123 -0
- package/templates/next/files/components/ui/separator.jsx +119 -0
- package/templates/next/files/components/ui/sheet.jsx +96 -11
- package/templates/next/files/components/ui/slider.jsx +174 -0
- package/templates/next/files/components/ui/stat.jsx +574 -0
- package/templates/next/files/components/ui/steps.jsx +338 -0
- package/templates/next/files/components/ui/swatch.jsx +33 -0
- package/templates/next/files/components/ui/table.jsx +130 -0
- package/templates/next/files/components/ui/toast.jsx +440 -0
- package/templates/next/files/components/ui/toggle.jsx +195 -0
- package/templates/next/files/components/ui/tooltip.jsx +270 -0
- package/templates/next/template.json +264 -8
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { isValidElement, useCallback, useEffect, useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
4
|
+
import { createRoot } from "react-dom/client";
|
|
5
|
+
import { cx } from "./cx";
|
|
6
|
+
import { Button, IconButton } from "./button";
|
|
7
|
+
import { Icon } from "./icon";
|
|
8
|
+
import { Spinner } from "./feedback";
|
|
9
|
+
|
|
10
|
+
// Toast — a short line about something that just happened ("Saved",
|
|
11
|
+
// "Invite sent"), which leaves on its own. Call it from any client code;
|
|
12
|
+
// nothing needs mounting: the first toast mounts a host into the page's
|
|
13
|
+
// top layer (a manual popover, above sheets and menus). app/layout.jsx is
|
|
14
|
+
// fixed, so this is how an app gets toasts at all. Put <Toaster /> in a
|
|
15
|
+
// surface only to choose where they stack.
|
|
16
|
+
//
|
|
17
|
+
// toast("Saved") → id
|
|
18
|
+
// toast.success / .error / .info / .warning(title, options)
|
|
19
|
+
// toast.promise(promise, { loading, success, error })
|
|
20
|
+
// success / error: a string, (value) → string, or
|
|
21
|
+
// { title, description, action }; null dismisses. Returns the
|
|
22
|
+
// promise.
|
|
23
|
+
// toast.dismiss(id) one; no id = all
|
|
24
|
+
//
|
|
25
|
+
// options description the line under the title
|
|
26
|
+
// action { label, onClick } — one button; the toast
|
|
27
|
+
// closes after unless onClick calls
|
|
28
|
+
// event.preventDefault()
|
|
29
|
+
// duration ms, default 5000; Infinity stays until closed
|
|
30
|
+
// id reuse one to update a toast in place
|
|
31
|
+
//
|
|
32
|
+
// <Toaster position visible />
|
|
33
|
+
// position bottom-end (the default) · bottom-center ·
|
|
34
|
+
// top-end · top-center. On a phone every position
|
|
35
|
+
// is full width at its edge.
|
|
36
|
+
// visible how many show at once (3); older ones wait behind
|
|
37
|
+
//
|
|
38
|
+
// Newest in front; the rest stack behind and fan out on hover or focus,
|
|
39
|
+
// and every timer pauses while they do (and while the tab is hidden).
|
|
40
|
+
// Close with the ×, Escape, or a sideways swipe. Screen readers hear each
|
|
41
|
+
// toast once through a live region (assertive for .error). A toast is
|
|
42
|
+
// never the only record of something that matters: an error the user
|
|
43
|
+
// must act on is a Notice on the surface.
|
|
44
|
+
|
|
45
|
+
const DURATION = 5000;
|
|
46
|
+
const EXIT_MS = 200;
|
|
47
|
+
const GAP = 12;
|
|
48
|
+
const PEEK = 12;
|
|
49
|
+
const SWIPE = 80;
|
|
50
|
+
|
|
51
|
+
const TONES = {
|
|
52
|
+
neutral: { box: "border-border", icon: null },
|
|
53
|
+
success: { box: "border-success/40", icon: "check", color: "text-success" },
|
|
54
|
+
info: { box: "border-info/40", icon: "info", color: "text-info" },
|
|
55
|
+
warning: { box: "border-warning/50", icon: "warning", color: "text-warning" },
|
|
56
|
+
danger: { box: "border-destructive/50", icon: "warning", color: "text-destructive" },
|
|
57
|
+
loading: { box: "border-border", icon: null },
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Position → where the host sits. Class strings are written out whole:
|
|
61
|
+
// Tailwind reads them literally.
|
|
62
|
+
const PLACES = {
|
|
63
|
+
"bottom-end": "top-auto bottom-0 left-0 right-0 pb-[max(0.75rem,env(safe-area-inset-bottom))] sm:left-auto sm:right-0",
|
|
64
|
+
"bottom-center": "top-auto bottom-0 left-0 right-0 pb-[max(0.75rem,env(safe-area-inset-bottom))] sm:mx-auto",
|
|
65
|
+
"top-end": "top-0 bottom-auto left-0 right-0 sm:left-auto sm:right-0",
|
|
66
|
+
"top-center": "top-0 bottom-auto left-0 right-0 sm:mx-auto",
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// ---- The store: module-level, so toast() works from anywhere ----------
|
|
70
|
+
|
|
71
|
+
const EMPTY = { toasts: [], host: null };
|
|
72
|
+
const AUTO = { auto: true };
|
|
73
|
+
let state = EMPTY;
|
|
74
|
+
let seq = 0;
|
|
75
|
+
let auto = null;
|
|
76
|
+
const hosts = [];
|
|
77
|
+
const listeners = new Set();
|
|
78
|
+
|
|
79
|
+
function set(next) {
|
|
80
|
+
state = { ...state, ...next };
|
|
81
|
+
for (const l of listeners) l();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function subscribe(l) {
|
|
85
|
+
listeners.add(l);
|
|
86
|
+
return () => listeners.delete(l);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const reduced = () => typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
90
|
+
|
|
91
|
+
// No <Toaster /> on the page: lay one in <body>, in its own root.
|
|
92
|
+
function mount() {
|
|
93
|
+
if (typeof document === "undefined" || state.host || auto) return;
|
|
94
|
+
const el = document.createElement("div");
|
|
95
|
+
el.setAttribute("data-toaster", "");
|
|
96
|
+
document.body.appendChild(el);
|
|
97
|
+
auto = { el, root: createRoot(el) };
|
|
98
|
+
set({ host: AUTO });
|
|
99
|
+
auto.root.render(<Host token={AUTO} />);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function show(title, options, tone) {
|
|
103
|
+
const { id: wanted, description, action, duration } = options ?? {};
|
|
104
|
+
const id = wanted ?? `toast-${++seq}`;
|
|
105
|
+
const was = state.toasts.find((t) => t.id === id);
|
|
106
|
+
const item = {
|
|
107
|
+
id,
|
|
108
|
+
tone,
|
|
109
|
+
title,
|
|
110
|
+
description,
|
|
111
|
+
action,
|
|
112
|
+
duration: duration ?? (tone === "loading" ? Infinity : DURATION),
|
|
113
|
+
version: (was?.version ?? 0) + 1,
|
|
114
|
+
leaving: false,
|
|
115
|
+
};
|
|
116
|
+
set({ toasts: was ? state.toasts.map((t) => (t.id === id ? item : t)) : [item, ...state.toasts] });
|
|
117
|
+
mount();
|
|
118
|
+
return id;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function dismiss(id) {
|
|
122
|
+
const hit = (t) => id === undefined || t.id === id;
|
|
123
|
+
if (!state.toasts.some((t) => hit(t) && !t.leaving)) return;
|
|
124
|
+
set({ toasts: state.toasts.map((t) => (hit(t) ? { ...t, leaving: true } : t)) });
|
|
125
|
+
setTimeout(() => set({ toasts: state.toasts.filter((t) => !(hit(t) && t.leaving)) }), reduced() ? 0 : EXIT_MS);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function toast(title, options) {
|
|
129
|
+
return show(title, options, "neutral");
|
|
130
|
+
}
|
|
131
|
+
toast.success = (title, options) => show(title, options, "success");
|
|
132
|
+
toast.error = (title, options) => show(title, options, "danger");
|
|
133
|
+
toast.info = (title, options) => show(title, options, "info");
|
|
134
|
+
toast.warning = (title, options) => show(title, options, "warning");
|
|
135
|
+
toast.dismiss = dismiss;
|
|
136
|
+
toast.promise = (promise, { loading = "Working…", success, error } = {}) => {
|
|
137
|
+
const p = typeof promise === "function" ? promise() : promise;
|
|
138
|
+
const id = show(loading, {}, "loading");
|
|
139
|
+
const settle = (message, value, tone) => {
|
|
140
|
+
const m = typeof message === "function" ? message(value) : message;
|
|
141
|
+
if (m == null || m === false) dismiss(id);
|
|
142
|
+
else if (typeof m === "object" && !isValidElement(m)) show(m.title, { ...m, id }, tone);
|
|
143
|
+
else show(m, { id }, tone);
|
|
144
|
+
};
|
|
145
|
+
Promise.resolve(p).then(
|
|
146
|
+
(v) => settle(success ?? "Done", v, "success"),
|
|
147
|
+
(e) => settle(error ?? "Something went wrong", e, "danger"),
|
|
148
|
+
);
|
|
149
|
+
return p;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// ---- The host ---------------------------------------------------------
|
|
153
|
+
|
|
154
|
+
/** Where toasts stack. Optional — without one, the first toast mounts a
|
|
155
|
+
* bottom-end host by itself. The newest <Toaster /> on the page wins. */
|
|
156
|
+
export function Toaster({ position = "bottom-end", visible = 3, className }) {
|
|
157
|
+
const token = useRef(null);
|
|
158
|
+
if (!token.current) token.current = {};
|
|
159
|
+
useEffect(() => {
|
|
160
|
+
const own = token.current;
|
|
161
|
+
hosts.push(own);
|
|
162
|
+
set({ host: own });
|
|
163
|
+
if (auto) {
|
|
164
|
+
const a = auto;
|
|
165
|
+
auto = null;
|
|
166
|
+
setTimeout(() => {
|
|
167
|
+
a.root.unmount();
|
|
168
|
+
a.el.remove();
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
return () => {
|
|
172
|
+
hosts.splice(hosts.indexOf(own), 1);
|
|
173
|
+
set({ host: hosts[hosts.length - 1] ?? null });
|
|
174
|
+
if (!state.host && state.toasts.length) mount();
|
|
175
|
+
};
|
|
176
|
+
}, []);
|
|
177
|
+
return <Host token={token.current} position={position} visible={visible} className={className} />;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function Host({ token, position = "bottom-end", visible = 3, className }) {
|
|
181
|
+
const s = useSyncExternalStore(subscribe, () => state, () => EMPTY);
|
|
182
|
+
const pop = useRef(null);
|
|
183
|
+
const said = useRef(new Set());
|
|
184
|
+
const [hovered, setHovered] = useState(false);
|
|
185
|
+
const [focused, setFocused] = useState(false);
|
|
186
|
+
const [hidden, setHidden] = useState(false);
|
|
187
|
+
const [heights, setHeights] = useState({});
|
|
188
|
+
const [say, setSay] = useState({ polite: "", assertive: "" });
|
|
189
|
+
const mine = s.host === token;
|
|
190
|
+
const items = mine ? s.toasts : [];
|
|
191
|
+
const live = items.filter((t) => !t.leaving);
|
|
192
|
+
const newest = live[0]?.id;
|
|
193
|
+
const top = position.startsWith("top");
|
|
194
|
+
|
|
195
|
+
// In the top layer while there is something to show. A modal <dialog>
|
|
196
|
+
// opened since would sit above it: show again to rise over it.
|
|
197
|
+
useLayoutEffect(() => {
|
|
198
|
+
const p = pop.current;
|
|
199
|
+
if (!p?.showPopover) return;
|
|
200
|
+
const open = p.matches(":popover-open");
|
|
201
|
+
if (items.length && !open) p.showPopover();
|
|
202
|
+
else if (!items.length && open) p.hidePopover();
|
|
203
|
+
else if (open && newest && document.querySelector("dialog:modal") && !p.contains(document.activeElement)) {
|
|
204
|
+
p.hidePopover();
|
|
205
|
+
p.showPopover();
|
|
206
|
+
}
|
|
207
|
+
}, [items.length, newest]);
|
|
208
|
+
|
|
209
|
+
// An emptied stack cannot report the pointer leaving it.
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
if (items.length === 0) {
|
|
212
|
+
setHovered(false);
|
|
213
|
+
setFocused(false);
|
|
214
|
+
}
|
|
215
|
+
}, [items.length]);
|
|
216
|
+
|
|
217
|
+
useEffect(() => {
|
|
218
|
+
const on = () => setHidden(document.visibilityState === "hidden");
|
|
219
|
+
document.addEventListener("visibilitychange", on);
|
|
220
|
+
return () => document.removeEventListener("visibilitychange", on);
|
|
221
|
+
}, []);
|
|
222
|
+
|
|
223
|
+
// Each toast is announced once per version, a beat after the live
|
|
224
|
+
// region exists (a region born with its text is not read).
|
|
225
|
+
const timer = useRef(0);
|
|
226
|
+
useEffect(() => () => clearTimeout(timer.current), []);
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
const t = live.find((x) => !said.current.has(`${x.id}:${x.version}`));
|
|
229
|
+
if (!t) return;
|
|
230
|
+
said.current.add(`${t.id}:${t.version}`);
|
|
231
|
+
const text = [t.title, t.description].filter((x) => typeof x === "string" || typeof x === "number").join(". ");
|
|
232
|
+
if (!text) return;
|
|
233
|
+
clearTimeout(timer.current);
|
|
234
|
+
timer.current = setTimeout(() => setSay(t.tone === "danger" ? { polite: "", assertive: text } : { polite: text, assertive: "" }), 100);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
const measure = useCallback((id, h) => setHeights((prev) => (prev[id] === h ? prev : { ...prev, [id]: h })), []);
|
|
238
|
+
|
|
239
|
+
if (!mine) return null;
|
|
240
|
+
|
|
241
|
+
const expanded = hovered || focused;
|
|
242
|
+
const paused = expanded || hidden;
|
|
243
|
+
const shown = live.slice(0, visible);
|
|
244
|
+
let run = 0;
|
|
245
|
+
const offsets = shown.map((t) => {
|
|
246
|
+
const at = run;
|
|
247
|
+
run += (heights[t.id] ?? 0) + GAP;
|
|
248
|
+
return at;
|
|
249
|
+
});
|
|
250
|
+
const front = heights[shown[0]?.id] ?? 0;
|
|
251
|
+
const height = expanded ? Math.max(0, run - GAP) : front + PEEK * Math.max(0, shown.length - 1);
|
|
252
|
+
|
|
253
|
+
return (
|
|
254
|
+
<>
|
|
255
|
+
<div className="sr-only" role="status" aria-live="polite" aria-atomic="true">
|
|
256
|
+
{say.polite}
|
|
257
|
+
</div>
|
|
258
|
+
<div className="sr-only" aria-live="assertive" aria-atomic="true">
|
|
259
|
+
{say.assertive}
|
|
260
|
+
</div>
|
|
261
|
+
<section
|
|
262
|
+
ref={pop}
|
|
263
|
+
popover="manual"
|
|
264
|
+
aria-label="Notifications"
|
|
265
|
+
onPointerEnter={() => setHovered(true)}
|
|
266
|
+
onPointerLeave={() => setHovered(false)}
|
|
267
|
+
onFocus={() => setFocused(true)}
|
|
268
|
+
onBlur={(e) => {
|
|
269
|
+
if (!e.currentTarget.contains(e.relatedTarget)) setFocused(false);
|
|
270
|
+
}}
|
|
271
|
+
className={cx(
|
|
272
|
+
"pointer-events-none fixed z-50 m-0 h-auto w-full overflow-visible bg-transparent p-3 sm:w-96 sm:p-4",
|
|
273
|
+
PLACES[position] ?? PLACES["bottom-end"],
|
|
274
|
+
className,
|
|
275
|
+
)}
|
|
276
|
+
>
|
|
277
|
+
<ol className="relative transition-[height] duration-300 ease-out motion-reduce:transition-none" style={{ height }}>
|
|
278
|
+
{items.map((t) => {
|
|
279
|
+
const i = live.indexOf(t);
|
|
280
|
+
return (
|
|
281
|
+
<ToastItem
|
|
282
|
+
key={t.id}
|
|
283
|
+
t={t}
|
|
284
|
+
index={i}
|
|
285
|
+
top={top}
|
|
286
|
+
beyond={i >= visible}
|
|
287
|
+
offset={offsets[i] ?? 0}
|
|
288
|
+
expanded={expanded}
|
|
289
|
+
clip={!expanded && i > 0 ? front : undefined}
|
|
290
|
+
paused={paused}
|
|
291
|
+
onHeight={measure}
|
|
292
|
+
/>
|
|
293
|
+
);
|
|
294
|
+
})}
|
|
295
|
+
</ol>
|
|
296
|
+
</section>
|
|
297
|
+
</>
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function ToastItem({ t, index, top, beyond, offset, expanded, clip, paused, onHeight }) {
|
|
302
|
+
const inner = useRef(null);
|
|
303
|
+
const left = useRef(t.duration);
|
|
304
|
+
const ver = useRef(0);
|
|
305
|
+
const drag = useRef(null);
|
|
306
|
+
const last = useRef("");
|
|
307
|
+
const [dx, setDx] = useState(0);
|
|
308
|
+
const [exit, setExit] = useState(0);
|
|
309
|
+
const tone = TONES[t.tone] ?? TONES.neutral;
|
|
310
|
+
|
|
311
|
+
// The timer: counts down only while nothing holds the stack open; a
|
|
312
|
+
// new version (toast.promise settling, an update by id) starts it over.
|
|
313
|
+
useEffect(() => {
|
|
314
|
+
if (ver.current !== t.version) {
|
|
315
|
+
ver.current = t.version;
|
|
316
|
+
left.current = t.duration;
|
|
317
|
+
}
|
|
318
|
+
if (paused || t.leaving || !Number.isFinite(t.duration)) return;
|
|
319
|
+
const start = Date.now();
|
|
320
|
+
const h = setTimeout(() => dismiss(t.id), Math.max(0, left.current));
|
|
321
|
+
return () => {
|
|
322
|
+
clearTimeout(h);
|
|
323
|
+
left.current -= Date.now() - start;
|
|
324
|
+
};
|
|
325
|
+
}, [paused, t.leaving, t.version, t.duration, t.id]);
|
|
326
|
+
|
|
327
|
+
useLayoutEffect(() => {
|
|
328
|
+
const el = inner.current;
|
|
329
|
+
if (!el || typeof ResizeObserver === "undefined") return;
|
|
330
|
+
const ro = new ResizeObserver(() => onHeight(t.id, el.offsetHeight));
|
|
331
|
+
ro.observe(el);
|
|
332
|
+
onHeight(t.id, el.offsetHeight);
|
|
333
|
+
return () => ro.disconnect();
|
|
334
|
+
}, [t.id, onHeight]);
|
|
335
|
+
|
|
336
|
+
// Where it sits in the stack. A leaving toast keeps its last place
|
|
337
|
+
// while it fades, so the others close the gap at once.
|
|
338
|
+
const dir = top ? 1 : -1;
|
|
339
|
+
if (!t.leaving) {
|
|
340
|
+
const y = expanded ? offset : index * PEEK;
|
|
341
|
+
const k = expanded ? 1 : 1 - Math.min(index, 3) * 0.05;
|
|
342
|
+
last.current = `translateY(${dir * y}px) scale(${k})`;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
function onPointerDown(e) {
|
|
346
|
+
if (e.button !== 0 || e.target.closest("button, a, input, textarea, select")) return;
|
|
347
|
+
drag.current = { x: e.clientX, at: e.timeStamp };
|
|
348
|
+
e.currentTarget.setPointerCapture(e.pointerId);
|
|
349
|
+
}
|
|
350
|
+
function onPointerMove(e) {
|
|
351
|
+
if (drag.current) setDx(e.clientX - drag.current.x);
|
|
352
|
+
}
|
|
353
|
+
function onPointerUp(e) {
|
|
354
|
+
const d = drag.current;
|
|
355
|
+
drag.current = null;
|
|
356
|
+
if (!d) return;
|
|
357
|
+
const moved = e.clientX - d.x;
|
|
358
|
+
const fast = Math.abs(moved) > 10 && Math.abs(moved) / Math.max(1, e.timeStamp - d.at) > 0.5;
|
|
359
|
+
if (Math.abs(moved) > SWIPE || fast) {
|
|
360
|
+
setExit(Math.sign(moved) || 1);
|
|
361
|
+
dismiss(t.id);
|
|
362
|
+
} else setDx(0);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const dragging = drag.current !== null && dx !== 0;
|
|
366
|
+
const style = {
|
|
367
|
+
zIndex: 1000 - Math.max(index, 0),
|
|
368
|
+
transform: last.current,
|
|
369
|
+
transformOrigin: top ? "bottom center" : "top center",
|
|
370
|
+
height: clip,
|
|
371
|
+
touchAction: "pan-y",
|
|
372
|
+
};
|
|
373
|
+
if (dragging) {
|
|
374
|
+
style.translate = `${dx}px 0`;
|
|
375
|
+
style.opacity = Math.max(0, 1 - Math.abs(dx) / 240);
|
|
376
|
+
style.transition = "none";
|
|
377
|
+
} else if (exit) style.translate = `${exit * 110}% 0`;
|
|
378
|
+
|
|
379
|
+
return (
|
|
380
|
+
<li
|
|
381
|
+
style={style}
|
|
382
|
+
inert={beyond || undefined}
|
|
383
|
+
aria-hidden={beyond || undefined}
|
|
384
|
+
onPointerDown={onPointerDown}
|
|
385
|
+
onPointerMove={onPointerMove}
|
|
386
|
+
onPointerUp={onPointerUp}
|
|
387
|
+
onPointerCancel={() => {
|
|
388
|
+
drag.current = null;
|
|
389
|
+
setDx(0);
|
|
390
|
+
}}
|
|
391
|
+
onKeyDown={(e) => {
|
|
392
|
+
if (e.key === "Escape") dismiss(t.id);
|
|
393
|
+
}}
|
|
394
|
+
className={cx(
|
|
395
|
+
"pointer-events-auto absolute inset-x-0 select-none",
|
|
396
|
+
"transition-[opacity,translate,transform,height] duration-300 ease-out motion-reduce:transition-none",
|
|
397
|
+
top ? "top-0 starting:-translate-y-full" : "bottom-0 starting:translate-y-full",
|
|
398
|
+
"starting:opacity-0",
|
|
399
|
+
clip !== undefined && "overflow-hidden rounded-lg",
|
|
400
|
+
(t.leaving || beyond) && "opacity-0",
|
|
401
|
+
t.leaving && !exit && (top ? "-translate-y-2" : "translate-y-2"),
|
|
402
|
+
beyond && "pointer-events-none",
|
|
403
|
+
)}
|
|
404
|
+
>
|
|
405
|
+
<div
|
|
406
|
+
ref={inner}
|
|
407
|
+
className={cx(
|
|
408
|
+
"flex items-start gap-3 rounded-lg border bg-popover py-3 pl-4 pr-2 text-sm text-popover-foreground shadow-lg",
|
|
409
|
+
"[&>*]:transition-opacity [&>*]:duration-200 motion-reduce:[&>*]:transition-none",
|
|
410
|
+
tone.box,
|
|
411
|
+
clip !== undefined && "[&>*]:opacity-0",
|
|
412
|
+
)}
|
|
413
|
+
>
|
|
414
|
+
{t.tone === "loading" ? (
|
|
415
|
+
<Spinner size="sm" label={null} className="mt-0.5 text-muted-foreground" />
|
|
416
|
+
) : tone.icon ? (
|
|
417
|
+
<Icon name={tone.icon} className={cx("mt-0.5 shrink-0", tone.color)} />
|
|
418
|
+
) : null}
|
|
419
|
+
<div className="min-w-0 flex-1 py-px">
|
|
420
|
+
<p className="font-medium leading-snug [overflow-wrap:anywhere]">{t.title}</p>
|
|
421
|
+
{t.description ? <p className="mt-0.5 text-muted-foreground [overflow-wrap:anywhere]">{t.description}</p> : null}
|
|
422
|
+
</div>
|
|
423
|
+
{t.action ? (
|
|
424
|
+
<Button
|
|
425
|
+
size="sm"
|
|
426
|
+
variant="secondary"
|
|
427
|
+
className="-my-1 shrink-0"
|
|
428
|
+
onClick={(e) => {
|
|
429
|
+
t.action.onClick?.(e);
|
|
430
|
+
if (!e.defaultPrevented) dismiss(t.id);
|
|
431
|
+
}}
|
|
432
|
+
>
|
|
433
|
+
{t.action.label}
|
|
434
|
+
</Button>
|
|
435
|
+
) : null}
|
|
436
|
+
<IconButton icon="x" label="Dismiss" size="sm" className="-my-1.5 shrink-0" onClick={() => dismiss(t.id)} />
|
|
437
|
+
</div>
|
|
438
|
+
</li>
|
|
439
|
+
);
|
|
440
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useRef, useState } from "react";
|
|
4
|
+
import { cx } from "./cx";
|
|
5
|
+
import { Icon } from "./icon";
|
|
6
|
+
|
|
7
|
+
// Toggle — a button that stays down: bold on, pinned, "show archived".
|
|
8
|
+
// A real <button aria-pressed>, so Space and Enter work and a screen
|
|
9
|
+
// reader says "pressed". Controlled (`pressed` + `onPressedChange(next)`)
|
|
10
|
+
// or not (`defaultPressed`). A setting that saves is a Switch; a toggle
|
|
11
|
+
// changes what THIS view shows or does. Off reads muted, on reads lit
|
|
12
|
+
// (full text, the accent fill, a stronger edge) — never colour alone.
|
|
13
|
+
//
|
|
14
|
+
// variant secondary (bordered; the default) · quiet (no fill until pressed)
|
|
15
|
+
// size md (44px) · sm (36px)
|
|
16
|
+
// icon a name from ./icon; with no children the toggle is square
|
|
17
|
+
// and `label` is required (what a screen reader says)
|
|
18
|
+
//
|
|
19
|
+
// ToggleGroup below is a row of them as one control — the segmented
|
|
20
|
+
// control. Arrow keys move between items (roving focus: the row is one
|
|
21
|
+
// Tab stop), Space or Enter presses.
|
|
22
|
+
|
|
23
|
+
const VARIANTS = {
|
|
24
|
+
secondary:
|
|
25
|
+
"bg-secondary text-muted-foreground border-border hover:bg-accent hover:text-foreground " +
|
|
26
|
+
"aria-pressed:bg-accent aria-pressed:text-accent-foreground aria-pressed:border-foreground/50",
|
|
27
|
+
quiet:
|
|
28
|
+
"bg-transparent text-muted-foreground border-transparent hover:bg-accent hover:text-foreground " +
|
|
29
|
+
"aria-pressed:bg-accent aria-pressed:text-accent-foreground",
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// `square` is the icon-only toggle's own box, used INSTEAD of `box` —
|
|
33
|
+
// never a px-0 laid over box's padding: cx does not merge classes, so
|
|
34
|
+
// which of two paddings wins is CSS order, not the order written.
|
|
35
|
+
const SIZES = {
|
|
36
|
+
md: { box: "min-h-11 px-3 text-sm", square: "size-11 px-0 text-sm", glyph: 18 },
|
|
37
|
+
sm: { box: "min-h-9 px-2.5 text-sm", square: "size-9 px-0 text-sm", glyph: 16 },
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export function Toggle({
|
|
41
|
+
pressed,
|
|
42
|
+
defaultPressed = false,
|
|
43
|
+
onPressedChange,
|
|
44
|
+
variant = "secondary",
|
|
45
|
+
size = "md",
|
|
46
|
+
icon,
|
|
47
|
+
label,
|
|
48
|
+
className,
|
|
49
|
+
children,
|
|
50
|
+
onClick,
|
|
51
|
+
...rest
|
|
52
|
+
}) {
|
|
53
|
+
const [own, setOwn] = useState(defaultPressed);
|
|
54
|
+
const on = pressed ?? own;
|
|
55
|
+
const s = SIZES[size] ?? SIZES.md;
|
|
56
|
+
const square = icon && !children;
|
|
57
|
+
return (
|
|
58
|
+
<button
|
|
59
|
+
type="button"
|
|
60
|
+
aria-pressed={on}
|
|
61
|
+
aria-label={square ? label : undefined}
|
|
62
|
+
title={square ? label : undefined}
|
|
63
|
+
onClick={(e) => {
|
|
64
|
+
onClick?.(e);
|
|
65
|
+
if (e.defaultPrevented) return;
|
|
66
|
+
if (pressed === undefined) setOwn(!on);
|
|
67
|
+
onPressedChange?.(!on);
|
|
68
|
+
}}
|
|
69
|
+
className={cx(
|
|
70
|
+
"inline-flex items-center justify-center gap-2 rounded-md border font-medium whitespace-nowrap transition-colors",
|
|
71
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background",
|
|
72
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
73
|
+
VARIANTS[variant] ?? VARIANTS.secondary,
|
|
74
|
+
square ? s.square : s.box,
|
|
75
|
+
className,
|
|
76
|
+
)}
|
|
77
|
+
{...rest}
|
|
78
|
+
>
|
|
79
|
+
{icon ? <Icon name={icon} size={square ? s.glyph : 16} /> : null}
|
|
80
|
+
{children}
|
|
81
|
+
</button>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// As SIZES: `square` replaces `item` for an icon-only item.
|
|
86
|
+
const SEG = {
|
|
87
|
+
md: { track: "p-1", item: "min-h-9 px-3", square: "min-h-9 min-w-9 px-0", glyph: 18 },
|
|
88
|
+
sm: { track: "p-0.5", item: "min-h-8 px-2.5", square: "min-h-8 min-w-8 px-0", glyph: 16 },
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* A row of toggles as one control, the segmented look: a muted track,
|
|
93
|
+
* the pressed items raised. `type` single (exactly one pressed — pressing
|
|
94
|
+
* it again keeps it; a filter that can be off is `multiple`) · multiple.
|
|
95
|
+
* `value` is a string (single) or an array (multiple); `onChange` gets
|
|
96
|
+
* the same shape. md is 44px tall, sm 36px. Stretches when given a width
|
|
97
|
+
* (className="w-full"): the items share it.
|
|
98
|
+
*
|
|
99
|
+
* items [{ value, label, icon?, iconOnly?, disabled? }] — `iconOnly`
|
|
100
|
+
* shows the icon alone; `label` is then what a screen reader says
|
|
101
|
+
*/
|
|
102
|
+
export function ToggleGroup({
|
|
103
|
+
type = "single",
|
|
104
|
+
items,
|
|
105
|
+
value,
|
|
106
|
+
defaultValue,
|
|
107
|
+
onChange,
|
|
108
|
+
size = "md",
|
|
109
|
+
disabled,
|
|
110
|
+
className,
|
|
111
|
+
"aria-label": ariaLabel,
|
|
112
|
+
}) {
|
|
113
|
+
const multiple = type === "multiple";
|
|
114
|
+
const [own, setOwn] = useState(defaultValue ?? (multiple ? [] : undefined));
|
|
115
|
+
const current = value !== undefined ? value : own;
|
|
116
|
+
const refs = useRef([]);
|
|
117
|
+
const s = SEG[size] ?? SEG.md;
|
|
118
|
+
const live = (items ?? []).filter(Boolean);
|
|
119
|
+
|
|
120
|
+
const isOn = (v) => (multiple ? (current ?? []).includes(v) : current === v);
|
|
121
|
+
const usable = (i) => !disabled && !live[i]?.disabled;
|
|
122
|
+
|
|
123
|
+
function press(v) {
|
|
124
|
+
let next;
|
|
125
|
+
if (multiple) next = isOn(v) ? current.filter((x) => x !== v) : [...(current ?? []), v];
|
|
126
|
+
else if (current === v) return;
|
|
127
|
+
else next = v;
|
|
128
|
+
if (value === undefined) setOwn(next);
|
|
129
|
+
onChange?.(next);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// One Tab stop: the first pressed item, else the first usable one.
|
|
133
|
+
let stop = live.findIndex((it, i) => usable(i) && isOn(it.value));
|
|
134
|
+
if (stop < 0) stop = live.findIndex((_, i) => usable(i));
|
|
135
|
+
|
|
136
|
+
function onKeyDown(e, index) {
|
|
137
|
+
const step = e.key === "ArrowRight" || e.key === "ArrowDown" ? 1 : e.key === "ArrowLeft" || e.key === "ArrowUp" ? -1 : 0;
|
|
138
|
+
let next = null;
|
|
139
|
+
if (step) {
|
|
140
|
+
for (let k = 1; k <= live.length; k++) {
|
|
141
|
+
const i = (index + step * k + live.length) % live.length;
|
|
142
|
+
if (usable(i)) {
|
|
143
|
+
next = i;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} else if (e.key === "Home") next = live.findIndex((_, i) => usable(i));
|
|
148
|
+
else if (e.key === "End") next = live.findLastIndex((_, i) => usable(i));
|
|
149
|
+
if (next === null || next < 0) return;
|
|
150
|
+
e.preventDefault();
|
|
151
|
+
refs.current[next]?.focus();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (live.length === 0) return null;
|
|
155
|
+
|
|
156
|
+
return (
|
|
157
|
+
<div
|
|
158
|
+
role="group"
|
|
159
|
+
aria-label={ariaLabel}
|
|
160
|
+
className={cx("inline-flex max-w-full gap-1 rounded-md bg-muted", s.track, disabled && "opacity-50", className)}
|
|
161
|
+
>
|
|
162
|
+
{live.map((it, i) => {
|
|
163
|
+
const on = isOn(it.value);
|
|
164
|
+
const square = it.icon && it.iconOnly;
|
|
165
|
+
return (
|
|
166
|
+
<button
|
|
167
|
+
key={it.value}
|
|
168
|
+
ref={(el) => {
|
|
169
|
+
refs.current[i] = el;
|
|
170
|
+
}}
|
|
171
|
+
type="button"
|
|
172
|
+
aria-pressed={on}
|
|
173
|
+
aria-label={square ? it.label : undefined}
|
|
174
|
+
title={square ? it.label : undefined}
|
|
175
|
+
disabled={!usable(i)}
|
|
176
|
+
tabIndex={i === stop ? 0 : -1}
|
|
177
|
+
onClick={() => press(it.value)}
|
|
178
|
+
onKeyDown={(e) => onKeyDown(e, i)}
|
|
179
|
+
className={cx(
|
|
180
|
+
"inline-flex flex-1 items-center justify-center gap-2 rounded-sm text-sm font-medium whitespace-nowrap transition-colors",
|
|
181
|
+
"outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
182
|
+
"disabled:cursor-not-allowed",
|
|
183
|
+
!disabled && "disabled:opacity-50",
|
|
184
|
+
square ? s.square : s.item,
|
|
185
|
+
on ? "bg-background text-foreground shadow-sm ring-1 ring-border" : "text-muted-foreground hover:text-foreground",
|
|
186
|
+
)}
|
|
187
|
+
>
|
|
188
|
+
{it.icon ? <Icon name={it.icon} size={square ? s.glyph : 16} /> : null}
|
|
189
|
+
{square ? null : it.label}
|
|
190
|
+
</button>
|
|
191
|
+
);
|
|
192
|
+
})}
|
|
193
|
+
</div>
|
|
194
|
+
);
|
|
195
|
+
}
|