@agent-native/core 0.92.10 → 0.92.12
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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +29 -0
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/agent/production-agent.ts +214 -17
- package/corpus/core/src/agent/run-manager.ts +72 -14
- package/corpus/core/src/agent/run-store.ts +152 -27
- package/corpus/core/src/cli/design-connect.ts +433 -151
- package/corpus/core/src/cli/skills.ts +14 -0
- package/corpus/core/src/client/AssistantChat.tsx +25 -0
- package/corpus/core/src/client/MultiTabAssistantChat.tsx +40 -6
- package/corpus/core/src/client/agent-chat-adapter.ts +56 -12
- package/corpus/core/src/client/agent-chat.ts +165 -1
- package/corpus/core/src/client/chat/index.ts +9 -1
- package/corpus/core/src/client/extensions/EmbeddedExtension.tsx +38 -2
- package/corpus/core/src/client/index.ts +5 -0
- package/corpus/core/src/client/rich-markdown-editor/useCollabReconcile.ts +18 -7
- package/corpus/core/src/collab/awareness-store.ts +23 -12
- package/corpus/core/src/collab/client.ts +16 -5
- package/corpus/core/src/collab/index.ts +4 -0
- package/corpus/core/src/collab/recent-edits.ts +65 -2
- package/corpus/core/src/index.browser.ts +1 -0
- package/corpus/core/src/server/agent-chat-plugin.ts +98 -11
- package/corpus/core/src/server/builder-design-systems.ts +30 -4
- package/corpus/templates/clips/.agents/skills/ai-video-tools/SKILL.md +1 -1
- package/corpus/templates/clips/.agents/skills/video-sharing/SKILL.md +12 -6
- package/corpus/templates/clips/AGENTS.md +4 -0
- package/corpus/templates/clips/actions/create-recording.ts +2 -0
- package/corpus/templates/clips/actions/lib/create-recording-schema.ts +5 -3
- package/corpus/templates/clips/actions/request-transcript.ts +102 -33
- package/corpus/templates/clips/app/components/library/library-grid.tsx +1 -0
- package/corpus/templates/clips/app/components/player/share-dialog.tsx +59 -19
- package/corpus/templates/clips/app/components/player/transcript-panel.tsx +75 -9
- package/corpus/templates/clips/app/components/player/video-player.tsx +17 -12
- package/corpus/templates/clips/app/hooks/use-player-shortcuts.ts +1 -0
- package/corpus/templates/clips/app/i18n/ar-SA.ts +1 -0
- package/corpus/templates/clips/app/i18n/de-DE.ts +1 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +1 -0
- package/corpus/templates/clips/app/i18n/es-ES.ts +1 -0
- package/corpus/templates/clips/app/i18n/fr-FR.ts +1 -0
- package/corpus/templates/clips/app/i18n/hi-IN.ts +1 -0
- package/corpus/templates/clips/app/i18n/ja-JP.ts +1 -0
- package/corpus/templates/clips/app/i18n/ko-KR.ts +1 -0
- package/corpus/templates/clips/app/i18n/pt-BR.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-CN.ts +1 -0
- package/corpus/templates/clips/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +70 -37
- package/corpus/templates/clips/app/routes/record.tsx +17 -4
- package/corpus/templates/clips/app/routes/share.$shareId.tsx +2 -0
- package/corpus/templates/clips/changelog/2026-07-09-desktop-popover-sits-closer-to-the-menu-bar.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-desktop-recording-optimization-progress-stays-visible-until-the-clip-opens.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-fixed-large-video-file-uploads-failing-before-their-resumabl.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-fixed-new-video-uploads-defaulting-to-private.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-long-recordings-now-get-enough-time-to-download-their-media-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-meeting-notes-no-longer-lowers-your-microphone-volume-for-ot.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-on-mobile-tapping-a-playing-clip-reveals-playback-controls-w.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-regenerate-any-clip-transcript-from-its-saved-recording-or-r.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-09-slack-previews-now-show-the-clip-length-alongside-its-descri.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-10-fixed-copying-agent-responses-and-transcript-text-from-recor.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +12 -2
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +8 -1
- package/corpus/templates/clips/desktop/src/lib/recorder.ts +8 -5
- package/corpus/templates/clips/desktop/src/lib/transcription-engine.ts +5 -5
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +3 -0
- package/corpus/templates/clips/desktop/src/styles.css +6 -3
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +29 -11
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen.rs +1 -1
- package/corpus/templates/clips/desktop/src-tauri/src/system_audio.rs +103 -21
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +117 -39
- package/corpus/templates/clips/server/lib/slack-unfurls.ts +20 -1
- package/corpus/templates/clips/server/lib/streaming-upload-mode.ts +10 -4
- package/corpus/templates/clips/shared/recording-core.ts +12 -0
- package/corpus/templates/content/AGENTS.md +7 -6
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +82 -7
- package/corpus/templates/content/actions/_database-source-utils.ts +149 -30
- package/corpus/templates/content/actions/_document-flush.ts +132 -17
- package/corpus/templates/content/actions/_notion-action-utils.ts +15 -0
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +4 -7
- package/corpus/templates/content/actions/attach-content-database-source.ts +41 -17
- package/corpus/templates/content/actions/change-content-database-source-role.ts +46 -8
- package/corpus/templates/content/actions/create-and-link-notion-page.ts +2 -0
- package/corpus/templates/content/actions/link-notion-page.ts +2 -0
- package/corpus/templates/content/actions/pull-document.ts +5 -7
- package/corpus/templates/content/actions/pull-notion-page.ts +2 -0
- package/corpus/templates/content/actions/push-notion-page.ts +10 -0
- package/corpus/templates/content/actions/resolve-notion-sync-conflict.ts +2 -0
- package/corpus/templates/content/actions/suggest-source-join-key.ts +8 -1
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +88 -23
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +32 -2
- package/corpus/templates/content/app/hooks/use-notion.ts +6 -6
- package/corpus/templates/content/app/i18n/zh-TW.ts +1 -0
- package/corpus/templates/content/app/i18n-data.ts +18 -0
- package/corpus/templates/content/changelog/2026-07-09-builder-source-refreshes-now-keep-mapped-fields-such-as-topi.md +6 -0
- package/corpus/templates/content/changelog/2026-07-09-notion-conflict-choices-and-version-restores-preserve-docume.md +6 -0
- package/corpus/templates/content/server/lib/notion-sync.ts +80 -64
- package/corpus/templates/content/shared/api.ts +1 -0
- package/corpus/templates/design/.agents/skills/design-generation/SKILL.md +29 -2
- package/corpus/templates/design/.agents/skills/design-systems/SKILL.md +86 -0
- package/corpus/templates/design/.agents/skills/export-handoff/SKILL.md +57 -0
- package/corpus/templates/design/.agents/skills/visual-edit/SKILL.md +11 -0
- package/corpus/templates/design/AGENTS.md +45 -10
- package/corpus/templates/design/actions/add-localhost-screens.ts +66 -13
- package/corpus/templates/design/actions/apply-component-prop-edit.ts +45 -36
- package/corpus/templates/design/actions/apply-motion-edit.ts +25 -31
- package/corpus/templates/design/actions/apply-shader-fill.ts +29 -42
- package/corpus/templates/design/actions/detach-component-instance.ts +337 -0
- package/corpus/templates/design/actions/export-design-as-figma-svg.ts +219 -0
- package/corpus/templates/design/actions/generate-design.ts +79 -12
- package/corpus/templates/design/actions/generate-screens.ts +57 -12
- package/corpus/templates/design/actions/get-figma-styles.ts +115 -0
- package/corpus/templates/design/actions/go-to-main-component.ts +254 -0
- package/corpus/templates/design/actions/grant-localhost-write-consent.ts +4 -3
- package/corpus/templates/design/actions/import-design-source.ts +4 -31
- package/corpus/templates/design/actions/import-figma-clipboard.ts +134 -0
- package/corpus/templates/design/actions/import-figma-frame.ts +95 -0
- package/corpus/templates/design/actions/index-design-system-with-builder.ts +16 -1
- package/corpus/templates/design/actions/list-design-components.ts +104 -0
- package/corpus/templates/design/actions/list-figma-library-assets.ts +1 -24
- package/corpus/templates/design/actions/open-component-source.ts +2 -4
- package/corpus/templates/design/actions/present-design-variants.ts +412 -16
- package/corpus/templates/design/actions/preview-source-edit.ts +14 -1
- package/corpus/templates/design/actions/run-design-audit.ts +25 -3
- package/corpus/templates/design/actions/show-design-questions.ts +10 -0
- package/corpus/templates/design/actions/swap-component-instance.ts +544 -0
- package/corpus/templates/design/actions/take-design-screenshot.ts +45 -60
- package/corpus/templates/design/actions/write-local-file.ts +25 -1
- package/corpus/templates/design/app/components/design/CanvasContextMenu.tsx +152 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +1077 -58
- package/corpus/templates/design/app/components/design/DesignEditorSkeleton.tsx +5 -5
- package/corpus/templates/design/app/components/design/DesignExtensionsPanel.tsx +73 -21
- package/corpus/templates/design/app/components/design/EditPanel.tsx +16 -11
- package/corpus/templates/design/app/components/design/KeyboardShortcutsPanel.tsx +364 -0
- package/corpus/templates/design/app/components/design/LayersPanel.tsx +180 -53
- package/corpus/templates/design/app/components/design/LocalhostWriteConsentDialog.tsx +0 -2
- package/corpus/templates/design/app/components/design/MotionDock.tsx +144 -21
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +1152 -167
- package/corpus/templates/design/app/components/design/QuestionFlow.tsx +27 -5
- package/corpus/templates/design/app/components/design/ReviewPanel.tsx +23 -2
- package/corpus/templates/design/app/components/design/TokensPanel.tsx +63 -49
- package/corpus/templates/design/app/components/design/bridge/editor-chrome.bridge.ts +1293 -54
- package/corpus/templates/design/app/components/design/bridge/embedded-wheel.bridge.ts +7 -0
- package/corpus/templates/design/app/components/design/bridge/hit-test.bridge.ts +6 -1
- package/corpus/templates/design/app/components/design/bridge/motion-preview.bridge.ts +23 -6
- package/corpus/templates/design/app/components/design/bridge/sample.bridge.ts +7 -0
- package/corpus/templates/design/app/components/design/code-workbench/CodeWorkbench.tsx +5 -0
- package/corpus/templates/design/app/components/design/code-workbench/editor/MonacoHost.tsx +14 -2
- package/corpus/templates/design/app/components/design/code-workbench/explorer/FileTree.tsx +37 -2
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open-guard.ts +25 -0
- package/corpus/templates/design/app/components/design/code-workbench/format/format-on-open.ts +19 -1
- package/corpus/templates/design/app/components/design/code-workbench/model-registry.ts +43 -5
- package/corpus/templates/design/app/components/design/code-workbench/search/SearchView.tsx +27 -2
- package/corpus/templates/design/app/components/design/code-workbench/search/search-engine.ts +10 -1
- package/corpus/templates/design/app/components/design/code-workbench/store.tsx +19 -2
- package/corpus/templates/design/app/components/design/design-canvas/annotation-snapshot.ts +265 -0
- package/corpus/templates/design/app/components/design/design-canvas/annotation-submit.ts +16 -5
- package/corpus/templates/design/app/components/design/design-canvas/coordinate-transforms.ts +16 -2
- package/corpus/templates/design/app/components/design/design-canvas/embedded-frame.ts +7 -2
- package/corpus/templates/design/app/components/design/design-canvas/iframe-events.ts +3 -1
- package/corpus/templates/design/app/components/design/edit-panel/code-inspect-helpers.tsx +78 -8
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +451 -73
- package/corpus/templates/design/app/components/design/edit-panel/document-colors.ts +12 -4
- package/corpus/templates/design/app/components/design/edit-panel/effects-properties.tsx +398 -272
- package/corpus/templates/design/app/components/design/edit-panel/element-classification.ts +41 -7
- package/corpus/templates/design/app/components/design/edit-panel/element-identity.ts +16 -3
- package/corpus/templates/design/app/components/design/edit-panel/field-primitives.tsx +24 -4
- package/corpus/templates/design/app/components/design/edit-panel/fill-gradient-helpers.ts +222 -4
- package/corpus/templates/design/app/components/design/edit-panel/fill-properties.tsx +171 -78
- package/corpus/templates/design/app/components/design/edit-panel/inspector-controls.tsx +45 -5
- package/corpus/templates/design/app/components/design/edit-panel/layout-properties.tsx +299 -28
- package/corpus/templates/design/app/components/design/edit-panel/panel-primitives.tsx +120 -150
- package/corpus/templates/design/app/components/design/edit-panel/position-helpers.ts +53 -1
- package/corpus/templates/design/app/components/design/edit-panel/position-layout-properties.tsx +284 -117
- package/corpus/templates/design/app/components/design/edit-panel/selection-helpers.ts +81 -0
- package/corpus/templates/design/app/components/design/edit-panel/stroke-properties.tsx +19 -14
- package/corpus/templates/design/app/components/design/edit-panel/style-options.ts +7 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-helpers.ts +155 -0
- package/corpus/templates/design/app/components/design/edit-panel/typography-properties.tsx +268 -46
- package/corpus/templates/design/app/components/design/inspector/AutoLayoutMatrix.tsx +350 -31
- package/corpus/templates/design/app/components/design/inspector/ConstraintsWidget.tsx +13 -4
- package/corpus/templates/design/app/components/design/inspector/DesignColorPicker.tsx +233 -23
- package/corpus/templates/design/app/components/design/inspector/GradientEditor.tsx +72 -2
- package/corpus/templates/design/app/components/design/inspector/ScrubInput.tsx +51 -11
- package/corpus/templates/design/app/components/design/inspector/ShaderFillsPanel.tsx +84 -11
- package/corpus/templates/design/app/components/design/inspector/index.ts +3 -0
- package/corpus/templates/design/app/components/design/keyboard-shortcuts.ts +552 -0
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +157 -0
- package/corpus/templates/design/app/components/design/multi-screen/frame-geometry.ts +53 -0
- package/corpus/templates/design/app/components/design/multi-screen/overview-layout.ts +184 -0
- package/corpus/templates/design/app/components/design/multi-screen/primitive-drop-target.ts +403 -26
- package/corpus/templates/design/app/components/design/multi-screen/types.ts +20 -1
- package/corpus/templates/design/app/components/design/types.ts +33 -0
- package/corpus/templates/design/app/components/editor/PromptDialog.tsx +59 -7
- package/corpus/templates/design/app/components/visual-editor/CanvasCommentPins.tsx +119 -17
- package/corpus/templates/design/app/components/visual-editor/DrawOverlay.tsx +275 -63
- package/corpus/templates/design/app/hooks/use-question-flow.ts +14 -3
- package/corpus/templates/design/app/hooks/useDesignHotkeys.ts +67 -10
- package/corpus/templates/design/app/i18n/zh-TW.ts +91 -1
- package/corpus/templates/design/app/i18n-data.ts +1217 -10
- package/corpus/templates/design/app/i18n-keyboard-shortcuts.ts +577 -0
- package/corpus/templates/design/app/lib/agent-chat.ts +23 -0
- package/corpus/templates/design/app/lib/design-import.ts +24 -0
- package/corpus/templates/design/app/lib/figma-clipboard.ts +157 -0
- package/corpus/templates/design/app/lib/figma-svg-copy.ts +221 -0
- package/corpus/templates/design/app/pages/design-editor/code-layer-state.ts +143 -30
- package/corpus/templates/design/app/pages/design-editor/collab-sync.ts +15 -0
- package/corpus/templates/design/app/pages/design-editor/editor-session.ts +33 -0
- package/corpus/templates/design/app/pages/design-editor/editor-state.ts +38 -0
- package/corpus/templates/design/app/pages/design-editor/overview-annotation-context.ts +157 -0
- package/corpus/templates/design/app/pages/design-editor/overview-camera.ts +62 -6
- package/corpus/templates/design/app/pages/design-editor/pending-edits.ts +245 -0
- package/corpus/templates/design/app/pages/design-editor/react-semantic-handoff.ts +586 -0
- package/corpus/templates/design/app/pages/design-editor/screen-auto-layout.ts +169 -0
- package/corpus/templates/design/app/pages/design-editor/selection-state.ts +201 -1
- package/corpus/templates/design/changelog/2026-07-09-added-underline-strikethrough-and-text-case-uppercase-lowerc.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-annotate-now-draws-across-the-all-screens-canvas-without-swi.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-auto-layout-children-can-now-be-dragged-into-freeform-screen.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-board-shapes-now-stay-visible-and-nest-correctly-across-the-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-component-source-navigation-now-opens-reliably-from-the-insp.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-cross-screen-local-react-layer-moves-now-hand-off-exact-sour.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-cross-screen-moves-undo-and-redo-now-keep-both-screens-stabl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-detach-a-component-instance-into-plain-editable-eleme.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-dragging-layers-into-auto-layout-now-respects-ignore-auto-la.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-drawing-annotations-sent-to-the-agent-now-include-a-rendered.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-editor-sidebars-now-use-figma-matched-default-widths-for-a-r.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-empty-frames-and-rectangles-now-expose-full-auto-layout-cont.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-export-any-design-screen-as-a-real-vector-svg-for-figma-with.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-grid-auto-layout-now-uses-true-responsive-rows-and-columns-w.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-hidden-and-locked-screens-now-behave-consistently-between-la.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-image-fills-now-preserve-valid-urls-and-layered-fit-settings.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-import-figma-frames-as-pixel-accurate-design-screens-via-a-s.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-inspect-code-now-hides-internal-styling-metadata-and-wraps-l.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-inspector-blur-and-shadow-effects-now-preserve-other-effects.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-jump-to-a-components-other-instances-from-the-inspecto.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-keyboard-shortcuts-are-now-discoverable-in-a-figma-style-bot.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layer-selection-now-keeps-cmd-or-ctrl-toggles-and-shift-rang.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-layers-dropped-into-auto-layout-now-participate-correctly-in.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-live-edit-screens-now-enter-and-leave-full-view-withou.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-preview-urls-now-live-in-the-inspector-instead-of-taki.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-layers-can-now-be-hidden-and-locked-from-layers-.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-layers-now-keep-exact-source-provenance-and-supp.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-local-react-visual-editing-now-loads-reliably-and-shows-live.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-paste-from-figma-cmd-v-now-imports-exact-editable-nodes-when.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-pressing-escape-after-selecting-a-screen-now-reveals-page-pr.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-right-click-overlapping-or-nested-objects-to-choose-the-exac.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-scale-edge-stretch-and-center-constraints-now-preserve-layer.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-screen-rows-can-now-be-reordered-in-layers-with-matching-can.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-screen-selection-stays-responsive-in-designs-with-hundreds-o.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-shift-a-now-enables-auto-layout-on-a-selected-screen-with-fl.md +6 -0
- package/corpus/templates/design/changelog/2026-07-09-swap-a-component-instance-for-another-from-the-libra.md +6 -0
- package/corpus/templates/design/changelog/2026-07-10-drawing-annotations-now-stay-available-to-retry-when-the.md +6 -0
- package/corpus/templates/design/e2e/global-setup.ts +3 -6
- package/corpus/templates/design/e2e/helpers.ts +27 -6
- package/corpus/templates/design/server/lib/design-to-figma-svg.ts +1412 -0
- package/corpus/templates/design/server/lib/figma-clipboard-match.ts +196 -0
- package/corpus/templates/design/server/lib/figma-node-import.ts +311 -0
- package/corpus/templates/design/server/lib/figma-node-to-html.ts +1334 -0
- package/corpus/templates/design/server/lib/figma-paste-fallback.ts +64 -0
- package/corpus/templates/design/server/lib/playwright-runtime.ts +78 -0
- package/corpus/templates/design/server/plugins/db.ts +41 -0
- package/corpus/templates/design/server/source-workspace.ts +64 -0
- package/corpus/templates/design/shared/board-file.ts +13 -2
- package/corpus/templates/design/shared/canvas-math.ts +231 -33
- package/corpus/templates/design/shared/code-layer.ts +122 -8
- package/corpus/templates/design/shared/component-library.ts +161 -0
- package/corpus/templates/design/shared/db-conflict.ts +27 -0
- package/corpus/templates/design/shared/design-source-capabilities.ts +2 -1
- package/corpus/templates/design/shared/figma-url.ts +149 -0
- package/corpus/templates/design/shared/pen-path.ts +16 -7
- package/corpus/templates/design/shared/source-mode.ts +1 -0
- package/corpus/templates/plan/app/components/plan/CanvasArea.tsx +7 -19
- package/corpus/templates/plan/changelog/2026-07-09-canvas-panning-now-keeps-zoom-fixed-even-at-the-edges.md +6 -0
- package/corpus/templates/slides/actions/index-design-system-with-builder.ts +16 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +311 -70
- package/corpus/templates/slides/changelog/2026-07-09-fixed-the-slide-rail-going-permanently-stale-during-a-long-a.md +6 -0
- package/dist/agent/production-agent.d.ts +82 -7
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +180 -17
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/run-manager.d.ts.map +1 -1
- package/dist/agent/run-manager.js +63 -14
- package/dist/agent/run-manager.js.map +1 -1
- package/dist/agent/run-store.d.ts +46 -0
- package/dist/agent/run-store.d.ts.map +1 -1
- package/dist/agent/run-store.js +129 -22
- package/dist/agent/run-store.js.map +1 -1
- package/dist/cli/design-connect.d.ts +6 -0
- package/dist/cli/design-connect.d.ts.map +1 -1
- package/dist/cli/design-connect.js +336 -139
- package/dist/cli/design-connect.js.map +1 -1
- package/dist/cli/skills.d.ts.map +1 -1
- package/dist/cli/skills.js +14 -0
- package/dist/cli/skills.js.map +1 -1
- package/dist/client/AssistantChat.d.ts +2 -0
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +19 -3
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +38 -18
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +48 -12
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/agent-chat.d.ts +60 -0
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +122 -1
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/chat/index.d.ts +1 -1
- package/dist/client/chat/index.d.ts.map +1 -1
- package/dist/client/chat/index.js +1 -1
- package/dist/client/chat/index.js.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.d.ts +12 -0
- package/dist/client/extensions/EmbeddedExtension.d.ts.map +1 -1
- package/dist/client/extensions/EmbeddedExtension.js +36 -2
- package/dist/client/extensions/EmbeddedExtension.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.d.ts.map +1 -1
- package/dist/client/rich-markdown-editor/useCollabReconcile.js +18 -6
- package/dist/client/rich-markdown-editor/useCollabReconcile.js.map +1 -1
- package/dist/collab/awareness-store.d.ts +5 -0
- package/dist/collab/awareness-store.d.ts.map +1 -1
- package/dist/collab/awareness-store.js +19 -12
- package/dist/collab/awareness-store.js.map +1 -1
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/awareness.d.ts.map +1 -1
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +13 -5
- package/dist/collab/client.js.map +1 -1
- package/dist/collab/index.d.ts +1 -0
- package/dist/collab/index.d.ts.map +1 -1
- package/dist/collab/index.js +1 -0
- package/dist/collab/index.js.map +1 -1
- package/dist/collab/recent-edits.d.ts +3 -1
- package/dist/collab/recent-edits.d.ts.map +1 -1
- package/dist/collab/recent-edits.js +57 -2
- package/dist/collab/recent-edits.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/resources/handlers.d.ts +3 -3
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +87 -10
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/builder-design-systems.d.ts +15 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +9 -4
- package/dist/server/builder-design-systems.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { FrameGeometry } from "./types";
|
|
2
|
+
|
|
1
3
|
export function hasBoardSurfaceContent(html: string | undefined) {
|
|
2
4
|
if (!html) return false;
|
|
3
5
|
const bodyMatch = html.match(/<body\b[^>]*>([\s\S]*?)<\/body>/i);
|
|
@@ -53,6 +55,108 @@ function getCssPixelValue(style: string, name: string) {
|
|
|
53
55
|
return Number.isFinite(parsed) ? parsed : null;
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Returns the canvas-space bounds occupied by top-level board nodes.
|
|
60
|
+
*
|
|
61
|
+
* Board coordinates are persisted directly in each root node's absolute
|
|
62
|
+
* `left`/`top`. Keeping this parser string-only makes it usable during SSR and
|
|
63
|
+
* in the jsdom-less unit suite, while restricting the scan to root nodes keeps
|
|
64
|
+
* nested children from being counted twice with parent-relative coordinates.
|
|
65
|
+
*/
|
|
66
|
+
export function getBoardSurfaceContentBounds(
|
|
67
|
+
html: string | undefined,
|
|
68
|
+
): FrameGeometry | null {
|
|
69
|
+
if (!html) return null;
|
|
70
|
+
|
|
71
|
+
const stack: Array<{
|
|
72
|
+
tagName: string;
|
|
73
|
+
nodeId: string;
|
|
74
|
+
offsetX: number;
|
|
75
|
+
offsetY: number;
|
|
76
|
+
}> = [];
|
|
77
|
+
let minX = Number.POSITIVE_INFINITY;
|
|
78
|
+
let minY = Number.POSITIVE_INFINITY;
|
|
79
|
+
let maxX = Number.NEGATIVE_INFINITY;
|
|
80
|
+
let maxY = Number.NEGATIVE_INFINITY;
|
|
81
|
+
|
|
82
|
+
for (const match of html.matchAll(HTML_TAG_RE)) {
|
|
83
|
+
const token = match[0];
|
|
84
|
+
const tagName = match[1]?.toLowerCase();
|
|
85
|
+
if (!tagName) continue;
|
|
86
|
+
|
|
87
|
+
if (token.startsWith("</")) {
|
|
88
|
+
const index = findLastHtmlStackTagIndex(stack, tagName);
|
|
89
|
+
if (index >= 0) stack.splice(index);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const nodeId = getHtmlAttributeValue(token, "data-agent-native-node-id");
|
|
94
|
+
const style = getHtmlAttributeValue(token, "style");
|
|
95
|
+
const left = getCssPixelValue(style, "left") ?? 0;
|
|
96
|
+
const top = getCssPixelValue(style, "top") ?? 0;
|
|
97
|
+
const parentOffsetX = stack.reduce(
|
|
98
|
+
(total, entry) => total + entry.offsetX,
|
|
99
|
+
0,
|
|
100
|
+
);
|
|
101
|
+
const parentOffsetY = stack.reduce(
|
|
102
|
+
(total, entry) => total + entry.offsetY,
|
|
103
|
+
0,
|
|
104
|
+
);
|
|
105
|
+
const isDocumentRootTag =
|
|
106
|
+
tagName === "html" ||
|
|
107
|
+
tagName === "body" ||
|
|
108
|
+
tagName === "style" ||
|
|
109
|
+
tagName === "script";
|
|
110
|
+
if (nodeId && !isDocumentRootTag && !isAccidentalBoardBackdropTag(token)) {
|
|
111
|
+
const primitiveKind = getHtmlAttributeValue(
|
|
112
|
+
token,
|
|
113
|
+
"data-an-primitive",
|
|
114
|
+
).toLowerCase();
|
|
115
|
+
// Auto-sized text has no persisted width/height. A one-pixel extent is
|
|
116
|
+
// not enough when it sits near a render-window edge. Reserve a modest
|
|
117
|
+
// intrinsic text box; the camera viewport remains the final authority
|
|
118
|
+
// for unusually long content.
|
|
119
|
+
const fallbackWidth = primitiveKind === "text" ? 256 : 1;
|
|
120
|
+
const fallbackHeight = primitiveKind === "text" ? 64 : 1;
|
|
121
|
+
const width = Math.max(
|
|
122
|
+
1,
|
|
123
|
+
getCssPixelValue(style, "width") ?? fallbackWidth,
|
|
124
|
+
);
|
|
125
|
+
const height = Math.max(
|
|
126
|
+
1,
|
|
127
|
+
getCssPixelValue(style, "height") ?? fallbackHeight,
|
|
128
|
+
);
|
|
129
|
+
const absoluteLeft = parentOffsetX + left;
|
|
130
|
+
const absoluteTop = parentOffsetY + top;
|
|
131
|
+
minX = Math.min(minX, absoluteLeft);
|
|
132
|
+
minY = Math.min(minY, absoluteTop);
|
|
133
|
+
maxX = Math.max(maxX, absoluteLeft + width);
|
|
134
|
+
maxY = Math.max(maxY, absoluteTop + height);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const selfClosing = token.endsWith("/>") || HTML_VOID_TAGS.has(tagName);
|
|
138
|
+
if (!selfClosing) {
|
|
139
|
+
stack.push({ tagName, nodeId, offsetX: left, offsetY: top });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (
|
|
144
|
+
!Number.isFinite(minX) ||
|
|
145
|
+
!Number.isFinite(minY) ||
|
|
146
|
+
!Number.isFinite(maxX) ||
|
|
147
|
+
!Number.isFinite(maxY)
|
|
148
|
+
) {
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return {
|
|
153
|
+
x: minX,
|
|
154
|
+
y: minY,
|
|
155
|
+
width: Math.max(1, maxX - minX),
|
|
156
|
+
height: Math.max(1, maxY - minY),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
|
|
56
160
|
function parseCssColor(value: string) {
|
|
57
161
|
const trimmed = value.trim().toLowerCase();
|
|
58
162
|
if (!trimmed || trimmed === "transparent") return null;
|
|
@@ -167,6 +271,59 @@ export function getBoardSurfaceRenderContent(html: string) {
|
|
|
167
271
|
return `${BOARD_SURFACE_RENDER_STYLE}${renderHtml}`;
|
|
168
272
|
}
|
|
169
273
|
|
|
274
|
+
function stripExecutableStaticPreviewContent(html: string) {
|
|
275
|
+
return html
|
|
276
|
+
.replace(/<script\b[^>]*>[\s\S]*?<\/script\s*>/gi, "") // i18n-ignore static-preview sanitizer regex, not visible UI copy
|
|
277
|
+
.replace(/<script\b[^>]*\/?\s*>/gi, "")
|
|
278
|
+
.replace(/<(iframe|object|audio|video)\b[^>]*>[\s\S]*?<\/\1\s*>/gi, "") // i18n-ignore static-preview sanitizer regex, not visible UI copy
|
|
279
|
+
.replace(/<(?:iframe|object|embed|audio|video|source)\b[^>]*\/?\s*>/gi, "")
|
|
280
|
+
.replace(/<(?:link|meta|base)\b[^>]*>/gi, "")
|
|
281
|
+
.replace(/@import\s+(?:url\([^)]*\)|["'][^"']*["'])\s*[^;]*;/gi, "")
|
|
282
|
+
.replace(/url\(\s*(?:"[^"]*"|'[^']*'|[^)]*)\s*\)/gi, "none")
|
|
283
|
+
.replace(/<(?:img|image|use)\b[^>]*>/gi, (tag) =>
|
|
284
|
+
tag.replace(
|
|
285
|
+
/\s+(?:src|srcset|href|xlink:href)\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi,
|
|
286
|
+
"",
|
|
287
|
+
),
|
|
288
|
+
)
|
|
289
|
+
.replace(/\s+on[a-z][\w:-]*\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]+)/gi, "");
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Produces the inert, compressed document painted behind the live board
|
|
294
|
+
* window at very low zoom. The document is also rendered in an iframe with an
|
|
295
|
+
* empty sandbox, but removing executable markup here is defense in depth and
|
|
296
|
+
* guarantees Alpine/React never starts a duplicate runtime.
|
|
297
|
+
*
|
|
298
|
+
* Root offsets use the same `translate` seam as the interactive finite board
|
|
299
|
+
* iframe. Scaling the body into a small browser-safe viewport makes the whole
|
|
300
|
+
* logical board paintable without allocating or scrolling a 131k iframe.
|
|
301
|
+
*/
|
|
302
|
+
export function getBoardSurfaceStaticPreviewContent(args: {
|
|
303
|
+
html: string;
|
|
304
|
+
logicalGeometry: FrameGeometry;
|
|
305
|
+
viewport: { width: number; height: number };
|
|
306
|
+
}) {
|
|
307
|
+
const renderHtml = stripExecutableStaticPreviewContent(
|
|
308
|
+
getBoardSurfaceRenderContent(args.html),
|
|
309
|
+
);
|
|
310
|
+
const width = Math.max(1, args.logicalGeometry.width);
|
|
311
|
+
const height = Math.max(1, args.logicalGeometry.height);
|
|
312
|
+
const viewportWidth = Math.max(1, args.viewport.width);
|
|
313
|
+
const viewportHeight = Math.max(1, args.viewport.height);
|
|
314
|
+
const scale = Math.min(viewportWidth / width, viewportHeight / height);
|
|
315
|
+
const offsetX = -args.logicalGeometry.x;
|
|
316
|
+
const offsetY = -args.logicalGeometry.y;
|
|
317
|
+
const style = `<style data-agent-native-board-static-preview>*,*::before,*::after{animation:none!important;animation-delay:0s!important;transition:none!important;caret-color:transparent!important;}html{width:${viewportWidth}px!important;height:${viewportHeight}px!important;overflow:hidden!important;}body{margin:0!important;width:${width}px!important;height:${height}px!important;overflow:visible!important;transform:scale(${scale})!important;transform-origin:0 0!important;}body>[data-agent-native-node-id]{translate:${offsetX}px ${offsetY}px!important;}</style>`;
|
|
318
|
+
if (/<\/head>/i.test(renderHtml)) {
|
|
319
|
+
return renderHtml.replace(/<\/head>/i, `${style}</head>`);
|
|
320
|
+
}
|
|
321
|
+
if (/<body\b/i.test(renderHtml)) {
|
|
322
|
+
return renderHtml.replace(/<body\b/i, `${style}<body`);
|
|
323
|
+
}
|
|
324
|
+
return `${style}${renderHtml}`;
|
|
325
|
+
}
|
|
326
|
+
|
|
170
327
|
/** Simple djb2-xor string hash, used to build cheap cache keys elsewhere in
|
|
171
328
|
* the multi-screen canvas (board content signatures, primitive-parse cache
|
|
172
329
|
* keys, etc). */
|
|
@@ -18,6 +18,59 @@ export interface ScreenViewportSize {
|
|
|
18
18
|
height: number;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/** Canonical bottom-to-top screen stack. Persisted frame `z` wins; screens
|
|
22
|
+
* without one retain their source order, which is also the canvas DOM paint
|
|
23
|
+
* order. This is shared by the overview canvas and Layers projection so the
|
|
24
|
+
* two surfaces can never disagree about which screen is above another. */
|
|
25
|
+
export function getCanonicalScreenStack(
|
|
26
|
+
screens: ReadonlyArray<{ id: string }>,
|
|
27
|
+
geometryById: Record<string, Partial<FrameGeometry> | undefined>,
|
|
28
|
+
): string[] {
|
|
29
|
+
return screens
|
|
30
|
+
.map((screen, index) => ({
|
|
31
|
+
id: screen.id,
|
|
32
|
+
index,
|
|
33
|
+
z: Number.isFinite(geometryById[screen.id]?.z)
|
|
34
|
+
? geometryById[screen.id]!.z!
|
|
35
|
+
: index,
|
|
36
|
+
}))
|
|
37
|
+
.sort((a, b) => a.z - b.z || a.index - b.index)
|
|
38
|
+
.map(({ id }) => id);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Reorders a canonical bottom-to-top stack using DOM placement semantics:
|
|
42
|
+
* `before` paints below the target and `after` paints above it. `inside` is
|
|
43
|
+
* not a screen-stack operation (it remains the layer-into-screen drop path). */
|
|
44
|
+
export function reorderCanonicalScreenStack(args: {
|
|
45
|
+
orderedIds: readonly string[];
|
|
46
|
+
draggedIds: readonly string[];
|
|
47
|
+
targetId: string;
|
|
48
|
+
placement: "before" | "after" | "inside";
|
|
49
|
+
}): string[] | null {
|
|
50
|
+
if (args.placement === "inside") return null;
|
|
51
|
+
const orderedIds = Array.from(new Set(args.orderedIds));
|
|
52
|
+
const orderedIdSet = new Set(orderedIds);
|
|
53
|
+
if (!orderedIdSet.has(args.targetId)) return null;
|
|
54
|
+
const draggedIdSet = new Set(
|
|
55
|
+
args.draggedIds.filter(
|
|
56
|
+
(id) => orderedIdSet.has(id) && id !== args.targetId,
|
|
57
|
+
),
|
|
58
|
+
);
|
|
59
|
+
if (draggedIdSet.size === 0) return null;
|
|
60
|
+
const moving = orderedIds.filter((id) => draggedIdSet.has(id));
|
|
61
|
+
const remaining = orderedIds.filter((id) => !draggedIdSet.has(id));
|
|
62
|
+
const targetIndex = remaining.indexOf(args.targetId);
|
|
63
|
+
if (targetIndex < 0) return null;
|
|
64
|
+
const insertionIndex =
|
|
65
|
+
args.placement === "before" ? targetIndex : targetIndex + 1;
|
|
66
|
+
const next = [
|
|
67
|
+
...remaining.slice(0, insertionIndex),
|
|
68
|
+
...moving,
|
|
69
|
+
...remaining.slice(insertionIndex),
|
|
70
|
+
];
|
|
71
|
+
return next.every((id, index) => id === orderedIds[index]) ? null : next;
|
|
72
|
+
}
|
|
73
|
+
|
|
21
74
|
export function getBreakpointFrameGeometry(args: {
|
|
22
75
|
widthPx: number;
|
|
23
76
|
naturalAspect: number;
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
import type { CSSProperties } from "react";
|
|
2
2
|
|
|
3
3
|
import type { FrameGeometry } from "./types";
|
|
4
|
+
import type { Point } from "./types";
|
|
4
5
|
|
|
5
6
|
export const OVERVIEW_FRAME_WIDTH = 320;
|
|
6
7
|
export const SURFACE_PADDING = 240;
|
|
7
8
|
|
|
9
|
+
// Chromium does not reliably paint the far interior of the old
|
|
10
|
+
// 131,072×131,072 board iframe. Keep the logical board that large for
|
|
11
|
+
// persistence and hit testing, but render only a stable, chunk-snapped window
|
|
12
|
+
// around the current design. Four-kilopixel chunks plus two chunks of minimum
|
|
13
|
+
// extent leave ample room for nearby drawing/movement without re-keying the
|
|
14
|
+
// iframe on every small edit.
|
|
15
|
+
export const BOARD_SURFACE_RENDER_CHUNK = 4096;
|
|
16
|
+
export const BOARD_SURFACE_RENDER_PADDING = 2048;
|
|
17
|
+
export const BOARD_SURFACE_RENDER_MIN_SIZE = 8192;
|
|
18
|
+
export const BOARD_SURFACE_RENDER_MAX_SIZE = 24_576;
|
|
19
|
+
export const BOARD_SURFACE_STATIC_PREVIEW_SIZE = 4096;
|
|
20
|
+
|
|
8
21
|
export const LINEUP_RECENTER_SUPPRESS_MAX_AGE_MS = 10_000;
|
|
9
22
|
|
|
10
23
|
export interface LineupRecenterDuplicateArm {
|
|
@@ -60,3 +73,174 @@ export function getBoardSurfaceLayerStyle(args: {
|
|
|
60
73
|
zIndex: 0,
|
|
61
74
|
};
|
|
62
75
|
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* The interactive board iframe intentionally stays below Chromium's reliable
|
|
79
|
+
* paint limit. At very low zoom the visible world can be wider than that
|
|
80
|
+
* window, so a script-disabled static replica supplies visual coverage behind
|
|
81
|
+
* it. Keep the fallback off at ordinary zoom where the live window already
|
|
82
|
+
* covers the viewport.
|
|
83
|
+
*/
|
|
84
|
+
export function shouldRenderBoardSurfaceStaticPreview(args: {
|
|
85
|
+
zoom: number;
|
|
86
|
+
viewportGeometry?: FrameGeometry | null;
|
|
87
|
+
renderGeometry: FrameGeometry;
|
|
88
|
+
}) {
|
|
89
|
+
if (args.viewportGeometry) {
|
|
90
|
+
return (
|
|
91
|
+
args.viewportGeometry.width > args.renderGeometry.width ||
|
|
92
|
+
args.viewportGeometry.height > args.renderGeometry.height
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
// ResizeObserver has not reported yet. The 5% fallback matches a 1229px
|
|
96
|
+
// viewport against the 24,576-world-pixel live cap and avoids one blank
|
|
97
|
+
// first paint at the minimum 2% zoom.
|
|
98
|
+
return args.zoom <= 5;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function getBoardSurfaceStaticPreviewViewport(
|
|
102
|
+
logicalGeometry: FrameGeometry,
|
|
103
|
+
) {
|
|
104
|
+
const longestAxis = Math.max(
|
|
105
|
+
1,
|
|
106
|
+
logicalGeometry.width,
|
|
107
|
+
logicalGeometry.height,
|
|
108
|
+
);
|
|
109
|
+
const scale = Math.min(1, BOARD_SURFACE_STATIC_PREVIEW_SIZE / longestAxis);
|
|
110
|
+
return {
|
|
111
|
+
width: Math.max(1, logicalGeometry.width * scale),
|
|
112
|
+
height: Math.max(1, logicalGeometry.height * scale),
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function geometryExtent(geometry: FrameGeometry) {
|
|
117
|
+
return {
|
|
118
|
+
minX: geometry.x,
|
|
119
|
+
minY: geometry.y,
|
|
120
|
+
maxX: geometry.x + Math.max(1, geometry.width),
|
|
121
|
+
maxY: geometry.y + Math.max(1, geometry.height),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function fitRenderAxis(args: {
|
|
126
|
+
desiredMin: number;
|
|
127
|
+
desiredMax: number;
|
|
128
|
+
logicalMin: number;
|
|
129
|
+
logicalMax: number;
|
|
130
|
+
focus: number;
|
|
131
|
+
}) {
|
|
132
|
+
const chunk = BOARD_SURFACE_RENDER_CHUNK;
|
|
133
|
+
const logicalSize = Math.max(1, args.logicalMax - args.logicalMin);
|
|
134
|
+
const maxSize = Math.min(BOARD_SURFACE_RENDER_MAX_SIZE, logicalSize);
|
|
135
|
+
const minSize = Math.min(BOARD_SURFACE_RENDER_MIN_SIZE, maxSize);
|
|
136
|
+
let min =
|
|
137
|
+
Math.floor((args.desiredMin - BOARD_SURFACE_RENDER_PADDING) / chunk) *
|
|
138
|
+
chunk;
|
|
139
|
+
let max =
|
|
140
|
+
Math.ceil((args.desiredMax + BOARD_SURFACE_RENDER_PADDING) / chunk) * chunk;
|
|
141
|
+
|
|
142
|
+
if (max - min < minSize) {
|
|
143
|
+
const center = (min + max) / 2;
|
|
144
|
+
min = Math.floor((center - minSize / 2) / chunk) * chunk;
|
|
145
|
+
max = min + minSize;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (max - min > maxSize) {
|
|
149
|
+
// A single browser iframe cannot safely cover arbitrarily distant board
|
|
150
|
+
// islands. Prefer the active design focus while keeping the render window
|
|
151
|
+
// chunk-aligned; persistence and geometry hit testing still use the full
|
|
152
|
+
// logical board and remain lossless.
|
|
153
|
+
min = Math.floor((args.focus - maxSize / 2) / chunk) * chunk;
|
|
154
|
+
max = min + maxSize;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (min < args.logicalMin) {
|
|
158
|
+
max += args.logicalMin - min;
|
|
159
|
+
min = args.logicalMin;
|
|
160
|
+
}
|
|
161
|
+
if (max > args.logicalMax) {
|
|
162
|
+
min -= max - args.logicalMax;
|
|
163
|
+
max = args.logicalMax;
|
|
164
|
+
}
|
|
165
|
+
min = Math.max(args.logicalMin, min);
|
|
166
|
+
max = Math.min(args.logicalMax, Math.max(min + 1, max));
|
|
167
|
+
return { origin: min, size: max - min };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Builds the finite iframe window used to paint the otherwise-infinite board.
|
|
172
|
+
* The returned geometry is deliberately separate from the logical board
|
|
173
|
+
* geometry so persisted coordinates and broad hit-testing retain their full
|
|
174
|
+
* range while Chromium only has to paint a browser-safe surface.
|
|
175
|
+
*/
|
|
176
|
+
export function getBoardSurfaceRenderGeometry(args: {
|
|
177
|
+
logicalGeometry: FrameGeometry;
|
|
178
|
+
contentBounds?: FrameGeometry | null;
|
|
179
|
+
screenGeometries?: readonly FrameGeometry[];
|
|
180
|
+
focus?: { x: number; y: number };
|
|
181
|
+
}): FrameGeometry {
|
|
182
|
+
const candidates = [
|
|
183
|
+
...(args.contentBounds ? [args.contentBounds] : []),
|
|
184
|
+
...(args.screenGeometries ?? []),
|
|
185
|
+
];
|
|
186
|
+
const logical = geometryExtent(args.logicalGeometry);
|
|
187
|
+
const extents = candidates.map(geometryExtent);
|
|
188
|
+
const desired =
|
|
189
|
+
extents.length > 0
|
|
190
|
+
? {
|
|
191
|
+
minX: Math.min(...extents.map((extent) => extent.minX)),
|
|
192
|
+
minY: Math.min(...extents.map((extent) => extent.minY)),
|
|
193
|
+
maxX: Math.max(...extents.map((extent) => extent.maxX)),
|
|
194
|
+
maxY: Math.max(...extents.map((extent) => extent.maxY)),
|
|
195
|
+
}
|
|
196
|
+
: {
|
|
197
|
+
minX: 0,
|
|
198
|
+
minY: 0,
|
|
199
|
+
maxX: 1,
|
|
200
|
+
maxY: 1,
|
|
201
|
+
};
|
|
202
|
+
const focus = args.focus ?? {
|
|
203
|
+
x: (desired.minX + desired.maxX) / 2,
|
|
204
|
+
y: (desired.minY + desired.maxY) / 2,
|
|
205
|
+
};
|
|
206
|
+
const xAxis = fitRenderAxis({
|
|
207
|
+
desiredMin: desired.minX,
|
|
208
|
+
desiredMax: desired.maxX,
|
|
209
|
+
logicalMin: logical.minX,
|
|
210
|
+
logicalMax: logical.maxX,
|
|
211
|
+
focus: focus.x,
|
|
212
|
+
});
|
|
213
|
+
const yAxis = fitRenderAxis({
|
|
214
|
+
desiredMin: desired.minY,
|
|
215
|
+
desiredMax: desired.maxY,
|
|
216
|
+
logicalMin: logical.minY,
|
|
217
|
+
logicalMax: logical.maxY,
|
|
218
|
+
focus: focus.y,
|
|
219
|
+
});
|
|
220
|
+
return {
|
|
221
|
+
x: xAxis.origin,
|
|
222
|
+
y: yAxis.origin,
|
|
223
|
+
width: xAxis.size,
|
|
224
|
+
height: yAxis.size,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export function boardPointToBoardSurfaceLocalPoint(
|
|
229
|
+
point: Point,
|
|
230
|
+
renderGeometry: FrameGeometry,
|
|
231
|
+
): Point {
|
|
232
|
+
return {
|
|
233
|
+
x: point.x - renderGeometry.x,
|
|
234
|
+
y: point.y - renderGeometry.y,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function boardSurfaceLocalPointToBoardPoint(
|
|
239
|
+
point: Point,
|
|
240
|
+
renderGeometry: FrameGeometry,
|
|
241
|
+
): Point {
|
|
242
|
+
return {
|
|
243
|
+
x: renderGeometry.x + point.x,
|
|
244
|
+
y: renderGeometry.y + point.y,
|
|
245
|
+
};
|
|
246
|
+
}
|