makersclaw 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/THIRD-PARTY-NOTICES.md +180 -0
- package/package.json +3 -2
- package/r/annotate.json +62 -0
- package/r/approval-request.json +52 -0
- package/r/audio-player.json +74 -0
- package/r/auth-form.json +55 -0
- package/r/board.json +10 -6
- package/r/calendar-view.json +105 -0
- package/r/cart.json +62 -0
- package/r/chart.json +83 -0
- package/r/chat.json +95 -0
- package/r/code-editor.json +94 -0
- package/r/comment-box.json +64 -0
- package/r/contact-section.json +53 -0
- package/r/core.json +205 -8
- package/r/csv-import.json +63 -0
- package/r/data-table.json +69 -0
- package/r/diagram.json +74 -0
- package/r/doc-editor.json +82 -0
- package/r/doc-page.json +61 -0
- package/r/email-render.json +73 -0
- package/r/faq.json +50 -0
- package/r/file-upload.json +54 -0
- package/r/flow-canvas.json +93 -0
- package/r/footer.json +52 -0
- package/r/gantt.json +70 -0
- package/r/job-panel.json +12 -7
- package/r/json-editor.json +66 -0
- package/r/map.json +89 -0
- package/r/menubar.json +52 -0
- package/r/mind-map.json +67 -0
- package/r/navigation-menu.json +52 -0
- package/r/order-detail.json +54 -0
- package/r/org-chart.json +66 -0
- package/r/page-builder.json +105 -0
- package/r/payment-methods.json +51 -0
- package/r/pdf-document.json +79 -0
- package/r/pdf-viewer.json +88 -0
- package/r/product-detail.json +76 -0
- package/r/product-grid.json +65 -0
- package/r/record-form.json +67 -0
- package/r/record-notes.json +55 -0
- package/r/registry.json +3411 -29
- package/r/search-dialog.json +51 -0
- package/r/settings-list.json +66 -0
- package/r/setup-checklist.json +51 -0
- package/r/share-dialog.json +52 -0
- package/r/sidebar.json +69 -0
- package/r/signature-pad.json +72 -0
- package/r/sketch-canvas.json +99 -0
- package/r/spreadsheet.json +90 -0
- package/r/stat-cards.json +66 -0
- package/r/task-list.json +63 -0
- package/r/task-model.json +98 -0
- package/r/testimonials.json +52 -0
- package/r/transaction-list.json +53 -0
- package/r/whiteboard.json +66 -0
- package/registry/blocks/annotate/README.md +179 -0
- package/registry/blocks/annotate/annotate-data.js +250 -0
- package/registry/blocks/annotate/annotate.jsx +646 -0
- package/registry/blocks/annotate/block.json +10 -0
- package/registry/blocks/annotate/demo.jsx +135 -0
- package/registry/blocks/annotate/index.js +15 -0
- package/registry/blocks/approval-request/README.md +116 -0
- package/registry/blocks/approval-request/approval-request.jsx +386 -0
- package/registry/blocks/approval-request/block.json +10 -0
- package/registry/blocks/approval-request/demo.jsx +127 -0
- package/registry/blocks/approval-request/index.js +4 -0
- package/registry/blocks/audio-player/README.md +167 -0
- package/registry/blocks/audio-player/audio-player.jsx +623 -0
- package/registry/blocks/audio-player/block.json +14 -0
- package/registry/blocks/audio-player/colors.js +109 -0
- package/registry/blocks/audio-player/demo.jsx +209 -0
- package/registry/blocks/audio-player/index.js +6 -0
- package/registry/blocks/audio-player/time.js +67 -0
- package/registry/blocks/audio-player/wavesurfer.js +9 -0
- package/registry/blocks/auth-form/README.md +126 -0
- package/registry/blocks/auth-form/auth-form.jsx +568 -0
- package/registry/blocks/auth-form/block.json +10 -0
- package/registry/blocks/auth-form/demo.jsx +131 -0
- package/registry/blocks/auth-form/index.js +3 -0
- package/registry/blocks/board/README.md +55 -5
- package/registry/blocks/board/block.json +2 -2
- package/registry/blocks/board/board.jsx +230 -86
- package/registry/blocks/board/demo.jsx +103 -24
- package/registry/blocks/calendar-view/README.md +180 -0
- package/registry/blocks/calendar-view/agenda.jsx +147 -0
- package/registry/blocks/calendar-view/block.json +76 -0
- package/registry/blocks/calendar-view/calendar-model.js +442 -0
- package/registry/blocks/calendar-view/calendar.jsx +627 -0
- package/registry/blocks/calendar-view/demo.jsx +195 -0
- package/registry/blocks/calendar-view/draft.jsx +49 -0
- package/registry/blocks/calendar-view/index.js +39 -0
- package/registry/blocks/calendar-view/month.jsx +346 -0
- package/registry/blocks/calendar-view/paint.js +69 -0
- package/registry/blocks/calendar-view/time-grid.jsx +527 -0
- package/registry/blocks/calendar-view/tray.jsx +87 -0
- package/registry/blocks/cart/README.md +146 -0
- package/registry/blocks/cart/block.json +10 -0
- package/registry/blocks/cart/cart.jsx +597 -0
- package/registry/blocks/cart/demo.jsx +98 -0
- package/registry/blocks/cart/index.js +4 -0
- package/registry/blocks/cart/money.js +28 -0
- package/registry/blocks/chart/README.md +316 -0
- package/registry/blocks/chart/block.json +10 -0
- package/registry/blocks/chart/cartesian.jsx +642 -0
- package/registry/blocks/chart/core.jsx +262 -0
- package/registry/blocks/chart/demo.jsx +357 -0
- package/registry/blocks/chart/heatmap.jsx +336 -0
- package/registry/blocks/chart/index.js +8 -0
- package/registry/blocks/chart/pie.jsx +245 -0
- package/registry/blocks/chart/sparkline.jsx +88 -0
- package/registry/blocks/chat/README.md +273 -0
- package/registry/blocks/chat/attachment.jsx +95 -0
- package/registry/blocks/chat/block.json +10 -0
- package/registry/blocks/chat/chat.jsx +132 -0
- package/registry/blocks/chat/composer.jsx +364 -0
- package/registry/blocks/chat/demo.jsx +578 -0
- package/registry/blocks/chat/header.jsx +34 -0
- package/registry/blocks/chat/index.js +9 -0
- package/registry/blocks/chat/message.jsx +450 -0
- package/registry/blocks/chat/scroller.jsx +247 -0
- package/registry/blocks/chat/text.jsx +104 -0
- package/registry/blocks/code-editor/README.md +210 -0
- package/registry/blocks/code-editor/block.json +22 -0
- package/registry/blocks/code-editor/code-editor.jsx +534 -0
- package/registry/blocks/code-editor/codemirror.js +38 -0
- package/registry/blocks/code-editor/demo.jsx +205 -0
- package/registry/blocks/code-editor/index.js +8 -0
- package/registry/blocks/code-editor/json.js +317 -0
- package/registry/blocks/code-editor/sql.js +136 -0
- package/registry/blocks/code-editor/text.js +101 -0
- package/registry/blocks/code-editor/theme.js +186 -0
- package/registry/blocks/comment-box/README.md +123 -0
- package/registry/blocks/comment-box/block.json +10 -0
- package/registry/blocks/comment-box/comment-body.jsx +217 -0
- package/registry/blocks/comment-box/comment-box.jsx +198 -0
- package/registry/blocks/comment-box/comment-time.jsx +77 -0
- package/registry/blocks/comment-box/demo.jsx +141 -0
- package/registry/blocks/comment-box/index.js +8 -0
- package/registry/blocks/contact-section/README.md +152 -0
- package/registry/blocks/contact-section/block.json +11 -0
- package/registry/blocks/contact-section/contact-section.jsx +509 -0
- package/registry/blocks/contact-section/demo.jsx +93 -0
- package/registry/blocks/contact-section/index.js +4 -0
- package/registry/blocks/csv-import/README.md +133 -0
- package/registry/blocks/csv-import/block.json +13 -0
- package/registry/blocks/csv-import/csv-import.jsx +479 -0
- package/registry/blocks/csv-import/demo.jsx +106 -0
- package/registry/blocks/csv-import/import.js +200 -0
- package/registry/blocks/csv-import/index.js +7 -0
- package/registry/blocks/data-table/README.md +386 -0
- package/registry/blocks/data-table/block.json +10 -0
- package/registry/blocks/data-table/data-table.jsx +1164 -0
- package/registry/blocks/data-table/demo.jsx +588 -0
- package/registry/blocks/data-table/index.js +5 -0
- package/registry/blocks/data-table/model.js +169 -0
- package/registry/blocks/diagram/README.md +108 -0
- package/registry/blocks/diagram/block.json +13 -0
- package/registry/blocks/diagram/demo.jsx +113 -0
- package/registry/blocks/diagram/diagram.jsx +481 -0
- package/registry/blocks/diagram/index.js +7 -0
- package/registry/blocks/diagram/mermaid.js +52 -0
- package/registry/blocks/diagram/palette.js +313 -0
- package/registry/blocks/diagram/source.js +98 -0
- package/registry/blocks/doc-editor/README.md +215 -0
- package/registry/blocks/doc-editor/block.json +15 -0
- package/registry/blocks/doc-editor/demo.jsx +225 -0
- package/registry/blocks/doc-editor/doc-editor.jsx +291 -0
- package/registry/blocks/doc-editor/doc.js +309 -0
- package/registry/blocks/doc-editor/index.js +7 -0
- package/registry/blocks/doc-editor/schema.jsx +56 -0
- package/registry/blocks/doc-editor/shadcn-classes.js +110 -0
- package/registry/blocks/doc-editor/theme.js +82 -0
- package/registry/blocks/doc-page/README.md +119 -0
- package/registry/blocks/doc-page/autosave.js +104 -0
- package/registry/blocks/doc-page/block.json +10 -0
- package/registry/blocks/doc-page/demo.jsx +137 -0
- package/registry/blocks/doc-page/doc-page.jsx +276 -0
- package/registry/blocks/doc-page/index.js +4 -0
- package/registry/blocks/email-render/README.md +151 -0
- package/registry/blocks/email-render/block.json +14 -0
- package/registry/blocks/email-render/demo.jsx +153 -0
- package/registry/blocks/email-render/doc-email.jsx +210 -0
- package/registry/blocks/email-render/email.jsx +221 -0
- package/registry/blocks/email-render/index.js +10 -0
- package/registry/blocks/email-render/render.js +50 -0
- package/registry/blocks/email-render/theme.js +215 -0
- package/registry/blocks/faq/README.md +101 -0
- package/registry/blocks/faq/block.json +11 -0
- package/registry/blocks/faq/demo.jsx +89 -0
- package/registry/blocks/faq/faq.jsx +220 -0
- package/registry/blocks/faq/index.js +4 -0
- package/registry/blocks/file-upload/README.md +138 -0
- package/registry/blocks/file-upload/block.json +10 -0
- package/registry/blocks/file-upload/demo.jsx +204 -0
- package/registry/blocks/file-upload/file-upload.jsx +635 -0
- package/registry/blocks/file-upload/index.js +4 -0
- package/registry/blocks/flow-canvas/README.md +420 -0
- package/registry/blocks/flow-canvas/block.json +13 -0
- package/registry/blocks/flow-canvas/board.js +819 -0
- package/registry/blocks/flow-canvas/chrome.jsx +649 -0
- package/registry/blocks/flow-canvas/context.jsx +35 -0
- package/registry/blocks/flow-canvas/demo.jsx +249 -0
- package/registry/blocks/flow-canvas/edges.jsx +107 -0
- package/registry/blocks/flow-canvas/flow-canvas.jsx +1329 -0
- package/registry/blocks/flow-canvas/index.js +41 -0
- package/registry/blocks/flow-canvas/nodes.jsx +392 -0
- package/registry/blocks/flow-canvas/theme.js +174 -0
- package/registry/blocks/footer/README.md +133 -0
- package/registry/blocks/footer/block.json +11 -0
- package/registry/blocks/footer/demo.jsx +119 -0
- package/registry/blocks/footer/footer.jsx +406 -0
- package/registry/blocks/footer/index.js +4 -0
- package/registry/blocks/gantt/README.md +220 -0
- package/registry/blocks/gantt/block.json +10 -0
- package/registry/blocks/gantt/demo.jsx +148 -0
- package/registry/blocks/gantt/gantt.jsx +923 -0
- package/registry/blocks/gantt/index.js +7 -0
- package/registry/blocks/gantt/rows.jsx +468 -0
- package/registry/blocks/gantt/schedule.js +278 -0
- package/registry/blocks/job-panel/README.md +80 -0
- package/registry/blocks/job-panel/block.json +3 -3
- package/registry/blocks/job-panel/demo.jsx +230 -3
- package/registry/blocks/job-panel/job-panel.jsx +169 -3
- package/registry/blocks/json-editor/README.md +133 -0
- package/registry/blocks/json-editor/block.json +10 -0
- package/registry/blocks/json-editor/demo.jsx +92 -0
- package/registry/blocks/json-editor/index.js +7 -0
- package/registry/blocks/json-editor/json-editor.jsx +305 -0
- package/registry/blocks/json-editor/json-tree.jsx +393 -0
- package/registry/blocks/json-editor/tree.js +225 -0
- package/registry/blocks/map/README.md +221 -0
- package/registry/blocks/map/block.json +14 -0
- package/registry/blocks/map/demo.jsx +201 -0
- package/registry/blocks/map/geo.js +198 -0
- package/registry/blocks/map/index.js +8 -0
- package/registry/blocks/map/list.jsx +128 -0
- package/registry/blocks/map/map-view.jsx +715 -0
- package/registry/blocks/map/maplibre.js +30 -0
- package/registry/blocks/map/marks.jsx +146 -0
- package/registry/blocks/map/theme.js +142 -0
- package/registry/blocks/menubar/README.md +109 -0
- package/registry/blocks/menubar/block.json +10 -0
- package/registry/blocks/menubar/demo.jsx +128 -0
- package/registry/blocks/menubar/index.js +4 -0
- package/registry/blocks/menubar/menubar.jsx +199 -0
- package/registry/blocks/mind-map/README.md +206 -0
- package/registry/blocks/mind-map/block.json +10 -0
- package/registry/blocks/mind-map/demo.jsx +103 -0
- package/registry/blocks/mind-map/index.js +31 -0
- package/registry/blocks/mind-map/mind-map.jsx +1125 -0
- package/registry/blocks/mind-map/topic.jsx +143 -0
- package/registry/blocks/mind-map/tree.js +645 -0
- package/registry/blocks/navigation-menu/README.md +124 -0
- package/registry/blocks/navigation-menu/block.json +10 -0
- package/registry/blocks/navigation-menu/demo.jsx +84 -0
- package/registry/blocks/navigation-menu/index.js +4 -0
- package/registry/blocks/navigation-menu/navigation-menu.jsx +448 -0
- package/registry/blocks/order-detail/README.md +109 -0
- package/registry/blocks/order-detail/block.json +10 -0
- package/registry/blocks/order-detail/demo.jsx +88 -0
- package/registry/blocks/order-detail/index.js +4 -0
- package/registry/blocks/order-detail/order-detail.jsx +354 -0
- package/registry/blocks/org-chart/README.md +145 -0
- package/registry/blocks/org-chart/block.json +10 -0
- package/registry/blocks/org-chart/demo.jsx +94 -0
- package/registry/blocks/org-chart/index.js +7 -0
- package/registry/blocks/org-chart/org-chart.jsx +631 -0
- package/registry/blocks/org-chart/org.js +245 -0
- package/registry/blocks/org-chart/person.jsx +96 -0
- package/registry/blocks/page-builder/README.md +257 -0
- package/registry/blocks/page-builder/block.json +14 -0
- package/registry/blocks/page-builder/demo.jsx +145 -0
- package/registry/blocks/page-builder/grapes.js +18 -0
- package/registry/blocks/page-builder/index.js +11 -0
- package/registry/blocks/page-builder/page-builder.jsx +704 -0
- package/registry/blocks/page-builder/page-view.jsx +33 -0
- package/registry/blocks/page-builder/page.js +118 -0
- package/registry/blocks/page-builder/panels.jsx +588 -0
- package/registry/blocks/page-builder/sections.js +209 -0
- package/registry/blocks/page-builder/theme.js +87 -0
- package/registry/blocks/page-builder/thumbs.jsx +189 -0
- package/registry/blocks/page-builder/tokens.js +329 -0
- package/registry/blocks/payment-methods/README.md +104 -0
- package/registry/blocks/payment-methods/block.json +10 -0
- package/registry/blocks/payment-methods/demo.jsx +71 -0
- package/registry/blocks/payment-methods/index.js +4 -0
- package/registry/blocks/payment-methods/payment-methods.jsx +302 -0
- package/registry/blocks/pdf-document/README.md +213 -0
- package/registry/blocks/pdf-document/block.json +13 -0
- package/registry/blocks/pdf-document/demo.jsx +136 -0
- package/registry/blocks/pdf-document/index.js +33 -0
- package/registry/blocks/pdf-document/money.js +83 -0
- package/registry/blocks/pdf-document/pdf-document.jsx +144 -0
- package/registry/blocks/pdf-document/primitives.jsx +271 -0
- package/registry/blocks/pdf-document/quote.jsx +179 -0
- package/registry/blocks/pdf-document/theme.js +193 -0
- package/registry/blocks/pdf-viewer/README.md +191 -0
- package/registry/blocks/pdf-viewer/block.json +14 -0
- package/registry/blocks/pdf-viewer/demo.jsx +252 -0
- package/registry/blocks/pdf-viewer/helpers.js +270 -0
- package/registry/blocks/pdf-viewer/index.js +8 -0
- package/registry/blocks/pdf-viewer/notes.jsx +195 -0
- package/registry/blocks/pdf-viewer/pdf-viewer.jsx +1368 -0
- package/registry/blocks/pdf-viewer/pdfjs.js +37 -0
- package/registry/blocks/pdf-viewer/ssr-shim-end.js +6 -0
- package/registry/blocks/pdf-viewer/ssr-shim.js +44 -0
- package/registry/blocks/product-detail/README.md +217 -0
- package/registry/blocks/product-detail/block.json +10 -0
- package/registry/blocks/product-detail/demo.jsx +233 -0
- package/registry/blocks/product-detail/index.js +7 -0
- package/registry/blocks/product-detail/price.jsx +115 -0
- package/registry/blocks/product-detail/product-detail.jsx +348 -0
- package/registry/blocks/product-detail/product-media.jsx +102 -0
- package/registry/blocks/product-detail/product-options.jsx +144 -0
- package/registry/blocks/product-grid/README.md +162 -0
- package/registry/blocks/product-grid/block.json +10 -0
- package/registry/blocks/product-grid/demo.jsx +255 -0
- package/registry/blocks/product-grid/index.js +5 -0
- package/registry/blocks/product-grid/product-card.jsx +232 -0
- package/registry/blocks/product-grid/product-grid.jsx +235 -0
- package/registry/blocks/record-form/README.md +196 -0
- package/registry/blocks/record-form/block.json +10 -0
- package/registry/blocks/record-form/demo.jsx +525 -0
- package/registry/blocks/record-form/index.js +4 -0
- package/registry/blocks/record-form/record-fields.jsx +457 -0
- package/registry/blocks/record-form/record-form.jsx +415 -0
- package/registry/blocks/record-form/rules.js +81 -0
- package/registry/blocks/record-notes/README.md +139 -0
- package/registry/blocks/record-notes/block.json +10 -0
- package/registry/blocks/record-notes/demo.jsx +179 -0
- package/registry/blocks/record-notes/index.js +4 -0
- package/registry/blocks/record-notes/record-notes.jsx +266 -0
- package/registry/blocks/search-dialog/README.md +108 -0
- package/registry/blocks/search-dialog/block.json +10 -0
- package/registry/blocks/search-dialog/demo.jsx +116 -0
- package/registry/blocks/search-dialog/index.js +3 -0
- package/registry/blocks/search-dialog/search-dialog.jsx +235 -0
- package/registry/blocks/settings-list/README.md +171 -0
- package/registry/blocks/settings-list/block.json +10 -0
- package/registry/blocks/settings-list/demo.jsx +333 -0
- package/registry/blocks/settings-list/index.js +4 -0
- package/registry/blocks/settings-list/row-state.jsx +93 -0
- package/registry/blocks/settings-list/settings-list.jsx +349 -0
- package/registry/blocks/settings-list/settings-matrix.jsx +118 -0
- package/registry/blocks/setup-checklist/README.md +142 -0
- package/registry/blocks/setup-checklist/block.json +10 -0
- package/registry/blocks/setup-checklist/demo.jsx +159 -0
- package/registry/blocks/setup-checklist/index.js +4 -0
- package/registry/blocks/setup-checklist/setup-checklist.jsx +446 -0
- package/registry/blocks/share-dialog/README.md +113 -0
- package/registry/blocks/share-dialog/block.json +10 -0
- package/registry/blocks/share-dialog/demo.jsx +140 -0
- package/registry/blocks/share-dialog/index.js +3 -0
- package/registry/blocks/share-dialog/share-dialog.jsx +384 -0
- package/registry/blocks/sidebar/README.md +190 -0
- package/registry/blocks/sidebar/block.json +43 -0
- package/registry/blocks/sidebar/demo.jsx +577 -0
- package/registry/blocks/sidebar/index.js +4 -0
- package/registry/blocks/sidebar/sidebar-panel.jsx +149 -0
- package/registry/blocks/sidebar/sidebar.jsx +864 -0
- package/registry/blocks/signature-pad/README.md +137 -0
- package/registry/blocks/signature-pad/block.json +13 -0
- package/registry/blocks/signature-pad/colors.js +115 -0
- package/registry/blocks/signature-pad/demo.jsx +94 -0
- package/registry/blocks/signature-pad/index.js +6 -0
- package/registry/blocks/signature-pad/pad.js +7 -0
- package/registry/blocks/signature-pad/signature-pad.jsx +434 -0
- package/registry/blocks/signature-pad/signature.js +68 -0
- package/registry/blocks/sketch-canvas/README.md +280 -0
- package/registry/blocks/sketch-canvas/block.json +13 -0
- package/registry/blocks/sketch-canvas/demo.jsx +159 -0
- package/registry/blocks/sketch-canvas/excalidraw.js +40 -0
- package/registry/blocks/sketch-canvas/index.js +9 -0
- package/registry/blocks/sketch-canvas/palette.js +226 -0
- package/registry/blocks/sketch-canvas/sketch-canvas.jsx +1188 -0
- package/registry/blocks/sketch-canvas/sketch.js +179 -0
- package/registry/blocks/sketch-canvas/ssr-shim-end.js +6 -0
- package/registry/blocks/sketch-canvas/ssr-shim.js +45 -0
- package/registry/blocks/sketch-canvas/stamps.js +104 -0
- package/registry/blocks/sketch-canvas/theme.js +131 -0
- package/registry/blocks/spreadsheet/README.md +307 -0
- package/registry/blocks/spreadsheet/block.json +13 -0
- package/registry/blocks/spreadsheet/cells.jsx +455 -0
- package/registry/blocks/spreadsheet/chrome.jsx +325 -0
- package/registry/blocks/spreadsheet/demo.jsx +177 -0
- package/registry/blocks/spreadsheet/grid.js +387 -0
- package/registry/blocks/spreadsheet/index.js +34 -0
- package/registry/blocks/spreadsheet/spreadsheet.jsx +1732 -0
- package/registry/blocks/spreadsheet/types.js +473 -0
- package/registry/blocks/stat-cards/README.md +173 -0
- package/registry/blocks/stat-cards/block.json +10 -0
- package/registry/blocks/stat-cards/demo.jsx +257 -0
- package/registry/blocks/stat-cards/index.js +4 -0
- package/registry/blocks/stat-cards/stat-cards.jsx +307 -0
- package/registry/blocks/stat-cards/usage.jsx +243 -0
- package/registry/blocks/task-list/README.md +176 -0
- package/registry/blocks/task-list/block.json +10 -0
- package/registry/blocks/task-list/demo.jsx +134 -0
- package/registry/blocks/task-list/index.js +5 -0
- package/registry/blocks/task-list/task-list.jsx +907 -0
- package/registry/blocks/task-model/README.md +455 -0
- package/registry/blocks/task-model/block.json +167 -0
- package/registry/blocks/task-model/changes.js +89 -0
- package/registry/blocks/task-model/dates.js +371 -0
- package/registry/blocks/task-model/demo.jsx +215 -0
- package/registry/blocks/task-model/dnd.jsx +240 -0
- package/registry/blocks/task-model/index.js +97 -0
- package/registry/blocks/task-model/model.js +919 -0
- package/registry/blocks/task-model/parts.jsx +449 -0
- package/registry/blocks/task-model/toolbar.jsx +271 -0
- package/registry/blocks/testimonials/README.md +139 -0
- package/registry/blocks/testimonials/block.json +11 -0
- package/registry/blocks/testimonials/demo.jsx +137 -0
- package/registry/blocks/testimonials/index.js +4 -0
- package/registry/blocks/testimonials/testimonials.jsx +430 -0
- package/registry/blocks/transaction-list/README.md +126 -0
- package/registry/blocks/transaction-list/block.json +10 -0
- package/registry/blocks/transaction-list/demo.jsx +79 -0
- package/registry/blocks/transaction-list/index.js +4 -0
- package/registry/blocks/transaction-list/transaction-list.jsx +383 -0
- package/registry/blocks/whiteboard/README.md +179 -0
- package/registry/blocks/whiteboard/block.json +10 -0
- package/registry/blocks/whiteboard/demo.jsx +169 -0
- package/registry/blocks/whiteboard/index.js +6 -0
- package/registry/blocks/whiteboard/templates.js +150 -0
- package/registry/blocks/whiteboard/whiteboard.jsx +721 -0
- package/src/install.mjs +18 -0
- package/src/shadcn.mjs +8 -0
- package/templates/next/files/README.md +145 -11
- package/templates/next/files/app/globals.css +55 -4
- package/templates/next/files/check/run.mjs +3 -3
- package/templates/next/files/components/ui/avatar.jsx +141 -0
- package/templates/next/files/components/ui/breadcrumb.jsx +149 -0
- package/templates/next/files/components/ui/button-group.jsx +70 -0
- package/templates/next/files/components/ui/button.jsx +132 -12
- package/templates/next/files/components/ui/calendar.jsx +609 -0
- package/templates/next/files/components/ui/carousel.jsx +281 -0
- package/templates/next/files/components/ui/collapsible.jsx +208 -0
- package/templates/next/files/components/ui/combobox.jsx +608 -0
- package/templates/next/files/components/ui/command.jsx +577 -0
- package/templates/next/files/components/ui/context-menu.jsx +191 -0
- package/templates/next/files/components/ui/date-picker.jsx +360 -0
- package/templates/next/files/components/ui/distribution.jsx +117 -0
- package/templates/next/files/components/ui/feedback.jsx +143 -0
- package/templates/next/files/components/ui/field.jsx +115 -3
- package/templates/next/files/components/ui/file-input.jsx +234 -0
- package/templates/next/files/components/ui/icon.jsx +130 -8
- package/templates/next/files/components/ui/image.jsx +143 -0
- package/templates/next/files/components/ui/index.js +47 -2
- package/templates/next/files/components/ui/input-group.jsx +213 -0
- package/templates/next/files/components/ui/input-otp.jsx +170 -0
- package/templates/next/files/components/ui/item.jsx +206 -0
- package/templates/next/files/components/ui/menu.jsx +454 -82
- package/templates/next/files/components/ui/notice.jsx +126 -14
- package/templates/next/files/components/ui/pagination.jsx +156 -0
- package/templates/next/files/components/ui/popover.jsx +284 -0
- package/templates/next/files/components/ui/radio.jsx +193 -0
- package/templates/next/files/components/ui/rating.jsx +131 -0
- package/templates/next/files/components/ui/resizable.jsx +338 -0
- package/templates/next/files/components/ui/scroll-area.jsx +123 -0
- package/templates/next/files/components/ui/separator.jsx +119 -0
- package/templates/next/files/components/ui/sheet.jsx +96 -11
- package/templates/next/files/components/ui/slider.jsx +174 -0
- package/templates/next/files/components/ui/stat.jsx +574 -0
- package/templates/next/files/components/ui/steps.jsx +338 -0
- package/templates/next/files/components/ui/swatch.jsx +33 -0
- package/templates/next/files/components/ui/table.jsx +130 -0
- package/templates/next/files/components/ui/toast.jsx +440 -0
- package/templates/next/files/components/ui/toggle.jsx +195 -0
- package/templates/next/files/components/ui/tooltip.jsx +270 -0
- package/templates/next/template.json +264 -8
|
@@ -0,0 +1,588 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// The builder's panels, in the kit: Add (blocks), Layers (the page's tree),
|
|
4
|
+
// Design (the selected element's look, token choices only) and the
|
|
5
|
+
// template picker. Each reads the GrapesJS editor it is handed and changes
|
|
6
|
+
// the page through the editor's own API, so undo/redo covers every edit.
|
|
7
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
8
|
+
import { Button, Field, FileInput, Icon, IconButton, Input, Select, Swatch, Switch, ToggleGroup, Tooltip, cx, toast } from "../../ui";
|
|
9
|
+
import { BlocksProvider } from "./grapes";
|
|
10
|
+
import { BlockThumb, PageThumb } from "./thumbs";
|
|
11
|
+
import { currentOption, groupsFor, patchFor, swatchVar } from "./tokens";
|
|
12
|
+
|
|
13
|
+
// ---- helpers over components ------------------------------------------------
|
|
14
|
+
|
|
15
|
+
const TEXT_TAGS = new Set(["h1", "h2", "h3", "h4", "h5", "h6", "p", "li", "span", "strong", "em", "blockquote", "label", "small"]);
|
|
16
|
+
|
|
17
|
+
/** text · link · image · box — which Design groups apply. */
|
|
18
|
+
export function kindOf(c) {
|
|
19
|
+
if (!c) return "box";
|
|
20
|
+
if (c.is("image")) return "image";
|
|
21
|
+
if (c.is("link")) return "link";
|
|
22
|
+
if (c.is("text") || TEXT_TAGS.has(String(c.get("tagName") ?? "").toLowerCase())) return "text";
|
|
23
|
+
return "box";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function nameOf(editor, c) {
|
|
27
|
+
if (!c) return "";
|
|
28
|
+
const own = c.get("name") || c.getAttributes?.()["data-gjs-name"];
|
|
29
|
+
if (own) return own;
|
|
30
|
+
const tag = String(c.get("tagName") ?? "").toLowerCase();
|
|
31
|
+
if (/^h[1-6]$/.test(tag)) return "Heading";
|
|
32
|
+
if (tag === "p") return "Text";
|
|
33
|
+
if (tag === "ul" || tag === "ol") return "List";
|
|
34
|
+
if (tag === "li") return "List item";
|
|
35
|
+
if (tag === "hr") return "Divider";
|
|
36
|
+
if (tag === "nav") return "Links";
|
|
37
|
+
if (c.is("link")) return c.getClasses?.().includes("pb-button") ? "Button" : "Link";
|
|
38
|
+
if (c.is("image")) return "Image";
|
|
39
|
+
if (c.is("text")) return "Text";
|
|
40
|
+
return editor?.Layers?.getName?.(c) || c.getName?.() || "Box";
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** The children a layer tree shows: no bare text nodes, nothing inside a
|
|
44
|
+
* text (its bold and italic runs are part of the text). */
|
|
45
|
+
function layerKids(c) {
|
|
46
|
+
if (!c || c.is("text") || c.is("link")) return [];
|
|
47
|
+
return c.components().filter((k) => k.get("type") !== "textnode" && k.get("layerable") !== false);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function topLevel(editor, c) {
|
|
51
|
+
const wrapper = editor.getWrapper();
|
|
52
|
+
let cur = c;
|
|
53
|
+
while (cur?.parent() && cur.parent() !== wrapper) cur = cur.parent();
|
|
54
|
+
return cur;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ---- Add ---------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
/** The block library: search, blocks grouped by category, click or drag. */
|
|
60
|
+
export function AddPanel({ editor, blocks, templates, onAdd, onDragging, onTemplates }) {
|
|
61
|
+
const [query, setQuery] = useState("");
|
|
62
|
+
const q = query.trim().toLowerCase();
|
|
63
|
+
const groups = useMemo(() => {
|
|
64
|
+
const out = new Map();
|
|
65
|
+
for (const b of blocks) {
|
|
66
|
+
if (q && !`${b.label} ${b.description} ${b.category}`.toLowerCase().includes(q)) continue;
|
|
67
|
+
if (!out.has(b.category)) out.set(b.category, []);
|
|
68
|
+
out.get(b.category).push(b);
|
|
69
|
+
}
|
|
70
|
+
return [...out.entries()];
|
|
71
|
+
}, [blocks, q]);
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div className="flex min-h-0 flex-1 flex-col">
|
|
75
|
+
<div className="flex items-center gap-2 px-3 pb-3">
|
|
76
|
+
<Input
|
|
77
|
+
type="search"
|
|
78
|
+
value={query}
|
|
79
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
80
|
+
placeholder="Search blocks"
|
|
81
|
+
aria-label="Search blocks"
|
|
82
|
+
/>
|
|
83
|
+
{templates?.length ? (
|
|
84
|
+
<Tooltip label="Start from a template">
|
|
85
|
+
<IconButton icon="file" label="Templates" size="sm" variant="secondary" onClick={onTemplates} />
|
|
86
|
+
</Tooltip>
|
|
87
|
+
) : null}
|
|
88
|
+
</div>
|
|
89
|
+
<div className="min-h-0 flex-1 overflow-y-auto px-3 pb-4">
|
|
90
|
+
{groups.length === 0 ? (
|
|
91
|
+
<p className="px-1 py-6 text-center text-sm text-muted-foreground">No block matches “{query}”.</p>
|
|
92
|
+
) : (
|
|
93
|
+
<BlocksProvider>
|
|
94
|
+
{({ dragStart, dragStop }) => (
|
|
95
|
+
<div className="grid gap-5">
|
|
96
|
+
{groups.map(([category, list]) => (
|
|
97
|
+
<section key={category} aria-label={category} className="grid gap-2">
|
|
98
|
+
<h3 className="px-1 text-xs font-medium text-muted-foreground">{category}</h3>
|
|
99
|
+
<div className="grid grid-cols-2 gap-2">
|
|
100
|
+
{list.map((b) => (
|
|
101
|
+
<BlockTile
|
|
102
|
+
key={b.id}
|
|
103
|
+
block={b}
|
|
104
|
+
onAdd={() => onAdd(b)}
|
|
105
|
+
onDragStart={(ev) => {
|
|
106
|
+
const gb = editor?.Blocks.get(b.id);
|
|
107
|
+
if (!gb) return;
|
|
108
|
+
onDragging?.(true);
|
|
109
|
+
dragStart(gb, ev);
|
|
110
|
+
}}
|
|
111
|
+
onDragEnd={() => {
|
|
112
|
+
dragStop(false);
|
|
113
|
+
onDragging?.(false);
|
|
114
|
+
}}
|
|
115
|
+
/>
|
|
116
|
+
))}
|
|
117
|
+
</div>
|
|
118
|
+
</section>
|
|
119
|
+
))}
|
|
120
|
+
</div>
|
|
121
|
+
)}
|
|
122
|
+
</BlocksProvider>
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
<p className="border-t border-border px-4 py-2.5 text-xs text-muted-foreground">
|
|
126
|
+
Click to add below the selection, or drag onto the page.
|
|
127
|
+
</p>
|
|
128
|
+
</div>
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function BlockTile({ block, onAdd, onDragStart, onDragEnd }) {
|
|
133
|
+
// raw: a tile that is both a button and an HTML5 drag source; a kit
|
|
134
|
+
// Button is not draggable in every browser (Firefox drops drags that
|
|
135
|
+
// start on a <button>), so this is a div with the button role and keys.
|
|
136
|
+
const tile = (
|
|
137
|
+
<div
|
|
138
|
+
role="button"
|
|
139
|
+
tabIndex={0}
|
|
140
|
+
draggable
|
|
141
|
+
aria-label={`Add ${block.label}`}
|
|
142
|
+
onClick={onAdd}
|
|
143
|
+
onKeyDown={(e) => {
|
|
144
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
onAdd();
|
|
147
|
+
}
|
|
148
|
+
}}
|
|
149
|
+
onDragStart={(e) => {
|
|
150
|
+
e.dataTransfer.effectAllowed = "copy";
|
|
151
|
+
onDragStart(e.nativeEvent);
|
|
152
|
+
}}
|
|
153
|
+
onDragEnd={onDragEnd}
|
|
154
|
+
className={cx(
|
|
155
|
+
"group grid cursor-grab gap-1.5 rounded-lg border border-transparent p-1.5 text-left outline-none transition-colors duration-150 active:cursor-grabbing",
|
|
156
|
+
"hover:border-border hover:bg-accent focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
|
|
157
|
+
)}
|
|
158
|
+
>
|
|
159
|
+
<BlockThumb name={block.thumb} className="aspect-[16/10] w-full transition-shadow duration-150 group-hover:shadow-sm" />
|
|
160
|
+
<span className="truncate px-0.5 text-xs font-medium">{block.label}</span>
|
|
161
|
+
</div>
|
|
162
|
+
);
|
|
163
|
+
return block.description ? (
|
|
164
|
+
<Tooltip label={block.description} side="right">
|
|
165
|
+
{tile}
|
|
166
|
+
</Tooltip>
|
|
167
|
+
) : (
|
|
168
|
+
tile
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ---- Templates -----------------------------------------------------------------
|
|
173
|
+
|
|
174
|
+
/** Template cards: a stacked wireframe, a name, a line. */
|
|
175
|
+
export function TemplateGrid({ templates, onPick, compact = false }) {
|
|
176
|
+
return (
|
|
177
|
+
<div className={cx("grid gap-3", compact ? "grid-cols-2 @2xl:grid-cols-3" : "grid-cols-1 sm:grid-cols-2")}>
|
|
178
|
+
{templates.map((t) => (
|
|
179
|
+
// raw: a card-sized choice (picture, name, description); Button is a
|
|
180
|
+
// one-line control and cannot hold this layout.
|
|
181
|
+
<button
|
|
182
|
+
key={t.id}
|
|
183
|
+
type="button"
|
|
184
|
+
onClick={() => onPick(t)}
|
|
185
|
+
className={cx(
|
|
186
|
+
"group grid gap-2 rounded-lg border border-border bg-card p-2 text-left outline-none transition-[border-color,box-shadow] duration-150",
|
|
187
|
+
"hover:border-primary/50 hover:shadow-sm focus-visible:ring-2 focus-visible:ring-ring motion-reduce:transition-none",
|
|
188
|
+
)}
|
|
189
|
+
>
|
|
190
|
+
<PageThumb names={t.thumbs ?? []} className="w-full" />
|
|
191
|
+
<span className="grid gap-0.5 px-1 pb-1">
|
|
192
|
+
<span className="text-sm font-medium">{t.label}</span>
|
|
193
|
+
{t.description ? <span className="text-xs text-muted-foreground">{t.description}</span> : null}
|
|
194
|
+
</span>
|
|
195
|
+
</button>
|
|
196
|
+
))}
|
|
197
|
+
</div>
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ---- Layers ----------------------------------------------------------------------
|
|
202
|
+
|
|
203
|
+
/** The page as a tree: select, fold, hide. Arrow keys walk it. */
|
|
204
|
+
export function LayersPanel({ editor, selected, rev, onSelect }) {
|
|
205
|
+
const [closed, setClosed] = useState(() => new Set());
|
|
206
|
+
const list = useRef(null);
|
|
207
|
+
const wrapper = editor?.getWrapper();
|
|
208
|
+
// `rev` changes whenever the page does; the tree is rebuilt from the editor.
|
|
209
|
+
const rows = useMemo(() => {
|
|
210
|
+
const out = [];
|
|
211
|
+
const walk = (c, depth) => {
|
|
212
|
+
for (const k of layerKids(c)) {
|
|
213
|
+
const kids = layerKids(k);
|
|
214
|
+
out.push({ c: k, depth, hasKids: kids.length > 0 });
|
|
215
|
+
if (kids.length && !closed.has(k.cid)) walk(k, depth + 1);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
if (wrapper) walk(wrapper, 0);
|
|
219
|
+
return out;
|
|
220
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
221
|
+
}, [wrapper, rev, closed]);
|
|
222
|
+
|
|
223
|
+
const toggle = (cid) =>
|
|
224
|
+
setClosed((s) => {
|
|
225
|
+
const n = new Set(s);
|
|
226
|
+
n.has(cid) ? n.delete(cid) : n.add(cid);
|
|
227
|
+
return n;
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
function onKeyDown(e, i, row) {
|
|
231
|
+
const items = [...(list.current?.querySelectorAll("[data-layer-row]") ?? [])];
|
|
232
|
+
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
|
233
|
+
e.preventDefault();
|
|
234
|
+
items[Math.min(items.length - 1, Math.max(0, i + (e.key === "ArrowDown" ? 1 : -1)))]?.focus();
|
|
235
|
+
} else if (e.key === "ArrowRight" && row.hasKids && closed.has(row.c.cid)) {
|
|
236
|
+
e.preventDefault();
|
|
237
|
+
toggle(row.c.cid);
|
|
238
|
+
} else if (e.key === "ArrowLeft" && row.hasKids && !closed.has(row.c.cid)) {
|
|
239
|
+
e.preventDefault();
|
|
240
|
+
toggle(row.c.cid);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (!rows.length) {
|
|
245
|
+
return <p className="px-4 py-8 text-center text-sm text-muted-foreground">Nothing on the page yet. Add a section to begin.</p>;
|
|
246
|
+
}
|
|
247
|
+
return (
|
|
248
|
+
<ul ref={list} role="tree" aria-label="Page layers" className="grid gap-px px-2 pb-4">
|
|
249
|
+
{rows.map((row, i) => {
|
|
250
|
+
const on = selected === row.c;
|
|
251
|
+
const hidden = editor.Layers.isVisible(row.c) === false;
|
|
252
|
+
const open = !closed.has(row.c.cid);
|
|
253
|
+
return (
|
|
254
|
+
<li key={row.c.cid} role="treeitem" aria-selected={on} aria-expanded={row.hasKids ? open : undefined} aria-level={row.depth + 1}>
|
|
255
|
+
<div
|
|
256
|
+
className={cx(
|
|
257
|
+
"group flex min-h-9 items-center gap-1 rounded-md pr-1 text-sm transition-colors duration-150 motion-reduce:transition-none",
|
|
258
|
+
on ? "bg-accent text-accent-foreground" : "hover:bg-accent/60",
|
|
259
|
+
hidden && "text-muted-foreground",
|
|
260
|
+
)}
|
|
261
|
+
style={{ paddingInlineStart: 4 + row.depth * 14 }}
|
|
262
|
+
>
|
|
263
|
+
{row.hasKids ? (
|
|
264
|
+
// raw: a 24px fold chevron inside a 36px row; the kit's
|
|
265
|
+
// smallest IconButton is the row's own height.
|
|
266
|
+
<button
|
|
267
|
+
type="button"
|
|
268
|
+
tabIndex={-1}
|
|
269
|
+
aria-label={open ? "Fold" : "Unfold"}
|
|
270
|
+
onClick={() => toggle(row.c.cid)}
|
|
271
|
+
className="grid size-6 shrink-0 place-items-center rounded text-muted-foreground hover:text-foreground"
|
|
272
|
+
>
|
|
273
|
+
<Icon name={open ? "chevron-down" : "chevron-right"} size={14} />
|
|
274
|
+
</button>
|
|
275
|
+
) : (
|
|
276
|
+
<span className="size-6 shrink-0" />
|
|
277
|
+
)}
|
|
278
|
+
{/* raw: the row's name is the tree item's focus target; a kit
|
|
279
|
+
Button would add its own padding and 36px minimum inside the row. */}
|
|
280
|
+
<button
|
|
281
|
+
type="button"
|
|
282
|
+
data-layer-row
|
|
283
|
+
onClick={() => onSelect(row.c)}
|
|
284
|
+
onKeyDown={(e) => onKeyDown(e, i, row)}
|
|
285
|
+
className="min-w-0 flex-1 truncate py-1.5 text-left outline-none focus-visible:underline"
|
|
286
|
+
>
|
|
287
|
+
{nameOf(editor, row.c)}
|
|
288
|
+
</button>
|
|
289
|
+
<Tooltip label={hidden ? "Show while editing" : "Hide while editing"}>
|
|
290
|
+
<IconButton
|
|
291
|
+
icon={hidden ? "eye-off" : "eye"}
|
|
292
|
+
label={hidden ? `Show ${nameOf(editor, row.c)}` : `Hide ${nameOf(editor, row.c)}`}
|
|
293
|
+
size="sm"
|
|
294
|
+
onClick={() => editor.Layers.setVisible(row.c, hidden)}
|
|
295
|
+
className={cx("transition-opacity duration-150", hidden ? "opacity-100" : "opacity-0 group-hover:opacity-100 focus-visible:opacity-100 [@media(hover:none)]:opacity-100")}
|
|
296
|
+
/>
|
|
297
|
+
</Tooltip>
|
|
298
|
+
</div>
|
|
299
|
+
</li>
|
|
300
|
+
);
|
|
301
|
+
})}
|
|
302
|
+
</ul>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
// ---- Design ------------------------------------------------------------------------
|
|
307
|
+
|
|
308
|
+
/** The selected element's look — only the token choices in `groups` — plus
|
|
309
|
+
* its link or picture, and the moves (parent, up, down, copy, delete). */
|
|
310
|
+
export function DesignPanel({ editor, selected, rev, groups, onUploadImage, onAction }) {
|
|
311
|
+
if (!selected) {
|
|
312
|
+
return (
|
|
313
|
+
<div className="grid gap-4 px-4 py-8 text-center">
|
|
314
|
+
<span className="mx-auto grid size-10 place-items-center rounded-full bg-muted text-muted-foreground">
|
|
315
|
+
<Icon name="mouse-pointer" size={18} />
|
|
316
|
+
</span>
|
|
317
|
+
<div className="grid gap-1">
|
|
318
|
+
<p className="text-sm font-medium">Select something to style it</p>
|
|
319
|
+
<p className="text-sm text-muted-foreground">Click any part of the page. Double-click text to edit the words.</p>
|
|
320
|
+
</div>
|
|
321
|
+
</div>
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
const kind = kindOf(selected);
|
|
325
|
+
const style = selected.getStyle?.() ?? {};
|
|
326
|
+
const shown = groupsFor(groups, kind);
|
|
327
|
+
const parent = selected.parent();
|
|
328
|
+
const index = selected.index();
|
|
329
|
+
const siblings = parent ? parent.components().length : 0;
|
|
330
|
+
|
|
331
|
+
function apply(group, value) {
|
|
332
|
+
const next = { ...(selected.getStyle?.() ?? {}) };
|
|
333
|
+
for (const [k, v] of Object.entries(patchFor(group, value))) {
|
|
334
|
+
if (v === "") delete next[k];
|
|
335
|
+
else next[k] = v;
|
|
336
|
+
}
|
|
337
|
+
selected.setStyle(next);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
return (
|
|
341
|
+
<div className="grid gap-5 px-4 pb-6" key={selected.cid}>
|
|
342
|
+
<div className="grid gap-2">
|
|
343
|
+
<div className="flex items-baseline justify-between gap-2">
|
|
344
|
+
<p className="truncate text-sm font-semibold">{nameOf(editor, selected)}</p>
|
|
345
|
+
<p className="shrink-0 text-xs text-muted-foreground">{KIND_LABEL[kind]}</p>
|
|
346
|
+
</div>
|
|
347
|
+
<div className="flex flex-wrap gap-1" role="toolbar" aria-label="Arrange">
|
|
348
|
+
<Tooltip label="Select the parent">
|
|
349
|
+
<IconButton icon="arrow-up" label="Select the parent" size="sm" variant="secondary" disabled={!parent || parent === editor.getWrapper()} onClick={() => onAction("parent")} />
|
|
350
|
+
</Tooltip>
|
|
351
|
+
<Tooltip label="Move up">
|
|
352
|
+
<IconButton icon="chevron-up" label="Move up" size="sm" variant="secondary" disabled={index <= 0} onClick={() => onAction("up")} />
|
|
353
|
+
</Tooltip>
|
|
354
|
+
<Tooltip label="Move down">
|
|
355
|
+
<IconButton icon="chevron-down" label="Move down" size="sm" variant="secondary" disabled={index < 0 || index >= siblings - 1} onClick={() => onAction("down")} />
|
|
356
|
+
</Tooltip>
|
|
357
|
+
<Tooltip label="Duplicate">
|
|
358
|
+
<IconButton icon="copy" label="Duplicate" size="sm" variant="secondary" onClick={() => onAction("duplicate")} />
|
|
359
|
+
</Tooltip>
|
|
360
|
+
<Tooltip label="Delete">
|
|
361
|
+
<IconButton icon="trash" label="Delete" size="sm" variant="danger" onClick={() => onAction("delete")} />
|
|
362
|
+
</Tooltip>
|
|
363
|
+
</div>
|
|
364
|
+
</div>
|
|
365
|
+
|
|
366
|
+
{kind === "link" ? <LinkFields key={`l${selected.cid}`} component={selected} /> : null}
|
|
367
|
+
{kind === "image" ? <ImageFields key={`i${selected.cid}`} component={selected} onUploadImage={onUploadImage} /> : null}
|
|
368
|
+
|
|
369
|
+
{shown.map((g) => (
|
|
370
|
+
<StyleGroup key={g.id} group={g} value={currentOption(g, style)} onChange={(v) => apply(g, v)} />
|
|
371
|
+
))}
|
|
372
|
+
|
|
373
|
+
{Object.keys(style).length ? (
|
|
374
|
+
<Button variant="quiet" size="sm" icon="refresh" onClick={() => selected.setStyle({})} className="justify-self-start">
|
|
375
|
+
Clear this element’s style
|
|
376
|
+
</Button>
|
|
377
|
+
) : null}
|
|
378
|
+
</div>
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const KIND_LABEL = { text: "Text", link: "Link", image: "Image", box: "Box" };
|
|
383
|
+
|
|
384
|
+
function StyleGroup({ group, value, onChange }) {
|
|
385
|
+
const current = group.options.find((o) => o.value === value);
|
|
386
|
+
const choices = group.options.filter((o) => o.value !== "");
|
|
387
|
+
const id = `pb-${group.id}`;
|
|
388
|
+
return (
|
|
389
|
+
<div className="grid gap-2">
|
|
390
|
+
<div className="flex min-h-5 items-center justify-between gap-2">
|
|
391
|
+
<span id={id} className="text-xs font-medium">
|
|
392
|
+
{group.label}
|
|
393
|
+
</span>
|
|
394
|
+
{value ? (
|
|
395
|
+
<span className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
396
|
+
{value === "custom" ? "Custom" : current?.label}
|
|
397
|
+
<Button variant="link" size="inherit" tone="muted" onClick={() => onChange("")}>
|
|
398
|
+
Reset
|
|
399
|
+
</Button>
|
|
400
|
+
</span>
|
|
401
|
+
) : (
|
|
402
|
+
<span className="text-xs text-muted-foreground">Default</span>
|
|
403
|
+
)}
|
|
404
|
+
</div>
|
|
405
|
+
{group.kind === "swatch" ? (
|
|
406
|
+
<SwatchRow labelledBy={id} options={choices} value={value} onChange={onChange} />
|
|
407
|
+
) : group.kind === "select" ? (
|
|
408
|
+
<Select
|
|
409
|
+
aria-labelledby={id}
|
|
410
|
+
value={value === "custom" ? "" : value}
|
|
411
|
+
onChange={(e) => onChange(e.target.value)}
|
|
412
|
+
options={group.options.map((o) => ({ value: o.value, label: o.label }))}
|
|
413
|
+
/>
|
|
414
|
+
) : (
|
|
415
|
+
<ToggleGroup
|
|
416
|
+
aria-label={group.label}
|
|
417
|
+
size="sm"
|
|
418
|
+
value={value}
|
|
419
|
+
onChange={(v) => onChange(v === value ? "" : v)}
|
|
420
|
+
items={choices.map((o) => (o.icon ? { value: o.value, label: o.label, icon: o.icon, iconOnly: true } : { value: o.value, label: o.label }))}
|
|
421
|
+
className="w-full"
|
|
422
|
+
/>
|
|
423
|
+
)}
|
|
424
|
+
</div>
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function SwatchRow({ labelledBy, options, value, onChange }) {
|
|
429
|
+
const refs = useRef([]);
|
|
430
|
+
const at = Math.max(0, options.findIndex((o) => o.value === value));
|
|
431
|
+
function onKeyDown(e, i) {
|
|
432
|
+
const d = e.key === "ArrowRight" || e.key === "ArrowDown" ? 1 : e.key === "ArrowLeft" || e.key === "ArrowUp" ? -1 : 0;
|
|
433
|
+
if (!d) return;
|
|
434
|
+
e.preventDefault();
|
|
435
|
+
const n = (i + d + options.length) % options.length;
|
|
436
|
+
refs.current[n]?.focus();
|
|
437
|
+
onChange(options[n].value);
|
|
438
|
+
}
|
|
439
|
+
return (
|
|
440
|
+
<div role="radiogroup" aria-labelledby={labelledBy} className="flex flex-wrap gap-1.5">
|
|
441
|
+
{options.map((o, i) => {
|
|
442
|
+
const on = o.value === value;
|
|
443
|
+
const color = swatchVar(o);
|
|
444
|
+
return (
|
|
445
|
+
<Tooltip key={o.value} label={o.label}>
|
|
446
|
+
{/* raw: a colour choice is a swatch you press; the kit's
|
|
447
|
+
ToggleGroup items carry an icon or words, not a colour. */}
|
|
448
|
+
<button
|
|
449
|
+
ref={(el) => {
|
|
450
|
+
refs.current[i] = el;
|
|
451
|
+
}}
|
|
452
|
+
type="button"
|
|
453
|
+
role="radio"
|
|
454
|
+
aria-checked={on}
|
|
455
|
+
aria-label={o.label}
|
|
456
|
+
tabIndex={i === at ? 0 : -1}
|
|
457
|
+
onClick={() => onChange(on ? "" : o.value)}
|
|
458
|
+
onKeyDown={(e) => onKeyDown(e, i)}
|
|
459
|
+
className={cx(
|
|
460
|
+
"grid size-9 place-items-center rounded-md outline-none transition-shadow duration-150 motion-reduce:transition-none",
|
|
461
|
+
"focus-visible:ring-2 focus-visible:ring-ring",
|
|
462
|
+
on ? "ring-2 ring-primary" : "hover:bg-accent",
|
|
463
|
+
)}
|
|
464
|
+
>
|
|
465
|
+
{color ? (
|
|
466
|
+
<Swatch color={color} className="size-6 rounded-full" />
|
|
467
|
+
) : (
|
|
468
|
+
<span aria-hidden="true" className="relative block size-6 overflow-hidden rounded-full border border-border bg-background">
|
|
469
|
+
<span className="absolute left-1/2 top-[-2px] h-[calc(100%+4px)] w-px -translate-x-1/2 rotate-45 bg-muted-foreground" />
|
|
470
|
+
</span>
|
|
471
|
+
)}
|
|
472
|
+
</button>
|
|
473
|
+
</Tooltip>
|
|
474
|
+
);
|
|
475
|
+
})}
|
|
476
|
+
</div>
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// ---- Content fields ---------------------------------------------------------------
|
|
481
|
+
|
|
482
|
+
function LinkFields({ component }) {
|
|
483
|
+
const attrs = component.getAttributes();
|
|
484
|
+
const [href, setHref] = useState(attrs.href ?? "");
|
|
485
|
+
const [blank, setBlank] = useState(attrs.target === "_blank");
|
|
486
|
+
const commit = () => {
|
|
487
|
+
const v = href.trim();
|
|
488
|
+
if (v === (component.getAttributes().href ?? "")) return;
|
|
489
|
+
if (/^\s*javascript:/i.test(v)) {
|
|
490
|
+
toast.error("That link cannot be used", { description: "Use a web address or a path such as /pricing." });
|
|
491
|
+
setHref(component.getAttributes().href ?? "");
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
component.addAttributes({ href: v });
|
|
495
|
+
};
|
|
496
|
+
return (
|
|
497
|
+
<div className="grid gap-3">
|
|
498
|
+
<Field id={`pb-href-${component.cid}`} label="Link" hint="A path like /pricing, or a full web address.">
|
|
499
|
+
<Input
|
|
500
|
+
id={`pb-href-${component.cid}`}
|
|
501
|
+
value={href}
|
|
502
|
+
onChange={(e) => setHref(e.target.value)}
|
|
503
|
+
onBlur={commit}
|
|
504
|
+
onKeyDown={(e) => e.key === "Enter" && commit()}
|
|
505
|
+
placeholder="/signup"
|
|
506
|
+
/>
|
|
507
|
+
</Field>
|
|
508
|
+
<Switch
|
|
509
|
+
id={`pb-blank-${component.cid}`}
|
|
510
|
+
label="Open in a new tab"
|
|
511
|
+
checked={blank}
|
|
512
|
+
onChange={(next) => {
|
|
513
|
+
const on = typeof next === "boolean" ? next : next?.target?.checked;
|
|
514
|
+
setBlank(on);
|
|
515
|
+
if (on) component.addAttributes({ target: "_blank", rel: "noopener" });
|
|
516
|
+
else component.removeAttributes(["target", "rel"]);
|
|
517
|
+
}}
|
|
518
|
+
/>
|
|
519
|
+
</div>
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
function ImageFields({ component, onUploadImage }) {
|
|
524
|
+
const attrs = component.getAttributes();
|
|
525
|
+
const [src, setSrc] = useState(/^data:image\/svg/.test(attrs.src ?? "") ? "" : attrs.src ?? "");
|
|
526
|
+
const [alt, setAlt] = useState(attrs.alt ?? "");
|
|
527
|
+
const [busy, setBusy] = useState(false);
|
|
528
|
+
const commitSrc = (v = src) => {
|
|
529
|
+
const next = v.trim();
|
|
530
|
+
if (!next || /^\s*javascript:/i.test(next)) return;
|
|
531
|
+
component.set("src", next);
|
|
532
|
+
};
|
|
533
|
+
async function upload(files) {
|
|
534
|
+
const file = files?.[0];
|
|
535
|
+
if (!file) return;
|
|
536
|
+
setBusy(true);
|
|
537
|
+
try {
|
|
538
|
+
const res = await onUploadImage(file);
|
|
539
|
+
if (res?.ok && res.url) {
|
|
540
|
+
setSrc(res.url);
|
|
541
|
+
component.set("src", res.url);
|
|
542
|
+
} else {
|
|
543
|
+
toast.error("The picture was not uploaded", { description: res?.error ?? "Try again, or paste an image address instead." });
|
|
544
|
+
}
|
|
545
|
+
} catch {
|
|
546
|
+
toast.error("The picture was not uploaded", { description: "Try again, or paste an image address instead." });
|
|
547
|
+
} finally {
|
|
548
|
+
setBusy(false);
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
return (
|
|
552
|
+
<div className="grid gap-3">
|
|
553
|
+
<Field id={`pb-src-${component.cid}`} label="Picture" hint={onUploadImage ? "Upload one, or paste its address." : "Paste the picture’s address."}>
|
|
554
|
+
<div className="flex gap-2">
|
|
555
|
+
<Input
|
|
556
|
+
id={`pb-src-${component.cid}`}
|
|
557
|
+
value={src}
|
|
558
|
+
onChange={(e) => setSrc(e.target.value)}
|
|
559
|
+
onBlur={() => commitSrc()}
|
|
560
|
+
onKeyDown={(e) => e.key === "Enter" && commitSrc()}
|
|
561
|
+
placeholder="https://…"
|
|
562
|
+
|
|
563
|
+
/>
|
|
564
|
+
{onUploadImage ? (
|
|
565
|
+
<FileInput accept="image/*" onFiles={upload} label="Upload a picture" size="sm" variant="secondary" disabled={busy} />
|
|
566
|
+
) : null}
|
|
567
|
+
</div>
|
|
568
|
+
</Field>
|
|
569
|
+
<Field id={`pb-alt-${component.cid}`} label="Describe the picture" hint="For people using a screen reader. Leave empty if it is decoration.">
|
|
570
|
+
<Input
|
|
571
|
+
id={`pb-alt-${component.cid}`}
|
|
572
|
+
value={alt}
|
|
573
|
+
onChange={(e) => setAlt(e.target.value)}
|
|
574
|
+
onBlur={() => component.addAttributes({ alt: alt.trim() })}
|
|
575
|
+
/>
|
|
576
|
+
</Field>
|
|
577
|
+
</div>
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
/** Keep a stable callback identity for handlers that read fresh props. */
|
|
582
|
+
export function useLatest(value) {
|
|
583
|
+
const ref = useRef(value);
|
|
584
|
+
useEffect(() => {
|
|
585
|
+
ref.current = value;
|
|
586
|
+
});
|
|
587
|
+
return ref;
|
|
588
|
+
}
|