@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 { isMixedValue, MIXED_VALUE } from "./selection-helpers";
|
|
2
|
+
|
|
1
3
|
export const FONT_FAMILY_OPTIONS = [
|
|
2
4
|
{ value: "inherit", key: "inherit" },
|
|
3
5
|
{ value: "sans-serif", key: "sansSerif" },
|
|
@@ -21,8 +23,38 @@ export const FONT_WEIGHT_OPTIONS = [
|
|
|
21
23
|
{ value: "900", key: "black" },
|
|
22
24
|
] as const;
|
|
23
25
|
|
|
26
|
+
/**
|
|
27
|
+
* True when `value` matches one of the nine standard FONT_WEIGHT_OPTIONS
|
|
28
|
+
* notches. Variable-font weights (e.g. "550") or a keyword the browser
|
|
29
|
+
* didn't normalize are real but "unknown" — callers should inject a
|
|
30
|
+
* synthesized option for these instead of silently rendering a Select whose
|
|
31
|
+
* value matches no item (blank dropdown, current weight still applied).
|
|
32
|
+
*/
|
|
33
|
+
export function isKnownFontWeight(value: string): boolean {
|
|
34
|
+
return FONT_WEIGHT_OPTIONS.some((option) => option.value === value);
|
|
35
|
+
}
|
|
36
|
+
|
|
24
37
|
export type TextResizeMode = "auto-width" | "auto-height" | "fixed";
|
|
25
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Fallback dimension used when converting a text box from an auto (width or
|
|
41
|
+
* height) resize mode to "fixed". When the box already has a real authored
|
|
42
|
+
* size (not auto), that size is preserved verbatim. Otherwise this must use
|
|
43
|
+
* the element's actual current on-screen size (`boundingSizePx`, from
|
|
44
|
+
* `boundingRect`) rather than an arbitrary constant — converting auto-width
|
|
45
|
+
* text that currently renders at, say, 340px wide to "fixed" must keep it at
|
|
46
|
+
* ~340px, not silently snap it to a hardcoded default and visibly resize it.
|
|
47
|
+
*/
|
|
48
|
+
export function resolveFixedResizeDimension(
|
|
49
|
+
authoredValue: string | undefined,
|
|
50
|
+
isAuto: boolean,
|
|
51
|
+
boundingSizePx: number,
|
|
52
|
+
): string {
|
|
53
|
+
if (authoredValue && !isAuto) return authoredValue;
|
|
54
|
+
const size = Number.isFinite(boundingSizePx) ? Math.round(boundingSizePx) : 0;
|
|
55
|
+
return `${Math.max(1, size)}px`;
|
|
56
|
+
}
|
|
57
|
+
|
|
26
58
|
function cleanFontFamilyName(value: string): string {
|
|
27
59
|
const trimmed = value.trim();
|
|
28
60
|
if (
|
|
@@ -115,3 +147,126 @@ export function resolveFontFamilySelectValue(
|
|
|
115
147
|
);
|
|
116
148
|
return firstFamilyOption?.value ?? raw;
|
|
117
149
|
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Mixed-selection-safe wrapper around resolveFontFamilySelectValue.
|
|
153
|
+
*
|
|
154
|
+
* A multi-selection spanning different font families injects the MIXED_VALUE
|
|
155
|
+
* sentinel string ("Mixed") into computedStyles.fontFamily (see
|
|
156
|
+
* mixedElementFromSelection/sameOrMixed in selection-helpers.ts). Feeding
|
|
157
|
+
* that sentinel straight into resolveFontFamilySelectValue happened to
|
|
158
|
+
* resolve back to the literal string "Mixed" (no option's normalized stack
|
|
159
|
+
* or first-family matches, so the raw fallback wins) — but only by
|
|
160
|
+
* coincidence, since MIXED_VALUE itself is "Mixed". Callers must not rely on
|
|
161
|
+
* that coincidence: without an explicit mixed check the caller has no signal
|
|
162
|
+
* to render the value as a disabled placeholder, so "Mixed" ends up as a
|
|
163
|
+
* normal, clickable SelectItem the user could select and commit as a literal
|
|
164
|
+
* (nonsensical) `font-family: Mixed` style. This wrapper makes the mixed
|
|
165
|
+
* state explicit so callers can branch on it the same way they already do
|
|
166
|
+
* for fontWeight/fontSize/lineHeight/letterSpacing.
|
|
167
|
+
*/
|
|
168
|
+
export function resolveFontFamilyFieldValue(
|
|
169
|
+
computedFontFamily: string | undefined,
|
|
170
|
+
): string {
|
|
171
|
+
if (isMixedValue(computedFontFamily)) return MIXED_VALUE;
|
|
172
|
+
return resolveFontFamilySelectValue(computedFontFamily);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* PERSISTENCE GOTCHA — commit text-decoration toggles through "text-decoration"
|
|
177
|
+
* (the shorthand), never "text-decoration-line" (the longhand).
|
|
178
|
+
*
|
|
179
|
+
* The persisted-source style patcher (`applyStyleEdit`/`normalizeStyleProperty`
|
|
180
|
+
* in `shared/code-layer.ts`) only writes properties on its `VisualStyleProperty`
|
|
181
|
+
* allow-list. That list has "text-decoration" but does NOT have
|
|
182
|
+
* "text-decoration-line" — so an `onStyleChange("textDecorationLine", ...)`
|
|
183
|
+
* call would normalize to the unlisted kebab name, miss the allow-list, and
|
|
184
|
+
* return "unsupported": the live iframe preview (which patches the DOM
|
|
185
|
+
* directly via `element.style.setProperty`, no allow-list) would still
|
|
186
|
+
* visually flip on the toggle tick, but the change would never reach the
|
|
187
|
+
* saved HTML source and would revert on the next load/reparse — a
|
|
188
|
+
* works-in-preview, doesn't-persist bug. The shorthand happily accepts a bare
|
|
189
|
+
* line-keyword list ("underline", "underline line-through", "none") as its
|
|
190
|
+
* value, which is valid CSS and *is* on the allow-list, so every helper below
|
|
191
|
+
* reads/writes through "text-decoration" (property name "textDecoration" from
|
|
192
|
+
* call sites) even though the bridge separately exposes the clean longhand
|
|
193
|
+
* `textDecorationLine` computed value for reading current state.
|
|
194
|
+
*/
|
|
195
|
+
export type TextDecorationLineToken = "underline" | "line-through" | "overline";
|
|
196
|
+
|
|
197
|
+
const TEXT_DECORATION_LINE_TOKENS: readonly TextDecorationLineToken[] = [
|
|
198
|
+
"underline",
|
|
199
|
+
"line-through",
|
|
200
|
+
"overline",
|
|
201
|
+
];
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Parses a text-decoration-line-ish CSS value ("none", "underline",
|
|
205
|
+
* "underline line-through", or even the full shorthand computed string like
|
|
206
|
+
* "underline solid rgb(0, 0, 0)") into the set of line tokens present. Works
|
|
207
|
+
* on either the clean longhand or the composite shorthand since it just
|
|
208
|
+
* looks for each known keyword as a whole word.
|
|
209
|
+
*/
|
|
210
|
+
export function parseTextDecorationLineTokens(
|
|
211
|
+
value: string | undefined,
|
|
212
|
+
): Set<TextDecorationLineToken> {
|
|
213
|
+
const tokens = new Set<TextDecorationLineToken>();
|
|
214
|
+
if (!value) return tokens;
|
|
215
|
+
for (const token of TEXT_DECORATION_LINE_TOKENS) {
|
|
216
|
+
if (new RegExp(`(?:^|\\s)${token}(?:\\s|$)`).test(value)) {
|
|
217
|
+
tokens.add(token);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return tokens;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* True when `line` is active in `value`. A mixed-selection sentinel (see
|
|
225
|
+
* `isMixedValue`) always reads as inactive — same convention every other
|
|
226
|
+
* mixed-aware field in this panel uses (fontFamily/fontWeight/fontSize/...):
|
|
227
|
+
* an indeterminate state renders as "off", not as a guess at one element's
|
|
228
|
+
* value.
|
|
229
|
+
*/
|
|
230
|
+
export function isTextDecorationLineActive(
|
|
231
|
+
value: string | undefined,
|
|
232
|
+
line: TextDecorationLineToken,
|
|
233
|
+
): boolean {
|
|
234
|
+
if (isMixedValue(value)) return false;
|
|
235
|
+
return parseTextDecorationLineTokens(value).has(line);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Returns the "text-decoration" value to commit after toggling `line` on/off
|
|
240
|
+
* against the element's current decoration-line state. A mixed selection is
|
|
241
|
+
* treated as "no lines active yet" so the first click always turns the
|
|
242
|
+
* toggled line ON uniformly across every selected element — matching how
|
|
243
|
+
* every other Select-driven field here (fontFamily, fontWeight, ...)
|
|
244
|
+
* overwrites a mixed selection with one explicit value instead of trying to
|
|
245
|
+
* merge each element's own prior state.
|
|
246
|
+
*/
|
|
247
|
+
export function nextTextDecorationLineValue(
|
|
248
|
+
currentValue: string | undefined,
|
|
249
|
+
line: TextDecorationLineToken,
|
|
250
|
+
): string {
|
|
251
|
+
const current = isMixedValue(currentValue)
|
|
252
|
+
? new Set<TextDecorationLineToken>()
|
|
253
|
+
: parseTextDecorationLineTokens(currentValue);
|
|
254
|
+
if (current.has(line)) current.delete(line);
|
|
255
|
+
else current.add(line);
|
|
256
|
+
return current.size === 0 ? "none" : Array.from(current).join(" ");
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* text-transform options (Figma's "Case" control). Unlike font-family/weight,
|
|
261
|
+
* "text-transform" is already on the persisted-source `VisualStyleProperty`
|
|
262
|
+
* allow-list under its own name, so callers can commit it directly with
|
|
263
|
+
* `onStyleChange("textTransform", value)` — no shorthand workaround needed.
|
|
264
|
+
*/
|
|
265
|
+
export const TEXT_CASE_OPTIONS = [
|
|
266
|
+
{ value: "none", key: "none" },
|
|
267
|
+
{ value: "uppercase", key: "uppercase" },
|
|
268
|
+
{ value: "lowercase", key: "lowercase" },
|
|
269
|
+
{ value: "capitalize", key: "capitalize" },
|
|
270
|
+
] as const;
|
|
271
|
+
|
|
272
|
+
export type TextCaseValue = (typeof TEXT_CASE_OPTIONS)[number]["value"];
|
|
@@ -10,9 +10,15 @@ import {
|
|
|
10
10
|
IconLayoutAlignMiddle,
|
|
11
11
|
IconLayoutAlignTop,
|
|
12
12
|
IconLetterCase,
|
|
13
|
+
IconLetterCaseLower,
|
|
14
|
+
IconLetterCaseToggle,
|
|
15
|
+
IconLetterCaseUpper,
|
|
13
16
|
IconLetterSpacing,
|
|
14
17
|
IconLineHeight,
|
|
15
18
|
IconSquare,
|
|
19
|
+
IconStrikethrough,
|
|
20
|
+
IconTextSize,
|
|
21
|
+
IconUnderline,
|
|
16
22
|
} from "@tabler/icons-react";
|
|
17
23
|
import { useState } from "react";
|
|
18
24
|
|
|
@@ -45,12 +51,22 @@ import { PanelSection } from "./panel-primitives";
|
|
|
45
51
|
import { roundToOneDecimal } from "./position-helpers";
|
|
46
52
|
import { isMixedValue, MIXED_VALUE } from "./selection-helpers";
|
|
47
53
|
import type { StyleChangeHandler } from "./style-change-types";
|
|
48
|
-
import {
|
|
54
|
+
import {
|
|
55
|
+
optionValue,
|
|
56
|
+
parseNumericValue,
|
|
57
|
+
resolveLineHeight,
|
|
58
|
+
} from "./style-options";
|
|
49
59
|
import {
|
|
50
60
|
displayFontFamilyName,
|
|
51
61
|
FONT_FAMILY_OPTIONS,
|
|
52
62
|
FONT_WEIGHT_OPTIONS,
|
|
53
|
-
|
|
63
|
+
isKnownFontWeight,
|
|
64
|
+
isTextDecorationLineActive,
|
|
65
|
+
nextTextDecorationLineValue,
|
|
66
|
+
resolveFixedResizeDimension,
|
|
67
|
+
resolveFontFamilyFieldValue,
|
|
68
|
+
TEXT_CASE_OPTIONS,
|
|
69
|
+
type TextDecorationLineToken,
|
|
54
70
|
type TextResizeMode,
|
|
55
71
|
} from "./typography-helpers";
|
|
56
72
|
|
|
@@ -90,14 +106,76 @@ function TextResizeControls({
|
|
|
90
106
|
);
|
|
91
107
|
}
|
|
92
108
|
|
|
109
|
+
type TypographyDetailsTab = "basics" | "details";
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* The tab bar's "Basics"/"Details" buttons are a real tab list (not the
|
|
113
|
+
* static, non-interactive spans this replaced) — see the module-level note
|
|
114
|
+
* near `TypographyDetailsPopover` for why the third "Variable" tab was
|
|
115
|
+
* dropped instead of wired up.
|
|
116
|
+
*/
|
|
117
|
+
function TypographyDetailsTabButton({
|
|
118
|
+
label,
|
|
119
|
+
active,
|
|
120
|
+
onClick,
|
|
121
|
+
}: {
|
|
122
|
+
label: string;
|
|
123
|
+
active: boolean;
|
|
124
|
+
onClick: () => void;
|
|
125
|
+
}) {
|
|
126
|
+
return (
|
|
127
|
+
<button
|
|
128
|
+
type="button"
|
|
129
|
+
role="tab"
|
|
130
|
+
aria-selected={active}
|
|
131
|
+
onClick={onClick}
|
|
132
|
+
className={cn(
|
|
133
|
+
"cursor-pointer rounded px-2.5 py-1 !text-[11px] font-medium text-muted-foreground",
|
|
134
|
+
active &&
|
|
135
|
+
"bg-[var(--design-editor-panel-raised-bg)] font-semibold text-foreground",
|
|
136
|
+
)}
|
|
137
|
+
>
|
|
138
|
+
{label}
|
|
139
|
+
</button>
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Text decoration (underline/strikethrough) and case (none/uppercase/
|
|
145
|
+
* lowercase/capitalize) live here, in the popover's "Details" tab, rather
|
|
146
|
+
* than as a 5th always-visible row in the compact panel above — matching
|
|
147
|
+
* Figma, which tucks these into the same type-details flyout instead of the
|
|
148
|
+
* always-on compact type row. Deliberately NOT duplicating line-height /
|
|
149
|
+
* letter-spacing here even though Figma's flyout also shows them: this
|
|
150
|
+
* panel's compact row (see TypographyProperties below) already exposes both
|
|
151
|
+
* as always-visible, directly-editable fields, so a second live-editable
|
|
152
|
+
* copy of the exact same property here would be redundant clutter and an
|
|
153
|
+
* easy source of two-inputs-fighting-the-same-value bugs, not a feature.
|
|
154
|
+
*/
|
|
93
155
|
function TypographyDetailsPopover({
|
|
94
156
|
resizeMode,
|
|
95
157
|
onResizeModeChange,
|
|
158
|
+
underlineActive,
|
|
159
|
+
strikethroughActive,
|
|
160
|
+
onToggleUnderline,
|
|
161
|
+
onToggleStrikethrough,
|
|
162
|
+
textCase,
|
|
163
|
+
textCaseIsMixed,
|
|
164
|
+
onTextCaseChange,
|
|
96
165
|
}: {
|
|
97
166
|
resizeMode: TextResizeMode;
|
|
98
167
|
onResizeModeChange: (mode: TextResizeMode) => void;
|
|
168
|
+
underlineActive: boolean;
|
|
169
|
+
strikethroughActive: boolean;
|
|
170
|
+
onToggleUnderline: () => void;
|
|
171
|
+
onToggleStrikethrough: () => void;
|
|
172
|
+
textCase: string;
|
|
173
|
+
textCaseIsMixed: boolean;
|
|
174
|
+
onTextCaseChange: (value: string) => void;
|
|
99
175
|
}) {
|
|
176
|
+
const t = useT();
|
|
100
177
|
const [open, setOpen] = useState(false);
|
|
178
|
+
const [activeTab, setActiveTab] = useState<TypographyDetailsTab>("basics");
|
|
101
179
|
|
|
102
180
|
return (
|
|
103
181
|
<Popover open={open} onOpenChange={setOpen}>
|
|
@@ -131,32 +209,99 @@ function TypographyDetailsPopover({
|
|
|
131
209
|
className="z-[100010] w-[360px] rounded-xl border-[var(--design-editor-control-border)] bg-[var(--design-editor-panel-bg)] p-0 text-foreground shadow-2xl"
|
|
132
210
|
>
|
|
133
211
|
<div className="flex items-center gap-1 border-b border-[var(--design-editor-control-border)] p-2.5">
|
|
134
|
-
<div
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
<
|
|
139
|
-
{"
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
212
|
+
<div
|
|
213
|
+
role="tablist"
|
|
214
|
+
className="flex rounded-md bg-[var(--design-editor-control-bg)] p-0.5"
|
|
215
|
+
>
|
|
216
|
+
<TypographyDetailsTabButton
|
|
217
|
+
label={t("editPanel.typographyDetails.basicsTab")}
|
|
218
|
+
active={activeTab === "basics"}
|
|
219
|
+
onClick={() => setActiveTab("basics")}
|
|
220
|
+
/>
|
|
221
|
+
<TypographyDetailsTabButton
|
|
222
|
+
label={t("editPanel.typographyDetails.detailsTab")}
|
|
223
|
+
active={activeTab === "details"}
|
|
224
|
+
onClick={() => setActiveTab("details")}
|
|
225
|
+
/>
|
|
144
226
|
</div>
|
|
145
227
|
</div>
|
|
146
|
-
|
|
147
|
-
<div className="
|
|
148
|
-
|
|
228
|
+
{activeTab === "basics" ? (
|
|
229
|
+
<div className="space-y-3 p-4 !text-[11px]">
|
|
230
|
+
<div className="flex h-20 items-center justify-center rounded-md bg-[var(--design-editor-control-bg)] text-[18px] text-muted-foreground/80">
|
|
231
|
+
{"Preview" /* i18n-ignore design typography details preview */}
|
|
232
|
+
</div>
|
|
233
|
+
<div className="flex items-center justify-between gap-3">
|
|
234
|
+
<span className="!text-[11px] font-medium text-muted-foreground">
|
|
235
|
+
{"Text box" /* i18n-ignore design typography details label */}
|
|
236
|
+
</span>
|
|
237
|
+
<TextResizeControls
|
|
238
|
+
resizeMode={resizeMode}
|
|
239
|
+
onResizeModeChange={onResizeModeChange}
|
|
240
|
+
/>
|
|
241
|
+
</div>
|
|
149
242
|
</div>
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
243
|
+
) : (
|
|
244
|
+
<div className="space-y-3 p-4 !text-[11px]">
|
|
245
|
+
<div className="flex items-center justify-between gap-3">
|
|
246
|
+
<span className="!text-[11px] font-medium text-muted-foreground">
|
|
247
|
+
{t("editPanel.typographyDetails.decorationLabel")}
|
|
248
|
+
</span>
|
|
249
|
+
<InspectorSegment>
|
|
250
|
+
<InspectorIconButton
|
|
251
|
+
label={t("editPanel.textDecorations.underline")}
|
|
252
|
+
shortcut="⌘U"
|
|
253
|
+
active={underlineActive}
|
|
254
|
+
onClick={onToggleUnderline}
|
|
255
|
+
>
|
|
256
|
+
<IconUnderline className="size-3.5" />
|
|
257
|
+
</InspectorIconButton>
|
|
258
|
+
<InspectorIconButton
|
|
259
|
+
label={t("editPanel.textDecorations.strikethrough")}
|
|
260
|
+
shortcut="⌘⇧X"
|
|
261
|
+
active={strikethroughActive}
|
|
262
|
+
onClick={onToggleStrikethrough}
|
|
263
|
+
>
|
|
264
|
+
<IconStrikethrough className="size-3.5" />
|
|
265
|
+
</InspectorIconButton>
|
|
266
|
+
</InspectorSegment>
|
|
267
|
+
</div>
|
|
268
|
+
<div className="flex items-center justify-between gap-3">
|
|
269
|
+
<span className="!text-[11px] font-medium text-muted-foreground">
|
|
270
|
+
{t("editPanel.typographyDetails.caseLabel")}
|
|
271
|
+
</span>
|
|
272
|
+
<InspectorSegment>
|
|
273
|
+
<InspectorIconButton
|
|
274
|
+
label={t("editPanel.textCases.none")}
|
|
275
|
+
active={!textCaseIsMixed && textCase === "none"}
|
|
276
|
+
onClick={() => onTextCaseChange("none")}
|
|
277
|
+
>
|
|
278
|
+
<IconLetterCase className="size-3.5" />
|
|
279
|
+
</InspectorIconButton>
|
|
280
|
+
<InspectorIconButton
|
|
281
|
+
label={t("editPanel.textCases.uppercase")}
|
|
282
|
+
active={!textCaseIsMixed && textCase === "uppercase"}
|
|
283
|
+
onClick={() => onTextCaseChange("uppercase")}
|
|
284
|
+
>
|
|
285
|
+
<IconLetterCaseUpper className="size-3.5" />
|
|
286
|
+
</InspectorIconButton>
|
|
287
|
+
<InspectorIconButton
|
|
288
|
+
label={t("editPanel.textCases.lowercase")}
|
|
289
|
+
active={!textCaseIsMixed && textCase === "lowercase"}
|
|
290
|
+
onClick={() => onTextCaseChange("lowercase")}
|
|
291
|
+
>
|
|
292
|
+
<IconLetterCaseLower className="size-3.5" />
|
|
293
|
+
</InspectorIconButton>
|
|
294
|
+
<InspectorIconButton
|
|
295
|
+
label={t("editPanel.textCases.capitalize")}
|
|
296
|
+
active={!textCaseIsMixed && textCase === "capitalize"}
|
|
297
|
+
onClick={() => onTextCaseChange("capitalize")}
|
|
298
|
+
>
|
|
299
|
+
<IconLetterCaseToggle className="size-3.5" />
|
|
300
|
+
</InspectorIconButton>
|
|
301
|
+
</InspectorSegment>
|
|
302
|
+
</div>
|
|
158
303
|
</div>
|
|
159
|
-
|
|
304
|
+
)}
|
|
160
305
|
</PopoverContent>
|
|
161
306
|
</Popover>
|
|
162
307
|
);
|
|
@@ -176,24 +321,6 @@ export function TypographyProperties({
|
|
|
176
321
|
value: option.value,
|
|
177
322
|
label: t(`editPanel.fontFamilies.${option.key}`),
|
|
178
323
|
}));
|
|
179
|
-
const fontFamily = resolveFontFamilySelectValue(styles.fontFamily);
|
|
180
|
-
const fontFamilyOptions = FONT_FAMILY_OPTIONS.some(
|
|
181
|
-
(option) => option.value === fontFamily,
|
|
182
|
-
)
|
|
183
|
-
? baseFontFamilyOptions
|
|
184
|
-
: [
|
|
185
|
-
{
|
|
186
|
-
value: fontFamily,
|
|
187
|
-
label: displayFontFamilyName(styles.fontFamily || fontFamily),
|
|
188
|
-
},
|
|
189
|
-
...baseFontFamilyOptions,
|
|
190
|
-
];
|
|
191
|
-
const fontWeightOptions = FONT_WEIGHT_OPTIONS.map((option) => ({
|
|
192
|
-
value: option.value,
|
|
193
|
-
label: t(`editPanel.fontWeights.${option.key}`),
|
|
194
|
-
}));
|
|
195
|
-
const textAlign = styles.textAlign || "left";
|
|
196
|
-
|
|
197
324
|
// Mixed-selection guards: a multi-selection with differing values injects
|
|
198
325
|
// the MIXED_VALUE sentinel string into these computedStyles fields (see
|
|
199
326
|
// mixedElementFromSelection/sameOrMixed). Parsing that sentinel with
|
|
@@ -202,10 +329,75 @@ export function TypographyProperties({
|
|
|
202
329
|
// fabricated 0 (size), 1.2 (line-height), or blank (tracking) rather than
|
|
203
330
|
// the Mixed state ScrubInput already knows how to render — same pattern as
|
|
204
331
|
// the rotation field above.
|
|
332
|
+
const fontFamilyIsMixed = isMixedValue(styles.fontFamily);
|
|
205
333
|
const fontWeightIsMixed = isMixedValue(styles.fontWeight);
|
|
206
334
|
const fontSizeIsMixed = isMixedValue(styles.fontSize);
|
|
207
335
|
const lineHeightIsMixed = isMixedValue(styles.lineHeight);
|
|
208
336
|
const letterSpacingIsMixed = isMixedValue(styles.letterSpacing);
|
|
337
|
+
const textTransformIsMixed = isMixedValue(styles.textTransform);
|
|
338
|
+
|
|
339
|
+
// Text decoration (underline/strikethrough) reads through the bridge's
|
|
340
|
+
// clean `textDecorationLine` computed longhand (never the composite
|
|
341
|
+
// `textDecoration` shorthand string, which also carries style/color) but
|
|
342
|
+
// WRITES commit through the "textDecoration" property name — see
|
|
343
|
+
// nextTextDecorationLineValue's doc comment in typography-helpers.ts for
|
|
344
|
+
// why the longhand isn't on the persisted-source style allow-list.
|
|
345
|
+
const underlineActive = isTextDecorationLineActive(
|
|
346
|
+
styles.textDecorationLine,
|
|
347
|
+
"underline",
|
|
348
|
+
);
|
|
349
|
+
const strikethroughActive = isTextDecorationLineActive(
|
|
350
|
+
styles.textDecorationLine,
|
|
351
|
+
"line-through",
|
|
352
|
+
);
|
|
353
|
+
const toggleTextDecorationLine = (line: TextDecorationLineToken) => {
|
|
354
|
+
onStyleChange(
|
|
355
|
+
"textDecoration",
|
|
356
|
+
nextTextDecorationLineValue(styles.textDecorationLine, line),
|
|
357
|
+
);
|
|
358
|
+
};
|
|
359
|
+
// Mixed-selection guard mirrors fontWeight/fontFamily above: an
|
|
360
|
+
// indeterminate case across the selection renders with none of the four
|
|
361
|
+
// options highlighted rather than guessing one element's value.
|
|
362
|
+
const textCase = textTransformIsMixed
|
|
363
|
+
? "none"
|
|
364
|
+
: optionValue(TEXT_CASE_OPTIONS, styles.textTransform, "none");
|
|
365
|
+
const setTextCase = (value: string) => onStyleChange("textTransform", value);
|
|
366
|
+
|
|
367
|
+
// resolveFontFamilyFieldValue returns the MIXED_VALUE sentinel unchanged
|
|
368
|
+
// when the selection differs so the Select below can render it as an
|
|
369
|
+
// explicit disabled placeholder (matching fontWeight's pattern just below)
|
|
370
|
+
// instead of a normal, clickable option that could commit the literal
|
|
371
|
+
// string "Mixed" as a font-family value.
|
|
372
|
+
const fontFamily = resolveFontFamilyFieldValue(styles.fontFamily);
|
|
373
|
+
const fontFamilyOptions = fontFamilyIsMixed
|
|
374
|
+
? baseFontFamilyOptions
|
|
375
|
+
: FONT_FAMILY_OPTIONS.some((option) => option.value === fontFamily)
|
|
376
|
+
? baseFontFamilyOptions
|
|
377
|
+
: [
|
|
378
|
+
{
|
|
379
|
+
value: fontFamily,
|
|
380
|
+
label: displayFontFamilyName(styles.fontFamily || fontFamily),
|
|
381
|
+
},
|
|
382
|
+
...baseFontFamilyOptions,
|
|
383
|
+
];
|
|
384
|
+
const baseFontWeightOptions = FONT_WEIGHT_OPTIONS.map((option) => ({
|
|
385
|
+
value: option.value,
|
|
386
|
+
label: t(`editPanel.fontWeights.${option.key}`),
|
|
387
|
+
}));
|
|
388
|
+
// Non-mixed but not one of the nine standard notches (e.g. a variable-font
|
|
389
|
+
// weight like "550") needs the same synthesized-option treatment as an
|
|
390
|
+
// unknown font family — otherwise the Select's value matches no item and
|
|
391
|
+
// renders blank even though the real weight is still applied.
|
|
392
|
+
const currentFontWeight = styles.fontWeight || "400";
|
|
393
|
+
const fontWeightOptions =
|
|
394
|
+
fontWeightIsMixed || isKnownFontWeight(currentFontWeight)
|
|
395
|
+
? baseFontWeightOptions
|
|
396
|
+
: [
|
|
397
|
+
{ value: currentFontWeight, label: currentFontWeight },
|
|
398
|
+
...baseFontWeightOptions,
|
|
399
|
+
];
|
|
400
|
+
const textAlign = styles.textAlign || "left";
|
|
209
401
|
|
|
210
402
|
// M1 · Text resizing mode (auto-width / auto-height / fixed). the design
|
|
211
403
|
// editor's text nodes always expose this segment. Read authored
|
|
@@ -240,8 +432,20 @@ export function TypographyProperties({
|
|
|
240
432
|
: !heightIsAuto && !widthIsAuto
|
|
241
433
|
? "fixed"
|
|
242
434
|
: "auto-height";
|
|
243
|
-
|
|
244
|
-
|
|
435
|
+
// Fall back to the element's actual current on-screen size (not an
|
|
436
|
+
// arbitrary constant) when there's no real authored size yet — converting
|
|
437
|
+
// auto-width/auto-height text to "fixed" must preserve its current
|
|
438
|
+
// rendered size instead of visibly snapping it to a hardcoded default.
|
|
439
|
+
const currentWidth = resolveFixedResizeDimension(
|
|
440
|
+
styles.width,
|
|
441
|
+
widthIsAuto,
|
|
442
|
+
element.boundingRect.width,
|
|
443
|
+
);
|
|
444
|
+
const currentHeight = resolveFixedResizeDimension(
|
|
445
|
+
styles.height,
|
|
446
|
+
heightIsAuto,
|
|
447
|
+
element.boundingRect.height,
|
|
448
|
+
);
|
|
245
449
|
const setResizeMode = (mode: TextResizeMode) => {
|
|
246
450
|
if (mode === "auto-width") {
|
|
247
451
|
onStyleChange("width", "max-content");
|
|
@@ -318,6 +522,15 @@ export function TypographyProperties({
|
|
|
318
522
|
<SelectValue />
|
|
319
523
|
</SelectTrigger>
|
|
320
524
|
<SelectContent>
|
|
525
|
+
{fontFamilyIsMixed ? (
|
|
526
|
+
<SelectItem
|
|
527
|
+
value={MIXED_VALUE}
|
|
528
|
+
disabled
|
|
529
|
+
className="!text-[11px] text-muted-foreground"
|
|
530
|
+
>
|
|
531
|
+
{MIXED_VALUE}
|
|
532
|
+
</SelectItem>
|
|
533
|
+
) : null}
|
|
321
534
|
{fontFamilyOptions.map((opt) => (
|
|
322
535
|
<SelectItem
|
|
323
536
|
key={opt.value}
|
|
@@ -334,7 +547,7 @@ export function TypographyProperties({
|
|
|
334
547
|
{/* Row 2: weight + size side by side */}
|
|
335
548
|
<div className="grid grid-cols-2 gap-1.5">
|
|
336
549
|
<Select
|
|
337
|
-
value={fontWeightIsMixed ? MIXED_VALUE :
|
|
550
|
+
value={fontWeightIsMixed ? MIXED_VALUE : currentFontWeight}
|
|
338
551
|
onValueChange={(v) => onStyleChange("fontWeight", v)}
|
|
339
552
|
>
|
|
340
553
|
<SelectTrigger className="h-6 rounded-md border-[var(--design-editor-control-border)] bg-[var(--design-editor-control-bg)] px-1.5 !text-[11px] shadow-none focus:ring-1 focus:ring-[var(--design-editor-accent-color)]">
|
|
@@ -364,7 +577,7 @@ export function TypographyProperties({
|
|
|
364
577
|
<ScrubInput
|
|
365
578
|
label={t("editPanel.labels.size")}
|
|
366
579
|
ariaLabel={t("editPanel.labels.size")}
|
|
367
|
-
icon={
|
|
580
|
+
icon={IconTextSize}
|
|
368
581
|
value={
|
|
369
582
|
fontSizeIsMixed
|
|
370
583
|
? 0
|
|
@@ -493,6 +706,15 @@ export function TypographyProperties({
|
|
|
493
706
|
<TypographyDetailsPopover
|
|
494
707
|
resizeMode={resizeMode}
|
|
495
708
|
onResizeModeChange={setResizeMode}
|
|
709
|
+
underlineActive={underlineActive}
|
|
710
|
+
strikethroughActive={strikethroughActive}
|
|
711
|
+
onToggleUnderline={() => toggleTextDecorationLine("underline")}
|
|
712
|
+
onToggleStrikethrough={() =>
|
|
713
|
+
toggleTextDecorationLine("line-through")
|
|
714
|
+
}
|
|
715
|
+
textCase={textCase}
|
|
716
|
+
textCaseIsMixed={textTransformIsMixed}
|
|
717
|
+
onTextCaseChange={setTextCase}
|
|
496
718
|
/>
|
|
497
719
|
</div>
|
|
498
720
|
</div>
|