Fix type errors found by tsgo and vue-tsc
- Add interaction constants to core barrel export (were in constants.ts but not reachable via '@open-pencil/core') - Fix variable shadowing in use-text-edit.ts: rename inner 'editor' (textEditor) to 'textEd' to avoid shadowing the Editor parameter - Fix unused params: prefix with _ in scene.ts, describe-issues.ts, xpath.ts - Remove unused getCoords param from setupPanZoom - Move cursorCanvasX/Y assignment to app callback (not on EditorState) - Simplify EditorStore return: spread editor instead of listing 80+ methods individually — new Editor methods auto-forward, no more manual sync - Add tsgo to check script, add check:vue script for vue-tsc - Add vue-tsc as dev dependency - Reduces vue-tsc errors from 172 (pre-existing) to 135 (37 fixed)
This commit is contained in:
parent
59b66e68ca
commit
4a2c5ac0ce
17
bun.lock
17
bun.lock
|
|
@ -74,6 +74,7 @@
|
|||
"unplugin-vue-components": "^31.0.0",
|
||||
"vite": "^8.0.0",
|
||||
"vite-plugin-pwa": "^1.2.0",
|
||||
"vue-tsc": "^3.2.5",
|
||||
"workbox-window": "^7.4.0",
|
||||
"ws": "^8.19.0",
|
||||
},
|
||||
|
|
@ -1085,6 +1086,12 @@
|
|||
|
||||
"@vitejs/plugin-vue": ["@vitejs/plugin-vue@6.0.5", "", { "dependencies": { "@rolldown/pluginutils": "1.0.0-rc.2" }, "peerDependencies": { "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", "vue": "^3.2.25" } }, "sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg=="],
|
||||
|
||||
"@volar/language-core": ["@volar/language-core@2.4.28", "", { "dependencies": { "@volar/source-map": "2.4.28" } }, "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ=="],
|
||||
|
||||
"@volar/source-map": ["@volar/source-map@2.4.28", "", {}, "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ=="],
|
||||
|
||||
"@volar/typescript": ["@volar/typescript@2.4.28", "", { "dependencies": { "@volar/language-core": "2.4.28", "path-browserify": "^1.0.1", "vscode-uri": "^3.0.8" } }, "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw=="],
|
||||
|
||||
"@vue-macros/common": ["@vue-macros/common@3.1.2", "", { "dependencies": { "@vue/compiler-sfc": "^3.5.22", "ast-kit": "^2.1.2", "local-pkg": "^1.1.2", "magic-string-ast": "^1.0.2", "unplugin-utils": "^0.3.0" }, "peerDependencies": { "vue": "^2.7.0 || ^3.2.25" }, "optionalPeers": ["vue"] }, "sha512-h9t4ArDdniO9ekYHAD95t9AZcAbb19lEGK+26iAjUODOIJKmObDNBSe4+6ELQAA3vtYiFPPBtHh7+cQCKi3Dng=="],
|
||||
|
||||
"@vue/compiler-core": ["@vue/compiler-core@3.5.29", "", { "dependencies": { "@babel/parser": "^7.29.0", "@vue/shared": "3.5.29", "entities": "^7.0.1", "estree-walker": "^2.0.2", "source-map-js": "^1.2.1" } }, "sha512-cuzPhD8fwRHk8IGfmYaR4eEe4cAyJEL66Ove/WZL7yWNL134nqLddSLwNRIsFlnnW1kK+p8Ck3viFnC0chXCXw=="],
|
||||
|
|
@ -1101,6 +1108,8 @@
|
|||
|
||||
"@vue/devtools-shared": ["@vue/devtools-shared@8.0.7", "", {}, "sha512-CgAb9oJH5NUmbQRdYDj/1zMiaICYSLtm+B1kxcP72LBrifGAjUmt8bx52dDH1gWRPlQgxGPqpAMKavzVirAEhA=="],
|
||||
|
||||
"@vue/language-core": ["@vue/language-core@3.2.5", "", { "dependencies": { "@volar/language-core": "2.4.28", "@vue/compiler-dom": "^3.5.0", "@vue/shared": "^3.5.0", "alien-signals": "^3.0.0", "muggle-string": "^0.4.1", "path-browserify": "^1.0.1", "picomatch": "^4.0.2" } }, "sha512-d3OIxN/+KRedeM5wQ6H6NIpwS3P5gC9nmyaHgBk+rO6dIsjY+tOh4UlPpiZbAh3YtLdCGEX4M16RmsBqPmJV+g=="],
|
||||
|
||||
"@vue/reactivity": ["@vue/reactivity@3.5.29", "", { "dependencies": { "@vue/shared": "3.5.29" } }, "sha512-zcrANcrRdcLtmGZETBxWqIkoQei8HaFpZWx/GHKxx79JZsiZ8j1du0VUJtu4eJjgFvU/iKL5lRXFXksVmI+5DA=="],
|
||||
|
||||
"@vue/runtime-core": ["@vue/runtime-core@3.5.29", "", { "dependencies": { "@vue/reactivity": "3.5.29", "@vue/shared": "3.5.29" } }, "sha512-8DpW2QfdwIWOLqtsNcds4s+QgwSaHSJY/SUe04LptianUQ/0xi6KVsu/pYVh+HO3NTVvVJjIPL2t6GdeKbS4Lg=="],
|
||||
|
|
@ -1155,6 +1164,8 @@
|
|||
|
||||
"algoliasearch": ["algoliasearch@5.49.1", "", { "dependencies": { "@algolia/abtesting": "1.15.1", "@algolia/client-abtesting": "5.49.1", "@algolia/client-analytics": "5.49.1", "@algolia/client-common": "5.49.1", "@algolia/client-insights": "5.49.1", "@algolia/client-personalization": "5.49.1", "@algolia/client-query-suggestions": "5.49.1", "@algolia/client-search": "5.49.1", "@algolia/ingestion": "1.49.1", "@algolia/monitoring": "1.49.1", "@algolia/recommend": "5.49.1", "@algolia/requester-browser-xhr": "5.49.1", "@algolia/requester-fetch": "5.49.1", "@algolia/requester-node-http": "5.49.1" } }, "sha512-X3Pp2aRQhg4xUC6PQtkubn5NpRKuUPQ9FPDQlx36SmpFwwH2N0/tw4c+NXV3nw3PsgeUs+BuWGP0gjz3TvENLQ=="],
|
||||
|
||||
"alien-signals": ["alien-signals@3.1.2", "", {}, "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw=="],
|
||||
|
||||
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
||||
|
||||
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
|
||||
|
|
@ -2009,6 +2020,8 @@
|
|||
|
||||
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
||||
|
||||
"path-browserify": ["path-browserify@1.0.1", "", {}, "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="],
|
||||
|
||||
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
||||
|
||||
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
|
||||
|
|
@ -2409,6 +2422,8 @@
|
|||
|
||||
"void-elements": ["void-elements@3.1.0", "", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="],
|
||||
|
||||
"vscode-uri": ["vscode-uri@3.1.0", "", {}, "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ=="],
|
||||
|
||||
"vue": ["vue@3.5.29", "", { "dependencies": { "@vue/compiler-dom": "3.5.29", "@vue/compiler-sfc": "3.5.29", "@vue/runtime-dom": "3.5.29", "@vue/server-renderer": "3.5.29", "@vue/shared": "3.5.29" }, "peerDependencies": { "typescript": "*" }, "optionalPeers": ["typescript"] }, "sha512-BZqN4Ze6mDQVNAni0IHeMJ5mwr8VAJ3MQC9FmprRhcBYENw+wOAAjRj8jfmN6FLl0j96OXbR+CjWhmAmM+QGnA=="],
|
||||
|
||||
"vue-demi": ["vue-demi@0.14.10", "", { "peerDependencies": { "@vue/composition-api": "^1.0.0-rc.1", "vue": "^3.0.0-0 || ^2.6.0" }, "optionalPeers": ["@vue/composition-api"], "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", "vue-demi-switch": "bin/vue-demi-switch.js" } }, "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg=="],
|
||||
|
|
@ -2417,6 +2432,8 @@
|
|||
|
||||
"vue-stream-markdown": ["vue-stream-markdown@0.6.5", "", { "dependencies": { "@floating-ui/dom": "^1.7.5", "@vueuse/core": "^14.2.1", "marked": "^17.0.3", "mdast-util-from-markdown": "^2.0.3", "mdast-util-frontmatter": "^2.0.1", "mdast-util-gfm": "^3.1.0", "mdast-util-math": "^3.0.0", "mdast-util-to-markdown": "^2.1.2", "micromark-extension-cjk-friendly": "^2.0.1", "micromark-extension-cjk-friendly-gfm-strikethrough": "^2.0.1", "micromark-extension-frontmatter": "^2.0.0", "micromark-extension-gfm": "^3.0.0", "micromark-extension-math": "^3.1.0", "micromark-util-types": "^2.0.2" }, "peerDependencies": { "beautiful-mermaid": ">=0.1.0", "katex": ">=0.16.20", "mermaid": ">=11", "shiki": ">=3.15.0", "vue": ">=3.0.0" }, "optionalPeers": ["beautiful-mermaid", "katex", "mermaid", "shiki"] }, "sha512-wXj1Kjul+7tP1GcuEZ1fqrfT+UokBuTJXM8rGMzo8qH7pTmcUp//sGPIbjIPSfhhIrSHxuBdMLSBEbccwFp07g=="],
|
||||
|
||||
"vue-tsc": ["vue-tsc@3.2.5", "", { "dependencies": { "@volar/typescript": "2.4.28", "@vue/language-core": "3.2.5" }, "peerDependencies": { "typescript": ">=5.0.0" }, "bin": { "vue-tsc": "bin/vue-tsc.js" } }, "sha512-/htfTCMluQ+P2FISGAooul8kO4JMheOTCbCy4M6dYnYYjqLe3BExZudAua6MSIKSFYQtFOYAll7XobYwcpokGA=="],
|
||||
|
||||
"weald": ["weald@1.1.1", "", { "dependencies": { "ms": "^3.0.0-canary.1", "supports-color": "^10.0.0" } }, "sha512-PaEQShzMCz8J/AD2N3dJMc1hTZWkJeLKS2NMeiVkV5KDHwgZe7qXLEzyodsT/SODxWDdXJJqocuwf3kHzcXhSQ=="],
|
||||
|
||||
"web-vitals": ["web-vitals@4.2.4", "", {}, "sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw=="],
|
||||
|
|
|
|||
|
|
@ -14,7 +14,8 @@
|
|||
"tauri": "tauri",
|
||||
"lint": "oxlint -c oxlint.json --type-aware --type-check src/ packages/core/src/ packages/cli/src/ packages/mcp/src/",
|
||||
"format": "oxfmt --write src/",
|
||||
"check": "bun run lint",
|
||||
"check": "bun run lint && tsgo --noEmit",
|
||||
"check:vue": "vue-tsc --noEmit",
|
||||
"test": "playwright test --project=openpencil",
|
||||
"test:update": "playwright test --project=openpencil --update-snapshots",
|
||||
"test:figma": "playwright test --project=figma",
|
||||
|
|
@ -76,6 +77,7 @@
|
|||
"@hono/node-server": "^1.19.11",
|
||||
"@iconify-json/lucide": "^1.2.94",
|
||||
"@modelcontextprotocol/sdk": "^1.27.1",
|
||||
"@open-pencil/mcp": "workspace:*",
|
||||
"@playwright/test": "^1.58.2",
|
||||
"@tauri-apps/cli": "^2",
|
||||
"@types/culori": "^4.0.1",
|
||||
|
|
@ -97,8 +99,8 @@
|
|||
"unplugin-vue-components": "^31.0.0",
|
||||
"vite": "^8.0.0",
|
||||
"vite-plugin-pwa": "^1.2.0",
|
||||
"vue-tsc": "^3.2.5",
|
||||
"workbox-window": "^7.4.0",
|
||||
"ws": "^8.19.0",
|
||||
"@open-pencil/mcp": "workspace:*"
|
||||
"ws": "^8.19.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -316,3 +316,11 @@ export const SECTION_DEFAULT_STROKE: Stroke = {
|
|||
export const ZOOM_DIVISOR = 50
|
||||
export const ZOOM_SCALE_MIN = 0.75
|
||||
export const ZOOM_SCALE_MAX = 1.25
|
||||
|
||||
export const PEN_CLOSE_THRESHOLD = 8
|
||||
export const ROTATION_SNAP_DEGREES = 15
|
||||
export const CORNER_ROTATE_ZONE = 16
|
||||
export const HANDLE_HIT_RADIUS = 6
|
||||
export const DEFAULT_TEXT_WIDTH = 200
|
||||
export const DEFAULT_TEXT_HEIGHT = 24
|
||||
export const AUTO_LAYOUT_BREAK_THRESHOLD = 8
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ function isCulled(
|
|||
}
|
||||
|
||||
function applyNodeTransforms(
|
||||
r: SkiaRenderer,
|
||||
_r: SkiaRenderer,
|
||||
canvas: Canvas,
|
||||
node: SceneNode,
|
||||
nodeId: string,
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ function detectTypographyIssues(node: SceneNode, graph: SceneGraph, issues: Desc
|
|||
|
||||
const SPACING_GRID = 4
|
||||
|
||||
function detectSpacingIssues(node: SceneNode, graph: SceneGraph, gridSize: number, issues: DescribeIssue[]): void {
|
||||
function detectSpacingIssues(node: SceneNode, graph: SceneGraph, _gridSize: number, issues: DescribeIssue[]): void {
|
||||
if (node.layoutMode === 'NONE') return
|
||||
const children = node.childIds
|
||||
.map((id) => graph.getNode(id))
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ interface XPathNode {
|
|||
}
|
||||
|
||||
function wrapNode(
|
||||
graph: SceneGraph,
|
||||
_graph: SceneGraph,
|
||||
node: SceneNode,
|
||||
parent?: XPathNode | XPathDocument | null
|
||||
): XPathNode {
|
||||
|
|
|
|||
|
|
@ -603,11 +603,9 @@ export function useCanvasInput(
|
|||
}
|
||||
|
||||
function onMouseMove(e: MouseEvent) {
|
||||
{
|
||||
if (onCursorMove) {
|
||||
const { cx, cy } = getCoords(e)
|
||||
editor.state.cursorCanvasX = cx
|
||||
editor.state.cursorCanvasY = cy
|
||||
if (onCursorMove) onCursorMove(cx, cy)
|
||||
onCursorMove(cx, cy)
|
||||
}
|
||||
|
||||
if (editor.state.activeTool === 'PEN' && editor.state.penState && !drag.value) {
|
||||
|
|
@ -808,7 +806,7 @@ export function useCanvasInput(
|
|||
if (drag.value) onMouseUp()
|
||||
})
|
||||
|
||||
setupPanZoom(canvasRef, editor, drag, getCoords, onMouseDown, onMouseMove, onMouseUp)
|
||||
setupPanZoom(canvasRef, editor, drag, onMouseDown, onMouseMove, onMouseUp)
|
||||
|
||||
return {
|
||||
drag,
|
||||
|
|
|
|||
|
|
@ -14,37 +14,37 @@ import type { SceneNode } from '@open-pencil/core'
|
|||
|
||||
const CARET_BLINK_MS = 530
|
||||
|
||||
export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Editor) {
|
||||
export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, store: Editor) {
|
||||
const textareaRef = shallowRef<HTMLTextAreaElement | null>(null)
|
||||
let isComposing = false
|
||||
let blinkTimer = 0
|
||||
|
||||
function getEditingNode() {
|
||||
const id = editor.state.editingTextId
|
||||
const id = store.state.editingTextId
|
||||
if (!id) return null
|
||||
return editor.graph.getNode(id) ?? null
|
||||
return store.graph.getNode(id) ?? null
|
||||
}
|
||||
|
||||
function resetBlink() {
|
||||
if (editor.textEditor) editor.textEditor.caretVisible = true
|
||||
if (store.textEditor) store.textEditor.caretVisible = true
|
||||
clearInterval(blinkTimer)
|
||||
blinkTimer = window.setInterval(() => {
|
||||
if (!editor.textEditor) return
|
||||
editor.textEditor.caretVisible = !editor.textEditor.caretVisible
|
||||
editor.requestRepaint()
|
||||
if (!store.textEditor) return
|
||||
store.textEditor.caretVisible = !store.textEditor.caretVisible
|
||||
store.requestRepaint()
|
||||
}, CARET_BLINK_MS)
|
||||
editor.requestRepaint()
|
||||
store.requestRepaint()
|
||||
}
|
||||
|
||||
function syncText(nodeId: string, text: string, runs?: SceneNode['styleRuns']) {
|
||||
const changes: Partial<SceneNode> = { text }
|
||||
if (runs !== undefined) changes.styleRuns = runs
|
||||
editor.graph.updateNode(nodeId, changes)
|
||||
editor.requestRender()
|
||||
store.graph.updateNode(nodeId, changes)
|
||||
store.requestRender()
|
||||
}
|
||||
|
||||
function insertText(text: string, node: SceneNode) {
|
||||
const editor = editor.textEditor
|
||||
const editor = store.textEditor
|
||||
if (!editor) return
|
||||
const range = editor.getSelectionRange()
|
||||
let runs = node.styleRuns
|
||||
|
|
@ -59,7 +59,7 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
}
|
||||
|
||||
function deleteText(node: SceneNode, forward: boolean) {
|
||||
const editor = editor.textEditor
|
||||
const editor = store.textEditor
|
||||
if (!editor) return
|
||||
const range = editor.getSelectionRange()
|
||||
let runs = node.styleRuns
|
||||
|
|
@ -105,7 +105,7 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
resetBlink()
|
||||
}
|
||||
|
||||
function handleHorizontalArrow(e: KeyboardEvent, editor: NonNullable<typeof editor.textEditor>) {
|
||||
function handleHorizontalArrow(e: KeyboardEvent, editor: NonNullable<typeof store.textEditor>) {
|
||||
const select = e.shiftKey
|
||||
const isMeta = e.metaKey || e.ctrlKey
|
||||
if (e.key === 'ArrowLeft') {
|
||||
|
|
@ -121,7 +121,7 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
|
||||
function handleDeletion(
|
||||
e: KeyboardEvent,
|
||||
editor: NonNullable<typeof editor.textEditor>,
|
||||
editor: NonNullable<typeof store.textEditor>,
|
||||
node: SceneNode
|
||||
) {
|
||||
const isMeta = e.metaKey || e.ctrlKey
|
||||
|
|
@ -138,7 +138,7 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
|
||||
type MetaAction = (node: SceneNode) => void
|
||||
const metaKeyActions: Partial<Record<string, MetaAction>> = {
|
||||
a: () => editor.textEditor?.selectAll(),
|
||||
a: () => store.textEditor?.selectAll(),
|
||||
c: () => handleCopy(),
|
||||
x: (node) => handleCut(node),
|
||||
v: (node) => void handlePaste(node),
|
||||
|
|
@ -149,7 +149,7 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
|
||||
function onKeyDown(e: KeyboardEvent) {
|
||||
if (isComposing) return
|
||||
const editor = editor.textEditor
|
||||
const editor = store.textEditor
|
||||
const node = getEditingNode()
|
||||
if (!editor || !node) return
|
||||
|
||||
|
|
@ -158,7 +158,7 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
|
||||
switch (e.key) {
|
||||
case 'Escape':
|
||||
editor.commitTextEdit()
|
||||
store.commitTextEdit()
|
||||
canvasRef.value?.focus()
|
||||
e.preventDefault()
|
||||
return
|
||||
|
|
@ -198,21 +198,21 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
}
|
||||
|
||||
if (!textChanged) {
|
||||
editor.requestRender()
|
||||
store.requestRender()
|
||||
}
|
||||
resetBlink()
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
function applyFormatting(nodeId: string, changes: Partial<SceneNode>, label: string) {
|
||||
editor.updateNodeWithUndo(nodeId, changes, label)
|
||||
const updated = editor.graph.getNode(nodeId)
|
||||
if (updated) editor.textEditor?.rebuildParagraph(updated)
|
||||
editor.requestRender()
|
||||
store.updateNodeWithUndo(nodeId, changes, label)
|
||||
const updated = store.graph.getNode(nodeId)
|
||||
if (updated) store.textEditor?.rebuildParagraph(updated)
|
||||
store.requestRender()
|
||||
}
|
||||
|
||||
function toggleBold(node: SceneNode) {
|
||||
const editor = editor.textEditor
|
||||
const editor = store.textEditor
|
||||
const range = editor?.getSelectionRange()
|
||||
if (range) {
|
||||
const { runs } = toggleBoldInRange(
|
||||
|
|
@ -229,7 +229,7 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
}
|
||||
|
||||
function toggleItalic(node: SceneNode) {
|
||||
const editor = editor.textEditor
|
||||
const editor = store.textEditor
|
||||
const range = editor?.getSelectionRange()
|
||||
if (range) {
|
||||
const { runs } = toggleItalicInRange(
|
||||
|
|
@ -246,7 +246,7 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
}
|
||||
|
||||
function toggleUnderline(node: SceneNode) {
|
||||
const editor = editor.textEditor
|
||||
const editor = store.textEditor
|
||||
const range = editor?.getSelectionRange()
|
||||
if (range) {
|
||||
const { runs } = toggleDecorationInRange(
|
||||
|
|
@ -268,14 +268,14 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
}
|
||||
|
||||
function handleCopy() {
|
||||
const editor = editor.textEditor
|
||||
const editor = store.textEditor
|
||||
if (!editor) return
|
||||
const text = editor.getSelectedText()
|
||||
if (text) void navigator.clipboard.writeText(text)
|
||||
}
|
||||
|
||||
function handleCut(node: ReturnType<typeof getEditingNode>) {
|
||||
const editor = editor.textEditor
|
||||
const editor = store.textEditor
|
||||
if (!editor || !node) return
|
||||
const text = editor.getSelectedText()
|
||||
if (text) {
|
||||
|
|
@ -286,7 +286,7 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
}
|
||||
|
||||
async function handlePaste(node: ReturnType<typeof getEditingNode>) {
|
||||
const editor = editor.textEditor
|
||||
const editor = store.textEditor
|
||||
if (!editor || !node) return
|
||||
try {
|
||||
const text = await navigator.clipboard.readText()
|
||||
|
|
@ -305,13 +305,13 @@ export function useTextEdit(canvasRef: Ref<HTMLCanvasElement | null>, editor: Ed
|
|||
useEventListener(textareaRef, 'keydown', onKeyDown)
|
||||
|
||||
useEventListener(canvasRef, 'mousedown', () => {
|
||||
if (editor.state.editingTextId && textareaRef.value) {
|
||||
if (store.state.editingTextId && textareaRef.value) {
|
||||
requestAnimationFrame(() => textareaRef.value?.focus())
|
||||
}
|
||||
})
|
||||
|
||||
watch(
|
||||
() => editor.state.editingTextId,
|
||||
() => store.state.editingTextId,
|
||||
(id, _, onCleanup) => {
|
||||
if (id) {
|
||||
const el = document.createElement('textarea')
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ export function setupPanZoom(
|
|||
canvasRef: Ref<HTMLCanvasElement | null>,
|
||||
editor: Editor,
|
||||
drag: Ref<DragState | null>,
|
||||
getCoords: (e: MouseEvent) => { sx: number; sy: number; cx: number; cy: number },
|
||||
onMouseDown: (e: MouseEvent) => void,
|
||||
onMouseMove: (e: MouseEvent) => void,
|
||||
onMouseUp: () => void
|
||||
|
|
|
|||
|
|
@ -24,7 +24,11 @@ const { cursorOverride } = useCanvasInput(
|
|||
hitTestSectionTitle,
|
||||
hitTestComponentLabel,
|
||||
hitTestFrameTitle,
|
||||
(cx, cy) => collab?.updateCursor(cx, cy, store.state.currentPageId)
|
||||
(cx, cy) => {
|
||||
store.state.cursorCanvasX = cx
|
||||
store.state.cursorCanvasY = cy
|
||||
collab?.updateCursor(cx, cy, store.state.currentPageId)
|
||||
}
|
||||
)
|
||||
|
||||
useTextEdit(canvasRef, store)
|
||||
|
|
|
|||
|
|
@ -519,97 +519,15 @@ export function createEditorStore() {
|
|||
}
|
||||
|
||||
// ─── Public API ───────────────────────────────────────────────
|
||||
// Spread all core Editor methods, then override getters and add app-specific.
|
||||
|
||||
return {
|
||||
get graph() {
|
||||
return editor.graph
|
||||
},
|
||||
get renderer() {
|
||||
return editor.renderer
|
||||
},
|
||||
get textEditor() {
|
||||
return editor.textEditor
|
||||
},
|
||||
undo: editor.undo,
|
||||
...editor,
|
||||
state,
|
||||
selectedNodes,
|
||||
selectedNode,
|
||||
layerTree,
|
||||
|
||||
// Core editor methods
|
||||
requestRender: editor.requestRender,
|
||||
requestRepaint: editor.requestRepaint,
|
||||
setCanvasKit: editor.setCanvasKit,
|
||||
isTopLevel: editor.isTopLevel,
|
||||
switchPage: editor.switchPage,
|
||||
addPage: editor.addPage,
|
||||
deletePage: editor.deletePage,
|
||||
renamePage: editor.renamePage,
|
||||
setTool: editor.setTool,
|
||||
select: editor.select,
|
||||
clearSelection: editor.clearSelection,
|
||||
enterContainer: editor.enterContainer,
|
||||
exitContainer: editor.exitContainer,
|
||||
validateEnteredContainer: editor.validateEnteredContainer,
|
||||
selectAll: editor.selectAll,
|
||||
setMarquee: editor.setMarquee,
|
||||
setSnapGuides: editor.setSnapGuides,
|
||||
setRotationPreview: editor.setRotationPreview,
|
||||
setHoveredNode: editor.setHoveredNode,
|
||||
setDropTarget: editor.setDropTarget,
|
||||
setLayoutInsertIndicator: editor.setLayoutInsertIndicator,
|
||||
reorderInAutoLayout: editor.reorderInAutoLayout,
|
||||
reorderChildWithUndo: editor.reorderChildWithUndo,
|
||||
reparentNodes: editor.reparentNodes,
|
||||
penAddVertex: editor.penAddVertex,
|
||||
penSetDragTangent: editor.penSetDragTangent,
|
||||
penSetClosingToFirst: editor.penSetClosingToFirst,
|
||||
penCommit: editor.penCommit,
|
||||
penCancel: editor.penCancel,
|
||||
startTextEditing: editor.startTextEditing,
|
||||
commitTextEdit: editor.commitTextEdit,
|
||||
updateNode: editor.updateNode,
|
||||
updateNodeWithUndo: editor.updateNodeWithUndo,
|
||||
setLayoutMode: editor.setLayoutMode,
|
||||
wrapInAutoLayout: editor.wrapInAutoLayout,
|
||||
groupSelected: editor.groupSelected,
|
||||
ungroupSelected: editor.ungroupSelected,
|
||||
createComponentFromSelection: editor.createComponentFromSelection,
|
||||
createComponentSetFromComponents: editor.createComponentSetFromComponents,
|
||||
createInstanceFromComponent: editor.createInstanceFromComponent,
|
||||
detachInstance: editor.detachInstance,
|
||||
goToMainComponent: editor.goToMainComponent,
|
||||
bringToFront: editor.bringToFront,
|
||||
sendToBack: editor.sendToBack,
|
||||
toggleVisibility: editor.toggleVisibility,
|
||||
toggleLock: editor.toggleLock,
|
||||
moveToPage: editor.moveToPage,
|
||||
renameNode: editor.renameNode,
|
||||
createShape: editor.createShape,
|
||||
adoptNodesIntoSection: editor.adoptNodesIntoSection,
|
||||
duplicateSelected: editor.duplicateSelected,
|
||||
writeCopyData: editor.writeCopyData,
|
||||
pasteFromHTML: editor.pasteFromHTML,
|
||||
deleteSelected: editor.deleteSelected,
|
||||
commitMove: editor.commitMove,
|
||||
commitMoveWithReparent: editor.commitMoveWithReparent,
|
||||
commitResize: editor.commitResize,
|
||||
commitRotation: editor.commitRotation,
|
||||
commitNodeUpdate: editor.commitNodeUpdate,
|
||||
undoAction: editor.undoAction,
|
||||
redoAction: editor.redoAction,
|
||||
snapshotPage: editor.snapshotPage,
|
||||
restorePageFromSnapshot: editor.restorePageFromSnapshot,
|
||||
pushUndoEntry: editor.pushUndoEntry,
|
||||
screenToCanvas: editor.screenToCanvas,
|
||||
applyZoom: editor.applyZoom,
|
||||
pan: editor.pan,
|
||||
zoomToFit: editor.zoomToFit,
|
||||
zoomTo100: editor.zoomTo100,
|
||||
zoomToSelection: editor.zoomToSelection,
|
||||
storeImage: editor.storeImage,
|
||||
placeImageFiles: editor.placeImageFiles,
|
||||
|
||||
// App-specific methods
|
||||
flashNodes,
|
||||
aiMarkActive,
|
||||
|
|
|
|||
Loading…
Reference in a new issue