kopia lustrzana https://github.com/Tldraw/Tldraw
textfields: bring shape into view when editing (#3362)
This actually is a problem in production anyway, for any shape, not particular to new auto-editing or stickies. Case in point: - shape is selected - move the shape offscreen - hit Enter - you'll be editing the shape but it won't be visible to you. This change consolidates some of the duplicate logic in `Idle.ts` and in `noteHelpers.ts`. Two questions - `Idle.ts` didn't have the `select()` call but `noteHelpers.ts` did - is this really important? - `noteHelpers` didn't have the `mark()` call but `Idle.ts` did - seems like it was missing in noteHelpers, but lemme know if that was intended to be left out. ### Change Type <!-- ❗ Please select a 'Scope' label ❗️ --> - [x] `sdk` — Changes the tldraw SDK - [ ] `dotcom` — Changes the tldraw.com web app - [ ] `docs` — Changes to the documentation, examples, or templates. - [ ] `vs code` — Changes to the vscode plugin - [ ] `internal` — Does not affect user-facing stuff <!-- ❗ Please select a 'Type' label ❗️ --> - [x] `bugfix` — Bug fix - [ ] `feature` — New feature - [ ] `improvement` — Improving existing features - [ ] `chore` — Updating dependencies, other boring stuff - [ ] `galaxy brain` — Architectural changes - [ ] `tests` — Changes to any test code - [ ] `tools` — Changes to infrastructure, CI, internal scripts, debugging tools, etc. - [ ] `dunno` — I don't know ### Release Notes - Textfields: bring shape to view that's being edited. --------- Co-authored-by: Steve Ruiz <steveruizok@gmail.com>pull/3370/head
rodzic
7671e6291e
commit
c5059f15bb
|
@ -36,6 +36,7 @@ import {
|
|||
} from '../shared/default-shape-constants'
|
||||
import { getFontDefForExport } from '../shared/defaultStyleDefs'
|
||||
|
||||
import { startEditingShapeWithLabel } from '../shared/TextHelpers'
|
||||
import { useForceSolid } from '../shared/useForceSolid'
|
||||
import {
|
||||
ADJACENT_NOTE_MARGIN,
|
||||
|
@ -43,7 +44,6 @@ import {
|
|||
NOTE_CENTER_OFFSET,
|
||||
NOTE_SIZE,
|
||||
getNoteShapeForAdjacentPosition,
|
||||
startEditingNoteShape,
|
||||
} from './noteHelpers'
|
||||
|
||||
/** @public */
|
||||
|
@ -450,7 +450,7 @@ function useNoteKeydownHandler(id: TLShapeId) {
|
|||
const newNote = getNoteShapeForAdjacentPosition(editor, shape, adjacentCenter, pageRotation)
|
||||
|
||||
if (newNote) {
|
||||
startEditingNoteShape(editor, newNote)
|
||||
startEditingShapeWithLabel(editor, newNote, true /* selectAll */)
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -1,12 +1,5 @@
|
|||
import {
|
||||
ANIMATION_MEDIUM_MS,
|
||||
Editor,
|
||||
TLNoteShape,
|
||||
TLShape,
|
||||
Vec,
|
||||
compact,
|
||||
createShapeId,
|
||||
} from '@tldraw/editor'
|
||||
import { Editor, TLNoteShape, TLShape, Vec, compact, createShapeId } from '@tldraw/editor'
|
||||
import { zoomToShapeIfOffscreen } from '../shared/TextHelpers'
|
||||
|
||||
/** @internal */
|
||||
export const ADJACENT_NOTE_MARGIN = 20
|
||||
|
@ -173,29 +166,3 @@ export function getNoteShapeForAdjacentPosition(
|
|||
zoomToShapeIfOffscreen(editor)
|
||||
return nextNote
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function startEditingNoteShape(editor: Editor, shape: TLShape) {
|
||||
// Finish this sticky and start editing the next one
|
||||
editor.select(shape)
|
||||
editor.setEditingShape(shape)
|
||||
editor.setCurrentTool('select.editing_shape', {
|
||||
target: 'shape',
|
||||
shape: shape,
|
||||
})
|
||||
|
||||
// Select any text that's in the newly selected sticky
|
||||
;(document.getElementById(`text-input-${shape.id}`) as HTMLTextAreaElement)?.select()
|
||||
|
||||
zoomToShapeIfOffscreen(editor)
|
||||
}
|
||||
|
||||
function zoomToShapeIfOffscreen(editor: Editor) {
|
||||
const selectionPageBounds = editor.getSelectionPageBounds()
|
||||
const viewportPageBounds = editor.getViewportPageBounds()
|
||||
if (selectionPageBounds && !viewportPageBounds.contains(selectionPageBounds)) {
|
||||
editor.centerOnPoint(selectionPageBounds.center, {
|
||||
duration: ANIMATION_MEDIUM_MS,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
* Copyright (c) Federico Brigante <opensource@bfred.it> (bfred.it)
|
||||
*/
|
||||
|
||||
import { ANIMATION_MEDIUM_MS, Editor, TLShape } from '@tldraw/editor'
|
||||
|
||||
// TODO: Most of this file can be moved into a DOM utils library.
|
||||
|
||||
/** @internal */
|
||||
|
@ -290,3 +292,50 @@ function getCaretIndex(element: HTMLElement) {
|
|||
}
|
||||
return position
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function startEditingShapeWithLabel(
|
||||
editor: Editor,
|
||||
shape: TLShape,
|
||||
shouldSelectAll?: boolean
|
||||
) {
|
||||
// Finish this shape and start editing the next one
|
||||
editor.select(shape)
|
||||
editor.mark('editing shape')
|
||||
editor.setEditingShape(shape)
|
||||
editor.setCurrentTool('select.editing_shape', {
|
||||
target: 'shape',
|
||||
shape: shape,
|
||||
})
|
||||
|
||||
if (shouldSelectAll) {
|
||||
// Select any text that's in the newly selected sticky
|
||||
;(document.getElementById(`text-input-${shape.id}`) as HTMLTextAreaElement)?.select()
|
||||
}
|
||||
|
||||
zoomToShapeIfOffscreen(editor)
|
||||
}
|
||||
|
||||
const ZOOM_TO_SHAPE_PADDING = 16
|
||||
export function zoomToShapeIfOffscreen(editor: Editor) {
|
||||
const selectionPageBounds = editor.getSelectionPageBounds()
|
||||
const viewportPageBounds = editor.getViewportPageBounds()
|
||||
if (selectionPageBounds && !viewportPageBounds.contains(selectionPageBounds)) {
|
||||
const eb = selectionPageBounds
|
||||
.clone()
|
||||
// Expand the bounds by the padding
|
||||
.expandBy(ZOOM_TO_SHAPE_PADDING / editor.getZoomLevel())
|
||||
// then expand the bounds to include the viewport bounds
|
||||
.expand(viewportPageBounds)
|
||||
|
||||
// then use the difference between the centers to calculate the offset
|
||||
const nextBounds = viewportPageBounds.clone().translate({
|
||||
x: (eb.center.x - viewportPageBounds.center.x) * 2,
|
||||
y: (eb.center.y - viewportPageBounds.center.y) * 2,
|
||||
})
|
||||
editor.zoomToBounds(nextBounds, {
|
||||
duration: ANIMATION_MEDIUM_MS,
|
||||
inset: 0,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import {
|
|||
createShapeId,
|
||||
pointInPolygon,
|
||||
} from '@tldraw/editor'
|
||||
import { startEditingShapeWithLabel } from '../../../shapes/shared/TextHelpers'
|
||||
import { getHitShapeOnCanvasPointerDown } from '../../selection-logic/getHitShapeOnCanvasPointerDown'
|
||||
import { getShouldEnterCropMode } from '../../selection-logic/getShouldEnterCropModeOnPointerDown'
|
||||
import { selectOnCanvasPointerUp } from '../../selection-logic/selectOnCanvasPointerUp'
|
||||
|
@ -446,11 +447,15 @@ export class Idle extends StateNode {
|
|||
this.shouldStartEditingShape(onlySelectedShape) &&
|
||||
this.editor.getShapeUtil(onlySelectedShape).doesAutoEditOnKeyStroke(onlySelectedShape)
|
||||
) {
|
||||
this.startEditingShape(onlySelectedShape, {
|
||||
...info,
|
||||
target: 'shape',
|
||||
shape: onlySelectedShape,
|
||||
})
|
||||
this.startEditingShape(
|
||||
onlySelectedShape,
|
||||
{
|
||||
...info,
|
||||
target: 'shape',
|
||||
shape: onlySelectedShape,
|
||||
},
|
||||
true /* select all */
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -522,15 +527,8 @@ export class Idle extends StateNode {
|
|||
shouldSelectAll?: boolean
|
||||
) {
|
||||
if (this.editor.isShapeOrAncestorLocked(shape) && shape.type !== 'embed') return
|
||||
this.editor.mark('editing shape')
|
||||
this.editor.setEditingShape(shape.id)
|
||||
startEditingShapeWithLabel(this.editor, shape, shouldSelectAll)
|
||||
this.parent.transition('editing_shape', info)
|
||||
|
||||
if (shouldSelectAll) {
|
||||
// XXX this is a hack to select the text in the textarea when we hit enter.
|
||||
// Open to other ideas! I don't see how else to currently do this in the codebase.
|
||||
;(document.getElementById(`text-input-${shape.id}`) as HTMLTextAreaElement)?.select()
|
||||
}
|
||||
}
|
||||
|
||||
isDarwin = window.navigator.userAgent.toLowerCase().indexOf('mac') > -1
|
||||
|
|
|
@ -12,8 +12,8 @@ import {
|
|||
NOTE_CENTER_OFFSET,
|
||||
getNoteAdjacentPositions,
|
||||
getNoteShapeForAdjacentPosition,
|
||||
startEditingNoteShape,
|
||||
} from '../../../shapes/note/noteHelpers'
|
||||
import { startEditingShapeWithLabel } from '../../../shapes/shared/TextHelpers'
|
||||
|
||||
export class PointingHandle extends StateNode {
|
||||
static override id = 'pointing_handle'
|
||||
|
@ -53,7 +53,7 @@ export class PointingHandle extends StateNode {
|
|||
const { editor } = this
|
||||
const nextNote = getNoteForPit(editor, shape, handle, false)
|
||||
if (nextNote) {
|
||||
startEditingNoteShape(editor, nextNote)
|
||||
startEditingShapeWithLabel(editor, nextNote, true /* selectAll */)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ export class PointingHandle extends StateNode {
|
|||
isCreating: true,
|
||||
onCreate: () => {
|
||||
// When we're done, start editing it
|
||||
startEditingNoteShape(editor, nextNote)
|
||||
startEditingShapeWithLabel(editor, nextNote, true /* selectAll */)
|
||||
},
|
||||
})
|
||||
return
|
||||
|
|
Ładowanie…
Reference in New Issue