textfields: fix Safari cursor rendering bug, take 2 (#3513)

Take 2 on what this PR was trying to do:
https://github.com/tldraw/tldraw/pull/3373
Fixes https://github.com/tldraw/tldraw/issues/3398 hopefully this time
without the infinite recursion 🙃

### 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
This commit is contained in:
Mime Čuvalo 2024-04-17 15:31:35 +01:00 committed by GitHub
parent f754bebc32
commit f9bafb2f8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -12,24 +12,12 @@ import { INDENT, TextHelpers } from './TextHelpers'
/** @public */
export function useEditableText(id: TLShapeId, type: string, text: string) {
const editor = useEditor()
const rInput = useRef<HTMLTextAreaElement>(null)
const isEditing = useValue(
'isEditing',
() => {
return editor.getEditingShapeId() === id
},
[editor]
)
const isEditingAnything = useValue(
'isEditingAnything',
() => {
return editor.getEditingShapeId() !== null
},
[editor]
)
const rSelectionRanges = useRef<Range[] | null>()
const isEditing = useValue('isEditing', () => editor.getEditingShapeId() === id, [editor])
const isEditingAnything = useValue('isEditingAnything', () => !!editor.getEditingShapeId(), [
editor,
])
useEffect(() => {
function selectAllIfEditing({ shapeId }: { shapeId: TLShapeId }) {
@ -46,14 +34,13 @@ export function useEditableText(id: TLShapeId, type: string, text: string) {
}
})
}
editor.on('select-all-text', selectAllIfEditing)
return () => {
editor.off('select-all-text', selectAllIfEditing)
}
}, [editor, id])
const rSelectionRanges = useRef<Range[] | null>()
useEffect(() => {
if (!isEditing) return
@ -63,10 +50,18 @@ export function useEditableText(id: TLShapeId, type: string, text: string) {
// Focus if we're not already focused
if (document.activeElement !== elm) {
elm.focus()
// On mobile etc, just select all the text when we start focusing
if (editor.getInstanceState().isCoarsePointer) {
elm.select()
}
} else {
// This fixes iOS not showing the cursor sometimes. This "shakes" the cursor
// awake.
if (editor.environment.isSafari) {
elm.blur()
elm.focus()
}
}
// When the selection changes, save the selection ranges
@ -97,12 +92,14 @@ export function useEditableText(id: TLShapeId, type: string, text: string) {
requestAnimationFrame(() => {
const elm = rInput.current
const editingShapeId = editor.getEditingShapeId()
// Did we move to a different shape?
if (editingShapeId) {
// important! these ^v are two different things
// is that shape OUR shape?
if (elm && editingShapeId === id) {
elm.focus()
if (ranges && ranges.length) {
const selection = window.getSelection()
if (selection) {
@ -181,8 +178,6 @@ export function useEditableText(id: TLShapeId, type: string, text: string) {
[editor, id, isEditing]
)
const handleDoubleClick = stopEventPropagation
return {
rInput,
handleFocus: noop,
@ -190,7 +185,7 @@ export function useEditableText(id: TLShapeId, type: string, text: string) {
handleKeyDown,
handleChange,
handleInputPointerDown,
handleDoubleClick,
handleDoubleClick: stopEventPropagation,
isEmpty: text.trim().length === 0,
isEditing,
isEditingAnything,