makersclaw 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +180 -0
- package/package.json +3 -2
- package/r/annotate.json +62 -0
- package/r/approval-request.json +52 -0
- package/r/audio-player.json +74 -0
- package/r/auth-form.json +55 -0
- package/r/board.json +10 -6
- package/r/calendar-view.json +105 -0
- package/r/cart.json +62 -0
- package/r/chart.json +83 -0
- package/r/chat.json +95 -0
- package/r/code-editor.json +94 -0
- package/r/comment-box.json +64 -0
- package/r/contact-section.json +53 -0
- package/r/core.json +205 -8
- package/r/csv-import.json +63 -0
- package/r/data-table.json +69 -0
- package/r/diagram.json +74 -0
- package/r/doc-editor.json +82 -0
- package/r/doc-page.json +61 -0
- package/r/email-render.json +73 -0
- package/r/faq.json +50 -0
- package/r/file-upload.json +54 -0
- package/r/flow-canvas.json +93 -0
- package/r/footer.json +52 -0
- package/r/gantt.json +70 -0
- package/r/job-panel.json +12 -7
- package/r/json-editor.json +66 -0
- package/r/map.json +89 -0
- package/r/menubar.json +52 -0
- package/r/mind-map.json +67 -0
- package/r/navigation-menu.json +52 -0
- package/r/order-detail.json +54 -0
- package/r/org-chart.json +66 -0
- package/r/page-builder.json +105 -0
- package/r/payment-methods.json +51 -0
- package/r/pdf-document.json +79 -0
- package/r/pdf-viewer.json +88 -0
- package/r/product-detail.json +76 -0
- package/r/product-grid.json +65 -0
- package/r/record-form.json +67 -0
- package/r/record-notes.json +55 -0
- package/r/registry.json +3411 -29
- package/r/search-dialog.json +51 -0
- package/r/settings-list.json +66 -0
- package/r/setup-checklist.json +51 -0
- package/r/share-dialog.json +52 -0
- package/r/sidebar.json +69 -0
- package/r/signature-pad.json +72 -0
- package/r/sketch-canvas.json +99 -0
- package/r/spreadsheet.json +90 -0
- package/r/stat-cards.json +66 -0
- package/r/task-list.json +63 -0
- package/r/task-model.json +98 -0
- package/r/testimonials.json +52 -0
- package/r/transaction-list.json +53 -0
- package/r/whiteboard.json +66 -0
- package/registry/blocks/annotate/README.md +179 -0
- package/registry/blocks/annotate/annotate-data.js +250 -0
- package/registry/blocks/annotate/annotate.jsx +646 -0
- package/registry/blocks/annotate/block.json +10 -0
- package/registry/blocks/annotate/demo.jsx +135 -0
- package/registry/blocks/annotate/index.js +15 -0
- package/registry/blocks/approval-request/README.md +116 -0
- package/registry/blocks/approval-request/approval-request.jsx +386 -0
- package/registry/blocks/approval-request/block.json +10 -0
- package/registry/blocks/approval-request/demo.jsx +127 -0
- package/registry/blocks/approval-request/index.js +4 -0
- package/registry/blocks/audio-player/README.md +167 -0
- package/registry/blocks/audio-player/audio-player.jsx +623 -0
- package/registry/blocks/audio-player/block.json +14 -0
- package/registry/blocks/audio-player/colors.js +109 -0
- package/registry/blocks/audio-player/demo.jsx +209 -0
- package/registry/blocks/audio-player/index.js +6 -0
- package/registry/blocks/audio-player/time.js +67 -0
- package/registry/blocks/audio-player/wavesurfer.js +9 -0
- package/registry/blocks/auth-form/README.md +126 -0
- package/registry/blocks/auth-form/auth-form.jsx +568 -0
- package/registry/blocks/auth-form/block.json +10 -0
- package/registry/blocks/auth-form/demo.jsx +131 -0
- package/registry/blocks/auth-form/index.js +3 -0
- package/registry/blocks/board/README.md +55 -5
- package/registry/blocks/board/block.json +2 -2
- package/registry/blocks/board/board.jsx +230 -86
- package/registry/blocks/board/demo.jsx +103 -24
- package/registry/blocks/calendar-view/README.md +180 -0
- package/registry/blocks/calendar-view/agenda.jsx +147 -0
- package/registry/blocks/calendar-view/block.json +76 -0
- package/registry/blocks/calendar-view/calendar-model.js +442 -0
- package/registry/blocks/calendar-view/calendar.jsx +627 -0
- package/registry/blocks/calendar-view/demo.jsx +195 -0
- package/registry/blocks/calendar-view/draft.jsx +49 -0
- package/registry/blocks/calendar-view/index.js +39 -0
- package/registry/blocks/calendar-view/month.jsx +346 -0
- package/registry/blocks/calendar-view/paint.js +69 -0
- package/registry/blocks/calendar-view/time-grid.jsx +527 -0
- package/registry/blocks/calendar-view/tray.jsx +87 -0
- package/registry/blocks/cart/README.md +146 -0
- package/registry/blocks/cart/block.json +10 -0
- package/registry/blocks/cart/cart.jsx +597 -0
- package/registry/blocks/cart/demo.jsx +98 -0
- package/registry/blocks/cart/index.js +4 -0
- package/registry/blocks/cart/money.js +28 -0
- package/registry/blocks/chart/README.md +316 -0
- package/registry/blocks/chart/block.json +10 -0
- package/registry/blocks/chart/cartesian.jsx +642 -0
- package/registry/blocks/chart/core.jsx +262 -0
- package/registry/blocks/chart/demo.jsx +357 -0
- package/registry/blocks/chart/heatmap.jsx +336 -0
- package/registry/blocks/chart/index.js +8 -0
- package/registry/blocks/chart/pie.jsx +245 -0
- package/registry/blocks/chart/sparkline.jsx +88 -0
- package/registry/blocks/chat/README.md +273 -0
- package/registry/blocks/chat/attachment.jsx +95 -0
- package/registry/blocks/chat/block.json +10 -0
- package/registry/blocks/chat/chat.jsx +132 -0
- package/registry/blocks/chat/composer.jsx +364 -0
- package/registry/blocks/chat/demo.jsx +578 -0
- package/registry/blocks/chat/header.jsx +34 -0
- package/registry/blocks/chat/index.js +9 -0
- package/registry/blocks/chat/message.jsx +450 -0
- package/registry/blocks/chat/scroller.jsx +247 -0
- package/registry/blocks/chat/text.jsx +104 -0
- package/registry/blocks/code-editor/README.md +210 -0
- package/registry/blocks/code-editor/block.json +22 -0
- package/registry/blocks/code-editor/code-editor.jsx +534 -0
- package/registry/blocks/code-editor/codemirror.js +38 -0
- package/registry/blocks/code-editor/demo.jsx +205 -0
- package/registry/blocks/code-editor/index.js +8 -0
- package/registry/blocks/code-editor/json.js +317 -0
- package/registry/blocks/code-editor/sql.js +136 -0
- package/registry/blocks/code-editor/text.js +101 -0
- package/registry/blocks/code-editor/theme.js +186 -0
- package/registry/blocks/comment-box/README.md +123 -0
- package/registry/blocks/comment-box/block.json +10 -0
- package/registry/blocks/comment-box/comment-body.jsx +217 -0
- package/registry/blocks/comment-box/comment-box.jsx +198 -0
- package/registry/blocks/comment-box/comment-time.jsx +77 -0
- package/registry/blocks/comment-box/demo.jsx +141 -0
- package/registry/blocks/comment-box/index.js +8 -0
- package/registry/blocks/contact-section/README.md +152 -0
- package/registry/blocks/contact-section/block.json +11 -0
- package/registry/blocks/contact-section/contact-section.jsx +509 -0
- package/registry/blocks/contact-section/demo.jsx +93 -0
- package/registry/blocks/contact-section/index.js +4 -0
- package/registry/blocks/csv-import/README.md +133 -0
- package/registry/blocks/csv-import/block.json +13 -0
- package/registry/blocks/csv-import/csv-import.jsx +479 -0
- package/registry/blocks/csv-import/demo.jsx +106 -0
- package/registry/blocks/csv-import/import.js +200 -0
- package/registry/blocks/csv-import/index.js +7 -0
- package/registry/blocks/data-table/README.md +386 -0
- package/registry/blocks/data-table/block.json +10 -0
- package/registry/blocks/data-table/data-table.jsx +1164 -0
- package/registry/blocks/data-table/demo.jsx +588 -0
- package/registry/blocks/data-table/index.js +5 -0
- package/registry/blocks/data-table/model.js +169 -0
- package/registry/blocks/diagram/README.md +108 -0
- package/registry/blocks/diagram/block.json +13 -0
- package/registry/blocks/diagram/demo.jsx +113 -0
- package/registry/blocks/diagram/diagram.jsx +481 -0
- package/registry/blocks/diagram/index.js +7 -0
- package/registry/blocks/diagram/mermaid.js +52 -0
- package/registry/blocks/diagram/palette.js +313 -0
- package/registry/blocks/diagram/source.js +98 -0
- package/registry/blocks/doc-editor/README.md +215 -0
- package/registry/blocks/doc-editor/block.json +15 -0
- package/registry/blocks/doc-editor/demo.jsx +225 -0
- package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
- package/registry/blocks/doc-editor/doc.js +309 -0
- package/registry/blocks/doc-editor/index.js +7 -0
- package/registry/blocks/doc-editor/schema.jsx +56 -0
- package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
- package/registry/blocks/doc-editor/theme.js +82 -0
- package/registry/blocks/doc-page/README.md +119 -0
- package/registry/blocks/doc-page/autosave.js +104 -0
- package/registry/blocks/doc-page/block.json +10 -0
- package/registry/blocks/doc-page/demo.jsx +137 -0
- package/registry/blocks/doc-page/doc-page.jsx +276 -0
- package/registry/blocks/doc-page/index.js +4 -0
- package/registry/blocks/email-render/README.md +151 -0
- package/registry/blocks/email-render/block.json +14 -0
- package/registry/blocks/email-render/demo.jsx +153 -0
- package/registry/blocks/email-render/doc-email.jsx +210 -0
- package/registry/blocks/email-render/email.jsx +221 -0
- package/registry/blocks/email-render/index.js +10 -0
- package/registry/blocks/email-render/render.js +50 -0
- package/registry/blocks/email-render/theme.js +215 -0
- package/registry/blocks/faq/README.md +101 -0
- package/registry/blocks/faq/block.json +11 -0
- package/registry/blocks/faq/demo.jsx +89 -0
- package/registry/blocks/faq/faq.jsx +220 -0
- package/registry/blocks/faq/index.js +4 -0
- package/registry/blocks/file-upload/README.md +138 -0
- package/registry/blocks/file-upload/block.json +10 -0
- package/registry/blocks/file-upload/demo.jsx +204 -0
- package/registry/blocks/file-upload/file-upload.jsx +635 -0
- package/registry/blocks/file-upload/index.js +4 -0
- package/registry/blocks/flow-canvas/README.md +420 -0
- package/registry/blocks/flow-canvas/block.json +13 -0
- package/registry/blocks/flow-canvas/board.js +819 -0
- package/registry/blocks/flow-canvas/chrome.jsx +649 -0
- package/registry/blocks/flow-canvas/context.jsx +35 -0
- package/registry/blocks/flow-canvas/demo.jsx +249 -0
- package/registry/blocks/flow-canvas/edges.jsx +107 -0
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
- package/registry/blocks/flow-canvas/index.js +41 -0
- package/registry/blocks/flow-canvas/nodes.jsx +392 -0
- package/registry/blocks/flow-canvas/theme.js +174 -0
- package/registry/blocks/footer/README.md +133 -0
- package/registry/blocks/footer/block.json +11 -0
- package/registry/blocks/footer/demo.jsx +119 -0
- package/registry/blocks/footer/footer.jsx +406 -0
- package/registry/blocks/footer/index.js +4 -0
- package/registry/blocks/gantt/README.md +220 -0
- package/registry/blocks/gantt/block.json +10 -0
- package/registry/blocks/gantt/demo.jsx +148 -0
- package/registry/blocks/gantt/gantt.jsx +923 -0
- package/registry/blocks/gantt/index.js +7 -0
- package/registry/blocks/gantt/rows.jsx +468 -0
- package/registry/blocks/gantt/schedule.js +278 -0
- package/registry/blocks/job-panel/README.md +80 -0
- package/registry/blocks/job-panel/block.json +3 -3
- package/registry/blocks/job-panel/demo.jsx +230 -3
- package/registry/blocks/job-panel/job-panel.jsx +169 -3
- package/registry/blocks/json-editor/README.md +133 -0
- package/registry/blocks/json-editor/block.json +10 -0
- package/registry/blocks/json-editor/demo.jsx +92 -0
- package/registry/blocks/json-editor/index.js +7 -0
- package/registry/blocks/json-editor/json-editor.jsx +305 -0
- package/registry/blocks/json-editor/json-tree.jsx +393 -0
- package/registry/blocks/json-editor/tree.js +225 -0
- package/registry/blocks/map/README.md +221 -0
- package/registry/blocks/map/block.json +14 -0
- package/registry/blocks/map/demo.jsx +201 -0
- package/registry/blocks/map/geo.js +198 -0
- package/registry/blocks/map/index.js +8 -0
- package/registry/blocks/map/list.jsx +128 -0
- package/registry/blocks/map/map-view.jsx +715 -0
- package/registry/blocks/map/maplibre.js +30 -0
- package/registry/blocks/map/marks.jsx +146 -0
- package/registry/blocks/map/theme.js +142 -0
- package/registry/blocks/menubar/README.md +109 -0
- package/registry/blocks/menubar/block.json +10 -0
- package/registry/blocks/menubar/demo.jsx +128 -0
- package/registry/blocks/menubar/index.js +4 -0
- package/registry/blocks/menubar/menubar.jsx +199 -0
- package/registry/blocks/mind-map/README.md +206 -0
- package/registry/blocks/mind-map/block.json +10 -0
- package/registry/blocks/mind-map/demo.jsx +103 -0
- package/registry/blocks/mind-map/index.js +31 -0
- package/registry/blocks/mind-map/mind-map.jsx +1125 -0
- package/registry/blocks/mind-map/topic.jsx +143 -0
- package/registry/blocks/mind-map/tree.js +645 -0
- package/registry/blocks/navigation-menu/README.md +124 -0
- package/registry/blocks/navigation-menu/block.json +10 -0
- package/registry/blocks/navigation-menu/demo.jsx +84 -0
- package/registry/blocks/navigation-menu/index.js +4 -0
- package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
- package/registry/blocks/order-detail/README.md +109 -0
- package/registry/blocks/order-detail/block.json +10 -0
- package/registry/blocks/order-detail/demo.jsx +88 -0
- package/registry/blocks/order-detail/index.js +4 -0
- package/registry/blocks/order-detail/order-detail.jsx +354 -0
- package/registry/blocks/org-chart/README.md +145 -0
- package/registry/blocks/org-chart/block.json +10 -0
- package/registry/blocks/org-chart/demo.jsx +94 -0
- package/registry/blocks/org-chart/index.js +7 -0
- package/registry/blocks/org-chart/org-chart.jsx +631 -0
- package/registry/blocks/org-chart/org.js +245 -0
- package/registry/blocks/org-chart/person.jsx +96 -0
- package/registry/blocks/page-builder/README.md +257 -0
- package/registry/blocks/page-builder/block.json +14 -0
- package/registry/blocks/page-builder/demo.jsx +145 -0
- package/registry/blocks/page-builder/grapes.js +18 -0
- package/registry/blocks/page-builder/index.js +11 -0
- package/registry/blocks/page-builder/page-builder.jsx +704 -0
- package/registry/blocks/page-builder/page-view.jsx +33 -0
- package/registry/blocks/page-builder/page.js +118 -0
- package/registry/blocks/page-builder/panels.jsx +588 -0
- package/registry/blocks/page-builder/sections.js +209 -0
- package/registry/blocks/page-builder/theme.js +87 -0
- package/registry/blocks/page-builder/thumbs.jsx +189 -0
- package/registry/blocks/page-builder/tokens.js +329 -0
- package/registry/blocks/payment-methods/README.md +104 -0
- package/registry/blocks/payment-methods/block.json +10 -0
- package/registry/blocks/payment-methods/demo.jsx +71 -0
- package/registry/blocks/payment-methods/index.js +4 -0
- package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
- package/registry/blocks/pdf-document/README.md +213 -0
- package/registry/blocks/pdf-document/block.json +13 -0
- package/registry/blocks/pdf-document/demo.jsx +136 -0
- package/registry/blocks/pdf-document/index.js +33 -0
- package/registry/blocks/pdf-document/money.js +83 -0
- package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
- package/registry/blocks/pdf-document/primitives.jsx +271 -0
- package/registry/blocks/pdf-document/quote.jsx +179 -0
- package/registry/blocks/pdf-document/theme.js +193 -0
- package/registry/blocks/pdf-viewer/README.md +191 -0
- package/registry/blocks/pdf-viewer/block.json +14 -0
- package/registry/blocks/pdf-viewer/demo.jsx +252 -0
- package/registry/blocks/pdf-viewer/helpers.js +270 -0
- package/registry/blocks/pdf-viewer/index.js +8 -0
- package/registry/blocks/pdf-viewer/notes.jsx +195 -0
- package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
- package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
- package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
- package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
- package/registry/blocks/product-detail/README.md +217 -0
- package/registry/blocks/product-detail/block.json +10 -0
- package/registry/blocks/product-detail/demo.jsx +233 -0
- package/registry/blocks/product-detail/index.js +7 -0
- package/registry/blocks/product-detail/price.jsx +115 -0
- package/registry/blocks/product-detail/product-detail.jsx +348 -0
- package/registry/blocks/product-detail/product-media.jsx +102 -0
- package/registry/blocks/product-detail/product-options.jsx +144 -0
- package/registry/blocks/product-grid/README.md +162 -0
- package/registry/blocks/product-grid/block.json +10 -0
- package/registry/blocks/product-grid/demo.jsx +255 -0
- package/registry/blocks/product-grid/index.js +5 -0
- package/registry/blocks/product-grid/product-card.jsx +232 -0
- package/registry/blocks/product-grid/product-grid.jsx +235 -0
- package/registry/blocks/record-form/README.md +196 -0
- package/registry/blocks/record-form/block.json +10 -0
- package/registry/blocks/record-form/demo.jsx +525 -0
- package/registry/blocks/record-form/index.js +4 -0
- package/registry/blocks/record-form/record-fields.jsx +457 -0
- package/registry/blocks/record-form/record-form.jsx +415 -0
- package/registry/blocks/record-form/rules.js +81 -0
- package/registry/blocks/record-notes/README.md +139 -0
- package/registry/blocks/record-notes/block.json +10 -0
- package/registry/blocks/record-notes/demo.jsx +179 -0
- package/registry/blocks/record-notes/index.js +4 -0
- package/registry/blocks/record-notes/record-notes.jsx +266 -0
- package/registry/blocks/search-dialog/README.md +108 -0
- package/registry/blocks/search-dialog/block.json +10 -0
- package/registry/blocks/search-dialog/demo.jsx +116 -0
- package/registry/blocks/search-dialog/index.js +3 -0
- package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
- package/registry/blocks/settings-list/README.md +171 -0
- package/registry/blocks/settings-list/block.json +10 -0
- package/registry/blocks/settings-list/demo.jsx +333 -0
- package/registry/blocks/settings-list/index.js +4 -0
- package/registry/blocks/settings-list/row-state.jsx +93 -0
- package/registry/blocks/settings-list/settings-list.jsx +349 -0
- package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
- package/registry/blocks/setup-checklist/README.md +142 -0
- package/registry/blocks/setup-checklist/block.json +10 -0
- package/registry/blocks/setup-checklist/demo.jsx +159 -0
- package/registry/blocks/setup-checklist/index.js +4 -0
- package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
- package/registry/blocks/share-dialog/README.md +113 -0
- package/registry/blocks/share-dialog/block.json +10 -0
- package/registry/blocks/share-dialog/demo.jsx +140 -0
- package/registry/blocks/share-dialog/index.js +3 -0
- package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
- package/registry/blocks/sidebar/README.md +190 -0
- package/registry/blocks/sidebar/block.json +43 -0
- package/registry/blocks/sidebar/demo.jsx +577 -0
- package/registry/blocks/sidebar/index.js +4 -0
- package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
- package/registry/blocks/sidebar/sidebar.jsx +864 -0
- package/registry/blocks/signature-pad/README.md +137 -0
- package/registry/blocks/signature-pad/block.json +13 -0
- package/registry/blocks/signature-pad/colors.js +115 -0
- package/registry/blocks/signature-pad/demo.jsx +94 -0
- package/registry/blocks/signature-pad/index.js +6 -0
- package/registry/blocks/signature-pad/pad.js +7 -0
- package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
- package/registry/blocks/signature-pad/signature.js +68 -0
- package/registry/blocks/sketch-canvas/README.md +280 -0
- package/registry/blocks/sketch-canvas/block.json +13 -0
- package/registry/blocks/sketch-canvas/demo.jsx +159 -0
- package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
- package/registry/blocks/sketch-canvas/index.js +9 -0
- package/registry/blocks/sketch-canvas/palette.js +226 -0
- package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
- package/registry/blocks/sketch-canvas/sketch.js +179 -0
- package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
- package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
- package/registry/blocks/sketch-canvas/stamps.js +104 -0
- package/registry/blocks/sketch-canvas/theme.js +131 -0
- package/registry/blocks/spreadsheet/README.md +307 -0
- package/registry/blocks/spreadsheet/block.json +13 -0
- package/registry/blocks/spreadsheet/cells.jsx +455 -0
- package/registry/blocks/spreadsheet/chrome.jsx +325 -0
- package/registry/blocks/spreadsheet/demo.jsx +177 -0
- package/registry/blocks/spreadsheet/grid.js +387 -0
- package/registry/blocks/spreadsheet/index.js +34 -0
- package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
- package/registry/blocks/spreadsheet/types.js +473 -0
- package/registry/blocks/stat-cards/README.md +173 -0
- package/registry/blocks/stat-cards/block.json +10 -0
- package/registry/blocks/stat-cards/demo.jsx +257 -0
- package/registry/blocks/stat-cards/index.js +4 -0
- package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
- package/registry/blocks/stat-cards/usage.jsx +243 -0
- package/registry/blocks/task-list/README.md +176 -0
- package/registry/blocks/task-list/block.json +10 -0
- package/registry/blocks/task-list/demo.jsx +134 -0
- package/registry/blocks/task-list/index.js +5 -0
- package/registry/blocks/task-list/task-list.jsx +907 -0
- package/registry/blocks/task-model/README.md +455 -0
- package/registry/blocks/task-model/block.json +167 -0
- package/registry/blocks/task-model/changes.js +89 -0
- package/registry/blocks/task-model/dates.js +371 -0
- package/registry/blocks/task-model/demo.jsx +215 -0
- package/registry/blocks/task-model/dnd.jsx +240 -0
- package/registry/blocks/task-model/index.js +97 -0
- package/registry/blocks/task-model/model.js +919 -0
- package/registry/blocks/task-model/parts.jsx +449 -0
- package/registry/blocks/task-model/toolbar.jsx +271 -0
- package/registry/blocks/testimonials/README.md +139 -0
- package/registry/blocks/testimonials/block.json +11 -0
- package/registry/blocks/testimonials/demo.jsx +137 -0
- package/registry/blocks/testimonials/index.js +4 -0
- package/registry/blocks/testimonials/testimonials.jsx +430 -0
- package/registry/blocks/transaction-list/README.md +126 -0
- package/registry/blocks/transaction-list/block.json +10 -0
- package/registry/blocks/transaction-list/demo.jsx +79 -0
- package/registry/blocks/transaction-list/index.js +4 -0
- package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
- package/registry/blocks/whiteboard/README.md +179 -0
- package/registry/blocks/whiteboard/block.json +10 -0
- package/registry/blocks/whiteboard/demo.jsx +169 -0
- package/registry/blocks/whiteboard/index.js +6 -0
- package/registry/blocks/whiteboard/templates.js +150 -0
- package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
- package/src/cli.mjs +19 -6
- package/src/install.mjs +18 -0
- package/src/registry.mjs +38 -4
- package/src/shadcn.mjs +14 -1
- package/templates/next/files/README.md +145 -11
- package/templates/next/files/app/globals.css +55 -4
- package/templates/next/files/check/run.mjs +3 -3
- package/templates/next/files/components/ui/avatar.jsx +141 -0
- package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
- package/templates/next/files/components/ui/button-group.jsx +70 -0
- package/templates/next/files/components/ui/button.jsx +132 -12
- package/templates/next/files/components/ui/calendar.jsx +609 -0
- package/templates/next/files/components/ui/carousel.jsx +281 -0
- package/templates/next/files/components/ui/collapsible.jsx +208 -0
- package/templates/next/files/components/ui/combobox.jsx +608 -0
- package/templates/next/files/components/ui/command.jsx +577 -0
- package/templates/next/files/components/ui/context-menu.jsx +191 -0
- package/templates/next/files/components/ui/date-picker.jsx +360 -0
- package/templates/next/files/components/ui/distribution.jsx +117 -0
- package/templates/next/files/components/ui/feedback.jsx +143 -0
- package/templates/next/files/components/ui/field.jsx +115 -3
- package/templates/next/files/components/ui/file-input.jsx +234 -0
- package/templates/next/files/components/ui/icon.jsx +130 -8
- package/templates/next/files/components/ui/image.jsx +143 -0
- package/templates/next/files/components/ui/index.js +47 -2
- package/templates/next/files/components/ui/input-group.jsx +213 -0
- package/templates/next/files/components/ui/input-otp.jsx +170 -0
- package/templates/next/files/components/ui/item.jsx +206 -0
- package/templates/next/files/components/ui/menu.jsx +454 -82
- package/templates/next/files/components/ui/notice.jsx +126 -14
- package/templates/next/files/components/ui/pagination.jsx +156 -0
- package/templates/next/files/components/ui/popover.jsx +284 -0
- package/templates/next/files/components/ui/radio.jsx +193 -0
- package/templates/next/files/components/ui/rating.jsx +131 -0
- package/templates/next/files/components/ui/resizable.jsx +338 -0
- package/templates/next/files/components/ui/scroll-area.jsx +123 -0
- package/templates/next/files/components/ui/separator.jsx +119 -0
- package/templates/next/files/components/ui/sheet.jsx +96 -11
- package/templates/next/files/components/ui/slider.jsx +174 -0
- package/templates/next/files/components/ui/stat.jsx +574 -0
- package/templates/next/files/components/ui/steps.jsx +338 -0
- package/templates/next/files/components/ui/swatch.jsx +33 -0
- package/templates/next/files/components/ui/table.jsx +130 -0
- package/templates/next/files/components/ui/toast.jsx +440 -0
- package/templates/next/files/components/ui/toggle.jsx +195 -0
- package/templates/next/files/components/ui/tooltip.jsx +270 -0
- package/templates/next/template.json +264 -8
package/r/org-chart.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://ui.shadcn.com/schema/registry-item.json",
|
|
3
|
+
"name": "org-chart",
|
|
4
|
+
"type": "registry:block",
|
|
5
|
+
"title": "OrgChart",
|
|
6
|
+
"description": "An org chart on flow-canvas: people laid out top down from a flat list (each names a manager), managers centred over their teams, a team with no managers in it as a compact column, every line drawn for you. Teams fold past the first levels behind a chip that says how many are hidden; search finds a person, unfolds the way to them, centres them and lights their chain of managers; a card opens a details sheet (reports to, direct reports, team size). Colour strips and a legend by department. Optional: drag a card onto another to change someone's manager (async { ok }, optimistic, with Undo). Keyboard throughout.",
|
|
7
|
+
"registryDependencies": [
|
|
8
|
+
"https://cdn.jsdelivr.net/npm/makersclaw@0.3.1/r/core.json",
|
|
9
|
+
"https://cdn.jsdelivr.net/npm/makersclaw@0.3.1/r/flow-canvas.json"
|
|
10
|
+
],
|
|
11
|
+
"dependencies": [],
|
|
12
|
+
"files": [
|
|
13
|
+
{
|
|
14
|
+
"path": "registry/blocks/org-chart/index.js",
|
|
15
|
+
"type": "registry:component",
|
|
16
|
+
"target": "@components/makersclaw/blocks/org-chart/index.js",
|
|
17
|
+
"content": "// The OrgChart block — `makersclaw add org-chart`. Fixed: compose it\n// through its props (README.md beside this file). Built on flow-canvas\n// (it draws, pans and zooms; this block builds the tree, lays it out and\n// owns the keys). The helpers in org.js are plain functions and run\n// anywhere, the server included.\nexport { OrgChart } from \"./org-chart\";\nexport { buildOrg, layoutOrg, chainOf, orgToText, groupHues } from \"./org\";\n"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"path": "registry/blocks/org-chart/org-chart.jsx",
|
|
21
|
+
"type": "registry:component",
|
|
22
|
+
"target": "@components/makersclaw/blocks/org-chart/org-chart.jsx",
|
|
23
|
+
"content": "\"use client\";\n\n// OrgChart — the people tree, top down, on FlowCanvas. Managers over their\n// reports, a team with no managers in it as a compact column, teams folded\n// past the first levels with a chip that says how big they are. Find a\n// person from the search and the chart unfolds down to them, centres them\n// and lights their chain of managers. A person's card opens their details\n// (reports to, direct reports); with `onChangeManager`, drag a card onto\n// another to move someone to a new manager.\n//\n// People come in flat (each names a manager); org.js builds the tree and\n// lays it out, and the canvas — read-only, its own tools unused — draws,\n// pans and zooms. Pointer and keys come through this component.\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { Avatar, Badge, Button, Combobox, Empty, Item, ItemGroup, Kbd, Legend, Sheet, Tooltip, cx, toast } from \"../../ui\";\nimport { FlowCanvas, useFlowCanvas } from \"../flow-canvas\";\nimport { OrgContext, NODE_TYPES } from \"./person\";\nimport { CARD, STACK_FROM, buildOrg, chainOf, groupHues, layoutOrg } from \"./org\";\n\nconst CONTROL = 'input,textarea,select,[contenteditable=\"true\"],[contenteditable=\"plaintext-only\"],[role=\"dialog\"],[role=\"menu\"],[popover],button,a[href]';\n\nfunction useCoarsePointer() {\n const [coarse, setCoarse] = useState(false);\n useEffect(() => {\n const mq = window.matchMedia(\"(pointer: coarse)\");\n const on = () => setCoarse(mq.matches);\n on();\n mq.addEventListener(\"change\", on);\n return () => mq.removeEventListener(\"change\", on);\n }, []);\n return coarse;\n}\n\nasync function settle(fn, ...args) {\n try {\n const res = await fn(...args);\n return res && res.ok === false ? { ok: false, error: res.error } : { ok: true };\n } catch (e) {\n return { ok: false, error: e?.message };\n }\n}\n\nconst nameOf = (p) => p?.name || \"Unnamed\";\n\nexport function OrgChart({\n people,\n managerKey = \"managerId\",\n groupBy = \"department\",\n defaultDepth = 3,\n onChangeManager,\n onOpenPerson,\n renderDetails,\n onSelectionChange,\n height = 640,\n label = \"Org chart\",\n className,\n}) {\n const canvas = useFlowCanvas();\n const boxRef = useRef(null);\n const coarse = useCoarsePointer();\n const cbs = useRef({});\n cbs.current = { onChangeManager, onOpenPerson, onSelectionChange };\n\n // ── moves not yet in `people` (optimistic) ────────────────────────────\n const [moves, setMoves] = useState(() => new Map());\n useEffect(() => {\n // What the page has taken in needs no override any more.\n setMoves((m) => {\n if (!m.size) return m;\n const next = new Map(m);\n for (const p of people ?? []) if (next.has(String(p.id)) && String(p[managerKey] ?? \"\") === String(next.get(String(p.id)) ?? \"\")) next.delete(String(p.id));\n return next.size === m.size ? m : next;\n });\n }, [people, managerKey]);\n const everyone = useMemo(\n () => (people ?? []).filter((p) => p && p.id != null).map((p) => (moves.has(String(p.id)) ? { ...p, [managerKey]: moves.get(String(p.id)) } : p)),\n [people, moves, managerKey],\n );\n\n const org = useMemo(() => buildOrg(everyone, { managerKey }), [everyone, managerKey]);\n const hues = useMemo(() => groupHues(everyone, groupBy), [everyone, groupBy]);\n const groupOf = useCallback((p) => (groupBy ? (typeof groupBy === \"function\" ? groupBy(p) : p?.[groupBy]) : null), [groupBy]);\n\n // ── folding ───────────────────────────────────────────────────────────\n const [folds, setFolds] = useState(() => new Map()); // id → folded?\n const isFolded = useCallback((n) => (folds.has(n.id) ? folds.get(n.id) : n.depth >= defaultDepth - 1), [folds, defaultDepth]);\n const layout = useMemo(() => layoutOrg(org.roots, { collapsed: (n) => n.children.length > 0 && isFolded(n) }), [org, isFolded]);\n const itemsById = useMemo(() => new Map(layout.items.map((it) => [it.id, it])), [layout]);\n\n const board = useMemo(\n () => ({\n nodes: layout.items.map((it) => {\n const p = it.node.person;\n const g = groupOf(p);\n return {\n id: it.id,\n type: \"person\",\n position: { x: Math.round(it.x), y: Math.round(it.y) },\n width: it.width,\n height: it.height,\n draggable: false,\n connectable: false,\n data: {\n name: p.name,\n title: p.title,\n avatar: p.avatar,\n group: g ?? undefined,\n hue: g != null ? hues.get(g) : undefined,\n direct: it.node.children.length,\n total: it.node.total,\n folded: it.folded,\n parentId: it.parentId,\n link: it.link.length ? it.link.map((pt) => ({ x: pt.x - it.x, y: pt.y - it.y })) : null,\n },\n };\n }),\n edges: [],\n }),\n [layout, hues, groupOf],\n );\n\n // ── selection ─────────────────────────────────────────────────────────\n const [selectedId, setSelectedId] = useState(null);\n const selectedRef = useRef(null);\n const select = useCallback((id) => {\n selectedRef.current = id;\n setSelectedId(id);\n }, []);\n useEffect(() => {\n if (selectedId && !org.byId.has(selectedId)) select(null);\n }, [org, selectedId, select]);\n const chain = useMemo(() => new Set(selectedId ? chainOf(org.byId, selectedId).map((n) => n.id) : []), [org, selectedId]);\n\n // The canvas pans with a plain drag (its hand tool).\n const hand = useCallback(() => {\n const api = canvas.current;\n if (api && api.getTool?.() !== \"hand\") api.setTool(\"hand\");\n }, [canvas]);\n useEffect(() => {\n let raf = 0;\n let tries = 0;\n const wait = () => {\n if (canvas.current) return hand();\n if (tries++ < 120) raf = requestAnimationFrame(wait);\n };\n wait();\n return () => cancelAnimationFrame(raf);\n }, [canvas, hand]);\n\n /** Centre a person when they are off screen (or always, with `force`),\n * at the zoom there is — but close enough to read. */\n const reveal = useCallback(\n (id, { force = false, tries = 4 } = {}) => {\n const host = boxRef.current;\n const el = host?.querySelector(`[data-person=\"${CSS.escape(id)}\"]`);\n if (!el) {\n if (tries > 0) setTimeout(() => reveal(id, { force, tries: tries - 1 }), 60);\n return;\n }\n const r = el.getBoundingClientRect();\n const c = host.getBoundingClientRect();\n const pad = 24;\n const inView = r.left >= c.left + pad && r.right <= c.right - pad && r.top >= c.top + pad && r.bottom <= c.bottom - pad - 40;\n if (inView && !force) return;\n const now = r.width / CARD.width;\n const zoom = force ? Math.max(now, Math.min(1, (c.width - 48) / CARD.width)) : now;\n canvas.current?.fitView({ nodes: [{ id }], minZoom: zoom, maxZoom: zoom, padding: 0.6 });\n },\n [canvas],\n );\n\n const [announce, setAnnounce] = useState(\"\");\n const say = (m) => setAnnounce((x) => (x === m ? `${m} ` : m));\n\n useEffect(() => {\n const n = selectedId ? org.byId.get(selectedId) : null;\n cbs.current.onSelectionChange?.(n?.person ?? null);\n if (!n) return;\n const p = n.person;\n const boss = n.parentId ? org.byId.get(n.parentId)?.person : null;\n say(`${nameOf(p)}${p.title ? `, ${p.title}` : \"\"}${boss ? `, reports to ${nameOf(boss)}` : \"\"}${n.children.length ? `, ${n.children.length} direct report${n.children.length === 1 ? \"\" : \"s\"}` : \"\"}`);\n const raf = requestAnimationFrame(() => {\n const host = boxRef.current;\n const el = host?.querySelector(`.react-flow__node[data-id=\"${CSS.escape(selectedId)}\"]`);\n if (el && host.contains(document.activeElement) && document.activeElement !== el) el.focus({ preventScroll: true });\n reveal(selectedId);\n });\n return () => cancelAnimationFrame(raf);\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [selectedId]);\n\n const setFold = useCallback(\n (id, folded) => {\n const n = org.byId.get(id);\n if (!n || !n.children.length) return;\n setFolds((f) => new Map(f).set(id, folded ?? !isFolded(n)));\n say(`${nameOf(n.person)}'s team ${folded ?? !isFolded(n) ? \"hidden\" : \"shown\"}`);\n },\n [org, isFolded],\n );\n const foldAll = (folded) => {\n const next = new Map();\n for (const n of org.byId.values()) if (n.children.length) next.set(n.id, folded && n.depth > 0);\n setFolds(next);\n setTimeout(() => canvas.current?.fitView(), 80);\n };\n\n /** Unfold the way down to someone, select them, centre them. */\n const focusPerson = useCallback(\n (id) => {\n const path = chainOf(org.byId, id);\n if (!path.length) return;\n setFolds((f) => {\n const next = new Map(f);\n for (const n of path.slice(0, -1)) next.set(n.id, false);\n return next;\n });\n select(id);\n setTimeout(() => reveal(id, { force: true }), 30);\n },\n [org, select, reveal],\n );\n\n // ── details ───────────────────────────────────────────────────────────\n const [detailsId, setDetailsId] = useState(null);\n const open = useCallback(\n (id) => {\n const n = org.byId.get(id);\n if (!n) return;\n select(id);\n if (cbs.current.onOpenPerson) return cbs.current.onOpenPerson(n.person);\n setDetailsId(id);\n },\n [org, select],\n );\n\n // ── moving someone to a new manager ──────────────────────────────────\n const canMove = Boolean(onChangeManager);\n const reassign = async (id, to, { quiet = false } = {}) => {\n const n = org.byId.get(id);\n if (!n) return;\n const from = n.person[managerKey] ?? null;\n setMoves((m) => new Map(m).set(id, to));\n if (to) setFolds((f) => new Map(f).set(to, false));\n const boss = to ? org.byId.get(to)?.person : null;\n const res = await settle(cbs.current.onChangeManager, n.person, to);\n if (!res.ok) {\n setMoves((m) => {\n const next = new Map(m);\n if (String(from ?? \"\") === String((people ?? []).find((p) => String(p.id) === id)?.[managerKey] ?? \"\")) next.delete(id);\n else next.set(id, from);\n return next;\n });\n toast.error(`Couldn't move ${nameOf(n.person)}`, { description: res.error || \"Nothing changed. Try again.\" });\n return;\n }\n if (!quiet) {\n toast(`${nameOf(n.person)} now reports to ${boss ? nameOf(boss) : \"no one\"}`, {\n action: { label: \"Undo\", onClick: () => reassign(id, from, { quiet: true }) },\n });\n }\n };\n\n const [drag, setDrag] = useState(null); // { id, name, x, y }\n const [dropId, setDropId] = useState(null);\n const onCardPointerDown = (e, id) => {\n const wasSelected = selectedRef.current === id;\n select(id);\n const start = { x: e.clientX, y: e.clientY };\n let active = false;\n let over = null;\n const n = org.byId.get(id);\n const allowDrag = canMove && e.pointerType === \"mouse\";\n const move = (ev) => {\n if (!allowDrag) return;\n if (!active && Math.hypot(ev.clientX - start.x, ev.clientY - start.y) < 5) return;\n active = true;\n const host = boxRef.current?.getBoundingClientRect();\n if (!host) return;\n const hit = document\n .elementsFromPoint(ev.clientX, ev.clientY)\n .map((el) => el.closest?.(\"[data-person]\"))\n .find((el) => el && el.dataset.person !== id);\n const tid = hit?.dataset.person ?? null;\n const inside = tid && chainOf(org.byId, tid).some((x) => x.id === id);\n over = tid && !inside && n?.parentId !== tid ? tid : null;\n setDropId(over);\n setDrag({ id, name: nameOf(n?.person), x: ev.clientX - host.left, y: ev.clientY - host.top });\n };\n const up = () => {\n window.removeEventListener(\"pointermove\", move);\n window.removeEventListener(\"pointerup\", up);\n window.removeEventListener(\"pointercancel\", up);\n if (!active) {\n // A second click on the selected card opens it (a tap, on a phone).\n if (wasSelected) open(id);\n return;\n }\n setDrag(null);\n setDropId(null);\n if (over) reassign(id, over);\n };\n window.addEventListener(\"pointermove\", move);\n window.addEventListener(\"pointerup\", up);\n window.addEventListener(\"pointercancel\", up);\n };\n\n // A click on the empty canvas (not a pan) clears the selection.\n const paneDown = useRef(null);\n const onPointerDownCapture = (e) => {\n paneDown.current = e.target?.classList?.contains(\"react-flow__pane\") ? { x: e.clientX, y: e.clientY } : null;\n };\n const onPointerUpCapture = (e) => {\n const p = paneDown.current;\n paneDown.current = null;\n if (p && Math.hypot(e.clientX - p.x, e.clientY - p.y) <= 4) select(null);\n };\n\n // ── keys ──────────────────────────────────────────────────────────────\n const [searchOpen, setSearchOpen] = useState(false);\n const onKeyDownCapture = (e) => {\n const t = e.target;\n if (t?.closest?.(CONTROL)) return;\n const k = e.key;\n const mod = e.metaKey || e.ctrlKey;\n const done = () => {\n e.preventDefault();\n e.stopPropagation();\n };\n if (mod || e.altKey) return;\n if (k === \"/\") return done(), setSearchOpen(true);\n const sel = selectedRef.current && org.byId.has(selectedRef.current) ? selectedRef.current : null;\n if (k === \"Escape\") {\n if (sel) return done(), select(null);\n setTimeout(hand, 0);\n return;\n }\n const first = org.roots[0]?.id;\n if (!sel) {\n if ((k.startsWith(\"Arrow\") || k === \"Enter\" || k === \"Home\") && first) return done(), select(first);\n return;\n }\n const n = org.byId.get(sel);\n const parent = n.parentId ? org.byId.get(n.parentId) : null;\n const siblings = parent ? parent.children : org.roots;\n const i = siblings.findIndex((x) => x.id === sel);\n const stacked = parent && itemsById.get(siblings[0]?.id)?.link?.length === 3;\n if (k === \"Home\" && first) return done(), select(first);\n if (k === \"Enter\") return done(), open(sel);\n if (k === \" \") return done(), setFold(sel);\n if (k === \"ArrowUp\") {\n done();\n if (stacked && i > 0) return select(siblings[i - 1].id);\n return parent && select(parent.id);\n }\n if (k === \"ArrowDown\") {\n done();\n if (n.children.length) {\n if (isFolded(n)) setFold(sel, false);\n const kids = n.children;\n // Into a column: its top. Into a row: its middle, under the manager.\n const column = kids.length >= STACK_FROM && kids.every((c) => !c.children.length);\n return select(kids[column ? 0 : Math.floor((kids.length - 1) / 2)].id);\n }\n if (stacked && i < siblings.length - 1) return select(siblings[i + 1].id);\n return;\n }\n if (k === \"ArrowLeft\" || k === \"ArrowRight\") {\n done();\n const j = i + (k === \"ArrowLeft\" ? -1 : 1);\n if (siblings[j]) return select(siblings[j].id);\n // Past the end of the team: the nearest card across, in the same row.\n const me = itemsById.get(sel);\n if (!me) return;\n const across = layout.items\n .filter((it) => Math.abs(it.y - me.y) < 4 && (k === \"ArrowLeft\" ? it.x < me.x : it.x > me.x))\n .sort((a, b) => Math.abs(a.x - me.x) - Math.abs(b.x - me.x))[0];\n if (across) select(across.id);\n }\n };\n\n // ── the context the cards read ────────────────────────────────────────\n const ctx = useMemo(\n () => ({\n selectedId,\n chain,\n dropId,\n dragId: drag?.id ?? null,\n coarse,\n draggable: canMove && !coarse,\n onCardPointerDown,\n open,\n toggle: (id) => setFold(id),\n }),\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [selectedId, chain, dropId, drag, coarse, canMove, open, setFold, org],\n );\n\n // ── chrome ────────────────────────────────────────────────────────────\n const options = useMemo(\n () =>\n everyone.map((p) => ({\n value: String(p.id),\n label: nameOf(p),\n description: [p.title, groupOf(p)].filter(Boolean).join(\" · \") || undefined,\n icon: <Avatar name={p.name} src={p.avatar} size=\"xs\" />,\n keywords: [p.title, groupOf(p), p.email, p.location].filter(Boolean),\n })),\n [everyone, groupOf],\n );\n const legend = useMemo(() => {\n if (!groupBy || !hues.size) return [];\n const count = new Map();\n for (const p of everyone) {\n const g = groupOf(p);\n if (g != null && g !== \"\") count.set(g, (count.get(g) ?? 0) + 1);\n }\n return [...hues.entries()].map(([g, hue]) => ({ key: String(g), hue, label: String(g), count: count.get(g) }));\n }, [everyone, hues, groupBy, groupOf]);\n const managers = useMemo(() => [...org.byId.values()].filter((n) => n.children.length).length, [org]);\n const sized = /(^|\\s)(h-|min-h-|size-|flex-1|grow)/.test(className ?? \"\");\n const details = detailsId ? org.byId.get(detailsId) : null;\n\n if (!everyone.length) {\n return (\n <section aria-label={label} className={cx(\"grid place-items-center rounded-lg border border-border bg-background p-6\", className)} style={sized ? undefined : { minHeight: Math.min(Number(height) || 320, 320) }}>\n <Empty icon=\"users\" title=\"No one on the chart yet\" body=\"People appear here once they're added, each with the person they report to.\" />\n </section>\n );\n }\n\n return (\n <section aria-label={label} className={cx(\"flex flex-col overflow-hidden rounded-lg border border-border bg-background text-foreground\", className)} style={sized ? undefined : { height }}>\n <header className=\"grid shrink-0 gap-2 border-b border-border bg-card px-3 py-2 text-card-foreground\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <Combobox\n label=\"Find a person\"\n options={options}\n value={null}\n onValueChange={(v) => v && focusPerson(String(v))}\n open={searchOpen}\n onOpenChange={setSearchOpen}\n placeholder=\"Find a person…\"\n searchPlaceholder=\"Name, title or team\"\n empty=\"No one by that name.\"\n className=\"w-full sm:w-72\"\n />\n <p className=\"text-sm text-muted-foreground tabular-nums\">\n {everyone.length} {everyone.length === 1 ? \"person\" : \"people\"}\n <span className=\"max-sm:hidden\">\n {\" \"}\n · {managers} {managers === 1 ? \"manager\" : \"managers\"}\n </span>\n </p>\n <div className=\"flex-1\" />\n <div className=\"flex items-center gap-1\">\n <Tooltip label=\"Show every team\">\n <Button size=\"sm\" variant=\"quiet\" icon=\"chevron-down\" onClick={() => foldAll(false)}>\n Expand all\n </Button>\n </Tooltip>\n <Tooltip label=\"Fold every team under the top\">\n <Button size=\"sm\" variant=\"quiet\" icon=\"chevron-up\" onClick={() => foldAll(true)}>\n Collapse\n </Button>\n </Tooltip>\n </div>\n </div>\n {legend.length > 1 ? <Legend size=\"sm\" items={legend} label={typeof groupBy === \"string\" ? `People by ${groupBy}` : \"People by group\"} /> : null}\n </header>\n\n <div ref={boxRef} className=\"relative min-h-0 flex-1\" onKeyDownCapture={onKeyDownCapture} onPointerDownCapture={onPointerDownCapture} onPointerUpCapture={onPointerUpCapture}>\n <p className=\"sr-only\" aria-live=\"polite\">\n {announce}\n </p>\n <OrgContext.Provider value={ctx}>\n <FlowCanvas\n value={board}\n readOnly\n nodeTypes={NODE_TYPES}\n canvasRef={canvas}\n label={label}\n height=\"100%\"\n bare\n emptyState={false}\n templates={[]}\n describeNode={describePerson}\n className=\"[&_.react-flow__node]:transition-transform [&_.react-flow__node]:duration-200 [&_.react-flow__node]:ease-out motion-reduce:[&_.react-flow__node]:transition-none\"\n />\n </OrgContext.Provider>\n\n {drag ? (\n <div aria-hidden=\"true\" className=\"pointer-events-none absolute z-20 grid -translate-x-1/2 -translate-y-[calc(100%+10px)] justify-items-center gap-1\" style={{ left: drag.x, top: drag.y }}>\n <span className=\"max-w-60 truncate rounded-lg border border-border bg-popover px-3 py-1.5 text-sm font-medium text-popover-foreground shadow-lg\">{drag.name}</span>\n <span className=\"rounded-md bg-foreground px-2 py-0.5 text-xs text-background\">{dropId ? `Reports to ${nameOf(org.byId.get(dropId)?.person)}` : \"Drop on their new manager\"}</span>\n </div>\n ) : null}\n\n <div aria-hidden=\"true\" className=\"pointer-events-none absolute bottom-3 left-3 z-10 hidden items-center gap-3 rounded-lg border border-border bg-card/90 px-2.5 py-1.5 text-xs text-muted-foreground shadow-xs backdrop-blur-sm md:flex\">\n <span className=\"flex items-center gap-1.5\">\n <Kbd>/</Kbd>find\n </span>\n <span className=\"flex items-center gap-1.5\">\n <Kbd>←↑→↓</Kbd>move\n </span>\n <span className=\"flex items-center gap-1.5\">\n <Kbd>Space</Kbd>team\n </span>\n <span className=\"flex items-center gap-1.5\">\n <Kbd>Enter</Kbd>details\n </span>\n </div>\n </div>\n\n <Sheet\n open={Boolean(details)}\n onClose={() => setDetailsId(null)}\n title={details ? nameOf(details.person) : \"\"}\n description={details?.person.title}\n footer={\n details ? (\n <Button\n size=\"sm\"\n icon=\"target\"\n onClick={() => {\n const id = details.id;\n setDetailsId(null);\n focusPerson(id);\n }}\n >\n Show on the chart\n </Button>\n ) : null\n }\n >\n {details ? (\n <PersonDetails\n node={details}\n byId={org.byId}\n group={groupOf(details.person)}\n hue={hues.get(groupOf(details.person))}\n extra={renderDetails?.(details.person)}\n onPick={(id) => {\n setDetailsId(id);\n focusPerson(id);\n }}\n />\n ) : null}\n </Sheet>\n </section>\n );\n}\n\nfunction describePerson(n) {\n if (n.type !== \"person\") return undefined;\n const d = n.data ?? {};\n return `${d.name || \"Unnamed\"}${d.title ? `, ${d.title}` : \"\"}${d.direct ? ` — ${d.direct} direct report${d.direct === 1 ? \"\" : \"s\"}` : \"\"}`;\n}\n\nfunction PersonDetails({ node, byId, group, hue, extra, onPick }) {\n const p = node.person;\n const boss = node.parentId ? byId.get(node.parentId) : null;\n const facts = [p.location].filter(Boolean);\n return (\n <div className=\"grid gap-6\">\n <div className=\"flex items-center gap-4\">\n <Avatar name={p.name} src={p.avatar} size=\"lg\" />\n <div className=\"grid min-w-0 gap-1\">\n <p className=\"truncate text-base font-semibold\">{nameOf(p)}</p>\n {p.title ? <p className=\"truncate text-sm text-muted-foreground\">{p.title}</p> : null}\n <div className=\"flex flex-wrap items-center gap-2 pt-1\">\n {group != null && group !== \"\" ? (\n <Badge variant=\"soft\" hue={hue}>\n {String(group)}\n </Badge>\n ) : null}\n {facts.map((f) => (\n <span key={f} className=\"text-xs text-muted-foreground\">\n {f}\n </span>\n ))}\n </div>\n </div>\n </div>\n\n {p.email ? (\n <a href={`mailto:${p.email}`} className=\"-mt-2 w-fit truncate text-sm text-primary underline-offset-4 hover:underline\">\n {p.email}\n </a>\n ) : null}\n\n <section className=\"grid gap-2\">\n <h3 className=\"text-sm font-medium\">Reports to</h3>\n {boss ? (\n <Item size=\"sm\" variant=\"outline\" media={<Avatar name={boss.person.name} src={boss.person.avatar} size=\"sm\" />} title={nameOf(boss.person)} description={boss.person.title} onClick={() => onPick(boss.id)} />\n ) : (\n <p className=\"text-sm text-muted-foreground\">No one — the top of the chart.</p>\n )}\n </section>\n\n <section className=\"grid gap-2\">\n <h3 className=\"flex items-baseline gap-2 text-sm font-medium\">\n Direct reports\n <span className=\"text-xs font-normal text-muted-foreground tabular-nums\">\n {node.children.length}\n {node.total > node.children.length ? ` · ${node.total} in the team` : \"\"}\n </span>\n </h3>\n {node.children.length ? (\n <ItemGroup>\n {node.children.map((c) => (\n <Item\n key={c.id}\n size=\"sm\"\n media={<Avatar name={c.person.name} src={c.person.avatar} size=\"sm\" />}\n title={nameOf(c.person)}\n description={c.person.title}\n meta={c.total ? <span className=\"tabular-nums\">{c.total}</span> : null}\n onClick={() => onPick(c.id)}\n />\n ))}\n </ItemGroup>\n ) : (\n <p className=\"text-sm text-muted-foreground\">No one reports to {nameOf(p).split(\" \")[0]}.</p>\n )}\n </section>\n\n {extra ? <section className=\"grid gap-2\">{extra}</section> : null}\n </div>\n );\n}\n"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"path": "registry/blocks/org-chart/person.jsx",
|
|
27
|
+
"type": "registry:component",
|
|
28
|
+
"target": "@components/makersclaw/blocks/org-chart/person.jsx",
|
|
29
|
+
"content": "\"use client\";\n\n// One person on the chart, as a FlowCanvas node type: a card (face, name,\n// title, a strip in their group's colour), the line up to their manager\n// (an SVG reaching outside the card, so the canvas needs no connectors),\n// and — for a manager — the chip at the card's foot that folds the team\n// and says how big it is.\n//\n// What the chart knows (the selection, the chain being lit, a drag in\n// progress, what a click does) comes from OrgContext, which OrgChart\n// provides around the canvas.\nimport { createContext, useContext } from \"react\";\nimport { Avatar, Icon, cx } from \"../../ui\";\nimport { elbowPath } from \"./org\";\n\nexport const OrgContext = createContext(null);\n\n// Group hue → the strip's class, written out whole so Tailwind makes them.\nconst STRIP = { 1: \"bg-chart-1\", 2: \"bg-chart-2\", 3: \"bg-chart-3\", 4: \"bg-chart-4\", 5: \"bg-chart-5\" };\n\nexport function PersonNode({ id, data }) {\n const o = useContext(OrgContext);\n if (!o) return null;\n const { name, title, avatar, hue, direct = 0, total = 0, folded = false, link, parentId } = data ?? {};\n const selected = o.selectedId === id;\n const lit = o.chain.has(id) && parentId && o.chain.has(parentId);\n const isDrop = o.dropId === id;\n const dragged = o.dragId === id;\n\n return (\n <div data-person={id} className=\"group/person relative size-full\">\n {link ? (\n <svg aria-hidden=\"true\" width=\"1\" height=\"1\" className=\"pointer-events-none absolute top-0 left-0 overflow-visible\">\n <path d={elbowPath(link)} className={cx(\"fill-none transition-[stroke] duration-150 motion-reduce:transition-none\", lit ? \"stroke-primary\" : \"stroke-border\")} strokeWidth={lit ? 2 : 1.5} strokeLinecap=\"round\" strokeLinejoin=\"round\" />\n </svg>\n ) : null}\n {/* raw: the person's card on the canvas — it takes the pointer\n (a click selects, a click on the selected card opens it, a drag\n moves them to a new manager); the keys arrive through OrgChart's\n handler on the canvas. */}\n <div\n className={cx(\n \"relative flex size-full items-center gap-3 overflow-hidden rounded-xl border border-border bg-card py-2 pr-3 pl-4 text-card-foreground shadow-xs\",\n \"transition-[box-shadow,opacity,outline-color] duration-150 hover:shadow-md motion-reduce:transition-none\",\n o.coarse ? \"\" : \"nopan\",\n o.draggable ? \"cursor-grab\" : \"cursor-pointer\",\n selected && \"ring-2 ring-primary ring-offset-2 ring-offset-background\",\n isDrop && \"outline-2 outline-offset-4 outline-primary [outline-style:dashed]\",\n dragged && \"opacity-40\",\n )}\n onPointerDown={(e) => {\n if (e.button === 0) o.onCardPointerDown(e, id);\n }}\n >\n {hue ? <span aria-hidden=\"true\" className={cx(\"absolute inset-y-0 left-0 w-1\", STRIP[hue])} /> : null}\n <Avatar name={name} src={avatar} size=\"md\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"truncate text-sm font-medium\" title={name}>\n {name || \"Unnamed\"}\n </p>\n <p className=\"truncate text-xs text-muted-foreground\" title={title}>\n {title || \" \"}\n </p>\n </div>\n </div>\n\n {direct > 0 ? (\n // raw: a 22px chip on the card's foot, smaller than any kit button\n // — the canvas is zoomed out on a big org, and a 36px button would\n // cover the line to the team. Out of the tab order: Space folds.\n <button\n type=\"button\"\n tabIndex={-1}\n aria-label={`${folded ? \"Show\" : \"Hide\"} ${name}'s team: ${direct} direct, ${total} in all`}\n title={`${direct} direct report${direct === 1 ? \"\" : \"s\"}${total > direct ? ` · ${total} in the team` : \"\"} — ${folded ? \"show\" : \"hide\"}`}\n onMouseDown={(e) => e.preventDefault()}\n onPointerDown={(e) => e.stopPropagation()}\n onClick={(e) => {\n e.stopPropagation();\n o.toggle(id);\n }}\n className={cx(\n \"nodrag nopan absolute top-full left-1/2 z-10 flex h-[22px] -translate-x-1/2 -translate-y-1/2 items-center gap-0.5 rounded-full border px-2 text-[11px] leading-none font-medium tabular-nums shadow-xs\",\n \"transition-colors duration-150 motion-reduce:transition-none\",\n folded ? \"border-primary/50 bg-card text-foreground hover:bg-accent\" : \"border-border bg-card text-muted-foreground hover:text-foreground\",\n )}\n >\n {folded ? `+${total}` : direct}\n <Icon name={folded ? \"chevron-down\" : \"chevron-up\"} size={12} />\n </button>\n ) : null}\n </div>\n );\n}\n\nexport const NODE_TYPES = { person: PersonNode };\n"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"path": "registry/blocks/org-chart/org.js",
|
|
33
|
+
"type": "registry:component",
|
|
34
|
+
"target": "@components/makersclaw/blocks/org-chart/org.js",
|
|
35
|
+
"content": "// The org chart's data and layout — plain functions, no React, no DOM.\n// They run anywhere (the server, an agent's tool, a test).\n//\n// People come in flat, the way a table holds them: each row names its\n// manager. buildOrg turns them into a tree; layoutOrg places the tree top\n// down, managers centred over their reports, and a manager whose reports\n// have no reports of their own gets them as a compact column (a wide row\n// of twelve cards reads worse than a list).\n\n/** Department (or any group) colours, in order: chart hues, which every\n * theme derives from its own primary. As hue numbers for Legend/Badge. */\nexport const GROUP_HUES = [2, 3, 4, 5, 1];\n\nexport const CARD = { width: 248, height: 72 };\nconst GAP_X = 20; // between side-by-side teams\nconst GAP_Y = 52; // between a manager and the row of reports\nconst STACK_INDENT = 32; // a column of reports sits this far in\nconst STACK_GAP = 10;\nconst ROOT_GAP = 64; // between separate trees\n/** A manager's reports stack as a column when there are at least this\n * many and none of them manages anyone. */\nexport const STACK_FROM = 3;\n\n/**\n * Flat people → a tree. Returns { roots, byId }; each node is\n * { id, person, parentId, depth, children, total } (total: everyone under\n * them). Someone whose manager is missing, or whose chain of managers\n * loops, becomes a root.\n *\n * managerKey the field naming the manager's id (default \"managerId\")\n */\nexport function buildOrg(people, { managerKey = \"managerId\" } = {}) {\n const list = Array.isArray(people) ? people.filter((p) => p && p.id != null) : [];\n const byId = new Map();\n for (const p of list) {\n const id = String(p.id);\n if (!byId.has(id)) byId.set(id, { id, person: p, parentId: null, depth: 0, children: [], total: 0 });\n }\n const managerOf = (id) => {\n const m = byId.get(id)?.person?.[managerKey];\n return m != null && byId.has(String(m)) && String(m) !== id ? String(m) : null;\n };\n // A chain that comes back to itself: whoever closes the loop is a root.\n const loops = new Set();\n for (const id of byId.keys()) {\n const seen = new Set([id]);\n let cur = managerOf(id);\n while (cur) {\n if (seen.has(cur)) {\n if (cur === id) loops.add(id);\n break;\n }\n seen.add(cur);\n cur = managerOf(cur);\n }\n }\n const roots = [];\n for (const n of byId.values()) {\n const m = loops.has(n.id) ? null : managerOf(n.id);\n if (m && !loops.has(n.id)) {\n n.parentId = m;\n byId.get(m).children.push(n);\n } else roots.push(n);\n }\n // Anyone still unreached sits in a loop not broken above: a root too.\n const reached = new Set();\n const walk = (n, depth) => {\n if (reached.has(n.id)) return 0;\n reached.add(n.id);\n n.depth = depth;\n n.total = n.children.reduce((s, c) => s + 1 + walk(c, depth + 1), 0);\n return n.total;\n };\n for (const r of roots) walk(r, 0);\n for (const n of byId.values()) {\n if (reached.has(n.id)) continue;\n if (n.parentId) byId.get(n.parentId).children = byId.get(n.parentId).children.filter((c) => c.id !== n.id);\n n.parentId = null;\n roots.push(n);\n walk(n, 0);\n }\n return { roots, byId };\n}\n\n/** [root, …, the person's node] — their chain of managers, top first. */\nexport function chainOf(byId, id) {\n const out = [];\n let n = byId.get(String(id));\n const seen = new Set();\n while (n && !seen.has(n.id)) {\n seen.add(n.id);\n out.unshift(n);\n n = n.parentId ? byId.get(n.parentId) : null;\n }\n return out;\n}\n\n/** The colour group of each value of `key` (\"department\"): the first\n * seen gets the first hue. Map(value → hue number 1..5). */\nexport function groupHues(people, key) {\n const out = new Map();\n if (!key) return out;\n for (const p of people ?? []) {\n const v = typeof key === \"function\" ? key(p) : p?.[key];\n if (v == null || v === \"\" || out.has(v)) continue;\n out.set(v, GROUP_HUES[out.size % GROUP_HUES.length]);\n }\n return out;\n}\n\n// Rounded right-angle lines through points (a corner radius r).\nexport function elbowPath(points, r = 8) {\n if (points.length < 2) return \"\";\n let d = `M${points[0].x},${points[0].y}`;\n for (let i = 1; i < points.length - 1; i++) {\n const a = points[i - 1];\n const b = points[i];\n const c = points[i + 1];\n const r1 = Math.min(r, Math.hypot(b.x - a.x, b.y - a.y) / 2, Math.hypot(c.x - b.x, c.y - b.y) / 2);\n const u = { x: Math.sign(b.x - a.x), y: Math.sign(b.y - a.y) };\n const v = { x: Math.sign(c.x - b.x), y: Math.sign(c.y - b.y) };\n d += ` L${b.x - u.x * r1},${b.y - u.y * r1} Q${b.x},${b.y} ${b.x + v.x * r1},${b.y + v.y * r1}`;\n }\n const z = points[points.length - 1];\n return `${d} L${z.x},${z.y}`;\n}\n\n/**\n * Where every visible card goes. Top down; a manager centred over the\n * cards of their reports; a folded manager's team hidden; separate trees\n * side by side.\n *\n * collapsed(node) → true when the node's team is folded\n * stack true (default): reports with no reports of their own\n * become a column once there are STACK_FROM of them\n *\n * Returns { items, bounds }. Each item: { id, node, x, y, width, height,\n * depth, parentId, folded, link } — `link` the line up to the manager, as\n * points in board px ([] for a root).\n */\nexport function layoutOrg(roots, { collapsed = () => false, stack = true, card = CARD } = {}) {\n const W = card.width;\n const H = card.height;\n const info = new Map();\n const shown = (n) => (collapsed(n) ? [] : n.children);\n const measure = (n) => {\n const kids = shown(n);\n let mode = \"none\";\n let width = W;\n if (kids.length) {\n for (const k of kids) measure(k);\n if (stack && kids.length >= STACK_FROM && kids.every((k) => !k.children.length)) {\n mode = \"stack\";\n width = STACK_INDENT + W;\n } else {\n mode = \"row\";\n const total = kids.reduce((s, k) => s + info.get(k.id).width, 0) + GAP_X * (kids.length - 1);\n width = Math.max(W, total);\n }\n }\n info.set(n.id, { mode, width });\n };\n\n const items = [];\n const place = (n, left, top, parent) => {\n const { mode, width } = info.get(n.id);\n const kids = shown(n);\n const me = { id: n.id, node: n, x: left, y: top, width: W, height: H, depth: n.depth, parentId: parent?.id ?? null, folded: kids.length === 0 && n.children.length > 0, link: [] };\n items.push(me);\n if (mode === \"none\") {\n me.x = left + (width - W) / 2;\n return me;\n }\n if (mode === \"stack\") {\n me.x = left;\n let y = top + H + GAP_Y / 2 + 6;\n const spine = me.x + STACK_INDENT / 2;\n for (const k of kids) {\n const c = place(k, left + STACK_INDENT, y, me);\n c.link = [\n { x: spine, y: top + H },\n { x: spine, y: y + H / 2 },\n { x: c.x, y: y + H / 2 },\n ];\n y += H + STACK_GAP;\n }\n return me;\n }\n const total = kids.reduce((s, k) => s + info.get(k.id).width, 0) + GAP_X * (kids.length - 1);\n let x = left + (width - total) / 2;\n const placed = [];\n for (const k of kids) {\n placed.push(place(k, x, top + H + GAP_Y, me));\n x += info.get(k.id).width + GAP_X;\n }\n const a = placed[0].x + W / 2;\n const b = placed[placed.length - 1].x + W / 2;\n me.x = (a + b) / 2 - W / 2;\n const mid = top + H + GAP_Y / 2;\n for (const c of placed) {\n c.link = [\n { x: me.x + W / 2, y: top + H },\n { x: me.x + W / 2, y: mid },\n { x: c.x + W / 2, y: mid },\n { x: c.x + W / 2, y: c.y },\n ];\n // Straight down: two points are enough.\n if (Math.abs(c.link[0].x - c.link[3].x) < 0.5) c.link = [c.link[0], c.link[3]];\n }\n return me;\n };\n\n for (const r of roots) measure(r);\n let x = 0;\n for (const r of roots) {\n place(r, x, 0, null);\n x += info.get(r.id).width + ROOT_GAP;\n }\n\n let x1 = Infinity;\n let y1 = Infinity;\n let x2 = -Infinity;\n let y2 = -Infinity;\n for (const it of items) {\n x1 = Math.min(x1, it.x);\n y1 = Math.min(y1, it.y);\n x2 = Math.max(x2, it.x + it.width);\n y2 = Math.max(y2, it.y + it.height);\n }\n return { items, bounds: items.length ? { x: x1, y: y1, width: x2 - x1, height: y2 - y1 } : { x: 0, y: 0, width: 0, height: 0 } };\n}\n\n/** The org as plain text, one person a line, indented under their\n * manager: \"Maya Chen — VP Engineering (12)\". For an agent or search. */\nexport function orgToText(people, opts) {\n const { roots } = buildOrg(people, opts);\n const out = [];\n const walk = (n, depth) => {\n const p = n.person;\n out.push(`${\" \".repeat(depth)}${depth ? \"- \" : \"\"}${p.name ?? n.id}${p.title ? ` — ${p.title}` : \"\"}${n.total ? ` (${n.total})` : \"\"}`);\n for (const c of n.children) walk(c, depth + 1);\n };\n for (const r of roots) walk(r, 0);\n return out.join(\"\\n\");\n}\n"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"path": "registry/blocks/org-chart/README.md",
|
|
39
|
+
"type": "registry:file",
|
|
40
|
+
"target": "@components/makersclaw/blocks/org-chart/README.md",
|
|
41
|
+
"content": "# OrgChart\n\nWho reports to whom, top down. Give it people as a flat list — each row\nnames its manager — and it draws the tree: managers centred over their\nteams, a team with no managers in it as a compact column (twelve cards in\na row read worse than a list), every line in place.\n\nTeams past the first levels start folded; the chip under a manager says\nhow many report to them and, folded, how many are hidden. **Find a\nperson** (or press `/`) unfolds the way down to them, centres them and\nlights their chain of managers. A click selects a card; a second click\n(or Enter) opens a details sheet: who they report to, their direct\nreports, the team's size. Cards carry a colour strip by department, with\na legend on top.\n\nWith `onChangeManager`, drag a card onto another to move that person to a\nnew manager — shown at once, saved through your callback, undone if it\nfails, with an Undo in the toast.\n\nIt is built on `flow-canvas` (which draws it, pans and zooms): this block\nbuilds the tree, lays it out and owns the keys.\n\n```jsx\nimport { OrgChart } from \"../components/blocks/org-chart\"; // a Makersclaw app (\"./blocks/org-chart\" from components/)\nimport { OrgChart } from \"@/components/makersclaw/blocks/org-chart\"; // a shadcn project\n```\n\n`OrgChart` is a client component: render it from a `\"use client\"`\ncomponent. `makersclaw add org-chart` adds `flow-canvas` with it (and its\nnpm package, `@xyflow/react`: run `npm install` after). The helpers\n(`buildOrg`, `orgToText`…) are plain functions and work on the server too.\n\n## The data\n\nOne row per person, as a table holds them:\n\n```js\n[\n { id: \"p1\", name: \"Amara Okafor\", title: \"Chief Executive Officer\", department: \"Leadership\" },\n { id: \"p2\", name: \"Daniel Reyes\", title: \"VP Engineering\", department: \"Engineering\", managerId: \"p1\", avatar: \"https://…\", email: \"daniel@…\", location: \"Lisbon\" },\n]\n```\n\n- `id` — required, unique. `name`, `title` — the card's two lines.\n- `managerId` (or the field named by `managerKey`) — the manager's `id`.\n Missing, or naming someone not in the list: the person is the top of a\n tree (several tops sit side by side). A loop of managers is broken, and\n never hangs the chart.\n- `avatar` — an image URL; without one the card shows initials.\n- `department` (or the field named by `groupBy`) — the card's colour strip\n and the legend. Colours are the theme's chart hues, given in the order\n groups first appear.\n- `email`, `location` — shown in the details sheet. Any other field is\n kept and handed back to your callbacks.\n\n## Props\n\n- `people` — required, the rows above. An empty list shows a friendly\n empty state.\n- `managerKey` — the field naming the manager (default `\"managerId\"`).\n- `groupBy` — the field to colour by (default `\"department\"`), or\n `(person) => group`; `null` for no colours or legend.\n- `defaultDepth` — how many levels show before teams fold (default `3`:\n the top, their reports, and theirs).\n- `onChangeManager(person, managerId)` — `async`, return `{ ok: true }` or\n `{ ok: false, error? }` (a throw counts as failed). Turns on dragging a\n card onto another (with a mouse; on touch a drag always pans). The move\n shows at once; a failure puts the person back and says why. Update\n `people` when it succeeds (the chart keeps the move until you do).\n- `onOpenPerson(person)` — open your own view of a person (a record page,\n your own Sheet) instead of the built-in details sheet.\n- `renderDetails(person)` — more for the built-in details sheet, under the\n reports: kit parts (their open deals, a \"Message\" button).\n- `onSelectionChange(person | null)` — the selected card changed.\n- `height` — px or any CSS length, default `640`. A height class in\n `className` (`h-dvh`, `h-full`, `flex-1`) replaces it.\n- `label` — the chart's accessible name (default \"Org chart\").\n- `className` — layout around it (margin, width, height). Never colour.\n\n## Keyboard and pointer\n\n- `/` finds a person. Arrows walk the chart: ↑ to the manager, ↓ into the\n team (unfolding it), ← → along the team (and across to the next team\n at the end of a row); in a column ↑ ↓ go up and down it.\n- Space folds or unfolds the selected person's team; Enter opens their\n details; Home goes to the top; Esc clears the selection; ⇧1 fits the\n chart to the screen.\n- A plain drag on the canvas pans, pinch or ⌘-scroll zooms, the chip under\n a manager folds their team. The zoom bar (bottom right) has fit, zoom\n and a list view for screen readers.\n\n## The helpers\n\n- `buildOrg(people, { managerKey })` → `{ roots, byId }`: each node\n `{ id, person, parentId, depth, children, total }` (`total`: everyone\n under them).\n- `chainOf(byId, id)` → the chain of managers, top first, ending with them.\n- `orgToText(people, { managerKey })` — one person a line, indented under\n their manager, \"Daniel Reyes — VP Engineering (10)\": for an agent or a\n search column.\n- `layoutOrg(roots, { collapsed(node), stack = true })` → `{ items,\n bounds }`: every visible card's box and the line up to its manager.\n- `groupHues(people, key)` → Map(group → hue 1..5), the colours the chart\n uses (for a Legend or Badge elsewhere).\n\n## Example\n\n```jsx\n// components/TeamChart.jsx — client\n\"use client\";\nimport { useState } from \"react\";\nimport { updateRow } from \"../lib/actions\";\nimport { OrgChart } from \"./blocks/org-chart\";\n\nexport default function TeamChart({ employees }) {\n const [people, setPeople] = useState(employees); // rows of public.employees\n return (\n <OrgChart\n people={people}\n managerKey=\"manager_id\"\n onChangeManager={async (person, managerId) => {\n const res = await updateRow({ source: \"public.employees\", id: person.id, patch: { manager_id: managerId } });\n if (res.ok) setPeople((list) => list.map((p) => (p.id === person.id ? { ...p, manager_id: managerId } : p)));\n return res;\n }}\n className=\"h-[calc(100dvh-8rem)]\"\n />\n );\n}\n```\n\n## What it will not do\n\n- Show a person under two managers (dotted lines, matrix orgs): one\n manager each.\n- Edit a person's details: open your own form from `onOpenPerson` or put\n a button in `renderDetails`.\n- Export an image or print.\n- Render on the server: the server shows the people as text until the\n canvas mounts. For a read-only page that must be rich in the HTML,\n render `orgToText` yourself.\n\nA chart it cannot be is your own component in `components/` — not an edit\nto this block. Its files are fixed: `npm run check` refuses a change, and\n`makersclaw add org-chart` restores them.\n"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
"categories": [
|
|
45
|
+
"org chart",
|
|
46
|
+
"organization",
|
|
47
|
+
"organisation",
|
|
48
|
+
"hierarchy",
|
|
49
|
+
"reporting line",
|
|
50
|
+
"manager",
|
|
51
|
+
"team",
|
|
52
|
+
"people",
|
|
53
|
+
"directory",
|
|
54
|
+
"tree",
|
|
55
|
+
"reports",
|
|
56
|
+
"reorg",
|
|
57
|
+
"canvas"
|
|
58
|
+
],
|
|
59
|
+
"docs": "Installed to components/makersclaw/blocks/org-chart. Import: import { OrgChart, buildOrg, layoutOrg, chainOf, orgToText, groupHues } from \"@/components/makersclaw/blocks/org-chart\". Props and an example: components/makersclaw/blocks/org-chart/README.md. Makersclaw builds whole apps from these blocks: https://makersclaw.com",
|
|
60
|
+
"meta": {
|
|
61
|
+
"makersclaw": {
|
|
62
|
+
"version": "0.3.1",
|
|
63
|
+
"useWhen": "A screen that shows who reports to whom: a team or company directory's chart, an account's buying committee as a hierarchy, a reporting line to check before a reorg. Not for a free-form map of people and notes (account-map, flow-canvas), a plain list of people (data-table), or a tree of ideas (mind-map)."
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|