openpencil/packages/vue/src/canvas/text-edit/textarea.ts
Danila Poyarkov 7a02ee2c62
feat(editor): model split canvas panes (#519)
* refactor(editor): separate canvas view state

- Classify shared and view-local editor state explicitly

- Let canvas surfaces render supplied view state and report their viewport

- Preserve the existing one-canvas behavior by default

* fix(canvas): preserve loading render state

* feat(editor): model split canvas panes

- Add pure recursive split-tree operations with validated sizes

- Add explicit pane registry and independent view-state cloning

- Cap visible panes and cover close and split behavior

* refactor(editor): group state ownership modules

- Move shared and view state into the editor state namespace

- Model the partition with explicit interfaces and default factories

- Derive runtime view keys from the default view object

* feat(editor): model split canvas panes

- Add pure recursive split-tree operations with validated sizes

- Add explicit pane registry and independent view-state cloning

- Cap visible panes and cover close and split behavior

* feat(editor): add split canvas views

- Render recursive pane layouts with Reka UI splitters and pane-local headers
- Route canvas input, selection, viewport state, and close actions to the active pane
- Repaint every canvas during shared document previews and cover split lifecycle in tests

* fix(editor): clean up inactive pane interactions

- Cancel drag, padding preview, and text editing state when pane focus changes
- Remove duplicate changelog entries introduced while updating master
2026-08-15 10:31:52 +03:00

59 lines
1.4 KiB
TypeScript

import { watch } from 'vue'
import type { ShallowRef } from 'vue'
import type { Editor } from '@open-pencil/core/editor'
export function createHiddenTextArea() {
const textarea = document.createElement('textarea')
textarea.setAttribute('aria-hidden', 'true')
textarea.tabIndex = -1
textarea.className = 'fixed left-0 top-0 h-px w-px opacity-0'
document.body.appendChild(textarea)
return textarea
}
export function focusTextAreaOnCanvasPointerDown(
textareaRef: ShallowRef<HTMLTextAreaElement | null>,
store: Editor
) {
if (store.state.editingTextId && textareaRef.value) {
requestAnimationFrame(() => textareaRef.value?.focus())
}
}
export function useTextEditingSession({
store,
textareaRef,
resetBlink,
stopBlink,
resetComposition,
isEnabled
}: {
store: Editor
textareaRef: ShallowRef<HTMLTextAreaElement | null>
resetBlink: () => void
stopBlink: () => void
resetComposition: () => void
isEnabled?: () => boolean
}) {
watch(
() => [store.state.editingTextId, isEnabled?.() ?? true] as const,
([id, enabled], _, onCleanup) => {
if (!enabled) return
if (id) {
const el = createHiddenTextArea()
textareaRef.value = el
el.focus()
resetBlink()
onCleanup(() => {
stopBlink()
el.remove()
textareaRef.value = null
resetComposition()
})
}
}
)
}