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,252 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// PdfViewer three ways — the gallery's and the smoke test's surface. Not
|
|
4
|
+
// installed into apps. The PDF is not a file shipped with the demo: it is
|
|
5
|
+
// made in the browser, at load, by the pdf-document block (renderPdf), in
|
|
6
|
+
// the workspace's theme — the pair a quote or proposal screen uses.
|
|
7
|
+
// Review a three-page proposal with three highlights (placed by
|
|
8
|
+
// their words alone), notes, saves that can be made to fail
|
|
9
|
+
// Read only the same file in a phone-width frame: no highlighting,
|
|
10
|
+
// the rails as sheets
|
|
11
|
+
// Empty and error no file yet; a file that is not a PDF
|
|
12
|
+
import { useEffect, useMemo, useState } from "react";
|
|
13
|
+
import { Notice, Switch, TabPanel, Tabs } from "../components/ui";
|
|
14
|
+
import { PdfViewer, usePdfViewer } from "../components/blocks/pdf-viewer";
|
|
15
|
+
import {
|
|
16
|
+
PdfCallout,
|
|
17
|
+
PdfCol,
|
|
18
|
+
PdfDivider,
|
|
19
|
+
PdfDocument,
|
|
20
|
+
PdfField,
|
|
21
|
+
PdfHeading,
|
|
22
|
+
PdfLabel,
|
|
23
|
+
PdfLines,
|
|
24
|
+
PdfRow,
|
|
25
|
+
PdfStack,
|
|
26
|
+
PdfTable,
|
|
27
|
+
PdfText,
|
|
28
|
+
PdfTotals,
|
|
29
|
+
formatMoney,
|
|
30
|
+
renderPdf,
|
|
31
|
+
} from "../components/blocks/pdf-document";
|
|
32
|
+
|
|
33
|
+
const wait = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
34
|
+
|
|
35
|
+
// The proposal, written for this demo.
|
|
36
|
+
function Proposal() {
|
|
37
|
+
const phases = [
|
|
38
|
+
{ id: 1, phase: "Discovery", detail: "Interviews with 8 clinicians and 12 patients; analytics review", weeks: "2", fee: 9800 },
|
|
39
|
+
{ id: 2, phase: "Information architecture", detail: "Site map, navigation, content model", weeks: "2", fee: 8400 },
|
|
40
|
+
{ id: 3, phase: "Design", detail: "Design system, 14 key templates, two rounds of revisions", weeks: "5", fee: 26500 },
|
|
41
|
+
{ id: 4, phase: "Build", detail: "Next.js front end on your CMS, accessibility to WCAG 2.2 AA", weeks: "6", fee: 38200 },
|
|
42
|
+
{ id: 5, phase: "Launch and care", detail: "Migration, redirects, training, 30 days of support", weeks: "2", fee: 7600 },
|
|
43
|
+
];
|
|
44
|
+
const total = phases.reduce((s, p) => s + p.fee, 0);
|
|
45
|
+
return (
|
|
46
|
+
<PdfDocument title="Website redesign proposal" author="Northwind Studio" subject="Juniper Health" footer="Northwind Studio · Proposal NW-118 · Confidential">
|
|
47
|
+
<PdfStack gap={4}>
|
|
48
|
+
<PdfLabel>Proposal NW-118 · 18 September 2026</PdfLabel>
|
|
49
|
+
<PdfHeading level={1}>A calmer front door for Juniper Health</PdfHeading>
|
|
50
|
+
<PdfText tone="muted" size="lg" style={{ marginTop: 6 }}>
|
|
51
|
+
Website redesign and patient portal entry points
|
|
52
|
+
</PdfText>
|
|
53
|
+
</PdfStack>
|
|
54
|
+
<PdfDivider space={20} />
|
|
55
|
+
<PdfRow gap={24}>
|
|
56
|
+
<PdfCol>
|
|
57
|
+
<PdfLabel>Prepared for</PdfLabel>
|
|
58
|
+
<PdfLines lines={["Priya Raman", "Head of Digital, Juniper Health", "400 Market Street, San Francisco"]} />
|
|
59
|
+
</PdfCol>
|
|
60
|
+
<PdfCol>
|
|
61
|
+
<PdfLabel>Prepared by</PdfLabel>
|
|
62
|
+
<PdfLines lines={["Maya Chen", "Partner, Northwind Studio", "maya@northwind.studio"]} />
|
|
63
|
+
</PdfCol>
|
|
64
|
+
<PdfCol flex={0.8}>
|
|
65
|
+
<PdfField label="Valid until">16 October 2026</PdfField>
|
|
66
|
+
</PdfCol>
|
|
67
|
+
</PdfRow>
|
|
68
|
+
|
|
69
|
+
<PdfStack gap={8} style={{ marginTop: 28 }}>
|
|
70
|
+
<PdfHeading level={2}>Summary</PdfHeading>
|
|
71
|
+
<PdfText>
|
|
72
|
+
Juniper's site has grown one page at a time for nine years. Patients now reach the patient portal through four different doors, and half of all calls to the front desk ask where to find a form that is already online.
|
|
73
|
+
</PdfText>
|
|
74
|
+
<PdfText>
|
|
75
|
+
We propose a focused redesign over seventeen weeks: fewer pages, one clear way into the portal, and a design system your team can extend without us. The work is fixed-fee, in five phases, each ending in a review with your team.
|
|
76
|
+
</PdfText>
|
|
77
|
+
</PdfStack>
|
|
78
|
+
|
|
79
|
+
<PdfStack gap={8} style={{ marginTop: 20 }}>
|
|
80
|
+
<PdfHeading level={2}>What we heard</PdfHeading>
|
|
81
|
+
<PdfLines
|
|
82
|
+
first={false}
|
|
83
|
+
muted={false}
|
|
84
|
+
lines={[
|
|
85
|
+
"• Patients cannot tell which location a page is about.",
|
|
86
|
+
"• Booking starts on the site but ends on the phone.",
|
|
87
|
+
"• Clinicians want to update their own profiles.",
|
|
88
|
+
"• The portal login is buried three levels deep.",
|
|
89
|
+
]}
|
|
90
|
+
/>
|
|
91
|
+
</PdfStack>
|
|
92
|
+
|
|
93
|
+
<PdfStack gap={10} break>
|
|
94
|
+
<PdfHeading level={2}>Scope and timeline</PdfHeading>
|
|
95
|
+
<PdfText tone="muted">Five phases, seventeen weeks, starting the week of 5 October 2026.</PdfText>
|
|
96
|
+
<PdfTable
|
|
97
|
+
style={{ marginTop: 6 }}
|
|
98
|
+
columns={[
|
|
99
|
+
{ key: "phase", label: "Phase", flex: 3 },
|
|
100
|
+
{ key: "weeks", label: "Weeks", width: 52, align: "right" },
|
|
101
|
+
{ key: "fee", label: "Fee", width: 84, align: "right", render: (r) => formatMoney(r.fee) },
|
|
102
|
+
]}
|
|
103
|
+
rows={phases}
|
|
104
|
+
/>
|
|
105
|
+
<PdfTotals rows={[{ label: "Fixed fee", value: formatMoney(total), strong: true }]} />
|
|
106
|
+
<PdfCallout title="What is not included">
|
|
107
|
+
Photography, copywriting beyond the fourteen templates, and changes to the portal itself. We are glad to quote for any of these separately.
|
|
108
|
+
</PdfCallout>
|
|
109
|
+
</PdfStack>
|
|
110
|
+
|
|
111
|
+
<PdfStack gap={8} break>
|
|
112
|
+
<PdfHeading level={2}>Terms</PdfHeading>
|
|
113
|
+
<PdfText>
|
|
114
|
+
Invoices are sent at the start of each phase and are due within 14 days. The design phase includes two rounds of revisions per template; further rounds are billed at the day rate of $1,400.
|
|
115
|
+
</PdfText>
|
|
116
|
+
<PdfText>
|
|
117
|
+
After launch, the care plan renews each year. Fees rise by 4% at each annual renewal unless either side gives 60 days' notice.
|
|
118
|
+
</PdfText>
|
|
119
|
+
<PdfText>Either party may end the agreement with 30 days' written notice; work completed up to that date is paid in full.</PdfText>
|
|
120
|
+
<PdfDivider space={24} />
|
|
121
|
+
<PdfRow gap={32}>
|
|
122
|
+
<PdfCol>
|
|
123
|
+
<PdfLabel>For Northwind Studio</PdfLabel>
|
|
124
|
+
<PdfText bold>Maya Chen, Partner</PdfText>
|
|
125
|
+
</PdfCol>
|
|
126
|
+
<PdfCol>
|
|
127
|
+
<PdfLabel>For Juniper Health</PdfLabel>
|
|
128
|
+
<PdfText tone="muted">Name, title and date</PdfText>
|
|
129
|
+
</PdfCol>
|
|
130
|
+
</PdfRow>
|
|
131
|
+
</PdfStack>
|
|
132
|
+
</PdfDocument>
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Highlights given by their words only: the viewer finds where they sit.
|
|
137
|
+
const REVIEW_NOTES = [
|
|
138
|
+
{ id: "hl-1", text: "Fees rise by 4% at each annual renewal", note: "Ask for a 3% cap, like last year's contract.", tone: "warning", author: "Priya Raman", createdAt: "2026-09-21" },
|
|
139
|
+
{ id: "hl-2", text: "one clear way into the portal", note: "", tone: "info", author: "Leo Park", createdAt: "2026-09-22" },
|
|
140
|
+
{ id: "hl-3", text: "two rounds of revisions per template", note: "Matches what legal asked for.", tone: "success", author: "Priya Raman", createdAt: "2026-09-22" },
|
|
141
|
+
];
|
|
142
|
+
|
|
143
|
+
const FIRST_NOTE = REVIEW_NOTES.slice(0, 1);
|
|
144
|
+
|
|
145
|
+
function useProposal() {
|
|
146
|
+
const [blob, setBlob] = useState(null);
|
|
147
|
+
const [error, setError] = useState(null);
|
|
148
|
+
useEffect(() => {
|
|
149
|
+
let live = true;
|
|
150
|
+
renderPdf(<Proposal />)
|
|
151
|
+
.then((b) => live && setBlob(b))
|
|
152
|
+
.catch((e) => live && setError(e));
|
|
153
|
+
return () => {
|
|
154
|
+
live = false;
|
|
155
|
+
};
|
|
156
|
+
}, []);
|
|
157
|
+
return { blob, error };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function ReviewDemo({ blob }) {
|
|
161
|
+
const [highlights, setHighlights] = useState(REVIEW_NOTES);
|
|
162
|
+
const [fail, setFail] = useState(false);
|
|
163
|
+
const [page, setPage] = useState(1);
|
|
164
|
+
const viewer = usePdfViewer();
|
|
165
|
+
const failed = { ok: false, error: "The server didn't answer (the demo's switch is on)." };
|
|
166
|
+
return (
|
|
167
|
+
<div className="grid gap-3">
|
|
168
|
+
<div className="flex flex-wrap items-center justify-between gap-x-6 gap-y-1">
|
|
169
|
+
<p className="text-sm text-muted-foreground">
|
|
170
|
+
Select any sentence to highlight it or add a note. <span className="tabular-nums">Page {page}.</span>
|
|
171
|
+
</p>
|
|
172
|
+
<Switch id="pdf-fail" label="Make saves fail" checked={fail} onChange={(e) => setFail(e.target.checked)} />
|
|
173
|
+
</div>
|
|
174
|
+
<PdfViewer
|
|
175
|
+
file={blob}
|
|
176
|
+
loading={!blob}
|
|
177
|
+
title="Website redesign proposal — Juniper Health"
|
|
178
|
+
fileName="northwind-proposal-nw-118.pdf"
|
|
179
|
+
viewerRef={viewer}
|
|
180
|
+
highlights={highlights}
|
|
181
|
+
onPageChange={setPage}
|
|
182
|
+
onHighlight={async (h) => {
|
|
183
|
+
await wait(450);
|
|
184
|
+
if (fail) return failed;
|
|
185
|
+
const id = `hl-${Date.now()}`;
|
|
186
|
+
setHighlights((list) => [...list, { ...h, id, author: "You", createdAt: new Date().toISOString() }]);
|
|
187
|
+
return { ok: true, id };
|
|
188
|
+
}}
|
|
189
|
+
onHighlightChange={async (id, patch) => {
|
|
190
|
+
await wait(350);
|
|
191
|
+
if (fail) return failed;
|
|
192
|
+
setHighlights((list) => list.map((x) => (x.id === id ? { ...x, ...patch } : x)));
|
|
193
|
+
return { ok: true };
|
|
194
|
+
}}
|
|
195
|
+
onHighlightDelete={async (id) => {
|
|
196
|
+
await wait(300);
|
|
197
|
+
if (fail) return failed;
|
|
198
|
+
setHighlights((list) => list.filter((x) => x.id !== id));
|
|
199
|
+
return { ok: true };
|
|
200
|
+
}}
|
|
201
|
+
/>
|
|
202
|
+
</div>
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function ReadOnlyDemo({ blob }) {
|
|
207
|
+
return (
|
|
208
|
+
<div className="grid gap-3">
|
|
209
|
+
<p className="text-sm text-muted-foreground">No onHighlight: a reader. In a phone-width frame the pages and highlights open as sheets.</p>
|
|
210
|
+
<div className="mx-auto w-full max-w-[390px]">
|
|
211
|
+
<PdfViewer file={blob} loading={!blob} title="Website redesign proposal" highlights={FIRST_NOTE} height="720px" />
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function StatesDemo() {
|
|
218
|
+
const broken = useMemo(() => new Blob(["This is a note, not a PDF."], { type: "application/pdf" }), []);
|
|
219
|
+
return (
|
|
220
|
+
<div className="grid gap-4 lg:grid-cols-2">
|
|
221
|
+
<PdfViewer file={null} title="Signed agreement" height="420px" emptyTitle="No signed copy yet" emptyBody="When Juniper signs, their copy of the agreement shows here." />
|
|
222
|
+
<PdfViewer file={broken} title="statement-august.pdf" height="420px" />
|
|
223
|
+
</div>
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export default function PdfViewerDemo() {
|
|
228
|
+
const [tab, setTab] = useState("review");
|
|
229
|
+
const { blob, error } = useProposal();
|
|
230
|
+
return (
|
|
231
|
+
<div className="grid gap-4">
|
|
232
|
+
<Tabs
|
|
233
|
+
aria-label="PdfViewer variants"
|
|
234
|
+
value={tab}
|
|
235
|
+
onChange={setTab}
|
|
236
|
+
tabs={[
|
|
237
|
+
{ key: "review", label: "Review" },
|
|
238
|
+
{ key: "read", label: "Read only" },
|
|
239
|
+
{ key: "states", label: "Empty and error" },
|
|
240
|
+
]}
|
|
241
|
+
/>
|
|
242
|
+
{error ? (
|
|
243
|
+
<Notice tone="danger" title="The sample PDF couldn't be made">
|
|
244
|
+
{String(error.message ?? error)}
|
|
245
|
+
</Notice>
|
|
246
|
+
) : null}
|
|
247
|
+
<TabPanel tab={tab} value={tab}>
|
|
248
|
+
{tab === "review" ? <ReviewDemo blob={blob} /> : tab === "read" ? <ReadOnlyDemo blob={blob} /> : <StatesDemo />}
|
|
249
|
+
</TabPanel>
|
|
250
|
+
</div>
|
|
251
|
+
);
|
|
252
|
+
}
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
// The viewer's plain maths — search, page geometry, highlight rectangles.
|
|
2
|
+
// No DOM and no pdf.js here, so all of it runs in node (and is tested
|
|
3
|
+
// there) and on the server.
|
|
4
|
+
|
|
5
|
+
// ---- search -----------------------------------------------------------------
|
|
6
|
+
|
|
7
|
+
const fold = (s) => String(s ?? "").toLocaleLowerCase();
|
|
8
|
+
|
|
9
|
+
/** Every match of `query` in the pages' text, in reading order.
|
|
10
|
+
*
|
|
11
|
+
* pages [[str, str, …], …] — each page's text items as pdf.js gives
|
|
12
|
+
* them (getTextContent().items[].str), page 1 first
|
|
13
|
+
* query the text looked for, case-insensitive; under 2 characters
|
|
14
|
+
* finds nothing (a single letter matches everywhere)
|
|
15
|
+
*
|
|
16
|
+
* → [{ page (1-based), item, start, length }]. A match inside one text
|
|
17
|
+
* item only: pdf.js splits lines into items, and a phrase broken across
|
|
18
|
+
* two lines is not found (the same as most viewers' quick find). */
|
|
19
|
+
export function findMatches(pages, query) {
|
|
20
|
+
const q = fold(query).trim();
|
|
21
|
+
if (q.length < 2) return [];
|
|
22
|
+
const out = [];
|
|
23
|
+
(pages ?? []).forEach((items, p) => {
|
|
24
|
+
(items ?? []).forEach((str, item) => {
|
|
25
|
+
const s = fold(str);
|
|
26
|
+
let at = s.indexOf(q);
|
|
27
|
+
while (at !== -1) {
|
|
28
|
+
out.push({ page: p + 1, item, start: at, length: q.length });
|
|
29
|
+
at = s.indexOf(q, at + q.length);
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const ESCAPES = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
37
|
+
export const escapeHtml = (s) => String(s ?? "").replace(/[&<>"']/g, (c) => ESCAPES[c]);
|
|
38
|
+
|
|
39
|
+
/** One text item's HTML with its matches wrapped in <mark>: the text
|
|
40
|
+
* layer's custom renderer. `current` is the start offset of the match
|
|
41
|
+
* that is selected in this item (or -1); it gets `currentClass` and
|
|
42
|
+
* data-current, the others `markClass`. Everything else is escaped. */
|
|
43
|
+
export function markItem(str, matches, { current = -1, markClass = "", currentClass = "" } = {}) {
|
|
44
|
+
if (!matches?.length) return escapeHtml(str);
|
|
45
|
+
let html = "";
|
|
46
|
+
let at = 0;
|
|
47
|
+
for (const m of [...matches].sort((a, b) => a.start - b.start)) {
|
|
48
|
+
if (m.start < at) continue;
|
|
49
|
+
html += escapeHtml(str.slice(at, m.start));
|
|
50
|
+
const cur = m.start === current;
|
|
51
|
+
html += `<mark class="${cur ? currentClass : markClass}"${cur ? ' data-current="true"' : ""}>${escapeHtml(str.slice(m.start, m.start + m.length))}</mark>`;
|
|
52
|
+
at = m.start + m.length;
|
|
53
|
+
}
|
|
54
|
+
return html + escapeHtml(str.slice(at));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Matches grouped for fast lookup while rendering: "page:item" → [match]. */
|
|
58
|
+
export function indexMatches(matches) {
|
|
59
|
+
const map = new Map();
|
|
60
|
+
for (const m of matches ?? []) {
|
|
61
|
+
const k = `${m.page}:${m.item}`;
|
|
62
|
+
if (!map.has(k)) map.set(k, []);
|
|
63
|
+
map.get(k).push(m);
|
|
64
|
+
}
|
|
65
|
+
return map;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** A short excerpt around a match, for a result line: "…the renewal fee of…". */
|
|
69
|
+
export function excerpt(str, start, length, room = 28) {
|
|
70
|
+
const s = String(str ?? "");
|
|
71
|
+
const a = Math.max(0, start - room);
|
|
72
|
+
const b = Math.min(s.length, start + length + room);
|
|
73
|
+
return `${a > 0 ? "…" : ""}${s.slice(a, b).trim()}${b < s.length ? "…" : ""}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ---- pages and zoom ---------------------------------------------------------
|
|
77
|
+
|
|
78
|
+
/** The zoom steps the − and + buttons walk. */
|
|
79
|
+
export const ZOOM_STEPS = [0.5, 0.67, 0.75, 0.9, 1, 1.1, 1.25, 1.5, 1.75, 2, 2.5, 3, 4];
|
|
80
|
+
export const MIN_ZOOM = ZOOM_STEPS[0];
|
|
81
|
+
export const MAX_ZOOM = ZOOM_STEPS[ZOOM_STEPS.length - 1];
|
|
82
|
+
|
|
83
|
+
/** The next zoom step past `scale` in `dir` (+1 in, -1 out). */
|
|
84
|
+
export function stepZoom(scale, dir) {
|
|
85
|
+
if (dir > 0) return ZOOM_STEPS.find((z) => z > scale + 0.001) ?? MAX_ZOOM;
|
|
86
|
+
return [...ZOOM_STEPS].reverse().find((z) => z < scale - 0.001) ?? MIN_ZOOM;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export const clampZoom = (z) => Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, Number(z) || 1));
|
|
90
|
+
|
|
91
|
+
/** The scale at which the widest page fills `width` (px) — "fit width" —
|
|
92
|
+
* or, with `height`, at which the tallest fits both ways — "fit page". */
|
|
93
|
+
export function fitScale(sizes, width, height) {
|
|
94
|
+
if (!sizes?.length || !(width > 0)) return 1;
|
|
95
|
+
const w = Math.max(...sizes.map((s) => s.width));
|
|
96
|
+
let z = width / w;
|
|
97
|
+
if (height > 0) z = Math.min(z, height / Math.max(...sizes.map((s) => s.height)));
|
|
98
|
+
return clampZoom(Math.round(z * 1000) / 1000);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Where each page starts in the scrolling column: the page sizes at
|
|
102
|
+
* scale 1, times `scale`, with `gap` px between and `pad` px above the
|
|
103
|
+
* first. → { tops: [px], heights: [px], total } */
|
|
104
|
+
export function layoutPages(sizes, scale, gap = 16, pad = 16) {
|
|
105
|
+
const tops = [];
|
|
106
|
+
const heights = [];
|
|
107
|
+
let y = pad;
|
|
108
|
+
for (const s of sizes ?? []) {
|
|
109
|
+
tops.push(y);
|
|
110
|
+
const h = Math.round(s.height * scale);
|
|
111
|
+
heights.push(h);
|
|
112
|
+
y += h + gap;
|
|
113
|
+
}
|
|
114
|
+
return { tops, heights, total: y - gap + pad };
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** The page (1-based) shown at `y` px down the column: the last page
|
|
118
|
+
* whose top is at or above it. */
|
|
119
|
+
export function pageAt(tops, y) {
|
|
120
|
+
if (!tops?.length) return 1;
|
|
121
|
+
let lo = 0;
|
|
122
|
+
let hi = tops.length - 1;
|
|
123
|
+
while (lo < hi) {
|
|
124
|
+
const mid = (lo + hi + 1) >> 1;
|
|
125
|
+
if (tops[mid] <= y) lo = mid;
|
|
126
|
+
else hi = mid - 1;
|
|
127
|
+
}
|
|
128
|
+
return lo + 1;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The pages (1-based, inclusive) that touch the window [top, bottom],
|
|
132
|
+
* widened by `overscan` pages each way: the ones worth drawing. */
|
|
133
|
+
export function visiblePages(layout, top, bottom, overscan = 1) {
|
|
134
|
+
const n = layout?.tops?.length ?? 0;
|
|
135
|
+
if (!n) return [1, 0];
|
|
136
|
+
const first = pageAt(layout.tops, top);
|
|
137
|
+
const last = pageAt(layout.tops, bottom);
|
|
138
|
+
return [Math.max(1, first - overscan), Math.min(n, last + overscan)];
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Where a page is, as a share of the way down it (0…1) at `y`: kept
|
|
142
|
+
* across a zoom so the same line stays in view. */
|
|
143
|
+
export function anchorAt(layout, y) {
|
|
144
|
+
const page = pageAt(layout.tops, y);
|
|
145
|
+
const top = layout.tops[page - 1] ?? 0;
|
|
146
|
+
const h = layout.heights[page - 1] || 1;
|
|
147
|
+
return { page, frac: Math.min(1, Math.max(0, (y - top) / h)) };
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ---- highlights -------------------------------------------------------------
|
|
151
|
+
|
|
152
|
+
/** The screen rectangles of a text selection → the highlight's rectangles
|
|
153
|
+
* on its page: fractions of the page's box (0…1), so they hold at any
|
|
154
|
+
* zoom. Rectangles outside the page are dropped; slivers (a line end,
|
|
155
|
+
* a space) are dropped; rectangles on the same line are merged.
|
|
156
|
+
*
|
|
157
|
+
* rects [{ left, top, width, height }] — client rects of the range
|
|
158
|
+
* box { left, top, width, height } — the page's client rect */
|
|
159
|
+
export function toPageRects(rects, box) {
|
|
160
|
+
if (!box?.width || !box?.height) return [];
|
|
161
|
+
const out = [];
|
|
162
|
+
for (const r of rects ?? []) {
|
|
163
|
+
const left = Math.max(r.left, box.left);
|
|
164
|
+
const right = Math.min(r.left + r.width, box.left + box.width);
|
|
165
|
+
const top = Math.max(r.top, box.top);
|
|
166
|
+
const bottom = Math.min(r.top + r.height, box.top + box.height);
|
|
167
|
+
if (right - left < 1 || bottom - top < 2) continue;
|
|
168
|
+
out.push({ x: (left - box.left) / box.width, y: (top - box.top) / box.height, w: (right - left) / box.width, h: (bottom - top) / box.height });
|
|
169
|
+
}
|
|
170
|
+
return mergeRects(out);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Merge rectangles on the same line (their vertical middles within half
|
|
174
|
+
* a line of each other) that touch or nearly touch; sorted top to
|
|
175
|
+
* bottom, left to right. Numbers are rounded to 5 places (plenty for a
|
|
176
|
+
* page, and a saved highlight stays small). */
|
|
177
|
+
export function mergeRects(rects, gap = 0.01) {
|
|
178
|
+
const sorted = [...(rects ?? [])].filter((r) => r.w > 0 && r.h > 0).sort((a, b) => a.y + a.h / 2 - (b.y + b.h / 2) || a.x - b.x);
|
|
179
|
+
const out = [];
|
|
180
|
+
for (const r of sorted) {
|
|
181
|
+
const last = out[out.length - 1];
|
|
182
|
+
const sameLine = last && Math.abs(last.y + last.h / 2 - (r.y + r.h / 2)) < Math.min(last.h, r.h) / 2;
|
|
183
|
+
if (sameLine && r.x <= last.x + last.w + gap) {
|
|
184
|
+
const x = Math.min(last.x, r.x);
|
|
185
|
+
const y = Math.min(last.y, r.y);
|
|
186
|
+
last.w = Math.max(last.x + last.w, r.x + r.w) - x;
|
|
187
|
+
last.h = Math.max(last.y + last.h, r.y + r.h) - y;
|
|
188
|
+
last.x = x;
|
|
189
|
+
last.y = y;
|
|
190
|
+
} else out.push({ ...r });
|
|
191
|
+
}
|
|
192
|
+
const r5 = (n) => Math.round(n * 1e5) / 1e5;
|
|
193
|
+
return out
|
|
194
|
+
.map((r) => ({ x: r5(r.x), y: r5(r.y), w: r5(r.w), h: r5(r.h) }))
|
|
195
|
+
.sort((a, b) => a.y - b.y || a.x - b.x);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** Is the point (fractions of the page) inside any of the rectangles? */
|
|
199
|
+
export const hitRects = (rects, px, py) => (rects ?? []).some((r) => px >= r.x && px <= r.x + r.w && py >= r.y && py <= r.y + r.h);
|
|
200
|
+
|
|
201
|
+
/** The highlight under a point on a page, the newest first. */
|
|
202
|
+
export function highlightAt(highlights, page, px, py) {
|
|
203
|
+
for (let i = (highlights ?? []).length - 1; i >= 0; i--) {
|
|
204
|
+
const h = highlights[i];
|
|
205
|
+
if (h.page === page && hitRects(h.rects, px, py)) return h;
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/** Highlights sorted as they read: by page, then top to bottom. */
|
|
211
|
+
export function sortHighlights(highlights) {
|
|
212
|
+
const top = (h) => Math.min(...(h.rects?.length ? h.rects.map((r) => r.y) : [0]));
|
|
213
|
+
const page = (h) => h.page || Infinity;
|
|
214
|
+
return [...(highlights ?? [])].sort((a, b) => page(a) - page(b) || top(a) - top(b));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** A text item from pdf.js (getTextContent().items[i]) → its place on
|
|
218
|
+
* the page in PDF units: { str, x, y (the baseline, from the bottom), w,
|
|
219
|
+
* h (the font size) }. */
|
|
220
|
+
export function itemBox(item) {
|
|
221
|
+
const t = item?.transform ?? [1, 0, 0, 1, 0, 0];
|
|
222
|
+
return { str: item?.str ?? "", x: t[4], y: t[5], w: item?.width ?? 0, h: item?.height || Math.hypot(t[2], t[3]) || 0 };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const escapeRe = (s) => s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
226
|
+
|
|
227
|
+
/** Where a quote sits on a page: the rectangles (fractions of the page) of
|
|
228
|
+
* the first place `quote` appears in its text, case-insensitive, across
|
|
229
|
+
* line breaks. How a highlight given only by its words ({ page?, text })
|
|
230
|
+
* finds its place — an agent can flag a clause without any geometry.
|
|
231
|
+
*
|
|
232
|
+
* items the page's items as itemBox gives them
|
|
233
|
+
* size the page's { width, height } in PDF units (its viewport at 1)
|
|
234
|
+
*
|
|
235
|
+
* Within an item the x of a partial match is shared out by characters —
|
|
236
|
+
* close for body text, not exact for a proportional face. Unrotated
|
|
237
|
+
* pages only. → [] when the words are not on the page. */
|
|
238
|
+
export function rectsForQuote(items, quote, size) {
|
|
239
|
+
const q = String(quote ?? "").replace(/\s+/g, " ").trim();
|
|
240
|
+
if (q.length < 2 || !size?.width || !size?.height) return [];
|
|
241
|
+
let joined = "";
|
|
242
|
+
const spans = [];
|
|
243
|
+
(items ?? []).forEach((it, i) => {
|
|
244
|
+
if (!it?.str) return;
|
|
245
|
+
if (joined && !/\s$/.test(joined)) joined += " ";
|
|
246
|
+
spans.push({ i, from: joined.length, to: joined.length + it.str.length });
|
|
247
|
+
joined += it.str;
|
|
248
|
+
});
|
|
249
|
+
const m = new RegExp(escapeRe(q).replace(/ /g, "\\s+"), "i").exec(joined);
|
|
250
|
+
if (!m) return [];
|
|
251
|
+
const a = m.index;
|
|
252
|
+
const b = a + m[0].length;
|
|
253
|
+
const rects = [];
|
|
254
|
+
for (const sp of spans) {
|
|
255
|
+
if (sp.to <= a || sp.from >= b) continue;
|
|
256
|
+
const it = items[sp.i];
|
|
257
|
+
const len = it.str.length || 1;
|
|
258
|
+
const s0 = Math.max(a, sp.from) - sp.from;
|
|
259
|
+
const s1 = Math.min(b, sp.to) - sp.from;
|
|
260
|
+
const x = it.x + (it.w * s0) / len;
|
|
261
|
+
const w = (it.w * (s1 - s0)) / len;
|
|
262
|
+
const top = it.y + it.h * 0.9;
|
|
263
|
+
const bottom = it.y - it.h * 0.25;
|
|
264
|
+
rects.push({ x: x / size.width, y: 1 - top / size.height, w: w / size.width, h: (top - bottom) / size.height });
|
|
265
|
+
}
|
|
266
|
+
return mergeRects(rects);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/** "Page 3". */
|
|
270
|
+
export const pageLabel = (n) => `Page ${n}`;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// The PdfViewer block — `makersclaw add pdf-viewer`. Fixed: compose it
|
|
2
|
+
// through its props (README.md beside this file). The helpers (search,
|
|
3
|
+
// page geometry, highlight rectangles) run anywhere, the server included;
|
|
4
|
+
// the blocks built on this one (proposal-accept, contract review…) import
|
|
5
|
+
// it, never react-pdf or pdfjs-dist directly.
|
|
6
|
+
export { PdfViewer, usePdfViewer } from "./pdf-viewer";
|
|
7
|
+
export { HIGHLIGHT_TONES } from "./notes";
|
|
8
|
+
export { findMatches, toPageRects, mergeRects, sortHighlights, highlightAt, fitScale, ZOOM_STEPS } from "./helpers";
|