makersclaw 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +41 -1
- package/THIRD-PARTY-NOTICES.md +180 -0
- package/package.json +15 -8
- package/r/annotate.json +62 -0
- package/r/approval-request.json +52 -0
- package/r/audio-player.json +74 -0
- package/r/auth-form.json +55 -0
- package/r/board.json +55 -0
- package/r/calendar-view.json +105 -0
- package/r/cart.json +62 -0
- package/r/chart.json +83 -0
- package/r/chat.json +95 -0
- package/r/code-editor.json +94 -0
- package/r/comment-box.json +64 -0
- package/r/contact-section.json +53 -0
- package/r/core.json +341 -0
- package/r/csv-import.json +63 -0
- package/r/data-table.json +69 -0
- package/r/diagram.json +74 -0
- package/r/doc-editor.json +82 -0
- package/r/doc-page.json +61 -0
- package/r/email-render.json +73 -0
- package/r/faq.json +50 -0
- package/r/file-upload.json +54 -0
- package/r/flow-canvas.json +93 -0
- package/r/footer.json +52 -0
- package/r/gantt.json +70 -0
- package/r/job-panel.json +56 -0
- package/r/json-editor.json +66 -0
- package/r/map.json +89 -0
- package/r/menubar.json +52 -0
- package/r/mind-map.json +67 -0
- package/r/navigation-menu.json +52 -0
- package/r/order-detail.json +54 -0
- package/r/org-chart.json +66 -0
- package/r/page-builder.json +105 -0
- package/r/payment-methods.json +51 -0
- package/r/pdf-document.json +79 -0
- package/r/pdf-viewer.json +88 -0
- package/r/product-detail.json +76 -0
- package/r/product-grid.json +65 -0
- package/r/record-form.json +67 -0
- package/r/record-notes.json +55 -0
- package/r/registry.json +3612 -0
- package/r/search-dialog.json +51 -0
- package/r/settings-list.json +66 -0
- package/r/setup-checklist.json +51 -0
- package/r/share-dialog.json +52 -0
- package/r/sidebar.json +69 -0
- package/r/signature-pad.json +72 -0
- package/r/sketch-canvas.json +99 -0
- package/r/spreadsheet.json +90 -0
- package/r/stat-cards.json +66 -0
- package/r/task-list.json +63 -0
- package/r/task-model.json +98 -0
- package/r/testimonials.json +52 -0
- package/r/transaction-list.json +53 -0
- package/r/whiteboard.json +66 -0
- package/registry/blocks/annotate/README.md +179 -0
- package/registry/blocks/annotate/annotate-data.js +250 -0
- package/registry/blocks/annotate/annotate.jsx +646 -0
- package/registry/blocks/annotate/block.json +10 -0
- package/registry/blocks/annotate/demo.jsx +135 -0
- package/registry/blocks/annotate/index.js +15 -0
- package/registry/blocks/approval-request/README.md +116 -0
- package/registry/blocks/approval-request/approval-request.jsx +386 -0
- package/registry/blocks/approval-request/block.json +10 -0
- package/registry/blocks/approval-request/demo.jsx +127 -0
- package/registry/blocks/approval-request/index.js +4 -0
- package/registry/blocks/audio-player/README.md +167 -0
- package/registry/blocks/audio-player/audio-player.jsx +623 -0
- package/registry/blocks/audio-player/block.json +14 -0
- package/registry/blocks/audio-player/colors.js +109 -0
- package/registry/blocks/audio-player/demo.jsx +209 -0
- package/registry/blocks/audio-player/index.js +6 -0
- package/registry/blocks/audio-player/time.js +67 -0
- package/registry/blocks/audio-player/wavesurfer.js +9 -0
- package/registry/blocks/auth-form/README.md +126 -0
- package/registry/blocks/auth-form/auth-form.jsx +568 -0
- package/registry/blocks/auth-form/block.json +10 -0
- package/registry/blocks/auth-form/demo.jsx +131 -0
- package/registry/blocks/auth-form/index.js +3 -0
- package/registry/blocks/board/README.md +64 -13
- package/registry/blocks/board/block.json +2 -2
- package/registry/blocks/board/board.jsx +237 -94
- package/registry/blocks/board/demo.jsx +103 -24
- package/registry/blocks/calendar-view/README.md +180 -0
- package/registry/blocks/calendar-view/agenda.jsx +147 -0
- package/registry/blocks/calendar-view/block.json +76 -0
- package/registry/blocks/calendar-view/calendar-model.js +442 -0
- package/registry/blocks/calendar-view/calendar.jsx +627 -0
- package/registry/blocks/calendar-view/demo.jsx +195 -0
- package/registry/blocks/calendar-view/draft.jsx +49 -0
- package/registry/blocks/calendar-view/index.js +39 -0
- package/registry/blocks/calendar-view/month.jsx +346 -0
- package/registry/blocks/calendar-view/paint.js +69 -0
- package/registry/blocks/calendar-view/time-grid.jsx +527 -0
- package/registry/blocks/calendar-view/tray.jsx +87 -0
- package/registry/blocks/cart/README.md +146 -0
- package/registry/blocks/cart/block.json +10 -0
- package/registry/blocks/cart/cart.jsx +597 -0
- package/registry/blocks/cart/demo.jsx +98 -0
- package/registry/blocks/cart/index.js +4 -0
- package/registry/blocks/cart/money.js +28 -0
- package/registry/blocks/chart/README.md +316 -0
- package/registry/blocks/chart/block.json +10 -0
- package/registry/blocks/chart/cartesian.jsx +642 -0
- package/registry/blocks/chart/core.jsx +262 -0
- package/registry/blocks/chart/demo.jsx +357 -0
- package/registry/blocks/chart/heatmap.jsx +336 -0
- package/registry/blocks/chart/index.js +8 -0
- package/registry/blocks/chart/pie.jsx +245 -0
- package/registry/blocks/chart/sparkline.jsx +88 -0
- package/registry/blocks/chat/README.md +273 -0
- package/registry/blocks/chat/attachment.jsx +95 -0
- package/registry/blocks/chat/block.json +10 -0
- package/registry/blocks/chat/chat.jsx +132 -0
- package/registry/blocks/chat/composer.jsx +364 -0
- package/registry/blocks/chat/demo.jsx +578 -0
- package/registry/blocks/chat/header.jsx +34 -0
- package/registry/blocks/chat/index.js +9 -0
- package/registry/blocks/chat/message.jsx +450 -0
- package/registry/blocks/chat/scroller.jsx +247 -0
- package/registry/blocks/chat/text.jsx +104 -0
- package/registry/blocks/code-editor/README.md +210 -0
- package/registry/blocks/code-editor/block.json +22 -0
- package/registry/blocks/code-editor/code-editor.jsx +534 -0
- package/registry/blocks/code-editor/codemirror.js +38 -0
- package/registry/blocks/code-editor/demo.jsx +205 -0
- package/registry/blocks/code-editor/index.js +8 -0
- package/registry/blocks/code-editor/json.js +317 -0
- package/registry/blocks/code-editor/sql.js +136 -0
- package/registry/blocks/code-editor/text.js +101 -0
- package/registry/blocks/code-editor/theme.js +186 -0
- package/registry/blocks/comment-box/README.md +123 -0
- package/registry/blocks/comment-box/block.json +10 -0
- package/registry/blocks/comment-box/comment-body.jsx +217 -0
- package/registry/blocks/comment-box/comment-box.jsx +198 -0
- package/registry/blocks/comment-box/comment-time.jsx +77 -0
- package/registry/blocks/comment-box/demo.jsx +141 -0
- package/registry/blocks/comment-box/index.js +8 -0
- package/registry/blocks/contact-section/README.md +152 -0
- package/registry/blocks/contact-section/block.json +11 -0
- package/registry/blocks/contact-section/contact-section.jsx +509 -0
- package/registry/blocks/contact-section/demo.jsx +93 -0
- package/registry/blocks/contact-section/index.js +4 -0
- package/registry/blocks/csv-import/README.md +133 -0
- package/registry/blocks/csv-import/block.json +13 -0
- package/registry/blocks/csv-import/csv-import.jsx +479 -0
- package/registry/blocks/csv-import/demo.jsx +106 -0
- package/registry/blocks/csv-import/import.js +200 -0
- package/registry/blocks/csv-import/index.js +7 -0
- package/registry/blocks/data-table/README.md +386 -0
- package/registry/blocks/data-table/block.json +10 -0
- package/registry/blocks/data-table/data-table.jsx +1164 -0
- package/registry/blocks/data-table/demo.jsx +588 -0
- package/registry/blocks/data-table/index.js +5 -0
- package/registry/blocks/data-table/model.js +169 -0
- package/registry/blocks/diagram/README.md +108 -0
- package/registry/blocks/diagram/block.json +13 -0
- package/registry/blocks/diagram/demo.jsx +113 -0
- package/registry/blocks/diagram/diagram.jsx +481 -0
- package/registry/blocks/diagram/index.js +7 -0
- package/registry/blocks/diagram/mermaid.js +52 -0
- package/registry/blocks/diagram/palette.js +313 -0
- package/registry/blocks/diagram/source.js +98 -0
- package/registry/blocks/doc-editor/README.md +215 -0
- package/registry/blocks/doc-editor/block.json +15 -0
- package/registry/blocks/doc-editor/demo.jsx +225 -0
- package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
- package/registry/blocks/doc-editor/doc.js +309 -0
- package/registry/blocks/doc-editor/index.js +7 -0
- package/registry/blocks/doc-editor/schema.jsx +56 -0
- package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
- package/registry/blocks/doc-editor/theme.js +82 -0
- package/registry/blocks/doc-page/README.md +119 -0
- package/registry/blocks/doc-page/autosave.js +104 -0
- package/registry/blocks/doc-page/block.json +10 -0
- package/registry/blocks/doc-page/demo.jsx +137 -0
- package/registry/blocks/doc-page/doc-page.jsx +276 -0
- package/registry/blocks/doc-page/index.js +4 -0
- package/registry/blocks/email-render/README.md +151 -0
- package/registry/blocks/email-render/block.json +14 -0
- package/registry/blocks/email-render/demo.jsx +153 -0
- package/registry/blocks/email-render/doc-email.jsx +210 -0
- package/registry/blocks/email-render/email.jsx +221 -0
- package/registry/blocks/email-render/index.js +10 -0
- package/registry/blocks/email-render/render.js +50 -0
- package/registry/blocks/email-render/theme.js +215 -0
- package/registry/blocks/faq/README.md +101 -0
- package/registry/blocks/faq/block.json +11 -0
- package/registry/blocks/faq/demo.jsx +89 -0
- package/registry/blocks/faq/faq.jsx +220 -0
- package/registry/blocks/faq/index.js +4 -0
- package/registry/blocks/file-upload/README.md +138 -0
- package/registry/blocks/file-upload/block.json +10 -0
- package/registry/blocks/file-upload/demo.jsx +204 -0
- package/registry/blocks/file-upload/file-upload.jsx +635 -0
- package/registry/blocks/file-upload/index.js +4 -0
- package/registry/blocks/flow-canvas/README.md +420 -0
- package/registry/blocks/flow-canvas/block.json +13 -0
- package/registry/blocks/flow-canvas/board.js +819 -0
- package/registry/blocks/flow-canvas/chrome.jsx +649 -0
- package/registry/blocks/flow-canvas/context.jsx +35 -0
- package/registry/blocks/flow-canvas/demo.jsx +249 -0
- package/registry/blocks/flow-canvas/edges.jsx +107 -0
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
- package/registry/blocks/flow-canvas/index.js +41 -0
- package/registry/blocks/flow-canvas/nodes.jsx +392 -0
- package/registry/blocks/flow-canvas/theme.js +174 -0
- package/registry/blocks/footer/README.md +133 -0
- package/registry/blocks/footer/block.json +11 -0
- package/registry/blocks/footer/demo.jsx +119 -0
- package/registry/blocks/footer/footer.jsx +406 -0
- package/registry/blocks/footer/index.js +4 -0
- package/registry/blocks/gantt/README.md +220 -0
- package/registry/blocks/gantt/block.json +10 -0
- package/registry/blocks/gantt/demo.jsx +148 -0
- package/registry/blocks/gantt/gantt.jsx +923 -0
- package/registry/blocks/gantt/index.js +7 -0
- package/registry/blocks/gantt/rows.jsx +468 -0
- package/registry/blocks/gantt/schedule.js +278 -0
- package/registry/blocks/job-panel/README.md +86 -2
- package/registry/blocks/job-panel/block.json +3 -3
- package/registry/blocks/job-panel/demo.jsx +230 -3
- package/registry/blocks/job-panel/job-panel.jsx +169 -3
- package/registry/blocks/json-editor/README.md +133 -0
- package/registry/blocks/json-editor/block.json +10 -0
- package/registry/blocks/json-editor/demo.jsx +92 -0
- package/registry/blocks/json-editor/index.js +7 -0
- package/registry/blocks/json-editor/json-editor.jsx +305 -0
- package/registry/blocks/json-editor/json-tree.jsx +393 -0
- package/registry/blocks/json-editor/tree.js +225 -0
- package/registry/blocks/map/README.md +221 -0
- package/registry/blocks/map/block.json +14 -0
- package/registry/blocks/map/demo.jsx +201 -0
- package/registry/blocks/map/geo.js +198 -0
- package/registry/blocks/map/index.js +8 -0
- package/registry/blocks/map/list.jsx +128 -0
- package/registry/blocks/map/map-view.jsx +715 -0
- package/registry/blocks/map/maplibre.js +30 -0
- package/registry/blocks/map/marks.jsx +146 -0
- package/registry/blocks/map/theme.js +142 -0
- package/registry/blocks/menubar/README.md +109 -0
- package/registry/blocks/menubar/block.json +10 -0
- package/registry/blocks/menubar/demo.jsx +128 -0
- package/registry/blocks/menubar/index.js +4 -0
- package/registry/blocks/menubar/menubar.jsx +199 -0
- package/registry/blocks/mind-map/README.md +206 -0
- package/registry/blocks/mind-map/block.json +10 -0
- package/registry/blocks/mind-map/demo.jsx +103 -0
- package/registry/blocks/mind-map/index.js +31 -0
- package/registry/blocks/mind-map/mind-map.jsx +1125 -0
- package/registry/blocks/mind-map/topic.jsx +143 -0
- package/registry/blocks/mind-map/tree.js +645 -0
- package/registry/blocks/navigation-menu/README.md +124 -0
- package/registry/blocks/navigation-menu/block.json +10 -0
- package/registry/blocks/navigation-menu/demo.jsx +84 -0
- package/registry/blocks/navigation-menu/index.js +4 -0
- package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
- package/registry/blocks/order-detail/README.md +109 -0
- package/registry/blocks/order-detail/block.json +10 -0
- package/registry/blocks/order-detail/demo.jsx +88 -0
- package/registry/blocks/order-detail/index.js +4 -0
- package/registry/blocks/order-detail/order-detail.jsx +354 -0
- package/registry/blocks/org-chart/README.md +145 -0
- package/registry/blocks/org-chart/block.json +10 -0
- package/registry/blocks/org-chart/demo.jsx +94 -0
- package/registry/blocks/org-chart/index.js +7 -0
- package/registry/blocks/org-chart/org-chart.jsx +631 -0
- package/registry/blocks/org-chart/org.js +245 -0
- package/registry/blocks/org-chart/person.jsx +96 -0
- package/registry/blocks/page-builder/README.md +257 -0
- package/registry/blocks/page-builder/block.json +14 -0
- package/registry/blocks/page-builder/demo.jsx +145 -0
- package/registry/blocks/page-builder/grapes.js +18 -0
- package/registry/blocks/page-builder/index.js +11 -0
- package/registry/blocks/page-builder/page-builder.jsx +704 -0
- package/registry/blocks/page-builder/page-view.jsx +33 -0
- package/registry/blocks/page-builder/page.js +118 -0
- package/registry/blocks/page-builder/panels.jsx +588 -0
- package/registry/blocks/page-builder/sections.js +209 -0
- package/registry/blocks/page-builder/theme.js +87 -0
- package/registry/blocks/page-builder/thumbs.jsx +189 -0
- package/registry/blocks/page-builder/tokens.js +329 -0
- package/registry/blocks/payment-methods/README.md +104 -0
- package/registry/blocks/payment-methods/block.json +10 -0
- package/registry/blocks/payment-methods/demo.jsx +71 -0
- package/registry/blocks/payment-methods/index.js +4 -0
- package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
- package/registry/blocks/pdf-document/README.md +213 -0
- package/registry/blocks/pdf-document/block.json +13 -0
- package/registry/blocks/pdf-document/demo.jsx +136 -0
- package/registry/blocks/pdf-document/index.js +33 -0
- package/registry/blocks/pdf-document/money.js +83 -0
- package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
- package/registry/blocks/pdf-document/primitives.jsx +271 -0
- package/registry/blocks/pdf-document/quote.jsx +179 -0
- package/registry/blocks/pdf-document/theme.js +193 -0
- package/registry/blocks/pdf-viewer/README.md +191 -0
- package/registry/blocks/pdf-viewer/block.json +14 -0
- package/registry/blocks/pdf-viewer/demo.jsx +252 -0
- package/registry/blocks/pdf-viewer/helpers.js +270 -0
- package/registry/blocks/pdf-viewer/index.js +8 -0
- package/registry/blocks/pdf-viewer/notes.jsx +195 -0
- package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
- package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
- package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
- package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
- package/registry/blocks/product-detail/README.md +217 -0
- package/registry/blocks/product-detail/block.json +10 -0
- package/registry/blocks/product-detail/demo.jsx +233 -0
- package/registry/blocks/product-detail/index.js +7 -0
- package/registry/blocks/product-detail/price.jsx +115 -0
- package/registry/blocks/product-detail/product-detail.jsx +348 -0
- package/registry/blocks/product-detail/product-media.jsx +102 -0
- package/registry/blocks/product-detail/product-options.jsx +144 -0
- package/registry/blocks/product-grid/README.md +162 -0
- package/registry/blocks/product-grid/block.json +10 -0
- package/registry/blocks/product-grid/demo.jsx +255 -0
- package/registry/blocks/product-grid/index.js +5 -0
- package/registry/blocks/product-grid/product-card.jsx +232 -0
- package/registry/blocks/product-grid/product-grid.jsx +235 -0
- package/registry/blocks/record-form/README.md +196 -0
- package/registry/blocks/record-form/block.json +10 -0
- package/registry/blocks/record-form/demo.jsx +525 -0
- package/registry/blocks/record-form/index.js +4 -0
- package/registry/blocks/record-form/record-fields.jsx +457 -0
- package/registry/blocks/record-form/record-form.jsx +415 -0
- package/registry/blocks/record-form/rules.js +81 -0
- package/registry/blocks/record-notes/README.md +139 -0
- package/registry/blocks/record-notes/block.json +10 -0
- package/registry/blocks/record-notes/demo.jsx +179 -0
- package/registry/blocks/record-notes/index.js +4 -0
- package/registry/blocks/record-notes/record-notes.jsx +266 -0
- package/registry/blocks/search-dialog/README.md +108 -0
- package/registry/blocks/search-dialog/block.json +10 -0
- package/registry/blocks/search-dialog/demo.jsx +116 -0
- package/registry/blocks/search-dialog/index.js +3 -0
- package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
- package/registry/blocks/settings-list/README.md +171 -0
- package/registry/blocks/settings-list/block.json +10 -0
- package/registry/blocks/settings-list/demo.jsx +333 -0
- package/registry/blocks/settings-list/index.js +4 -0
- package/registry/blocks/settings-list/row-state.jsx +93 -0
- package/registry/blocks/settings-list/settings-list.jsx +349 -0
- package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
- package/registry/blocks/setup-checklist/README.md +142 -0
- package/registry/blocks/setup-checklist/block.json +10 -0
- package/registry/blocks/setup-checklist/demo.jsx +159 -0
- package/registry/blocks/setup-checklist/index.js +4 -0
- package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
- package/registry/blocks/share-dialog/README.md +113 -0
- package/registry/blocks/share-dialog/block.json +10 -0
- package/registry/blocks/share-dialog/demo.jsx +140 -0
- package/registry/blocks/share-dialog/index.js +3 -0
- package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
- package/registry/blocks/sidebar/README.md +190 -0
- package/registry/blocks/sidebar/block.json +43 -0
- package/registry/blocks/sidebar/demo.jsx +577 -0
- package/registry/blocks/sidebar/index.js +4 -0
- package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
- package/registry/blocks/sidebar/sidebar.jsx +864 -0
- package/registry/blocks/signature-pad/README.md +137 -0
- package/registry/blocks/signature-pad/block.json +13 -0
- package/registry/blocks/signature-pad/colors.js +115 -0
- package/registry/blocks/signature-pad/demo.jsx +94 -0
- package/registry/blocks/signature-pad/index.js +6 -0
- package/registry/blocks/signature-pad/pad.js +7 -0
- package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
- package/registry/blocks/signature-pad/signature.js +68 -0
- package/registry/blocks/sketch-canvas/README.md +280 -0
- package/registry/blocks/sketch-canvas/block.json +13 -0
- package/registry/blocks/sketch-canvas/demo.jsx +159 -0
- package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
- package/registry/blocks/sketch-canvas/index.js +9 -0
- package/registry/blocks/sketch-canvas/palette.js +226 -0
- package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
- package/registry/blocks/sketch-canvas/sketch.js +179 -0
- package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
- package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
- package/registry/blocks/sketch-canvas/stamps.js +104 -0
- package/registry/blocks/sketch-canvas/theme.js +131 -0
- package/registry/blocks/spreadsheet/README.md +307 -0
- package/registry/blocks/spreadsheet/block.json +13 -0
- package/registry/blocks/spreadsheet/cells.jsx +455 -0
- package/registry/blocks/spreadsheet/chrome.jsx +325 -0
- package/registry/blocks/spreadsheet/demo.jsx +177 -0
- package/registry/blocks/spreadsheet/grid.js +387 -0
- package/registry/blocks/spreadsheet/index.js +34 -0
- package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
- package/registry/blocks/spreadsheet/types.js +473 -0
- package/registry/blocks/stat-cards/README.md +173 -0
- package/registry/blocks/stat-cards/block.json +10 -0
- package/registry/blocks/stat-cards/demo.jsx +257 -0
- package/registry/blocks/stat-cards/index.js +4 -0
- package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
- package/registry/blocks/stat-cards/usage.jsx +243 -0
- package/registry/blocks/task-list/README.md +176 -0
- package/registry/blocks/task-list/block.json +10 -0
- package/registry/blocks/task-list/demo.jsx +134 -0
- package/registry/blocks/task-list/index.js +5 -0
- package/registry/blocks/task-list/task-list.jsx +907 -0
- package/registry/blocks/task-model/README.md +455 -0
- package/registry/blocks/task-model/block.json +167 -0
- package/registry/blocks/task-model/changes.js +89 -0
- package/registry/blocks/task-model/dates.js +371 -0
- package/registry/blocks/task-model/demo.jsx +215 -0
- package/registry/blocks/task-model/dnd.jsx +240 -0
- package/registry/blocks/task-model/index.js +97 -0
- package/registry/blocks/task-model/model.js +919 -0
- package/registry/blocks/task-model/parts.jsx +449 -0
- package/registry/blocks/task-model/toolbar.jsx +271 -0
- package/registry/blocks/testimonials/README.md +139 -0
- package/registry/blocks/testimonials/block.json +11 -0
- package/registry/blocks/testimonials/demo.jsx +137 -0
- package/registry/blocks/testimonials/index.js +4 -0
- package/registry/blocks/testimonials/testimonials.jsx +430 -0
- package/registry/blocks/transaction-list/README.md +126 -0
- package/registry/blocks/transaction-list/block.json +10 -0
- package/registry/blocks/transaction-list/demo.jsx +79 -0
- package/registry/blocks/transaction-list/index.js +4 -0
- package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
- package/registry/blocks/whiteboard/README.md +179 -0
- package/registry/blocks/whiteboard/block.json +10 -0
- package/registry/blocks/whiteboard/demo.jsx +169 -0
- package/registry/blocks/whiteboard/index.js +6 -0
- package/registry/blocks/whiteboard/templates.js +150 -0
- package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
- package/src/install.mjs +18 -0
- package/src/shadcn.mjs +171 -0
- package/templates/next/files/README.md +145 -11
- package/templates/next/files/app/globals.css +55 -4
- package/templates/next/files/check/run.mjs +3 -3
- package/templates/next/files/components/parts/fixture.jsx +1 -1
- package/templates/next/files/components/parts/sample.js +15 -0
- package/templates/next/files/components/ui/avatar.jsx +141 -0
- package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
- package/templates/next/files/components/ui/button-group.jsx +70 -0
- package/templates/next/files/components/ui/button.jsx +132 -12
- package/templates/next/files/components/ui/calendar.jsx +609 -0
- package/templates/next/files/components/ui/carousel.jsx +281 -0
- package/templates/next/files/components/ui/collapsible.jsx +208 -0
- package/templates/next/files/components/ui/combobox.jsx +608 -0
- package/templates/next/files/components/ui/command.jsx +577 -0
- package/templates/next/files/components/ui/context-menu.jsx +191 -0
- package/templates/next/files/components/ui/date-picker.jsx +360 -0
- package/templates/next/files/components/ui/distribution.jsx +117 -0
- package/templates/next/files/components/ui/feedback.jsx +143 -0
- package/templates/next/files/components/ui/field.jsx +115 -3
- package/templates/next/files/components/ui/file-input.jsx +234 -0
- package/templates/next/files/components/ui/icon.jsx +130 -8
- package/templates/next/files/components/ui/image.jsx +143 -0
- package/templates/next/files/components/ui/index.js +47 -2
- package/templates/next/files/components/ui/input-group.jsx +213 -0
- package/templates/next/files/components/ui/input-otp.jsx +170 -0
- package/templates/next/files/components/ui/item.jsx +206 -0
- package/templates/next/files/components/ui/menu.jsx +454 -82
- package/templates/next/files/components/ui/notice.jsx +126 -14
- package/templates/next/files/components/ui/pagination.jsx +156 -0
- package/templates/next/files/components/ui/popover.jsx +284 -0
- package/templates/next/files/components/ui/radio.jsx +193 -0
- package/templates/next/files/components/ui/rating.jsx +131 -0
- package/templates/next/files/components/ui/resizable.jsx +338 -0
- package/templates/next/files/components/ui/scroll-area.jsx +123 -0
- package/templates/next/files/components/ui/separator.jsx +119 -0
- package/templates/next/files/components/ui/sheet.jsx +96 -11
- package/templates/next/files/components/ui/slider.jsx +174 -0
- package/templates/next/files/components/ui/stat.jsx +574 -0
- package/templates/next/files/components/ui/steps.jsx +338 -0
- package/templates/next/files/components/ui/swatch.jsx +33 -0
- package/templates/next/files/components/ui/table.jsx +130 -0
- package/templates/next/files/components/ui/toast.jsx +440 -0
- package/templates/next/files/components/ui/toggle.jsx +195 -0
- package/templates/next/files/components/ui/tooltip.jsx +270 -0
- package/templates/next/files/lib/sample.js +4 -12
- package/templates/next/template.json +264 -8
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { cx } from "./cx";
|
|
2
|
-
import {
|
|
2
|
+
import { IconButton } from "./button";
|
|
3
3
|
import { Icon } from "./icon";
|
|
4
4
|
|
|
5
5
|
// Static parts: a card, a notice, a badge, a kicker, the empty state.
|
|
@@ -13,14 +13,36 @@ const TONES = {
|
|
|
13
13
|
danger: { box: "border-destructive/50 bg-card text-card-foreground", icon: "warning" },
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
/** A raised panel with an optional heading row.
|
|
17
|
-
|
|
16
|
+
/** A raised panel with an optional heading row.
|
|
17
|
+
* padding md (default, 16px) · sm (12px, a dense rail) · none (the
|
|
18
|
+
* body runs to the border — a table, a list of rows; the
|
|
19
|
+
* heading row keeps its own 16px inset)
|
|
20
|
+
* titleSize md (default, 16px) · lg (20px, a page-level card's title)
|
|
21
|
+
* Pick these here, never with a className: cx does not merge classes,
|
|
22
|
+
* so a `p-0` laid over the default padding wins only by CSS order. */
|
|
23
|
+
const CARD_PADDING = { none: "", sm: "p-3", md: "p-4" };
|
|
24
|
+
const CARD_TITLE = { md: "text-base", lg: "text-xl" };
|
|
25
|
+
|
|
26
|
+
export function Card({
|
|
27
|
+
title,
|
|
28
|
+
description,
|
|
29
|
+
actions,
|
|
30
|
+
padding = "md",
|
|
31
|
+
titleSize = "md",
|
|
32
|
+
className,
|
|
33
|
+
children,
|
|
34
|
+
as: Tag = "section",
|
|
35
|
+
}) {
|
|
36
|
+
const pad = CARD_PADDING[padding] ?? CARD_PADDING.md;
|
|
37
|
+
const bare = padding === "none";
|
|
18
38
|
return (
|
|
19
|
-
<Tag className={cx("rounded-lg border border-border bg-card
|
|
39
|
+
<Tag className={cx("rounded-lg border border-border bg-card text-card-foreground", pad, bare && "overflow-hidden", className)}>
|
|
20
40
|
{title || actions ? (
|
|
21
|
-
<div className="
|
|
41
|
+
<div className={cx("flex items-start justify-between gap-3", bare ? "px-4 pt-4 pb-3" : "mb-3")}>
|
|
22
42
|
<div className="min-w-0">
|
|
23
|
-
{title ?
|
|
43
|
+
{title ? (
|
|
44
|
+
<h2 className={cx("font-semibold leading-tight", CARD_TITLE[titleSize] ?? CARD_TITLE.md)}>{title}</h2>
|
|
45
|
+
) : null}
|
|
24
46
|
{description ? <p className="mt-0.5 text-sm text-muted-foreground">{description}</p> : null}
|
|
25
47
|
</div>
|
|
26
48
|
{actions ? <div className="flex shrink-0 gap-2">{actions}</div> : null}
|
|
@@ -45,25 +67,115 @@ export function Notice({ tone = "neutral", title, action, onDismiss, className,
|
|
|
45
67
|
</div>
|
|
46
68
|
{action ? <div className="shrink-0">{action}</div> : null}
|
|
47
69
|
{onDismiss ? (
|
|
48
|
-
<
|
|
49
|
-
<Icon name="x" />
|
|
50
|
-
</Button>
|
|
70
|
+
<IconButton icon="x" label="Dismiss" size="sm" onClick={onDismiss} className="-my-1 -mr-1" />
|
|
51
71
|
) : null}
|
|
52
72
|
</div>
|
|
53
73
|
);
|
|
54
74
|
}
|
|
55
75
|
|
|
56
|
-
/** A small label for a state or a count.
|
|
57
|
-
|
|
58
|
-
|
|
76
|
+
/** A small label for a state or a count.
|
|
77
|
+
* tone neutral · primary · success · warning · danger · info
|
|
78
|
+
* variant label (default: small caps, wide tracking; primary is a
|
|
79
|
+
* solid fill, every other tone a tint) · soft (the case as
|
|
80
|
+
* written, normal tracking, EVERY tone a tint — primary
|
|
81
|
+
* included: "Ready", "Daily over", "Feature") · outline (the
|
|
82
|
+
* case as written, a tone-coloured hairline on no fill) ·
|
|
83
|
+
* code (the mono face, the case as written, normal tracking
|
|
84
|
+
* — a version tag "v2.4.0", a commit "a3f8c2d", a path)
|
|
85
|
+
* hue 1..5 — a categorical colour, read from --color-chart-N,
|
|
86
|
+
* for KINDS of things (a DNS type, a platform, a content
|
|
87
|
+
* type). Tone is for status; hue is for category, and a
|
|
88
|
+
* tone given with it wins. With every variant: soft is the
|
|
89
|
+
* case as written on a tint of the hue with a hue dot and
|
|
90
|
+
* foreground text; label (and code) is filled with the hue
|
|
91
|
+
* and black or white text, whichever reads; outline is a
|
|
92
|
+
* hue hairline with foreground text. The text is never the
|
|
93
|
+
* hue itself: a chart colour is not made to be read as type
|
|
94
|
+
* Case is a variant, not its own prop: uppercase needs wide tracking and
|
|
95
|
+
* sentence case needs none, so the two travel together, and a `case`
|
|
96
|
+
* prop would have to be ignored by code. A soft primary lives on `soft`
|
|
97
|
+
* because `label` primary is a solid fill apps already rely on. The
|
|
98
|
+
* outline's ring is inset, so every variant is the same size in a row. */
|
|
99
|
+
const BADGE_LOOK = {
|
|
100
|
+
label: {
|
|
59
101
|
neutral: "bg-muted text-muted-foreground",
|
|
60
102
|
primary: "bg-primary text-primary-foreground",
|
|
61
103
|
success: "bg-success/15 text-success",
|
|
62
104
|
warning: "bg-warning/15 text-warning",
|
|
63
105
|
danger: "bg-destructive/15 text-destructive",
|
|
64
106
|
info: "bg-info/15 text-info",
|
|
65
|
-
}
|
|
66
|
-
|
|
107
|
+
},
|
|
108
|
+
soft: {
|
|
109
|
+
neutral: "bg-muted text-muted-foreground",
|
|
110
|
+
primary: "bg-primary/15 text-primary",
|
|
111
|
+
success: "bg-success/15 text-success",
|
|
112
|
+
warning: "bg-warning/15 text-warning",
|
|
113
|
+
danger: "bg-destructive/15 text-destructive",
|
|
114
|
+
info: "bg-info/15 text-info",
|
|
115
|
+
},
|
|
116
|
+
outline: {
|
|
117
|
+
neutral: "bg-transparent text-foreground ring-1 ring-inset ring-border",
|
|
118
|
+
primary: "bg-transparent text-primary ring-1 ring-inset ring-primary/50",
|
|
119
|
+
success: "bg-transparent text-success ring-1 ring-inset ring-success/50",
|
|
120
|
+
warning: "bg-transparent text-warning ring-1 ring-inset ring-warning/50",
|
|
121
|
+
danger: "bg-transparent text-destructive ring-1 ring-inset ring-destructive/50",
|
|
122
|
+
info: "bg-transparent text-info ring-1 ring-inset ring-info/50",
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
BADGE_LOOK.code = BADGE_LOOK.label;
|
|
126
|
+
|
|
127
|
+
const BADGE_FACE = {
|
|
128
|
+
label: "font-medium uppercase tracking-wide",
|
|
129
|
+
soft: "font-medium",
|
|
130
|
+
outline: "font-medium",
|
|
131
|
+
code: "font-mono font-normal",
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// Categorical hues, literal so Tailwind sees every class. A filled hue's
|
|
135
|
+
// text is black or white, picked from the fill's relative luminance (the
|
|
136
|
+
// WCAG formula, on the clipped sRGB channels): what CSS contrast-color()
|
|
137
|
+
// does, which no token can. A chart colour sits mid-lightness (chart-2…5
|
|
138
|
+
// are clamped to OKLCH L 0.55–0.8, often past sRGB), where the theme's
|
|
139
|
+
// light text fails on a light theme and its dark text on a dark primary.
|
|
140
|
+
// Black below Y 0.179, white above: the better of the two is always
|
|
141
|
+
// 4.58:1 or more. The soft tint is light (8%) so foreground text keeps
|
|
142
|
+
// its contrast.
|
|
143
|
+
const HUE_LOOK = {
|
|
144
|
+
label: {
|
|
145
|
+
1: "bg-chart-1 text-[color:color(from_var(--color-chart-1)_srgb_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1)_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1)_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1))]",
|
|
146
|
+
2: "bg-chart-2 text-[color:color(from_var(--color-chart-2)_srgb_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1)_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1)_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1))]",
|
|
147
|
+
3: "bg-chart-3 text-[color:color(from_var(--color-chart-3)_srgb_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1)_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1)_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1))]",
|
|
148
|
+
4: "bg-chart-4 text-[color:color(from_var(--color-chart-4)_srgb_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1)_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1)_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1))]",
|
|
149
|
+
5: "bg-chart-5 text-[color:color(from_var(--color-chart-5)_srgb_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1)_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1)_clamp(0,(0.179_-_(0.2126*pow(clamp(0,r,1),2.2)_+_0.7152*pow(clamp(0,g,1),2.2)_+_0.0722*pow(clamp(0,b,1),2.2)))*999,1))]",
|
|
150
|
+
},
|
|
151
|
+
soft: {
|
|
152
|
+
1: "bg-chart-1/8 text-foreground",
|
|
153
|
+
2: "bg-chart-2/8 text-foreground",
|
|
154
|
+
3: "bg-chart-3/8 text-foreground",
|
|
155
|
+
4: "bg-chart-4/8 text-foreground",
|
|
156
|
+
5: "bg-chart-5/8 text-foreground",
|
|
157
|
+
},
|
|
158
|
+
outline: {
|
|
159
|
+
1: "bg-transparent text-foreground ring-1 ring-inset ring-chart-1",
|
|
160
|
+
2: "bg-transparent text-foreground ring-1 ring-inset ring-chart-2",
|
|
161
|
+
3: "bg-transparent text-foreground ring-1 ring-inset ring-chart-3",
|
|
162
|
+
4: "bg-transparent text-foreground ring-1 ring-inset ring-chart-4",
|
|
163
|
+
5: "bg-transparent text-foreground ring-1 ring-inset ring-chart-5",
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
HUE_LOOK.code = HUE_LOOK.label;
|
|
167
|
+
const HUE_DOT = { 1: "bg-chart-1", 2: "bg-chart-2", 3: "bg-chart-3", 4: "bg-chart-4", 5: "bg-chart-5" };
|
|
168
|
+
|
|
169
|
+
export function Badge({ tone, hue, variant = "label", className, children }) {
|
|
170
|
+
const v = BADGE_FACE[variant] ? variant : "label";
|
|
171
|
+
const h = tone == null && HUE_DOT[hue] ? hue : null;
|
|
172
|
+
const look = h ? HUE_LOOK[v][h] : BADGE_LOOK[v][tone ?? "neutral"] ?? BADGE_LOOK[v].neutral;
|
|
173
|
+
return (
|
|
174
|
+
<span className={cx("inline-flex items-center rounded-sm px-1.5 py-0.5 text-2xs", h && v === "soft" && "gap-1", BADGE_FACE[v], look, className)}>
|
|
175
|
+
{h && v === "soft" ? <span aria-hidden="true" className={cx("size-1.5 shrink-0 rounded-full", HUE_DOT[h])} /> : null}
|
|
176
|
+
{children}
|
|
177
|
+
</span>
|
|
178
|
+
);
|
|
67
179
|
}
|
|
68
180
|
|
|
69
181
|
/** The small uppercase line above a heading. */
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { cx } from "./cx";
|
|
2
|
+
import { Button } from "./button";
|
|
3
|
+
import { Icon } from "./icon";
|
|
4
|
+
import { Select } from "./field";
|
|
5
|
+
|
|
6
|
+
// Pagination — move through a long list a page at a time. Numbers around
|
|
7
|
+
// the current page with "…" for the gaps, first and last always there,
|
|
8
|
+
// previous/next disabled at the ends. Two ways to move, pick one:
|
|
9
|
+
// `hrefFor(page)` makes every page a link (next/link, base path applied;
|
|
10
|
+
// works in a server surface, the URL is the state) or `onPageChange(page)`
|
|
11
|
+
// makes them buttons (a client surface holds the page).
|
|
12
|
+
//
|
|
13
|
+
// page the current page, 1-based
|
|
14
|
+
// pageCount how many pages there are
|
|
15
|
+
// siblings pages shown each side of the current one (default 1)
|
|
16
|
+
// compact always "Page 3 of 12" with previous/next; without it
|
|
17
|
+
// a phone gets that and a wider window the numbers
|
|
18
|
+
// pageSize with onPageSizeChange: a "Rows per page" Select
|
|
19
|
+
// pageSizes its choices (default 10 · 25 · 50 · 100)
|
|
20
|
+
// size md (44px targets) · sm (36px, for a dense table foot)
|
|
21
|
+
//
|
|
22
|
+
// One page and no page-size choice: nothing to move through, nothing drawn.
|
|
23
|
+
|
|
24
|
+
/** The slots to draw: page numbers and "gap". The row is the same width
|
|
25
|
+
* wherever the current page is, so the buttons never jump under a thumb. */
|
|
26
|
+
function slots(page, count, siblings) {
|
|
27
|
+
const width = siblings * 2 + 5; // first, gap, siblings, current, siblings, gap, last
|
|
28
|
+
if (count <= width) return Array.from({ length: count }, (_, i) => i + 1);
|
|
29
|
+
const range = (a, b) => Array.from({ length: b - a + 1 }, (_, i) => a + i);
|
|
30
|
+
const edge = siblings * 2 + 3; // what a run from either end holds before its gap
|
|
31
|
+
if (page <= edge - siblings) return [...range(1, edge), "gap", count];
|
|
32
|
+
if (page > count - (edge - siblings)) return [1, "gap", ...range(count - edge + 1, count)];
|
|
33
|
+
return [1, "gap", ...range(page - siblings, page + siblings), "gap", count];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function Pagination({
|
|
37
|
+
page,
|
|
38
|
+
pageCount,
|
|
39
|
+
hrefFor,
|
|
40
|
+
onPageChange,
|
|
41
|
+
siblings = 1,
|
|
42
|
+
compact = false,
|
|
43
|
+
pageSize,
|
|
44
|
+
pageSizes = [10, 25, 50, 100],
|
|
45
|
+
onPageSizeChange,
|
|
46
|
+
size = "md",
|
|
47
|
+
label = "Pagination",
|
|
48
|
+
className,
|
|
49
|
+
}) {
|
|
50
|
+
const count = Math.max(1, Math.floor(pageCount || 1));
|
|
51
|
+
const current = Math.min(Math.max(1, Math.floor(page || 1)), count);
|
|
52
|
+
const sizer = Boolean(onPageSizeChange && pageSize);
|
|
53
|
+
if (count <= 1 && !sizer) return null;
|
|
54
|
+
|
|
55
|
+
const square = size === "sm" ? "min-w-9 px-2" : "min-w-11 px-2";
|
|
56
|
+
|
|
57
|
+
// One page control: a link when hrefFor is given, else a button. Past
|
|
58
|
+
// either end it is a disabled button, never a link to nowhere.
|
|
59
|
+
const go = (to, { children, current: isCurrent, className: extra, ...rest }) => {
|
|
60
|
+
const disabled = to < 1 || to > count;
|
|
61
|
+
const common = {
|
|
62
|
+
size,
|
|
63
|
+
variant: isCurrent ? "secondary" : "quiet",
|
|
64
|
+
className: extra,
|
|
65
|
+
"aria-current": isCurrent ? "page" : undefined,
|
|
66
|
+
...rest,
|
|
67
|
+
};
|
|
68
|
+
if (disabled) return <Button {...common} disabled>{children}</Button>;
|
|
69
|
+
if (hrefFor) return <Button {...common} href={hrefFor(to)}>{children}</Button>;
|
|
70
|
+
return (
|
|
71
|
+
<Button {...common} onClick={isCurrent ? undefined : () => onPageChange?.(to)}>
|
|
72
|
+
{children}
|
|
73
|
+
</Button>
|
|
74
|
+
);
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const prev = (wide) =>
|
|
78
|
+
go(current - 1, {
|
|
79
|
+
"aria-label": "Previous page",
|
|
80
|
+
className: wide ? "gap-1 pl-2 pr-3" : square,
|
|
81
|
+
children: (
|
|
82
|
+
<>
|
|
83
|
+
<Icon name="chevron-left" />
|
|
84
|
+
{wide ? <span>Previous</span> : null}
|
|
85
|
+
</>
|
|
86
|
+
),
|
|
87
|
+
});
|
|
88
|
+
const next = (wide) =>
|
|
89
|
+
go(current + 1, {
|
|
90
|
+
"aria-label": "Next page",
|
|
91
|
+
className: wide ? "gap-1 pl-3 pr-2" : square,
|
|
92
|
+
children: (
|
|
93
|
+
<>
|
|
94
|
+
{wide ? <span>Next</span> : null}
|
|
95
|
+
<Icon name="chevron-right" />
|
|
96
|
+
</>
|
|
97
|
+
),
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
const status = (
|
|
101
|
+
<span data-nums className="whitespace-nowrap px-2 text-sm text-muted-foreground">
|
|
102
|
+
Page <span className="font-medium text-foreground">{current}</span> of {count}
|
|
103
|
+
</span>
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<nav aria-label={label} className={cx("flex flex-wrap items-center justify-between gap-x-4 gap-y-2", className)}>
|
|
108
|
+
{sizer ? (
|
|
109
|
+
<label className="inline-flex items-center gap-2 text-sm text-muted-foreground">
|
|
110
|
+
<span className="whitespace-nowrap">Rows per page</span>
|
|
111
|
+
<span className="w-20">
|
|
112
|
+
<Select
|
|
113
|
+
value={String(pageSize)}
|
|
114
|
+
onChange={(e) => onPageSizeChange(Number(e.target.value))}
|
|
115
|
+
options={pageSizes.map((n) => ({ value: String(n), label: String(n) }))}
|
|
116
|
+
/>
|
|
117
|
+
</span>
|
|
118
|
+
</label>
|
|
119
|
+
) : null}
|
|
120
|
+
|
|
121
|
+
{count > 1 ? (
|
|
122
|
+
<>
|
|
123
|
+
{/* Compact: every width when asked, else only a phone's. */}
|
|
124
|
+
<div className={cx("flex items-center gap-1", sizer ? "ml-auto" : "mx-auto", !compact && "sm:hidden")}>
|
|
125
|
+
{prev(false)}
|
|
126
|
+
{status}
|
|
127
|
+
{next(false)}
|
|
128
|
+
</div>
|
|
129
|
+
|
|
130
|
+
{compact ? null : (
|
|
131
|
+
<ul className={cx("hidden items-center gap-1 sm:flex", sizer ? "ml-auto" : "mx-auto")}>
|
|
132
|
+
<li>{prev(true)}</li>
|
|
133
|
+
{slots(current, count, Math.max(0, siblings)).map((s, i) =>
|
|
134
|
+
s === "gap" ? (
|
|
135
|
+
<li key={`gap-${i}`} aria-hidden="true" className={cx("inline-flex items-center justify-center text-muted-foreground", square)}>
|
|
136
|
+
<Icon name="more" />
|
|
137
|
+
</li>
|
|
138
|
+
) : (
|
|
139
|
+
<li key={s}>
|
|
140
|
+
{go(s, {
|
|
141
|
+
current: s === current,
|
|
142
|
+
"aria-label": `Page ${s}`,
|
|
143
|
+
className: square,
|
|
144
|
+
children: <span data-nums>{s}</span>,
|
|
145
|
+
})}
|
|
146
|
+
</li>
|
|
147
|
+
),
|
|
148
|
+
)}
|
|
149
|
+
<li>{next(true)}</li>
|
|
150
|
+
</ul>
|
|
151
|
+
)}
|
|
152
|
+
</>
|
|
153
|
+
) : null}
|
|
154
|
+
</nav>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
|
|
4
|
+
import { cx } from "./cx";
|
|
5
|
+
import { Button } from "./button";
|
|
6
|
+
|
|
7
|
+
// Popover — a panel that floats beside the control that opened it: a
|
|
8
|
+
// filter form under its button, a short setting beside a row. The Popover
|
|
9
|
+
// API does the hard part (top layer, light dismiss, Escape, focus back to
|
|
10
|
+
// the trigger); CSS anchor positioning keeps it beside the trigger where
|
|
11
|
+
// the browser has it, and a measured fallback does where it does not.
|
|
12
|
+
// Controlled (`open` + `onOpenChange`) or not (`defaultOpen`).
|
|
13
|
+
//
|
|
14
|
+
// trigger a node → the content of a kit Button (`variant`, `size`
|
|
15
|
+
// apply); or (props) => element for a trigger of your own —
|
|
16
|
+
// spread `props` on a <button> (ref, popoverTarget, aria-*)
|
|
17
|
+
// side top · right · bottom (default) · left; flips to the
|
|
18
|
+
// opposite side when there is no room, and every open tries
|
|
19
|
+
// the asked side first again
|
|
20
|
+
// align start · center (default) · end, along that side (physical:
|
|
21
|
+
// start is the left or top edge)
|
|
22
|
+
// width sm (224px) · md (288px, default) · lg (384px) · auto (its
|
|
23
|
+
// content); never wider than the window less 16px
|
|
24
|
+
// className the panel's; a padding in it (p-0, p-2…) replaces the p-4
|
|
25
|
+
// label what a screen reader calls the panel (role=dialog);
|
|
26
|
+
// defaults to the trigger when it is a string
|
|
27
|
+
// open, defaultOpen, onOpenChange(open) — light dismiss and Escape
|
|
28
|
+
// report onOpenChange(false); the panel follows `open`
|
|
29
|
+
//
|
|
30
|
+
// Focus moves to the panel's first control when it opens and back to the
|
|
31
|
+
// trigger when it closes; Tab past the panel's end closes it.
|
|
32
|
+
//
|
|
33
|
+
// For the parts built on this (Tooltip, HoverCard, a combobox, a date
|
|
34
|
+
// picker): usePopoverPosition(anchorRef, panelRef, { side, align, offset })
|
|
35
|
+
// keeps any [popover] panel beside its anchor — flipping, following scroll
|
|
36
|
+
// and resize — and panelClass(width, className) is the panel's look.
|
|
37
|
+
|
|
38
|
+
const WIDTHS = { sm: "w-56", md: "w-72", lg: "w-96", auto: "w-max" };
|
|
39
|
+
const OPPOSITE = { top: "bottom", bottom: "top", left: "right", right: "left" };
|
|
40
|
+
const EDGE = 8; // the room kept between a panel and the window's edge
|
|
41
|
+
|
|
42
|
+
/** The floating panel's look: popover tokens, a border, a shadow, and a
|
|
43
|
+
* quick fade that `prefers-reduced-motion` drops. */
|
|
44
|
+
export function panelClass(width = "md", className) {
|
|
45
|
+
return cx(
|
|
46
|
+
WIDTHS[width] ?? WIDTHS.md,
|
|
47
|
+
"max-w-[calc(100vw-1rem)] rounded-md border border-border bg-popover text-popover-foreground shadow-lg outline-none",
|
|
48
|
+
"opacity-0 scale-95 transition-[opacity,scale,display,overlay] transition-discrete duration-150 open:opacity-100 open:scale-100",
|
|
49
|
+
"starting:open:opacity-0 starting:open:scale-95 motion-reduce:transition-none",
|
|
50
|
+
className,
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Anchor positioning with the fallbacks we name: Chrome 129+, Safari 26.
|
|
55
|
+
// Checked once; anything older takes the measured path.
|
|
56
|
+
let anchored;
|
|
57
|
+
function canAnchor() {
|
|
58
|
+
if (anchored === undefined) {
|
|
59
|
+
anchored =
|
|
60
|
+
typeof CSS !== "undefined" &&
|
|
61
|
+
CSS.supports("position-area", "bottom span-right") &&
|
|
62
|
+
CSS.supports("position-try-fallbacks", "top span-left, bottom span-all");
|
|
63
|
+
}
|
|
64
|
+
return anchored;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Every place the panel may go, preferred first: the asked side with the
|
|
68
|
+
// asked alignment, then the other alignments, then the opposite side.
|
|
69
|
+
// `span-all` centres on the anchor with the whole window to spread into.
|
|
70
|
+
function areas(side, align) {
|
|
71
|
+
const vertical = side === "top" || side === "bottom";
|
|
72
|
+
const [start, end] = vertical ? ["span-right", "span-left"] : ["span-bottom", "span-top"];
|
|
73
|
+
const cross = { start, end, center: "span-all" };
|
|
74
|
+
const order = align === "start" ? ["start", "end", "center"] : align === "end" ? ["end", "start", "center"] : ["center", "start", "end"];
|
|
75
|
+
return [side, OPPOSITE[side]].flatMap((s) => order.map((a) => `${s} ${cross[a]}`));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Set a panel beside its anchor; returns the undo.
|
|
79
|
+
function attach(a, p, name, side, align, offset) {
|
|
80
|
+
const vertical = side === "top" || side === "bottom";
|
|
81
|
+
p.style.inset = "auto";
|
|
82
|
+
|
|
83
|
+
if (canAnchor()) {
|
|
84
|
+
const [first, ...rest] = areas(side, align);
|
|
85
|
+
// An anchor may hold several panels (a tooltip and a popover): the
|
|
86
|
+
// names are a list, and each panel adds and removes only its own.
|
|
87
|
+
const names = () => a.style.getPropertyValue("anchor-name").split(",").map((n) => n.trim()).filter((n) => n.startsWith("--"));
|
|
88
|
+
a.style.setProperty("anchor-name", [...names().filter((n) => n !== name), name].join(", "));
|
|
89
|
+
p.style.setProperty("position-anchor", name);
|
|
90
|
+
p.style.setProperty("position-area", first);
|
|
91
|
+
p.style.setProperty("position-try-fallbacks", rest.join(", "));
|
|
92
|
+
p.style.setProperty("position-visibility", "anchors-visible");
|
|
93
|
+
// Both sides of the axis, so a flipped panel keeps its gap.
|
|
94
|
+
p.style.margin = vertical ? `${offset}px 0` : `0 ${offset}px`;
|
|
95
|
+
// Chrome remembers the last fallback that fitted while the panel is
|
|
96
|
+
// still drawn — and the close fade keeps it drawn — so a panel that
|
|
97
|
+
// once flipped reopens flipped while that side still fits. A changed
|
|
98
|
+
// list makes it forget: every open alternates between the list and
|
|
99
|
+
// the same list with its last place repeated (a no-op try), so each
|
|
100
|
+
// open starts again from the asked side.
|
|
101
|
+
let fresh = false;
|
|
102
|
+
const reprefer = (e) => {
|
|
103
|
+
if (e.newState !== "open") return;
|
|
104
|
+
fresh = !fresh;
|
|
105
|
+
p.style.setProperty("position-try-fallbacks", (fresh ? [...rest, rest[rest.length - 1]] : rest).join(", "));
|
|
106
|
+
};
|
|
107
|
+
p.addEventListener("beforetoggle", reprefer);
|
|
108
|
+
return () => {
|
|
109
|
+
p.removeEventListener("beforetoggle", reprefer);
|
|
110
|
+
const left = names().filter((n) => n !== name);
|
|
111
|
+
if (left.length) a.style.setProperty("anchor-name", left.join(", "));
|
|
112
|
+
else a.style.removeProperty("anchor-name");
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
let frame = 0;
|
|
117
|
+
function place() {
|
|
118
|
+
frame = 0;
|
|
119
|
+
if (!p.matches(":popover-open")) return;
|
|
120
|
+
const r = a.getBoundingClientRect();
|
|
121
|
+
const vw = document.documentElement.clientWidth;
|
|
122
|
+
const vh = document.documentElement.clientHeight;
|
|
123
|
+
// Measure at the origin, where nothing squeezes it.
|
|
124
|
+
p.style.top = "0px";
|
|
125
|
+
p.style.left = "0px";
|
|
126
|
+
const w = p.offsetWidth;
|
|
127
|
+
const h = p.offsetHeight;
|
|
128
|
+
const room = { top: r.top, bottom: vh - r.bottom, left: r.left, right: vw - r.right };
|
|
129
|
+
const need = (vertical ? h : w) + offset + EDGE;
|
|
130
|
+
const s = room[side] < need && room[OPPOSITE[side]] > room[side] ? OPPOSITE[side] : side;
|
|
131
|
+
let x;
|
|
132
|
+
let y;
|
|
133
|
+
if (vertical) {
|
|
134
|
+
y = s === "bottom" ? r.bottom + offset : r.top - offset - h;
|
|
135
|
+
x = align === "start" ? r.left : align === "end" ? r.right - w : r.left + (r.width - w) / 2;
|
|
136
|
+
} else {
|
|
137
|
+
x = s === "right" ? r.right + offset : r.left - offset - w;
|
|
138
|
+
y = align === "start" ? r.top : align === "end" ? r.bottom - h : r.top + (r.height - h) / 2;
|
|
139
|
+
}
|
|
140
|
+
// Shift onto the screen; where neither side had room this may cover
|
|
141
|
+
// the anchor, which beats a panel cut off at the window's edge.
|
|
142
|
+
x = Math.max(EDGE, Math.min(x, vw - w - EDGE));
|
|
143
|
+
y = Math.max(EDGE, Math.min(y, vh - h - EDGE));
|
|
144
|
+
p.style.top = `${Math.round(y)}px`;
|
|
145
|
+
p.style.left = `${Math.round(x)}px`;
|
|
146
|
+
p.dataset.side = s;
|
|
147
|
+
// An anchor scrolled out of the window takes its panel with it.
|
|
148
|
+
p.style.visibility = r.bottom < 0 || r.top > vh || r.right < 0 || r.left > vw ? "hidden" : "";
|
|
149
|
+
}
|
|
150
|
+
const queue = () => {
|
|
151
|
+
if (!frame) frame = requestAnimationFrame(place);
|
|
152
|
+
};
|
|
153
|
+
// A ResizeObserver reports before paint, so the panel is placed in
|
|
154
|
+
// the frame it appears — and again whenever either box changes size.
|
|
155
|
+
const ro = new ResizeObserver(place);
|
|
156
|
+
ro.observe(p);
|
|
157
|
+
ro.observe(a);
|
|
158
|
+
window.addEventListener("scroll", queue, true);
|
|
159
|
+
window.addEventListener("resize", queue);
|
|
160
|
+
return () => {
|
|
161
|
+
ro.disconnect();
|
|
162
|
+
cancelAnimationFrame(frame);
|
|
163
|
+
window.removeEventListener("scroll", queue, true);
|
|
164
|
+
window.removeEventListener("resize", queue);
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Keep an open [popover] panel beside its anchor. CSS anchor positioning
|
|
170
|
+
* where the browser has it (it follows scroll natively and hides the
|
|
171
|
+
* panel when the anchor scrolls away); else it is measured — placed
|
|
172
|
+
* before the first paint, flipped to the opposite side when the asked one
|
|
173
|
+
* has no room, shifted along the other axis to stay on screen, and moved
|
|
174
|
+
* again on scroll, resize and a change in either element's size.
|
|
175
|
+
*/
|
|
176
|
+
export function usePopoverPosition(anchorRef, panelRef, { side = "bottom", align = "center", offset = 6 } = {}) {
|
|
177
|
+
const name = `--pop-${useId().replace(/[^\w-]/g, "")}`;
|
|
178
|
+
const live = useRef({ key: null, off: null });
|
|
179
|
+
|
|
180
|
+
// No dependency list: a panel may mount after its anchor (a portal) or
|
|
181
|
+
// either element be replaced, so every commit looks, and sets up again
|
|
182
|
+
// only when an element or an option changed.
|
|
183
|
+
useLayoutEffect(() => {
|
|
184
|
+
const key = [anchorRef.current, panelRef.current, side, align, offset];
|
|
185
|
+
if (live.current.key?.every((v, i) => v === key[i])) return;
|
|
186
|
+
live.current.off?.();
|
|
187
|
+
const [a, p] = key;
|
|
188
|
+
live.current = { key, off: a && p ? attach(a, p, name, side, align, offset) : null };
|
|
189
|
+
});
|
|
190
|
+
useLayoutEffect(
|
|
191
|
+
() => () => {
|
|
192
|
+
live.current.off?.();
|
|
193
|
+
live.current = { key: null, off: null };
|
|
194
|
+
},
|
|
195
|
+
[],
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const FOCUSABLE = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
200
|
+
|
|
201
|
+
export function Popover({
|
|
202
|
+
trigger,
|
|
203
|
+
label,
|
|
204
|
+
side = "bottom",
|
|
205
|
+
align = "center",
|
|
206
|
+
width = "md",
|
|
207
|
+
open,
|
|
208
|
+
defaultOpen = false,
|
|
209
|
+
onOpenChange,
|
|
210
|
+
variant = "secondary",
|
|
211
|
+
size = "md",
|
|
212
|
+
className,
|
|
213
|
+
children,
|
|
214
|
+
}) {
|
|
215
|
+
const id = useId();
|
|
216
|
+
const btn = useRef(null);
|
|
217
|
+
const pop = useRef(null);
|
|
218
|
+
const controlled = open !== undefined;
|
|
219
|
+
const [own, setOwn] = useState(defaultOpen);
|
|
220
|
+
const isOpen = controlled ? open : own;
|
|
221
|
+
const last = useRef(isOpen);
|
|
222
|
+
last.current = isOpen;
|
|
223
|
+
usePopoverPosition(btn, pop, { side, align });
|
|
224
|
+
|
|
225
|
+
// The state drives the top layer; the browser's own closes (light
|
|
226
|
+
// dismiss, Escape, the trigger again) come back through onToggle.
|
|
227
|
+
useEffect(() => {
|
|
228
|
+
const p = pop.current;
|
|
229
|
+
if (!p) return;
|
|
230
|
+
const shown = p.matches(":popover-open");
|
|
231
|
+
if (isOpen && !shown) p.showPopover();
|
|
232
|
+
else if (!isOpen && shown) p.hidePopover();
|
|
233
|
+
}, [isOpen]);
|
|
234
|
+
|
|
235
|
+
function onToggle(e) {
|
|
236
|
+
const now = e.newState === "open";
|
|
237
|
+
const p = pop.current;
|
|
238
|
+
if (now) (p?.querySelector(FOCUSABLE) ?? p)?.focus({ preventScroll: true });
|
|
239
|
+
else if (!document.activeElement || document.activeElement === document.body || p?.contains(document.activeElement)) {
|
|
240
|
+
btn.current?.focus({ preventScroll: true });
|
|
241
|
+
}
|
|
242
|
+
if (!controlled) setOwn(now);
|
|
243
|
+
if (now !== last.current) onOpenChange?.(now);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Tab out of the panel's end (to anything but the trigger) closes it.
|
|
247
|
+
function onBlur(e) {
|
|
248
|
+
const to = e.relatedTarget;
|
|
249
|
+
if (to && !pop.current?.contains(to) && to !== btn.current) pop.current?.hidePopover();
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const props = {
|
|
253
|
+
ref: btn,
|
|
254
|
+
popoverTarget: id,
|
|
255
|
+
"aria-haspopup": "dialog",
|
|
256
|
+
"aria-expanded": isOpen,
|
|
257
|
+
"aria-controls": id,
|
|
258
|
+
};
|
|
259
|
+
|
|
260
|
+
return (
|
|
261
|
+
<>
|
|
262
|
+
{typeof trigger === "function" ? (
|
|
263
|
+
trigger(props)
|
|
264
|
+
) : (
|
|
265
|
+
<Button variant={variant} size={size} {...props}>
|
|
266
|
+
{trigger}
|
|
267
|
+
</Button>
|
|
268
|
+
)}
|
|
269
|
+
<div
|
|
270
|
+
ref={pop}
|
|
271
|
+
id={id}
|
|
272
|
+
popover="auto"
|
|
273
|
+
role="dialog"
|
|
274
|
+
aria-label={label ?? (typeof trigger === "string" ? trigger : undefined)}
|
|
275
|
+
tabIndex={-1}
|
|
276
|
+
onToggle={onToggle}
|
|
277
|
+
onBlur={onBlur}
|
|
278
|
+
className={panelClass(width, cx(!/(^|\s)p[xytrbl]?-/.test(className ?? "") && "p-4", "text-sm", className))}
|
|
279
|
+
>
|
|
280
|
+
{children}
|
|
281
|
+
</div>
|
|
282
|
+
</>
|
|
283
|
+
);
|
|
284
|
+
}
|