textfields: nix disableTab option; make TextShapes have custom Tab behavior as intended (#3506)

We shouldn't be making this something you have to negate everytime you
use `useEditableText`. The TextShape can just have its custom behavior
since that's the intended usecase. (although I think that Tab there
doesn't do much anyway, but whatevs)

### 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 ️ -->

- [ ] `bugfix` — Bug fix
- [ ] `feature` — New feature
- [ ] `improvement` — Improving existing features
- [x] `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
pull/3512/head
Mime Čuvalo 2024-04-17 12:11:08 +01:00 zatwierdzone przez GitHub
rodzic 1450454873
commit 34ad856873
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
9 zmienionych plików z 45 dodań i 52 usunięć

Wyświetl plik

@ -203,7 +203,6 @@ export class SpeechBubbleUtil extends ShapeUtil<SpeechBubbleShape> {
text={text} text={text}
labelColor={theme[color].solid} labelColor={theme[color].solid}
isSelected={isSelected} isSelected={isSelected}
disableTab
wrap wrap
/> />
</> </>

Wyświetl plik

@ -2507,9 +2507,7 @@ export function useDefaultHelpers(): {
export function useDialogs(): TLUiDialogsContextType; export function useDialogs(): TLUiDialogsContextType;
// @public (undocumented) // @public (undocumented)
export function useEditableText(id: TLShapeId, type: string, text: string, opts?: { export function useEditableText(id: TLShapeId, type: string, text: string): {
disableTab: boolean;
}): {
handleBlur: () => void; handleBlur: () => void;
handleChange: (e: React_2.ChangeEvent<HTMLTextAreaElement>) => void; handleChange: (e: React_2.ChangeEvent<HTMLTextAreaElement>) => void;
handleDoubleClick: (e: any) => any; handleDoubleClick: (e: any) => any;

Wyświetl plik

@ -15735,7 +15735,7 @@
}, },
{ {
"kind": "Content", "kind": "Content",
"text": ") => {\n id: import(\"@tldraw/editor\")." "text": ") => {\n id: "
}, },
{ {
"kind": "Reference", "kind": "Reference",
@ -15819,7 +15819,7 @@
}, },
{ {
"kind": "Content", "kind": "Content",
"text": ") => {\n id: import(\"@tldraw/editor\")." "text": ") => {\n id: "
}, },
{ {
"kind": "Reference", "kind": "Reference",
@ -15894,7 +15894,7 @@
}, },
{ {
"kind": "Content", "kind": "Content",
"text": ") => {\n id: import(\"@tldraw/editor\")." "text": ") => {\n id: "
}, },
{ {
"kind": "Reference", "kind": "Reference",
@ -15903,7 +15903,7 @@
}, },
{ {
"kind": "Content", "kind": "Content",
"text": ";\n props: {\n autoSize: boolean;\n scale?: undefined;\n };\n type: \"text\";\n } | {\n id: import(\"@tldraw/editor\")." "text": ";\n props: {\n autoSize: boolean;\n scale?: undefined;\n };\n type: \"text\";\n } | {\n id: "
}, },
{ {
"kind": "Reference", "kind": "Reference",
@ -27480,14 +27480,6 @@
"kind": "Content", "kind": "Content",
"text": "string" "text": "string"
}, },
{
"kind": "Content",
"text": ", opts?: "
},
{
"kind": "Content",
"text": "{\n disableTab: boolean;\n}"
},
{ {
"kind": "Content", "kind": "Content",
"text": "): " "text": "): "
@ -27575,8 +27567,8 @@
], ],
"fileUrlPath": "packages/tldraw/src/lib/shapes/shared/useEditableText.ts", "fileUrlPath": "packages/tldraw/src/lib/shapes/shared/useEditableText.ts",
"returnTypeTokenRange": { "returnTypeTokenRange": {
"startIndex": 9, "startIndex": 7,
"endIndex": 26 "endIndex": 24
}, },
"releaseTag": "Public", "releaseTag": "Public",
"overloadIndex": 1, "overloadIndex": 1,
@ -27604,14 +27596,6 @@
"endIndex": 6 "endIndex": 6
}, },
"isOptional": false "isOptional": false
},
{
"parameterName": "opts",
"parameterTypeTokenRange": {
"startIndex": 7,
"endIndex": 8
},
"isOptional": true
} }
], ],
"name": "useEditableText" "name": "useEditableText"

Wyświetl plik

@ -35,7 +35,6 @@ export const ArrowTextLabel = React.memo(function ArrowTextLabel({
labelColor={theme[labelColor].solid} labelColor={theme[labelColor].solid}
textWidth={width} textWidth={width}
isSelected={isSelected} isSelected={isSelected}
disableTab
style={{ style={{
transform: `translate(${position.x}px, ${position.y}px)`, transform: `translate(${position.x}px, ${position.y}px)`,
}} }}

Wyświetl plik

@ -421,7 +421,6 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
text={text} text={text}
isSelected={isSelected} isSelected={isSelected}
labelColor={theme[props.labelColor].solid} labelColor={theme[props.labelColor].solid}
disableTab
wrap wrap
/> />
</HTMLContainer> </HTMLContainer>

Wyświetl plik

@ -190,7 +190,6 @@ export class NoteShapeUtil extends ShapeUtil<TLNoteShape> {
isNote isNote
isSelected={isSelected} isSelected={isSelected}
labelColor={theme[color].note.text} labelColor={theme[color].note.text}
disableTab
wrap wrap
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
/> />

Wyświetl plik

@ -27,7 +27,6 @@ type TextLabelProps = {
bounds?: Box bounds?: Box
isNote?: boolean isNote?: boolean
isSelected: boolean isSelected: boolean
disableTab?: boolean
onKeyDown?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void onKeyDown?: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void
classNamePrefix?: string classNamePrefix?: string
style?: React.CSSProperties style?: React.CSSProperties
@ -51,15 +50,13 @@ export const TextLabel = React.memo(function TextLabel({
onKeyDown: handleKeyDownCustom, onKeyDown: handleKeyDownCustom,
classNamePrefix, classNamePrefix,
style, style,
disableTab = false,
textWidth, textWidth,
textHeight, textHeight,
}: TextLabelProps) { }: TextLabelProps) {
const { rInput, isEmpty, isEditing, isEditingAnything, ...editableTextRest } = useEditableText( const { rInput, isEmpty, isEditing, isEditingAnything, ...editableTextRest } = useEditableText(
id, id,
type, type,
text, text
{ disableTab }
) )
const [initialText, setInitialText] = useState(text) const [initialText, setInitialText] = useState(text)

Wyświetl plik

@ -2,7 +2,6 @@ import {
TLShapeId, TLShapeId,
TLUnknownShape, TLUnknownShape,
getPointerInfo, getPointerInfo,
preventDefault,
stopEventPropagation, stopEventPropagation,
useEditor, useEditor,
useValue, useValue,
@ -11,12 +10,7 @@ import React, { useCallback, useEffect, useRef } from 'react'
import { INDENT, TextHelpers } from './TextHelpers' import { INDENT, TextHelpers } from './TextHelpers'
/** @public */ /** @public */
export function useEditableText( export function useEditableText(id: TLShapeId, type: string, text: string) {
id: TLShapeId,
type: string,
text: string,
opts = { disableTab: false } as { disableTab: boolean }
) {
const editor = useEditor() const editor = useEditor()
const rInput = useRef<HTMLTextAreaElement>(null) const rInput = useRef<HTMLTextAreaElement>(null)
@ -134,20 +128,9 @@ export function useEditableText(
} }
break break
} }
case 'Tab': {
if (!opts.disableTab) {
preventDefault(e)
if (e.shiftKey) {
TextHelpers.unindent(e.currentTarget)
} else {
TextHelpers.indent(e.currentTarget)
}
}
break
}
} }
}, },
[editor, id, opts.disableTab] [editor, id]
) )
// When the text changes, update the text value. // When the text changes, update the text value.

Wyświetl plik

@ -7,18 +7,22 @@ import {
SvgExportContext, SvgExportContext,
TLOnEditEndHandler, TLOnEditEndHandler,
TLOnResizeHandler, TLOnResizeHandler,
TLShapeId,
TLShapeUtilFlag, TLShapeUtilFlag,
TLTextShape, TLTextShape,
Vec, Vec,
WeakMapCache, WeakMapCache,
getDefaultColorTheme, getDefaultColorTheme,
preventDefault,
textShapeMigrations, textShapeMigrations,
textShapeProps, textShapeProps,
toDomPrecision, toDomPrecision,
useEditor, useEditor,
} from '@tldraw/editor' } from '@tldraw/editor'
import { useCallback } from 'react'
import { useDefaultColorTheme } from '../shared/ShapeFill' import { useDefaultColorTheme } from '../shared/ShapeFill'
import { SvgTextLabel } from '../shared/SvgTextLabel' import { SvgTextLabel } from '../shared/SvgTextLabel'
import { TextHelpers } from '../shared/TextHelpers'
import { TextLabel } from '../shared/TextLabel' import { TextLabel } from '../shared/TextLabel'
import { FONT_FAMILIES, FONT_SIZES, TEXT_PROPS } from '../shared/default-shape-constants' import { FONT_FAMILIES, FONT_SIZES, TEXT_PROPS } from '../shared/default-shape-constants'
import { getFontDefForExport } from '../shared/defaultStyleDefs' import { getFontDefForExport } from '../shared/defaultStyleDefs'
@ -73,6 +77,7 @@ export class TextShapeUtil extends ShapeUtil<TLTextShape> {
const { width, height } = this.getMinDimensions(shape) const { width, height } = this.getMinDimensions(shape)
const isSelected = shape.id === this.editor.getOnlySelectedShapeId() const isSelected = shape.id === this.editor.getOnlySelectedShapeId()
const theme = useDefaultColorTheme() const theme = useDefaultColorTheme()
const handleKeyDown = useTextShapeKeydownHandler(id)
return ( return (
<TextLabel <TextLabel
@ -94,6 +99,7 @@ export class TextShapeUtil extends ShapeUtil<TLTextShape> {
transformOrigin: 'top left', transformOrigin: 'top left',
}} }}
wrap wrap
onKeyDown={handleKeyDown}
/> />
) )
} }
@ -332,3 +338,32 @@ function getTextSize(editor: Editor, props: TLTextShape['props']) {
height: Math.max(fontSize, result.h), height: Math.max(fontSize, result.h),
} }
} }
function useTextShapeKeydownHandler(id: TLShapeId) {
const editor = useEditor()
return useCallback(
(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
if (editor.getEditingShapeId() !== id) return
switch (e.key) {
case 'Enter': {
if (e.ctrlKey || e.metaKey) {
editor.complete()
}
break
}
case 'Tab': {
preventDefault(e)
if (e.shiftKey) {
TextHelpers.unindent(e.currentTarget)
} else {
TextHelpers.indent(e.currentTarget)
}
break
}
}
},
[editor, id]
)
}