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,608 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useId, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { cx } from "./cx";
|
|
5
|
+
import { Icon } from "./icon";
|
|
6
|
+
import { Button } from "./button";
|
|
7
|
+
import { Sheet } from "./sheet";
|
|
8
|
+
import { panelClass, usePopoverPosition } from "./popover";
|
|
9
|
+
import {
|
|
10
|
+
CommandInput,
|
|
11
|
+
CommandList,
|
|
12
|
+
ItemIcon,
|
|
13
|
+
commandFilter,
|
|
14
|
+
listKeyDown,
|
|
15
|
+
optionId,
|
|
16
|
+
resolveActive,
|
|
17
|
+
useAsyncSearch,
|
|
18
|
+
useIsPhone,
|
|
19
|
+
withValues,
|
|
20
|
+
} from "./command";
|
|
21
|
+
|
|
22
|
+
// Combobox — pick one or many from a list you can search: a person, a
|
|
23
|
+
// company, a country, tags. A field-shaped trigger shows the choice; the
|
|
24
|
+
// panel beside it holds a search input and the options — Command's list and
|
|
25
|
+
// filter (./command), so the keys and the matching are the same everywhere.
|
|
26
|
+
// With `searchable={false}` it is the rich Select: the same trigger and
|
|
27
|
+
// options (icons, descriptions, groups) with no input, for a short list the
|
|
28
|
+
// native <select> cannot draw.
|
|
29
|
+
//
|
|
30
|
+
// options [{ value, label, description?, icon?, group?, keywords?,
|
|
31
|
+
// count?, disabled? }] — `icon` a glyph name or a node (an
|
|
32
|
+
// Avatar); `count` a number or short text at the option's
|
|
33
|
+
// right, muted ("15" beside a facet's value)
|
|
34
|
+
// value, defaultValue, onValueChange(value, option) — a value (null for
|
|
35
|
+
// none), or with `multiple` an array of values (and the
|
|
36
|
+
// options chosen)
|
|
37
|
+
// multiple chips in the trigger, each with a remove button; the
|
|
38
|
+
// panel stays open while you pick; Backspace in an empty
|
|
39
|
+
// search (or on the trigger) removes the last
|
|
40
|
+
// searchable true (default): a search input in the panel · false: the
|
|
41
|
+
// rich Select — focus stays on the trigger, arrows move,
|
|
42
|
+
// typing a letter jumps to the next option starting with it
|
|
43
|
+
// creatable offer `Create "typed"` when nothing matches exactly; true,
|
|
44
|
+
// or (text) => its label. onCreate(text) may return (or
|
|
45
|
+
// resolve) the new option; else it is { value: text, label: text }
|
|
46
|
+
// onSearch async (query, { signal }) → options, debounced; the list
|
|
47
|
+
// shows what it answers (a spinner meanwhile). A chosen
|
|
48
|
+
// option stays named after the results move on
|
|
49
|
+
// loading true while you fetch `options` yourself
|
|
50
|
+
// clearable an × that empties the choice
|
|
51
|
+
// disabled, invalid, name (hidden inputs, so a <form> posts the value)
|
|
52
|
+
// placeholder, searchPlaceholder, empty (shown when nothing matches)
|
|
53
|
+
// open, defaultOpen, onOpenChange(open) — the panel's state, controlled
|
|
54
|
+
// or not (default closed); light dismiss, Escape and a
|
|
55
|
+
// pick that closes report onOpenChange(false)
|
|
56
|
+
// label the name when it is not in a <Field> (a Field's label
|
|
57
|
+
// names it through `id`, and titles the phone sheet)
|
|
58
|
+
// side, align the panel's place, as Popover (default bottom · start);
|
|
59
|
+
// it is the trigger's width, 14rem at the least
|
|
60
|
+
// mobile sheet (default) · popover — on a phone (under 640px) the
|
|
61
|
+
// panel opens as a bottom Sheet: a popover under a field
|
|
62
|
+
// there is squeezed by the on-screen keyboard and half
|
|
63
|
+
// hidden; a sheet is the full width, within thumb reach,
|
|
64
|
+
// and its search sits above the keyboard. Multiple adds a
|
|
65
|
+
// Done button to it
|
|
66
|
+
//
|
|
67
|
+
// Every prop not named goes to the trigger button (aria-describedby for a
|
|
68
|
+
// Field's hint, onBlur…). In a Field, pass the same `id`:
|
|
69
|
+
//
|
|
70
|
+
// <Field id="owner" label="Owner"><Combobox id="owner" options={people} /></Field>
|
|
71
|
+
//
|
|
72
|
+
// ARIA: the trigger is role=combobox (its text is the value, the Field's
|
|
73
|
+
// label its name); the search input inside is a combobox too, pointing at
|
|
74
|
+
// the listbox with aria-activedescendant. Without a search, the trigger
|
|
75
|
+
// itself carries aria-activedescendant — the APG "select-only combobox".
|
|
76
|
+
|
|
77
|
+
const CREATE = "\u0000create";
|
|
78
|
+
const same = (a, b) => String(a).trim().toLowerCase() === String(b).trim().toLowerCase();
|
|
79
|
+
|
|
80
|
+
export function Combobox({
|
|
81
|
+
id,
|
|
82
|
+
options,
|
|
83
|
+
value,
|
|
84
|
+
defaultValue,
|
|
85
|
+
onValueChange,
|
|
86
|
+
multiple = false,
|
|
87
|
+
searchable = true,
|
|
88
|
+
creatable = false,
|
|
89
|
+
onCreate,
|
|
90
|
+
onSearch,
|
|
91
|
+
loading = false,
|
|
92
|
+
clearable = false,
|
|
93
|
+
disabled = false,
|
|
94
|
+
invalid = false,
|
|
95
|
+
name,
|
|
96
|
+
placeholder = "Select…",
|
|
97
|
+
searchPlaceholder = "Search…",
|
|
98
|
+
empty = "No results.",
|
|
99
|
+
label,
|
|
100
|
+
side = "bottom",
|
|
101
|
+
align = "start",
|
|
102
|
+
mobile = "sheet",
|
|
103
|
+
open,
|
|
104
|
+
defaultOpen = false,
|
|
105
|
+
onOpenChange,
|
|
106
|
+
className,
|
|
107
|
+
onKeyDown,
|
|
108
|
+
onKeyUp,
|
|
109
|
+
onBlur,
|
|
110
|
+
...rest
|
|
111
|
+
}) {
|
|
112
|
+
const uid = useId().replace(/[^\w-]/g, "");
|
|
113
|
+
const panelId = `${uid}-panel`;
|
|
114
|
+
const listId = `${uid}-list`;
|
|
115
|
+
const wrap = useRef(null);
|
|
116
|
+
const btn = useRef(null);
|
|
117
|
+
const panel = useRef(null);
|
|
118
|
+
const input = useRef(null);
|
|
119
|
+
const list = useRef(null);
|
|
120
|
+
const sheetBody = useRef(null);
|
|
121
|
+
const phone = useIsPhone() && mobile === "sheet";
|
|
122
|
+
|
|
123
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
124
|
+
const lastOpen = useRef(false);
|
|
125
|
+
// Every change of the panel's state passes here, so onOpenChange hears
|
|
126
|
+
// each one once, whoever made it (the trigger, a pick, light dismiss).
|
|
127
|
+
const setOpen = (now) => {
|
|
128
|
+
setIsOpen(now);
|
|
129
|
+
if (now !== lastOpen.current) {
|
|
130
|
+
lastOpen.current = now;
|
|
131
|
+
onOpenChange?.(now);
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
const [query, setQuery] = useState("");
|
|
135
|
+
const [active, setActive] = useState(null);
|
|
136
|
+
const [title, setTitle] = useState(label ?? placeholder);
|
|
137
|
+
const [width, setWidth] = useState(0);
|
|
138
|
+
const [created, setCreated] = useState([]);
|
|
139
|
+
const seed = useRef("");
|
|
140
|
+
const wasOpen = useRef(false);
|
|
141
|
+
const swallowSpace = useRef(false);
|
|
142
|
+
const typed = useRef({ text: "", at: 0 });
|
|
143
|
+
|
|
144
|
+
// The choice, as an array of string values either way.
|
|
145
|
+
const controlled = value !== undefined;
|
|
146
|
+
const [own, setOwn] = useState(defaultValue ?? (multiple ? [] : null));
|
|
147
|
+
const raw = controlled ? value : own;
|
|
148
|
+
const chosen = multiple ? (Array.isArray(raw) ? raw.map(String) : []) : raw == null || raw === "" ? [] : [String(raw)];
|
|
149
|
+
const key = chosen.join("\u0001");
|
|
150
|
+
const chosenSet = useMemo(() => new Set(key ? key.split("\u0001") : []), [key]);
|
|
151
|
+
|
|
152
|
+
// Every option seen, so a chosen one keeps its label (and icon) after a
|
|
153
|
+
// search replaced the list it came from.
|
|
154
|
+
const known = useRef(new Map());
|
|
155
|
+
const search = useAsyncSearch(onSearch, query, { enabled: isOpen });
|
|
156
|
+
const base = withValues(onSearch ? search.items ?? options : options);
|
|
157
|
+
const source = [...base, ...created.filter((c) => !base.some((o) => o.value === c.value))];
|
|
158
|
+
for (const o of source) known.current.set(o.value, o);
|
|
159
|
+
const optionOf = (v) => known.current.get(v) ?? { value: v, label: v };
|
|
160
|
+
|
|
161
|
+
let visible = searchable && !onSearch ? commandFilter(source, query) : source;
|
|
162
|
+
const text = query.trim();
|
|
163
|
+
if (creatable && text && !source.some((o) => same(o.label, text))) {
|
|
164
|
+
visible = [
|
|
165
|
+
...visible,
|
|
166
|
+
{ value: CREATE, label: typeof creatable === "function" ? creatable(text) : `Create "${text}"`, icon: "plus", create: true },
|
|
167
|
+
];
|
|
168
|
+
}
|
|
169
|
+
const current = resolveActive(visible, active);
|
|
170
|
+
const activeIndex = visible.findIndex((o) => o.value === current);
|
|
171
|
+
const activeId = activeIndex >= 0 ? optionId(listId, activeIndex) : null;
|
|
172
|
+
const busy = loading || search.loading;
|
|
173
|
+
// The list draws a count at an option's right inside its label: the
|
|
174
|
+
// filter, the typeahead and the chips keep reading the plain label.
|
|
175
|
+
const shown = visible.some((o) => o.count != null && o.count !== "")
|
|
176
|
+
? visible.map((o) =>
|
|
177
|
+
o.count == null || o.count === ""
|
|
178
|
+
? o
|
|
179
|
+
: {
|
|
180
|
+
...o,
|
|
181
|
+
label: (
|
|
182
|
+
<span className="flex items-center gap-2">
|
|
183
|
+
<span className="min-w-0 flex-1 truncate">{o.label}</span>
|
|
184
|
+
<span className="sr-only">, </span>
|
|
185
|
+
<span className="shrink-0 text-xs tabular-nums text-muted-foreground">{o.count}</span>
|
|
186
|
+
</span>
|
|
187
|
+
),
|
|
188
|
+
},
|
|
189
|
+
)
|
|
190
|
+
: visible;
|
|
191
|
+
|
|
192
|
+
usePopoverPosition(wrap, panel, { side, align });
|
|
193
|
+
|
|
194
|
+
// The panel is the trigger's width, kept as the field resizes.
|
|
195
|
+
useEffect(() => {
|
|
196
|
+
const el = wrap.current;
|
|
197
|
+
if (!el) return;
|
|
198
|
+
const ro = new ResizeObserver(() => setWidth(el.offsetWidth));
|
|
199
|
+
ro.observe(el);
|
|
200
|
+
return () => ro.disconnect();
|
|
201
|
+
}, []);
|
|
202
|
+
|
|
203
|
+
// `open` drives the panel; `defaultOpen` opens it once, on mount.
|
|
204
|
+
const want = open ?? null;
|
|
205
|
+
useEffect(() => {
|
|
206
|
+
if (want === null) return;
|
|
207
|
+
if (want && !lastOpen.current) show();
|
|
208
|
+
else if (!want && lastOpen.current) hide();
|
|
209
|
+
}, [want]); // eslint-disable-line react-hooks/exhaustive-deps
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
if (defaultOpen && open === undefined) show();
|
|
212
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
213
|
+
|
|
214
|
+
// Focus into the panel once it shows: the search, or (a phone sheet with
|
|
215
|
+
// no search) the list itself.
|
|
216
|
+
useEffect(() => {
|
|
217
|
+
if (!isOpen) return;
|
|
218
|
+
if (searchable) input.current?.focus({ preventScroll: true });
|
|
219
|
+
else if (phone) list.current?.focus({ preventScroll: true });
|
|
220
|
+
}, [isOpen, searchable, phone]);
|
|
221
|
+
|
|
222
|
+
// ─── open and close ────────────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
function fieldLabel() {
|
|
225
|
+
if (!id || typeof document === "undefined") return null;
|
|
226
|
+
const el = document.querySelector(`label[for="${CSS.escape(id)}"]`);
|
|
227
|
+
return el?.textContent?.replace(/\s*\*$/, "").trim() || null;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Every opening starts here: the typed seed (or nothing), the choice
|
|
231
|
+
// active, the title read from the Field.
|
|
232
|
+
function begin() {
|
|
233
|
+
setQuery(searchable ? seed.current : "");
|
|
234
|
+
seed.current = "";
|
|
235
|
+
setActive(chosen[0] ?? null);
|
|
236
|
+
setTitle(label ?? fieldLabel() ?? placeholder);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function show() {
|
|
240
|
+
if (disabled) return;
|
|
241
|
+
// Read the width live: a `defaultOpen` shows from the first effect,
|
|
242
|
+
// before the hydrated render has learnt it is on a phone.
|
|
243
|
+
if (phone || (mobile === "sheet" && window.matchMedia("(max-width: 639.98px)").matches)) {
|
|
244
|
+
begin();
|
|
245
|
+
setOpen(true);
|
|
246
|
+
} else if (!panel.current?.matches(":popover-open")) {
|
|
247
|
+
panel.current?.showPopover();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function hide() {
|
|
252
|
+
if (phone) {
|
|
253
|
+
// Close the <dialog> itself: it hands focus back to the trigger.
|
|
254
|
+
const dialog = sheetBody.current?.closest("dialog");
|
|
255
|
+
if (dialog?.open) dialog.close();
|
|
256
|
+
else setOpen(false);
|
|
257
|
+
} else if (panel.current?.matches(":popover-open")) {
|
|
258
|
+
panel.current.hidePopover();
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// The popover's own opens and closes (the trigger, light dismiss, Esc).
|
|
263
|
+
function onToggle(e) {
|
|
264
|
+
const now = e.newState === "open";
|
|
265
|
+
if (now) begin();
|
|
266
|
+
else {
|
|
267
|
+
const at = document.activeElement;
|
|
268
|
+
if (!at || at === document.body || panel.current?.contains(at)) btn.current?.focus({ preventScroll: true });
|
|
269
|
+
}
|
|
270
|
+
setOpen(now);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// ─── choosing ──────────────────────────────────────────────────────
|
|
274
|
+
|
|
275
|
+
function commit(next) {
|
|
276
|
+
if (multiple) {
|
|
277
|
+
if (!controlled) setOwn(next);
|
|
278
|
+
onValueChange?.(next, next.map(optionOf));
|
|
279
|
+
} else {
|
|
280
|
+
const v = next[0] ?? null;
|
|
281
|
+
if (!controlled) setOwn(v);
|
|
282
|
+
onValueChange?.(v, v == null ? null : optionOf(v));
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
function choose(v) {
|
|
287
|
+
if (multiple) {
|
|
288
|
+
commit(chosenSet.has(v) ? chosen.filter((x) => x !== v) : [...chosen, v]);
|
|
289
|
+
setActive(v);
|
|
290
|
+
} else {
|
|
291
|
+
commit([v]);
|
|
292
|
+
hide();
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
async function create(typedText) {
|
|
297
|
+
let made = null;
|
|
298
|
+
try {
|
|
299
|
+
made = await onCreate?.(typedText);
|
|
300
|
+
} catch {
|
|
301
|
+
return; // the caller refused it; its own error shows where it chose
|
|
302
|
+
}
|
|
303
|
+
const option = made && typeof made === "object" ? withValues([made])[0] : { value: typedText, label: typedText };
|
|
304
|
+
known.current.set(option.value, option);
|
|
305
|
+
setCreated((c) => [...c.filter((o) => o.value !== option.value), option]);
|
|
306
|
+
setQuery("");
|
|
307
|
+
if (multiple) {
|
|
308
|
+
commit([...chosen.filter((x) => x !== option.value), option.value]);
|
|
309
|
+
setActive(option.value);
|
|
310
|
+
} else {
|
|
311
|
+
commit([option.value]);
|
|
312
|
+
hide();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function pick(item) {
|
|
317
|
+
if (item.create) create(text);
|
|
318
|
+
else choose(item.value);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function remove(v) {
|
|
322
|
+
commit(chosen.filter((x) => x !== v));
|
|
323
|
+
btn.current?.focus({ preventScroll: true });
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// ─── keys ──────────────────────────────────────────────────────────
|
|
327
|
+
|
|
328
|
+
const printable = (e) => e.key.length === 1 && e.key !== " " && !e.metaKey && !e.ctrlKey && !e.altKey;
|
|
329
|
+
|
|
330
|
+
// Select-only: a letter jumps to the next option starting with it;
|
|
331
|
+
// letters typed quickly spell a prefix; one letter repeated cycles.
|
|
332
|
+
function typeahead(ch) {
|
|
333
|
+
const now = Date.now();
|
|
334
|
+
const t = typed.current;
|
|
335
|
+
t.text = now - t.at > 700 ? ch : t.text + ch;
|
|
336
|
+
t.at = now;
|
|
337
|
+
const repeat = [...t.text].every((c) => c === t.text[0]);
|
|
338
|
+
const q = (repeat ? t.text[0] : t.text).toLowerCase();
|
|
339
|
+
const live = visible.filter((o) => !o.disabled);
|
|
340
|
+
const at = Math.max(0, live.findIndex((o) => o.value === current));
|
|
341
|
+
const from = repeat ? at + 1 : at;
|
|
342
|
+
const order = [...live.slice(from), ...live.slice(0, from)];
|
|
343
|
+
const hit = order.find((o) => String(o.label).toLowerCase().startsWith(q));
|
|
344
|
+
if (hit) setActive(hit.value);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function onTriggerKey(e) {
|
|
348
|
+
onKeyDown?.(e);
|
|
349
|
+
if (e.defaultPrevented || disabled) return;
|
|
350
|
+
const open = isOpen && !phone;
|
|
351
|
+
if (!open) {
|
|
352
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
353
|
+
e.preventDefault();
|
|
354
|
+
show();
|
|
355
|
+
} else if (e.key === "Backspace" && multiple && chosen.length) {
|
|
356
|
+
e.preventDefault();
|
|
357
|
+
commit(chosen.slice(0, -1));
|
|
358
|
+
} else if (printable(e)) {
|
|
359
|
+
e.preventDefault();
|
|
360
|
+
if (searchable) seed.current = e.key;
|
|
361
|
+
show();
|
|
362
|
+
}
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
// Open without a search: the keys work the list from the trigger.
|
|
366
|
+
if (e.key === "Tab") return hide();
|
|
367
|
+
if (e.key === " " || e.key === "Enter") {
|
|
368
|
+
e.preventDefault();
|
|
369
|
+
swallowSpace.current = e.key === " ";
|
|
370
|
+
const item = visible.find((o) => o.value === current);
|
|
371
|
+
if (item && !item.disabled) pick(item);
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (listKeyDown(e, visible, current, setActive, pick)) return;
|
|
375
|
+
if (printable(e)) {
|
|
376
|
+
e.preventDefault();
|
|
377
|
+
typeahead(e.key);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// A Space that picked must not also click the trigger open again.
|
|
382
|
+
function onTriggerKeyUp(e) {
|
|
383
|
+
onKeyUp?.(e);
|
|
384
|
+
if (e.key === " " && swallowSpace.current) {
|
|
385
|
+
e.preventDefault();
|
|
386
|
+
swallowSpace.current = false;
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
function onSearchKey(e) {
|
|
391
|
+
if (listKeyDown(e, visible, current, setActive, pick)) return;
|
|
392
|
+
if (e.key === "Backspace" && multiple && !query && chosen.length) {
|
|
393
|
+
e.preventDefault();
|
|
394
|
+
commit(chosen.slice(0, -1));
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
// A phone sheet without a search: the focused listbox takes the keys.
|
|
399
|
+
function onListKey(e) {
|
|
400
|
+
if (e.key === " ") {
|
|
401
|
+
e.preventDefault();
|
|
402
|
+
const item = visible.find((o) => o.value === current);
|
|
403
|
+
if (item && !item.disabled) pick(item);
|
|
404
|
+
return;
|
|
405
|
+
}
|
|
406
|
+
if (listKeyDown(e, visible, current, setActive, pick)) return;
|
|
407
|
+
if (printable(e)) typeahead(e.key);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Focus leaving for anything outside the field and its panel closes it.
|
|
411
|
+
function leaving(e) {
|
|
412
|
+
const to = e.relatedTarget;
|
|
413
|
+
if (!to || phone) return;
|
|
414
|
+
if (panel.current?.contains(to) || wrap.current?.contains(to)) return;
|
|
415
|
+
hide();
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// ─── the trigger ───────────────────────────────────────────────────
|
|
419
|
+
|
|
420
|
+
const one = !multiple && chosen.length ? optionOf(chosen[0]) : null;
|
|
421
|
+
const showClear = clearable && chosen.length > 0 && !disabled;
|
|
422
|
+
|
|
423
|
+
const body = (
|
|
424
|
+
<>
|
|
425
|
+
{searchable ? (
|
|
426
|
+
<CommandInput
|
|
427
|
+
inputRef={input}
|
|
428
|
+
listId={listId}
|
|
429
|
+
activeId={activeId}
|
|
430
|
+
busy={busy && visible.length > 0}
|
|
431
|
+
aria-label={searchPlaceholder || `Search ${title}`}
|
|
432
|
+
placeholder={searchPlaceholder}
|
|
433
|
+
value={query}
|
|
434
|
+
onChange={(e) => {
|
|
435
|
+
setQuery(e.target.value);
|
|
436
|
+
setActive(null);
|
|
437
|
+
}}
|
|
438
|
+
onKeyDown={onSearchKey}
|
|
439
|
+
/>
|
|
440
|
+
) : null}
|
|
441
|
+
<CommandList
|
|
442
|
+
id={listId}
|
|
443
|
+
label={title}
|
|
444
|
+
items={shown}
|
|
445
|
+
active={current}
|
|
446
|
+
onActive={setActive}
|
|
447
|
+
onPick={pick}
|
|
448
|
+
selected={chosenSet}
|
|
449
|
+
multiple={multiple}
|
|
450
|
+
empty={empty}
|
|
451
|
+
loading={busy}
|
|
452
|
+
error={search.error}
|
|
453
|
+
focusable={phone && !searchable}
|
|
454
|
+
onKeyDown={phone && !searchable ? onListKey : undefined}
|
|
455
|
+
listRef={list}
|
|
456
|
+
// On a phone the list scrolls, not the sheet, so the search stays put.
|
|
457
|
+
className={phone ? "max-h-[55dvh]" : undefined}
|
|
458
|
+
/>
|
|
459
|
+
</>
|
|
460
|
+
);
|
|
461
|
+
|
|
462
|
+
return (
|
|
463
|
+
<>
|
|
464
|
+
<div
|
|
465
|
+
ref={wrap}
|
|
466
|
+
onPointerDown={() => {
|
|
467
|
+
wasOpen.current = isOpen;
|
|
468
|
+
}}
|
|
469
|
+
// A press on the field (not on one of its buttons) opens it; a
|
|
470
|
+
// press while open was the light dismiss that closed it.
|
|
471
|
+
onClick={(e) => {
|
|
472
|
+
if (disabled || e.target.closest("button")) return;
|
|
473
|
+
btn.current?.focus({ preventScroll: true });
|
|
474
|
+
if (!wasOpen.current) show();
|
|
475
|
+
}}
|
|
476
|
+
className={cx(
|
|
477
|
+
"relative flex w-full min-h-11 cursor-pointer flex-wrap items-center gap-1 rounded-md border border-input bg-background pl-3 text-sm text-foreground",
|
|
478
|
+
"has-[[data-combobox-trigger]:focus-visible]:ring-2 has-[[data-combobox-trigger]:focus-visible]:ring-ring",
|
|
479
|
+
"has-[[data-combobox-trigger][aria-invalid=true]]:border-destructive",
|
|
480
|
+
showClear ? "pr-16" : "pr-9",
|
|
481
|
+
multiple && chosen.length > 0 && "py-1.5 pl-1.5",
|
|
482
|
+
disabled && "cursor-not-allowed opacity-50",
|
|
483
|
+
className,
|
|
484
|
+
)}
|
|
485
|
+
>
|
|
486
|
+
{multiple
|
|
487
|
+
? chosen.map((v) => {
|
|
488
|
+
const o = optionOf(v);
|
|
489
|
+
return (
|
|
490
|
+
<span
|
|
491
|
+
key={v}
|
|
492
|
+
className="inline-flex min-h-7 max-w-full items-center gap-1 rounded-sm border border-border bg-secondary pl-2 pr-0.5 text-xs text-secondary-foreground"
|
|
493
|
+
>
|
|
494
|
+
{typeof o.icon === "string" ? <Icon name={o.icon} size={12} className="shrink-0 text-muted-foreground" /> : null}
|
|
495
|
+
<span className="truncate">{o.label}</span>
|
|
496
|
+
{disabled ? (
|
|
497
|
+
<span className="w-1.5" />
|
|
498
|
+
) : (
|
|
499
|
+
<button
|
|
500
|
+
type="button"
|
|
501
|
+
aria-label={`Remove ${o.label}`}
|
|
502
|
+
onClick={() => remove(v)}
|
|
503
|
+
className="grid size-6 shrink-0 place-items-center rounded-sm text-muted-foreground outline-none hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"
|
|
504
|
+
>
|
|
505
|
+
<Icon name="x" size={12} />
|
|
506
|
+
</button>
|
|
507
|
+
)}
|
|
508
|
+
</span>
|
|
509
|
+
);
|
|
510
|
+
})
|
|
511
|
+
: null}
|
|
512
|
+
<button
|
|
513
|
+
ref={btn}
|
|
514
|
+
id={id}
|
|
515
|
+
type="button"
|
|
516
|
+
role="combobox"
|
|
517
|
+
data-combobox-trigger=""
|
|
518
|
+
disabled={disabled}
|
|
519
|
+
aria-label={label}
|
|
520
|
+
aria-haspopup={searchable ? "dialog" : "listbox"}
|
|
521
|
+
aria-expanded={isOpen}
|
|
522
|
+
aria-controls={isOpen ? (searchable && !phone ? panelId : listId) : undefined}
|
|
523
|
+
aria-activedescendant={isOpen && !searchable && !phone ? activeId ?? undefined : undefined}
|
|
524
|
+
aria-invalid={invalid || undefined}
|
|
525
|
+
popoverTarget={phone ? undefined : panelId}
|
|
526
|
+
onClick={phone ? () => show() : undefined}
|
|
527
|
+
onKeyDown={onTriggerKey}
|
|
528
|
+
onKeyUp={onTriggerKeyUp}
|
|
529
|
+
onBlur={(e) => {
|
|
530
|
+
onBlur?.(e);
|
|
531
|
+
if (!searchable) leaving(e);
|
|
532
|
+
}}
|
|
533
|
+
className={cx(
|
|
534
|
+
"flex min-h-9 min-w-12 flex-1 items-center gap-2 self-stretch text-left outline-none disabled:cursor-not-allowed",
|
|
535
|
+
multiple && chosen.length > 0 && "pl-1",
|
|
536
|
+
)}
|
|
537
|
+
{...rest}
|
|
538
|
+
>
|
|
539
|
+
{multiple ? (
|
|
540
|
+
chosen.length ? (
|
|
541
|
+
<span className="sr-only">{chosen.map((v) => optionOf(v).label).join(", ")}</span>
|
|
542
|
+
) : (
|
|
543
|
+
<span className="truncate text-muted-foreground">{placeholder}</span>
|
|
544
|
+
)
|
|
545
|
+
) : one ? (
|
|
546
|
+
<>
|
|
547
|
+
<ItemIcon icon={one.icon} />
|
|
548
|
+
<span className="truncate">{one.label}</span>
|
|
549
|
+
</>
|
|
550
|
+
) : (
|
|
551
|
+
<span className="truncate text-muted-foreground">{placeholder}</span>
|
|
552
|
+
)}
|
|
553
|
+
</button>
|
|
554
|
+
{showClear ? (
|
|
555
|
+
<button
|
|
556
|
+
type="button"
|
|
557
|
+
aria-label="Clear"
|
|
558
|
+
onClick={() => {
|
|
559
|
+
commit([]);
|
|
560
|
+
btn.current?.focus({ preventScroll: true });
|
|
561
|
+
}}
|
|
562
|
+
className="absolute right-8 top-1/2 grid size-7 -translate-y-1/2 place-items-center rounded-sm text-muted-foreground outline-none hover:bg-accent hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring"
|
|
563
|
+
>
|
|
564
|
+
<Icon name="x" size={14} />
|
|
565
|
+
</button>
|
|
566
|
+
) : null}
|
|
567
|
+
<Icon name="chevrons-up-down" className="pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground" />
|
|
568
|
+
{name ? chosen.map((v) => <input key={v} type="hidden" name={name} value={v} />) : null}
|
|
569
|
+
</div>
|
|
570
|
+
|
|
571
|
+
{phone ? (
|
|
572
|
+
isOpen ? (
|
|
573
|
+
<Sheet
|
|
574
|
+
open
|
|
575
|
+
side="bottom"
|
|
576
|
+
title={title}
|
|
577
|
+
onClose={() => setOpen(false)}
|
|
578
|
+
footer={
|
|
579
|
+
multiple ? (
|
|
580
|
+
<Button variant="primary" onClick={hide} className="w-full">
|
|
581
|
+
Done{chosen.length ? ` · ${chosen.length} chosen` : ""}
|
|
582
|
+
</Button>
|
|
583
|
+
) : null
|
|
584
|
+
}
|
|
585
|
+
>
|
|
586
|
+
<div ref={sheetBody} className="-mx-4 -my-4">
|
|
587
|
+
{body}
|
|
588
|
+
</div>
|
|
589
|
+
</Sheet>
|
|
590
|
+
) : null
|
|
591
|
+
) : (
|
|
592
|
+
<div
|
|
593
|
+
ref={panel}
|
|
594
|
+
id={panelId}
|
|
595
|
+
popover="auto"
|
|
596
|
+
role={searchable ? "dialog" : undefined}
|
|
597
|
+
aria-label={searchable ? title : undefined}
|
|
598
|
+
onToggle={onToggle}
|
|
599
|
+
onBlur={leaving}
|
|
600
|
+
className={panelClass("auto", "overflow-hidden p-0 text-sm")}
|
|
601
|
+
style={width ? { width: `max(${width}px, 14rem)` } : undefined}
|
|
602
|
+
>
|
|
603
|
+
{body}
|
|
604
|
+
</div>
|
|
605
|
+
)}
|
|
606
|
+
</>
|
|
607
|
+
);
|
|
608
|
+
}
|