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
package/src/install.mjs
CHANGED
|
@@ -147,6 +147,7 @@ function lay(dir, tpl, before) {
|
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
const blocks = {};
|
|
150
|
+
const blockDeps = {};
|
|
150
151
|
const known = loadBlocks();
|
|
151
152
|
for (const [name, from] of Object.entries(before.manifest?.blocks ?? {})) {
|
|
152
153
|
if (!existsSync(join(dir, BLOCK_DIR, name))) {
|
|
@@ -170,6 +171,20 @@ function lay(dir, tpl, before) {
|
|
|
170
171
|
pins[f.to] = hash;
|
|
171
172
|
}
|
|
172
173
|
blocks[name] = v;
|
|
174
|
+
Object.assign(blockDeps, block.dependencies);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// The blocks' npm packages, at the versions this release pins them to
|
|
178
|
+
// (block.json `dependencies`): a block's files and its packages move
|
|
179
|
+
// together, or an update would lay files the installed package cannot run.
|
|
180
|
+
if (Object.keys(blockDeps).length && existsSync(join(dir, "package.json"))) {
|
|
181
|
+
const path = join(dir, "package.json");
|
|
182
|
+
const { out, changes } = mergePackage(readJson(path, {}), { dependencies: blockDeps });
|
|
183
|
+
if (changes.length) {
|
|
184
|
+
writeJson(path, out);
|
|
185
|
+
if (!written.includes("package.json")) written.push("package.json");
|
|
186
|
+
pkg = [...pkg, ...changes];
|
|
187
|
+
}
|
|
173
188
|
}
|
|
174
189
|
|
|
175
190
|
for (const p of Object.keys(before.pins)) {
|
|
@@ -446,6 +461,9 @@ export function diff(dir) {
|
|
|
446
461
|
const pkgPath = join(dir, "package.json");
|
|
447
462
|
const tplPkg = tpl.files.find((f) => f.class === "merged");
|
|
448
463
|
const pkg = existsSync(pkgPath) && tplPkg ? mergePackage(readJson(pkgPath), readJson(tplPkg.from)).changes : [];
|
|
464
|
+
// …and the installed blocks' npm packages, which update lays with them.
|
|
465
|
+
const blockDeps = Object.assign({}, ...Object.keys(manifest.blocks ?? {}).map((n) => known.find((b) => b.name === n)?.dependencies ?? {}));
|
|
466
|
+
if (existsSync(pkgPath) && Object.keys(blockDeps).length) pkg.push(...mergePackage(readJson(pkgPath), { dependencies: blockDeps }).changes);
|
|
449
467
|
return {
|
|
450
468
|
from: manifest.version,
|
|
451
469
|
to: v,
|
package/src/shadcn.mjs
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
// The free kit and blocks as a shadcn registry, so any Next.js + shadcn
|
|
2
|
+
// project can install them with the CLI it already has:
|
|
3
|
+
//
|
|
4
|
+
// npx shadcn@latest add https://cdn.jsdelivr.net/npm/makersclaw@<version>/r/board.json
|
|
5
|
+
//
|
|
6
|
+
// Two kinds of item:
|
|
7
|
+
// core the kit (components/ui) and the parts (components/parts),
|
|
8
|
+
// plus what a stock shadcn theme lacks: the success, warning
|
|
9
|
+
// and info colours, the text-2xs size, and four CSS rules
|
|
10
|
+
// <block> one block, which lists core as a registry dependency, so
|
|
11
|
+
// `add board` brings the kit along the first time
|
|
12
|
+
//
|
|
13
|
+
// Where it lands: components/makersclaw/{ui,parts,blocks/<name>} — the
|
|
14
|
+
// same relative shape as a Makersclaw app's components/, so every import
|
|
15
|
+
// inside the kit and the blocks (../../ui, ../../parts, ./sample) is
|
|
16
|
+
// relative and resolves unchanged; nothing needs rewriting, and nothing
|
|
17
|
+
// collides with the project's own components/ui. The files are served by
|
|
18
|
+
// jsDelivr straight from the npm tarball (`r/` is built at `npm pack`).
|
|
19
|
+
|
|
20
|
+
import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
21
|
+
import { basename, join } from "node:path";
|
|
22
|
+
import { PKG_ROOT, loadBlocks, loadTemplate, packageInfo } from "./registry.mjs";
|
|
23
|
+
|
|
24
|
+
const ITEM_SCHEMA = "https://ui.shadcn.com/schema/registry-item.json";
|
|
25
|
+
const INDEX_SCHEMA = "https://ui.shadcn.com/schema/registry.json";
|
|
26
|
+
/** Under the project's components folder: @components/ is the CLI's
|
|
27
|
+
* placeholder for it, and what follows is kept as written. */
|
|
28
|
+
export const SHADCN_ROOT = "@components/makersclaw";
|
|
29
|
+
|
|
30
|
+
/** Where the built registry is served from: this version's own files on
|
|
31
|
+
* jsDelivr, so a block's dependency on core names exactly its kit. */
|
|
32
|
+
export function defaultBase(version = packageInfo().version) {
|
|
33
|
+
return `https://cdn.jsdelivr.net/npm/makersclaw@${version}/r`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// What a stock shadcn theme lacks and the kit uses. Tailwind's own
|
|
37
|
+
// green/amber/blue at 600 on light and 400 on dark — status colours,
|
|
38
|
+
// readable on either ground.
|
|
39
|
+
const CSS_VARS = {
|
|
40
|
+
theme: {
|
|
41
|
+
"text-2xs": "0.6875rem",
|
|
42
|
+
"text-2xs--line-height": "1rem",
|
|
43
|
+
// The chart block's series colours. A shadcn theme already defines
|
|
44
|
+
// --chart-1…5 (light and dark); this only makes sure the utilities
|
|
45
|
+
// (fill-chart-1, stroke-chart-2…) read them.
|
|
46
|
+
"color-chart-1": "var(--chart-1)",
|
|
47
|
+
"color-chart-2": "var(--chart-2)",
|
|
48
|
+
"color-chart-3": "var(--chart-3)",
|
|
49
|
+
"color-chart-4": "var(--chart-4)",
|
|
50
|
+
"color-chart-5": "var(--chart-5)",
|
|
51
|
+
},
|
|
52
|
+
light: {
|
|
53
|
+
success: "oklch(0.627 0.194 149.214)",
|
|
54
|
+
warning: "oklch(0.666 0.179 58.318)",
|
|
55
|
+
info: "oklch(0.546 0.245 262.881)",
|
|
56
|
+
},
|
|
57
|
+
dark: {
|
|
58
|
+
success: "oklch(0.792 0.209 151.711)",
|
|
59
|
+
warning: "oklch(0.828 0.189 84.429)",
|
|
60
|
+
info: "oklch(0.707 0.165 254.624)",
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// The rules the kit leans on (the template's app/globals.css): tabular
|
|
65
|
+
// numbers, the native dialog and popover the Sheet and the Menu sit on,
|
|
66
|
+
// and the boundary where a depiction stops wearing the theme.
|
|
67
|
+
const CSS = {
|
|
68
|
+
"@layer base": {
|
|
69
|
+
"[data-nums]": { "font-variant-numeric": "tabular-nums" },
|
|
70
|
+
dialog: { color: "inherit" },
|
|
71
|
+
"dialog::backdrop": { background: "color-mix(in oklab, var(--background) 70%, transparent)" },
|
|
72
|
+
"[popover]": { color: "inherit", margin: "0", padding: "0", border: "0", background: "transparent" },
|
|
73
|
+
},
|
|
74
|
+
"@layer components": {
|
|
75
|
+
"[data-depiction]": {
|
|
76
|
+
isolation: "isolate",
|
|
77
|
+
"color-scheme": "light",
|
|
78
|
+
font: '16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Apple Color Emoji", "Segoe UI Emoji", sans-serif',
|
|
79
|
+
"letter-spacing": "normal",
|
|
80
|
+
"word-spacing": "normal",
|
|
81
|
+
"text-align": "start",
|
|
82
|
+
color: "CanvasText",
|
|
83
|
+
},
|
|
84
|
+
'[data-depiction][data-scheme="dark"]': { "color-scheme": "dark" },
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const README_URL = "https://www.npmjs.com/package/makersclaw";
|
|
89
|
+
|
|
90
|
+
function coreItem() {
|
|
91
|
+
const tpl = loadTemplate("next");
|
|
92
|
+
const files = tpl.files
|
|
93
|
+
.filter((f) => /^components\/(?:ui|parts)\//.test(f.path))
|
|
94
|
+
.map((f) => ({
|
|
95
|
+
path: `templates/next/files/${f.path}`,
|
|
96
|
+
type: "registry:ui",
|
|
97
|
+
target: `${SHADCN_ROOT}/${f.path.slice("components/".length)}`,
|
|
98
|
+
content: readFileSync(f.from, "utf8"),
|
|
99
|
+
}));
|
|
100
|
+
return {
|
|
101
|
+
$schema: ITEM_SCHEMA,
|
|
102
|
+
name: "core",
|
|
103
|
+
type: "registry:ui",
|
|
104
|
+
title: "Makersclaw kit",
|
|
105
|
+
description:
|
|
106
|
+
"The kit every Makersclaw block is built from — Button, Field, Select, Sheet, Tabs, Menu, Notice, Icon, Depiction — " +
|
|
107
|
+
"and the parts bound to data (RecordSwitcher, useFixture). Native elements under the project's own theme tokens.",
|
|
108
|
+
files,
|
|
109
|
+
cssVars: CSS_VARS,
|
|
110
|
+
css: CSS,
|
|
111
|
+
docs: `Installed to components/makersclaw/ui and components/makersclaw/parts. Import: import { Button } from "@/components/makersclaw/ui". Needs Next.js 15+, React 19 and Tailwind v4. ${README_URL}`,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function blockItem(block, base, version) {
|
|
116
|
+
const files = block.files.map((f) => ({
|
|
117
|
+
path: `registry/blocks/${block.name}/${basename(f.from)}`,
|
|
118
|
+
type: "registry:component",
|
|
119
|
+
target: `${SHADCN_ROOT}/blocks/${block.name}/${basename(f.from)}`,
|
|
120
|
+
content: readFileSync(f.from, "utf8"),
|
|
121
|
+
}));
|
|
122
|
+
if (block.readme) {
|
|
123
|
+
// Beside the code, where the developer and their assistant will look.
|
|
124
|
+
files.push({
|
|
125
|
+
path: `registry/blocks/${block.name}/README.md`,
|
|
126
|
+
type: "registry:file",
|
|
127
|
+
target: `${SHADCN_ROOT}/blocks/${block.name}/README.md`,
|
|
128
|
+
content: readFileSync(block.readme, "utf8"),
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
return {
|
|
132
|
+
$schema: ITEM_SCHEMA,
|
|
133
|
+
name: block.name,
|
|
134
|
+
type: "registry:block",
|
|
135
|
+
title: block.title,
|
|
136
|
+
description: block.description,
|
|
137
|
+
registryDependencies: [`${base}/core.json`, ...block.requires.map((r) => `${base}/${r}.json`)],
|
|
138
|
+
dependencies: Object.entries(block.dependencies ?? {}).map(([name, range]) => `${name}@${range}`),
|
|
139
|
+
files,
|
|
140
|
+
categories: block.tags,
|
|
141
|
+
docs:
|
|
142
|
+
`Installed to components/makersclaw/blocks/${block.name}. ` +
|
|
143
|
+
`Import: import { ${block.exports.join(", ")} } from "@/components/makersclaw/blocks/${block.name}". ` +
|
|
144
|
+
`Props and an example: components/makersclaw/blocks/${block.name}/README.md. ` +
|
|
145
|
+
`Makersclaw builds whole apps from these blocks: https://makersclaw.com`,
|
|
146
|
+
meta: { makersclaw: { version, useWhen: block.useWhen } },
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Every item, with its files' content, and the index shadcn's `list` and
|
|
151
|
+
* `search` read (the same items, without content). */
|
|
152
|
+
export function buildRegistry({ base = defaultBase(), version = packageInfo().version } = {}) {
|
|
153
|
+
const items = [coreItem(), ...loadBlocks().map((b) => blockItem(b, base, version))];
|
|
154
|
+
const index = {
|
|
155
|
+
$schema: INDEX_SCHEMA,
|
|
156
|
+
name: "makersclaw",
|
|
157
|
+
homepage: "https://makersclaw.com",
|
|
158
|
+
items: items.map(({ $schema, ...item }) => ({ ...item, files: item.files.map(({ content, ...f }) => f) })),
|
|
159
|
+
};
|
|
160
|
+
return { base, version, items, index };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/** Write r/<name>.json for every item and r/registry.json. */
|
|
164
|
+
export function writeRegistry(outDir = join(PKG_ROOT, "r"), opts = {}) {
|
|
165
|
+
const built = buildRegistry(opts);
|
|
166
|
+
rmSync(outDir, { recursive: true, force: true });
|
|
167
|
+
mkdirSync(outDir, { recursive: true });
|
|
168
|
+
for (const item of built.items) writeFileSync(join(outDir, `${item.name}.json`), `${JSON.stringify(item, null, 2)}\n`);
|
|
169
|
+
writeFileSync(join(outDir, "registry.json"), `${JSON.stringify(built.index, null, 2)}\n`);
|
|
170
|
+
return { ...built, outDir };
|
|
171
|
+
}
|
|
@@ -129,28 +129,162 @@ rarely does. `npm run check` refuses a raw `<select>`, `<dialog>`,
|
|
|
129
129
|
`<svg>`, `role="tab"`, `popover` or `window.confirm()` outside the kit.
|
|
130
130
|
|
|
131
131
|
```jsx
|
|
132
|
-
import { Button, IconButton,
|
|
133
|
-
|
|
132
|
+
import { Button, IconButton, ButtonGroup, ButtonGroupSeparator, Toggle, ToggleGroup,
|
|
133
|
+
Field, Input, TimeInput, Textarea, Select, Switch, Checkbox, RadioGroup, Radio, Rating,
|
|
134
|
+
InputGroup, PasswordInput, InputOTP, Slider, Image, FileInput, FileDrop, fileMatches, Combobox, Command, CommandDialog, Calendar, DatePicker, DateInput, DATE_PRESETS,
|
|
135
|
+
parseDate, isDateString, toDateString, todayString, addDays, addMonths,
|
|
136
|
+
startOfMonth, endOfMonth, dayOfWeek, formatDate, firstDayOfWeek,
|
|
137
|
+
Card, Notice, Badge, Kicker, Empty, Item, ItemGroup, Avatar, AvatarGroup,
|
|
138
|
+
Sheet, Confirm, Tabs, TabPanel, Menu, ContextMenu, Popover, Tooltip, HoverCard,
|
|
139
|
+
Breadcrumb, Pagination, Collapsible, Accordion, Carousel, ScrollArea,
|
|
140
|
+
ResizablePanelGroup, ResizablePanel, ResizableHandle,
|
|
141
|
+
Table, TableHeader, TableBody, TableFooter, TableRow, TableHead, TableCell, TableCaption,
|
|
142
|
+
Spinner, Skeleton, Progress, Separator, Kbd, KbdGroup, AspectRatio,
|
|
143
|
+
Stat, StatGroup, Delta, StatusDot, Legend, Meter, Distribution, Swatch, Steps,
|
|
144
|
+
toast, Toaster, Depiction, Icon, ICON_NAMES, usePopoverPosition, panelClass, cx }
|
|
134
145
|
from "../components/ui"; // "./ui" from a component
|
|
135
146
|
import { RecordSwitcher, useFixture, FixtureNotice, isSample } from "../components/parts";
|
|
136
147
|
```
|
|
137
148
|
|
|
138
149
|
- `Button` — `variant` primary (one per surface) · secondary · quiet ·
|
|
139
|
-
danger · link
|
|
140
|
-
`
|
|
150
|
+
danger · link (inline text: no padding or height, wraps and truncates
|
|
151
|
+
with its sentence; `size="inherit"` takes the sentence's size;
|
|
152
|
+
`tone="muted"` for a secondary link) · nav (a full-width navigation row, start-aligned, normal
|
|
153
|
+
weight, filled by `aria-current="page"`); `size` md (44px) · sm;
|
|
154
|
+
`align` center · start; `icon="plus"`; `href` for a link.
|
|
155
|
+
`IconButton` for an icon alone (`label` required). `loading` while its
|
|
156
|
+
action runs: a spinner, the same width, `aria-busy`, disabled.
|
|
141
157
|
- `Field` wraps `Input`, `Textarea`, `Select`, `Switch`, `Checkbox` with
|
|
142
158
|
its label, hint and error. `Select` with empty `options` renders a
|
|
143
|
-
muted line, never a disabled dropdown.
|
|
159
|
+
muted line, never a disabled dropdown. `TimeInput` — a time of day
|
|
160
|
+
("HH:MM"; `min max step`), the kit's clock in place of the browser's.
|
|
161
|
+
- `Rating` — stars: read-only `value` of `max` (halves drawn, "4.5 out
|
|
162
|
+
of 5" to a reader), or with `onChange` a radio-group input; `size`, `label`.
|
|
163
|
+
- `InputGroup` — an input with `icon`, `prefix` ("https://"), `suffix`
|
|
164
|
+
("USD"), `kbd` and an `action` button (copy, search, show password);
|
|
165
|
+
one border, focus ring and `invalid` for the whole group; `multiline`
|
|
166
|
+
is the chat composer (a growing textarea, `minRows` `maxRows`, `tools`
|
|
167
|
+
and the action in a bar under it, `above` for attached files).
|
|
168
|
+
`PasswordInput` — the password field with a show/hide toggle
|
|
169
|
+
(`autoComplete` passes through; "new-password" on sign-up).
|
|
170
|
+
`Textarea autoGrow` grows with its text the same way. `InputOTP` —
|
|
171
|
+
a one-time code in boxes (`length` or `groups={[3, 3]}`, `digitsOnly`,
|
|
172
|
+
`onComplete(code)`, `invalid`; paste and SMS autofill fill every box).
|
|
173
|
+
`Slider` — a number, or a range with `value={[low, high]}`; `min max
|
|
174
|
+
step`, `showValue` + `format`. A number someone will type is an Input.
|
|
175
|
+
- `Combobox` — pick one or many from a searchable list (`options` with
|
|
176
|
+
`icon`, `description`, `group`, `count` at the right; `multiple` →
|
|
177
|
+
chips; `creatable`; `open` + `onOpenChange` or `defaultOpen`;
|
|
178
|
+
`onSearch` async; `clearable`; in a `Field` by `id`; a bottom sheet on a
|
|
179
|
+
phone). `searchable={false}` is the rich Select (icons, descriptions)
|
|
180
|
+
— a plain list of words stays the native `Select`. `Command` — a
|
|
181
|
+
searchable list of actions (`items` with `icon`, `shortcut`, `keywords`,
|
|
182
|
+
`group`, `onSelect`); `CommandDialog hotkey="k"` is the ⌘K palette.
|
|
144
183
|
- `Sheet` — the one overlay, a rail beside the work (`side="end"`), a
|
|
145
|
-
dialog (`center`) or a bottom sheet; on a narrow window every side
|
|
146
|
-
becomes a bottom sheet
|
|
184
|
+
navigation drawer (`start`), a dialog (`center`) or a bottom sheet; on a narrow window every side
|
|
185
|
+
becomes a bottom sheet; `bare` + `label` for a panel that draws its own
|
|
186
|
+
top (no header, flush body). `Confirm` is the "delete this?" case;
|
|
187
|
+
`consequences`, `requireText` and `acknowledge` hold it until met.
|
|
188
|
+
- `Image src alt ratio fit rounded` — a picture of a thing (thumbnail,
|
|
189
|
+
cover): Skeleton while it loads, a glyph when it fails, lazy, `alt`
|
|
190
|
+
required. Never a raw `<img>`; a face is an `Avatar`.
|
|
191
|
+
- `FileInput onFiles accept multiple` (a Button that opens the picker;
|
|
192
|
+
only a `label` → an IconButton) and `FileDrop` (a drop zone, `label`
|
|
193
|
+
`hint` `size` sm · md; a drop is filtered by `accept`, the rest go to
|
|
194
|
+
`onReject`). Never a raw `<input type="file">`.
|
|
147
195
|
- `Tabs` + `TabPanel` — views of ONE thing (a record's notes | history).
|
|
148
196
|
Never for the app's surfaces; those are the shell's nav.
|
|
149
|
-
- `Menu` — the "…" of a row
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
197
|
+
- `Menu` — the "…" of a row, a View or Account dropdown. `items` are
|
|
198
|
+
data: actions (`icon`, `tone`, `shortcut`, `description`), `{ group,
|
|
199
|
+
items }`, `{ type: "separator" }`, `{ type: "checkbox", checked,
|
|
200
|
+
onCheckedChange }`, `{ type: "radio", value, onValueChange, options }`
|
|
201
|
+
(choices keep it open) and submenus `{ label, items }`; `side` +
|
|
202
|
+
`align`; `size` sm (36px, default) · md (44px trigger). Empty `items` render nothing: a menu is earned by having
|
|
203
|
+
actions. `ContextMenu` opens the same `items` on a region's right-click,
|
|
204
|
+
long press or Shift+F10 — a shortcut, never the only door.
|
|
205
|
+
- `Popover` (a panel beside its `trigger`; `side`, `align`, `width`;
|
|
206
|
+
flips at the window's edge; `open` + `onOpenChange` or uncontrolled),
|
|
207
|
+
`Tooltip` (a short text `label` on hover or keyboard focus; never on
|
|
208
|
+
touch, so it only repeats what is visible) and `HoverCard` (a preview
|
|
209
|
+
of what a link points at; may hold links). `usePopoverPosition` is the
|
|
210
|
+
placement alone, for a floating part of your own.
|
|
211
|
+
- `DatePicker` (a field that opens a Calendar; `mode` single · range,
|
|
212
|
+
`presets`, `clearable`, `min max disabled`; in a `Field` with the same
|
|
213
|
+
`id`), `Calendar` (the grid inline; `mode` single · multiple · range,
|
|
214
|
+
`numberOfMonths`, `captionLayout` dropdown · none (you show and move a
|
|
215
|
+
controlled `month`), `showWeekNumbers`, `weekStartsOn`, `marked` with
|
|
216
|
+
`emphasizeMarked` and `onlyMarked`) and
|
|
217
|
+
`DateInput` (a typed date with the Calendar a button away). Dates are
|
|
218
|
+
`"YYYY-MM-DD"` strings in and out — never a Date — and `addDays`,
|
|
219
|
+
`addMonths`, `formatDate`… do the arithmetic.
|
|
220
|
+
- `RadioGroup` (`options` or `<Radio>` children, each with a
|
|
221
|
+
`description`; `variant` list · card; `orientation`; in a `Field` with
|
|
222
|
+
the same `id`), `Toggle` (`pressed` + `onPressedChange`, aria-pressed),
|
|
223
|
+
`ToggleGroup` (the segmented control; `type` single · multiple) and
|
|
224
|
+
`ButtonGroup` (buttons, icon buttons and a `Menu` joined into one
|
|
225
|
+
piece; `ButtonGroupSeparator` between primary or quiet ones).
|
|
226
|
+
- `Avatar name src size shape status` (initials while loading and when
|
|
227
|
+
the image fails) and `AvatarGroup people max` ("+N" past `max`);
|
|
228
|
+
`Breadcrumb items={[{ label, href }]}` (last is this page; the middle
|
|
229
|
+
folds into "…"; the current page takes the rest of the row); `Pagination page pageCount` with `hrefFor(page)` or
|
|
230
|
+
`onPageChange` (compact on a phone; `pageSize` + `onPageSizeChange`).
|
|
231
|
+
- `Collapsible` (title, meta, `open` + `onOpenChange` or `defaultOpen`;
|
|
232
|
+
`variant` plain · outline · flush for edge-to-edge rows inside a Card;
|
|
233
|
+
`chevron` down · right, the disclosure triangle that turns down)
|
|
234
|
+
and `Accordion` (`items`, `type` single · multiple) — show and hide,
|
|
235
|
+
never a raw `<details>`. `Item` / `ItemGroup` — the list row (media or
|
|
236
|
+
icon, title, description, meta, actions; `href` or `onClick` makes the
|
|
237
|
+
whole row the target; `aria-current`, `onClick`, `target`, `rel` reach
|
|
238
|
+
that link or button). `Table` + `TableHeader`, `TableBody`, `TableRow`
|
|
239
|
+
(`selected`), `TableHead` (`sort` + `onSort`; `sortIndex` when several
|
|
240
|
+
are sorted), `TableCell` (`numeric`)
|
|
241
|
+
— a table that scrolls inside itself on a phone.
|
|
242
|
+
- `Card` (`padding` md · sm · none — none for a table or rows that run
|
|
243
|
+
to the border, never `p-0!`; `titleSize` md · lg for a 20px title),
|
|
244
|
+
`Notice` (tone neutral · info · success · warning · danger),
|
|
245
|
+
`Badge` (tone neutral · primary · success · warning · danger · info;
|
|
246
|
+
`variant` label — small caps · soft — the case as written, every tone
|
|
247
|
+
tinted, primary too · outline — the case as written, a hairline, no
|
|
248
|
+
fill · code — a version tag or a commit hash in the mono face; `hue`
|
|
249
|
+
1..5 for a KIND of thing — a platform, a content type — never a state:
|
|
250
|
+
tone is status, hue is category), `Kicker` (the small line above a heading), `Empty` (a filter
|
|
153
251
|
or search with no matches — not the landing state, that is the fixture).
|
|
252
|
+
- `Spinner` (size sm · md · lg), `Skeleton` (shape line · circle · rect,
|
|
253
|
+
sized by className), `Progress` (`value` of `max`, no value for
|
|
254
|
+
indeterminate; tone; `label`) — waiting, never a hand-drawn loader.
|
|
255
|
+
- `Steps steps={[{ label, description, status, meta }]}` (or `current`)
|
|
256
|
+
— where a staged job has got: `variant` dots · bar (rollout phases);
|
|
257
|
+
status complete · current · pending · failed · skipped; `orientation`
|
|
258
|
+
horizontal · vertical; `pulse`; `label` + `valueText`;
|
|
259
|
+
`hideStepLabels` for bare dots (still pass every label: it is what a
|
|
260
|
+
reader hears); `onSelect`
|
|
261
|
+
only when a step opens something. Never a hand-drawn stepper.
|
|
262
|
+
- `Stat label value unit caption tone delta invert size` (sm · md · lg)
|
|
263
|
+
in a `StatGroup` (the 2–4 summary strip; card · divided · bare);
|
|
264
|
+
`Delta value suffix invert` (coloured by sign; zero is neutral);
|
|
265
|
+
`StatusDot tone pulse label`; `Legend items={[{ tone, label, count }]}`;
|
|
266
|
+
`Meter value max unit target thresholds` (a role=meter; over the limit
|
|
267
|
+
turns danger; `direction` higher · lower picks the tone against the
|
|
268
|
+
target; `valueTone`; `targetMark={false}`; tone `muted` for a plain
|
|
269
|
+
grey share) — numbers and states, never a hand-drawn tile or bar.
|
|
270
|
+
`Delta hideValue` is the arrow alone; `StatusDot` and Legend items take
|
|
271
|
+
`hue` (1..5) for a category. `Distribution segments={[{ label, value,
|
|
272
|
+
tone, hue }]} legend label size` (thin · md) — parts of one whole as
|
|
273
|
+
one stacked bar, a hue per segment, a tone for sentiment. `Swatch color
|
|
274
|
+
label size` — a colour that comes from data; the only inline colour.
|
|
275
|
+
- `Separator` (horizontal · vertical; `decorative={false}` for a real
|
|
276
|
+
one), `Kbd` / `KbdGroup keys={["⌘", "K"]}`, `AspectRatio ratio="video"`
|
|
277
|
+
(its child fills it), `ScrollArea` (a bounded scroller with themed
|
|
278
|
+
scrollbars, `fade`, keyboard-focusable while it overflows; `ref` is the
|
|
279
|
+
scrolling element, for a list that sets its own scrollTop).
|
|
280
|
+
- `toast("Saved")`, `toast.success/.error/.info/.warning(title, {
|
|
281
|
+
description, action, duration })`, `toast.promise(p, { loading,
|
|
282
|
+
success, error })` — nothing to mount; `<Toaster position />` only to
|
|
283
|
+
move the stack. A toast is never the only record of an error.
|
|
284
|
+
- `Carousel label itemsPerView` (scroll-snap; 1 on a phone; dots ·
|
|
285
|
+
counter; `loop`, `autoplay` only when asked), `ResizablePanelGroup`
|
|
286
|
+
+ `ResizablePanel defaultSize minSize` + `ResizableHandle grip`
|
|
287
|
+
(`storageKey` remembers; a horizontal group stacks below md).
|
|
154
288
|
- `Icon name="…"` — one sprite, `ICON_NAMES` lists it. Missing one? Add
|
|
155
289
|
the glyph to `components/ui/icon.jsx`; never an `<svg>` in a surface.
|
|
156
290
|
- `RecordSwitcher` — pick a saved record or make a new one. With nothing
|
|
@@ -100,6 +100,41 @@
|
|
|
100
100
|
border: 0;
|
|
101
101
|
background: transparent;
|
|
102
102
|
}
|
|
103
|
+
|
|
104
|
+
/* Status tones when the preset does not pin them (@theme below reads
|
|
105
|
+
these). The plain fallbacks there are for a dark canvas and read faint
|
|
106
|
+
on a light one, so a light page gets darker ones: by color-scheme (the
|
|
107
|
+
preset's), through light-dark(), where the browser has it; by
|
|
108
|
+
data-theme=light where it does not. Every one reads at 4.5:1 or more
|
|
109
|
+
as text on the Daylight background and card. */
|
|
110
|
+
[data-theme=light] {
|
|
111
|
+
--scheme-success: #15703a;
|
|
112
|
+
--scheme-warning: #9a4a06;
|
|
113
|
+
--scheme-info: #1d4ed8;
|
|
114
|
+
--scheme-destructive: #c01c1c;
|
|
115
|
+
}
|
|
116
|
+
@supports (color: light-dark(red, red)) {
|
|
117
|
+
:root,
|
|
118
|
+
[data-theme] {
|
|
119
|
+
--scheme-success: light-dark(#15703a, #4ade80);
|
|
120
|
+
--scheme-warning: light-dark(#9a4a06, #ffbd38);
|
|
121
|
+
--scheme-info: light-dark(#1d4ed8, #60a5fa);
|
|
122
|
+
--scheme-destructive: light-dark(#c01c1c, #fb2c36);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Chart series 2-5, derived with relative colour (oklch(from …)), which
|
|
127
|
+
Chrome before 119 and Safari before 16.4 lack. Set only where it
|
|
128
|
+
parses; elsewhere @theme falls back to plain colours that still stay
|
|
129
|
+
apart, rather than to no colour at all. */
|
|
130
|
+
@supports (color: oklch(from red l c h)) {
|
|
131
|
+
:root {
|
|
132
|
+
--chart-derived-2: oklch(from var(--primary, var(--midground-base)) clamp(0.55, l, 0.8) clamp(0.12, c, 0.2) calc(h + 144));
|
|
133
|
+
--chart-derived-3: oklch(from var(--primary, var(--midground-base)) clamp(0.55, l, 0.8) clamp(0.12, c, 0.2) calc(h + 288));
|
|
134
|
+
--chart-derived-4: oklch(from var(--primary, var(--midground-base)) clamp(0.55, l, 0.8) clamp(0.12, c, 0.2) calc(h + 72));
|
|
135
|
+
--chart-derived-5: oklch(from var(--primary, var(--midground-base)) clamp(0.55, l, 0.8) clamp(0.12, c, 0.2) calc(h + 216));
|
|
136
|
+
}
|
|
137
|
+
}
|
|
103
138
|
}
|
|
104
139
|
|
|
105
140
|
/* The boundary where the workspace theme stops: a depiction (README §3c),
|
|
@@ -150,16 +185,32 @@
|
|
|
150
185
|
--color-accent: var(--accent, color-mix(in srgb, var(--midground-base) 12%, var(--background-base)));
|
|
151
186
|
--color-accent-foreground: var(--accent-foreground, var(--midground-base));
|
|
152
187
|
|
|
153
|
-
--color-destructive: var(--destructive, #fb2c36);
|
|
188
|
+
--color-destructive: var(--destructive, var(--scheme-destructive, #fb2c36));
|
|
154
189
|
--color-destructive-foreground: var(--destructive-foreground, #ffffff);
|
|
155
|
-
--color-success: var(--success, #4ade80);
|
|
156
|
-
--color-warning: var(--warning, #ffbd38);
|
|
157
|
-
--color-info: var(--info, #60a5fa);
|
|
190
|
+
--color-success: var(--success, var(--scheme-success, #4ade80));
|
|
191
|
+
--color-warning: var(--warning, var(--scheme-warning, #ffbd38));
|
|
192
|
+
--color-info: var(--info, var(--scheme-info, #60a5fa));
|
|
158
193
|
|
|
159
194
|
--color-border: var(--border, color-mix(in srgb, var(--midground-base) 15%, transparent));
|
|
160
195
|
--color-input: var(--input, color-mix(in srgb, var(--midground-base) 15%, transparent));
|
|
161
196
|
--color-ring: var(--ring, var(--midground-base));
|
|
162
197
|
|
|
198
|
+
/* Chart series (fill-chart-1, stroke-chart-2, bg-chart-3…), for the chart
|
|
199
|
+
block: several colours that must stay apart in every theme. A preset
|
|
200
|
+
(or a shadcn theme) may pin --chart-N. Otherwise chart-1 is the primary
|
|
201
|
+
and the others turn its hue round the wheel, 144° a step so neighbours
|
|
202
|
+
never sit close, keeping its lightness (the primary already reads on
|
|
203
|
+
this canvas) with a floor on chroma so a grey or pastel theme still
|
|
204
|
+
gets colours. Not success/warning/info: those are status, and a theme's
|
|
205
|
+
primary is often one of them (amber, mint, blue). The turn is worked
|
|
206
|
+
out in the base layer (--chart-derived-N); the hex after it is for a
|
|
207
|
+
browser without relative colour. */
|
|
208
|
+
--color-chart-1: var(--chart-1, var(--primary, var(--midground-base)));
|
|
209
|
+
--color-chart-2: var(--chart-2, var(--chart-derived-2, #14b8a6));
|
|
210
|
+
--color-chart-3: var(--chart-3, var(--chart-derived-3, #a78bfa));
|
|
211
|
+
--color-chart-4: var(--chart-4, var(--chart-derived-4, #f472b6));
|
|
212
|
+
--color-chart-5: var(--chart-5, var(--chart-derived-5, #38bdf8));
|
|
213
|
+
|
|
163
214
|
--radius-sm: calc(var(--theme-radius) - 4px);
|
|
164
215
|
--radius-md: calc(var(--theme-radius) - 2px);
|
|
165
216
|
--radius-lg: var(--theme-radius);
|
|
@@ -48,7 +48,7 @@ const STATIC_ONLY = process.argv.includes("--static");
|
|
|
48
48
|
// update` lays both folders again.
|
|
49
49
|
// Exact names AND extensions: Next resolves .js before .jsx, so a
|
|
50
50
|
// components/ui/depiction.js beside depiction.jsx would win unseen.
|
|
51
|
-
const KIT = /^components\/(?:ui\/(?:cx|index)\.js|ui\/(?:button|depiction|field|icon|menu|notice|sheet|tabs)\.jsx|parts\/index\.js|parts\/(?:fixture|record-switcher)\.jsx)$/;
|
|
51
|
+
const KIT = /^components\/(?:ui\/(?:cx|index)\.js|ui\/(?:radio|toggle|button-group|avatar|breadcrumb|pagination|button|collapsible|item|table|depiction|feedback|stat|distribution|swatch|steps|separator|scroll-area|field|icon|menu|context-menu|popover|calendar|date-picker|tooltip|notice|sheet|tabs|slider|input-group|image|file-input|input-otp|command|combobox|rating|toast|carousel|resizable)\.jsx|parts\/(?:index|sample)\.js|parts\/(?:fixture|record-switcher)\.jsx)$/;
|
|
52
52
|
|
|
53
53
|
// The pins: sha256 of every fixed file, written by `makersclaw init` and
|
|
54
54
|
// `makersclaw add` (check/pins.json). Read first, because a BLOCK is
|
|
@@ -209,11 +209,11 @@ const ATTRS = String.raw`(?:"[^"]*"|'[^']*'|\{(?:[^{}]|\{[^{}]*\})*\}|[^>"'{])*`
|
|
|
209
209
|
const RULES = [
|
|
210
210
|
[/<select\b/, "Select from components/ui, or RecordSwitcher from components/parts", files],
|
|
211
211
|
[/<dialog\b/, "Sheet or Confirm from components/ui", files],
|
|
212
|
-
[/<details\b/, "
|
|
212
|
+
[/<details\b/, "Collapsible or Accordion from components/ui", files],
|
|
213
213
|
[/role=["']tab(?:list)?["']/, "Tabs from components/ui", files],
|
|
214
214
|
[/role=["']menu(?:item)?["']/, "Menu from components/ui", files],
|
|
215
215
|
[/role=["']dialog["']/, "Sheet from components/ui", files],
|
|
216
|
-
[/\bpopover=/, "Menu from components/ui", files],
|
|
216
|
+
[/\bpopover=/, "Popover, Tooltip, HoverCard or Menu from components/ui", files],
|
|
217
217
|
[/window\.confirm\(/, "Confirm from components/ui", files],
|
|
218
218
|
[/<svg\b/, "Icon from components/ui (add a glyph there if it is missing)", appFiles],
|
|
219
219
|
];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
import { useMemo, useState } from "react";
|
|
4
|
-
import { markSample } from "
|
|
4
|
+
import { markSample } from "./sample";
|
|
5
5
|
import { Button, Notice } from "../ui";
|
|
6
6
|
|
|
7
7
|
// The worked example, never persisted. A surface opens populated (README
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Pure: importable from either side. The parts use it in the browser
|
|
2
|
+
// (fixture.jsx); lib/sample.js re-exports it for server code (lib/data.js).
|
|
3
|
+
// It lives beside the parts, not in lib/, so the parts travel as one folder
|
|
4
|
+
// — into an app's components/parts, or a shadcn project's
|
|
5
|
+
// components/makersclaw/parts — and import nothing outside it but the kit.
|
|
6
|
+
|
|
7
|
+
/** Sample rows get stable ids and a `_sample: true` marker, so a surface
|
|
8
|
+
* can label them until real rows exist and refuse to edit them. */
|
|
9
|
+
export function markSample(sample, idColumn = "id") {
|
|
10
|
+
return (sample ?? []).map((r, i) => ({
|
|
11
|
+
...r,
|
|
12
|
+
[idColumn]: r[idColumn] ?? `sample-${i + 1}`,
|
|
13
|
+
_sample: true,
|
|
14
|
+
}));
|
|
15
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, useState } from "react";
|
|
4
|
+
import { cx } from "./cx";
|
|
5
|
+
import { Icon } from "./icon";
|
|
6
|
+
|
|
7
|
+
// Avatar — a person's face, or their initials while it loads and when it
|
|
8
|
+
// fails. The initials are always drawn; the image lays over them only
|
|
9
|
+
// once it has loaded, so a slow, missing or broken `src` never shows a
|
|
10
|
+
// hole or the browser's broken-image glyph. No name either: a user icon.
|
|
11
|
+
//
|
|
12
|
+
// name "Jane Cooper" → JC; also the accessible name
|
|
13
|
+
// src the image; optional
|
|
14
|
+
// size xs (24px) · sm (32px) · md (40px) · lg (56px)
|
|
15
|
+
// shape round · square (a company, a bot, a workspace)
|
|
16
|
+
// status online · away · busy · offline — a dot, named to a reader
|
|
17
|
+
// label overrides what a screen reader says
|
|
18
|
+
//
|
|
19
|
+
// AvatarGroup below is the overlapping stack with "+N" after `max`.
|
|
20
|
+
|
|
21
|
+
const SIZES = {
|
|
22
|
+
xs: { box: "h-6 w-6 text-2xs", dot: "h-1.5 w-1.5", icon: 12, overlap: "-space-x-1.5" },
|
|
23
|
+
sm: { box: "h-8 w-8 text-xs", dot: "h-2 w-2", icon: 14, overlap: "-space-x-2" },
|
|
24
|
+
md: { box: "h-10 w-10 text-sm", dot: "h-2.5 w-2.5", icon: 18, overlap: "-space-x-2.5" },
|
|
25
|
+
lg: { box: "h-14 w-14 text-lg", dot: "h-3.5 w-3.5", icon: 24, overlap: "-space-x-3" },
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const SHAPES = { round: "rounded-full", square: "rounded-md" };
|
|
29
|
+
|
|
30
|
+
// Colour is the signal: the status tones are the workspace's status tokens.
|
|
31
|
+
const STATUS = {
|
|
32
|
+
online: { dot: "bg-success", say: "online" },
|
|
33
|
+
away: { dot: "bg-warning", say: "away" },
|
|
34
|
+
busy: { dot: "bg-destructive", say: "busy" },
|
|
35
|
+
offline: { dot: "bg-muted-foreground", say: "offline" },
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** "Jane Cooper" → "JC", "jane@acme.com" → "J", "Priya" → "P". First and
|
|
39
|
+
* last word, by code point, so an accented or non-Latin name survives. */
|
|
40
|
+
function initials(name) {
|
|
41
|
+
const words = String(name ?? "").split("@")[0].trim().split(/[\s._-]+/).filter(Boolean);
|
|
42
|
+
if (words.length === 0) return "";
|
|
43
|
+
const first = Array.from(words[0])[0] ?? "";
|
|
44
|
+
const last = words.length > 1 ? Array.from(words[words.length - 1])[0] ?? "" : "";
|
|
45
|
+
return (first + last).toUpperCase();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function Avatar({ name, src, size = "md", shape = "round", status, label, className }) {
|
|
49
|
+
const s = SIZES[size] ?? SIZES.md;
|
|
50
|
+
const round = SHAPES[shape] ?? SHAPES.round;
|
|
51
|
+
const st = STATUS[status];
|
|
52
|
+
const img = useRef(null);
|
|
53
|
+
// Both hold the src they are about, so a new src starts fresh unreset.
|
|
54
|
+
const [loaded, setLoaded] = useState(null);
|
|
55
|
+
const [failed, setFailed] = useState(null);
|
|
56
|
+
|
|
57
|
+
// A server-rendered <img> can load or fail before React is listening.
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
const i = img.current;
|
|
60
|
+
if (!i || !src || !i.complete) return;
|
|
61
|
+
if (i.naturalWidth > 0) setLoaded(src);
|
|
62
|
+
else setFailed(src);
|
|
63
|
+
}, [src]);
|
|
64
|
+
|
|
65
|
+
const text = initials(name);
|
|
66
|
+
const said = label ?? ([name, st?.say].filter(Boolean).join(", ") || undefined);
|
|
67
|
+
const showImg = src && failed !== src;
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<span
|
|
71
|
+
role={said ? "img" : undefined}
|
|
72
|
+
aria-label={said}
|
|
73
|
+
aria-hidden={said ? undefined : true}
|
|
74
|
+
title={name || undefined}
|
|
75
|
+
className={cx("relative inline-flex shrink-0 select-none", round, s.box, className)}
|
|
76
|
+
>
|
|
77
|
+
<span className={cx("relative flex h-full w-full items-center justify-center overflow-hidden bg-muted font-medium text-muted-foreground", round)}>
|
|
78
|
+
{/* Hidden, not removed, once the image is in: a transparent PNG must not show letters through it. */}
|
|
79
|
+
<span aria-hidden="true" className={cx("inline-flex leading-none", loaded === src && showImg && "invisible")}>
|
|
80
|
+
{text || <Icon name="user" size={s.icon} />}
|
|
81
|
+
</span>
|
|
82
|
+
{showImg ? (
|
|
83
|
+
<img
|
|
84
|
+
ref={img}
|
|
85
|
+
src={src}
|
|
86
|
+
alt=""
|
|
87
|
+
onLoad={() => setLoaded(src)}
|
|
88
|
+
onError={() => setFailed(src)}
|
|
89
|
+
className={cx("absolute inset-0 h-full w-full object-cover", loaded === src ? "opacity-100" : "opacity-0")}
|
|
90
|
+
/>
|
|
91
|
+
) : null}
|
|
92
|
+
</span>
|
|
93
|
+
{st ? (
|
|
94
|
+
<span
|
|
95
|
+
aria-hidden="true"
|
|
96
|
+
className={cx(
|
|
97
|
+
"absolute rounded-full ring-2 ring-background",
|
|
98
|
+
shape === "square" ? "-bottom-0.5 -right-0.5" : "bottom-0 right-0",
|
|
99
|
+
s.dot,
|
|
100
|
+
st.dot,
|
|
101
|
+
)}
|
|
102
|
+
/>
|
|
103
|
+
) : null}
|
|
104
|
+
</span>
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Faces overlapping, the first `max` of `people`, then "+N" naming the
|
|
109
|
+
* rest on hover and to a reader. No status dots: the next face covers
|
|
110
|
+
* them. Empty `people` renders nothing.
|
|
111
|
+
*
|
|
112
|
+
* people [{ name, src? }]
|
|
113
|
+
* max how many faces before "+N" (default 4)
|
|
114
|
+
*/
|
|
115
|
+
export function AvatarGroup({ people, max = 4, size = "sm", shape = "round", label, className }) {
|
|
116
|
+
const list = (people ?? []).filter(Boolean);
|
|
117
|
+
if (list.length === 0) return null;
|
|
118
|
+
const s = SIZES[size] ?? SIZES.sm;
|
|
119
|
+
const round = SHAPES[shape] ?? SHAPES.round;
|
|
120
|
+
const shown = list.slice(0, Math.max(1, max));
|
|
121
|
+
const rest = list.slice(shown.length);
|
|
122
|
+
const restNames = rest.map((p) => p.name).filter(Boolean).join(", ");
|
|
123
|
+
|
|
124
|
+
return (
|
|
125
|
+
<div role="group" aria-label={label ?? `${list.length} people`} className={cx("flex items-center", s.overlap, className)}>
|
|
126
|
+
{shown.map((p, i) => (
|
|
127
|
+
<Avatar key={i} name={p.name} src={p.src} size={size} shape={shape} className="ring-2 ring-background" />
|
|
128
|
+
))}
|
|
129
|
+
{rest.length > 0 ? (
|
|
130
|
+
<span
|
|
131
|
+
role="img"
|
|
132
|
+
aria-label={`and ${rest.length} more${restNames ? `: ${restNames}` : ""}`}
|
|
133
|
+
title={restNames || undefined}
|
|
134
|
+
className={cx("relative inline-flex shrink-0 items-center justify-center bg-muted font-medium text-muted-foreground ring-2 ring-background", round, s.box)}
|
|
135
|
+
>
|
|
136
|
+
<span data-nums aria-hidden="true" className="leading-none">+{rest.length}</span>
|
|
137
|
+
</span>
|
|
138
|
+
) : null}
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
}
|