[fix] Text on Safari (#232)

* Fix editing bug on safari text

* Fix text behavior when blurring

* Update SelectTool.ts
This commit is contained in:
Steve Ruiz 2021-11-09 14:26:41 +00:00 committed by GitHub
parent 0b5a516b57
commit 6592608a09
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 62 additions and 47 deletions

View file

@ -15,7 +15,6 @@ import {
TLWheelEventHandler,
Utils,
TLBounds,
Inputs,
} from '@tldraw/core'
import {
FlipType,
@ -134,6 +133,8 @@ export class TLDrawState extends StateManager<TLDrawSnapshot> {
currentTool: BaseTool = this.tools.select
editingStartTime = -1
private isCreating = false
// The editor's bounding client rect
@ -486,6 +487,7 @@ export class TLDrawState extends StateManager<TLDrawSnapshot> {
* @param id [string]
*/
setEditingId = (id?: string) => {
this.editingStartTime = Date.now()
this.patchState(
{
document: {
@ -2527,14 +2529,15 @@ export class TLDrawState extends StateManager<TLDrawSnapshot> {
}
onShapeBlur = () => {
// This prevents an auto-blur event from Safari
if (Date.now() - this.editingStartTime < 50) return
const { editingId } = this.pageState
if (editingId) {
// If we're editing text, then delete the text if it's empty
const shape = this.getShape(editingId)
this.setEditingId()
if (shape.type === TLDrawShapeType.Text) {
if (shape.text.trim().length <= 0) {
this.setState(Commands.deleteShapes(this.state, [editingId]), 'delete_empty_text')

View file

@ -12,7 +12,11 @@ import {
} from '~types'
import { BINDING_DISTANCE } from '~constants'
import { TLDrawShapeUtil } from '../TLDrawShapeUtil'
import { intersectLineSegmentEllipse, intersectRayEllipse } from '@tldraw/intersect'
import {
intersectEllipseBounds,
intersectLineSegmentEllipse,
intersectRayEllipse,
} from '@tldraw/intersect'
import { getEllipseIndicatorPathTLDrawSnapshot, getEllipsePath } from './ellipseHelpers'
type T = EllipseShape
@ -156,12 +160,27 @@ export class EllipseUtil extends TLDrawShapeUtil<T, E> {
)
}
hitTestBounds = (shape: T, bounds: TLBounds): boolean => {
const shapeBounds = this.getBounds(shape)
return (
Utils.boundsContained(shapeBounds, bounds) ||
intersectEllipseBounds(
this.getCenter(shape),
shape.radius[0],
shape.radius[1],
shape.rotation || 0,
bounds
).length > 0
)
}
shouldRender = (prev: T, next: T): boolean => {
return next.radius !== prev.radius || next.style !== prev.style
}
getCenter = (shape: T): number[] => {
return [shape.point[0] + shape.radius[0], shape.point[1] + shape.radius[1]]
return Vec.add(shape.point, shape.radius)
}
getBindingPoint = <K extends TLDrawShape>(

View file

@ -17,6 +17,8 @@ export class StickyUtil extends TLDrawShapeUtil<T, E> {
canBind = true
canEdit = true
getShape = (props: Partial<T>): T => {
return Utils.deepMerge<T>(
{
@ -89,25 +91,16 @@ export class StickyUtil extends TLDrawShapeUtil<T, E> {
[shape, onShapeChange]
)
const handleBlur = React.useCallback(
(e: React.FocusEvent<HTMLTextAreaElement>) => {
if (!isEditing) return
if (rIsMounted.current) {
const handleBlur = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {
e.currentTarget.setSelectionRange(0, 0)
onShapeBlur?.()
}
},
[isEditing]
)
}, [])
const handleFocus = React.useCallback(
(e: React.FocusEvent<HTMLTextAreaElement>) => {
if (!isEditing) return
if (!rIsMounted.current) return
if (document.activeElement === e.currentTarget) {
e.currentTarget.select()
}
},
[isEditing]
)
@ -115,14 +108,10 @@ export class StickyUtil extends TLDrawShapeUtil<T, E> {
// Focus when editing changes to true
React.useEffect(() => {
if (isEditing) {
if (document.activeElement !== rText.current) {
requestAnimationFrame(() => {
rIsMounted.current = true
const elm = rTextArea.current!
elm.focus()
elm.select()
})
}
}
}, [isEditing])
@ -151,6 +140,9 @@ export class StickyUtil extends TLDrawShapeUtil<T, E> {
onShapeChange?.({ id: shape.id, size: [size[0], MIN_CONTAINER_HEIGHT] })
return
}
const textarea = rTextArea.current
textarea?.focus()
}, [shape.text, shape.size[1], shape.style])
const style = {
@ -180,10 +172,13 @@ export class StickyUtil extends TLDrawShapeUtil<T, E> {
onKeyDown={handleKeyDown}
onFocus={handleFocus}
onBlur={handleBlur}
autoCapitalize="off"
autoComplete="off"
spellCheck={false}
tabIndex={-1}
autoComplete="false"
autoCapitalize="false"
autoCorrect="false"
autoSave="false"
autoFocus
spellCheck={false}
/>
)}
</StyledStickyContainer>

View file

@ -77,16 +77,10 @@ export class TextUtil extends TLDrawShapeUtil<T, E> {
[shape, onShapeChange]
)
const handleBlur = React.useCallback(
(e: React.FocusEvent<HTMLTextAreaElement>) => {
if (!isEditing) return
if (rIsMounted.current) {
const handleBlur = React.useCallback((e: React.FocusEvent<HTMLTextAreaElement>) => {
e.currentTarget.setSelectionRange(0, 0)
onShapeBlur?.()
}
},
[isEditing]
)
}, [])
const handleFocus = React.useCallback(
(e: React.FocusEvent<HTMLTextAreaElement>) => {
@ -117,6 +111,8 @@ export class TextUtil extends TLDrawShapeUtil<T, E> {
elm.focus()
elm.select()
})
} else {
onShapeBlur?.()
}
}, [isEditing])
@ -156,14 +152,14 @@ export class TextUtil extends TLDrawShapeUtil<T, E> {
autoCapitalize="false"
autoCorrect="false"
autoSave="false"
autoFocus
placeholder=""
color={styles.stroke}
onFocus={handleFocus}
onBlur={handleBlur}
onChange={handleChange}
onKeyDown={handleKeyDown}
onBlur={handleBlur}
onPointerDown={handlePointerDown}
autoFocus
wrap="off"
dir="auto"
datatype="wysiwyg"

View file

@ -429,9 +429,7 @@ export class SelectTool extends BaseTool<Status> {
// Unless the user is holding shift or meta, clear the current selection
if (!info.shiftKey) {
if (this.state.pageState.editingId) {
this.state.setEditingId()
}
this.state.onShapeBlur()
if (info.altKey && this.state.selectedIds.length > 0) {
this.state.duplicate(this.state.selectedIds, this.state.getPagePoint(info.point))
@ -459,7 +457,11 @@ export class SelectTool extends BaseTool<Status> {
return
}
const { hoveredId } = this.state.pageState
const { editingId, hoveredId } = this.state.pageState
if (editingId && info.target !== editingId) {
this.state.onShapeBlur()
}
// While holding command and shift, select or deselect
// the shape, ignoring any group that may contain it. Yikes!