From f3fbc94abf97eedd8ab5dd7bc9442d8aae367a13 Mon Sep 17 00:00:00 2001 From: Danila Poyarkov Date: Mon, 20 Jul 2026 21:22:30 +0300 Subject: [PATCH] feat(text): create text boxes by dragging --- packages/vue/src/canvas/tool-input/use.ts | 4 ++-- packages/vue/src/shared/input/draw.ts | 24 +++++++++++++++++------ tests/e2e/text/editing.spec.ts | 23 +++++++++++++++++++++- tests/helpers/store.ts | 3 ++- 4 files changed, 44 insertions(+), 10 deletions(-) diff --git a/packages/vue/src/canvas/tool-input/use.ts b/packages/vue/src/canvas/tool-input/use.ts index a522ef107..3d3a81843 100644 --- a/packages/vue/src/canvas/tool-input/use.ts +++ b/packages/vue/src/canvas/tool-input/use.ts @@ -3,7 +3,7 @@ import type { Ref } from 'vue' import type { Editor } from '@open-pencil/core/editor' import { startPenInput } from '#vue/canvas/pen-input/use' -import { startShapeDraw, startTextTool } from '#vue/shared/input/draw' +import { startShapeDraw, startTextDraw } from '#vue/shared/input/draw' import { startPanDrag } from '#vue/shared/input/pan' import { handleSelectDown } from '#vue/shared/input/select' import type { HitTestFns } from '#vue/shared/input/select' @@ -67,7 +67,7 @@ export function handleToolMouseDown({ } if (tool === 'TEXT') { - startTextTool(cx, cy, editor) + startTextDraw(cx, cy, editor, setDrag) return } diff --git a/packages/vue/src/shared/input/draw.ts b/packages/vue/src/shared/input/draw.ts index c59438323..809252548 100644 --- a/packages/vue/src/shared/input/draw.ts +++ b/packages/vue/src/shared/input/draw.ts @@ -4,13 +4,17 @@ import type { Editor } from '@open-pencil/core/editor' import { TOOL_TO_NODE } from '#vue/shared/input/types' import type { DragDraw, DragState } from '#vue/shared/input/types' -export function startTextTool(cx: number, cy: number, editor: Editor) { - const nodeId = editor.createShape('TEXT', cx, cy, DEFAULT_TEXT_WIDTH, DEFAULT_TEXT_HEIGHT) +export function startTextDraw( + cx: number, + cy: number, + editor: Editor, + setDrag: (d: DragState) => void +) { + editor.undo.beginBatch('Create text') + const nodeId = editor.createShape('TEXT', cx, cy, 0, 0) editor.graph.updateNode(nodeId, { text: '' }) editor.select([nodeId]) - editor.startTextEditing(nodeId) - editor.setTool('SELECT') - editor.requestRender() + setDrag({ type: 'draw', startX: cx, startY: cy, nodeId }) } export function startShapeDraw( @@ -54,7 +58,14 @@ export function handleDrawMove( export function handleDrawUp(d: DragDraw, editor: Editor) { const node = editor.graph.getNode(d.nodeId) - if (node && node.width < 2 && node.height < 2) { + if (node?.type === 'TEXT') { + const isPointText = node.width < 2 && node.height < 2 + editor.updateNode(d.nodeId, { + width: isPointText ? DEFAULT_TEXT_WIDTH : node.width, + height: isPointText ? DEFAULT_TEXT_HEIGHT : node.height, + textAutoResize: isPointText ? 'WIDTH_AND_HEIGHT' : 'NONE' + }) + } else if (node && node.width < 2 && node.height < 2) { editor.updateNode(d.nodeId, { width: 100, height: 100 }) } if (node?.type === 'SECTION') { @@ -63,4 +74,5 @@ export function handleDrawUp(d: DragDraw, editor: Editor) { editor.commitResize(d.nodeId, { x: d.startX, y: d.startY, width: 0, height: 0 }) editor.undo.commitBatch() editor.setTool('SELECT') + if (node?.type === 'TEXT') editor.startTextEditing(node.id) } diff --git a/tests/e2e/text/editing.spec.ts b/tests/e2e/text/editing.spec.ts index 6674c7c23..8dc079191 100644 --- a/tests/e2e/text/editing.spec.ts +++ b/tests/e2e/text/editing.spec.ts @@ -39,9 +39,10 @@ test('clicking with text tool creates a text node', async () => { expect(textNode).toBeTruthy() }) -test('text node is selected after creation', async () => { +test('point text is selected and auto-sizes after creation', async () => { const node = await getSelectedNode(editor.page) expect(node?.type).toBe('TEXT') + expect(node?.textAutoResize).toBe('WIDTH_AND_HEIGHT') }) test('typography section appears for text node', async () => { @@ -63,6 +64,26 @@ test('text node has default font properties', async () => { expect(node?.fontFamily).toBeTruthy() }) +test('dragging with the text tool creates a fixed-width text box', async () => { + await editor.page.keyboard.press('Escape') + await editor.page.keyboard.press('t') + await editor.canvas.drag(300, 120, 520, 240) + await editor.canvas.waitForRender() + + const node = expectDefined(await getSelectedNode(editor.page), 'selected text box') + expect(node.type).toBe('TEXT') + expect(node.width).toBeCloseTo(220) + expect(node.height).toBeCloseTo(120) + expect(node.textAutoResize).toBe('NONE') + + const editingTextId = await editor.page.evaluate(() => { + const store = window.openPencil?.getStore?.() + if (!store) throw new Error('OpenPencil store not initialized') + return store.state.editingTextId + }) + expect(editingTextId).toBe(node.id) +}) + test('creating text via store works', async () => { await editor.page.keyboard.press('Escape') await editor.canvas.waitForRender() diff --git a/tests/helpers/store.ts b/tests/helpers/store.ts index f7139a2d3..c8a05666a 100644 --- a/tests/helpers/store.ts +++ b/tests/helpers/store.ts @@ -60,7 +60,8 @@ export function getSelectedNode(page: Page) { fontSize: n.fontSize, fontFamily: n.fontFamily, fontWeight: n.fontWeight, - italic: n.italic + italic: n.italic, + textAutoResize: n.textAutoResize } }) }